diff --git a/packages/syncfusion_flutter_pdf/.pubignore b/packages/syncfusion_flutter_pdf/.pubignore deleted file mode 100644 index 805607a57..000000000 --- a/packages/syncfusion_flutter_pdf/.pubignore +++ /dev/null @@ -1,4 +0,0 @@ -# See https://dart.dev/tools/pub/publishing#what-files-are-published - -lib/src/test/* - diff --git a/packages/syncfusion_flutter_pdf/CHANGELOG.md b/packages/syncfusion_flutter_pdf/CHANGELOG.md index bf01dfbf3..411be5d7d 100644 --- a/packages/syncfusion_flutter_pdf/CHANGELOG.md +++ b/packages/syncfusion_flutter_pdf/CHANGELOG.md @@ -1,707 +1,803 @@ -## Unreleased - -**Bugs** - -* The compatible version of our Flutter PDF library has been updated to Flutter SDK 3.32.0. - -## [29.2.11] - 17/06/2025 - -**Bugs** - -* Resolved an exception that occurred when hiding document-level layers in a specific PDF document. - -## [29.2.9] - 05/06/2025 - -**Bugs** - -* Resolved a mismatch error in the text word length and text glyph length from a specific PDF document. - -## [29.2.7] - 27/05/2025 - -**Bugs** - -* Resolved a range error exception while extracting text lines from a specific PDF document. - -## [29.2.4] - 13/05/2025 - -**Bugs** - -* Resolved an Out-Of-Memory crash that occurred during the decryption of PDF document. -* Resolved a performance issue when decrypting password-protected PDF documents. - -## [29.1.41] - 06/05/2025 - -**Bugs** - -* Resolved an issue where an exception occurred when flattening a signature field in a PDF document. - -## [29.1.40] - 29/04/2025 - -**Bugs** - -* Resolved a content preservation issue that occurred when drawing multiple PDF grids on the same page of a PDF document. -* Resolved an issue where PDF form is returned as null when acro form has no fields. - -## [29.1.39] - 22/04/2025 - -**General** - -* The minimum Dart version has been updated to 3.7. - -## [29.1.38] - 04/15/2025 - -**Bugs** - -* Resolved an issue where the null check operator was incorrectly used on a nullable value. -* Resolved an issue where the PDF was shifting towards the top right corner when drawing existing page templates on PDFs. -* Exception occurs when getting the bounds of the text box form field item in a document has been resolved. - -## [29.1.37] - 04/08/2025 - -**Bugs** - -* Resolved the invalid cross reference table issue occurs while loading the specific PDF document. -* Resolved the Layer name not preserved properly while removing layers in the PDF document - -## [29.1.35] - 04/01/2025 - -**Bugs** - -* Resolved the exception that occurred while decrypting PDF files on the Flutter web platform. - -## [29.1.33] - 03/25/2025 - -**General** - -* The compatible version of our Flutter PDF library has been updated to Flutter SDK 3.29.0. -* The Syncfusion® Flutter PDF example sample have been updated to support [kotlin build scripts](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply) in Android platform. -* The Syncfusion® Flutter PDF example sample have been updated to support [Swift package manager](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers) in macOS and iOS platforms. - -**Bugs** - -* Fixed incorrect TextWord bounds when extracting text from a cropped PDF document. - -## [28.2.9] - 03/04/2025 - -**General** - -* The minimum Dart version of our Flutter widgets has been updated to 3.4 from 3.3. - -**Bugs** - -* Resolved the TypeError occurs when getting the bounds of the form field in a specific document - -## [28.2.7] - 02/25/2025 - -**Bugs** - -* Resolved the Performance issue occurs while decrypting the pdf - -## [28.2.5] - 02/11/2025 - -**Bugs** - -* Resolved the Format exception occurs while extracting the text from the PDF document - -## [28.2.4] - 02/04/2025 - -**Bugs** - -* Resolved the preservation issue when filling the multiline text box field. -* Typecasting issue occurs while loading the checkbox fields in the PDF document has been resolved. - -## [28.1.39] - 01/14/2025 - -**Bugs** - -* Resolved an issue where Unicode characters were not correctly recognized during text extraction from PDF documents. - -## [28.1.38] - 01/07/2025 - -**Bugs** - -* The preservation issue encountered when adding annotations to a document has been resolved. - -## [27.2.3] - 11/22/2024 - -**Bugs** - -* The issue of the signature appearance being duplicated when viewing the resultant PDF in the Syncfusion® viewer has been resolved. - -## [27.2.2] - 11/15/2024 - -**Bugs** - -* The format exception that occurred while signing the document with a specific certificate using an external signer has been resolved. - -## [27.1.58] - 11/5/2024 - -**Bugs** - -* The issue of an exception occurring when drawing emoji symbols in PDF form fields has been resolved. - -## [27.1.55] - 10/22/2024 - -**Bugs** - -* Type casting issue occurs while extracting text lines from a specific PDF document has been resolved. - -## [27.1.52] - 10/08/2024 - -**Bugs** - -* The issue of the file being corrupted while inserting a page into an existing PDF document has been resolved. - -## [27.1.50] - 09/24/2024 - -**Bugs** - -* Type casting issue occurs while loading annotations from the PDF document has been resolved. -* The issue where file size did not decrease after removing pages from the PDF document has been resolved. - -## [26.2.14] - 09/10/2024 - -**General** - -* The compatible version of our Flutter PDF library has been updated to Flutter SDK 3.24.0. - -**Bugs** - -* The issue of incorrect bounds being retrieved from text markup annotations created with the Firefox PDF viewer has been resolved. - -## [26.2.10] - 08/20/2024 - -**Bugs** - -* Exception will no longer be thrown while extracting text from a particular PDF document. - -## [26.2.9] - 08/13/2024 - -**Bugs** - -* Text will now be properly extracted in the Safari browser on macOS. - -## [26.2.7] - 07/30/2024 - -**Bugs** - -* The text color now remains consistent after decrypting and saving the PDF document. - -## [26.2.4] - 07/24/2024 - -**Bugs** - -* Incorrect bounds are no longer being retrieved when extracting text from a specific PDF document. - -## [26.1.42] - 07/16/2024 - -**Bugs** - -* The issue causing null check errors when retrieving items from a radio button field in the PDF document has been resolved. - -* The issue with type casting no longer occurs when retrieving annotations from a PDF document. - -## [26.1.41] - 07/09/2024 - -**Bugs** - -* The performance issue no longer occurs when reading the signature field from the PDF document. - -* The type cast issue no longer occurs when flattening the signature in a specific PDF document. - -## [26.1.40] - 07/02/2024 - -**Bugs** - -* High memory consumption will no longer occur while extracting text from large PDF documents. - -## [26.1.38] - 06/19/2024 - -**Bugs** - -* Extracting text lines now returns the proper bounds for the CID font type in the PDF document. - -* Performance issue no longer occurs while extracting text lines from the PDF document. - -## [26.1.35] - 06/11/2024 - -**Features** - -* Provided support for adding timestamp and LTV in PDF signature. - -## [25.2.6] - 05/28/2024 - -**Bugs** - -* Resolved the issue where flattening some form fields was not working in a specific PDF document. - -## [25.2.5] - 05/21/2024 - -**Bugs** - -* Preservation issues no longer occur when drawing on a page with negative crop box x and y coordinates. - -## [25.1.42] - 04/30/2024 - -**Bugs** - -* Extracting text from an encrypted PDF document will no longer significantly increase file size and corrupt the document. - -## [25.1.41] - 04/23/2024 - -**Bugs** - -* The existing signature no longer becomes invalid when adding a second signature to the PDF document. - -## [25.1.39] - 04/09/2024 - -**Bugs** - -* RangeError will no longer occur while extracting text lines from the PDF document. - -## [25.1.37] - 03/26/2024 - -**Bugs** - -* Preservation issue will no longer occur while flattening the signature field in the PDF document. - -* The issue with the invalid signature has been resolved when signing the PDF document. - -## [25.1.35] - 03/15/2024 - -**Breaking changes** - -* The `sign` method in the `IPdfExternalSigner` class has been changed to an asynchronous type, and the `signSync` method has been added for synchronous signing. - -**Features** - -* Provided support for importing and exporting annotations in the PDF document. - -* Provided support for asynchronous external signing in the PDF document. - -## [24.2.8] - 02/27/2024 - -**Bugs** - -* Resolved the issue where extracting text returns incorrect results for a specific PDF document. - -* Invalid font name error will no longer occur when extracting text from specific PDF document. - -## [24.2.5] - 02/13/2024 - -**Bugs** - -* Extracting text lines will no longer return incorrect results for specific PDF documents. - -## [24.2.4] - 02/06/2024 - -**Bugs** - -* Find text related issues are now resolved in PDF documents. - -* Extract text is now working properly in specific PDF document. - -## [24.2.3] - 01/31/2024 - -**Features** - -* Provided support to check and uncheck the check box field items. - -## [24.1.46] - 01/17/2024 - -**General** - -* Upgraded the `intl` package to the latest version 0.19.0. - -## [24.1.45] - 01/09/2024 - -**Bugs** - -* Preservation failure no longer occurs in Mac PDF viewer while saving specific encrypted PDF document. - -## [24.1.44] - 01/03/2023 - -**Bugs** - -* Null check error will no longer occur while removing pages from the PDF document. - -## [24.1.43] - 12/27/2023 - -**Bugs** - -* Preservation issue will no longer occur while flattening text box field in specific PDF document. - -## [24.1.41] - 12/18/2023 - -**Features** - -* Provided support for text markup and popup annotations. - -* Provided support for adding annotation flags to PDF annotations. - -**Bugs** - -* The issue of retrieving incorrect values from the text box field after saving an encrypted PDF document has been resolved. - -## [23.1.44] - 11/07/2023 - -**Bugs** - -* The null reference exception that occurred while retrieving the page from the form fields in the PDF has been resolved. - -## [23.1.40] - 10/10/2023 - -**Bugs** - -* Resolved the incorrect image dimension recording in PdfBitmap. - -## [23.1.39] - 10/04/2023 - -**Features** - -* Support has been provided for back color, border color, and border style in the PDF signature field. - -## [22.2.11] - 08/29/2023 - -**Bugs** - -* High memory consumption will no longer occurs while extracting text from large PDF documents. - -* Null check exceptions will no longer occur while drawing PDF grid in a loaded page. - -## [22.2.9] - 08/15/2023 - -**Bugs** - -* Null reference exceptions will no longer occur when retrieving form fields from the PDF document. - -## [22.2.5] - 07/27/2023 - -**Bugs** - -* Resolved white background preservation while flattening loaded empty signature field. - -* Type casting issue no longer occurs while flattening specific PDF document. - -## [22.1.36] - 06/28/2023 - -**Bugs** - -* Resolved the space between text missing issue in the extract text layout and lines. - -* PDF signature added with signed name is now valid in Adobe viewer. - -## [21.2.4] - 05/09/2023 - -**Bugs** - -* Null reference exceptions will no longer occur while getting form fields from the PDF document. - -* Now, spaces are preserved properly when extracting text with the layout. - -* The preservation issue no longer occurs after modifying the values in the fields of the PDF document. - -## [21.1.41] - 04/18/2023 - -**Bugs** - -* The unhandled exception that occurred during the extraction of text and flattening of form fields in the PDF document has been resolved. - -## [21.1.39] - 04/11/2023 - -**Bugs** - -* RTL bookmark title is now properly retrieved from Encrypted PDF documents. - -## [21.1.37] - 03/29/2023 - -**Bugs** - -* Text words are now properly split while extracting text from PDF documents. - -## [20.4.54] - 03/15/2023 - -**Bugs** - -* The issue of PDF document size increasing after removing pages has been resolved. - -## [20.4.50] - 02/14/2023 - -**Bugs** - -* Resolved the document corruption exception when signing existing signed PDF documents. - -* Text bounds are now retrieved properly when finding text from cropped PDF documents. - -## [20.3.57] - 11/15/2022 - -**Bugs** - -* Alpha channel is not initialized properly in transparent brush is now resolved. - -## [20.3.56] - 11/08/2022 - -**Features** - -* Provided support to set signed date while signing the pdf document. - -## [20.2.48] - 09/06/2022 - -**Bugs** - -* The type casting issue when trying to get annotation is now resolved. - -## [20.2.45] - 08/23/2022 - -**Bugs** - -* The font is not updated properly for loaded form fields is now resolved. - -## [20.2.36] - 06/30/2022 - -**Breaking changes** - -* The `save` method has been changed to an asynchronous type in the `PdfDocument` and the `saveSync` method has been added for synchronous. - -**Features** - -* Provided asynchronous save support for PDF documents. - -**Bugs** - -* The preservation issue when flattening the PDF text box field is now resolved. - -* Resolved the document corruption issue while modifying encrypted PDF document. - -## [20.1.48-beta] - 04/12/2022 - -**Bugs** - -* The layout issue when extracting text from the PDF document is now resolved. - -## [20.1.47-beta] - 04/04/2022 - -**Features** - -* Provided support to extract RTL text from an existing PDF document along with its bounds. - -* Provided support to find RTL text in an existing PDF document. - -**Known Limitation** - -* Combination of RTL and LTR text in find operations will not work. For example "80٪ خصم في المحدد jeans". - -## [19.4.41-beta] - 01/04/2022 - -**Bugs** - -* Typecasting exceptions will no longer occur while extracting text from the PDF document. - -## [19.3.55-beta] - 11/23/2021 - -**Bugs** - -* Exception will no longer be thrown while extracting text from a particular PDF document. - -## [19.3.48-beta] - 11/02/2021 - -**Bugs** - -* Emoji character preservation issue has been resolved now. - -* Null check exception will no longer be thrown while removing the password from a PDF document. - -## [19.3.47-beta] - 10/26/2021 - -**Features** - -* Provided support to identify whether the TextGlyph is rotated or not. - -## [19.3.46-beta] - 10/19/2021 - -**Bugs** - -* The text search bounds related issue has now been resolved. - -## [19.3.45-beta] - 10/12/2021 - -**Bugs** - -* The PDF destination retrieval related issue has now been resolved. - -## [19.2.56-beta.1] - 08/17/2021 - -**Bugs** - -* Resolved the RangeError while extracting text lines from the PDF document. -* The TextLine extraction bounds related issue has been resolved now. - -## [19.2.56-beta] - 08/17/2021 - -**Features** - -* Provided the support to get or set rotation in an existing PDF page. - -## [19.2.48-beta] - 07/20/2021 - -**Bugs** - -* The white space missing issue while extracting text has been resolved now. -* The unhandled exception when encrypting PDF document is resolved now. - -## [19.2.44-beta] - 06/30/2021 - -**Features** - -* Provided the support to import and export form fields. -* Provided the support to add skew transformation in PDF graphics. - -**Bugs** - -* The text extraction issue has been resolved now. -* The document corruption issue while removing pages has been resolved now. - -## [19.1.67-beta] - 06/08/2021 - -**Bugs** - -* The wrong text bounds calculation issue has been resolved now. - -## [19.1.54-beta] - 03/30/2021 - -**Breaking changes** - -* The property flatten has been removed from the `PdfAnnotation` and `PdfAnnotationCollection`. And added a new method called `flatten` and `flattenAllAnnotations` instead. - -**Features** - -* Provided the support to add image position in the PDF grid cell. -* Provided the support to set clip using the path data on the PDF graphics. -* Provided the support to add encryption options when protecting the PDF files. -* Provided the support to create, read, modify, fill, and flatten PDF form fields. -* Provided the support to digitally sign the PDF document. - -**Bugs** - -* The wrong header row index retrieved from the PDF grid begin cell callback has been resolved now. - -## [18.4.48-beta] - 03/23/2021 - -**Bugs** - -* The page size is not updated properly when adding margins issue resolved now. - -## [18.4.43-beta] - 02/16/2021 - -**Bugs** - -* The bookmark Unicode text preservation issue resolved now. - -## [18.4.42-beta] - 02/09/2021 - -**Bugs** - -* The unhandled exception when adding watermarks to the PDF document is resolved now. - -## [18.4.41-beta] - 02/02/2021 - -**Bugs** - -* The text rendering issue while using the PdfTextElement is resolved now. - -## [18.4.34-beta] - 01/12/2021 - -**Features** - -* Provided the support to set clip using path data on the PDF graphics. - -## [18.4.32-beta] - 12/30/2020 - -**Features** - -* Provided the support to add image position in PDF grid cell. - -## [18.4.31-beta] - 12/22/2020 - -**Bugs** - -* The header row index issue has been resolved now. - -## [18.4.30-beta] - 12/17/2020 - -**Breaking changes** - -* The `extractTextWithLine` method has been removed and added a new `extractTextLines` method instead. - -**Features** - -* Provided the support to encrypt or decrypt a PDF document. -* Provided the support to create, read, and edit layers in PDF documents. -* Provided the support to create a PDF conformance document. -* Provided the support to extract text with the layout. -* Provided the support to draw an image with pagination. -* Provided the support to add an attachment to the PDF document. -* Provided the support to add the document information in a PDF document. - -**Bugs** - -* The bookmark parsing issue has been resolved now. - -## [18.3.52-beta] - 12/01/2020 - -* The method `extractTextWithLine` from `PdfTextExtractor` has been deprecated and added new method called `extractTextLines` instead. - -## [18.3.51-beta] - 11/24/2020 - -**Bugs** - -* The typecasting issue has been resolved now. - -## [18.3.35-beta] - 10/01/2020 - -**Features** - -* Support provided to parse the existing PDF document. -* Support provided to add or remove the PDF pages in an existing PDF document. -* Support provided to add the graphical content to the existing PDF document page. -* Provided the incremental update support for the existing PDF document. -* Support provided to create and load the annotations in a new or existing PDF document. -* Support provided to load the existing PDF document bookmarks with its destination. -* Support provided to extract the text in an existing PDF document along with its bounds. -* Support provided to find the text in an existing PDF document along with its bounds and page index. -* Support provided to flatten the supported annotations in an existing PDF document. -* Support provided to save the PDF document with a cross-reference stream. - -## [18.2.59-beta.1] - 09/24/2020 - -**Bugs** - -* The meta package issue has been resolved now. - -## [18.1.52-beta] - 05/14/2020 - -**Bugs** - -* Text will be preserved properly while using the TrueType font. - -## [18.1.36-beta] - 03/19/2020 - -Initial release - -**Features** - -* Provided the support for creating a PDF document with pages and sections. -* Provided the support for adding text, images, shapes, and more. -* Provided the support for adding Unicode text with True Type font. -* Provided the support for drawing right-to-left (RTL) language text with True Type font. -* Provided the support to create a customizable table. -* Provided the support to create a table using DataTable as an external source. -* Provided the support for adding headers and footers with text, images, shapes, and dynamic fields such as page numbers, date and time, and more. -* Provided the support for adding a flow layout text using PdfTextElement. -* Provided the support for bullets and lists with more customization -* Provided the support for creating bookmarks to the PDF. -* Provided the support for drawing images (JPEG and PNG only) to the PDF document. -* Provided the support for adding hyperlinks and internal document navigations. -* Provided the support for color, pen, and brushes. -* Provided the support for adding Chinese, Japanese, and Korean text with the standard CJK fonts. -* Provided the support for creating and drawing PdfTemplates. +## [31.2.16] - 12/02/2025 + +- No changes. + +## [31.2.15] - 11/25/2025 + +**Bugs** + +- Resolved an issue where the time zone sign and the offset value were incorrect for negative offset time zones in the PdfSignature dictionary. + +## [31.2.12] - 11/18/2025 + +- No changes. + +## [31.2.10] - 11/12/2025 + +- No changes. + +## [31.2.5] - 11/04/2025 + +- No changes. + +## [31.2.4] - 10/28/2025 + +- No changes. + +## [31.2.3] - 10/22/2025 + +- No changes. + +## [31.2.2] - 10/15/2025 + +- No changes. + +## [31.1.23] - 10/07/2025 + +**Bugs** + +- Resolved an issue where the application freezes when extracting text from a specific PDF document + +## [31.1.22] - 10/01/2025 + +- No changes. + +## [31.1.21] - 09/23/2025 + +- No changes. + +## [31.1.20] - 09/17/2025 + +**Bugs** + +- Resolved a typecast error encountered while accessing a form in a specific PDF document. + +## [31.1.19] - 09/12/2025 + +- No changes. + +## [31.1.18] - 09/10/2025 + +- No changes. + +## [31.1.17] - 09/05/2025 + +- No changes. + +## [30.2.7] - 08/26/2025 + +**Bugs** + +- Resolved an issue related to incorrect glyph bounding in a specific PDF document. + +## [30.2.6] - 08/19/2025 + +**Bugs** + +- Fixed performance lag during loading encrypted PDF document. + +## [30.2.5] - 08/13/2025 + +**Bugs** + +- Resolved an issue where the application hangs when accessing the read-only value of a form field in a specific PDF document. + +## [30.2.4] - 08/07/2025 + +**Bugs** + +* Resolved an issue while extracting text line bounds from 90-degree rotated pages in a specific PDF document. + +## [30.1.41] - 07/22/2025 + +**Bugs** + +* Resolved an exception that occurred when removing document-level layers in a specific PDF document. + +## [30.1.37] - 06/25/2025 + +**General** + +* The compatible version of our Flutter PDF library has been updated to Flutter SDK 3.32.0. + +## [29.2.11] - 06/17/2025 + +**Bugs** + +* Resolved an exception that occurred when hiding document-level layers in a specific PDF document. + +## [29.2.9] - 06/05/2025 + +**Bugs** + +* Resolved a mismatch error in the text word length and text glyph length from a specific PDF document. + +## [29.2.7] - 05/27/2025 + +**Bugs** + +* Resolved a range error exception while extracting text lines from a specific PDF document. + +## [29.2.4] - 05/14/2025 + +**Bugs** + +* Resolved an Out-Of-Memory crash that occurred during the decryption of PDF document. +* Resolved a performance issue when decrypting password-protected PDF documents. + +## [29.1.41] - 05/06/2025 + +**Bugs** + +* Resolved an issue where an exception occurred when flattening a signature field in a PDF document. + +## [29.1.40] - 04/29/2025 + +**Bugs** + +* Resolved a content preservation issue that occurred when drawing multiple PDF grids on the same page of a PDF document. +* Resolved an issue where PDF form is returned as null when acro form has no fields. + +## [29.1.39] - 04/22/2025 + +**General** + +* The minimum Dart version has been updated to 3.7. + +## [29.1.38] - 04/15/2025 + +**Bugs** + +* Resolved an issue where the null check operator was incorrectly used on a nullable value. +* Resolved an issue where the PDF was shifting towards the top right corner when drawing existing page templates on PDFs. +* Exception occurs when getting the bounds of the text box form field item in a document has been resolved. + +## [29.1.37] - 04/08/2025 + +**Bugs** + +* Resolved the invalid cross reference table issue occurs while loading the specific PDF document. +* Resolved the Layer name not preserved properly while removing layers in the PDF document + +## [29.1.35] - 04/01/2025 + +**Bugs** + +* Resolved the exception that occurred while decrypting PDF files on the Flutter web platform. + +## [29.1.33] - 03/25/2025 + +**General** + +* The compatible version of our Flutter PDF library has been updated to Flutter SDK 3.29.0. +* The Syncfusion® Flutter PDF example sample have been updated to support [kotlin build scripts](https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply) in Android platform. +* The Syncfusion® Flutter PDF example sample have been updated to support [Swift package manager](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers) in macOS and iOS platforms. + +**Bugs** + +* Fixed incorrect TextWord bounds when extracting text from a cropped PDF document. + +## [28.2.9] - 03/04/2025 + +**General** + +* The minimum Dart version of our Flutter widgets has been updated to 3.4 from 3.3. + +**Bugs** + +* Resolved the TypeError occurs when getting the bounds of the form field in a specific document + +## [28.2.7] - 02/25/2025 + +**Bugs** + +* Resolved the Performance issue occurs while decrypting the pdf + +## [28.2.5] - 02/11/2025 + +**Bugs** + +* Resolved the Format exception occurs while extracting the text from the PDF document + +## [28.2.4] - 02/04/2025 + +**Bugs** + +* Resolved the preservation issue when filling the multiline text box field. +* Typecasting issue occurs while loading the checkbox fields in the PDF document has been resolved. + +## [28.1.39] - 01/14/2025 + +**Bugs** + +* Resolved an issue where Unicode characters were not correctly recognized during text extraction from PDF documents. + +## [28.1.38] - 01/07/2025 + +**Bugs** + +* The preservation issue encountered when adding annotations to a document has been resolved. + +## [27.2.3] - 11/22/2024 + +**Bugs** + +* The issue of the signature appearance being duplicated when viewing the resultant PDF in the Syncfusion® viewer has been resolved. + +## [27.2.2] - 11/15/2024 + +**Bugs** + +* The format exception that occurred while signing the document with a specific certificate using an external signer has been resolved. + +## [27.1.58] - 11/5/2024 + +**Bugs** + +* The issue of an exception occurring when drawing emoji symbols in PDF form fields has been resolved. + +## [27.1.55] - 10/22/2024 + +**Bugs** + +* Type casting issue occurs while extracting text lines from a specific PDF document has been resolved. + +## [27.1.52] - 10/08/2024 + +**Bugs** + +* The issue of the file being corrupted while inserting a page into an existing PDF document has been resolved. + +## [27.1.50] - 09/24/2024 + +**Bugs** + +* Type casting issue occurs while loading annotations from the PDF document has been resolved. +* The issue where file size did not decrease after removing pages from the PDF document has been resolved. + +## [26.2.14] - 09/10/2024 + +**General** + +* The compatible version of our Flutter PDF library has been updated to Flutter SDK 3.24.0. + +**Bugs** + +* The issue of incorrect bounds being retrieved from text markup annotations created with the Firefox PDF viewer has been resolved. + +## [26.2.10] - 08/20/2024 + +**Bugs** + +* Exception will no longer be thrown while extracting text from a particular PDF document. + +## [26.2.9] - 08/13/2024 + +**Bugs** + +* Text will now be properly extracted in the Safari browser on macOS. + +## [26.2.7] - 07/30/2024 + +**Bugs** + +* The text color now remains consistent after decrypting and saving the PDF document. + +## [26.2.4] - 07/24/2024 + +**Bugs** + +* Incorrect bounds are no longer being retrieved when extracting text from a specific PDF document. + +## [26.1.42] - 07/16/2024 + +**Bugs** + +* The issue causing null check errors when retrieving items from a radio button field in the PDF document has been resolved. + +* The issue with type casting no longer occurs when retrieving annotations from a PDF document. + +## [26.1.41] - 07/09/2024 + +**Bugs** + +* The performance issue no longer occurs when reading the signature field from the PDF document. + +* The type cast issue no longer occurs when flattening the signature in a specific PDF document. + +## [26.1.40] - 07/02/2024 + +**Bugs** + +* High memory consumption will no longer occur while extracting text from large PDF documents. + +## [26.1.38] - 06/19/2024 + +**Bugs** + +* Extracting text lines now returns the proper bounds for the CID font type in the PDF document. + +* Performance issue no longer occurs while extracting text lines from the PDF document. + +## [26.1.35] - 06/11/2024 + +**Features** + +* Provided support for adding timestamp and LTV in PDF signature. + +## [25.2.6] - 05/28/2024 + +**Bugs** + +* Resolved the issue where flattening some form fields was not working in a specific PDF document. + +## [25.2.5] - 05/21/2024 + +**Bugs** + +* Preservation issues no longer occur when drawing on a page with negative crop box x and y coordinates. + +## [25.1.42] - 04/30/2024 + +**Bugs** + +* Extracting text from an encrypted PDF document will no longer significantly increase file size and corrupt the document. + +## [25.1.41] - 04/23/2024 + +**Bugs** + +* The existing signature no longer becomes invalid when adding a second signature to the PDF document. + +## [25.1.39] - 04/09/2024 + +**Bugs** + +* RangeError will no longer occur while extracting text lines from the PDF document. + +## [25.1.37] - 03/26/2024 + +**Bugs** + +* Preservation issue will no longer occur while flattening the signature field in the PDF document. + +* The issue with the invalid signature has been resolved when signing the PDF document. + +## [25.1.35] - 03/15/2024 + +**Breaking changes** + +* The `sign` method in the `IPdfExternalSigner` class has been changed to an asynchronous type, and the `signSync` method has been added for synchronous signing. + +**Features** + +* Provided support for importing and exporting annotations in the PDF document. + +* Provided support for asynchronous external signing in the PDF document. + +## [24.2.8] - 02/27/2024 + +**Bugs** + +* Resolved the issue where extracting text returns incorrect results for a specific PDF document. + +* Invalid font name error will no longer occur when extracting text from specific PDF document. + +## [24.2.5] - 02/13/2024 + +**Bugs** + +* Extracting text lines will no longer return incorrect results for specific PDF documents. + +## [24.2.4] - 02/06/2024 + +**Bugs** + +* Find text related issues are now resolved in PDF documents. + +* Extract text is now working properly in specific PDF document. + +## [24.2.3] - 01/31/2024 + +**Features** + +* Provided support to check and uncheck the check box field items. + +## [24.1.46] - 01/17/2024 + +**General** + +* Upgraded the `intl` package to the latest version 0.19.0. + +## [24.1.45] - 01/09/2024 + +**Bugs** + +* Preservation failure no longer occurs in Mac PDF viewer while saving specific encrypted PDF document. + +## [24.1.44] - 01/03/2023 + +**Bugs** + +* Null check error will no longer occur while removing pages from the PDF document. + +## [24.1.43] - 12/27/2023 + +**Bugs** + +* Preservation issue will no longer occur while flattening text box field in specific PDF document. + +## [24.1.41] - 12/18/2023 + +**Features** + +* Provided support for text markup and popup annotations. + +* Provided support for adding annotation flags to PDF annotations. + +**Bugs** + +* The issue of retrieving incorrect values from the text box field after saving an encrypted PDF document has been resolved. + +## [23.1.44] - 11/07/2023 + +**Bugs** + +* The null reference exception that occurred while retrieving the page from the form fields in the PDF has been resolved. + +## [23.1.40] - 10/10/2023 + +**Bugs** + +* Resolved the incorrect image dimension recording in PdfBitmap. + +## [23.1.39] - 10/04/2023 + +**Features** + +* Support has been provided for back color, border color, and border style in the PDF signature field. + +## [22.2.11] - 08/29/2023 + +**Bugs** + +* High memory consumption will no longer occurs while extracting text from large PDF documents. + +* Null check exceptions will no longer occur while drawing PDF grid in a loaded page. + +## [22.2.9] - 08/15/2023 + +**Bugs** + +* Null reference exceptions will no longer occur when retrieving form fields from the PDF document. + +## [22.2.5] - 07/27/2023 + +**Bugs** + +* Resolved white background preservation while flattening loaded empty signature field. + +* Type casting issue no longer occurs while flattening specific PDF document. + +## [22.1.36] - 06/28/2023 + +**Bugs** + +* Resolved the space between text missing issue in the extract text layout and lines. + +* PDF signature added with signed name is now valid in Adobe viewer. + +## [21.2.4] - 05/09/2023 + +**Bugs** + +* Null reference exceptions will no longer occur while getting form fields from the PDF document. + +* Now, spaces are preserved properly when extracting text with the layout. + +* The preservation issue no longer occurs after modifying the values in the fields of the PDF document. + +## [21.1.41] - 04/18/2023 + +**Bugs** + +* The unhandled exception that occurred during the extraction of text and flattening of form fields in the PDF document has been resolved. + +## [21.1.39] - 04/11/2023 + +**Bugs** + +* RTL bookmark title is now properly retrieved from Encrypted PDF documents. + +## [21.1.37] - 03/29/2023 + +**Bugs** + +* Text words are now properly split while extracting text from PDF documents. + +## [20.4.54] - 03/15/2023 + +**Bugs** + +* The issue of PDF document size increasing after removing pages has been resolved. + +## [20.4.50] - 02/14/2023 + +**Bugs** + +* Resolved the document corruption exception when signing existing signed PDF documents. + +* Text bounds are now retrieved properly when finding text from cropped PDF documents. + +## [20.3.57] - 11/15/2022 + +**Bugs** + +* Alpha channel is not initialized properly in transparent brush is now resolved. + +## [20.3.56] - 11/08/2022 + +**Features** + +* Provided support to set signed date while signing the pdf document. + +## [20.2.48] - 09/06/2022 + +**Bugs** + +* The type casting issue when trying to get annotation is now resolved. + +## [20.2.45] - 08/23/2022 + +**Bugs** + +* The font is not updated properly for loaded form fields is now resolved. + +## [20.2.36] - 06/30/2022 + +**Breaking changes** + +* The `save` method has been changed to an asynchronous type in the `PdfDocument` and the `saveSync` method has been added for synchronous. + +**Features** + +* Provided asynchronous save support for PDF documents. + +**Bugs** + +* The preservation issue when flattening the PDF text box field is now resolved. + +* Resolved the document corruption issue while modifying encrypted PDF document. + +## [20.1.48-beta] - 04/12/2022 + +**Bugs** + +* The layout issue when extracting text from the PDF document is now resolved. + +## [20.1.47-beta] - 04/04/2022 + +**Features** + +* Provided support to extract RTL text from an existing PDF document along with its bounds. + +* Provided support to find RTL text in an existing PDF document. + +**Known Limitation** + +* Combination of RTL and LTR text in find operations will not work. For example "80٪ خصم في المحدد jeans". + +## [19.4.41-beta] - 01/04/2022 + +**Bugs** + +* Typecasting exceptions will no longer occur while extracting text from the PDF document. + +## [19.3.55-beta] - 11/23/2021 + +**Bugs** + +* Exception will no longer be thrown while extracting text from a particular PDF document. + +## [19.3.48-beta] - 11/02/2021 + +**Bugs** + +* Emoji character preservation issue has been resolved now. + +* Null check exception will no longer be thrown while removing the password from a PDF document. + +## [19.3.47-beta] - 10/26/2021 + +**Features** + +* Provided support to identify whether the TextGlyph is rotated or not. + +## [19.3.46-beta] - 10/19/2021 + +**Bugs** + +* The text search bounds related issue has now been resolved. + +## [19.3.45-beta] - 10/12/2021 + +**Bugs** + +* The PDF destination retrieval related issue has now been resolved. + +## [19.2.56-beta.1] - 08/17/2021 + +**Bugs** + +* Resolved the RangeError while extracting text lines from the PDF document. +* The TextLine extraction bounds related issue has been resolved now. + +## [19.2.56-beta] - 08/17/2021 + +**Features** + +* Provided the support to get or set rotation in an existing PDF page. + +## [19.2.48-beta] - 07/20/2021 + +**Bugs** + +* The white space missing issue while extracting text has been resolved now. +* The unhandled exception when encrypting PDF document is resolved now. + +## [19.2.44-beta] - 06/30/2021 + +**Features** + +* Provided the support to import and export form fields. +* Provided the support to add skew transformation in PDF graphics. + +**Bugs** + +* The text extraction issue has been resolved now. +* The document corruption issue while removing pages has been resolved now. + +## [19.1.67-beta] - 06/08/2021 + +**Bugs** + +* The wrong text bounds calculation issue has been resolved now. + +## [19.1.54-beta] - 03/30/2021 + +**Breaking changes** + +* The property flatten has been removed from the `PdfAnnotation` and `PdfAnnotationCollection`. And added a new method called `flatten` and `flattenAllAnnotations` instead. + +**Features** + +* Provided the support to add image position in the PDF grid cell. +* Provided the support to set clip using the path data on the PDF graphics. +* Provided the support to add encryption options when protecting the PDF files. +* Provided the support to create, read, modify, fill, and flatten PDF form fields. +* Provided the support to digitally sign the PDF document. + +**Bugs** + +* The wrong header row index retrieved from the PDF grid begin cell callback has been resolved now. + +## [18.4.48-beta] - 03/23/2021 + +**Bugs** + +* The page size is not updated properly when adding margins issue resolved now. + +## [18.4.43-beta] - 02/16/2021 + +**Bugs** + +* The bookmark Unicode text preservation issue resolved now. + +## [18.4.42-beta] - 02/09/2021 + +**Bugs** + +* The unhandled exception when adding watermarks to the PDF document is resolved now. + +## [18.4.41-beta] - 02/02/2021 + +**Bugs** + +* The text rendering issue while using the PdfTextElement is resolved now. + +## [18.4.34-beta] - 01/12/2021 + +**Features** + +* Provided the support to set clip using path data on the PDF graphics. + +## [18.4.32-beta] - 12/30/2020 + +**Features** + +* Provided the support to add image position in PDF grid cell. + +## [18.4.31-beta] - 12/22/2020 + +**Bugs** + +* The header row index issue has been resolved now. + +## [18.4.30-beta] - 12/17/2020 + +**Breaking changes** + +* The `extractTextWithLine` method has been removed and added a new `extractTextLines` method instead. + +**Features** + +* Provided the support to encrypt or decrypt a PDF document. +* Provided the support to create, read, and edit layers in PDF documents. +* Provided the support to create a PDF conformance document. +* Provided the support to extract text with the layout. +* Provided the support to draw an image with pagination. +* Provided the support to add an attachment to the PDF document. +* Provided the support to add the document information in a PDF document. + +**Bugs** + +* The bookmark parsing issue has been resolved now. + +## [18.3.52-beta] - 12/01/2020 + +* The method `extractTextWithLine` from `PdfTextExtractor` has been deprecated and added new method called `extractTextLines` instead. + +## [18.3.51-beta] - 11/24/2020 + +**Bugs** + +* The typecasting issue has been resolved now. + +## [18.3.35-beta] - 10/01/2020 + +**Features** + +* Support provided to parse the existing PDF document. +* Support provided to add or remove the PDF pages in an existing PDF document. +* Support provided to add the graphical content to the existing PDF document page. +* Provided the incremental update support for the existing PDF document. +* Support provided to create and load the annotations in a new or existing PDF document. +* Support provided to load the existing PDF document bookmarks with its destination. +* Support provided to extract the text in an existing PDF document along with its bounds. +* Support provided to find the text in an existing PDF document along with its bounds and page index. +* Support provided to flatten the supported annotations in an existing PDF document. +* Support provided to save the PDF document with a cross-reference stream. + +## [18.2.59-beta.1] - 09/24/2020 + +**Bugs** + +* The meta package issue has been resolved now. + +## [18.1.52-beta] - 05/14/2020 + +**Bugs** + +* Text will be preserved properly while using the TrueType font. + +## [18.1.36-beta] - 03/19/2020 + +Initial release + +**Features** + +* Provided the support for creating a PDF document with pages and sections. +* Provided the support for adding text, images, shapes, and more. +* Provided the support for adding Unicode text with True Type font. +* Provided the support for drawing right-to-left (RTL) language text with True Type font. +* Provided the support to create a customizable table. +* Provided the support to create a table using DataTable as an external source. +* Provided the support for adding headers and footers with text, images, shapes, and dynamic fields such as page numbers, date and time, and more. +* Provided the support for adding a flow layout text using PdfTextElement. +* Provided the support for bullets and lists with more customization +* Provided the support for creating bookmarks to the PDF. +* Provided the support for drawing images (JPEG and PNG only) to the PDF document. +* Provided the support for adding hyperlinks and internal document navigations. +* Provided the support for color, pen, and brushes. +* Provided the support for adding Chinese, Japanese, and Korean text with the standard CJK fonts. +* Provided the support for creating and drawing PdfTemplates. diff --git a/packages/syncfusion_flutter_pdf/LICENSE b/packages/syncfusion_flutter_pdf/LICENSE index 9b5e95bb8..56aafe0d8 100644 --- a/packages/syncfusion_flutter_pdf/LICENSE +++ b/packages/syncfusion_flutter_pdf/LICENSE @@ -1,14 +1,14 @@ -Syncfusion License - -Syncfusion Flutter PDF package is available under the Syncfusion Essential Studio program, and can be licensed either under the Syncfusion Community License Program or the Syncfusion commercial license. - -To be qualified for the Syncfusion Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion’s terms and conditions. - -Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. - -Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion’s license containing all terms and conditions. - -The Syncfusion license that contains the terms and conditions can be found at -https://www.syncfusion.com/content/downloads/syncfusion_license.pdf - -Syncfusion provides implementation but you would subsequently need to have a license to use Flutter. The Flutter engine must be licensed from google directly. We do not license Flutter or the Flutter Engine and provide no license or rights even if you end up with the binaries from us by mistake. +Syncfusion® License + +Syncfusion® Flutter PDF package is available under the Syncfusion Essential Studio® program, and can be licensed either under the Syncfusion® Community License Program or the Syncfusion® commercial license. + +To be qualified for the Syncfusion® Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion®’s terms and conditions. + +Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options. + +Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion®’s license containing all terms and conditions. + +The Syncfusion® license that contains the terms and conditions can be found at +https://www.syncfusion.com/content/downloads/syncfusion_license.pdf + +Syncfusion® provides implementation but you would subsequently need to have a license to use Flutter. The Flutter engine must be licensed from google directly. We do not license Flutter or the Flutter Engine and provide no license or rights even if you end up with the binaries from us by mistake. diff --git a/packages/syncfusion_flutter_pdf/README.md b/packages/syncfusion_flutter_pdf/README.md index 248d5abd3..c4d008d13 100644 --- a/packages/syncfusion_flutter_pdf/README.md +++ b/packages/syncfusion_flutter_pdf/README.md @@ -1,661 +1,660 @@ -![syncfusion_flutter_pdf_banner](https://cdn.syncfusion.com/content/images/FTControl/Flutter-PDF-Banner.png) - -# Flutter PDF library - -Flutter PDF is a feature-rich and high-performance non-UI PDF library written natively in Dart. It allows you to add robust PDF functionalities to Flutter applications. - -See an interactive demo here: https://flutter.syncfusion.com/#/pdf/invoice - -## Overview - -The PDF package is a non-UI, reusable Flutter library for creating PDF reports programmatically with formatted text, images, shapes, tables, links, lists, headers, footers, and more. The library can be used to create, read, edit, and secure PDF documents in Flutter mobile and web platforms without dependency on Adobe Acrobat. The creation of a PDF follows the most popular PDF 1.7 (ISO 32000-1) and latest PDF 2.0 (ISO 32000-2) specifications. - -**Disclaimer:** This is a commercial package. To use this package, you need to have either a Syncfusion commercial license or [Free Syncfusion Community license](https://www.syncfusion.com/products/communitylicense). For more details, please check the [LICENSE](https://github.com/syncfusion/flutter-examples/blob/master/LICENSE) file. - -![PDF Overview](https://cdn.syncfusion.com/content/images/FTControl/Flutter/Flutter-PDF-Overview.png) - -## Table of contents -- [Key features](#key-features) -- [Get the demo application](#get-the-demo-application) -- [Useful links](#useful-links) -- [Installation](#installation) -- [Getting started](#getting-started) - - [Create a PDF document from simple text](#create-a-pdf-document-from-simple-text) - - [Add text using TrueType fonts](#add-text-using-truetype-fonts) - - [Add images to a PDF document](#add-images-to-a-pdf-document) - - [PDF document with flow layout](#pdf-document-with-flow-layout) - - [Add bullets and lists](#add-bullets-and-lists) - - [Add tables](#add-tables) - - [Add headers and footers](#add-headers-and-footers) - - [Load and modify an existing PDF document](#load-and-modify-an-existing-pdf-document) - - [Create and load annotations](#create-and-load-annotations) - - [Add bookmarks](#add-bookmarks) - - [Extract text](#extract-text) - - [Find text](#find-text) - - [Encryption and decryption](#encryption-and-decryption) - - [PDF conformance](#pdf-conformance) - - [PDF form](#pdf-form) - - [Digital signature](#digital-signature) -- [Support and feedback](#support-and-feedback) -- [About Syncfusion](#about-syncfusion) - -## Key features - -The following are the key features of Syncfusion Flutter PDF: - -* Create multipage PDF files from scratch. -* Add Unicode and RTL text. -* Insert JPEG and PNG images in the PDF document. -* Generate tables in PDF files with different styles and formats. -* Add headers and footers. -* Add different shapes to PDF files. -* Add paragraphs, bullets, and lists. -* Open, modify, and save existing PDF files. -* Encrypt and decrypt PDF files with advanced standards. -* Add, modify, and remove interactive elements such as bookmarks, annotations, hyperlinks, and attachments. -* Create PDF/A-1B, PDF/A-2B, PDF/A-3B conformances. -* Digitally sign PDF documents. -* Use on mobile and web platforms. - -## Get the demo application - -Explore the full capability of our Flutter widgets on your device by installing our sample browser application from the following app stores and viewing the sample code in GitHub. - -

- - - -

-

- - - -

- -## Other useful links - -Take a look at the following to learn more about Syncfusion Flutter PDF: - -* [Syncfusion Flutter PDF product page](https://www.syncfusion.com/flutter-widgets/pdf-library) -* [User guide documentation](https://help.syncfusion.com/flutter/pdf/overview) -* [Knowledge base](https://www.syncfusion.com/kb) - -## Installation - -Install the latest version from [pub.dev](https://pub.dartlang.org/packages/syncfusion_flutter_pdf#-installing-tab-). - -## Getting started - -Import the following package to your project to create a PDF document from scratch. - -```dart -import 'package:syncfusion_flutter_pdf/pdf.dart'; -``` - -### Create a PDF document from simple text - -Add the following code to create a simple PDF document. - -```dart -// Create a new PDF document. -final PdfDocument document = PdfDocument(); -// Add a PDF page and draw text. -document.pages.add().graphics.drawString( - 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - brush: PdfSolidBrush(PdfColor(0, 0, 0)), - bounds: const Rect.fromLTWH(0, 0, 150, 20)); -// Save the document. -File('HelloWorld.pdf').writeAsBytes(await document.save()); -// Dispose the document. -document.dispose(); -``` - -### Add text using TrueType fonts - -Use the following code to add a Unicode text to the PDF document. - -```dart -//Create a new PDF document. -final PdfDocument document = PdfDocument(); -//Read font data. -final Uint8List fontData = File('arial.ttf').readAsBytesSync(); -//Create a PDF true type font object. -final PdfFont font = PdfTrueTypeFont(fontData, 12); -//Draw text using ttf font. -document.pages.add().graphics.drawString('Hello World!!!', font, - bounds: const Rect.fromLTWH(0, 0, 200, 50)); -// Save the document. -File('TrueType.pdf').writeAsBytes(await document.save()); -// Dispose the document. -document.dispose(); -``` - -### Add images to a PDF document - -The PdfBitmap class is used to draw images in a PDF document. Syncfusion Flutter PDF supports PNG and JPEG images. Refer to the following code to draw images in a PDF document. - -```dart -//Create a new PDF document. -final PdfDocument document = PdfDocument(); -//Read image data. -final Uint8List imageData = File('input.png').readAsBytesSync(); -//Load the image using PdfBitmap. -final PdfBitmap image = PdfBitmap(imageData); -//Draw the image to the PDF page. -document.pages - .add() - .graphics - .drawImage(image, const Rect.fromLTWH(0, 0, 500, 200)); -// Save the document. -File('ImageToPDF.pdf').writeAsBytes(await document.save()); -// Dispose the document. -document.dispose(); -``` - -### PDF document with flow layout - -Add the following code to create a PDF document with flow layout. - -```dart -const String paragraphText = - 'Adobe Systems Incorporated\'s Portable Document Format (PDF) is the de facto' - 'standard for the accurate, reliable, and platform-independent representation of a paged' - 'document. It\'s the only universally accepted file format that allows pixel-perfect layouts.' - 'In addition, PDF supports user interaction and collaborative workflows that are not' - 'possible with printed documents.'; - -// Create a new PDF document. -final PdfDocument document = PdfDocument(); -// Add a new page to the document. -final PdfPage page = document.pages.add(); -// Create a new PDF text element class and draw the flow layout text. -final PdfLayoutResult layoutResult = PdfTextElement( - text: paragraphText, - font: PdfStandardFont(PdfFontFamily.helvetica, 12), - brush: PdfSolidBrush(PdfColor(0, 0, 0))) - .draw( - page: page, - bounds: Rect.fromLTWH( - 0, 0, page.getClientSize().width, page.getClientSize().height), - format: PdfLayoutFormat(layoutType: PdfLayoutType.paginate))!; -// Draw the next paragraph/content. -page.graphics.drawLine( - PdfPen(PdfColor(255, 0, 0)), - Offset(0, layoutResult.bounds.bottom + 10), - Offset(page.getClientSize().width, layoutResult.bounds.bottom + 10)); -// Save the document. -File('TextFlow.pdf').writeAsBytes(await document.save()); -// Dispose the document. -document.dispose(); -``` - -### Add bullets and lists - -Add the following code to create bullets and lists in a PDF document. - -```dart -// Create a new PDF document. -final PdfDocument document = PdfDocument(); -// Add a new page to the document. -final PdfPage page = document.pages.add(); -// Create a PDF ordered list. -final PdfOrderedList orderedList = PdfOrderedList( - items: PdfListItemCollection([ - 'Mammals', - 'Reptiles', - 'Birds', - 'Insects', - 'Aquatic Animals' - ]), - marker: PdfOrderedMarker( - style: PdfNumberStyle.numeric, - font: PdfStandardFont(PdfFontFamily.helvetica, 12)), - markerHierarchy: true, - format: PdfStringFormat(lineSpacing: 10), - textIndent: 10); -// Create a un ordered list and add it as a sublist. -orderedList.items[0].subList = PdfUnorderedList( - marker: PdfUnorderedMarker( - font: PdfStandardFont(PdfFontFamily.helvetica, 10), - style: PdfUnorderedMarkerStyle.disk), - items: PdfListItemCollection([ - 'body covered by hair or fur', - 'warm-blooded', - 'have a backbone', - 'produce milk', - 'Examples' - ]), - textIndent: 10, - indent: 20); -// Draw the list to the PDF page. -orderedList.draw( - page: page, - bounds: Rect.fromLTWH( - 0, 0, page.getClientSize().width, page.getClientSize().height)); -// Save the document. -File('BulletandList.pdf').writeAsBytes(await document.save()); -// Dispose the document. -document.dispose(); -``` - -### Add tables - -Add the following code to create a PDF table. - -```dart -// Create a new PDF document. -final PdfDocument document = PdfDocument(); -// Add a new page to the document. -final PdfPage page = document.pages.add(); -// Create a PDF grid class to add tables. -final PdfGrid grid = PdfGrid(); -// Specify the grid column count. -grid.columns.add(count: 3); -// Add a grid header row. -final PdfGridRow headerRow = grid.headers.add(1)[0]; -headerRow.cells[0].value = 'Customer ID'; -headerRow.cells[1].value = 'Contact Name'; -headerRow.cells[2].value = 'Country'; -// Set header font. -headerRow.style.font = - PdfStandardFont(PdfFontFamily.helvetica, 10, style: PdfFontStyle.bold); -// Add rows to the grid. -PdfGridRow row = grid.rows.add(); -row.cells[0].value = 'ALFKI'; -row.cells[1].value = 'Maria Anders'; -row.cells[2].value = 'Germany'; -// Add next row. -row = grid.rows.add(); -row.cells[0].value = 'ANATR'; -row.cells[1].value = 'Ana Trujillo'; -row.cells[2].value = 'Mexico'; -// Add next row. -row = grid.rows.add(); -row.cells[0].value = 'ANTON'; -row.cells[1].value = 'Antonio Mereno'; -row.cells[2].value = 'Mexico'; -// Set grid format. -grid.style.cellPadding = PdfPaddings(left: 5, top: 5); -// Draw table in the PDF page. -grid.draw( - page: page, - bounds: Rect.fromLTWH( - 0, 0, page.getClientSize().width, page.getClientSize().height)); -// Save the document. -File('PDFTable.pdf').writeAsBytes(await document.save()); -// Dispose the document. -document.dispose(); -``` - -### Add headers and footers - -Use the following code to add headers and footers to a PDF document. - -```dart -//Create a new PDF document. -final PdfDocument document = PdfDocument(); -//Create a PDF page template and add header content. -final PdfPageTemplateElement headerTemplate = - PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); -//Draw text in the header. -headerTemplate.graphics.drawString( - 'This is page header', PdfStandardFont(PdfFontFamily.helvetica, 12), - bounds: const Rect.fromLTWH(0, 15, 200, 20)); -//Add the header element to the document. -document.template.top = headerTemplate; -//Create a PDF page template and add footer content. -final PdfPageTemplateElement footerTemplate = - PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); -//Draw text in the footer. -footerTemplate.graphics.drawString( - 'This is page footer', PdfStandardFont(PdfFontFamily.helvetica, 12), - bounds: const Rect.fromLTWH(0, 15, 200, 20)); -//Set footer in the document. -document.template.bottom = footerTemplate; -//Now create pages. -document.pages.add(); -document.pages.add(); -// Save the document. -File('HeaderandFooter.pdf').writeAsBytes(await document.save()); -// Dispose the document. -document.dispose(); -``` - -### Load and modify an existing PDF document - -Add the following code to load and modify the existing PDF document. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); -//Get the existing PDF page. -final PdfPage page = document.pages[0]; -//Draw text in the PDF page. -page.graphics.drawString( - 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - brush: PdfSolidBrush(PdfColor(0, 0, 0)), - bounds: const Rect.fromLTWH(0, 0, 150, 20)); -//Save the document. -File('output.pdf').writeAsBytes(await document.save()); -//Dispose the document. -document.dispose(); -``` - -Add the following code to add or remove a page from the existing PDF document. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); -//Remove the page from the document. -document.pages.removeAt(0); -//Add new page and draw text. -document.pages.add().graphics.drawString( - 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - brush: PdfSolidBrush(PdfColor(0, 0, 0)), - bounds: const Rect.fromLTWH(0, 0, 150, 20)); -//Save the document. -File('output.pdf').writeAsBytes(await document.save()); -//Dispose the document. -document.dispose(); -``` - -### Create and load annotations - -Using this package, we can create and load annotations in a new or existing PDF document. - -Add the following code to create a new annotation in a PDF document. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); -//Create a new rectangle annotation and add to the PDF page. -document.pages[0].annotations.add(PdfRectangleAnnotation( - Rect.fromLTWH(0, 0, 150, 100), 'Rectangle', - color: PdfColor(255, 0, 0), setAppearance: true)); -//Save the document. -File('annotations.pdf').writeAsBytes(await document.save()); -//Dispose the document. -document.dispose(); -``` - -Add the following code to load the annotation and modify it. - -```dart -//Load and modify the existing annotation. -final PdfRectangleAnnotation rectangleAnnotation = - document.pages[0].annotations[0] as PdfRectangleAnnotation; -//Change the annotation text. -rectangleAnnotation.text = 'Changed'; -``` - -Refer to our documentation for more details about [annotations](https://help.syncfusion.com/flutter/pdf/working-with-annotations). - -### Add bookmarks - -Add the following code to create bookmarks in a PDF document. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); -//Create a document bookmark. -final PdfBookmark bookmark = document.bookmarks.add('Page 1'); -//Set the destination page and location. -bookmark.destination = PdfDestination(document.pages[1], Offset(20, 20)); -//Set the bookmark color. -bookmark.color = PdfColor(255, 0, 0); -//Save the document. -File('bookmark.pdf').writeAsBytes(await document.save()); -//Dispose the document. -document.dispose(); -``` - -Refer to our documentation for more details about [bookmarks](https://help.syncfusion.com/flutter/pdf/working-with-bookmarks). - -### Extract text - -Using this package, we can extract text from an existing PDF document along with its bounds. - -Add the following code to extract text from a PDF document. - -```dart -//Load an existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); -//Extract the text from all the pages. -String text = PdfTextExtractor(document).extractText(); -//Dispose the document. -document.dispose(); -``` - -The following code sample explains how to extract text from a specific page. - -```dart -//Load an existing PDF document. -PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); -//Extract the text from page 1. -String text = PdfTextExtractor(document).extractText(startPageIndex: 0); -//Dispose the document. -document.dispose(); -``` - -Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-text-extraction) for more details. - -### Find text - -Using this package, we can find text in an existing PDF document along with its bounds and page index. - -Add the following code to find text in a PDF document. - -```dart -//Load an existing PDF document. -PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); -//Find the text and get matched items. -List textCollection = - PdfTextExtractor(document).findText(['text1', 'text2']); -//Get the matched item in the collection using index. -MatchedItem matchedText = textCollection[0]; -//Get the text bounds. -Rect textBounds = matchedText.bounds; -//Get the page index. -int pageIndex = matchedText.pageIndex; -//Get the text. -String text = matchedText.text; -//Dispose the document. -document.dispose(); -``` - -Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-text-extraction#working-with-find-text) for more details. - -### Encryption and decryption - -Encrypt new or existing PDF documents with encryption standards like 40-bit RC4, 128-bit RC4, 128-bit AES, and 256-bit AES, and the advanced encryption standard 256-bit AES Revision 6 (PDF 2.0) to protect documents against unauthorized access. Using this package, you can also decrypt existing encrypted documents. - -Add the following code to encrypt an existing PDF document. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - -//Add security to the document. -final PdfSecurity security = document.security; - -//Set password. -security.userPassword = 'userpassword@123'; -security.ownerPassword = 'ownerpassword@123'; - -//Set the encryption algorithm. -security.algorithm = PdfEncryptionAlgorithm.aesx256Bit; - -//Save the document. -File('secured.pdf').writeAsBytes(await document.save()); - -//Dispose the document. -document.dispose(); -``` - -Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-security) for more details. - -### PDF conformance - -Using this package, we can create PDF conformance documents, such as: - -* PDF/A-1B -* PDF/A-2B -* PDF/A-3B - -Add the following code to create a PDF conformance document. - -```dart -//Create a PDF conformance document. -final PdfDocument document = PdfDocument(conformanceLevel: PdfConformanceLevel.a1b) - ..pages.add().graphics.drawString('Hello World', - PdfTrueTypeFont(File('Roboto-Regular.ttf').readAsBytesSync(), 12), - bounds: Rect.fromLTWH(20, 20, 200, 50), brush: PdfBrushes.black); -//Save and dispose the document. -File('conformance.pdf').writeAsBytesSync(await document.save()); -document.dispose(); -``` - -Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-pdf-conformance) for more details. - -### PDF form - -PDF forms provide the best way to collect information from users. Using this package, we can create, modify, fill, and flatten PDF forms. - -Add the following code to create PDF form. - -```dart -//Create a new PDF document. -PdfDocument document = PdfDocument(); - -//Create a new page to add form fields. -PdfPage page = document.pages.add(); - -//Create text box field and add to the forms collection. -document.form.fields.add(PdfTextBoxField( - page, 'firstname', Rect.fromLTWH(0, 0, 100, 20), - text: 'John')); - -//Create check box field and add to the form. -document.form.fields.add(PdfCheckBoxField( - page, 'checkbox', Rect.fromLTWH(150, 0, 30, 30), - isChecked: true)); - -//Save and dispose the document. -File('form.pdf').writeAsBytesSync(await document.save()); -document.dispose(); -``` - -Add the following code to fill the existing PDF form. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - -//Get the form. -PdfForm form = document.form; - -//Get text box and fill value. -PdfTextBoxField name = document.form.fields[0] as PdfTextBoxField; -name.text = 'John'; - -//Get the radio button and select. -PdfRadioButtonListField gender = form.fields[1] as PdfRadioButtonListField; -gender.selectedIndex = 1; - -//Save and dispose the document. -File('output.pdf').writeAsBytesSync(await document.save()); -document.dispose(); -``` - -Add the following code to flatten the existing form. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - -//Get the form. -PdfForm form = document.form; - -//Flatten all the form fields. -form.flattenAllFields(); - -//Save and dispose the document. -File('output.pdf').writeAsBytesSync(await document.save()); -document.dispose(); -``` - -Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-forms) for more details. - -### Digital signature - -PDF digital signature is the best way to protect your PDF files from being forged. Using this package, we can digitally sign a PDF document using X509 certificates (.pfx file with private key). - -Add the following code to sign the PDF document. - -```dart -//Create a new PDF document. -PdfDocument document = PdfDocument(); - -//Add a new PDF page. -PdfPage page = document.pages.add(); - -//Create signature field. -PdfSignatureField signatureField = PdfSignatureField(page, 'Signature', - bounds: Rect.fromLTWH(0, 0, 200, 50), - signature: PdfSignature( - certificate: - PdfCertificate(File('certificate.pfx').readAsBytesSync(), 'password@123') - )); - -//Add the signature field to the document. -document.form.fields.add(signatureField); - -//Save and dispose the PDF document -File('signed.pdf').writeAsBytes(await document.save()); -document.dispose(); -``` -Add the following code to sign the existing PDF document. - -```dart -//Load the existing PDF document. -final PdfDocument document = - PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - -//Get the signature field. -PdfSignatureField signatureField = - document.form.fields[0] as PdfSignatureField; - -//Get signature field and sign. -signatureField.signature = PdfSignature( - certificate: - PdfCertificate(File('certificate.pfx').readAsBytesSync(), 'password@123'), -); - -//Save and dispose the document. -File('output.pdf').writeAsBytesSync(await document.save()); -document.dispose(); -``` - -Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-digital-signature) for more details. - - -## Support and feedback - -* For any questions, please post them in our [community forums](https://www.syncfusion.com/forums) or contact our [Syncfusion support team](https://support.syncfusion.com/support/tickets/create). You can also submit a feature request or a bug alert through our [feedback portal](https://www.syncfusion.com/feedback/flutter). -* To renew your subscription, click [renew](https://www.syncfusion.com/sales/products) or contact our sales team at salessupport@syncfusion.com | Toll free: 1-888-9 DOTNET. - -## About Syncfusion - -Founded in 2001 and headquartered in Research Triangle Park, N.C., Syncfusion has more than 22,000 customers and more than 1 million users, including large financial institutions, Fortune 500 companies, and global IT consultancies. - +![syncfusion_flutter_pdf_banner](https://cdn.syncfusion.com/content/images/FTControl/Flutter-PDF-Banner.png) + +# Flutter PDF library + +Flutter PDF is a feature-rich and high-performance non-UI PDF library written natively in Dart. It allows you to add robust PDF functionalities to Flutter applications. + +See an interactive demo here: https://flutter.syncfusion.com/#/pdf/invoice + +## Overview + +The PDF package is a non-UI, reusable Flutter library for creating PDF reports programmatically with formatted text, images, shapes, tables, links, lists, headers, footers, and more. The library can be used to create, read, edit, and secure PDF documents in Flutter mobile and web platforms without dependency on Adobe Acrobat. The creation of a PDF follows the most popular PDF 1.7 (ISO 32000-1) and latest PDF 2.0 (ISO 32000-2) specifications. + +**Disclaimer:** This is a commercial package. To use this package, you need to have either a Syncfusion® commercial license or [Free Syncfusion® Community license](https://www.syncfusion.com/products/communitylicense). For more details, please check the [LICENSE](https://github.com/syncfusion/flutter-examples/blob/master/LICENSE) file. + +![PDF Overview](https://cdn.syncfusion.com/content/images/FTControl/Flutter/Flutter-PDF-Overview.png) + +## Table of contents +- [Key features](#key-features) +- [Get the demo application](#get-the-demo-application) +- [Useful links](#useful-links) +- [Installation](#installation) +- [Getting started](#getting-started) + - [Create a PDF document from simple text](#create-a-pdf-document-from-simple-text) + - [Add text using TrueType fonts](#add-text-using-truetype-fonts) + - [Add images to a PDF document](#add-images-to-a-pdf-document) + - [PDF document with flow layout](#pdf-document-with-flow-layout) + - [Add bullets and lists](#add-bullets-and-lists) + - [Add tables](#add-tables) + - [Add headers and footers](#add-headers-and-footers) + - [Load and modify an existing PDF document](#load-and-modify-an-existing-pdf-document) + - [Create and load annotations](#create-and-load-annotations) + - [Add bookmarks](#add-bookmarks) + - [Extract text](#extract-text) + - [Find text](#find-text) + - [Encryption and decryption](#encryption-and-decryption) + - [PDF conformance](#pdf-conformance) + - [PDF form](#pdf-form) + - [Digital signature](#digital-signature) +- [Support and feedback](#support-and-feedback) +- [About Syncfusion®](#about-syncfusion) + +## Key features + +The following are the key features of Syncfusion® Flutter PDF: + +* Create multipage PDF files from scratch. +* Add Unicode and RTL text. +* Insert JPEG and PNG images in the PDF document. +* Generate tables in PDF files with different styles and formats. +* Add headers and footers. +* Add different shapes to PDF files. +* Add paragraphs, bullets, and lists. +* Open, modify, and save existing PDF files. +* Encrypt and decrypt PDF files with advanced standards. +* Add, modify, and remove interactive elements such as bookmarks, annotations, hyperlinks, and attachments. +* Create PDF/A-1B, PDF/A-2B, PDF/A-3B conformances. +* Digitally sign PDF documents. +* Use on mobile and web platforms. + +## Get the demo application + +Explore the full capability of our Flutter widgets on your device by installing our sample browser application from the following app stores and viewing the sample code in GitHub. + +

+ + + +

+

+ + +

+ +## Other useful links + +Take a look at the following to learn more about Syncfusion® Flutter PDF: + +* [Syncfusion® Flutter PDF product page](https://www.syncfusion.com/flutter-widgets/pdf-library) +* [User guide documentation](https://help.syncfusion.com/flutter/pdf/overview) +* [Knowledge base](https://www.syncfusion.com/kb) + +## Installation + +Install the latest version from [pub.dev](https://pub.dartlang.org/packages/syncfusion_flutter_pdf#-installing-tab-). + +## Getting started + +Import the following package to your project to create a PDF document from scratch. + +```dart +import 'package:syncfusion_flutter_pdf/pdf.dart'; +``` + +### Create a PDF document from simple text + +Add the following code to create a simple PDF document. + +```dart +// Create a new PDF document. +final PdfDocument document = PdfDocument(); +// Add a PDF page and draw text. +document.pages.add().graphics.drawString( + 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + brush: PdfSolidBrush(PdfColor(0, 0, 0)), + bounds: const Rect.fromLTWH(0, 0, 150, 20)); +// Save the document. +File('HelloWorld.pdf').writeAsBytes(await document.save()); +// Dispose the document. +document.dispose(); +``` + +### Add text using TrueType fonts + +Use the following code to add a Unicode text to the PDF document. + +```dart +//Create a new PDF document. +final PdfDocument document = PdfDocument(); +//Read font data. +final Uint8List fontData = File('arial.ttf').readAsBytesSync(); +//Create a PDF true type font object. +final PdfFont font = PdfTrueTypeFont(fontData, 12); +//Draw text using ttf font. +document.pages.add().graphics.drawString('Hello World!!!', font, + bounds: const Rect.fromLTWH(0, 0, 200, 50)); +// Save the document. +File('TrueType.pdf').writeAsBytes(await document.save()); +// Dispose the document. +document.dispose(); +``` + +### Add images to a PDF document + +The PdfBitmap class is used to draw images in a PDF document. Syncfusion® Flutter PDF supports PNG and JPEG images. Refer to the following code to draw images in a PDF document. + +```dart +//Create a new PDF document. +final PdfDocument document = PdfDocument(); +//Read image data. +final Uint8List imageData = File('input.png').readAsBytesSync(); +//Load the image using PdfBitmap. +final PdfBitmap image = PdfBitmap(imageData); +//Draw the image to the PDF page. +document.pages + .add() + .graphics + .drawImage(image, const Rect.fromLTWH(0, 0, 500, 200)); +// Save the document. +File('ImageToPDF.pdf').writeAsBytes(await document.save()); +// Dispose the document. +document.dispose(); +``` + +### PDF document with flow layout + +Add the following code to create a PDF document with flow layout. + +```dart +const String paragraphText = + 'Adobe Systems Incorporated\'s Portable Document Format (PDF) is the de facto' + 'standard for the accurate, reliable, and platform-independent representation of a paged' + 'document. It\'s the only universally accepted file format that allows pixel-perfect layouts.' + 'In addition, PDF supports user interaction and collaborative workflows that are not' + 'possible with printed documents.'; + +// Create a new PDF document. +final PdfDocument document = PdfDocument(); +// Add a new page to the document. +final PdfPage page = document.pages.add(); +// Create a new PDF text element class and draw the flow layout text. +final PdfLayoutResult layoutResult = PdfTextElement( + text: paragraphText, + font: PdfStandardFont(PdfFontFamily.helvetica, 12), + brush: PdfSolidBrush(PdfColor(0, 0, 0))) + .draw( + page: page, + bounds: Rect.fromLTWH( + 0, 0, page.getClientSize().width, page.getClientSize().height), + format: PdfLayoutFormat(layoutType: PdfLayoutType.paginate))!; +// Draw the next paragraph/content. +page.graphics.drawLine( + PdfPen(PdfColor(255, 0, 0)), + Offset(0, layoutResult.bounds.bottom + 10), + Offset(page.getClientSize().width, layoutResult.bounds.bottom + 10)); +// Save the document. +File('TextFlow.pdf').writeAsBytes(await document.save()); +// Dispose the document. +document.dispose(); +``` + +### Add bullets and lists + +Add the following code to create bullets and lists in a PDF document. + +```dart +// Create a new PDF document. +final PdfDocument document = PdfDocument(); +// Add a new page to the document. +final PdfPage page = document.pages.add(); +// Create a PDF ordered list. +final PdfOrderedList orderedList = PdfOrderedList( + items: PdfListItemCollection([ + 'Mammals', + 'Reptiles', + 'Birds', + 'Insects', + 'Aquatic Animals' + ]), + marker: PdfOrderedMarker( + style: PdfNumberStyle.numeric, + font: PdfStandardFont(PdfFontFamily.helvetica, 12)), + markerHierarchy: true, + format: PdfStringFormat(lineSpacing: 10), + textIndent: 10); +// Create a un ordered list and add it as a sublist. +orderedList.items[0].subList = PdfUnorderedList( + marker: PdfUnorderedMarker( + font: PdfStandardFont(PdfFontFamily.helvetica, 10), + style: PdfUnorderedMarkerStyle.disk), + items: PdfListItemCollection([ + 'body covered by hair or fur', + 'warm-blooded', + 'have a backbone', + 'produce milk', + 'Examples' + ]), + textIndent: 10, + indent: 20); +// Draw the list to the PDF page. +orderedList.draw( + page: page, + bounds: Rect.fromLTWH( + 0, 0, page.getClientSize().width, page.getClientSize().height)); +// Save the document. +File('BulletandList.pdf').writeAsBytes(await document.save()); +// Dispose the document. +document.dispose(); +``` + +### Add tables + +Add the following code to create a PDF table. + +```dart +// Create a new PDF document. +final PdfDocument document = PdfDocument(); +// Add a new page to the document. +final PdfPage page = document.pages.add(); +// Create a PDF grid class to add tables. +final PdfGrid grid = PdfGrid(); +// Specify the grid column count. +grid.columns.add(count: 3); +// Add a grid header row. +final PdfGridRow headerRow = grid.headers.add(1)[0]; +headerRow.cells[0].value = 'Customer ID'; +headerRow.cells[1].value = 'Contact Name'; +headerRow.cells[2].value = 'Country'; +// Set header font. +headerRow.style.font = + PdfStandardFont(PdfFontFamily.helvetica, 10, style: PdfFontStyle.bold); +// Add rows to the grid. +PdfGridRow row = grid.rows.add(); +row.cells[0].value = 'ALFKI'; +row.cells[1].value = 'Maria Anders'; +row.cells[2].value = 'Germany'; +// Add next row. +row = grid.rows.add(); +row.cells[0].value = 'ANATR'; +row.cells[1].value = 'Ana Trujillo'; +row.cells[2].value = 'Mexico'; +// Add next row. +row = grid.rows.add(); +row.cells[0].value = 'ANTON'; +row.cells[1].value = 'Antonio Mereno'; +row.cells[2].value = 'Mexico'; +// Set grid format. +grid.style.cellPadding = PdfPaddings(left: 5, top: 5); +// Draw table in the PDF page. +grid.draw( + page: page, + bounds: Rect.fromLTWH( + 0, 0, page.getClientSize().width, page.getClientSize().height)); +// Save the document. +File('PDFTable.pdf').writeAsBytes(await document.save()); +// Dispose the document. +document.dispose(); +``` + +### Add headers and footers + +Use the following code to add headers and footers to a PDF document. + +```dart +//Create a new PDF document. +final PdfDocument document = PdfDocument(); +//Create a PDF page template and add header content. +final PdfPageTemplateElement headerTemplate = + PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); +//Draw text in the header. +headerTemplate.graphics.drawString( + 'This is page header', PdfStandardFont(PdfFontFamily.helvetica, 12), + bounds: const Rect.fromLTWH(0, 15, 200, 20)); +//Add the header element to the document. +document.template.top = headerTemplate; +//Create a PDF page template and add footer content. +final PdfPageTemplateElement footerTemplate = + PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); +//Draw text in the footer. +footerTemplate.graphics.drawString( + 'This is page footer', PdfStandardFont(PdfFontFamily.helvetica, 12), + bounds: const Rect.fromLTWH(0, 15, 200, 20)); +//Set footer in the document. +document.template.bottom = footerTemplate; +//Now create pages. +document.pages.add(); +document.pages.add(); +// Save the document. +File('HeaderandFooter.pdf').writeAsBytes(await document.save()); +// Dispose the document. +document.dispose(); +``` + +### Load and modify an existing PDF document + +Add the following code to load and modify the existing PDF document. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); +//Get the existing PDF page. +final PdfPage page = document.pages[0]; +//Draw text in the PDF page. +page.graphics.drawString( + 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + brush: PdfSolidBrush(PdfColor(0, 0, 0)), + bounds: const Rect.fromLTWH(0, 0, 150, 20)); +//Save the document. +File('output.pdf').writeAsBytes(await document.save()); +//Dispose the document. +document.dispose(); +``` + +Add the following code to add or remove a page from the existing PDF document. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); +//Remove the page from the document. +document.pages.removeAt(0); +//Add new page and draw text. +document.pages.add().graphics.drawString( + 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + brush: PdfSolidBrush(PdfColor(0, 0, 0)), + bounds: const Rect.fromLTWH(0, 0, 150, 20)); +//Save the document. +File('output.pdf').writeAsBytes(await document.save()); +//Dispose the document. +document.dispose(); +``` + +### Create and load annotations + +Using this package, we can create and load annotations in a new or existing PDF document. + +Add the following code to create a new annotation in a PDF document. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); +//Create a new rectangle annotation and add to the PDF page. +document.pages[0].annotations.add(PdfRectangleAnnotation( + Rect.fromLTWH(0, 0, 150, 100), 'Rectangle', + color: PdfColor(255, 0, 0), setAppearance: true)); +//Save the document. +File('annotations.pdf').writeAsBytes(await document.save()); +//Dispose the document. +document.dispose(); +``` + +Add the following code to load the annotation and modify it. + +```dart +//Load and modify the existing annotation. +final PdfRectangleAnnotation rectangleAnnotation = + document.pages[0].annotations[0] as PdfRectangleAnnotation; +//Change the annotation text. +rectangleAnnotation.text = 'Changed'; +``` + +Refer to our documentation for more details about [annotations](https://help.syncfusion.com/flutter/pdf/working-with-annotations). + +### Add bookmarks + +Add the following code to create bookmarks in a PDF document. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); +//Create a document bookmark. +final PdfBookmark bookmark = document.bookmarks.add('Page 1'); +//Set the destination page and location. +bookmark.destination = PdfDestination(document.pages[1], Offset(20, 20)); +//Set the bookmark color. +bookmark.color = PdfColor(255, 0, 0); +//Save the document. +File('bookmark.pdf').writeAsBytes(await document.save()); +//Dispose the document. +document.dispose(); +``` + +Refer to our documentation for more details about [bookmarks](https://help.syncfusion.com/flutter/pdf/working-with-bookmarks). + +### Extract text + +Using this package, we can extract text from an existing PDF document along with its bounds. + +Add the following code to extract text from a PDF document. + +```dart +//Load an existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); +//Extract the text from all the pages. +String text = PdfTextExtractor(document).extractText(); +//Dispose the document. +document.dispose(); +``` + +The following code sample explains how to extract text from a specific page. + +```dart +//Load an existing PDF document. +PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); +//Extract the text from page 1. +String text = PdfTextExtractor(document).extractText(startPageIndex: 0); +//Dispose the document. +document.dispose(); +``` + +Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-text-extraction) for more details. + +### Find text + +Using this package, we can find text in an existing PDF document along with its bounds and page index. + +Add the following code to find text in a PDF document. + +```dart +//Load an existing PDF document. +PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); +//Find the text and get matched items. +List textCollection = + PdfTextExtractor(document).findText(['text1', 'text2']); +//Get the matched item in the collection using index. +MatchedItem matchedText = textCollection[0]; +//Get the text bounds. +Rect textBounds = matchedText.bounds; +//Get the page index. +int pageIndex = matchedText.pageIndex; +//Get the text. +String text = matchedText.text; +//Dispose the document. +document.dispose(); +``` + +Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-text-extraction#working-with-find-text) for more details. + +### Encryption and decryption + +Encrypt new or existing PDF documents with encryption standards like 40-bit RC4, 128-bit RC4, 128-bit AES, and 256-bit AES, and the advanced encryption standard 256-bit AES Revision 6 (PDF 2.0) to protect documents against unauthorized access. Using this package, you can also decrypt existing encrypted documents. + +Add the following code to encrypt an existing PDF document. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + +//Add security to the document. +final PdfSecurity security = document.security; + +//Set password. +security.userPassword = 'userpassword@123'; +security.ownerPassword = 'ownerpassword@123'; + +//Set the encryption algorithm. +security.algorithm = PdfEncryptionAlgorithm.aesx256Bit; + +//Save the document. +File('secured.pdf').writeAsBytes(await document.save()); + +//Dispose the document. +document.dispose(); +``` + +Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-security) for more details. + +### PDF conformance + +Using this package, we can create PDF conformance documents, such as: + +* PDF/A-1B +* PDF/A-2B +* PDF/A-3B + +Add the following code to create a PDF conformance document. + +```dart +//Create a PDF conformance document. +final PdfDocument document = PdfDocument(conformanceLevel: PdfConformanceLevel.a1b) + ..pages.add().graphics.drawString('Hello World', + PdfTrueTypeFont(File('Roboto-Regular.ttf').readAsBytesSync(), 12), + bounds: Rect.fromLTWH(20, 20, 200, 50), brush: PdfBrushes.black); +//Save and dispose the document. +File('conformance.pdf').writeAsBytesSync(await document.save()); +document.dispose(); +``` + +Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-pdf-conformance) for more details. + +### PDF form + +PDF forms provide the best way to collect information from users. Using this package, we can create, modify, fill, and flatten PDF forms. + +Add the following code to create PDF form. + +```dart +//Create a new PDF document. +PdfDocument document = PdfDocument(); + +//Create a new page to add form fields. +PdfPage page = document.pages.add(); + +//Create text box field and add to the forms collection. +document.form.fields.add(PdfTextBoxField( + page, 'firstname', Rect.fromLTWH(0, 0, 100, 20), + text: 'John')); + +//Create check box field and add to the form. +document.form.fields.add(PdfCheckBoxField( + page, 'checkbox', Rect.fromLTWH(150, 0, 30, 30), + isChecked: true)); + +//Save and dispose the document. +File('form.pdf').writeAsBytesSync(await document.save()); +document.dispose(); +``` + +Add the following code to fill the existing PDF form. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + +//Get the form. +PdfForm form = document.form; + +//Get text box and fill value. +PdfTextBoxField name = document.form.fields[0] as PdfTextBoxField; +name.text = 'John'; + +//Get the radio button and select. +PdfRadioButtonListField gender = form.fields[1] as PdfRadioButtonListField; +gender.selectedIndex = 1; + +//Save and dispose the document. +File('output.pdf').writeAsBytesSync(await document.save()); +document.dispose(); +``` + +Add the following code to flatten the existing form. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + +//Get the form. +PdfForm form = document.form; + +//Flatten all the form fields. +form.flattenAllFields(); + +//Save and dispose the document. +File('output.pdf').writeAsBytesSync(await document.save()); +document.dispose(); +``` + +Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-forms) for more details. + +### Digital signature + +PDF digital signature is the best way to protect your PDF files from being forged. Using this package, we can digitally sign a PDF document using X509 certificates (.pfx file with private key). + +Add the following code to sign the PDF document. + +```dart +//Create a new PDF document. +PdfDocument document = PdfDocument(); + +//Add a new PDF page. +PdfPage page = document.pages.add(); + +//Create signature field. +PdfSignatureField signatureField = PdfSignatureField(page, 'Signature', + bounds: Rect.fromLTWH(0, 0, 200, 50), + signature: PdfSignature( + certificate: + PdfCertificate(File('certificate.pfx').readAsBytesSync(), 'password@123') + )); + +//Add the signature field to the document. +document.form.fields.add(signatureField); + +//Save and dispose the PDF document +File('signed.pdf').writeAsBytes(await document.save()); +document.dispose(); +``` +Add the following code to sign the existing PDF document. + +```dart +//Load the existing PDF document. +final PdfDocument document = + PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + +//Get the signature field. +PdfSignatureField signatureField = + document.form.fields[0] as PdfSignatureField; + +//Get signature field and sign. +signatureField.signature = PdfSignature( + certificate: + PdfCertificate(File('certificate.pfx').readAsBytesSync(), 'password@123'), +); + +//Save and dispose the document. +File('output.pdf').writeAsBytesSync(await document.save()); +document.dispose(); +``` + +Refer to our [documentation](https://help.syncfusion.com/flutter/pdf/working-with-digital-signature) for more details. + + +## Support and feedback + +* For any questions, please post them in our [community forums](https://www.syncfusion.com/forums) or contact our [Syncfusion® support team](https://support.syncfusion.com/support/tickets/create). You can also submit a feature request or a bug alert through our [feedback portal](https://www.syncfusion.com/feedback/flutter). +* To renew your subscription, click [renew](https://www.syncfusion.com/sales/products) or contact our sales team at salessupport@syncfusion.com | Toll free: 1-888-9 DOTNET. + +## About Syncfusion® + +Founded in 2001 and headquartered in Research Triangle Park, N.C., Syncfusion® has more than 22,000 customers and more than 1 million users, including large financial institutions, Fortune 500 companies, and global IT consultancies. + Today we provide 1,600+ controls and frameworks for web ([ASP.NET Core](https://www.syncfusion.com/aspnet-core-ui-controls), [ASP.NET MVC](https://www.syncfusion.com/aspnet-mvc-ui-controls), [ASP.NET WebForms](https://www.syncfusion.com/jquery/aspnet-web-forms-ui-controls), [JavaScript](https://www.syncfusion.com/javascript-ui-controls), [Angular](https://www.syncfusion.com/angular-ui-components), [React](https://www.syncfusion.com/react-ui-components), [Vue](https://www.syncfusion.com/vue-ui-components), [Flutter](https://www.syncfusion.com/flutter-widgets), and [Blazor](https://www.syncfusion.com/blazor-components)), mobile ([Xamarin](https://www.syncfusion.com/xamarin-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), [Flutter](https://www.syncfusion.com/flutter-widgets), [UWP](https://www.syncfusion.com/uwp-ui-controls), and [JavaScript](https://www.syncfusion.com/javascript-ui-controls)), and desktop development ([Flutter](https://www.syncfusion.com/flutter-widgets), [WinForms](https://www.syncfusion.com/winforms-ui-controls), [WPF](https://www.syncfusion.com/wpf-ui-controls), [UWP](https://www.syncfusion.com/uwp-ui-controls), [.NET MAUI](https://www.syncfusion.com/maui-controls), and [WinUI](https://www.syncfusion.com/winui-controls)). We provide ready-to deploy enterprise software in our Bold line of products for dashboarding and reporting. Many customers have saved millions in licensing fees by deploying our software. \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/analysis_options.yaml b/packages/syncfusion_flutter_pdf/analysis_options.yaml index 03286a00b..eb11d4dfe 100644 --- a/packages/syncfusion_flutter_pdf/analysis_options.yaml +++ b/packages/syncfusion_flutter_pdf/analysis_options.yaml @@ -1 +1 @@ -include: package:syncfusion_flutter_core/analysis_options.yaml +include: package:syncfusion_flutter_core/analysis_options.yaml diff --git a/packages/syncfusion_flutter_pdf/dartdoc_options.yaml b/packages/syncfusion_flutter_pdf/dartdoc_options.yaml deleted file mode 100644 index 2fd85ba9b..000000000 --- a/packages/syncfusion_flutter_pdf/dartdoc_options.yaml +++ /dev/null @@ -1,4 +0,0 @@ -dartdoc: - ignore: - - broken-link - - missing-from-search-index \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/README.md b/packages/syncfusion_flutter_pdf/example/README.md index 1649922e1..63d977b98 100644 --- a/packages/syncfusion_flutter_pdf/example/README.md +++ b/packages/syncfusion_flutter_pdf/example/README.md @@ -1,3 +1,3 @@ -# pdf_example - -Demo for creating a PDF file using syncfusion_flutter_pdf package. +# pdf_example + +Demo for creating a PDF file using syncfusion_flutter_pdf package. diff --git a/packages/syncfusion_flutter_pdf/example/analysis_options.yaml b/packages/syncfusion_flutter_pdf/example/analysis_options.yaml index 3c7353f05..616e1ab55 100644 --- a/packages/syncfusion_flutter_pdf/example/analysis_options.yaml +++ b/packages/syncfusion_flutter_pdf/example/analysis_options.yaml @@ -1,10 +1,10 @@ -include: package:syncfusion_flutter_core/analysis_options.yaml - -analyzer: - errors: - include_file_not_found: ignore - library_private_types_in_public_api: ignore - lines_longer_than_80_chars: ignore - avoid_as: ignore - uri_does_not_exist: ignore - invalid_dependency: ignore +include: package:syncfusion_flutter_core/analysis_options.yaml + +analyzer: + errors: + include_file_not_found: ignore + library_private_types_in_public_api: ignore + lines_longer_than_80_chars: ignore + avoid_as: ignore + uri_does_not_exist: ignore + invalid_dependency: ignore diff --git a/packages/syncfusion_flutter_pdf/example/android/.gitignore b/packages/syncfusion_flutter_pdf/example/android/.gitignore deleted file mode 100644 index 55afd919c..000000000 --- a/packages/syncfusion_flutter_pdf/example/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/to/reference-keystore -key.properties -**/*.keystore -**/*.jks diff --git a/packages/syncfusion_flutter_pdf/example/android/app/build.gradle b/packages/syncfusion_flutter_pdf/example/android/app/build.gradle index e6af82920..a6e3f0afa 100644 --- a/packages/syncfusion_flutter_pdf/example/android/app/build.gradle +++ b/packages/syncfusion_flutter_pdf/example/android/app/build.gradle @@ -1,44 +1,44 @@ -plugins { - id "com.android.application" - id "kotlin-android" - // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" -} - -android { - namespace = "com.example.pdf_example" - compileSdk = flutter.compileSdkVersion - ndkVersion = flutter.ndkVersion - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8 - } - - defaultConfig { - // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.pdf_example" - // You can update the following values to match your application needs. - // For more information, see: https://flutter.dev/to/review-gradle-config. - minSdk = flutter.minSdkVersion - targetSdk = flutter.targetSdkVersion - versionCode = flutter.versionCode - versionName = flutter.versionName - } - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug - } - } -} - -flutter { - source = "../.." -} +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" +} + +android { + namespace = "com.example.pdf_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.pdf_example" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.debug + } + } +} + +flutter { + source = "../.." +} diff --git a/packages/syncfusion_flutter_pdf/example/android/app/src/debug/AndroidManifest.xml b/packages/syncfusion_flutter_pdf/example/android/app/src/debug/AndroidManifest.xml index 399f6981d..8ffe02464 100644 --- a/packages/syncfusion_flutter_pdf/example/android/app/src/debug/AndroidManifest.xml +++ b/packages/syncfusion_flutter_pdf/example/android/app/src/debug/AndroidManifest.xml @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/packages/syncfusion_flutter_pdf/example/android/app/src/main/AndroidManifest.xml b/packages/syncfusion_flutter_pdf/example/android/app/src/main/AndroidManifest.xml index 8c6372c09..f84f4e9f7 100644 --- a/packages/syncfusion_flutter_pdf/example/android/app/src/main/AndroidManifest.xml +++ b/packages/syncfusion_flutter_pdf/example/android/app/src/main/AndroidManifest.xml @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/packages/syncfusion_flutter_pdf/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt deleted file mode 100644 index e793a000d..000000000 --- a/packages/syncfusion_flutter_pdf/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.example - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() { -} diff --git a/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/drawable/launch_background.xml b/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/drawable/launch_background.xml index 304732f88..84037589b 100644 --- a/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/drawable/launch_background.xml +++ b/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/drawable/launch_background.xml @@ -1,12 +1,12 @@ - - - - - - - - + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/values/styles.xml b/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/values/styles.xml index cb1ef8805..5fac67961 100644 --- a/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/values/styles.xml +++ b/packages/syncfusion_flutter_pdf/example/android/app/src/main/res/values/styles.xml @@ -1,18 +1,18 @@ - - - - - - - + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/android/app/src/profile/AndroidManifest.xml b/packages/syncfusion_flutter_pdf/example/android/app/src/profile/AndroidManifest.xml index 399f6981d..8ffe02464 100644 --- a/packages/syncfusion_flutter_pdf/example/android/app/src/profile/AndroidManifest.xml +++ b/packages/syncfusion_flutter_pdf/example/android/app/src/profile/AndroidManifest.xml @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/packages/syncfusion_flutter_pdf/example/android/build.gradle b/packages/syncfusion_flutter_pdf/example/android/build.gradle index d2ffbffa4..00666442d 100644 --- a/packages/syncfusion_flutter_pdf/example/android/build.gradle +++ b/packages/syncfusion_flutter_pdf/example/android/build.gradle @@ -1,18 +1,18 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = "../build" -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(":app") -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = "../build" +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/packages/syncfusion_flutter_pdf/example/android/gradle.properties b/packages/syncfusion_flutter_pdf/example/android/gradle.properties index 259717082..5ddc5594e 100644 --- a/packages/syncfusion_flutter_pdf/example/android/gradle.properties +++ b/packages/syncfusion_flutter_pdf/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError -android.useAndroidX=true -android.enableJetifier=true +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6ba..dcc7e10d2 100644 --- a/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/syncfusion_flutter_pdf/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/packages/syncfusion_flutter_pdf/example/android/settings.gradle b/packages/syncfusion_flutter_pdf/example/android/settings.gradle index b9e43bd37..ad0470334 100644 --- a/packages/syncfusion_flutter_pdf/example/android/settings.gradle +++ b/packages/syncfusion_flutter_pdf/example/android/settings.gradle @@ -1,25 +1,25 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.1.0" apply false - id "org.jetbrains.kotlin.android" version "1.8.22" apply false -} - -include ":app" +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.9.1" apply false + id "org.jetbrains.kotlin.android" version "2.2.20" apply false +} + +include ":app" diff --git a/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/_composite.stamp b/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/_composite.stamp new file mode 100644 index 000000000..1b2d28c4e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/_composite.stamp @@ -0,0 +1 @@ +{"inputs":[],"outputs":[]} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/gen_dart_plugin_registrant.stamp b/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/gen_dart_plugin_registrant.stamp new file mode 100644 index 000000000..8f66dbede --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/gen_dart_plugin_registrant.stamp @@ -0,0 +1 @@ +{"inputs":["/Users/mac/Desktop/sample_pdf_translator/syncfusion_flutter_pdf/example/.dart_tool/package_config.json"],"outputs":["/Users/mac/Desktop/sample_pdf_translator/syncfusion_flutter_pdf/example/.dart_tool/flutter_build/dart_plugin_registrant.dart"]} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/gen_localizations.stamp b/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/gen_localizations.stamp new file mode 100644 index 000000000..1b2d28c4e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ebb8ae27a724aea2d6280681773e3f5c/gen_localizations.stamp @@ -0,0 +1 @@ +{"inputs":[],"outputs":[]} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/.last_build_id b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/.last_build_id new file mode 100644 index 000000000..73c598218 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/.last_build_id @@ -0,0 +1 @@ +7426c7eac74880692804fa099f89cd7c \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/App b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/App new file mode 100755 index 000000000..763c19092 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/App differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/Info.plist new file mode 100644 index 000000000..1dc6cf765 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 13.0 + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..5b1f23d05 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/_CodeSignature/CodeResources @@ -0,0 +1,212 @@ + + + + + files + + Info.plist + + T7ae0s1yqPVdrLK0y5gqABVb1PU= + + flutter_assets/AssetManifest.bin + + 21tVqbIV90TbglF4ZJhNBz8uj4w= + + flutter_assets/FontManifest.json + + +D1xbIOooc3ypce1+jh+mmLy1J0= + + flutter_assets/NOTICES.Z + + AXyVWLODHa/0OkUkKJ+LZ8eJFkE= + + flutter_assets/NativeAssetsManifest.json + + re4p7E8rPLLsN+wzaPN/+AVpXTY= + + flutter_assets/fonts/MaterialIcons-Regular.otf + + /CUoTuPQqqdexfyOT9lpJhV+2MQ= + + flutter_assets/isolate_snapshot_data + + Oct4LBWkbrUyhS8o11D8knDiOCw= + + flutter_assets/kernel_blob.bin + + xJK2Y4wcwvcJLYpeprI0c3lbUjE= + + flutter_assets/shaders/ink_sparkle.frag + + VvTF10G1gIeea4aI0DhJjCjHgXQ= + + flutter_assets/shaders/stretch_effect.frag + + kG7Fh+R6JkaM/GufJFUfEToHTEg= + + flutter_assets/vm_snapshot_data + + 3y4zj1lbLxr1MIJjsR7xSTsrd4k= + + + files2 + + flutter_assets/AssetManifest.bin + + hash2 + + 9WbMb8zGVzZcAZeszzp9b4D4Ugn/Zm/3dPTcvFJKqEI= + + + flutter_assets/FontManifest.json + + hash2 + + KLHrKz0uGtYLjIsPkQCxzL9JL3+pf1vrtR6pfnOSbn0= + + + flutter_assets/NOTICES.Z + + hash2 + + NrzjHg60IXWImNkLTcTe7UCS05stOUJPlqXWWY/FNkI= + + + flutter_assets/NativeAssetsManifest.json + + hash2 + + lUijHkoEgTXB2U+Rkyi/tirix7s8q5ZVfHlB2ql3dss= + + + flutter_assets/fonts/MaterialIcons-Regular.otf + + hash2 + + 2YZbZxoJ1oPROoYwidiCXg9ho3aWzl19RIvIAjqmJFM= + + + flutter_assets/isolate_snapshot_data + + hash2 + + wHUhal5u7BswH9uKyMGmAinBbqMbGrC0nmFvt+raT08= + + + flutter_assets/kernel_blob.bin + + hash2 + + ep/WR3I5PLXXV7RxcQ7FfWvg01VWJNtKO9QO09OUJUg= + + + flutter_assets/shaders/ink_sparkle.frag + + hash2 + + TGVjYgE+Oyl6guvhhPPrWfynkxkJeFjSzSLsQqn7Q3M= + + + flutter_assets/shaders/stretch_effect.frag + + hash2 + + Y/95u280RMpR6e6ndBjH5Pm8ujZSD5Qf33woQ/NncNU= + + + flutter_assets/vm_snapshot_data + + hash2 + + OdF1NJaYIhUMtPHX5I2sunghfvWky6zAyizwBbVifbU= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin new file mode 100644 index 000000000..86d111f09 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/AssetManifest.bin differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json new file mode 100644 index 000000000..3abf18c41 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/FontManifest.json @@ -0,0 +1 @@ +[{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]}] \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z new file mode 100644 index 000000000..830d1e2c2 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NOTICES.Z differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json new file mode 100644 index 000000000..523bfc7c6 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/NativeAssetsManifest.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf new file mode 100644 index 000000000..8c9926613 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data new file mode 100644 index 000000000..0923d40ce Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/isolate_snapshot_data differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin new file mode 100644 index 000000000..503bc3048 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/kernel_blob.bin differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag new file mode 100644 index 000000000..77ed3e358 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/ink_sparkle.frag differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/stretch_effect.frag b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/stretch_effect.frag new file mode 100644 index 000000000..d7581175b Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/shaders/stretch_effect.frag differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data new file mode 100644 index 000000000..af8b65ebd Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/App.framework/flutter_assets/vm_snapshot_data differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter new file mode 100755 index 000000000..6ac377dcf Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Flutter differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/Flutter.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/Flutter.h new file mode 100644 index 000000000..54e1cd3ea --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/Flutter.h @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTER_H_ + +#import "FlutterAppDelegate.h" +#import "FlutterBinaryMessenger.h" +#import "FlutterCallbackCache.h" +#import "FlutterChannels.h" +#import "FlutterCodecs.h" +#import "FlutterDartProject.h" +#import "FlutterEngine.h" +#import "FlutterEngineGroup.h" +#import "FlutterHeadlessDartRunner.h" +#import "FlutterMacros.h" +#import "FlutterPlatformViews.h" +#import "FlutterPlugin.h" +#import "FlutterPluginAppLifeCycleDelegate.h" +#import "FlutterSceneDelegate.h" +#import "FlutterSceneLifeCycle.h" +#import "FlutterTexture.h" +#import "FlutterViewController.h" + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterAppDelegate.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterAppDelegate.h new file mode 100644 index 000000000..fce4fd33a --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterAppDelegate.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERAPPDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERAPPDELEGATE_H_ + +#import + +#import "FlutterMacros.h" +#import "FlutterPlugin.h" + +/** + * `UIApplicationDelegate` subclass for simple apps that want default behavior. + * + * This class implements the following behaviors: + * * Status bar touches are forwarded to the key window's root view + * `FlutterViewController`, in order to trigger scroll to top. + * * Keeps the Flutter connection open in debug mode when the phone screen + * locks. + * + * App delegates for Flutter applications are *not* required to inherit from + * this class. Developers of custom app delegate classes should copy and paste + * code as necessary from FlutterAppDelegate.mm. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterAppDelegate + : UIResponder + +@property(nonatomic, strong, nullable) UIWindow* window; + +/** + * The `FlutterPluginRegistrant` that will be used when FlutterViewControllers + * are instantiated from nibs. + * + * The `FlutterAppDelegate` itself can be passed in without creating a retain + * cycle. + * + * This was introduced to help users migrate code from the FlutterAppDelegate + * when UISceneDelegate was adopted. Using + * FlutterViewController.pluginRegistrant should be preferred since it doesn't + * rely on the FlutterAppDelegate. + */ +@property(nonatomic, strong, nullable) NSObject* pluginRegistrant; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERAPPDELEGATE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterBinaryMessenger.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterBinaryMessenger.h new file mode 100644 index 000000000..eb0186fd2 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterBinaryMessenger.h @@ -0,0 +1,106 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERBINARYMESSENGER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERBINARYMESSENGER_H_ + +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN +/** + * A message reply callback. + * + * Used for submitting a binary reply back to a Flutter message sender. Also used + * in for handling a binary message reply received from Flutter. + * + * @param reply The reply. + */ +typedef void (^FlutterBinaryReply)(NSData* _Nullable reply); + +/** + * A strategy for handling incoming binary messages from Flutter and to send + * asynchronous replies back to Flutter. + * + * @param message The message. + * @param reply A callback for submitting an asynchronous reply to the sender. + */ +typedef void (^FlutterBinaryMessageHandler)(NSData* _Nullable message, FlutterBinaryReply reply); + +typedef int64_t FlutterBinaryMessengerConnection; + +@protocol FlutterTaskQueue +@end + +/** + * A facility for communicating with the Flutter side using asynchronous message + * passing with binary messages. + * + * Implementated by: + * - `FlutterBasicMessageChannel`, which supports communication using structured + * messages. + * - `FlutterMethodChannel`, which supports communication using asynchronous + * method calls. + * - `FlutterEventChannel`, which supports commuication using event streams. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterBinaryMessenger +/// TODO(gaaclarke): Remove optional when macos supports Background Platform Channels. +@optional +- (NSObject*)makeBackgroundTaskQueue; + +- (FlutterBinaryMessengerConnection) + setMessageHandlerOnChannel:(NSString*)channel + binaryMessageHandler:(FlutterBinaryMessageHandler _Nullable)handler + taskQueue:(NSObject* _Nullable)taskQueue; + +@required +/** + * Sends a binary message to the Flutter side on the specified channel, expecting + * no reply. + * + * @param channel The channel name. + * @param message The message. + */ +- (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message; + +/** + * Sends a binary message to the Flutter side on the specified channel, expecting + * an asynchronous reply. + * + * @param channel The channel name. + * @param message The message. + * @param callback A callback for receiving a reply. + */ +- (void)sendOnChannel:(NSString*)channel + message:(NSData* _Nullable)message + binaryReply:(FlutterBinaryReply _Nullable)callback; + +/** + * Registers a message handler for incoming binary messages from the Flutter side + * on the specified channel. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param channel The channel name. + * @param handler The message handler. + * @return An identifier that represents the connection that was just created to the channel. + */ +- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel + binaryMessageHandler: + (FlutterBinaryMessageHandler _Nullable)handler; + +/** + * Clears out a channel's message handler if that handler is still the one that + * was created as a result of + * `setMessageHandlerOnChannel:binaryMessageHandler:`. + * + * @param connection The result from `setMessageHandlerOnChannel:binaryMessageHandler:`. + */ +- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection; +@end +NS_ASSUME_NONNULL_END +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERBINARYMESSENGER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterCallbackCache.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterCallbackCache.h new file mode 100644 index 000000000..b6e331d44 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterCallbackCache.h @@ -0,0 +1,54 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERCALLBACKCACHE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERCALLBACKCACHE_H_ + +#import + +#import "FlutterMacros.h" + +/** + * An object containing the result of `FlutterCallbackCache`'s `lookupCallbackInformation` + * method. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterCallbackInformation : NSObject +/** + * The name of the callback. + */ +@property(copy) NSString* callbackName; +/** + * The class name of the callback. + */ +@property(copy) NSString* callbackClassName; +/** + * The library path of the callback. + */ +@property(copy) NSString* callbackLibraryPath; +@end + +/** + * The cache containing callback information for spawning a + * `FlutterHeadlessDartRunner`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterCallbackCache : NSObject +/** + * Returns the callback information for the given callback handle. + * This callback information can be used when spawning a + * `FlutterHeadlessDartRunner`. + * + * @param handle The handle for a callback, provided by the + * Dart method `PluginUtilities.getCallbackHandle`. + * @return A `FlutterCallbackInformation` object which contains the name of the + * callback, the name of the class in which the callback is defined, and the + * path of the library which contains the callback. If the provided handle is + * invalid, nil is returned. + */ ++ (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERCALLBACKCACHE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterChannels.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterChannels.h new file mode 100644 index 000000000..b88b78a90 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterChannels.h @@ -0,0 +1,487 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCHANNELS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCHANNELS_H_ + +#import "FlutterBinaryMessenger.h" +#import "FlutterCodecs.h" + +NS_ASSUME_NONNULL_BEGIN +/** + * A message reply callback. + * + * Used for submitting a reply back to a Flutter message sender. Also used in + * the dual capacity for handling a message reply received from Flutter. + * + * @param reply The reply. + */ +typedef void (^FlutterReply)(id _Nullable reply); + +/** + * A strategy for handling incoming messages from Flutter and to send + * asynchronous replies back to Flutter. + * + * @param message The message. + * @param callback A callback for submitting a reply to the sender which can be invoked from any + * thread. + */ +typedef void (^FlutterMessageHandler)(id _Nullable message, FlutterReply callback); + +/** + * A channel for communicating with the Flutter side using basic, asynchronous + * message passing. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterBasicMessageChannel : NSObject +/** + * Creates a `FlutterBasicMessageChannel` with the specified name and binary + * messenger. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * The channel uses `FlutterStandardMessageCodec` to encode and decode messages. + * + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (instancetype)messageChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Creates a `FlutterBasicMessageChannel` with the specified name, binary + * messenger, and message codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The message codec. + */ ++ (instancetype)messageChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterBasicMessageChannel` with the specified name, binary + * messenger, and message codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The message codec. + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterBasicMessageChannel` with the specified name, binary + * messenger, and message codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The message codec. + * @param taskQueue The FlutterTaskQueue that executes the handler (see + -[FlutterBinaryMessenger makeBackgroundTaskQueue]). + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec + taskQueue:(NSObject* _Nullable)taskQueue; + +/** + * Sends the specified message to the Flutter side, ignoring any reply. + * + * @param message The message. Must be supported by the codec of this + * channel. + */ +- (void)sendMessage:(id _Nullable)message; + +/** + * Sends the specified message to the Flutter side, expecting an asynchronous + * reply. + * + * @param message The message. Must be supported by the codec of this channel. + * @param callback A callback to be invoked with the message reply from Flutter. + */ +- (void)sendMessage:(id _Nullable)message reply:(FlutterReply _Nullable)callback; + +/** + * Registers a message handler with this channel. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param handler The message handler. + */ +- (void)setMessageHandler:(FlutterMessageHandler _Nullable)handler; + +/** + * Adjusts the number of messages that will get buffered when sending messages to + * channels that aren't fully set up yet. For example, the engine isn't running + * yet or the channel's message handler isn't set up on the Dart side yet. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param newSize The number of messages that will get buffered. + */ ++ (void)resizeChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + size:(NSInteger)newSize; + +/** + * Adjusts the number of messages that will get buffered when sending messages to + * channels that aren't fully set up yet. For example, the engine isn't running + * yet or the channel's message handler isn't set up on the Dart side yet. + * + * @param newSize The number of messages that will get buffered. + */ +- (void)resizeChannelBuffer:(NSInteger)newSize; + +/** + * Defines whether the channel should show warning messages when discarding messages + * due to overflow. + * + * @param warns When false, the channel is expected to overflow and warning messages + * will not be shown. + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (void)setWarnsOnOverflow:(BOOL)warns + forChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Defines whether the channel should show warning messages when discarding messages + * due to overflow. + * + * @param warns When false, the channel is expected to overflow and warning messages + * will not be shown. + */ +- (void)setWarnsOnOverflow:(BOOL)warns; + +@end + +/** + * A method call result callback. + * + * Used for submitting a method call result back to a Flutter caller. Also used in + * the dual capacity for handling a method call result received from Flutter. + * + * @param result The result. + */ +typedef void (^FlutterResult)(id _Nullable result); + +/** + * A strategy for handling method calls. + * + * @param call The incoming method call. + * @param result A callback to asynchronously submit the result of the call. + * Invoke the callback with a `FlutterError` to indicate that the call failed. + * Invoke the callback with `FlutterMethodNotImplemented` to indicate that the + * method was unknown. Any other values, including `nil`, are interpreted as + * successful results. This can be invoked from any thread. + */ +typedef void (^FlutterMethodCallHandler)(FlutterMethodCall* call, FlutterResult result); + +/** + * A constant used with `FlutterMethodCallHandler` to respond to the call of an + * unknown method. + */ +FLUTTER_DARWIN_EXPORT +extern NSObject const* FlutterMethodNotImplemented; + +/** + * A channel for communicating with the Flutter side using invocation of + * asynchronous methods. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterMethodChannel : NSObject +/** + * Creates a `FlutterMethodChannel` with the specified name and binary messenger. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * The channel uses `FlutterStandardMethodCodec` to encode and decode method calls + * and result envelopes. + * + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (instancetype)methodChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Creates a `FlutterMethodChannel` with the specified name, binary messenger, and + * method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ ++ (instancetype)methodChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterMethodChannel` with the specified name, binary messenger, + * and method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterMethodChannel` with the specified name, binary messenger, + * method codec, and task queue. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + * @param taskQueue The FlutterTaskQueue that executes the handler (see + -[FlutterBinaryMessenger makeBackgroundTaskQueue]). + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec + taskQueue:(NSObject* _Nullable)taskQueue; + +// clang-format off +/** + * Invokes the specified Flutter method with the specified arguments, expecting + * no results. + * + * @see [MethodChannel.setMethodCallHandler](https://api.flutter.dev/flutter/services/MethodChannel/setMethodCallHandler.html) + * + * @param method The name of the method to invoke. + * @param arguments The arguments. Must be a value supported by the codec of this + * channel. + */ +// clang-format on +- (void)invokeMethod:(NSString*)method arguments:(id _Nullable)arguments; + +/** + * Invokes the specified Flutter method with the specified arguments, expecting + * an asynchronous result. + * + * @param method The name of the method to invoke. + * @param arguments The arguments. Must be a value supported by the codec of this + * channel. + * @param callback A callback that will be invoked with the asynchronous result. + * The result will be a `FlutterError` instance, if the method call resulted + * in an error on the Flutter side. Will be `FlutterMethodNotImplemented`, if + * the method called was not implemented on the Flutter side. Any other value, + * including `nil`, should be interpreted as successful results. + */ +- (void)invokeMethod:(NSString*)method + arguments:(id _Nullable)arguments + result:(FlutterResult _Nullable)callback; +/** + * Registers a handler for method calls from the Flutter side. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param handler The method call handler. + */ +- (void)setMethodCallHandler:(FlutterMethodCallHandler _Nullable)handler; + +/** + * Adjusts the number of messages that will get buffered when sending messages to + * channels that aren't fully set up yet. For example, the engine isn't running + * yet or the channel's message handler isn't set up on the Dart side yet. + */ +- (void)resizeChannelBuffer:(NSInteger)newSize; + +@end + +/** + * An event sink callback. + * + * @param event The event. + */ +typedef void (^FlutterEventSink)(id _Nullable event); + +/** + * A strategy for exposing an event stream to the Flutter side. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterStreamHandler +/** + * Sets up an event stream and begin emitting events. + * + * Invoked when the first listener is registered with the Stream associated to + * this channel on the Flutter side. + * + * @param arguments Arguments for the stream. + * @param events A callback to asynchronously emit events. Invoke the + * callback with a `FlutterError` to emit an error event. Invoke the + * callback with `FlutterEndOfEventStream` to indicate that no more + * events will be emitted. Any other value, including `nil` are emitted as + * successful events. + * @return A FlutterError instance, if setup fails. + */ +- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments + eventSink:(FlutterEventSink)events; + +/** + * Tears down an event stream. + * + * Invoked when the last listener is deregistered from the Stream associated to + * this channel on the Flutter side. + * + * The channel implementation may call this method with `nil` arguments + * to separate a pair of two consecutive set up requests. Such request pairs + * may occur during Flutter hot restart. + * + * @param arguments Arguments for the stream. + * @return A FlutterError instance, if teardown fails. + */ +- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments; +@end + +/** + * A constant used with `FlutterEventChannel` to indicate end of stream. + */ +FLUTTER_DARWIN_EXPORT +extern NSObject const* FlutterEndOfEventStream; + +/** + * A channel for communicating with the Flutter side using event streams. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEventChannel : NSObject +/** + * Creates a `FlutterEventChannel` with the specified name and binary messenger. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterViewController`. + * + * The channel uses `FlutterStandardMethodCodec` to decode stream setup and + * teardown requests, and to encode event envelopes. + * + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (instancetype)eventChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Creates a `FlutterEventChannel` with the specified name, binary messenger, + * and method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ ++ (instancetype)eventChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterEventChannel` with the specified name, binary messenger, + * and method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterEventChannel` with the specified name, binary messenger, + * method codec and task queue. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + * @param taskQueue The FlutterTaskQueue that executes the handler (see + -[FlutterBinaryMessenger makeBackgroundTaskQueue]). + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec + taskQueue:(NSObject* _Nullable)taskQueue; +/** + * Registers a handler for stream setup requests from the Flutter side. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param handler The stream handler. + */ +- (void)setStreamHandler:(NSObject* _Nullable)handler; +@end +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCHANNELS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterCodecs.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterCodecs.h new file mode 100644 index 000000000..93e1d32d9 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterCodecs.h @@ -0,0 +1,478 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCODECS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCODECS_H_ + +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A message encoding/decoding mechanism. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterMessageCodec +/** + * Returns a shared instance of this `FlutterMessageCodec`. + */ ++ (instancetype)sharedInstance; + +/** + * Encodes the specified message into binary. + * + * @param message The message. + * @return The binary encoding, or `nil`, if `message` was `nil`. + */ +- (NSData* _Nullable)encode:(id _Nullable)message; + +/** + * Decodes the specified message from binary. + * + * @param message The message. + * @return The decoded message, or `nil`, if `message` was `nil`. + */ +- (id _Nullable)decode:(NSData* _Nullable)message; +@end + +/** + * A `FlutterMessageCodec` using unencoded binary messages, represented as + * `NSData` instances. + * + * This codec is guaranteed to be compatible with the corresponding + * [BinaryCodec](https://api.flutter.dev/flutter/services/BinaryCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * On the Dart side, messages are represented using `ByteData`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterBinaryCodec : NSObject +@end + +/** + * A `FlutterMessageCodec` using UTF-8 encoded `NSString` messages. + * + * This codec is guaranteed to be compatible with the corresponding + * [StringCodec](https://api.flutter.dev/flutter/services/StringCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStringCodec : NSObject +@end + +/** + * A `FlutterMessageCodec` using UTF-8 encoded JSON messages. + * + * This codec is guaranteed to be compatible with the corresponding + * [JSONMessageCodec](https://api.flutter.dev/flutter/services/JSONMessageCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Supports values accepted by `NSJSONSerialization` plus top-level + * `nil`, `NSNumber`, and `NSString`. + * + * On the Dart side, JSON messages are handled by the JSON facilities of the + * [`dart:convert`](https://api.dartlang.org/stable/dart-convert/JSON-constant.html) + * package. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterJSONMessageCodec : NSObject +@end + +/** + * A writer of the Flutter standard binary encoding. + * + * See `FlutterStandardMessageCodec` for details on the encoding. + * + * The encoding is extensible via subclasses overriding `writeValue`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardWriter : NSObject +/** + * Create a `FlutterStandardWriter` who will write to \p data. + */ +- (instancetype)initWithData:(NSMutableData*)data; +/** Write a 8-bit byte. */ +- (void)writeByte:(UInt8)value; +/** Write an array of \p bytes of size \p length. */ +- (void)writeBytes:(const void*)bytes length:(NSUInteger)length; +/** Write an array of bytes contained in \p data. */ +- (void)writeData:(NSData*)data; +/** Write 32-bit unsigned integer that represents a \p size of a collection. */ +- (void)writeSize:(UInt32)size; +/** Write zero padding until data is aligned with \p alignment. */ +- (void)writeAlignment:(UInt8)alignment; +/** Write a string with UTF-8 encoding. */ +- (void)writeUTF8:(NSString*)value; +/** Introspects into an object and writes its representation. + * + * Supported Data Types: + * - NSNull + * - NSNumber + * - NSString (as UTF-8) + * - FlutterStandardTypedData + * - NSArray of supported types + * - NSDictionary of supporte types + * + * NSAsserts on failure. + */ +- (void)writeValue:(id)value; +@end + +/** + * A reader of the Flutter standard binary encoding. + * + * See `FlutterStandardMessageCodec` for details on the encoding. + * + * The encoding is extensible via subclasses overriding `readValueOfType`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardReader : NSObject +/** + * Create a new `FlutterStandardReader` who reads from \p data. + */ +- (instancetype)initWithData:(NSData*)data; +/** Returns YES when the reader hasn't reached the end of its data. */ +- (BOOL)hasMore; +/** Reads a byte value and increments the position. */ +- (UInt8)readByte; +/** Reads a sequence of byte values of \p length and increments the position. */ +- (void)readBytes:(void*)destination length:(NSUInteger)length; +/** Reads a sequence of byte values of \p length and increments the position. */ +- (NSData*)readData:(NSUInteger)length; +/** Reads a 32-bit unsigned integer representing a collection size and increments the position.*/ +- (UInt32)readSize; +/** Advances the read position until it is aligned with \p alignment. */ +- (void)readAlignment:(UInt8)alignment; +/** Read a null terminated string encoded with UTF-8/ */ +- (NSString*)readUTF8; +/** + * Reads a byte for `FlutterStandardField` the decodes a value matching that type. + * + * See also: -[FlutterStandardWriter writeValue] + */ +- (nullable id)readValue; +/** + * Decodes a value matching the \p type specified. + * + * See also: + * - `FlutterStandardField` + * - `-[FlutterStandardWriter writeValue]` + */ +- (nullable id)readValueOfType:(UInt8)type; +@end + +/** + * A factory of compatible reader/writer instances using the Flutter standard + * binary encoding or extensions thereof. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardReaderWriter : NSObject +/** + * Create a new `FlutterStandardWriter` for writing to \p data. + */ +- (FlutterStandardWriter*)writerWithData:(NSMutableData*)data; +/** + * Create a new `FlutterStandardReader` for reading from \p data. + */ +- (FlutterStandardReader*)readerWithData:(NSData*)data; +@end + +/** + * A `FlutterMessageCodec` using the Flutter standard binary encoding. + * + * This codec is guaranteed to be compatible with the corresponding + * [StandardMessageCodec](https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Supported messages are acyclic values of these forms: + * + * - `nil` or `NSNull` + * - `NSNumber` (including their representation of Boolean values) + * - `NSString` + * - `FlutterStandardTypedData` + * - `NSArray` of supported values + * - `NSDictionary` with supported keys and values + * + * On the Dart side, these values are represented as follows: + * + * - `nil` or `NSNull`: null + * - `NSNumber`: `bool`, `int`, or `double`, depending on the contained value. + * - `NSString`: `String` + * - `FlutterStandardTypedData`: `Uint8List`, `Int32List`, `Int64List`, or `Float64List` + * - `NSArray`: `List` + * - `NSDictionary`: `Map` + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardMessageCodec : NSObject +/** + * Create a `FlutterStandardMessageCodec` who will read and write to \p readerWriter. + */ ++ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter; +@end + +/** + * Command object representing a method call on a `FlutterMethodChannel`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterMethodCall : NSObject +/** + * Creates a method call for invoking the specified named method with the + * specified arguments. + * + * @param method the name of the method to call. + * @param arguments the arguments value. + */ ++ (instancetype)methodCallWithMethodName:(NSString*)method arguments:(id _Nullable)arguments; + +/** + * The method name. + */ +@property(readonly, nonatomic) NSString* method; + +/** + * The arguments. + */ +@property(readonly, nonatomic, nullable) id arguments; +@end + +/** + * Error object representing an unsuccessful outcome of invoking a method + * on a `FlutterMethodChannel`, or an error event on a `FlutterEventChannel`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterError : NSObject +/** + * Creates a `FlutterError` with the specified error code, message, and details. + * + * @param code An error code string for programmatic use. + * @param message A human-readable error message. + * @param details Custom error details. + */ ++ (instancetype)errorWithCode:(NSString*)code + message:(NSString* _Nullable)message + details:(id _Nullable)details; +/** + The error code. + */ +@property(readonly, nonatomic) NSString* code; + +/** + The error message. + */ +@property(readonly, nonatomic, nullable) NSString* message; + +/** + The error details. + */ +@property(readonly, nonatomic, nullable) id details; +@end + +/** + * Type of numeric data items encoded in a `FlutterStandardDataType`. + * + * - FlutterStandardDataTypeUInt8: plain bytes + * - FlutterStandardDataTypeInt32: 32-bit signed integers + * - FlutterStandardDataTypeInt64: 64-bit signed integers + * - FlutterStandardDataTypeFloat64: 64-bit floats + */ +typedef NS_ENUM(NSInteger, FlutterStandardDataType) { + // NOLINTBEGIN(readability-identifier-naming) + FlutterStandardDataTypeUInt8, + FlutterStandardDataTypeInt32, + FlutterStandardDataTypeInt64, + FlutterStandardDataTypeFloat32, + FlutterStandardDataTypeFloat64, + // NOLINTEND(readability-identifier-naming) +}; + +/** + * A byte buffer holding `UInt8`, `SInt32`, `SInt64`, or `Float64` values, used + * with `FlutterStandardMessageCodec` and `FlutterStandardMethodCodec`. + * + * Two's complement encoding is used for signed integers. IEEE754 + * double-precision representation is used for floats. The platform's native + * endianness is assumed. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardTypedData : NSObject +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as plain bytes. + * + * @param data the byte data. + */ ++ (instancetype)typedDataWithBytes:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 32-bit signed integers. + * + * @param data the byte data. The length must be divisible by 4. + */ ++ (instancetype)typedDataWithInt32:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 64-bit signed integers. + * + * @param data the byte data. The length must be divisible by 8. + */ ++ (instancetype)typedDataWithInt64:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 32-bit floats. + * + * @param data the byte data. The length must be divisible by 8. + */ ++ (instancetype)typedDataWithFloat32:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 64-bit floats. + * + * @param data the byte data. The length must be divisible by 8. + */ ++ (instancetype)typedDataWithFloat64:(NSData*)data; + +/** + * The raw underlying data buffer. + */ +@property(readonly, nonatomic) NSData* data; + +/** + * The type of the encoded values. + */ +@property(readonly, nonatomic, assign) FlutterStandardDataType type; + +/** + * The number of value items encoded. + */ +@property(readonly, nonatomic, assign) UInt32 elementCount; + +/** + * The number of bytes used by the encoding of a single value item. + */ +@property(readonly, nonatomic, assign) UInt8 elementSize; +@end + +/** + * An arbitrarily large integer value, used with `FlutterStandardMessageCodec` + * and `FlutterStandardMethodCodec`. + */ +FLUTTER_DARWIN_EXPORT +FLUTTER_UNAVAILABLE("Unavailable on 2018-08-31. Deprecated on 2018-01-09. " + "FlutterStandardBigInteger was needed because the Dart 1.0 int type had no " + "size limit. With Dart 2.0, the int type is a fixed-size, 64-bit signed " + "integer. If you need to communicate larger integers, use NSString encoding " + "instead.") +@interface FlutterStandardBigInteger : NSObject +@end + +/** + * A codec for method calls and enveloped results. + * + * Method calls are encoded as binary messages with enough structure that the + * codec can extract a method name `NSString` and an arguments `NSObject`, + * possibly `nil`. These data items are used to populate a `FlutterMethodCall`. + * + * Result envelopes are encoded as binary messages with enough structure that + * the codec can determine whether the result was successful or an error. In + * the former case, the codec can extract the result `NSObject`, possibly `nil`. + * In the latter case, the codec can extract an error code `NSString`, a + * human-readable `NSString` error message (possibly `nil`), and a custom + * error details `NSObject`, possibly `nil`. These data items are used to + * populate a `FlutterError`. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterMethodCodec +/** + * Provides access to a shared instance this codec. + * + * @return The shared instance. + */ ++ (instancetype)sharedInstance; + +/** + * Encodes the specified method call into binary. + * + * @param methodCall The method call. The arguments value + * must be supported by this codec. + * @return The binary encoding. + */ +- (NSData*)encodeMethodCall:(FlutterMethodCall*)methodCall; + +/** + * Decodes the specified method call from binary. + * + * @param methodCall The method call to decode. + * @return The decoded method call. + */ +- (FlutterMethodCall*)decodeMethodCall:(NSData*)methodCall; + +/** + * Encodes the specified successful result into binary. + * + * @param result The result. Must be a value supported by this codec. + * @return The binary encoding. + */ +- (NSData*)encodeSuccessEnvelope:(id _Nullable)result; + +/** + * Encodes the specified error result into binary. + * + * @param error The error object. The error details value must be supported + * by this codec. + * @return The binary encoding. + */ +- (NSData*)encodeErrorEnvelope:(FlutterError*)error; + +/** + * Deccodes the specified result envelope from binary. + * + * @param envelope The error object. + * @return The result value, if the envelope represented a successful result, + * or a `FlutterError` instance, if not. + */ +- (id _Nullable)decodeEnvelope:(NSData*)envelope; +@end + +/** + * A `FlutterMethodCodec` using UTF-8 encoded JSON method calls and result + * envelopes. + * + * This codec is guaranteed to be compatible with the corresponding + * [JSONMethodCodec](https://api.flutter.dev/flutter/services/JSONMethodCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Values supported as methods arguments and result payloads are + * those supported as top-level or leaf values by `FlutterJSONMessageCodec`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterJSONMethodCodec : NSObject +@end + +/** + * A `FlutterMethodCodec` using the Flutter standard binary encoding. + * + * This codec is guaranteed to be compatible with the corresponding + * [StandardMethodCodec](https://api.flutter.dev/flutter/services/StandardMethodCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Values supported as method arguments and result payloads are those supported by + * `FlutterStandardMessageCodec`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardMethodCodec : NSObject +/** + * Create a `FlutterStandardMethodCodec` who will read and write to \p readerWriter. + */ ++ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCODECS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterDartProject.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterDartProject.h new file mode 100644 index 000000000..c1fd8db50 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterDartProject.h @@ -0,0 +1,102 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERDARTPROJECT_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERDARTPROJECT_H_ + +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A set of Flutter and Dart assets used by a `FlutterEngine` to initialize execution. + * + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterDartProject : NSObject + +/** + * Initializes a Flutter Dart project from a bundle. + * + * The bundle must either contain a flutter_assets resource directory, or set the Info.plist key + * FLTAssetsPath to override that name (if you are doing a custom build using a different name). + * + * @param bundle The bundle containing the Flutter assets directory. If nil, the App framework + * created by Flutter will be used. + */ +- (instancetype)initWithPrecompiledDartBundle:(nullable NSBundle*)bundle NS_DESIGNATED_INITIALIZER; +/** + * Unavailable - use `init` instead. + */ +- (instancetype)initFromDefaultSourceForConfiguration API_UNAVAILABLE(macos) + FLUTTER_UNAVAILABLE("Use -init instead."); + +/** + * Returns the default identifier for the bundle where we expect to find the Flutter Dart + * application. + */ ++ (NSString*)defaultBundleIdentifier; + +/** + * An NSArray of NSStrings to be passed as command line arguments to the Dart entrypoint. + * + * If this is not explicitly set, this will default to the contents of + * [NSProcessInfo arguments], without the binary name. + * + * Set this to nil to pass no arguments to the Dart entrypoint. + */ +@property(nonatomic, nullable, copy) + NSArray* dartEntrypointArguments API_UNAVAILABLE(ios); + +/** + * Returns the file name for the given asset. If the bundle with the identifier + * "io.flutter.flutter.app" exists, it will try use that bundle; otherwise, it + * will use the main bundle. To specify a different bundle, use + * `+lookupKeyForAsset:fromBundle`. + * + * @param asset The name of the asset. The name can be hierarchical. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset; + +/** + * Returns the file name for the given asset. + * The returned file name can be used to access the asset in the supplied bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param bundle The `NSBundle` to use for looking up the asset. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset fromBundle:(nullable NSBundle*)bundle; + +/** + * Returns the file name for the given asset which originates from the specified package. + * The returned file name can be used to access the asset in the application's main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package; + +/** + * Returns the file name for the given asset which originates from the specified package. + * The returned file name can be used to access the asset in the specified bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @param bundle The bundle to use when doing the lookup. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset + fromPackage:(NSString*)package + fromBundle:(nullable NSBundle*)bundle; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERDARTPROJECT_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterEngine.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterEngine.h new file mode 100644 index 000000000..c11e2c72f --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterEngine.h @@ -0,0 +1,495 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINE_H_ + +#import +#import + +#import "FlutterBinaryMessenger.h" +#import "FlutterDartProject.h" +#import "FlutterMacros.h" +#import "FlutterPlugin.h" +#import "FlutterTexture.h" + +@class FlutterViewController; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The dart entrypoint that is associated with `main()`. This is to be used as an argument to the + * `runWithEntrypoint*` methods. + */ +// NOLINTNEXTLINE(readability-identifier-naming) +extern NSString* const FlutterDefaultDartEntrypoint; + +/** + * The default Flutter initial route ("/"). + */ +// NOLINTNEXTLINE(readability-identifier-naming) +extern NSString* const FlutterDefaultInitialRoute; + +/** + * The FlutterEngine class coordinates a single instance of execution for a + * `FlutterDartProject`. It may have zero or one `FlutterViewController` at a + * time, which can be specified via `-setViewController:`. + * `FlutterViewController`'s `initWithEngine` initializer will automatically call + * `-setViewController:` for itself. + * + * A FlutterEngine can be created independently of a `FlutterViewController` for + * headless execution. It can also persist across the lifespan of multiple + * `FlutterViewController` instances to maintain state and/or asynchronous tasks + * (such as downloading a large file). + * + * A FlutterEngine can also be used to prewarm the Dart execution environment and reduce the + * latency of showing the Flutter screen when a `FlutterViewController` is created and presented. + * See http://flutter.dev/docs/development/add-to-app/performance for more details on loading + * performance. + * + * Alternatively, you can simply create a new `FlutterViewController` with only a + * `FlutterDartProject`. That `FlutterViewController` will internally manage its + * own instance of a FlutterEngine, but will not guarantee survival of the engine + * beyond the life of the ViewController. + * + * A newly initialized FlutterEngine will not actually run a Dart Isolate until + * either `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is invoked. + * One of these methods must be invoked before calling `-setViewController:`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEngine : NSObject + +/** + * Default initializer for a FlutterEngine. + * + * Threads created by this FlutterEngine will appear as "FlutterEngine #" in + * Instruments. The prefix can be customized using `initWithName`. + * + * The engine will execute the project located in the bundle with the identifier + * "io.flutter.flutter.app" (the default for Flutter projects). + * + * A newly initialized engine will not run until either `-runWithEntrypoint:` or + * `-runWithEntrypoint:libraryURI:` is called. + * + * FlutterEngine created with this method will have allowHeadlessExecution set to `YES`. + * This means that the engine will continue to run regardless of whether a `FlutterViewController` + * is attached to it or not, until `-destroyContext:` is called or the process finishes. + */ +- (instancetype)init; + +/** + * Initialize this FlutterEngine. + * + * The engine will execute the project located in the bundle with the identifier + * "io.flutter.flutter.app" (the default for Flutter projects). + * + * A newly initialized engine will not run until either `-runWithEntrypoint:` or + * `-runWithEntrypoint:libraryURI:` is called. + * + * FlutterEngine created with this method will have allowHeadlessExecution set to `YES`. + * This means that the engine will continue to run regardless of whether a `FlutterViewController` + * is attached to it or not, until `-destroyContext:` is called or the process finishes. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + */ +- (instancetype)initWithName:(NSString*)labelPrefix; + +/** + * Initialize this FlutterEngine with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterEngine will attempt to locate + * the project in a default location (the flutter_assets folder in the iOS application + * bundle). + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI:` is called. + * + * FlutterEngine created with this method will have allowHeadlessExecution set to `YES`. + * This means that the engine will continue to run regardless of whether a `FlutterViewController` + * is attached to it or not, until `-destroyContext:` is called or the process finishes. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + * @param project The `FlutterDartProject` to run. + */ +- (instancetype)initWithName:(NSString*)labelPrefix project:(nullable FlutterDartProject*)project; + +/** + * Initialize this FlutterEngine with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterEngine will attempt to locate + * the project in a default location (the flutter_assets folder in the iOS application + * bundle). + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI:` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + * @param project The `FlutterDartProject` to run. + * @param allowHeadlessExecution Whether or not to allow this instance to continue + * running after passing a nil `FlutterViewController` to `-setViewController:`. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(nullable FlutterDartProject*)project + allowHeadlessExecution:(BOOL)allowHeadlessExecution; + +/** + * Initialize this FlutterEngine with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterEngine will attempt to locate + * the project in a default location (the flutter_assets folder in the iOS application + * bundle). + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI:` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + * @param project The `FlutterDartProject` to run. + * @param allowHeadlessExecution Whether or not to allow this instance to continue + * running after passing a nil `FlutterViewController` to `-setViewController:`. + * @param restorationEnabled Whether state restoration is enabled. When true, the framework will + * wait for the attached view controller to provide restoration data. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(nullable FlutterDartProject*)project + allowHeadlessExecution:(BOOL)allowHeadlessExecution + restorationEnabled:(BOOL)restorationEnabled NS_DESIGNATED_INITIALIZER; + +/** + * Runs a Dart program on an Isolate from the main Dart library (i.e. the library that + * contains `main()`), using `main()` as the entrypoint (the default for Flutter projects), + * and using "/" (the default route) as the initial route. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)run; + +/** + * Runs a Dart program on an Isolate from the main Dart library (i.e. the library that + * contains `main()`), using "/" (the default route) as the initial route. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from the same Dart + * library that contains the app's main() function. If this is FlutterDefaultDartEntrypoint (or + * nil) it will default to `main()`. If it is not the app's main() function, that function must + * be decorated with `@pragma(vm:entry-point)` to ensure the method is not tree-shaken by the Dart + * compiler. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint; + +/** + * Runs a Dart program on an Isolate from the main Dart library (i.e. the library that + * contains `main()`). + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from the same Dart + * library that contains the app's main() function. If this is FlutterDefaultDartEntrypoint (or + * nil), it will default to `main()`. If it is not the app's main() function, that function must + * be decorated with `@pragma(vm:entry-point)` to ensure the method is not tree-shaken by the Dart + * compiler. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint + initialRoute:(nullable NSString*)initialRoute; + +/** + * Runs a Dart program on an Isolate using the specified entrypoint and Dart library, + * which may not be the same as the library containing the Dart program's `main()` function. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param uri The URI of the Dart library which contains the entrypoint method + * (example "package:foo_package/main.dart"). If nil, this will default to + * the same library as the `main()` function in the Dart program. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint libraryURI:(nullable NSString*)uri; + +/** + * Runs a Dart program on an Isolate using the specified entrypoint and Dart library, + * which may not be the same as the library containing the Dart program's `main()` function. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint + * method (example "package:foo_package/main.dart"). If nil, this will + * default to the same library as the `main()` function in the Dart program. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI + initialRoute:(nullable NSString*)initialRoute; + +/** + * Runs a Dart program on an Isolate using the specified entrypoint and Dart library, + * which may not be the same as the library containing the Dart program's `main()` function. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint + * method (example "package:foo_package/main.dart"). If nil, this will + * default to the same library as the `main()` function in the Dart program. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * @param entrypointArgs Arguments passed as a list of string to Dart's entrypoint function. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI + initialRoute:(nullable NSString*)initialRoute + entrypointArgs:(nullable NSArray*)entrypointArgs; + +/** + * Destroy running context for an engine. + * + * This method can be used to force the FlutterEngine object to release all resources. + * After sending this message, the object will be in an unusable state until it is deallocated. + * Accessing properties or sending messages to it will result in undefined behavior or runtime + * errors. + */ +- (void)destroyContext; + +/** + * Ensures that Flutter will generate a semantics tree. + * + * This is enabled by default if certain accessibility services are turned on by + * the user, or when using a Simulator. This method allows a user to turn + * semantics on when they would not ordinarily be generated and the performance + * overhead is not a concern, e.g. for UI testing. Note that semantics should + * never be programmatically turned off, as it would potentially disable + * accessibility services an end user has requested. + * + * This method must only be called after launching the engine via + * `-runWithEntrypoint:` or `-runWithEntryPoint:libraryURI`. + * + * Although this method returns synchronously, it does not guarantee that a + * semantics tree is actually available when the method returns. It + * synchronously ensures that the next frame the Flutter framework creates will + * have a semantics tree. + * + * You can subscribe to semantics updates via `NSNotificationCenter` by adding + * an observer for the name `FlutterSemanticsUpdateNotification`. The `object` + * parameter will be the `FlutterViewController` associated with the semantics + * update. This will asynchronously fire after a semantics tree has actually + * built (which may be some time after the frame has been rendered). + */ +- (void)ensureSemanticsEnabled; + +/** + * Sets the `FlutterViewController` for this instance. The FlutterEngine must be + * running (e.g. a successful call to `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI`) + * before calling this method. Callers may pass nil to remove the viewController + * and have the engine run headless in the current process. + * + * A FlutterEngine can only have one `FlutterViewController` at a time. If there is + * already a `FlutterViewController` associated with this instance, this method will replace + * the engine's current viewController with the newly specified one. + * + * Setting the viewController will signal the engine to start animations and drawing, and unsetting + * it will signal the engine to stop animations and drawing. However, neither will impact the state + * of the Dart program's execution. + */ +@property(nonatomic, weak) FlutterViewController* viewController; + +/** + * The `FlutterMethodChannel` used for localization related platform messages, such as + * setting the locale. + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly, nullable) FlutterMethodChannel* localizationChannel; +/** + * The `FlutterMethodChannel` used for navigation related platform messages. + * + * Can be nil after `destroyContext` is called. + * + * @see [Navigation + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/navigation-constant.html) + * @see [Navigator Widget](https://api.flutter.dev/flutter/widgets/Navigator-class.html) + */ +@property(nonatomic, readonly) FlutterMethodChannel* navigationChannel; + +/** + * The `FlutterMethodChannel` used for restoration related platform messages. + * + * Can be nil after `destroyContext` is called. + * + * @see [Restoration + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/restoration-constant.html) + */ +@property(nonatomic, readonly) FlutterMethodChannel* restorationChannel; + +/** + * The `FlutterMethodChannel` used for core platform messages, such as + * information about the screen orientation. + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly) FlutterMethodChannel* platformChannel; + +/** + * The `FlutterMethodChannel` used to communicate text input events to the + * Dart Isolate. + * + * Can be nil after `destroyContext` is called. + * + * @see [Text Input + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/textInput-constant.html) + */ +@property(nonatomic, readonly) FlutterMethodChannel* textInputChannel; + +/** + * The `FlutterBasicMessageChannel` used to communicate app lifecycle events + * to the Dart Isolate. + * + * Can be nil after `destroyContext` is called. + * + * @see [Lifecycle + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/lifecycle-constant.html) + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* lifecycleChannel; + +/** + * The `FlutterBasicMessageChannel` used for communicating system events, such as + * memory pressure events. + * + * Can be nil after `destroyContext` is called. + * + * @see [System + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/system-constant.html) + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* systemChannel; + +/** + * The `FlutterBasicMessageChannel` used for communicating user settings such as + * clock format and text scale. + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* settingsChannel; + +/** + * The `FlutterBasicMessageChannel` used for communicating key events + * from physical keyboards + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* keyEventChannel; + +/** + * The `NSURL` of the Dart VM Service for the service isolate. + * + * This is only set in debug and profile runtime modes, and only after the + * Dart VM Service is ready. In release mode or before the Dart VM Service has + * started, it returns `nil`. + */ +@property(nonatomic, readonly, nullable) NSURL* vmServiceUrl; + +/** + * The `FlutterBinaryMessenger` associated with this FlutterEngine (used for communicating with + * channels). + */ +@property(nonatomic, readonly) NSObject* binaryMessenger; + +/** + * The `FlutterTextureRegistry` associated with this FlutterEngine (used to register textures). + */ +@property(nonatomic, readonly) NSObject* textureRegistry; + +/** + * The UI Isolate ID of the engine. + * + * This property will be nil if the engine is not running. + */ +@property(nonatomic, readonly, copy, nullable) NSString* isolateId; + +/** + * Whether or not GPU calls are allowed. + * + * Typically this is set when the app is backgrounded and foregrounded. + */ +@property(nonatomic, assign) BOOL isGpuDisabled; + +@end + +/** + * Exposes parts of a `FlutterEngine` for registration purposes. + * + * This is used when the engine is created implicitly to allow registering + * plugins, application-level method channels, platform views, etc. + */ +@protocol FlutterImplicitEngineBridge + +/** + * The `FlutterPluginRegistry` for the created `FlutterEngine`. + * + * This can be used to vend `FlutterPluginRegistrar`s for plugins. + */ +@property(nonatomic, readonly) NSObject* pluginRegistry; + +/** + * The `FlutterApplicationRegistrar` for the created `FlutterEngine`. + * + * This registrar provides access to application-level services, such as the engine's + * `FlutterBinaryMessenger` or `FlutterTextureRegistry`. + */ +@property(nonatomic, readonly) NSObject* applicationRegistrar; + +@end + +/** + * Protocol for receiving a callback when an implicit engine is initialized, such as when created by + * a FlutterViewController from a storyboard. + * + * This provides the engine bridge to the listener. + */ +@protocol FlutterImplicitEngineDelegate +@required + +/** + * Called once the implicit `FlutterEngine` is initialized. + * + * The `FlutterImplicitEngineBridge` can then be used to register plugins, + * application-level method channels, platform views, etc. + */ +- (void)didInitializeImplicitFlutterEngine:(NSObject*)engineBridge; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterEngineGroup.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterEngineGroup.h new file mode 100644 index 000000000..47cdc0753 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterEngineGroup.h @@ -0,0 +1,115 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINEGROUP_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINEGROUP_H_ + +#import + +#import "FlutterEngine.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Options that control how a FlutterEngine should be created. */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEngineGroupOptions : NSObject + +/** + * The name of a top-level function from a Dart library. If this is FlutterDefaultDartEntrypoint + * (or nil); this will default to `main()`. If it is not the app's main() function, that function + * must be decorated with `@pragma(vm:entry-point)` to ensure themethod is not tree-shaken by the + * Dart compiler. + */ +@property(nonatomic, copy, nullable) NSString* entrypoint; + +/** + * The URI of the Dart library which contains the entrypoint method. If nil, this will default to + * the same library as the `main()` function in the Dart program. + */ +@property(nonatomic, copy, nullable) NSString* libraryURI; + +/** + * The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + */ +@property(nonatomic, copy, nullable) NSString* initialRoute; + +/** + * Arguments passed as a list of string to Dart's entrypoint function. + */ +@property(nonatomic, copy, nullable) NSArray* entrypointArgs; +@end + +/** + * Represents a collection of FlutterEngines who share resources which allows + * them to be created with less time const and occupy less memory than just + * creating multiple FlutterEngines. + * + * Deleting a FlutterEngineGroup doesn't invalidate existing FlutterEngines, but + * it eliminates the possibility to create more FlutterEngines in that group. + * + * @warning This class is a work-in-progress and may change. + * @see https://github.com/flutter/flutter/issues/72009 + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEngineGroup : NSObject +- (instancetype)init NS_UNAVAILABLE; + +/** + * Initialize a new FlutterEngineGroup. + * + * @param name The name that will present in the threads shared across the + * engines in this group. + * @param project The `FlutterDartProject` that all FlutterEngines in this group + * will be executing. + */ +- (instancetype)initWithName:(NSString*)name + project:(nullable FlutterDartProject*)project NS_DESIGNATED_INITIALIZER; + +/** + * Creates a running `FlutterEngine` that shares components with this group. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint method. IF nil, + * this will default to the same library as the `main()` function in the Dart program. + * + * @see FlutterEngineGroup + */ +- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI; + +/** + * Creates a running `FlutterEngine` that shares components with this group. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint method. IF nil, + * this will default to the same library as the `main()` function in the Dart program. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * + * @see FlutterEngineGroup + */ +- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI + initialRoute:(nullable NSString*)initialRoute; + +/** + * Creates a running `FlutterEngine` that shares components with this group. + * + * @param options Options that control how a FlutterEngine should be created. + * + * @see FlutterEngineGroupOptions + */ +- (FlutterEngine*)makeEngineWithOptions:(nullable FlutterEngineGroupOptions*)options; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINEGROUP_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterHeadlessDartRunner.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterHeadlessDartRunner.h new file mode 100644 index 000000000..08069ab5b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterHeadlessDartRunner.h @@ -0,0 +1,97 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERHEADLESSDARTRUNNER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERHEADLESSDARTRUNNER_H_ + +#import + +#import "FlutterBinaryMessenger.h" +#import "FlutterDartProject.h" +#import "FlutterEngine.h" +#import "FlutterMacros.h" + +/** + * A callback for when FlutterHeadlessDartRunner has attempted to start a Dart + * Isolate in the background. + * + * @param success YES if the Isolate was started and run successfully, NO + * otherwise. + */ +typedef void (^FlutterHeadlessDartRunnerCallback)(BOOL success); + +/** + * The deprecated FlutterHeadlessDartRunner runs Flutter Dart code with a null rasterizer, + * and no native drawing surface. It is appropriate for use in running Dart + * code e.g. in the background from a plugin. + * + * Most callers should prefer using `FlutterEngine` directly; this interface exists + * for legacy support. + */ +FLUTTER_DARWIN_EXPORT +FLUTTER_DEPRECATED("FlutterEngine should be used rather than FlutterHeadlessDartRunner") +@interface FlutterHeadlessDartRunner : FlutterEngine + +/** + * Initialize this FlutterHeadlessDartRunner with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate + * the project in a default location. + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances + * @param projectOrNil The `FlutterDartProject` to run. + */ +- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil; + +/** + * Initialize this FlutterHeadlessDartRunner with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate + * the project in a default location. + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances + * @param projectOrNil The `FlutterDartProject` to run. + * @param allowHeadlessExecution Must be set to `YES`. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(FlutterDartProject*)projectOrNil + allowHeadlessExecution:(BOOL)allowHeadlessExecution; + +/** + * Initialize this FlutterHeadlessDartRunner with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate + * the project in a default location. + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances + * @param projectOrNil The `FlutterDartProject` to run. + * @param allowHeadlessExecution Must be set to `YES`. + * @param restorationEnabled Must be set to `NO`. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(FlutterDartProject*)projectOrNil + allowHeadlessExecution:(BOOL)allowHeadlessExecution + restorationEnabled:(BOOL)restorationEnabled NS_DESIGNATED_INITIALIZER; + +/** + * Not recommended for use - will initialize with a default label ("io.flutter.headless") + * and the default FlutterDartProject. + */ +- (instancetype)init; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERHEADLESSDARTRUNNER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterHourFormat.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterHourFormat.h new file mode 100644 index 000000000..e33e1a0ac --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterHourFormat.h @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERHOURFORMAT_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERHOURFORMAT_H_ + +#import + +@interface FlutterHourFormat : NSObject ++ (BOOL)isAlwaysUse24HourFormat; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERHOURFORMAT_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterMacros.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterMacros.h new file mode 100644 index 000000000..7f53b4133 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterMacros.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERMACROS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERMACROS_H_ + +#if defined(FLUTTER_FRAMEWORK) + +#define FLUTTER_DARWIN_EXPORT __attribute__((visibility("default"))) + +#else // defined(FLUTTER_SDK) + +#define FLUTTER_DARWIN_EXPORT + +#endif // defined(FLUTTER_SDK) + +#ifndef NS_ASSUME_NONNULL_BEGIN +#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") +#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") +#endif // defined(NS_ASSUME_NONNULL_BEGIN) + +/** + * Indicates that the API has been deprecated for the specified reason. Code + * that uses the deprecated API will continue to work as before. However, the + * API will soon become unavailable and users are encouraged to immediately take + * the appropriate action mentioned in the deprecation message and the BREAKING + * CHANGES section present in the Flutter.h umbrella header. + */ +#define FLUTTER_DEPRECATED(msg) __attribute__((__deprecated__(msg))) + +/** + * Indicates that the previously deprecated API is now unavailable. Code that + * uses the API will not work and the declaration of the API is only a stub + * meant to display the given message detailing the actions for the user to take + * immediately. + */ +#define FLUTTER_UNAVAILABLE(msg) __attribute__((__unavailable__(msg))) + +#if __has_feature(objc_arc) +#define FLUTTER_ASSERT_ARC +#define FLUTTER_ASSERT_NOT_ARC #error ARC must be disabled ! +#else +#define FLUTTER_ASSERT_ARC #error ARC must be enabled ! +#define FLUTTER_ASSERT_NOT_ARC +#endif + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERMACROS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPlatformViews.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPlatformViews.h new file mode 100644 index 000000000..4742bfe8e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPlatformViews.h @@ -0,0 +1,56 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLATFORMVIEWS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLATFORMVIEWS_H_ + +#import + +#import "FlutterCodecs.h" +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Wraps a `UIView` for embedding in the Flutter hierarchy + */ +@protocol FlutterPlatformView +/** + * Returns a reference to the `UIView` that is wrapped by this `FlutterPlatformView`. + */ +- (UIView*)view; +@end + +FLUTTER_DARWIN_EXPORT +@protocol FlutterPlatformViewFactory +/** + * Create a `FlutterPlatformView`. + * + * Implemented by iOS code that expose a `UIView` for embedding in a Flutter app. + * + * The implementation of this method should create a new `UIView` and return it. + * + * @param frame The rectangle for the newly created `UIView` measured in points. + * @param viewId A unique identifier for this `UIView`. + * @param args Parameters for creating the `UIView` sent from the Dart side of the Flutter app. + * If `createArgsCodec` is not implemented, or if no creation arguments were sent from the Dart + * code, this will be null. Otherwise this will be the value sent from the Dart code as decoded by + * `createArgsCodec`. + */ +- (NSObject*)createWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args; + +/** + * Returns the `FlutterMessageCodec` for decoding the args parameter of `createWithFrame`. + * + * Only needs to be implemented if `createWithFrame` needs an arguments parameter. + */ +@optional +- (NSObject*)createArgsCodec; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLATFORMVIEWS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPlugin.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPlugin.h new file mode 100644 index 000000000..24e83756b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPlugin.h @@ -0,0 +1,513 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGIN_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGIN_H_ + +#import +#import + +#import "FlutterBinaryMessenger.h" +#import "FlutterChannels.h" +#import "FlutterCodecs.h" +#import "FlutterPlatformViews.h" +#import "FlutterSceneLifeCycle.h" +#import "FlutterTexture.h" + +NS_ASSUME_NONNULL_BEGIN +@protocol FlutterPluginRegistrar; +@protocol FlutterPluginRegistry; + +#pragma mark - +/** + * Protocol for listener of events from the UIApplication, typically a FlutterPlugin. + */ +@protocol FlutterApplicationLifeCycleDelegate + +@optional +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if this vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if this vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + willFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationDidBecomeActive:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillResignActive:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationDidEnterBackground:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillEnterForeground:(UIApplication*)application; + +/** + Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillTerminate:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings + API_DEPRECATED( + "See -[UIApplicationDelegate application:didRegisterUserNotificationSettings:] deprecation", + ios(8.0, 10.0)); + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + didReceiveRemoteNotification:(NSDictionary*)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didReceiveLocalNotification:(UILocalNotification*)notification + API_DEPRECATED( + "See -[UIApplicationDelegate application:didReceiveLocalNotification:] deprecation", + ios(4.0, 10.0)); + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + options:(NSDictionary*)options; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + sourceApplication:(NSString*)sourceApplication + annotation:(id)annotation; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler + API_AVAILABLE(ios(9.0)); + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + handleEventsForBackgroundURLSession:(nonnull NSString*)identifier + completionHandler:(nonnull void (^)(void))completionHandler; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + continueUserActivity:(NSUserActivity*)userActivity + restorationHandler:(void (^)(NSArray*))restorationHandler; +@end + +#pragma mark - +/** + * A plugin registration callback. + * + * Used for registering plugins with additional instances of + * `FlutterPluginRegistry`. + * + * @param registry The registry to register plugins with. + */ +typedef void (*FlutterPluginRegistrantCallback)(NSObject* registry); + +#pragma mark - +/** + * Implemented by the iOS part of a Flutter plugin. + * + * Defines a set of optional callback methods and a method to set up the plugin + * and register it to be called by other application components. + */ +@protocol FlutterPlugin +@required +/** + * Registers this plugin using the context information and callback registration + * methods exposed by the given registrar. + * + * The registrar is obtained from a `FlutterPluginRegistry` which keeps track of + * the identity of registered plugins and provides basic support for cross-plugin + * coordination. + * + * The caller of this method, a plugin registrant, is usually autogenerated by + * Flutter tooling based on declared plugin dependencies. The generated registrant + * asks the registry for a registrar for each plugin, and calls this method to + * allow the plugin to initialize itself and register callbacks with application + * objects available through the registrar protocol. + * + * @param registrar A helper providing application context and methods for + * registering callbacks. + */ ++ (void)registerWithRegistrar:(NSObject*)registrar; +@optional +/** + * Set a callback for registering plugins to an additional `FlutterPluginRegistry`, + * including headless `FlutterEngine` instances. + * + * This method is typically called from within an application's `AppDelegate` at + * startup to allow for plugins which create additional `FlutterEngine` instances + * to register the application's plugins. + * + * @param callback A callback for registering some set of plugins with a + * `FlutterPluginRegistry`. + */ ++ (void)setPluginRegistrantCallback:(FlutterPluginRegistrantCallback)callback; +@optional +/** + * Called if this plugin has been registered to receive `FlutterMethodCall`s. + * + * @param call The method call command object. + * @param result A callback for submitting the result of the call. + */ +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result; +@optional +/** + * Called when a plugin is being removed from a `FlutterEngine`, which is + * usually the result of the `FlutterEngine` being deallocated. This method + * provides the opportunity to do necessary cleanup. + * + * You will only receive this method if you registered your plugin instance with + * the `FlutterEngine` via `-[FlutterPluginRegistry publish:]`. + * + * @param registrar The registrar that was used to publish the plugin. + * + */ +- (void)detachFromEngineForRegistrar:(NSObject*)registrar; +@end + +#pragma mark - +/** + * How the UIGestureRecognizers of a platform view are blocked. + * + * UIGestureRecognizers of platform views can be blocked based on decisions made by the + * Flutter Framework (e.g. When an interact-able widget is covering the platform view). + */ +typedef enum { + // NOLINTBEGIN(readability-identifier-naming) + /** + * Flutter blocks all the UIGestureRecognizers on the platform view as soon as it + * decides they should be blocked. + * + * With this policy, only the `touchesBegan` method for all the UIGestureRecognizers is guaranteed + * to be called. + */ + FlutterPlatformViewGestureRecognizersBlockingPolicyEager, + /** + * Flutter blocks the platform view's UIGestureRecognizers from recognizing only after + * touchesEnded was invoked. + * + * This results in the platform view's UIGestureRecognizers seeing the entire touch sequence, + * but never recognizing the gesture (and never invoking actions). + */ + FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded, + // NOLINTEND(readability-identifier-naming) +} FlutterPlatformViewGestureRecognizersBlockingPolicy; + +#pragma mark - +/** + * The base interface for `FlutterPluginRegistrar` and `FlutterApplicationRegistrar`. + * + * Provides registration context for the application or plugins. + */ +@protocol FlutterBaseRegistrar +/** + * Returns a `FlutterBinaryMessenger` for creating Dart/iOS communication + * channels to be used by the application or a plugin. + * + * @return The messenger. + */ +- (NSObject*)messenger; + +/** + * Returns a `FlutterTextureRegistry` for registering textures + * provided by the application or a plugin. + * + * @return The texture registry. + */ +- (NSObject*)textures; + +/** + * Registers a `FlutterPlatformViewFactory` for creation of platform views. + * + * Applications or plugins can expose `UIView` for embedding in Flutter apps by registering a view + * factory. + * + * @param factory The view factory that will be registered. + * @param factoryId A unique identifier for the factory, the Dart code of the Flutter app can use + * this identifier to request creation of a `UIView` by the registered factory. + */ +- (void)registerViewFactory:(NSObject*)factory + withId:(NSString*)factoryId; + +/** + * Registers a `FlutterPlatformViewFactory` for creation of platform views. + * + * Applications or plugins can expose a `UIView` for embedding in Flutter apps by registering a view + * factory. + * + * @param factory The view factory that will be registered. + * @param factoryId A unique identifier for the factory, the Dart code of the Flutter app can use + * this identifier to request creation of a `UIView` by the registered factory. + * @param gestureRecognizersBlockingPolicy How UIGestureRecognizers on the platform views are + * blocked. + * + */ +- (void)registerViewFactory:(NSObject*)factory + withId:(NSString*)factoryId + gestureRecognizersBlockingPolicy: + (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy; +@end + +/** + * A registrar for Flutter applications. + * + * This registrar provides access to application-level services, such as the binary messenger and + * texture registry. + * + * See also `FlutterBaseRegistrar`. + */ +@protocol FlutterApplicationRegistrar +@end + +/** + * Registration context for a single `FlutterPlugin`, providing a one stop shop + * for the plugin to access contextual information and register callbacks for + * various application events. + * + * Registrars are obtained from a `FlutterPluginRegistry` which keeps track of + * the identity of registered plugins and provides basic support for cross-plugin + * coordination. + */ +@protocol FlutterPluginRegistrar + +/** + * The `UIViewController` whose view is displaying Flutter content. + * + * The plugin typically should not store a strong reference to this view + * controller. + * + * This property is provided for backwards compatibility for apps that assume + * a single view, and will eventually be replaced by the multi-view API variant. + * + * This property may be |nil|, for instance in a headless environment, or when + * the underlying Flutter engine is deallocated. + */ +@property(nullable, readonly) UIViewController* viewController; + +/** + * Publishes a value for external use of the plugin. + * + * Plugins may publish a single value, such as an instance of the + * plugin's main class, for situations where external control or + * interaction is needed. + * + * The published value will be available from the `FlutterPluginRegistry`. + * Repeated calls overwrite any previous publication. + * + * @param value The value to be published. + */ +- (void)publish:(NSObject*)value; + +/** + * Registers the plugin as a receiver of incoming method calls from the Dart side + * on the specified `FlutterMethodChannel`. + * + * @param delegate The receiving object, such as the plugin's main class. + * @param channel The channel + */ +- (void)addMethodCallDelegate:(NSObject*)delegate + channel:(FlutterMethodChannel*)channel; + +/** + * Registers the plugin as a receiver of `UIApplicationDelegate` calls. + * + * @param delegate The receiving object, such as the plugin's main class. + */ +- (void)addApplicationDelegate:(NSObject*)delegate + NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in plugins used in app extensions"); + +/** + * Registers the plugin as a receiver of `UISceneDelegate` and `UIWindowSceneDelegate` calls. + * + * @param delegate The receiving object, such as the plugin's main class. + */ +- (void)addSceneDelegate:(NSObject*)delegate + API_AVAILABLE(ios(13.0)); + +/** + * Returns the file name for the given asset. + * The returned file name can be used to access the asset in the application's main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @return the file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset; + +/** + * Returns the file name for the given asset which originates from the specified package. + * The returned file name can be used to access the asset in the application's main bundle. + * + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @return the file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package; +@end + +#pragma mark - +/** + * A registry of Flutter iOS plugins. + * + * Plugins are identified by unique string keys, typically the name of the + * plugin's main class. The registry tracks plugins by this key, mapping it to + * a value published by the plugin during registration, if any. This provides a + * very basic means of cross-plugin coordination with loose coupling between + * unrelated plugins. + * + * Plugins typically need contextual information and the ability to register + * callbacks for various application events. To keep the API of the registry + * focused, these facilities are not provided directly by the registry, but by + * a `FlutterPluginRegistrar`, created by the registry in exchange for the unique + * key of the plugin. + * + * There is no implied connection between the registry and the registrar. + * Specifically, callbacks registered by the plugin via the registrar may be + * relayed directly to the underlying iOS application objects. + */ +@protocol FlutterPluginRegistry +/** + * Returns a registrar for registering a plugin. + * + * @param pluginKey The unique key identifying the plugin. + */ +- (nullable NSObject*)registrarForPlugin:(NSString*)pluginKey; +/** + * Returns whether the specified plugin has been registered. + * + * @param pluginKey The unique key identifying the plugin. + * @return `YES` if `registrarForPlugin` has been called with `pluginKey`. + */ +- (BOOL)hasPlugin:(NSString*)pluginKey; + +/** + * Returns a value published by the specified plugin. + * + * @param pluginKey The unique key identifying the plugin. + * @return An object published by the plugin, if any. Will be `NSNull` if + * nothing has been published. Will be `nil` if the plugin has not been + * registered. + */ +- (nullable NSObject*)valuePublishedByPlugin:(NSString*)pluginKey; +@end + +#pragma mark - +/** + * The target of registration of plugins. + * + * This often is hooked up to the GeneratedPluginRegistrant which is + * automatically generated by Flutter for the dependencies listed in the + * project. + */ +@protocol FlutterPluginRegistrant +@required +/** + * Register all the plugins for the registrant. + * + * This will be called after a FlutterEngine has been instantiated, the registry + * will connect any plugins to that engine. + * + * @param registry The registry where plugins will be registered. + */ +- (void)registerWithRegistry:(NSObject*)registry; +@end + +#pragma mark - +/** + * Implement this in the `UIAppDelegate` of your app to enable Flutter plugins to register + * themselves to the application life cycle events. + * + * For plugins to receive events from `UNUserNotificationCenter`, register this as the + * `UNUserNotificationCenterDelegate`. + */ +@protocol FlutterAppLifeCycleProvider + +/** + * Called when registering a new `FlutterApplicaitonLifeCycleDelegate`. + * + * See also: `-[FlutterAppDelegate addApplicationLifeCycleDelegate:]` + */ +- (void)addApplicationLifeCycleDelegate:(NSObject*)delegate; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGIN_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h new file mode 100644 index 000000000..95d1e611e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h @@ -0,0 +1,148 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ + +#import "FlutterPlugin.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Propagates `UIAppDelegate` callbacks to registered plugins. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterPluginAppLifeCycleDelegate : NSObject + +/** + * Registers `delegate` to receive life cycle callbacks via this FlutterPluginAppLifeCycleDelegate + * as long as it is alive. + * + * `delegate` will only be referenced weakly. + */ +- (void)addDelegate:(NSObject*)delegate; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if any plugin vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if any plugin vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + willFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Called if this plugin has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings + API_DEPRECATED( + "See -[UIApplicationDelegate application:didRegisterUserNotificationSettings:] deprecation", + ios(8.0, 10.0)); + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didReceiveRemoteNotification:(NSDictionary*)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didReceiveLocalNotification:(UILocalNotification*)notification + API_DEPRECATED( + "See -[UIApplicationDelegate application:didReceiveLocalNotification:] deprecation", + ios(4.0, 10.0)); + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + options:(NSDictionary*)options; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + sourceApplication:(NSString*)sourceApplication + annotation:(id)annotation; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler + API_AVAILABLE(ios(9.0)); + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + handleEventsForBackgroundURLSession:(nonnull NSString*)identifier + completionHandler:(nonnull void (^)(void))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @returns `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + continueUserActivity:(NSUserActivity*)userActivity + restorationHandler:(void (^)(NSArray*))restorationHandler; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterSceneDelegate.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterSceneDelegate.h new file mode 100644 index 000000000..2238d7333 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterSceneDelegate.h @@ -0,0 +1,28 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ + +#import +#import "FlutterMacros.h" +#import "FlutterSceneLifeCycle.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The UISceneDelegate used by Flutter by default. + * + * This class is typically specified as the UISceneDelegate in the Info.plist. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterSceneDelegate + : NSObject +@property(nonatomic, strong, nullable) UIWindow* window; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterSceneLifeCycle.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterSceneLifeCycle.h new file mode 100644 index 000000000..70898c840 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterSceneLifeCycle.h @@ -0,0 +1,219 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENELIFECYCLE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENELIFECYCLE_H_ + +#import +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FlutterEngine; + +/** + * A protocol for delegates that handle `UISceneDelegate` and `UIWindowSceneDelegate` life-cycle + * events. + * + * This protocol provides a way for Flutter plugins to observe and react to scene-based life-cycle + * events. The methods in this protocol correspond to methods in `UISceneDelegate` and + * `UIWindowSceneDelegate`. + * + * See also: + * + * * `UISceneDelegate`, core methods you use to respond to life-cycle events occurring within a + * scene: https://developer.apple.com/documentation/uikit/uiscenedelegate + * * `UIWindowSceneDelegate`, additional methods that you use to manage app-specific tasks + * occurring in a scene: https://developer.apple.com/documentation/uikit/uiwindowscenedelegate + */ +API_AVAILABLE(ios(13.0)) +@protocol FlutterSceneLifeCycleDelegate + +@optional + +#pragma mark - Connecting and disconnecting the scene + +/** + * Informs the delegate that a new scene is about to be connected and configured. + * + * This corresponds to `-[UISceneDelegate scene:willConnectToSession:options:]`. `connectionOptions` + * may be nil if another plugin has already handled the connection. + * + * @return `YES` if this handled the connection. + */ +- (BOOL)scene:(UIScene*)scene + willConnectToSession:(UISceneSession*)session + options:(nullable UISceneConnectionOptions*)connectionOptions; + +- (void)sceneDidDisconnect:(UIScene*)scene; + +#pragma mark - Transitioning to the foreground + +- (void)sceneWillEnterForeground:(UIScene*)scene; + +- (void)sceneDidBecomeActive:(UIScene*)scene; + +#pragma mark - Transitioning to the background + +- (void)sceneWillResignActive:(UIScene*)scene; + +- (void)sceneDidEnterBackground:(UIScene*)scene; + +#pragma mark - Opening URLs + +/** + * Asks the delegate to open one or more URLs. + * + * This corresponds to `-[UISceneDelegate scene:openURLContexts:]`. + * + * @return `YES` if this handled one or more of the URLs. + */ +- (BOOL)scene:(UIScene*)scene openURLContexts:(NSSet*)URLContexts; + +#pragma mark - Continuing user activities + +/** + * Tells the delegate that the scene is continuing a user activity. + * + * This corresponds to `-[UISceneDelegate scene:continueUserActivity:]`. + * + * @return `YES` if this handled the activity. + */ +- (BOOL)scene:(UIScene*)scene continueUserActivity:(NSUserActivity*)userActivity; + +#pragma mark - Performing tasks + +/** + * Tells the delegate that the user has selected a home screen quick action. + * + * This corresponds to `-[UIWindowSceneDelegate + * windowScene:performActionForShortcutItem:completionHandler:]`. + * + * @return `YES` if this handled the shortcut. + */ +- (BOOL)windowScene:(UIWindowScene*)windowScene + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler; + +@end + +/** + * A protocol for manually registering a `FlutterEngine` to receive scene life cycle events. + */ +@protocol FlutterSceneLifeCycleEngineRegistration +/** + * Registers a `FlutterEngine` to receive scene life cycle events. + * + * This method is **only** necessary when the following conditions are true: + * 1. Multiple Scenes (UIApplicationSupportsMultipleScenes) is enabled. + * 2. The `UIWindowSceneDelegate` `window.rootViewController` is not a `FlutterViewController` + * initialized with the target `FlutterEngine`. + * + * When multiple scenes is enabled (UIApplicationSupportsMultipleScenes), Flutter cannot + * automatically associate a `FlutterEngine` with a scene during the scene connection phase. In + * order for plugins to receive launch connection information, the `FlutterEngine` must be manually + * registered with either the `FlutterSceneDelegate` or `FlutterPluginSceneLifeCycleDelegate` during + * `scene:willConnectToSession:options:`. + * + * In all other cases, or once the `FlutterViewController.view` associated with the `FlutterEngine` + * is added to the view hierarchy, Flutter will automatically handle registration for scene events. + * + * Manually registered engines must also be manually deregistered and re-registered if they + * switch scenes. Use `unregisterSceneLifeCycleWithFlutterEngine:`. + * + * @param engine The `FlutterEngine` to register for scene life cycle events. + * @return `NO` if already manually registered. + */ +- (BOOL)registerSceneLifeCycleWithFlutterEngine:(FlutterEngine*)engine; + +/** + * Use this method to unregister a `FlutterEngine` from the scene's life cycle events. + * + * @param engine The `FlutterEngine` to unregister for scene life cycle events. + * @return `NO` if the engine was not found among the manually registered engines and could not be + * unregistered. + */ +- (BOOL)unregisterSceneLifeCycleWithFlutterEngine:(FlutterEngine*)engine; +@end + +/** + * Forwards `UISceneDelegate` and `UIWindowSceneDelegate` callbacks to plugins that register for + * them. + * + * This class is responsible for receiving `UISceneDelegate` and `UIWindowSceneDelegate` callbacks + * and forwarding them to any plugins. + */ +FLUTTER_DARWIN_EXPORT +API_AVAILABLE(ios(13.0)) +@interface FlutterPluginSceneLifeCycleDelegate : NSObject + +#pragma mark - Connecting and disconnecting the scene + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)scene:(UIScene*)scene + willConnectToSession:(UISceneSession*)session + options:(UISceneConnectionOptions*)connectionOptions; + +- (void)sceneDidDisconnect:(UIScene*)scene; + +#pragma mark - Transitioning to the foreground + +- (void)sceneWillEnterForeground:(UIScene*)scene; + +- (void)sceneDidBecomeActive:(UIScene*)scene; + +#pragma mark - Transitioning to the background + +- (void)sceneWillResignActive:(UIScene*)scene; + +- (void)sceneDidEnterBackground:(UIScene*)scene; + +#pragma mark - Opening URLs + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)scene:(UIScene*)scene openURLContexts:(NSSet*)URLContexts; + +#pragma mark - Continuing user activities + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)scene:(UIScene*)scene continueUserActivity:(NSUserActivity*)userActivity; + +#pragma mark - Performing tasks + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)windowScene:(UIWindowScene*)windowScene + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler; + +@end + +/** + * A protocol for `UIWindowSceneDelegate` objects that vend a `FlutterPluginSceneLifeCycleDelegate`. + * + * By conforming to this protocol, a `UIWindowSceneDelegate` can vend a + * `FlutterPluginSceneLifeCycleDelegate` that can be used to forward scene life-cycle events to + * Flutter plugins. + * + * This is typically implemented by the app's `SceneDelegate`. + */ +API_AVAILABLE(ios(13.0)) +@protocol FlutterSceneLifeCycleProvider +@property(nonatomic, strong) FlutterPluginSceneLifeCycleDelegate* sceneLifeCycleDelegate; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENELIFECYCLE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterTexture.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterTexture.h new file mode 100644 index 000000000..1fa7a0ef6 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterTexture.h @@ -0,0 +1,69 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERTEXTURE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERTEXTURE_H_ + +#import +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +FLUTTER_DARWIN_EXPORT +/** + * Represents a texture that can be shared with Flutter. + * + * See also: https://github.com/flutter/plugins/tree/master/packages/camera + */ +@protocol FlutterTexture +/** + * Copy the contents of the texture into a `CVPixelBuffer`. + * + * The type of the pixel buffer is one of the following: + * - `kCVPixelFormatType_32BGRA` + * - `kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange` + * - `kCVPixelFormatType_420YpCbCr8BiPlanarFullRange` + */ +- (CVPixelBufferRef _Nullable)copyPixelBuffer; + +/** + * Called when the texture is unregistered. + * + * Called on the raster thread. + */ +@optional +- (void)onTextureUnregistered:(NSObject*)texture; +@end + +FLUTTER_DARWIN_EXPORT +/** + * A collection of registered `FlutterTexture`'s. + */ +@protocol FlutterTextureRegistry +/** + * Registers a `FlutterTexture` for usage in Flutter and returns an id that can be used to reference + * that texture when calling into Flutter with channels. Textures must be registered on the + * platform thread. On success returns the pointer to the registered texture, else returns 0. + */ +- (int64_t)registerTexture:(NSObject*)texture; +/** + * Notifies Flutter that the content of the previously registered texture has been updated. + * + * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. + */ +- (void)textureFrameAvailable:(int64_t)textureId; +/** + * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures + * must be unregistered on the platform thread. + * + * @param textureId The result that was previously returned from `registerTexture:`. + */ +- (void)unregisterTexture:(int64_t)textureId; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERTEXTURE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterViewController.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterViewController.h new file mode 100644 index 000000000..e41565c3b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Headers/FlutterViewController.h @@ -0,0 +1,261 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERVIEWCONTROLLER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERVIEWCONTROLLER_H_ + +#import +#include + +#import "FlutterBinaryMessenger.h" +#import "FlutterDartProject.h" +#import "FlutterEngine.h" +#import "FlutterHourFormat.h" +#import "FlutterMacros.h" +#import "FlutterPlugin.h" +#import "FlutterTexture.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FlutterEngine; + +/** + * The name used for semantic update notifications via `NSNotificationCenter`. + * + * The object passed as the sender is the `FlutterViewController` associated + * with the update. + */ +FLUTTER_DARWIN_EXPORT +// NOLINTNEXTLINE(readability-identifier-naming) +extern NSNotificationName const FlutterSemanticsUpdateNotification; + +/** + * A `UIViewController` implementation for Flutter views. + * + * Dart execution, channel communication, texture registration, and plugin registration are all + * handled by `FlutterEngine`. Calls on this class to those members all proxy through to the + * `FlutterEngine` attached FlutterViewController. + * + * A FlutterViewController can be initialized either with an already-running `FlutterEngine` via the + * `initWithEngine:` initializer, or it can be initialized with a `FlutterDartProject` that will be + * used to implicitly spin up a new `FlutterEngine`. Creating a `FlutterEngine` before showing a + * FlutterViewController can be used to pre-initialize the Dart VM and to prepare the isolate in + * order to reduce the latency to the first rendered frame. See + * https://flutter.dev/docs/development/add-to-app/performance for more details on loading + * latency. + * + * Holding a `FlutterEngine` independently of FlutterViewControllers can also be used to not to lose + * Dart-related state and asynchronous tasks when navigating back and forth between a + * FlutterViewController and other `UIViewController`s. + */ +FLUTTER_DARWIN_EXPORT +#ifdef __IPHONE_13_4 +@interface FlutterViewController + : UIViewController +#else +@interface FlutterViewController : UIViewController +#endif + +/** + * Initializes this FlutterViewController with the specified `FlutterEngine`. + * + * The initialized viewcontroller will attach itself to the engine as part of this process. + * + * @param engine The `FlutterEngine` instance to attach to. Cannot be nil. + * @param nibName The NIB name to initialize this UIViewController with. + * @param nibBundle The NIB bundle. + */ +- (instancetype)initWithEngine:(FlutterEngine*)engine + nibName:(nullable NSString*)nibName + bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a new FlutterViewController and `FlutterEngine` with the specified + * `FlutterDartProject`. + * + * This will implicitly create a new `FlutterEngine` which is retrievable via the `engine` property + * after initialization. + * + * @param project The `FlutterDartProject` to initialize the `FlutterEngine` with. + * @param nibName The NIB name to initialize this UIViewController with. + * @param nibBundle The NIB bundle. + */ +- (instancetype)initWithProject:(nullable FlutterDartProject*)project + nibName:(nullable NSString*)nibName + bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a new FlutterViewController and `FlutterEngine` with the specified + * `FlutterDartProject` and `initialRoute`. + * + * This will implicitly create a new `FlutterEngine` which is retrievable via the `engine` property + * after initialization. + * + * @param project The `FlutterDartProject` to initialize the `FlutterEngine` with. + * @param initialRoute The initial `Navigator` route to load. + * @param nibName The NIB name to initialize this UIViewController with. + * @param nibBundle The NIB bundle. + */ +- (instancetype)initWithProject:(nullable FlutterDartProject*)project + initialRoute:(nullable NSString*)initialRoute + nibName:(nullable NSString*)nibName + bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER; + +/** + * Initializer that is called from loading a FlutterViewController from a XIB. + * + * See also: + * https://developer.apple.com/documentation/foundation/nscoding/1416145-initwithcoder?language=objc + */ +- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_DESIGNATED_INITIALIZER; + +/** + * Registers a callback that will be invoked when the Flutter view has been rendered. + * The callback will be fired only once. + * + * Replaces an existing callback. Use a `nil` callback to unregister the existing one. + */ +- (void)setFlutterViewDidRenderCallback:(void (^)(void))callback; + +/** + * Returns the file name for the given asset. + * The returned file name can be used to access the asset in the application's + * main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @return The file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset; + +/** + * Returns the file name for the given asset which originates from the specified + * package. + * The returned file name can be used to access the asset in the application's + * main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @return The file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package; + +/** + * Deprecated API to set initial route. + * + * Attempts to set the first route that the Flutter app shows if the Flutter + * runtime hasn't yet started. The default is "/". + * + * This method must be called immediately after `initWithProject` and has no + * effect when using `initWithEngine` if the `FlutterEngine` has already been + * run. + * + * Setting this after the Flutter started running has no effect. See `pushRoute` + * and `popRoute` to change the route after Flutter started running. + * + * This is deprecated because it needs to be called at the time of initialization + * and thus should just be in the `initWithProject` initializer. If using + * `initWithEngine`, the initial route should be set on the engine's + * initializer. + * + * @param route The name of the first route to show. + */ +- (void)setInitialRoute:(NSString*)route + FLUTTER_DEPRECATED("Use FlutterViewController initializer to specify initial route"); + +/** + * Instructs the Flutter Navigator (if any) to go back. + */ +- (void)popRoute; + +/** + * Instructs the Flutter Navigator (if any) to push a route on to the navigation + * stack. + * + * @param route The name of the route to push to the navigation stack. + */ +- (void)pushRoute:(NSString*)route; + +/** + * The `FlutterPluginRegistry` used by this FlutterViewController. + */ +- (id)pluginRegistry; + +/** + * A wrapper around UIAccessibilityIsVoiceOverRunning(). + * + * As a C function, UIAccessibilityIsVoiceOverRunning() cannot be mocked in testing. Mock + * this class method to testing features depends on UIAccessibilityIsVoiceOverRunning(). + */ ++ (BOOL)isUIAccessibilityIsVoiceOverRunning; + +/** + * True if at least one frame has rendered and the ViewController has appeared. + * + * This property is reset to false when the ViewController disappears. It is + * guaranteed to only alternate between true and false for observers. + */ +@property(nonatomic, readonly, getter=isDisplayingFlutterUI) BOOL displayingFlutterUI; + +/** + * Specifies the view to use as a splash screen. Flutter's rendering is asynchronous, so the first + * frame rendered by the Flutter application might not immediately appear when the Flutter view is + * initially placed in the view hierarchy. The splash screen view will be used as + * a replacement until the first frame is rendered. + * + * The view used should be appropriate for multiple sizes; an autoresizing mask to + * have a flexible width and height will be applied automatically. + * + * Set to nil to remove the splash screen view. + */ +@property(strong, nonatomic, nullable) UIView* splashScreenView; + +/** + * Attempts to set the `splashScreenView` property from the `UILaunchStoryboardName` from the + * main bundle's `Info.plist` file. This method will not change the value of `splashScreenView` + * if it cannot find a default one from a storyboard or nib. + * + * @return `YES` if successful, `NO` otherwise. + */ +- (BOOL)loadDefaultSplashScreenView; + +/** + * Controls whether the created view will be opaque or not. + * + * Default is `YES`. Note that setting this to `NO` may negatively impact performance + * when using hardware acceleration, and toggling this will trigger a re-layout of the + * view. + */ +@property(nonatomic, getter=isViewOpaque) BOOL viewOpaque; + +/** + * The `FlutterEngine` instance for this view controller. This could be the engine this + * `FlutterViewController` is initialized with or a new `FlutterEngine` implicitly created if + * no engine was supplied during initialization. + */ +@property(nonatomic, readonly) FlutterEngine* engine; + +/** + * The `FlutterBinaryMessenger` associated with this FlutterViewController (used for communicating + * with channels). + * + * This is just a convenient way to get the |FlutterEngine|'s binary messenger. + */ +@property(nonatomic, readonly) NSObject* binaryMessenger; + +/** + * If the `FlutterViewController` creates a `FlutterEngine`, this property + * determines if that `FlutterEngine` has `allowHeadlessExecution` set. + * + * The intention is that this is used with the XIB. Otherwise, a + * `FlutterEngine` can just be sent to the init methods. + * + * See also: `-[FlutterEngine initWithName:project:allowHeadlessExecution:]` + */ +@property(nonatomic, readonly) BOOL engineAllowHeadlessExecution; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERVIEWCONTROLLER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Info.plist new file mode 100644 index 000000000..4dae4d462 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Flutter + CFBundleIdentifier + io.flutter.flutter + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Flutter + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 13.0 + FlutterEngine + a5cb96369ef86c7e85abf5d662a1ca5d89775053 + BuildMode + debug + ClangVersion + b'Fuchsia clang version 21.0.0git (https://llvm.googlesource.com/llvm-project 8c7a2ce01a77c96028fe2c8566f65c45ad9408d3)' + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Modules/module.modulemap b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Modules/module.modulemap new file mode 100644 index 000000000..bf81c8a86 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module Flutter { + umbrella header "Flutter.h" + + export * + module * { export * } +} diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/PrivacyInfo.xcprivacy b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..d4bc7fc2e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/PrivacyInfo.xcprivacy @@ -0,0 +1,32 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + 0A2A.1 + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..a9d6a76c9 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/_CodeSignature/CodeResources @@ -0,0 +1,344 @@ + + + + + files + + Headers/Flutter.h + + dQsuFiftv2fxtixhcMIA/+B+uUM= + + Headers/FlutterAppDelegate.h + + PfJCf6hbYTWm910ECDC5roRPfWE= + + Headers/FlutterBinaryMessenger.h + + ksjIMu5IPw+Q3rw2YkAx0KjxkdM= + + Headers/FlutterCallbackCache.h + + V/wkSSsyYdMoexF6wPrC3KgkL4g= + + Headers/FlutterChannels.h + + vFsZXNqjflvqKqAzsIptQaTSJho= + + Headers/FlutterCodecs.h + + sUgX1PJzkvyinL5i7nS1ro/Kd5o= + + Headers/FlutterDartProject.h + + SpNs7IhIC7xP34Ej+LQCaEZkqik= + + Headers/FlutterEngine.h + + BFan2MPs+CkI3+ihxkbJDuKQ7a0= + + Headers/FlutterEngineGroup.h + + bkw+DmHReHDg1PPcvmSjuLZrheA= + + Headers/FlutterHeadlessDartRunner.h + + UqnnVWwQEYYX56eu7lt6dpR3LIc= + + Headers/FlutterHourFormat.h + + VjAwScWkWWSrDeetip3K4yhuwDU= + + Headers/FlutterMacros.h + + crQ9782ULebLQfIR+MbBkjB7d+k= + + Headers/FlutterPlatformViews.h + + hAwPmAERwlkwVd6RZpc09UHL50I= + + Headers/FlutterPlugin.h + + REG3r2IMfvEjtswwALvyVHTQhjo= + + Headers/FlutterPluginAppLifeCycleDelegate.h + + qWHw5VIWEa0NmJ1PMhD16nlfRKk= + + Headers/FlutterSceneDelegate.h + + 1YaIV2MTzs0X0U13jT89+5nUoL8= + + Headers/FlutterSceneLifeCycle.h + + IqEbKnMthck20540eNZgrlrLvJE= + + Headers/FlutterTexture.h + + 31prWLso2k5PfMMSbf5hGl+VE6Y= + + Headers/FlutterViewController.h + + LDr6kSVbUfyQFAxLwCACF5S2VEA= + + Info.plist + + 6xaOzhYI3/7yanBhXMuFNn0S+OA= + + Modules/module.modulemap + + wJV5dCKEGl+FAtDc8wJJh/fvKXs= + + PrivacyInfo.xcprivacy + + D+cqXttvC7E/uziGjFdqFabWd7A= + + icudtl.dat + + ipm8hg7aB3LzsfShJfpNR0QQ4hw= + + + files2 + + Headers/Flutter.h + + hash2 + + wfWyagPYLCRR2+wTuGRbtW3z3z2AWS+YFxuiBOFdSjY= + + + Headers/FlutterAppDelegate.h + + hash2 + + ehumZ2VCA9xOXBI/7gQunPmAgn9cJpiZKDS9p8XWqkY= + + + Headers/FlutterBinaryMessenger.h + + hash2 + + EXDk4t+7qCpyQkar+q9WHqY9bcK8eyohCwGVtBJhMy8= + + + Headers/FlutterCallbackCache.h + + hash2 + + 0h9+vK5K+r8moTsiGBfs6+TM9Qog089afHAy3gbcwDU= + + + Headers/FlutterChannels.h + + hash2 + + kg195C3vZLiOn8KeFQUy7DoVuA9VZDpqoBLVn64uGaI= + + + Headers/FlutterCodecs.h + + hash2 + + ZyqlHYuZbpFevVeny9Wdl0rVFgS7szIyssSiCyaaeFM= + + + Headers/FlutterDartProject.h + + hash2 + + U8q/0Ibt9q4O2HMsCdUwITtJdTx8Ljhlx+0aY83fH6s= + + + Headers/FlutterEngine.h + + hash2 + + QwvtJ2TkMcRYqWJ9V4J3LToKMLVK1pOcJpQtnIdnA+s= + + + Headers/FlutterEngineGroup.h + + hash2 + + SqzvIxqBXEJ3U9LJ32hCEXsrH2P16gumQ+gQx6Pdlf4= + + + Headers/FlutterHeadlessDartRunner.h + + hash2 + + nmZjZpvFCXrygf4U9aPkNi8VcI7cL5AtA+CY5uUWIL0= + + + Headers/FlutterHourFormat.h + + hash2 + + Q4SLFSghL/5EFJPyLg7PNi9J/xpkVVfzro0VQiQHtrY= + + + Headers/FlutterMacros.h + + hash2 + + ebBVHSZcUnAbN4hRcYq3ttt6++z1Ybc8KVSYhVToD5k= + + + Headers/FlutterPlatformViews.h + + hash2 + + 0aU9uM6QcpzmZpuFYObj9dGlGEkTKowPMERJQQdF2P4= + + + Headers/FlutterPlugin.h + + hash2 + + QcjhOhk5cb1U7bmyQh9TnFm1M2Tgv82RSSbJ6OIdMr4= + + + Headers/FlutterPluginAppLifeCycleDelegate.h + + hash2 + + +PMn+5SDj2Vd6RU8CQIt/JYl3T+8Dhp7HImqAzocoNk= + + + Headers/FlutterSceneDelegate.h + + hash2 + + G9urZeE312ldazkeP/7sut0t2hA3lfcuxHRSuLmj+gY= + + + Headers/FlutterSceneLifeCycle.h + + hash2 + + nvPq1KiXUwgQ/TtOSqHisNHQPvnVpvtXi3L0zLchdyI= + + + Headers/FlutterTexture.h + + hash2 + + JcpN4a9sv6xynlD3Ri611N5y+HoupUWp2hyrIXB/I8Y= + + + Headers/FlutterViewController.h + + hash2 + + yEgZTlCNrK/A/QBjEwNGB6ffC+A9gorPvnNgSbYuQ7Y= + + + Modules/module.modulemap + + hash2 + + 0VjriRpZ7AZZaP/0mMAPMJPhi6LoMB4MhXzL5j24tGs= + + + PrivacyInfo.xcprivacy + + hash2 + + n5XX54YqS1a2btkmvW1iLSplRagn0ZhHJ4tDjVcdQhI= + + + icudtl.dat + + hash2 + + wSU3Ai74GJkae/7UGnbY1q6WL/vA5lEax2Kl0IRef3w= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/icudtl.dat b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/icudtl.dat new file mode 100644 index 000000000..17e5b2aac Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Flutter.framework/icudtl.dat differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.o b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.o new file mode 100644 index 000000000..37d69dc2c Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.o differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 000000000..817111a8a Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.abi.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.abi.json new file mode 100644 index 000000000..d2f988e4e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.abi.json @@ -0,0 +1,9 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "NO_MODULE", + "printedName": "NO_MODULE", + "json_format_version": 8 + }, + "ConstValues": [] +} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.swiftdoc new file mode 100644 index 000000000..79d140930 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.swiftdoc differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.swiftmodule b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.swiftmodule new file mode 100644 index 000000000..608bc78c9 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/FlutterGeneratedPluginSwiftPackage.swiftmodule/arm64-apple-ios-simulator.swiftmodule differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Headers/Pods-Runner-umbrella.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Headers/Pods-Runner-umbrella.h new file mode 100644 index 000000000..5bf0aab02 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Headers/Pods-Runner-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double Pods_RunnerVersionNumber; +FOUNDATION_EXPORT const unsigned char Pods_RunnerVersionString[]; + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Info.plist new file mode 100644 index 000000000..993ca5221 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Modules/module.modulemap b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Modules/module.modulemap new file mode 100644 index 000000000..d2cf6f641 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module Pods_Runner { + umbrella header "Pods-Runner-umbrella.h" + + export * + module * { export * } +} diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Pods_Runner b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Pods_Runner new file mode 100644 index 000000000..15f01192c Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/Pods_Runner differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeDirectory b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeDirectory new file mode 100644 index 000000000..65add114d Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeDirectory differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeRequirements b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeRequirements new file mode 100644 index 000000000..dbf9d6144 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeRequirements differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..85a431619 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeResources @@ -0,0 +1,124 @@ + + + + + files + + Headers/Pods-Runner-umbrella.h + + qwiYDWd9StHsFttCKLnCkouErV8= + + Info.plist + + f9UpiUJ7pncEJbxTCMvHm6sP2YE= + + Modules/module.modulemap + + fTjMFx0S8KBV991TY3+5DAzl1R0= + + + files2 + + Headers/Pods-Runner-umbrella.h + + hash2 + + h9Q8dOdlbfVmyAwN0d7ym11XjgSop1/nJGh4JH8yc2c= + + + Modules/module.modulemap + + hash2 + + wuAmO8HNOlsSiQE1FebYfxZqLzXImN1XYTTH47H5HUs= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeSignature b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Pods_Runner.framework/_CodeSignature/CodeSignature new file mode 100644 index 000000000..e69de29bb diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppFrameworkInfo.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppFrameworkInfo.plist new file mode 100644 index 000000000..9b3a25545 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppFrameworkInfo.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppIcon60x60@2x.png b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppIcon60x60@2x.png new file mode 100644 index 000000000..0ec303439 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppIcon60x60@2x.png differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppIcon76x76@2x~ipad.png b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppIcon76x76@2x~ipad.png new file mode 100644 index 000000000..8953cba09 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/AppIcon76x76@2x~ipad.png differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Assets.car b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Assets.car new file mode 100644 index 000000000..3fe1e6658 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Assets.car differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib new file mode 100644 index 000000000..623fb36a0 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/Info.plist new file mode 100644 index 000000000..32288e88f Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib new file mode 100644 index 000000000..29c62978e Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib new file mode 100644 index 000000000..5368f937a Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/Info.plist new file mode 100644 index 000000000..9a41f2cb9 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib new file mode 100644 index 000000000..789545ea6 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/App b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/App new file mode 100755 index 000000000..763c19092 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/App differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/Info.plist new file mode 100644 index 000000000..1dc6cf765 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 13.0 + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..5b1f23d05 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/_CodeSignature/CodeResources @@ -0,0 +1,212 @@ + + + + + files + + Info.plist + + T7ae0s1yqPVdrLK0y5gqABVb1PU= + + flutter_assets/AssetManifest.bin + + 21tVqbIV90TbglF4ZJhNBz8uj4w= + + flutter_assets/FontManifest.json + + +D1xbIOooc3ypce1+jh+mmLy1J0= + + flutter_assets/NOTICES.Z + + AXyVWLODHa/0OkUkKJ+LZ8eJFkE= + + flutter_assets/NativeAssetsManifest.json + + re4p7E8rPLLsN+wzaPN/+AVpXTY= + + flutter_assets/fonts/MaterialIcons-Regular.otf + + /CUoTuPQqqdexfyOT9lpJhV+2MQ= + + flutter_assets/isolate_snapshot_data + + Oct4LBWkbrUyhS8o11D8knDiOCw= + + flutter_assets/kernel_blob.bin + + xJK2Y4wcwvcJLYpeprI0c3lbUjE= + + flutter_assets/shaders/ink_sparkle.frag + + VvTF10G1gIeea4aI0DhJjCjHgXQ= + + flutter_assets/shaders/stretch_effect.frag + + kG7Fh+R6JkaM/GufJFUfEToHTEg= + + flutter_assets/vm_snapshot_data + + 3y4zj1lbLxr1MIJjsR7xSTsrd4k= + + + files2 + + flutter_assets/AssetManifest.bin + + hash2 + + 9WbMb8zGVzZcAZeszzp9b4D4Ugn/Zm/3dPTcvFJKqEI= + + + flutter_assets/FontManifest.json + + hash2 + + KLHrKz0uGtYLjIsPkQCxzL9JL3+pf1vrtR6pfnOSbn0= + + + flutter_assets/NOTICES.Z + + hash2 + + NrzjHg60IXWImNkLTcTe7UCS05stOUJPlqXWWY/FNkI= + + + flutter_assets/NativeAssetsManifest.json + + hash2 + + lUijHkoEgTXB2U+Rkyi/tirix7s8q5ZVfHlB2ql3dss= + + + flutter_assets/fonts/MaterialIcons-Regular.otf + + hash2 + + 2YZbZxoJ1oPROoYwidiCXg9ho3aWzl19RIvIAjqmJFM= + + + flutter_assets/isolate_snapshot_data + + hash2 + + wHUhal5u7BswH9uKyMGmAinBbqMbGrC0nmFvt+raT08= + + + flutter_assets/kernel_blob.bin + + hash2 + + ep/WR3I5PLXXV7RxcQ7FfWvg01VWJNtKO9QO09OUJUg= + + + flutter_assets/shaders/ink_sparkle.frag + + hash2 + + TGVjYgE+Oyl6guvhhPPrWfynkxkJeFjSzSLsQqn7Q3M= + + + flutter_assets/shaders/stretch_effect.frag + + hash2 + + Y/95u280RMpR6e6ndBjH5Pm8ujZSD5Qf33woQ/NncNU= + + + flutter_assets/vm_snapshot_data + + hash2 + + OdF1NJaYIhUMtPHX5I2sunghfvWky6zAyizwBbVifbU= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/AssetManifest.bin b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/AssetManifest.bin new file mode 100644 index 000000000..86d111f09 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/AssetManifest.bin differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/FontManifest.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/FontManifest.json new file mode 100644 index 000000000..3abf18c41 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/FontManifest.json @@ -0,0 +1 @@ +[{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]}] \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/NOTICES.Z b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/NOTICES.Z new file mode 100644 index 000000000..830d1e2c2 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/NOTICES.Z differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/NativeAssetsManifest.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/NativeAssetsManifest.json new file mode 100644 index 000000000..523bfc7c6 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/NativeAssetsManifest.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf new file mode 100644 index 000000000..8c9926613 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/isolate_snapshot_data b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/isolate_snapshot_data new file mode 100644 index 000000000..0923d40ce Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/isolate_snapshot_data differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/kernel_blob.bin b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/kernel_blob.bin new file mode 100644 index 000000000..503bc3048 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/kernel_blob.bin differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/shaders/ink_sparkle.frag b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/shaders/ink_sparkle.frag new file mode 100644 index 000000000..77ed3e358 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/shaders/ink_sparkle.frag differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/shaders/stretch_effect.frag b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/shaders/stretch_effect.frag new file mode 100644 index 000000000..d7581175b Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/shaders/stretch_effect.frag differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/vm_snapshot_data b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/vm_snapshot_data new file mode 100644 index 000000000..af8b65ebd Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/App.framework/flutter_assets/vm_snapshot_data differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Flutter b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Flutter new file mode 100755 index 000000000..6ac377dcf Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Flutter differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/Flutter.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/Flutter.h new file mode 100644 index 000000000..54e1cd3ea --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/Flutter.h @@ -0,0 +1,26 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTER_H_ + +#import "FlutterAppDelegate.h" +#import "FlutterBinaryMessenger.h" +#import "FlutterCallbackCache.h" +#import "FlutterChannels.h" +#import "FlutterCodecs.h" +#import "FlutterDartProject.h" +#import "FlutterEngine.h" +#import "FlutterEngineGroup.h" +#import "FlutterHeadlessDartRunner.h" +#import "FlutterMacros.h" +#import "FlutterPlatformViews.h" +#import "FlutterPlugin.h" +#import "FlutterPluginAppLifeCycleDelegate.h" +#import "FlutterSceneDelegate.h" +#import "FlutterSceneLifeCycle.h" +#import "FlutterTexture.h" +#import "FlutterViewController.h" + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterAppDelegate.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterAppDelegate.h new file mode 100644 index 000000000..fce4fd33a --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterAppDelegate.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERAPPDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERAPPDELEGATE_H_ + +#import + +#import "FlutterMacros.h" +#import "FlutterPlugin.h" + +/** + * `UIApplicationDelegate` subclass for simple apps that want default behavior. + * + * This class implements the following behaviors: + * * Status bar touches are forwarded to the key window's root view + * `FlutterViewController`, in order to trigger scroll to top. + * * Keeps the Flutter connection open in debug mode when the phone screen + * locks. + * + * App delegates for Flutter applications are *not* required to inherit from + * this class. Developers of custom app delegate classes should copy and paste + * code as necessary from FlutterAppDelegate.mm. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterAppDelegate + : UIResponder + +@property(nonatomic, strong, nullable) UIWindow* window; + +/** + * The `FlutterPluginRegistrant` that will be used when FlutterViewControllers + * are instantiated from nibs. + * + * The `FlutterAppDelegate` itself can be passed in without creating a retain + * cycle. + * + * This was introduced to help users migrate code from the FlutterAppDelegate + * when UISceneDelegate was adopted. Using + * FlutterViewController.pluginRegistrant should be preferred since it doesn't + * rely on the FlutterAppDelegate. + */ +@property(nonatomic, strong, nullable) NSObject* pluginRegistrant; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERAPPDELEGATE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterBinaryMessenger.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterBinaryMessenger.h new file mode 100644 index 000000000..eb0186fd2 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterBinaryMessenger.h @@ -0,0 +1,106 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERBINARYMESSENGER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERBINARYMESSENGER_H_ + +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN +/** + * A message reply callback. + * + * Used for submitting a binary reply back to a Flutter message sender. Also used + * in for handling a binary message reply received from Flutter. + * + * @param reply The reply. + */ +typedef void (^FlutterBinaryReply)(NSData* _Nullable reply); + +/** + * A strategy for handling incoming binary messages from Flutter and to send + * asynchronous replies back to Flutter. + * + * @param message The message. + * @param reply A callback for submitting an asynchronous reply to the sender. + */ +typedef void (^FlutterBinaryMessageHandler)(NSData* _Nullable message, FlutterBinaryReply reply); + +typedef int64_t FlutterBinaryMessengerConnection; + +@protocol FlutterTaskQueue +@end + +/** + * A facility for communicating with the Flutter side using asynchronous message + * passing with binary messages. + * + * Implementated by: + * - `FlutterBasicMessageChannel`, which supports communication using structured + * messages. + * - `FlutterMethodChannel`, which supports communication using asynchronous + * method calls. + * - `FlutterEventChannel`, which supports commuication using event streams. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterBinaryMessenger +/// TODO(gaaclarke): Remove optional when macos supports Background Platform Channels. +@optional +- (NSObject*)makeBackgroundTaskQueue; + +- (FlutterBinaryMessengerConnection) + setMessageHandlerOnChannel:(NSString*)channel + binaryMessageHandler:(FlutterBinaryMessageHandler _Nullable)handler + taskQueue:(NSObject* _Nullable)taskQueue; + +@required +/** + * Sends a binary message to the Flutter side on the specified channel, expecting + * no reply. + * + * @param channel The channel name. + * @param message The message. + */ +- (void)sendOnChannel:(NSString*)channel message:(NSData* _Nullable)message; + +/** + * Sends a binary message to the Flutter side on the specified channel, expecting + * an asynchronous reply. + * + * @param channel The channel name. + * @param message The message. + * @param callback A callback for receiving a reply. + */ +- (void)sendOnChannel:(NSString*)channel + message:(NSData* _Nullable)message + binaryReply:(FlutterBinaryReply _Nullable)callback; + +/** + * Registers a message handler for incoming binary messages from the Flutter side + * on the specified channel. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param channel The channel name. + * @param handler The message handler. + * @return An identifier that represents the connection that was just created to the channel. + */ +- (FlutterBinaryMessengerConnection)setMessageHandlerOnChannel:(NSString*)channel + binaryMessageHandler: + (FlutterBinaryMessageHandler _Nullable)handler; + +/** + * Clears out a channel's message handler if that handler is still the one that + * was created as a result of + * `setMessageHandlerOnChannel:binaryMessageHandler:`. + * + * @param connection The result from `setMessageHandlerOnChannel:binaryMessageHandler:`. + */ +- (void)cleanUpConnection:(FlutterBinaryMessengerConnection)connection; +@end +NS_ASSUME_NONNULL_END +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERBINARYMESSENGER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterCallbackCache.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterCallbackCache.h new file mode 100644 index 000000000..b6e331d44 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterCallbackCache.h @@ -0,0 +1,54 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERCALLBACKCACHE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERCALLBACKCACHE_H_ + +#import + +#import "FlutterMacros.h" + +/** + * An object containing the result of `FlutterCallbackCache`'s `lookupCallbackInformation` + * method. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterCallbackInformation : NSObject +/** + * The name of the callback. + */ +@property(copy) NSString* callbackName; +/** + * The class name of the callback. + */ +@property(copy) NSString* callbackClassName; +/** + * The library path of the callback. + */ +@property(copy) NSString* callbackLibraryPath; +@end + +/** + * The cache containing callback information for spawning a + * `FlutterHeadlessDartRunner`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterCallbackCache : NSObject +/** + * Returns the callback information for the given callback handle. + * This callback information can be used when spawning a + * `FlutterHeadlessDartRunner`. + * + * @param handle The handle for a callback, provided by the + * Dart method `PluginUtilities.getCallbackHandle`. + * @return A `FlutterCallbackInformation` object which contains the name of the + * callback, the name of the class in which the callback is defined, and the + * path of the library which contains the callback. If the provided handle is + * invalid, nil is returned. + */ ++ (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERCALLBACKCACHE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterChannels.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterChannels.h new file mode 100644 index 000000000..b88b78a90 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterChannels.h @@ -0,0 +1,487 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCHANNELS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCHANNELS_H_ + +#import "FlutterBinaryMessenger.h" +#import "FlutterCodecs.h" + +NS_ASSUME_NONNULL_BEGIN +/** + * A message reply callback. + * + * Used for submitting a reply back to a Flutter message sender. Also used in + * the dual capacity for handling a message reply received from Flutter. + * + * @param reply The reply. + */ +typedef void (^FlutterReply)(id _Nullable reply); + +/** + * A strategy for handling incoming messages from Flutter and to send + * asynchronous replies back to Flutter. + * + * @param message The message. + * @param callback A callback for submitting a reply to the sender which can be invoked from any + * thread. + */ +typedef void (^FlutterMessageHandler)(id _Nullable message, FlutterReply callback); + +/** + * A channel for communicating with the Flutter side using basic, asynchronous + * message passing. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterBasicMessageChannel : NSObject +/** + * Creates a `FlutterBasicMessageChannel` with the specified name and binary + * messenger. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * The channel uses `FlutterStandardMessageCodec` to encode and decode messages. + * + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (instancetype)messageChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Creates a `FlutterBasicMessageChannel` with the specified name, binary + * messenger, and message codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The message codec. + */ ++ (instancetype)messageChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterBasicMessageChannel` with the specified name, binary + * messenger, and message codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The message codec. + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterBasicMessageChannel` with the specified name, binary + * messenger, and message codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The message codec. + * @param taskQueue The FlutterTaskQueue that executes the handler (see + -[FlutterBinaryMessenger makeBackgroundTaskQueue]). + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec + taskQueue:(NSObject* _Nullable)taskQueue; + +/** + * Sends the specified message to the Flutter side, ignoring any reply. + * + * @param message The message. Must be supported by the codec of this + * channel. + */ +- (void)sendMessage:(id _Nullable)message; + +/** + * Sends the specified message to the Flutter side, expecting an asynchronous + * reply. + * + * @param message The message. Must be supported by the codec of this channel. + * @param callback A callback to be invoked with the message reply from Flutter. + */ +- (void)sendMessage:(id _Nullable)message reply:(FlutterReply _Nullable)callback; + +/** + * Registers a message handler with this channel. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param handler The message handler. + */ +- (void)setMessageHandler:(FlutterMessageHandler _Nullable)handler; + +/** + * Adjusts the number of messages that will get buffered when sending messages to + * channels that aren't fully set up yet. For example, the engine isn't running + * yet or the channel's message handler isn't set up on the Dart side yet. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param newSize The number of messages that will get buffered. + */ ++ (void)resizeChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + size:(NSInteger)newSize; + +/** + * Adjusts the number of messages that will get buffered when sending messages to + * channels that aren't fully set up yet. For example, the engine isn't running + * yet or the channel's message handler isn't set up on the Dart side yet. + * + * @param newSize The number of messages that will get buffered. + */ +- (void)resizeChannelBuffer:(NSInteger)newSize; + +/** + * Defines whether the channel should show warning messages when discarding messages + * due to overflow. + * + * @param warns When false, the channel is expected to overflow and warning messages + * will not be shown. + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (void)setWarnsOnOverflow:(BOOL)warns + forChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Defines whether the channel should show warning messages when discarding messages + * due to overflow. + * + * @param warns When false, the channel is expected to overflow and warning messages + * will not be shown. + */ +- (void)setWarnsOnOverflow:(BOOL)warns; + +@end + +/** + * A method call result callback. + * + * Used for submitting a method call result back to a Flutter caller. Also used in + * the dual capacity for handling a method call result received from Flutter. + * + * @param result The result. + */ +typedef void (^FlutterResult)(id _Nullable result); + +/** + * A strategy for handling method calls. + * + * @param call The incoming method call. + * @param result A callback to asynchronously submit the result of the call. + * Invoke the callback with a `FlutterError` to indicate that the call failed. + * Invoke the callback with `FlutterMethodNotImplemented` to indicate that the + * method was unknown. Any other values, including `nil`, are interpreted as + * successful results. This can be invoked from any thread. + */ +typedef void (^FlutterMethodCallHandler)(FlutterMethodCall* call, FlutterResult result); + +/** + * A constant used with `FlutterMethodCallHandler` to respond to the call of an + * unknown method. + */ +FLUTTER_DARWIN_EXPORT +extern NSObject const* FlutterMethodNotImplemented; + +/** + * A channel for communicating with the Flutter side using invocation of + * asynchronous methods. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterMethodChannel : NSObject +/** + * Creates a `FlutterMethodChannel` with the specified name and binary messenger. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * The channel uses `FlutterStandardMethodCodec` to encode and decode method calls + * and result envelopes. + * + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (instancetype)methodChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Creates a `FlutterMethodChannel` with the specified name, binary messenger, and + * method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ ++ (instancetype)methodChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterMethodChannel` with the specified name, binary messenger, + * and method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterMethodChannel` with the specified name, binary messenger, + * method codec, and task queue. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + * @param taskQueue The FlutterTaskQueue that executes the handler (see + -[FlutterBinaryMessenger makeBackgroundTaskQueue]). + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec + taskQueue:(NSObject* _Nullable)taskQueue; + +// clang-format off +/** + * Invokes the specified Flutter method with the specified arguments, expecting + * no results. + * + * @see [MethodChannel.setMethodCallHandler](https://api.flutter.dev/flutter/services/MethodChannel/setMethodCallHandler.html) + * + * @param method The name of the method to invoke. + * @param arguments The arguments. Must be a value supported by the codec of this + * channel. + */ +// clang-format on +- (void)invokeMethod:(NSString*)method arguments:(id _Nullable)arguments; + +/** + * Invokes the specified Flutter method with the specified arguments, expecting + * an asynchronous result. + * + * @param method The name of the method to invoke. + * @param arguments The arguments. Must be a value supported by the codec of this + * channel. + * @param callback A callback that will be invoked with the asynchronous result. + * The result will be a `FlutterError` instance, if the method call resulted + * in an error on the Flutter side. Will be `FlutterMethodNotImplemented`, if + * the method called was not implemented on the Flutter side. Any other value, + * including `nil`, should be interpreted as successful results. + */ +- (void)invokeMethod:(NSString*)method + arguments:(id _Nullable)arguments + result:(FlutterResult _Nullable)callback; +/** + * Registers a handler for method calls from the Flutter side. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param handler The method call handler. + */ +- (void)setMethodCallHandler:(FlutterMethodCallHandler _Nullable)handler; + +/** + * Adjusts the number of messages that will get buffered when sending messages to + * channels that aren't fully set up yet. For example, the engine isn't running + * yet or the channel's message handler isn't set up on the Dart side yet. + */ +- (void)resizeChannelBuffer:(NSInteger)newSize; + +@end + +/** + * An event sink callback. + * + * @param event The event. + */ +typedef void (^FlutterEventSink)(id _Nullable event); + +/** + * A strategy for exposing an event stream to the Flutter side. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterStreamHandler +/** + * Sets up an event stream and begin emitting events. + * + * Invoked when the first listener is registered with the Stream associated to + * this channel on the Flutter side. + * + * @param arguments Arguments for the stream. + * @param events A callback to asynchronously emit events. Invoke the + * callback with a `FlutterError` to emit an error event. Invoke the + * callback with `FlutterEndOfEventStream` to indicate that no more + * events will be emitted. Any other value, including `nil` are emitted as + * successful events. + * @return A FlutterError instance, if setup fails. + */ +- (FlutterError* _Nullable)onListenWithArguments:(id _Nullable)arguments + eventSink:(FlutterEventSink)events; + +/** + * Tears down an event stream. + * + * Invoked when the last listener is deregistered from the Stream associated to + * this channel on the Flutter side. + * + * The channel implementation may call this method with `nil` arguments + * to separate a pair of two consecutive set up requests. Such request pairs + * may occur during Flutter hot restart. + * + * @param arguments Arguments for the stream. + * @return A FlutterError instance, if teardown fails. + */ +- (FlutterError* _Nullable)onCancelWithArguments:(id _Nullable)arguments; +@end + +/** + * A constant used with `FlutterEventChannel` to indicate end of stream. + */ +FLUTTER_DARWIN_EXPORT +extern NSObject const* FlutterEndOfEventStream; + +/** + * A channel for communicating with the Flutter side using event streams. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEventChannel : NSObject +/** + * Creates a `FlutterEventChannel` with the specified name and binary messenger. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterViewController`. + * + * The channel uses `FlutterStandardMethodCodec` to decode stream setup and + * teardown requests, and to encode event envelopes. + * + * @param name The channel name. + * @param messenger The binary messenger. + */ ++ (instancetype)eventChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger; + +/** + * Creates a `FlutterEventChannel` with the specified name, binary messenger, + * and method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ ++ (instancetype)eventChannelWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterEventChannel` with the specified name, binary messenger, + * and method codec. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec; + +/** + * Initializes a `FlutterEventChannel` with the specified name, binary messenger, + * method codec and task queue. + * + * The channel name logically identifies the channel; identically named channels + * interfere with each other's communication. + * + * The binary messenger is a facility for sending raw, binary messages to the + * Flutter side. This protocol is implemented by `FlutterEngine` and `FlutterViewController`. + * + * @param name The channel name. + * @param messenger The binary messenger. + * @param codec The method codec. + * @param taskQueue The FlutterTaskQueue that executes the handler (see + -[FlutterBinaryMessenger makeBackgroundTaskQueue]). + */ +- (instancetype)initWithName:(NSString*)name + binaryMessenger:(NSObject*)messenger + codec:(NSObject*)codec + taskQueue:(NSObject* _Nullable)taskQueue; +/** + * Registers a handler for stream setup requests from the Flutter side. + * + * Replaces any existing handler. Use a `nil` handler for unregistering the + * existing handler. + * + * @param handler The stream handler. + */ +- (void)setStreamHandler:(NSObject* _Nullable)handler; +@end +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCHANNELS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterCodecs.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterCodecs.h new file mode 100644 index 000000000..93e1d32d9 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterCodecs.h @@ -0,0 +1,478 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCODECS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCODECS_H_ + +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A message encoding/decoding mechanism. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterMessageCodec +/** + * Returns a shared instance of this `FlutterMessageCodec`. + */ ++ (instancetype)sharedInstance; + +/** + * Encodes the specified message into binary. + * + * @param message The message. + * @return The binary encoding, or `nil`, if `message` was `nil`. + */ +- (NSData* _Nullable)encode:(id _Nullable)message; + +/** + * Decodes the specified message from binary. + * + * @param message The message. + * @return The decoded message, or `nil`, if `message` was `nil`. + */ +- (id _Nullable)decode:(NSData* _Nullable)message; +@end + +/** + * A `FlutterMessageCodec` using unencoded binary messages, represented as + * `NSData` instances. + * + * This codec is guaranteed to be compatible with the corresponding + * [BinaryCodec](https://api.flutter.dev/flutter/services/BinaryCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * On the Dart side, messages are represented using `ByteData`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterBinaryCodec : NSObject +@end + +/** + * A `FlutterMessageCodec` using UTF-8 encoded `NSString` messages. + * + * This codec is guaranteed to be compatible with the corresponding + * [StringCodec](https://api.flutter.dev/flutter/services/StringCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStringCodec : NSObject +@end + +/** + * A `FlutterMessageCodec` using UTF-8 encoded JSON messages. + * + * This codec is guaranteed to be compatible with the corresponding + * [JSONMessageCodec](https://api.flutter.dev/flutter/services/JSONMessageCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Supports values accepted by `NSJSONSerialization` plus top-level + * `nil`, `NSNumber`, and `NSString`. + * + * On the Dart side, JSON messages are handled by the JSON facilities of the + * [`dart:convert`](https://api.dartlang.org/stable/dart-convert/JSON-constant.html) + * package. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterJSONMessageCodec : NSObject +@end + +/** + * A writer of the Flutter standard binary encoding. + * + * See `FlutterStandardMessageCodec` for details on the encoding. + * + * The encoding is extensible via subclasses overriding `writeValue`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardWriter : NSObject +/** + * Create a `FlutterStandardWriter` who will write to \p data. + */ +- (instancetype)initWithData:(NSMutableData*)data; +/** Write a 8-bit byte. */ +- (void)writeByte:(UInt8)value; +/** Write an array of \p bytes of size \p length. */ +- (void)writeBytes:(const void*)bytes length:(NSUInteger)length; +/** Write an array of bytes contained in \p data. */ +- (void)writeData:(NSData*)data; +/** Write 32-bit unsigned integer that represents a \p size of a collection. */ +- (void)writeSize:(UInt32)size; +/** Write zero padding until data is aligned with \p alignment. */ +- (void)writeAlignment:(UInt8)alignment; +/** Write a string with UTF-8 encoding. */ +- (void)writeUTF8:(NSString*)value; +/** Introspects into an object and writes its representation. + * + * Supported Data Types: + * - NSNull + * - NSNumber + * - NSString (as UTF-8) + * - FlutterStandardTypedData + * - NSArray of supported types + * - NSDictionary of supporte types + * + * NSAsserts on failure. + */ +- (void)writeValue:(id)value; +@end + +/** + * A reader of the Flutter standard binary encoding. + * + * See `FlutterStandardMessageCodec` for details on the encoding. + * + * The encoding is extensible via subclasses overriding `readValueOfType`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardReader : NSObject +/** + * Create a new `FlutterStandardReader` who reads from \p data. + */ +- (instancetype)initWithData:(NSData*)data; +/** Returns YES when the reader hasn't reached the end of its data. */ +- (BOOL)hasMore; +/** Reads a byte value and increments the position. */ +- (UInt8)readByte; +/** Reads a sequence of byte values of \p length and increments the position. */ +- (void)readBytes:(void*)destination length:(NSUInteger)length; +/** Reads a sequence of byte values of \p length and increments the position. */ +- (NSData*)readData:(NSUInteger)length; +/** Reads a 32-bit unsigned integer representing a collection size and increments the position.*/ +- (UInt32)readSize; +/** Advances the read position until it is aligned with \p alignment. */ +- (void)readAlignment:(UInt8)alignment; +/** Read a null terminated string encoded with UTF-8/ */ +- (NSString*)readUTF8; +/** + * Reads a byte for `FlutterStandardField` the decodes a value matching that type. + * + * See also: -[FlutterStandardWriter writeValue] + */ +- (nullable id)readValue; +/** + * Decodes a value matching the \p type specified. + * + * See also: + * - `FlutterStandardField` + * - `-[FlutterStandardWriter writeValue]` + */ +- (nullable id)readValueOfType:(UInt8)type; +@end + +/** + * A factory of compatible reader/writer instances using the Flutter standard + * binary encoding or extensions thereof. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardReaderWriter : NSObject +/** + * Create a new `FlutterStandardWriter` for writing to \p data. + */ +- (FlutterStandardWriter*)writerWithData:(NSMutableData*)data; +/** + * Create a new `FlutterStandardReader` for reading from \p data. + */ +- (FlutterStandardReader*)readerWithData:(NSData*)data; +@end + +/** + * A `FlutterMessageCodec` using the Flutter standard binary encoding. + * + * This codec is guaranteed to be compatible with the corresponding + * [StandardMessageCodec](https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Supported messages are acyclic values of these forms: + * + * - `nil` or `NSNull` + * - `NSNumber` (including their representation of Boolean values) + * - `NSString` + * - `FlutterStandardTypedData` + * - `NSArray` of supported values + * - `NSDictionary` with supported keys and values + * + * On the Dart side, these values are represented as follows: + * + * - `nil` or `NSNull`: null + * - `NSNumber`: `bool`, `int`, or `double`, depending on the contained value. + * - `NSString`: `String` + * - `FlutterStandardTypedData`: `Uint8List`, `Int32List`, `Int64List`, or `Float64List` + * - `NSArray`: `List` + * - `NSDictionary`: `Map` + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardMessageCodec : NSObject +/** + * Create a `FlutterStandardMessageCodec` who will read and write to \p readerWriter. + */ ++ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter; +@end + +/** + * Command object representing a method call on a `FlutterMethodChannel`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterMethodCall : NSObject +/** + * Creates a method call for invoking the specified named method with the + * specified arguments. + * + * @param method the name of the method to call. + * @param arguments the arguments value. + */ ++ (instancetype)methodCallWithMethodName:(NSString*)method arguments:(id _Nullable)arguments; + +/** + * The method name. + */ +@property(readonly, nonatomic) NSString* method; + +/** + * The arguments. + */ +@property(readonly, nonatomic, nullable) id arguments; +@end + +/** + * Error object representing an unsuccessful outcome of invoking a method + * on a `FlutterMethodChannel`, or an error event on a `FlutterEventChannel`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterError : NSObject +/** + * Creates a `FlutterError` with the specified error code, message, and details. + * + * @param code An error code string for programmatic use. + * @param message A human-readable error message. + * @param details Custom error details. + */ ++ (instancetype)errorWithCode:(NSString*)code + message:(NSString* _Nullable)message + details:(id _Nullable)details; +/** + The error code. + */ +@property(readonly, nonatomic) NSString* code; + +/** + The error message. + */ +@property(readonly, nonatomic, nullable) NSString* message; + +/** + The error details. + */ +@property(readonly, nonatomic, nullable) id details; +@end + +/** + * Type of numeric data items encoded in a `FlutterStandardDataType`. + * + * - FlutterStandardDataTypeUInt8: plain bytes + * - FlutterStandardDataTypeInt32: 32-bit signed integers + * - FlutterStandardDataTypeInt64: 64-bit signed integers + * - FlutterStandardDataTypeFloat64: 64-bit floats + */ +typedef NS_ENUM(NSInteger, FlutterStandardDataType) { + // NOLINTBEGIN(readability-identifier-naming) + FlutterStandardDataTypeUInt8, + FlutterStandardDataTypeInt32, + FlutterStandardDataTypeInt64, + FlutterStandardDataTypeFloat32, + FlutterStandardDataTypeFloat64, + // NOLINTEND(readability-identifier-naming) +}; + +/** + * A byte buffer holding `UInt8`, `SInt32`, `SInt64`, or `Float64` values, used + * with `FlutterStandardMessageCodec` and `FlutterStandardMethodCodec`. + * + * Two's complement encoding is used for signed integers. IEEE754 + * double-precision representation is used for floats. The platform's native + * endianness is assumed. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardTypedData : NSObject +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as plain bytes. + * + * @param data the byte data. + */ ++ (instancetype)typedDataWithBytes:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 32-bit signed integers. + * + * @param data the byte data. The length must be divisible by 4. + */ ++ (instancetype)typedDataWithInt32:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 64-bit signed integers. + * + * @param data the byte data. The length must be divisible by 8. + */ ++ (instancetype)typedDataWithInt64:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 32-bit floats. + * + * @param data the byte data. The length must be divisible by 8. + */ ++ (instancetype)typedDataWithFloat32:(NSData*)data; + +/** + * Creates a `FlutterStandardTypedData` which interprets the specified data + * as 64-bit floats. + * + * @param data the byte data. The length must be divisible by 8. + */ ++ (instancetype)typedDataWithFloat64:(NSData*)data; + +/** + * The raw underlying data buffer. + */ +@property(readonly, nonatomic) NSData* data; + +/** + * The type of the encoded values. + */ +@property(readonly, nonatomic, assign) FlutterStandardDataType type; + +/** + * The number of value items encoded. + */ +@property(readonly, nonatomic, assign) UInt32 elementCount; + +/** + * The number of bytes used by the encoding of a single value item. + */ +@property(readonly, nonatomic, assign) UInt8 elementSize; +@end + +/** + * An arbitrarily large integer value, used with `FlutterStandardMessageCodec` + * and `FlutterStandardMethodCodec`. + */ +FLUTTER_DARWIN_EXPORT +FLUTTER_UNAVAILABLE("Unavailable on 2018-08-31. Deprecated on 2018-01-09. " + "FlutterStandardBigInteger was needed because the Dart 1.0 int type had no " + "size limit. With Dart 2.0, the int type is a fixed-size, 64-bit signed " + "integer. If you need to communicate larger integers, use NSString encoding " + "instead.") +@interface FlutterStandardBigInteger : NSObject +@end + +/** + * A codec for method calls and enveloped results. + * + * Method calls are encoded as binary messages with enough structure that the + * codec can extract a method name `NSString` and an arguments `NSObject`, + * possibly `nil`. These data items are used to populate a `FlutterMethodCall`. + * + * Result envelopes are encoded as binary messages with enough structure that + * the codec can determine whether the result was successful or an error. In + * the former case, the codec can extract the result `NSObject`, possibly `nil`. + * In the latter case, the codec can extract an error code `NSString`, a + * human-readable `NSString` error message (possibly `nil`), and a custom + * error details `NSObject`, possibly `nil`. These data items are used to + * populate a `FlutterError`. + */ +FLUTTER_DARWIN_EXPORT +@protocol FlutterMethodCodec +/** + * Provides access to a shared instance this codec. + * + * @return The shared instance. + */ ++ (instancetype)sharedInstance; + +/** + * Encodes the specified method call into binary. + * + * @param methodCall The method call. The arguments value + * must be supported by this codec. + * @return The binary encoding. + */ +- (NSData*)encodeMethodCall:(FlutterMethodCall*)methodCall; + +/** + * Decodes the specified method call from binary. + * + * @param methodCall The method call to decode. + * @return The decoded method call. + */ +- (FlutterMethodCall*)decodeMethodCall:(NSData*)methodCall; + +/** + * Encodes the specified successful result into binary. + * + * @param result The result. Must be a value supported by this codec. + * @return The binary encoding. + */ +- (NSData*)encodeSuccessEnvelope:(id _Nullable)result; + +/** + * Encodes the specified error result into binary. + * + * @param error The error object. The error details value must be supported + * by this codec. + * @return The binary encoding. + */ +- (NSData*)encodeErrorEnvelope:(FlutterError*)error; + +/** + * Deccodes the specified result envelope from binary. + * + * @param envelope The error object. + * @return The result value, if the envelope represented a successful result, + * or a `FlutterError` instance, if not. + */ +- (id _Nullable)decodeEnvelope:(NSData*)envelope; +@end + +/** + * A `FlutterMethodCodec` using UTF-8 encoded JSON method calls and result + * envelopes. + * + * This codec is guaranteed to be compatible with the corresponding + * [JSONMethodCodec](https://api.flutter.dev/flutter/services/JSONMethodCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Values supported as methods arguments and result payloads are + * those supported as top-level or leaf values by `FlutterJSONMessageCodec`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterJSONMethodCodec : NSObject +@end + +/** + * A `FlutterMethodCodec` using the Flutter standard binary encoding. + * + * This codec is guaranteed to be compatible with the corresponding + * [StandardMethodCodec](https://api.flutter.dev/flutter/services/StandardMethodCodec-class.html) + * on the Dart side. These parts of the Flutter SDK are evolved synchronously. + * + * Values supported as method arguments and result payloads are those supported by + * `FlutterStandardMessageCodec`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterStandardMethodCodec : NSObject +/** + * Create a `FlutterStandardMethodCodec` who will read and write to \p readerWriter. + */ ++ (instancetype)codecWithReaderWriter:(FlutterStandardReaderWriter*)readerWriter; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERCODECS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterDartProject.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterDartProject.h new file mode 100644 index 000000000..c1fd8db50 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterDartProject.h @@ -0,0 +1,102 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERDARTPROJECT_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERDARTPROJECT_H_ + +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * A set of Flutter and Dart assets used by a `FlutterEngine` to initialize execution. + * + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterDartProject : NSObject + +/** + * Initializes a Flutter Dart project from a bundle. + * + * The bundle must either contain a flutter_assets resource directory, or set the Info.plist key + * FLTAssetsPath to override that name (if you are doing a custom build using a different name). + * + * @param bundle The bundle containing the Flutter assets directory. If nil, the App framework + * created by Flutter will be used. + */ +- (instancetype)initWithPrecompiledDartBundle:(nullable NSBundle*)bundle NS_DESIGNATED_INITIALIZER; +/** + * Unavailable - use `init` instead. + */ +- (instancetype)initFromDefaultSourceForConfiguration API_UNAVAILABLE(macos) + FLUTTER_UNAVAILABLE("Use -init instead."); + +/** + * Returns the default identifier for the bundle where we expect to find the Flutter Dart + * application. + */ ++ (NSString*)defaultBundleIdentifier; + +/** + * An NSArray of NSStrings to be passed as command line arguments to the Dart entrypoint. + * + * If this is not explicitly set, this will default to the contents of + * [NSProcessInfo arguments], without the binary name. + * + * Set this to nil to pass no arguments to the Dart entrypoint. + */ +@property(nonatomic, nullable, copy) + NSArray* dartEntrypointArguments API_UNAVAILABLE(ios); + +/** + * Returns the file name for the given asset. If the bundle with the identifier + * "io.flutter.flutter.app" exists, it will try use that bundle; otherwise, it + * will use the main bundle. To specify a different bundle, use + * `+lookupKeyForAsset:fromBundle`. + * + * @param asset The name of the asset. The name can be hierarchical. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset; + +/** + * Returns the file name for the given asset. + * The returned file name can be used to access the asset in the supplied bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param bundle The `NSBundle` to use for looking up the asset. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset fromBundle:(nullable NSBundle*)bundle; + +/** + * Returns the file name for the given asset which originates from the specified package. + * The returned file name can be used to access the asset in the application's main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package; + +/** + * Returns the file name for the given asset which originates from the specified package. + * The returned file name can be used to access the asset in the specified bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @param bundle The bundle to use when doing the lookup. + * @return the file name to be used for lookup in the main bundle. + */ ++ (NSString*)lookupKeyForAsset:(NSString*)asset + fromPackage:(NSString*)package + fromBundle:(nullable NSBundle*)bundle; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERDARTPROJECT_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterEngine.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterEngine.h new file mode 100644 index 000000000..c11e2c72f --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterEngine.h @@ -0,0 +1,495 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINE_H_ + +#import +#import + +#import "FlutterBinaryMessenger.h" +#import "FlutterDartProject.h" +#import "FlutterMacros.h" +#import "FlutterPlugin.h" +#import "FlutterTexture.h" + +@class FlutterViewController; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The dart entrypoint that is associated with `main()`. This is to be used as an argument to the + * `runWithEntrypoint*` methods. + */ +// NOLINTNEXTLINE(readability-identifier-naming) +extern NSString* const FlutterDefaultDartEntrypoint; + +/** + * The default Flutter initial route ("/"). + */ +// NOLINTNEXTLINE(readability-identifier-naming) +extern NSString* const FlutterDefaultInitialRoute; + +/** + * The FlutterEngine class coordinates a single instance of execution for a + * `FlutterDartProject`. It may have zero or one `FlutterViewController` at a + * time, which can be specified via `-setViewController:`. + * `FlutterViewController`'s `initWithEngine` initializer will automatically call + * `-setViewController:` for itself. + * + * A FlutterEngine can be created independently of a `FlutterViewController` for + * headless execution. It can also persist across the lifespan of multiple + * `FlutterViewController` instances to maintain state and/or asynchronous tasks + * (such as downloading a large file). + * + * A FlutterEngine can also be used to prewarm the Dart execution environment and reduce the + * latency of showing the Flutter screen when a `FlutterViewController` is created and presented. + * See http://flutter.dev/docs/development/add-to-app/performance for more details on loading + * performance. + * + * Alternatively, you can simply create a new `FlutterViewController` with only a + * `FlutterDartProject`. That `FlutterViewController` will internally manage its + * own instance of a FlutterEngine, but will not guarantee survival of the engine + * beyond the life of the ViewController. + * + * A newly initialized FlutterEngine will not actually run a Dart Isolate until + * either `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is invoked. + * One of these methods must be invoked before calling `-setViewController:`. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEngine : NSObject + +/** + * Default initializer for a FlutterEngine. + * + * Threads created by this FlutterEngine will appear as "FlutterEngine #" in + * Instruments. The prefix can be customized using `initWithName`. + * + * The engine will execute the project located in the bundle with the identifier + * "io.flutter.flutter.app" (the default for Flutter projects). + * + * A newly initialized engine will not run until either `-runWithEntrypoint:` or + * `-runWithEntrypoint:libraryURI:` is called. + * + * FlutterEngine created with this method will have allowHeadlessExecution set to `YES`. + * This means that the engine will continue to run regardless of whether a `FlutterViewController` + * is attached to it or not, until `-destroyContext:` is called or the process finishes. + */ +- (instancetype)init; + +/** + * Initialize this FlutterEngine. + * + * The engine will execute the project located in the bundle with the identifier + * "io.flutter.flutter.app" (the default for Flutter projects). + * + * A newly initialized engine will not run until either `-runWithEntrypoint:` or + * `-runWithEntrypoint:libraryURI:` is called. + * + * FlutterEngine created with this method will have allowHeadlessExecution set to `YES`. + * This means that the engine will continue to run regardless of whether a `FlutterViewController` + * is attached to it or not, until `-destroyContext:` is called or the process finishes. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + */ +- (instancetype)initWithName:(NSString*)labelPrefix; + +/** + * Initialize this FlutterEngine with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterEngine will attempt to locate + * the project in a default location (the flutter_assets folder in the iOS application + * bundle). + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI:` is called. + * + * FlutterEngine created with this method will have allowHeadlessExecution set to `YES`. + * This means that the engine will continue to run regardless of whether a `FlutterViewController` + * is attached to it or not, until `-destroyContext:` is called or the process finishes. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + * @param project The `FlutterDartProject` to run. + */ +- (instancetype)initWithName:(NSString*)labelPrefix project:(nullable FlutterDartProject*)project; + +/** + * Initialize this FlutterEngine with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterEngine will attempt to locate + * the project in a default location (the flutter_assets folder in the iOS application + * bundle). + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI:` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + * @param project The `FlutterDartProject` to run. + * @param allowHeadlessExecution Whether or not to allow this instance to continue + * running after passing a nil `FlutterViewController` to `-setViewController:`. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(nullable FlutterDartProject*)project + allowHeadlessExecution:(BOOL)allowHeadlessExecution; + +/** + * Initialize this FlutterEngine with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterEngine will attempt to locate + * the project in a default location (the flutter_assets folder in the iOS application + * bundle). + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI:` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances, and is used in instrumentation to label + * the threads used by this FlutterEngine. + * @param project The `FlutterDartProject` to run. + * @param allowHeadlessExecution Whether or not to allow this instance to continue + * running after passing a nil `FlutterViewController` to `-setViewController:`. + * @param restorationEnabled Whether state restoration is enabled. When true, the framework will + * wait for the attached view controller to provide restoration data. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(nullable FlutterDartProject*)project + allowHeadlessExecution:(BOOL)allowHeadlessExecution + restorationEnabled:(BOOL)restorationEnabled NS_DESIGNATED_INITIALIZER; + +/** + * Runs a Dart program on an Isolate from the main Dart library (i.e. the library that + * contains `main()`), using `main()` as the entrypoint (the default for Flutter projects), + * and using "/" (the default route) as the initial route. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)run; + +/** + * Runs a Dart program on an Isolate from the main Dart library (i.e. the library that + * contains `main()`), using "/" (the default route) as the initial route. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from the same Dart + * library that contains the app's main() function. If this is FlutterDefaultDartEntrypoint (or + * nil) it will default to `main()`. If it is not the app's main() function, that function must + * be decorated with `@pragma(vm:entry-point)` to ensure the method is not tree-shaken by the Dart + * compiler. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint; + +/** + * Runs a Dart program on an Isolate from the main Dart library (i.e. the library that + * contains `main()`). + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from the same Dart + * library that contains the app's main() function. If this is FlutterDefaultDartEntrypoint (or + * nil), it will default to `main()`. If it is not the app's main() function, that function must + * be decorated with `@pragma(vm:entry-point)` to ensure the method is not tree-shaken by the Dart + * compiler. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint + initialRoute:(nullable NSString*)initialRoute; + +/** + * Runs a Dart program on an Isolate using the specified entrypoint and Dart library, + * which may not be the same as the library containing the Dart program's `main()` function. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param uri The URI of the Dart library which contains the entrypoint method + * (example "package:foo_package/main.dart"). If nil, this will default to + * the same library as the `main()` function in the Dart program. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint libraryURI:(nullable NSString*)uri; + +/** + * Runs a Dart program on an Isolate using the specified entrypoint and Dart library, + * which may not be the same as the library containing the Dart program's `main()` function. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint + * method (example "package:foo_package/main.dart"). If nil, this will + * default to the same library as the `main()` function in the Dart program. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI + initialRoute:(nullable NSString*)initialRoute; + +/** + * Runs a Dart program on an Isolate using the specified entrypoint and Dart library, + * which may not be the same as the library containing the Dart program's `main()` function. + * + * The first call to this method will create a new Isolate. Subsequent calls will return + * immediately and have no effect. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint + * method (example "package:foo_package/main.dart"). If nil, this will + * default to the same library as the `main()` function in the Dart program. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * @param entrypointArgs Arguments passed as a list of string to Dart's entrypoint function. + * @return YES if the call succeeds in creating and running a Flutter Engine instance; NO otherwise. + */ +- (BOOL)runWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI + initialRoute:(nullable NSString*)initialRoute + entrypointArgs:(nullable NSArray*)entrypointArgs; + +/** + * Destroy running context for an engine. + * + * This method can be used to force the FlutterEngine object to release all resources. + * After sending this message, the object will be in an unusable state until it is deallocated. + * Accessing properties or sending messages to it will result in undefined behavior or runtime + * errors. + */ +- (void)destroyContext; + +/** + * Ensures that Flutter will generate a semantics tree. + * + * This is enabled by default if certain accessibility services are turned on by + * the user, or when using a Simulator. This method allows a user to turn + * semantics on when they would not ordinarily be generated and the performance + * overhead is not a concern, e.g. for UI testing. Note that semantics should + * never be programmatically turned off, as it would potentially disable + * accessibility services an end user has requested. + * + * This method must only be called after launching the engine via + * `-runWithEntrypoint:` or `-runWithEntryPoint:libraryURI`. + * + * Although this method returns synchronously, it does not guarantee that a + * semantics tree is actually available when the method returns. It + * synchronously ensures that the next frame the Flutter framework creates will + * have a semantics tree. + * + * You can subscribe to semantics updates via `NSNotificationCenter` by adding + * an observer for the name `FlutterSemanticsUpdateNotification`. The `object` + * parameter will be the `FlutterViewController` associated with the semantics + * update. This will asynchronously fire after a semantics tree has actually + * built (which may be some time after the frame has been rendered). + */ +- (void)ensureSemanticsEnabled; + +/** + * Sets the `FlutterViewController` for this instance. The FlutterEngine must be + * running (e.g. a successful call to `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI`) + * before calling this method. Callers may pass nil to remove the viewController + * and have the engine run headless in the current process. + * + * A FlutterEngine can only have one `FlutterViewController` at a time. If there is + * already a `FlutterViewController` associated with this instance, this method will replace + * the engine's current viewController with the newly specified one. + * + * Setting the viewController will signal the engine to start animations and drawing, and unsetting + * it will signal the engine to stop animations and drawing. However, neither will impact the state + * of the Dart program's execution. + */ +@property(nonatomic, weak) FlutterViewController* viewController; + +/** + * The `FlutterMethodChannel` used for localization related platform messages, such as + * setting the locale. + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly, nullable) FlutterMethodChannel* localizationChannel; +/** + * The `FlutterMethodChannel` used for navigation related platform messages. + * + * Can be nil after `destroyContext` is called. + * + * @see [Navigation + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/navigation-constant.html) + * @see [Navigator Widget](https://api.flutter.dev/flutter/widgets/Navigator-class.html) + */ +@property(nonatomic, readonly) FlutterMethodChannel* navigationChannel; + +/** + * The `FlutterMethodChannel` used for restoration related platform messages. + * + * Can be nil after `destroyContext` is called. + * + * @see [Restoration + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/restoration-constant.html) + */ +@property(nonatomic, readonly) FlutterMethodChannel* restorationChannel; + +/** + * The `FlutterMethodChannel` used for core platform messages, such as + * information about the screen orientation. + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly) FlutterMethodChannel* platformChannel; + +/** + * The `FlutterMethodChannel` used to communicate text input events to the + * Dart Isolate. + * + * Can be nil after `destroyContext` is called. + * + * @see [Text Input + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/textInput-constant.html) + */ +@property(nonatomic, readonly) FlutterMethodChannel* textInputChannel; + +/** + * The `FlutterBasicMessageChannel` used to communicate app lifecycle events + * to the Dart Isolate. + * + * Can be nil after `destroyContext` is called. + * + * @see [Lifecycle + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/lifecycle-constant.html) + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* lifecycleChannel; + +/** + * The `FlutterBasicMessageChannel` used for communicating system events, such as + * memory pressure events. + * + * Can be nil after `destroyContext` is called. + * + * @see [System + * Channel](https://api.flutter.dev/flutter/services/SystemChannels/system-constant.html) + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* systemChannel; + +/** + * The `FlutterBasicMessageChannel` used for communicating user settings such as + * clock format and text scale. + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* settingsChannel; + +/** + * The `FlutterBasicMessageChannel` used for communicating key events + * from physical keyboards + * + * Can be nil after `destroyContext` is called. + */ +@property(nonatomic, readonly) FlutterBasicMessageChannel* keyEventChannel; + +/** + * The `NSURL` of the Dart VM Service for the service isolate. + * + * This is only set in debug and profile runtime modes, and only after the + * Dart VM Service is ready. In release mode or before the Dart VM Service has + * started, it returns `nil`. + */ +@property(nonatomic, readonly, nullable) NSURL* vmServiceUrl; + +/** + * The `FlutterBinaryMessenger` associated with this FlutterEngine (used for communicating with + * channels). + */ +@property(nonatomic, readonly) NSObject* binaryMessenger; + +/** + * The `FlutterTextureRegistry` associated with this FlutterEngine (used to register textures). + */ +@property(nonatomic, readonly) NSObject* textureRegistry; + +/** + * The UI Isolate ID of the engine. + * + * This property will be nil if the engine is not running. + */ +@property(nonatomic, readonly, copy, nullable) NSString* isolateId; + +/** + * Whether or not GPU calls are allowed. + * + * Typically this is set when the app is backgrounded and foregrounded. + */ +@property(nonatomic, assign) BOOL isGpuDisabled; + +@end + +/** + * Exposes parts of a `FlutterEngine` for registration purposes. + * + * This is used when the engine is created implicitly to allow registering + * plugins, application-level method channels, platform views, etc. + */ +@protocol FlutterImplicitEngineBridge + +/** + * The `FlutterPluginRegistry` for the created `FlutterEngine`. + * + * This can be used to vend `FlutterPluginRegistrar`s for plugins. + */ +@property(nonatomic, readonly) NSObject* pluginRegistry; + +/** + * The `FlutterApplicationRegistrar` for the created `FlutterEngine`. + * + * This registrar provides access to application-level services, such as the engine's + * `FlutterBinaryMessenger` or `FlutterTextureRegistry`. + */ +@property(nonatomic, readonly) NSObject* applicationRegistrar; + +@end + +/** + * Protocol for receiving a callback when an implicit engine is initialized, such as when created by + * a FlutterViewController from a storyboard. + * + * This provides the engine bridge to the listener. + */ +@protocol FlutterImplicitEngineDelegate +@required + +/** + * Called once the implicit `FlutterEngine` is initialized. + * + * The `FlutterImplicitEngineBridge` can then be used to register plugins, + * application-level method channels, platform views, etc. + */ +- (void)didInitializeImplicitFlutterEngine:(NSObject*)engineBridge; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterEngineGroup.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterEngineGroup.h new file mode 100644 index 000000000..47cdc0753 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterEngineGroup.h @@ -0,0 +1,115 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINEGROUP_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINEGROUP_H_ + +#import + +#import "FlutterEngine.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Options that control how a FlutterEngine should be created. */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEngineGroupOptions : NSObject + +/** + * The name of a top-level function from a Dart library. If this is FlutterDefaultDartEntrypoint + * (or nil); this will default to `main()`. If it is not the app's main() function, that function + * must be decorated with `@pragma(vm:entry-point)` to ensure themethod is not tree-shaken by the + * Dart compiler. + */ +@property(nonatomic, copy, nullable) NSString* entrypoint; + +/** + * The URI of the Dart library which contains the entrypoint method. If nil, this will default to + * the same library as the `main()` function in the Dart program. + */ +@property(nonatomic, copy, nullable) NSString* libraryURI; + +/** + * The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + */ +@property(nonatomic, copy, nullable) NSString* initialRoute; + +/** + * Arguments passed as a list of string to Dart's entrypoint function. + */ +@property(nonatomic, copy, nullable) NSArray* entrypointArgs; +@end + +/** + * Represents a collection of FlutterEngines who share resources which allows + * them to be created with less time const and occupy less memory than just + * creating multiple FlutterEngines. + * + * Deleting a FlutterEngineGroup doesn't invalidate existing FlutterEngines, but + * it eliminates the possibility to create more FlutterEngines in that group. + * + * @warning This class is a work-in-progress and may change. + * @see https://github.com/flutter/flutter/issues/72009 + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterEngineGroup : NSObject +- (instancetype)init NS_UNAVAILABLE; + +/** + * Initialize a new FlutterEngineGroup. + * + * @param name The name that will present in the threads shared across the + * engines in this group. + * @param project The `FlutterDartProject` that all FlutterEngines in this group + * will be executing. + */ +- (instancetype)initWithName:(NSString*)name + project:(nullable FlutterDartProject*)project NS_DESIGNATED_INITIALIZER; + +/** + * Creates a running `FlutterEngine` that shares components with this group. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint method. IF nil, + * this will default to the same library as the `main()` function in the Dart program. + * + * @see FlutterEngineGroup + */ +- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI; + +/** + * Creates a running `FlutterEngine` that shares components with this group. + * + * @param entrypoint The name of a top-level function from a Dart library. If this is + * FlutterDefaultDartEntrypoint (or nil); this will default to `main()`. If it is not the app's + * main() function, that function must be decorated with `@pragma(vm:entry-point)` to ensure the + * method is not tree-shaken by the Dart compiler. + * @param libraryURI The URI of the Dart library which contains the entrypoint method. IF nil, + * this will default to the same library as the `main()` function in the Dart program. + * @param initialRoute The name of the initial Flutter `Navigator` `Route` to load. If this is + * FlutterDefaultInitialRoute (or nil), it will default to the "/" route. + * + * @see FlutterEngineGroup + */ +- (FlutterEngine*)makeEngineWithEntrypoint:(nullable NSString*)entrypoint + libraryURI:(nullable NSString*)libraryURI + initialRoute:(nullable NSString*)initialRoute; + +/** + * Creates a running `FlutterEngine` that shares components with this group. + * + * @param options Options that control how a FlutterEngine should be created. + * + * @see FlutterEngineGroupOptions + */ +- (FlutterEngine*)makeEngineWithOptions:(nullable FlutterEngineGroupOptions*)options; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERENGINEGROUP_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterHeadlessDartRunner.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterHeadlessDartRunner.h new file mode 100644 index 000000000..08069ab5b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterHeadlessDartRunner.h @@ -0,0 +1,97 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERHEADLESSDARTRUNNER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERHEADLESSDARTRUNNER_H_ + +#import + +#import "FlutterBinaryMessenger.h" +#import "FlutterDartProject.h" +#import "FlutterEngine.h" +#import "FlutterMacros.h" + +/** + * A callback for when FlutterHeadlessDartRunner has attempted to start a Dart + * Isolate in the background. + * + * @param success YES if the Isolate was started and run successfully, NO + * otherwise. + */ +typedef void (^FlutterHeadlessDartRunnerCallback)(BOOL success); + +/** + * The deprecated FlutterHeadlessDartRunner runs Flutter Dart code with a null rasterizer, + * and no native drawing surface. It is appropriate for use in running Dart + * code e.g. in the background from a plugin. + * + * Most callers should prefer using `FlutterEngine` directly; this interface exists + * for legacy support. + */ +FLUTTER_DARWIN_EXPORT +FLUTTER_DEPRECATED("FlutterEngine should be used rather than FlutterHeadlessDartRunner") +@interface FlutterHeadlessDartRunner : FlutterEngine + +/** + * Initialize this FlutterHeadlessDartRunner with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate + * the project in a default location. + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances + * @param projectOrNil The `FlutterDartProject` to run. + */ +- (instancetype)initWithName:(NSString*)labelPrefix project:(FlutterDartProject*)projectOrNil; + +/** + * Initialize this FlutterHeadlessDartRunner with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate + * the project in a default location. + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances + * @param projectOrNil The `FlutterDartProject` to run. + * @param allowHeadlessExecution Must be set to `YES`. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(FlutterDartProject*)projectOrNil + allowHeadlessExecution:(BOOL)allowHeadlessExecution; + +/** + * Initialize this FlutterHeadlessDartRunner with a `FlutterDartProject`. + * + * If the FlutterDartProject is not specified, the FlutterHeadlessDartRunner will attempt to locate + * the project in a default location. + * + * A newly initialized engine will not run the `FlutterDartProject` until either + * `-runWithEntrypoint:` or `-runWithEntrypoint:libraryURI` is called. + * + * @param labelPrefix The label prefix used to identify threads for this instance. Should + * be unique across FlutterEngine instances + * @param projectOrNil The `FlutterDartProject` to run. + * @param allowHeadlessExecution Must be set to `YES`. + * @param restorationEnabled Must be set to `NO`. + */ +- (instancetype)initWithName:(NSString*)labelPrefix + project:(FlutterDartProject*)projectOrNil + allowHeadlessExecution:(BOOL)allowHeadlessExecution + restorationEnabled:(BOOL)restorationEnabled NS_DESIGNATED_INITIALIZER; + +/** + * Not recommended for use - will initialize with a default label ("io.flutter.headless") + * and the default FlutterDartProject. + */ +- (instancetype)init; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERHEADLESSDARTRUNNER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterHourFormat.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterHourFormat.h new file mode 100644 index 000000000..e33e1a0ac --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterHourFormat.h @@ -0,0 +1,15 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERHOURFORMAT_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERHOURFORMAT_H_ + +#import + +@interface FlutterHourFormat : NSObject ++ (BOOL)isAlwaysUse24HourFormat; + +@end + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERHOURFORMAT_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterMacros.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterMacros.h new file mode 100644 index 000000000..7f53b4133 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterMacros.h @@ -0,0 +1,48 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERMACROS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERMACROS_H_ + +#if defined(FLUTTER_FRAMEWORK) + +#define FLUTTER_DARWIN_EXPORT __attribute__((visibility("default"))) + +#else // defined(FLUTTER_SDK) + +#define FLUTTER_DARWIN_EXPORT + +#endif // defined(FLUTTER_SDK) + +#ifndef NS_ASSUME_NONNULL_BEGIN +#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") +#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") +#endif // defined(NS_ASSUME_NONNULL_BEGIN) + +/** + * Indicates that the API has been deprecated for the specified reason. Code + * that uses the deprecated API will continue to work as before. However, the + * API will soon become unavailable and users are encouraged to immediately take + * the appropriate action mentioned in the deprecation message and the BREAKING + * CHANGES section present in the Flutter.h umbrella header. + */ +#define FLUTTER_DEPRECATED(msg) __attribute__((__deprecated__(msg))) + +/** + * Indicates that the previously deprecated API is now unavailable. Code that + * uses the API will not work and the declaration of the API is only a stub + * meant to display the given message detailing the actions for the user to take + * immediately. + */ +#define FLUTTER_UNAVAILABLE(msg) __attribute__((__unavailable__(msg))) + +#if __has_feature(objc_arc) +#define FLUTTER_ASSERT_ARC +#define FLUTTER_ASSERT_NOT_ARC #error ARC must be disabled ! +#else +#define FLUTTER_ASSERT_ARC #error ARC must be enabled ! +#define FLUTTER_ASSERT_NOT_ARC +#endif + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERMACROS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPlatformViews.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPlatformViews.h new file mode 100644 index 000000000..4742bfe8e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPlatformViews.h @@ -0,0 +1,56 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLATFORMVIEWS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLATFORMVIEWS_H_ + +#import + +#import "FlutterCodecs.h" +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Wraps a `UIView` for embedding in the Flutter hierarchy + */ +@protocol FlutterPlatformView +/** + * Returns a reference to the `UIView` that is wrapped by this `FlutterPlatformView`. + */ +- (UIView*)view; +@end + +FLUTTER_DARWIN_EXPORT +@protocol FlutterPlatformViewFactory +/** + * Create a `FlutterPlatformView`. + * + * Implemented by iOS code that expose a `UIView` for embedding in a Flutter app. + * + * The implementation of this method should create a new `UIView` and return it. + * + * @param frame The rectangle for the newly created `UIView` measured in points. + * @param viewId A unique identifier for this `UIView`. + * @param args Parameters for creating the `UIView` sent from the Dart side of the Flutter app. + * If `createArgsCodec` is not implemented, or if no creation arguments were sent from the Dart + * code, this will be null. Otherwise this will be the value sent from the Dart code as decoded by + * `createArgsCodec`. + */ +- (NSObject*)createWithFrame:(CGRect)frame + viewIdentifier:(int64_t)viewId + arguments:(id _Nullable)args; + +/** + * Returns the `FlutterMessageCodec` for decoding the args parameter of `createWithFrame`. + * + * Only needs to be implemented if `createWithFrame` needs an arguments parameter. + */ +@optional +- (NSObject*)createArgsCodec; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLATFORMVIEWS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPlugin.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPlugin.h new file mode 100644 index 000000000..24e83756b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPlugin.h @@ -0,0 +1,513 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGIN_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGIN_H_ + +#import +#import + +#import "FlutterBinaryMessenger.h" +#import "FlutterChannels.h" +#import "FlutterCodecs.h" +#import "FlutterPlatformViews.h" +#import "FlutterSceneLifeCycle.h" +#import "FlutterTexture.h" + +NS_ASSUME_NONNULL_BEGIN +@protocol FlutterPluginRegistrar; +@protocol FlutterPluginRegistry; + +#pragma mark - +/** + * Protocol for listener of events from the UIApplication, typically a FlutterPlugin. + */ +@protocol FlutterApplicationLifeCycleDelegate + +@optional +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if this vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if this vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + willFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationDidBecomeActive:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillResignActive:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationDidEnterBackground:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillEnterForeground:(UIApplication*)application; + +/** + Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)applicationWillTerminate:(UIApplication*)application; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings + API_DEPRECATED( + "See -[UIApplicationDelegate application:didRegisterUserNotificationSettings:] deprecation", + ios(8.0, 10.0)); + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + didReceiveRemoteNotification:(NSDictionary*)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didReceiveLocalNotification:(UILocalNotification*)notification + API_DEPRECATED( + "See -[UIApplicationDelegate application:didReceiveLocalNotification:] deprecation", + ios(4.0, 10.0)); + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + options:(NSDictionary*)options; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + sourceApplication:(NSString*)sourceApplication + annotation:(id)annotation; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler + API_AVAILABLE(ios(9.0)); + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + handleEventsForBackgroundURLSession:(nonnull NSString*)identifier + completionHandler:(nonnull void (^)(void))completionHandler; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Called if this has been registered for `UIApplicationDelegate` callbacks. + * + * @return `YES` if this handles the request. + */ +- (BOOL)application:(UIApplication*)application + continueUserActivity:(NSUserActivity*)userActivity + restorationHandler:(void (^)(NSArray*))restorationHandler; +@end + +#pragma mark - +/** + * A plugin registration callback. + * + * Used for registering plugins with additional instances of + * `FlutterPluginRegistry`. + * + * @param registry The registry to register plugins with. + */ +typedef void (*FlutterPluginRegistrantCallback)(NSObject* registry); + +#pragma mark - +/** + * Implemented by the iOS part of a Flutter plugin. + * + * Defines a set of optional callback methods and a method to set up the plugin + * and register it to be called by other application components. + */ +@protocol FlutterPlugin +@required +/** + * Registers this plugin using the context information and callback registration + * methods exposed by the given registrar. + * + * The registrar is obtained from a `FlutterPluginRegistry` which keeps track of + * the identity of registered plugins and provides basic support for cross-plugin + * coordination. + * + * The caller of this method, a plugin registrant, is usually autogenerated by + * Flutter tooling based on declared plugin dependencies. The generated registrant + * asks the registry for a registrar for each plugin, and calls this method to + * allow the plugin to initialize itself and register callbacks with application + * objects available through the registrar protocol. + * + * @param registrar A helper providing application context and methods for + * registering callbacks. + */ ++ (void)registerWithRegistrar:(NSObject*)registrar; +@optional +/** + * Set a callback for registering plugins to an additional `FlutterPluginRegistry`, + * including headless `FlutterEngine` instances. + * + * This method is typically called from within an application's `AppDelegate` at + * startup to allow for plugins which create additional `FlutterEngine` instances + * to register the application's plugins. + * + * @param callback A callback for registering some set of plugins with a + * `FlutterPluginRegistry`. + */ ++ (void)setPluginRegistrantCallback:(FlutterPluginRegistrantCallback)callback; +@optional +/** + * Called if this plugin has been registered to receive `FlutterMethodCall`s. + * + * @param call The method call command object. + * @param result A callback for submitting the result of the call. + */ +- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result; +@optional +/** + * Called when a plugin is being removed from a `FlutterEngine`, which is + * usually the result of the `FlutterEngine` being deallocated. This method + * provides the opportunity to do necessary cleanup. + * + * You will only receive this method if you registered your plugin instance with + * the `FlutterEngine` via `-[FlutterPluginRegistry publish:]`. + * + * @param registrar The registrar that was used to publish the plugin. + * + */ +- (void)detachFromEngineForRegistrar:(NSObject*)registrar; +@end + +#pragma mark - +/** + * How the UIGestureRecognizers of a platform view are blocked. + * + * UIGestureRecognizers of platform views can be blocked based on decisions made by the + * Flutter Framework (e.g. When an interact-able widget is covering the platform view). + */ +typedef enum { + // NOLINTBEGIN(readability-identifier-naming) + /** + * Flutter blocks all the UIGestureRecognizers on the platform view as soon as it + * decides they should be blocked. + * + * With this policy, only the `touchesBegan` method for all the UIGestureRecognizers is guaranteed + * to be called. + */ + FlutterPlatformViewGestureRecognizersBlockingPolicyEager, + /** + * Flutter blocks the platform view's UIGestureRecognizers from recognizing only after + * touchesEnded was invoked. + * + * This results in the platform view's UIGestureRecognizers seeing the entire touch sequence, + * but never recognizing the gesture (and never invoking actions). + */ + FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded, + // NOLINTEND(readability-identifier-naming) +} FlutterPlatformViewGestureRecognizersBlockingPolicy; + +#pragma mark - +/** + * The base interface for `FlutterPluginRegistrar` and `FlutterApplicationRegistrar`. + * + * Provides registration context for the application or plugins. + */ +@protocol FlutterBaseRegistrar +/** + * Returns a `FlutterBinaryMessenger` for creating Dart/iOS communication + * channels to be used by the application or a plugin. + * + * @return The messenger. + */ +- (NSObject*)messenger; + +/** + * Returns a `FlutterTextureRegistry` for registering textures + * provided by the application or a plugin. + * + * @return The texture registry. + */ +- (NSObject*)textures; + +/** + * Registers a `FlutterPlatformViewFactory` for creation of platform views. + * + * Applications or plugins can expose `UIView` for embedding in Flutter apps by registering a view + * factory. + * + * @param factory The view factory that will be registered. + * @param factoryId A unique identifier for the factory, the Dart code of the Flutter app can use + * this identifier to request creation of a `UIView` by the registered factory. + */ +- (void)registerViewFactory:(NSObject*)factory + withId:(NSString*)factoryId; + +/** + * Registers a `FlutterPlatformViewFactory` for creation of platform views. + * + * Applications or plugins can expose a `UIView` for embedding in Flutter apps by registering a view + * factory. + * + * @param factory The view factory that will be registered. + * @param factoryId A unique identifier for the factory, the Dart code of the Flutter app can use + * this identifier to request creation of a `UIView` by the registered factory. + * @param gestureRecognizersBlockingPolicy How UIGestureRecognizers on the platform views are + * blocked. + * + */ +- (void)registerViewFactory:(NSObject*)factory + withId:(NSString*)factoryId + gestureRecognizersBlockingPolicy: + (FlutterPlatformViewGestureRecognizersBlockingPolicy)gestureRecognizersBlockingPolicy; +@end + +/** + * A registrar for Flutter applications. + * + * This registrar provides access to application-level services, such as the binary messenger and + * texture registry. + * + * See also `FlutterBaseRegistrar`. + */ +@protocol FlutterApplicationRegistrar +@end + +/** + * Registration context for a single `FlutterPlugin`, providing a one stop shop + * for the plugin to access contextual information and register callbacks for + * various application events. + * + * Registrars are obtained from a `FlutterPluginRegistry` which keeps track of + * the identity of registered plugins and provides basic support for cross-plugin + * coordination. + */ +@protocol FlutterPluginRegistrar + +/** + * The `UIViewController` whose view is displaying Flutter content. + * + * The plugin typically should not store a strong reference to this view + * controller. + * + * This property is provided for backwards compatibility for apps that assume + * a single view, and will eventually be replaced by the multi-view API variant. + * + * This property may be |nil|, for instance in a headless environment, or when + * the underlying Flutter engine is deallocated. + */ +@property(nullable, readonly) UIViewController* viewController; + +/** + * Publishes a value for external use of the plugin. + * + * Plugins may publish a single value, such as an instance of the + * plugin's main class, for situations where external control or + * interaction is needed. + * + * The published value will be available from the `FlutterPluginRegistry`. + * Repeated calls overwrite any previous publication. + * + * @param value The value to be published. + */ +- (void)publish:(NSObject*)value; + +/** + * Registers the plugin as a receiver of incoming method calls from the Dart side + * on the specified `FlutterMethodChannel`. + * + * @param delegate The receiving object, such as the plugin's main class. + * @param channel The channel + */ +- (void)addMethodCallDelegate:(NSObject*)delegate + channel:(FlutterMethodChannel*)channel; + +/** + * Registers the plugin as a receiver of `UIApplicationDelegate` calls. + * + * @param delegate The receiving object, such as the plugin's main class. + */ +- (void)addApplicationDelegate:(NSObject*)delegate + NS_EXTENSION_UNAVAILABLE_IOS("Disallowed in plugins used in app extensions"); + +/** + * Registers the plugin as a receiver of `UISceneDelegate` and `UIWindowSceneDelegate` calls. + * + * @param delegate The receiving object, such as the plugin's main class. + */ +- (void)addSceneDelegate:(NSObject*)delegate + API_AVAILABLE(ios(13.0)); + +/** + * Returns the file name for the given asset. + * The returned file name can be used to access the asset in the application's main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @return the file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset; + +/** + * Returns the file name for the given asset which originates from the specified package. + * The returned file name can be used to access the asset in the application's main bundle. + * + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @return the file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package; +@end + +#pragma mark - +/** + * A registry of Flutter iOS plugins. + * + * Plugins are identified by unique string keys, typically the name of the + * plugin's main class. The registry tracks plugins by this key, mapping it to + * a value published by the plugin during registration, if any. This provides a + * very basic means of cross-plugin coordination with loose coupling between + * unrelated plugins. + * + * Plugins typically need contextual information and the ability to register + * callbacks for various application events. To keep the API of the registry + * focused, these facilities are not provided directly by the registry, but by + * a `FlutterPluginRegistrar`, created by the registry in exchange for the unique + * key of the plugin. + * + * There is no implied connection between the registry and the registrar. + * Specifically, callbacks registered by the plugin via the registrar may be + * relayed directly to the underlying iOS application objects. + */ +@protocol FlutterPluginRegistry +/** + * Returns a registrar for registering a plugin. + * + * @param pluginKey The unique key identifying the plugin. + */ +- (nullable NSObject*)registrarForPlugin:(NSString*)pluginKey; +/** + * Returns whether the specified plugin has been registered. + * + * @param pluginKey The unique key identifying the plugin. + * @return `YES` if `registrarForPlugin` has been called with `pluginKey`. + */ +- (BOOL)hasPlugin:(NSString*)pluginKey; + +/** + * Returns a value published by the specified plugin. + * + * @param pluginKey The unique key identifying the plugin. + * @return An object published by the plugin, if any. Will be `NSNull` if + * nothing has been published. Will be `nil` if the plugin has not been + * registered. + */ +- (nullable NSObject*)valuePublishedByPlugin:(NSString*)pluginKey; +@end + +#pragma mark - +/** + * The target of registration of plugins. + * + * This often is hooked up to the GeneratedPluginRegistrant which is + * automatically generated by Flutter for the dependencies listed in the + * project. + */ +@protocol FlutterPluginRegistrant +@required +/** + * Register all the plugins for the registrant. + * + * This will be called after a FlutterEngine has been instantiated, the registry + * will connect any plugins to that engine. + * + * @param registry The registry where plugins will be registered. + */ +- (void)registerWithRegistry:(NSObject*)registry; +@end + +#pragma mark - +/** + * Implement this in the `UIAppDelegate` of your app to enable Flutter plugins to register + * themselves to the application life cycle events. + * + * For plugins to receive events from `UNUserNotificationCenter`, register this as the + * `UNUserNotificationCenterDelegate`. + */ +@protocol FlutterAppLifeCycleProvider + +/** + * Called when registering a new `FlutterApplicaitonLifeCycleDelegate`. + * + * See also: `-[FlutterAppDelegate addApplicationLifeCycleDelegate:]` + */ +- (void)addApplicationLifeCycleDelegate:(NSObject*)delegate; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGIN_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h new file mode 100644 index 000000000..95d1e611e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h @@ -0,0 +1,148 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ + +#import "FlutterPlugin.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Propagates `UIAppDelegate` callbacks to registered plugins. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterPluginAppLifeCycleDelegate : NSObject + +/** + * Registers `delegate` to receive life cycle callbacks via this FlutterPluginAppLifeCycleDelegate + * as long as it is alive. + * + * `delegate` will only be referenced weakly. + */ +- (void)addDelegate:(NSObject*)delegate; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if any plugin vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + * + * @return `NO` if any plugin vetos application launch. + */ +- (BOOL)application:(UIApplication*)application + willFinishLaunchingWithOptions:(NSDictionary*)launchOptions; + +/** + * Called if this plugin has been registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings + API_DEPRECATED( + "See -[UIApplicationDelegate application:didRegisterUserNotificationSettings:] deprecation", + ios(8.0, 10.0)); + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didFailToRegisterForRemoteNotificationsWithError:(NSError*)error; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didReceiveRemoteNotification:(NSDictionary*)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + didReceiveLocalNotification:(UILocalNotification*)notification + API_DEPRECATED( + "See -[UIApplicationDelegate application:didReceiveLocalNotification:] deprecation", + ios(4.0, 10.0)); + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + options:(NSDictionary*)options; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + openURL:(NSURL*)url + sourceApplication:(NSString*)sourceApplication + annotation:(id)annotation; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks. + */ +- (void)application:(UIApplication*)application + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler + API_AVAILABLE(ios(9.0)); + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + handleEventsForBackgroundURLSession:(nonnull NSString*)identifier + completionHandler:(nonnull void (^)(void))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @returns `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; + +/** + * Calls all plugins registered for `UIApplicationDelegate` callbacks in order of registration until + * some plugin handles the request. + * + * @return `YES` if any plugin handles the request. + */ +- (BOOL)application:(UIApplication*)application + continueUserActivity:(NSUserActivity*)userActivity + restorationHandler:(void (^)(NSArray*))restorationHandler; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERPLUGINAPPLIFECYCLEDELEGATE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterSceneDelegate.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterSceneDelegate.h new file mode 100644 index 000000000..2238d7333 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterSceneDelegate.h @@ -0,0 +1,28 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ + +#import +#import "FlutterMacros.h" +#import "FlutterSceneLifeCycle.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The UISceneDelegate used by Flutter by default. + * + * This class is typically specified as the UISceneDelegate in the Info.plist. + */ +FLUTTER_DARWIN_EXPORT +@interface FlutterSceneDelegate + : NSObject +@property(nonatomic, strong, nullable) UIWindow* window; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENEDELEGATE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterSceneLifeCycle.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterSceneLifeCycle.h new file mode 100644 index 000000000..70898c840 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterSceneLifeCycle.h @@ -0,0 +1,219 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENELIFECYCLE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENELIFECYCLE_H_ + +#import +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FlutterEngine; + +/** + * A protocol for delegates that handle `UISceneDelegate` and `UIWindowSceneDelegate` life-cycle + * events. + * + * This protocol provides a way for Flutter plugins to observe and react to scene-based life-cycle + * events. The methods in this protocol correspond to methods in `UISceneDelegate` and + * `UIWindowSceneDelegate`. + * + * See also: + * + * * `UISceneDelegate`, core methods you use to respond to life-cycle events occurring within a + * scene: https://developer.apple.com/documentation/uikit/uiscenedelegate + * * `UIWindowSceneDelegate`, additional methods that you use to manage app-specific tasks + * occurring in a scene: https://developer.apple.com/documentation/uikit/uiwindowscenedelegate + */ +API_AVAILABLE(ios(13.0)) +@protocol FlutterSceneLifeCycleDelegate + +@optional + +#pragma mark - Connecting and disconnecting the scene + +/** + * Informs the delegate that a new scene is about to be connected and configured. + * + * This corresponds to `-[UISceneDelegate scene:willConnectToSession:options:]`. `connectionOptions` + * may be nil if another plugin has already handled the connection. + * + * @return `YES` if this handled the connection. + */ +- (BOOL)scene:(UIScene*)scene + willConnectToSession:(UISceneSession*)session + options:(nullable UISceneConnectionOptions*)connectionOptions; + +- (void)sceneDidDisconnect:(UIScene*)scene; + +#pragma mark - Transitioning to the foreground + +- (void)sceneWillEnterForeground:(UIScene*)scene; + +- (void)sceneDidBecomeActive:(UIScene*)scene; + +#pragma mark - Transitioning to the background + +- (void)sceneWillResignActive:(UIScene*)scene; + +- (void)sceneDidEnterBackground:(UIScene*)scene; + +#pragma mark - Opening URLs + +/** + * Asks the delegate to open one or more URLs. + * + * This corresponds to `-[UISceneDelegate scene:openURLContexts:]`. + * + * @return `YES` if this handled one or more of the URLs. + */ +- (BOOL)scene:(UIScene*)scene openURLContexts:(NSSet*)URLContexts; + +#pragma mark - Continuing user activities + +/** + * Tells the delegate that the scene is continuing a user activity. + * + * This corresponds to `-[UISceneDelegate scene:continueUserActivity:]`. + * + * @return `YES` if this handled the activity. + */ +- (BOOL)scene:(UIScene*)scene continueUserActivity:(NSUserActivity*)userActivity; + +#pragma mark - Performing tasks + +/** + * Tells the delegate that the user has selected a home screen quick action. + * + * This corresponds to `-[UIWindowSceneDelegate + * windowScene:performActionForShortcutItem:completionHandler:]`. + * + * @return `YES` if this handled the shortcut. + */ +- (BOOL)windowScene:(UIWindowScene*)windowScene + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler; + +@end + +/** + * A protocol for manually registering a `FlutterEngine` to receive scene life cycle events. + */ +@protocol FlutterSceneLifeCycleEngineRegistration +/** + * Registers a `FlutterEngine` to receive scene life cycle events. + * + * This method is **only** necessary when the following conditions are true: + * 1. Multiple Scenes (UIApplicationSupportsMultipleScenes) is enabled. + * 2. The `UIWindowSceneDelegate` `window.rootViewController` is not a `FlutterViewController` + * initialized with the target `FlutterEngine`. + * + * When multiple scenes is enabled (UIApplicationSupportsMultipleScenes), Flutter cannot + * automatically associate a `FlutterEngine` with a scene during the scene connection phase. In + * order for plugins to receive launch connection information, the `FlutterEngine` must be manually + * registered with either the `FlutterSceneDelegate` or `FlutterPluginSceneLifeCycleDelegate` during + * `scene:willConnectToSession:options:`. + * + * In all other cases, or once the `FlutterViewController.view` associated with the `FlutterEngine` + * is added to the view hierarchy, Flutter will automatically handle registration for scene events. + * + * Manually registered engines must also be manually deregistered and re-registered if they + * switch scenes. Use `unregisterSceneLifeCycleWithFlutterEngine:`. + * + * @param engine The `FlutterEngine` to register for scene life cycle events. + * @return `NO` if already manually registered. + */ +- (BOOL)registerSceneLifeCycleWithFlutterEngine:(FlutterEngine*)engine; + +/** + * Use this method to unregister a `FlutterEngine` from the scene's life cycle events. + * + * @param engine The `FlutterEngine` to unregister for scene life cycle events. + * @return `NO` if the engine was not found among the manually registered engines and could not be + * unregistered. + */ +- (BOOL)unregisterSceneLifeCycleWithFlutterEngine:(FlutterEngine*)engine; +@end + +/** + * Forwards `UISceneDelegate` and `UIWindowSceneDelegate` callbacks to plugins that register for + * them. + * + * This class is responsible for receiving `UISceneDelegate` and `UIWindowSceneDelegate` callbacks + * and forwarding them to any plugins. + */ +FLUTTER_DARWIN_EXPORT +API_AVAILABLE(ios(13.0)) +@interface FlutterPluginSceneLifeCycleDelegate : NSObject + +#pragma mark - Connecting and disconnecting the scene + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)scene:(UIScene*)scene + willConnectToSession:(UISceneSession*)session + options:(UISceneConnectionOptions*)connectionOptions; + +- (void)sceneDidDisconnect:(UIScene*)scene; + +#pragma mark - Transitioning to the foreground + +- (void)sceneWillEnterForeground:(UIScene*)scene; + +- (void)sceneDidBecomeActive:(UIScene*)scene; + +#pragma mark - Transitioning to the background + +- (void)sceneWillResignActive:(UIScene*)scene; + +- (void)sceneDidEnterBackground:(UIScene*)scene; + +#pragma mark - Opening URLs + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)scene:(UIScene*)scene openURLContexts:(NSSet*)URLContexts; + +#pragma mark - Continuing user activities + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)scene:(UIScene*)scene continueUserActivity:(NSUserActivity*)userActivity; + +#pragma mark - Performing tasks + +/** + * Calls all plugins registered for `UIWindowScene` callbacks in order of registration until + * a plugin handles the request. + */ +- (void)windowScene:(UIWindowScene*)windowScene + performActionForShortcutItem:(UIApplicationShortcutItem*)shortcutItem + completionHandler:(void (^)(BOOL succeeded))completionHandler; + +@end + +/** + * A protocol for `UIWindowSceneDelegate` objects that vend a `FlutterPluginSceneLifeCycleDelegate`. + * + * By conforming to this protocol, a `UIWindowSceneDelegate` can vend a + * `FlutterPluginSceneLifeCycleDelegate` that can be used to forward scene life-cycle events to + * Flutter plugins. + * + * This is typically implemented by the app's `SceneDelegate`. + */ +API_AVAILABLE(ios(13.0)) +@protocol FlutterSceneLifeCycleProvider +@property(nonatomic, strong) FlutterPluginSceneLifeCycleDelegate* sceneLifeCycleDelegate; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERSCENELIFECYCLE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterTexture.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterTexture.h new file mode 100644 index 000000000..1fa7a0ef6 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterTexture.h @@ -0,0 +1,69 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERTEXTURE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERTEXTURE_H_ + +#import +#import + +#import "FlutterMacros.h" + +NS_ASSUME_NONNULL_BEGIN + +FLUTTER_DARWIN_EXPORT +/** + * Represents a texture that can be shared with Flutter. + * + * See also: https://github.com/flutter/plugins/tree/master/packages/camera + */ +@protocol FlutterTexture +/** + * Copy the contents of the texture into a `CVPixelBuffer`. + * + * The type of the pixel buffer is one of the following: + * - `kCVPixelFormatType_32BGRA` + * - `kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange` + * - `kCVPixelFormatType_420YpCbCr8BiPlanarFullRange` + */ +- (CVPixelBufferRef _Nullable)copyPixelBuffer; + +/** + * Called when the texture is unregistered. + * + * Called on the raster thread. + */ +@optional +- (void)onTextureUnregistered:(NSObject*)texture; +@end + +FLUTTER_DARWIN_EXPORT +/** + * A collection of registered `FlutterTexture`'s. + */ +@protocol FlutterTextureRegistry +/** + * Registers a `FlutterTexture` for usage in Flutter and returns an id that can be used to reference + * that texture when calling into Flutter with channels. Textures must be registered on the + * platform thread. On success returns the pointer to the registered texture, else returns 0. + */ +- (int64_t)registerTexture:(NSObject*)texture; +/** + * Notifies Flutter that the content of the previously registered texture has been updated. + * + * This will trigger a call to `-[FlutterTexture copyPixelBuffer]` on the raster thread. + */ +- (void)textureFrameAvailable:(int64_t)textureId; +/** + * Unregisters a `FlutterTexture` that has previously regeistered with `registerTexture:`. Textures + * must be unregistered on the platform thread. + * + * @param textureId The result that was previously returned from `registerTexture:`. + */ +- (void)unregisterTexture:(int64_t)textureId; +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_FRAMEWORK_HEADERS_FLUTTERTEXTURE_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterViewController.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterViewController.h new file mode 100644 index 000000000..e41565c3b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Headers/FlutterViewController.h @@ -0,0 +1,261 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERVIEWCONTROLLER_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERVIEWCONTROLLER_H_ + +#import +#include + +#import "FlutterBinaryMessenger.h" +#import "FlutterDartProject.h" +#import "FlutterEngine.h" +#import "FlutterHourFormat.h" +#import "FlutterMacros.h" +#import "FlutterPlugin.h" +#import "FlutterTexture.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FlutterEngine; + +/** + * The name used for semantic update notifications via `NSNotificationCenter`. + * + * The object passed as the sender is the `FlutterViewController` associated + * with the update. + */ +FLUTTER_DARWIN_EXPORT +// NOLINTNEXTLINE(readability-identifier-naming) +extern NSNotificationName const FlutterSemanticsUpdateNotification; + +/** + * A `UIViewController` implementation for Flutter views. + * + * Dart execution, channel communication, texture registration, and plugin registration are all + * handled by `FlutterEngine`. Calls on this class to those members all proxy through to the + * `FlutterEngine` attached FlutterViewController. + * + * A FlutterViewController can be initialized either with an already-running `FlutterEngine` via the + * `initWithEngine:` initializer, or it can be initialized with a `FlutterDartProject` that will be + * used to implicitly spin up a new `FlutterEngine`. Creating a `FlutterEngine` before showing a + * FlutterViewController can be used to pre-initialize the Dart VM and to prepare the isolate in + * order to reduce the latency to the first rendered frame. See + * https://flutter.dev/docs/development/add-to-app/performance for more details on loading + * latency. + * + * Holding a `FlutterEngine` independently of FlutterViewControllers can also be used to not to lose + * Dart-related state and asynchronous tasks when navigating back and forth between a + * FlutterViewController and other `UIViewController`s. + */ +FLUTTER_DARWIN_EXPORT +#ifdef __IPHONE_13_4 +@interface FlutterViewController + : UIViewController +#else +@interface FlutterViewController : UIViewController +#endif + +/** + * Initializes this FlutterViewController with the specified `FlutterEngine`. + * + * The initialized viewcontroller will attach itself to the engine as part of this process. + * + * @param engine The `FlutterEngine` instance to attach to. Cannot be nil. + * @param nibName The NIB name to initialize this UIViewController with. + * @param nibBundle The NIB bundle. + */ +- (instancetype)initWithEngine:(FlutterEngine*)engine + nibName:(nullable NSString*)nibName + bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a new FlutterViewController and `FlutterEngine` with the specified + * `FlutterDartProject`. + * + * This will implicitly create a new `FlutterEngine` which is retrievable via the `engine` property + * after initialization. + * + * @param project The `FlutterDartProject` to initialize the `FlutterEngine` with. + * @param nibName The NIB name to initialize this UIViewController with. + * @param nibBundle The NIB bundle. + */ +- (instancetype)initWithProject:(nullable FlutterDartProject*)project + nibName:(nullable NSString*)nibName + bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a new FlutterViewController and `FlutterEngine` with the specified + * `FlutterDartProject` and `initialRoute`. + * + * This will implicitly create a new `FlutterEngine` which is retrievable via the `engine` property + * after initialization. + * + * @param project The `FlutterDartProject` to initialize the `FlutterEngine` with. + * @param initialRoute The initial `Navigator` route to load. + * @param nibName The NIB name to initialize this UIViewController with. + * @param nibBundle The NIB bundle. + */ +- (instancetype)initWithProject:(nullable FlutterDartProject*)project + initialRoute:(nullable NSString*)initialRoute + nibName:(nullable NSString*)nibName + bundle:(nullable NSBundle*)nibBundle NS_DESIGNATED_INITIALIZER; + +/** + * Initializer that is called from loading a FlutterViewController from a XIB. + * + * See also: + * https://developer.apple.com/documentation/foundation/nscoding/1416145-initwithcoder?language=objc + */ +- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_DESIGNATED_INITIALIZER; + +/** + * Registers a callback that will be invoked when the Flutter view has been rendered. + * The callback will be fired only once. + * + * Replaces an existing callback. Use a `nil` callback to unregister the existing one. + */ +- (void)setFlutterViewDidRenderCallback:(void (^)(void))callback; + +/** + * Returns the file name for the given asset. + * The returned file name can be used to access the asset in the application's + * main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @return The file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset; + +/** + * Returns the file name for the given asset which originates from the specified + * package. + * The returned file name can be used to access the asset in the application's + * main bundle. + * + * @param asset The name of the asset. The name can be hierarchical. + * @param package The name of the package from which the asset originates. + * @return The file name to be used for lookup in the main bundle. + */ +- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package; + +/** + * Deprecated API to set initial route. + * + * Attempts to set the first route that the Flutter app shows if the Flutter + * runtime hasn't yet started. The default is "/". + * + * This method must be called immediately after `initWithProject` and has no + * effect when using `initWithEngine` if the `FlutterEngine` has already been + * run. + * + * Setting this after the Flutter started running has no effect. See `pushRoute` + * and `popRoute` to change the route after Flutter started running. + * + * This is deprecated because it needs to be called at the time of initialization + * and thus should just be in the `initWithProject` initializer. If using + * `initWithEngine`, the initial route should be set on the engine's + * initializer. + * + * @param route The name of the first route to show. + */ +- (void)setInitialRoute:(NSString*)route + FLUTTER_DEPRECATED("Use FlutterViewController initializer to specify initial route"); + +/** + * Instructs the Flutter Navigator (if any) to go back. + */ +- (void)popRoute; + +/** + * Instructs the Flutter Navigator (if any) to push a route on to the navigation + * stack. + * + * @param route The name of the route to push to the navigation stack. + */ +- (void)pushRoute:(NSString*)route; + +/** + * The `FlutterPluginRegistry` used by this FlutterViewController. + */ +- (id)pluginRegistry; + +/** + * A wrapper around UIAccessibilityIsVoiceOverRunning(). + * + * As a C function, UIAccessibilityIsVoiceOverRunning() cannot be mocked in testing. Mock + * this class method to testing features depends on UIAccessibilityIsVoiceOverRunning(). + */ ++ (BOOL)isUIAccessibilityIsVoiceOverRunning; + +/** + * True if at least one frame has rendered and the ViewController has appeared. + * + * This property is reset to false when the ViewController disappears. It is + * guaranteed to only alternate between true and false for observers. + */ +@property(nonatomic, readonly, getter=isDisplayingFlutterUI) BOOL displayingFlutterUI; + +/** + * Specifies the view to use as a splash screen. Flutter's rendering is asynchronous, so the first + * frame rendered by the Flutter application might not immediately appear when the Flutter view is + * initially placed in the view hierarchy. The splash screen view will be used as + * a replacement until the first frame is rendered. + * + * The view used should be appropriate for multiple sizes; an autoresizing mask to + * have a flexible width and height will be applied automatically. + * + * Set to nil to remove the splash screen view. + */ +@property(strong, nonatomic, nullable) UIView* splashScreenView; + +/** + * Attempts to set the `splashScreenView` property from the `UILaunchStoryboardName` from the + * main bundle's `Info.plist` file. This method will not change the value of `splashScreenView` + * if it cannot find a default one from a storyboard or nib. + * + * @return `YES` if successful, `NO` otherwise. + */ +- (BOOL)loadDefaultSplashScreenView; + +/** + * Controls whether the created view will be opaque or not. + * + * Default is `YES`. Note that setting this to `NO` may negatively impact performance + * when using hardware acceleration, and toggling this will trigger a re-layout of the + * view. + */ +@property(nonatomic, getter=isViewOpaque) BOOL viewOpaque; + +/** + * The `FlutterEngine` instance for this view controller. This could be the engine this + * `FlutterViewController` is initialized with or a new `FlutterEngine` implicitly created if + * no engine was supplied during initialization. + */ +@property(nonatomic, readonly) FlutterEngine* engine; + +/** + * The `FlutterBinaryMessenger` associated with this FlutterViewController (used for communicating + * with channels). + * + * This is just a convenient way to get the |FlutterEngine|'s binary messenger. + */ +@property(nonatomic, readonly) NSObject* binaryMessenger; + +/** + * If the `FlutterViewController` creates a `FlutterEngine`, this property + * determines if that `FlutterEngine` has `allowHeadlessExecution` set. + * + * The intention is that this is used with the XIB. Otherwise, a + * `FlutterEngine` can just be sent to the init methods. + * + * See also: `-[FlutterEngine initWithName:project:allowHeadlessExecution:]` + */ +@property(nonatomic, readonly) BOOL engineAllowHeadlessExecution; + +@end + +NS_ASSUME_NONNULL_END + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_HEADERS_FLUTTERVIEWCONTROLLER_H_ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Info.plist new file mode 100644 index 000000000..4dae4d462 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Flutter + CFBundleIdentifier + io.flutter.flutter + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Flutter + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 13.0 + FlutterEngine + a5cb96369ef86c7e85abf5d662a1ca5d89775053 + BuildMode + debug + ClangVersion + b'Fuchsia clang version 21.0.0git (https://llvm.googlesource.com/llvm-project 8c7a2ce01a77c96028fe2c8566f65c45ad9408d3)' + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Modules/module.modulemap b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Modules/module.modulemap new file mode 100644 index 000000000..bf81c8a86 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module Flutter { + umbrella header "Flutter.h" + + export * + module * { export * } +} diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/PrivacyInfo.xcprivacy b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..d4bc7fc2e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/PrivacyInfo.xcprivacy @@ -0,0 +1,32 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + 0A2A.1 + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategorySystemBootTime + NSPrivacyAccessedAPITypeReasons + + 35F9.1 + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..a9d6a76c9 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/_CodeSignature/CodeResources @@ -0,0 +1,344 @@ + + + + + files + + Headers/Flutter.h + + dQsuFiftv2fxtixhcMIA/+B+uUM= + + Headers/FlutterAppDelegate.h + + PfJCf6hbYTWm910ECDC5roRPfWE= + + Headers/FlutterBinaryMessenger.h + + ksjIMu5IPw+Q3rw2YkAx0KjxkdM= + + Headers/FlutterCallbackCache.h + + V/wkSSsyYdMoexF6wPrC3KgkL4g= + + Headers/FlutterChannels.h + + vFsZXNqjflvqKqAzsIptQaTSJho= + + Headers/FlutterCodecs.h + + sUgX1PJzkvyinL5i7nS1ro/Kd5o= + + Headers/FlutterDartProject.h + + SpNs7IhIC7xP34Ej+LQCaEZkqik= + + Headers/FlutterEngine.h + + BFan2MPs+CkI3+ihxkbJDuKQ7a0= + + Headers/FlutterEngineGroup.h + + bkw+DmHReHDg1PPcvmSjuLZrheA= + + Headers/FlutterHeadlessDartRunner.h + + UqnnVWwQEYYX56eu7lt6dpR3LIc= + + Headers/FlutterHourFormat.h + + VjAwScWkWWSrDeetip3K4yhuwDU= + + Headers/FlutterMacros.h + + crQ9782ULebLQfIR+MbBkjB7d+k= + + Headers/FlutterPlatformViews.h + + hAwPmAERwlkwVd6RZpc09UHL50I= + + Headers/FlutterPlugin.h + + REG3r2IMfvEjtswwALvyVHTQhjo= + + Headers/FlutterPluginAppLifeCycleDelegate.h + + qWHw5VIWEa0NmJ1PMhD16nlfRKk= + + Headers/FlutterSceneDelegate.h + + 1YaIV2MTzs0X0U13jT89+5nUoL8= + + Headers/FlutterSceneLifeCycle.h + + IqEbKnMthck20540eNZgrlrLvJE= + + Headers/FlutterTexture.h + + 31prWLso2k5PfMMSbf5hGl+VE6Y= + + Headers/FlutterViewController.h + + LDr6kSVbUfyQFAxLwCACF5S2VEA= + + Info.plist + + 6xaOzhYI3/7yanBhXMuFNn0S+OA= + + Modules/module.modulemap + + wJV5dCKEGl+FAtDc8wJJh/fvKXs= + + PrivacyInfo.xcprivacy + + D+cqXttvC7E/uziGjFdqFabWd7A= + + icudtl.dat + + ipm8hg7aB3LzsfShJfpNR0QQ4hw= + + + files2 + + Headers/Flutter.h + + hash2 + + wfWyagPYLCRR2+wTuGRbtW3z3z2AWS+YFxuiBOFdSjY= + + + Headers/FlutterAppDelegate.h + + hash2 + + ehumZ2VCA9xOXBI/7gQunPmAgn9cJpiZKDS9p8XWqkY= + + + Headers/FlutterBinaryMessenger.h + + hash2 + + EXDk4t+7qCpyQkar+q9WHqY9bcK8eyohCwGVtBJhMy8= + + + Headers/FlutterCallbackCache.h + + hash2 + + 0h9+vK5K+r8moTsiGBfs6+TM9Qog089afHAy3gbcwDU= + + + Headers/FlutterChannels.h + + hash2 + + kg195C3vZLiOn8KeFQUy7DoVuA9VZDpqoBLVn64uGaI= + + + Headers/FlutterCodecs.h + + hash2 + + ZyqlHYuZbpFevVeny9Wdl0rVFgS7szIyssSiCyaaeFM= + + + Headers/FlutterDartProject.h + + hash2 + + U8q/0Ibt9q4O2HMsCdUwITtJdTx8Ljhlx+0aY83fH6s= + + + Headers/FlutterEngine.h + + hash2 + + QwvtJ2TkMcRYqWJ9V4J3LToKMLVK1pOcJpQtnIdnA+s= + + + Headers/FlutterEngineGroup.h + + hash2 + + SqzvIxqBXEJ3U9LJ32hCEXsrH2P16gumQ+gQx6Pdlf4= + + + Headers/FlutterHeadlessDartRunner.h + + hash2 + + nmZjZpvFCXrygf4U9aPkNi8VcI7cL5AtA+CY5uUWIL0= + + + Headers/FlutterHourFormat.h + + hash2 + + Q4SLFSghL/5EFJPyLg7PNi9J/xpkVVfzro0VQiQHtrY= + + + Headers/FlutterMacros.h + + hash2 + + ebBVHSZcUnAbN4hRcYq3ttt6++z1Ybc8KVSYhVToD5k= + + + Headers/FlutterPlatformViews.h + + hash2 + + 0aU9uM6QcpzmZpuFYObj9dGlGEkTKowPMERJQQdF2P4= + + + Headers/FlutterPlugin.h + + hash2 + + QcjhOhk5cb1U7bmyQh9TnFm1M2Tgv82RSSbJ6OIdMr4= + + + Headers/FlutterPluginAppLifeCycleDelegate.h + + hash2 + + +PMn+5SDj2Vd6RU8CQIt/JYl3T+8Dhp7HImqAzocoNk= + + + Headers/FlutterSceneDelegate.h + + hash2 + + G9urZeE312ldazkeP/7sut0t2hA3lfcuxHRSuLmj+gY= + + + Headers/FlutterSceneLifeCycle.h + + hash2 + + nvPq1KiXUwgQ/TtOSqHisNHQPvnVpvtXi3L0zLchdyI= + + + Headers/FlutterTexture.h + + hash2 + + JcpN4a9sv6xynlD3Ri611N5y+HoupUWp2hyrIXB/I8Y= + + + Headers/FlutterViewController.h + + hash2 + + yEgZTlCNrK/A/QBjEwNGB6ffC+A9gorPvnNgSbYuQ7Y= + + + Modules/module.modulemap + + hash2 + + 0VjriRpZ7AZZaP/0mMAPMJPhi6LoMB4MhXzL5j24tGs= + + + PrivacyInfo.xcprivacy + + hash2 + + n5XX54YqS1a2btkmvW1iLSplRagn0ZhHJ4tDjVcdQhI= + + + icudtl.dat + + hash2 + + wSU3Ai74GJkae/7UGnbY1q6WL/vA5lEax2Kl0IRef3w= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/icudtl.dat b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/icudtl.dat new file mode 100644 index 000000000..17e5b2aac Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/Flutter.framework/icudtl.dat differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/Info.plist new file mode 100644 index 000000000..b95c6f364 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..af5ed3805 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/_CodeSignature/CodeResources @@ -0,0 +1,101 @@ + + + + + files + + Info.plist + + t2lS3OfCvnlqSDlmDNh7Opo1yN4= + + + files2 + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/open_file_ios b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/open_file_ios new file mode 100755 index 000000000..312c002f4 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/open_file_ios.framework/open_file_ios differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/Info.plist new file mode 100644 index 000000000..3da0d7a47 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..5305cd8c1 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/_CodeSignature/CodeResources @@ -0,0 +1,124 @@ + + + + + files + + Info.plist + + 9tFT9ECNecWz1iEt2bkPXiS0OsU= + + path_provider_foundation_privacy.bundle/Info.plist + + uZhDvLtUFGGxUo04IxQgK3UPBUU= + + path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy + + /LX0ZlwxwIAIhjZaDB8EiH5KpXA= + + + files2 + + path_provider_foundation_privacy.bundle/Info.plist + + hash2 + + yitl00ny/gjEcOnTGu8fNpoBtU5yAvzkXiMhBFgXnS0= + + + path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy + + hash2 + + bS2g2NkwIn1CjB2TY7CtbjoS4sm2jFzilxWKdBL8jDE= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation new file mode 100755 index 000000000..353e65665 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist new file mode 100644 index 000000000..529e057cd Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..a34b7e2e6 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Info.plist new file mode 100644 index 000000000..4596734a5 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/PkgInfo b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/PkgInfo new file mode 100644 index 000000000..bd04210fb --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Runner b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Runner new file mode 100755 index 000000000..564140a2b Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Runner differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Runner.debug.dylib b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Runner.debug.dylib new file mode 100755 index 000000000..a78f8fe12 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/Runner.debug.dylib differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/_CodeSignature/CodeResources new file mode 100644 index 000000000..8f182eead --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/_CodeSignature/CodeResources @@ -0,0 +1,744 @@ + + + + + files + + AppFrameworkInfo.plist + + Xn4L7bM2rcO/4cI2SnVsh54DvCY= + + AppIcon60x60@2x.png + + WBDcNG/0BUOtsKQgKYOLyuqAbAM= + + AppIcon76x76@2x~ipad.png + + Bqtil6RquU1Hfn8gu0IYARWvCIM= + + Assets.car + + V9vLiwPPeg7Dt5e1PmYiElwagOo= + + Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib + + 28xWMBQ91UzszfdXY91SqhC7ecg= + + Base.lproj/LaunchScreen.storyboardc/Info.plist + + n2t8gsDpfE6XkhG31p7IQJRxTxU= + + Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib + + ZVgM1+KwZcZnwhgaI0F7Bt1ba2c= + + Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib + + hMnf/VIyTGR2nRcoLS3JCfeGmDs= + + Base.lproj/Main.storyboardc/Info.plist + + MDrKFvFWroTb0+KEbQShBcoBvo4= + + Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib + + nFC1waP0YzYOchnqa85lPwrC73s= + + Frameworks/App.framework/App + + yHA7gvIYo9xJkJRz5Xjn3Ms8h0M= + + Frameworks/App.framework/Info.plist + + T7ae0s1yqPVdrLK0y5gqABVb1PU= + + Frameworks/App.framework/_CodeSignature/CodeResources + + KZXWw+KbuhnM6yqbfVdIE8xfus4= + + Frameworks/App.framework/flutter_assets/AssetManifest.bin + + 21tVqbIV90TbglF4ZJhNBz8uj4w= + + Frameworks/App.framework/flutter_assets/FontManifest.json + + +D1xbIOooc3ypce1+jh+mmLy1J0= + + Frameworks/App.framework/flutter_assets/NOTICES.Z + + AXyVWLODHa/0OkUkKJ+LZ8eJFkE= + + Frameworks/App.framework/flutter_assets/NativeAssetsManifest.json + + re4p7E8rPLLsN+wzaPN/+AVpXTY= + + Frameworks/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf + + /CUoTuPQqqdexfyOT9lpJhV+2MQ= + + Frameworks/App.framework/flutter_assets/isolate_snapshot_data + + Oct4LBWkbrUyhS8o11D8knDiOCw= + + Frameworks/App.framework/flutter_assets/kernel_blob.bin + + xJK2Y4wcwvcJLYpeprI0c3lbUjE= + + Frameworks/App.framework/flutter_assets/shaders/ink_sparkle.frag + + VvTF10G1gIeea4aI0DhJjCjHgXQ= + + Frameworks/App.framework/flutter_assets/shaders/stretch_effect.frag + + kG7Fh+R6JkaM/GufJFUfEToHTEg= + + Frameworks/App.framework/flutter_assets/vm_snapshot_data + + 3y4zj1lbLxr1MIJjsR7xSTsrd4k= + + Frameworks/Flutter.framework/Flutter + + q7Vz/ur64MbVzWOpebqX/XoWdlE= + + Frameworks/Flutter.framework/Headers/Flutter.h + + dQsuFiftv2fxtixhcMIA/+B+uUM= + + Frameworks/Flutter.framework/Headers/FlutterAppDelegate.h + + PfJCf6hbYTWm910ECDC5roRPfWE= + + Frameworks/Flutter.framework/Headers/FlutterBinaryMessenger.h + + ksjIMu5IPw+Q3rw2YkAx0KjxkdM= + + Frameworks/Flutter.framework/Headers/FlutterCallbackCache.h + + V/wkSSsyYdMoexF6wPrC3KgkL4g= + + Frameworks/Flutter.framework/Headers/FlutterChannels.h + + vFsZXNqjflvqKqAzsIptQaTSJho= + + Frameworks/Flutter.framework/Headers/FlutterCodecs.h + + sUgX1PJzkvyinL5i7nS1ro/Kd5o= + + Frameworks/Flutter.framework/Headers/FlutterDartProject.h + + SpNs7IhIC7xP34Ej+LQCaEZkqik= + + Frameworks/Flutter.framework/Headers/FlutterEngine.h + + BFan2MPs+CkI3+ihxkbJDuKQ7a0= + + Frameworks/Flutter.framework/Headers/FlutterEngineGroup.h + + bkw+DmHReHDg1PPcvmSjuLZrheA= + + Frameworks/Flutter.framework/Headers/FlutterHeadlessDartRunner.h + + UqnnVWwQEYYX56eu7lt6dpR3LIc= + + Frameworks/Flutter.framework/Headers/FlutterHourFormat.h + + VjAwScWkWWSrDeetip3K4yhuwDU= + + Frameworks/Flutter.framework/Headers/FlutterMacros.h + + crQ9782ULebLQfIR+MbBkjB7d+k= + + Frameworks/Flutter.framework/Headers/FlutterPlatformViews.h + + hAwPmAERwlkwVd6RZpc09UHL50I= + + Frameworks/Flutter.framework/Headers/FlutterPlugin.h + + REG3r2IMfvEjtswwALvyVHTQhjo= + + Frameworks/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h + + qWHw5VIWEa0NmJ1PMhD16nlfRKk= + + Frameworks/Flutter.framework/Headers/FlutterSceneDelegate.h + + 1YaIV2MTzs0X0U13jT89+5nUoL8= + + Frameworks/Flutter.framework/Headers/FlutterSceneLifeCycle.h + + IqEbKnMthck20540eNZgrlrLvJE= + + Frameworks/Flutter.framework/Headers/FlutterTexture.h + + 31prWLso2k5PfMMSbf5hGl+VE6Y= + + Frameworks/Flutter.framework/Headers/FlutterViewController.h + + LDr6kSVbUfyQFAxLwCACF5S2VEA= + + Frameworks/Flutter.framework/Info.plist + + 6xaOzhYI3/7yanBhXMuFNn0S+OA= + + Frameworks/Flutter.framework/Modules/module.modulemap + + wJV5dCKEGl+FAtDc8wJJh/fvKXs= + + Frameworks/Flutter.framework/PrivacyInfo.xcprivacy + + D+cqXttvC7E/uziGjFdqFabWd7A= + + Frameworks/Flutter.framework/_CodeSignature/CodeResources + + Y434Ej6CyzL1kl/wwpKuVgPQn9M= + + Frameworks/Flutter.framework/icudtl.dat + + ipm8hg7aB3LzsfShJfpNR0QQ4hw= + + Frameworks/open_file_ios.framework/Info.plist + + t2lS3OfCvnlqSDlmDNh7Opo1yN4= + + Frameworks/open_file_ios.framework/_CodeSignature/CodeResources + + yNdVW8NZY8wdrQ5yomT+WNGbXrU= + + Frameworks/open_file_ios.framework/open_file_ios + + yx0Feur8HquYzqoTljVf81YGLzo= + + Frameworks/path_provider_foundation.framework/Info.plist + + 9tFT9ECNecWz1iEt2bkPXiS0OsU= + + Frameworks/path_provider_foundation.framework/_CodeSignature/CodeResources + + RKIRPm2sP9lDKm38bAA+66MVcg0= + + Frameworks/path_provider_foundation.framework/path_provider_foundation + + X4XrEVc5+YAgLyiMv9/l1aByr7U= + + Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist + + uZhDvLtUFGGxUo04IxQgK3UPBUU= + + Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy + + /LX0ZlwxwIAIhjZaDB8EiH5KpXA= + + Info.plist + + xBDYFiJqZ6zm8m1mnEHBPbEjWG8= + + PkgInfo + + n57qDP4tZfLD1rCS43W0B4LQjzE= + + Runner.debug.dylib + + 0cDaQY1YGX7mHyGqZPN40UW8afE= + + __preview.dylib + + /47Ukfr52tmy9TtKNWWqRY6aT4M= + + + files2 + + AppFrameworkInfo.plist + + hash2 + + G4lBGUbG8Y+PUnHlv145+f60u99sUfvqFJdwYSD2rcM= + + + AppIcon60x60@2x.png + + hash2 + + Gb4XFIHccaCygD680B3YsMX9V3je40wKPKvJSMIl8k4= + + + AppIcon76x76@2x~ipad.png + + hash2 + + QcfUL25h+P5/MLH/oiVq7LyWgr4G0YxKMGIEPhouVHw= + + + Assets.car + + hash2 + + 8SSj/uHCuHzAt+cqcf8pB5NLXsGfEwZcCDCkOmCB+8k= + + + Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib + + hash2 + + by6WshwXWgbEYiAy2bvh0UtjSVa3EwySkNFc1FazGdY= + + + Base.lproj/LaunchScreen.storyboardc/Info.plist + + hash2 + + HyVdXMU7Ux4/KalAao30mpWOK/lEPT4gvYN09wf31cg= + + + Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib + + hash2 + + VPNjf2cf66XxnoLsT0p/tEi7PPwPsYDwiapXH8jwU+I= + + + Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib + + hash2 + + BY/hOMO0FcCl8mCMQqjVbFeb8Q97c1G9lHscfspHFNk= + + + Base.lproj/Main.storyboardc/Info.plist + + hash2 + + PpvapAjR62rl6Ym4E6hkTgpKmBICxTaQXeUqcpHmmqQ= + + + Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib + + hash2 + + y90o2JQjssm+7ysnziyWCNMNbGqdLnZ595pTgURE5T8= + + + Frameworks/App.framework/App + + hash2 + + 2s9RuUcpVWkQ2F+lylB8+6H1BAdVwwVgCiBunSwB+iQ= + + + Frameworks/App.framework/Info.plist + + hash2 + + kbjTW9nIi0OuDqyDSPm1fS8+IJpFAOZRaxi0Wbfj8r4= + + + Frameworks/App.framework/_CodeSignature/CodeResources + + hash2 + + iHt4CAV5FjCqhbG2tCz6Uai942Paz19dTLoKtCGg8QA= + + + Frameworks/App.framework/flutter_assets/AssetManifest.bin + + hash2 + + 9WbMb8zGVzZcAZeszzp9b4D4Ugn/Zm/3dPTcvFJKqEI= + + + Frameworks/App.framework/flutter_assets/FontManifest.json + + hash2 + + KLHrKz0uGtYLjIsPkQCxzL9JL3+pf1vrtR6pfnOSbn0= + + + Frameworks/App.framework/flutter_assets/NOTICES.Z + + hash2 + + NrzjHg60IXWImNkLTcTe7UCS05stOUJPlqXWWY/FNkI= + + + Frameworks/App.framework/flutter_assets/NativeAssetsManifest.json + + hash2 + + lUijHkoEgTXB2U+Rkyi/tirix7s8q5ZVfHlB2ql3dss= + + + Frameworks/App.framework/flutter_assets/fonts/MaterialIcons-Regular.otf + + hash2 + + 2YZbZxoJ1oPROoYwidiCXg9ho3aWzl19RIvIAjqmJFM= + + + Frameworks/App.framework/flutter_assets/isolate_snapshot_data + + hash2 + + wHUhal5u7BswH9uKyMGmAinBbqMbGrC0nmFvt+raT08= + + + Frameworks/App.framework/flutter_assets/kernel_blob.bin + + hash2 + + ep/WR3I5PLXXV7RxcQ7FfWvg01VWJNtKO9QO09OUJUg= + + + Frameworks/App.framework/flutter_assets/shaders/ink_sparkle.frag + + hash2 + + TGVjYgE+Oyl6guvhhPPrWfynkxkJeFjSzSLsQqn7Q3M= + + + Frameworks/App.framework/flutter_assets/shaders/stretch_effect.frag + + hash2 + + Y/95u280RMpR6e6ndBjH5Pm8ujZSD5Qf33woQ/NncNU= + + + Frameworks/App.framework/flutter_assets/vm_snapshot_data + + hash2 + + OdF1NJaYIhUMtPHX5I2sunghfvWky6zAyizwBbVifbU= + + + Frameworks/Flutter.framework/Flutter + + hash2 + + 96X14mxgZyLL61GkSSWFMvQLRZmvgtGHzkaEZO63qv8= + + + Frameworks/Flutter.framework/Headers/Flutter.h + + hash2 + + wfWyagPYLCRR2+wTuGRbtW3z3z2AWS+YFxuiBOFdSjY= + + + Frameworks/Flutter.framework/Headers/FlutterAppDelegate.h + + hash2 + + ehumZ2VCA9xOXBI/7gQunPmAgn9cJpiZKDS9p8XWqkY= + + + Frameworks/Flutter.framework/Headers/FlutterBinaryMessenger.h + + hash2 + + EXDk4t+7qCpyQkar+q9WHqY9bcK8eyohCwGVtBJhMy8= + + + Frameworks/Flutter.framework/Headers/FlutterCallbackCache.h + + hash2 + + 0h9+vK5K+r8moTsiGBfs6+TM9Qog089afHAy3gbcwDU= + + + Frameworks/Flutter.framework/Headers/FlutterChannels.h + + hash2 + + kg195C3vZLiOn8KeFQUy7DoVuA9VZDpqoBLVn64uGaI= + + + Frameworks/Flutter.framework/Headers/FlutterCodecs.h + + hash2 + + ZyqlHYuZbpFevVeny9Wdl0rVFgS7szIyssSiCyaaeFM= + + + Frameworks/Flutter.framework/Headers/FlutterDartProject.h + + hash2 + + U8q/0Ibt9q4O2HMsCdUwITtJdTx8Ljhlx+0aY83fH6s= + + + Frameworks/Flutter.framework/Headers/FlutterEngine.h + + hash2 + + QwvtJ2TkMcRYqWJ9V4J3LToKMLVK1pOcJpQtnIdnA+s= + + + Frameworks/Flutter.framework/Headers/FlutterEngineGroup.h + + hash2 + + SqzvIxqBXEJ3U9LJ32hCEXsrH2P16gumQ+gQx6Pdlf4= + + + Frameworks/Flutter.framework/Headers/FlutterHeadlessDartRunner.h + + hash2 + + nmZjZpvFCXrygf4U9aPkNi8VcI7cL5AtA+CY5uUWIL0= + + + Frameworks/Flutter.framework/Headers/FlutterHourFormat.h + + hash2 + + Q4SLFSghL/5EFJPyLg7PNi9J/xpkVVfzro0VQiQHtrY= + + + Frameworks/Flutter.framework/Headers/FlutterMacros.h + + hash2 + + ebBVHSZcUnAbN4hRcYq3ttt6++z1Ybc8KVSYhVToD5k= + + + Frameworks/Flutter.framework/Headers/FlutterPlatformViews.h + + hash2 + + 0aU9uM6QcpzmZpuFYObj9dGlGEkTKowPMERJQQdF2P4= + + + Frameworks/Flutter.framework/Headers/FlutterPlugin.h + + hash2 + + QcjhOhk5cb1U7bmyQh9TnFm1M2Tgv82RSSbJ6OIdMr4= + + + Frameworks/Flutter.framework/Headers/FlutterPluginAppLifeCycleDelegate.h + + hash2 + + +PMn+5SDj2Vd6RU8CQIt/JYl3T+8Dhp7HImqAzocoNk= + + + Frameworks/Flutter.framework/Headers/FlutterSceneDelegate.h + + hash2 + + G9urZeE312ldazkeP/7sut0t2hA3lfcuxHRSuLmj+gY= + + + Frameworks/Flutter.framework/Headers/FlutterSceneLifeCycle.h + + hash2 + + nvPq1KiXUwgQ/TtOSqHisNHQPvnVpvtXi3L0zLchdyI= + + + Frameworks/Flutter.framework/Headers/FlutterTexture.h + + hash2 + + JcpN4a9sv6xynlD3Ri611N5y+HoupUWp2hyrIXB/I8Y= + + + Frameworks/Flutter.framework/Headers/FlutterViewController.h + + hash2 + + yEgZTlCNrK/A/QBjEwNGB6ffC+A9gorPvnNgSbYuQ7Y= + + + Frameworks/Flutter.framework/Info.plist + + hash2 + + hM9l0FjoZ+6i48VxG0iTgAZRNuDfHowAsUx+AnE90+U= + + + Frameworks/Flutter.framework/Modules/module.modulemap + + hash2 + + 0VjriRpZ7AZZaP/0mMAPMJPhi6LoMB4MhXzL5j24tGs= + + + Frameworks/Flutter.framework/PrivacyInfo.xcprivacy + + hash2 + + n5XX54YqS1a2btkmvW1iLSplRagn0ZhHJ4tDjVcdQhI= + + + Frameworks/Flutter.framework/_CodeSignature/CodeResources + + hash2 + + 6o+7tVcNwrHtgjX6KbRrdi/IZp46P9WMiosGhpNN7qE= + + + Frameworks/Flutter.framework/icudtl.dat + + hash2 + + wSU3Ai74GJkae/7UGnbY1q6WL/vA5lEax2Kl0IRef3w= + + + Frameworks/open_file_ios.framework/Info.plist + + hash2 + + gKJqkfBYvT7iNzawrHUJzngZxP1q6k3o+/xyoRUNAnk= + + + Frameworks/open_file_ios.framework/_CodeSignature/CodeResources + + hash2 + + 1TUMNw3cWfTzViibPFa18zuqhlY/fyn7oxjpvZE9pbQ= + + + Frameworks/open_file_ios.framework/open_file_ios + + hash2 + + 8LlCqtikikg/LVR9K+vQU60I81nYjQva2JTisaKmHwg= + + + Frameworks/path_provider_foundation.framework/Info.plist + + hash2 + + H2Z6dJZFSEomv1Z7zT4P9bEsosE+gDP0hDPg4XICB4s= + + + Frameworks/path_provider_foundation.framework/_CodeSignature/CodeResources + + hash2 + + ff39ok1f4MZkpFwk0zSVhFtb4NA9WiABX3KxEOY78/Q= + + + Frameworks/path_provider_foundation.framework/path_provider_foundation + + hash2 + + sUtMHNoGxx8fpwgcUdCHYBaQowD3lWR1rF+W5Vd4HdU= + + + Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist + + hash2 + + yitl00ny/gjEcOnTGu8fNpoBtU5yAvzkXiMhBFgXnS0= + + + Frameworks/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy + + hash2 + + bS2g2NkwIn1CjB2TY7CtbjoS4sm2jFzilxWKdBL8jDE= + + + Runner.debug.dylib + + hash2 + + erSShgWhQEry3In5ACPcEGlYryDtwuy1PoB7gg/brg0= + + + __preview.dylib + + hash2 + + 0FmX/8Szq5TLKtggtttVsABFyKdBoHa+Rwa1BcGome8= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/__preview.dylib b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/__preview.dylib new file mode 100755 index 000000000..b44eb2615 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.app/__preview.dylib differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 000000000..50483dcc4 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.abi.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.abi.json new file mode 100644 index 000000000..d2f988e4e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.abi.json @@ -0,0 +1,9 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "NO_MODULE", + "printedName": "NO_MODULE", + "json_format_version": 8 + }, + "ConstValues": [] +} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.swiftdoc new file mode 100644 index 000000000..ae51f3452 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.swiftdoc differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.swiftmodule b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.swiftmodule new file mode 100644 index 000000000..7356a0830 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/Runner.swiftmodule/arm64-apple-ios-simulator.swiftmodule differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Headers/OpenFilePlugin.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Headers/OpenFilePlugin.h new file mode 100644 index 000000000..0c4461661 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Headers/OpenFilePlugin.h @@ -0,0 +1,6 @@ +#import + +@interface OpenFilePlugin : NSObject +@end +@interface UIDocumentInteractionControllerDelegate +@end diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Headers/open_file_ios-umbrella.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Headers/open_file_ios-umbrella.h new file mode 100644 index 000000000..65faf8796 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Headers/open_file_ios-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "OpenFilePlugin.h" + +FOUNDATION_EXPORT double open_file_iosVersionNumber; +FOUNDATION_EXPORT const unsigned char open_file_iosVersionString[]; + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Info.plist new file mode 100644 index 000000000..b95c6f364 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Modules/module.modulemap b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Modules/module.modulemap new file mode 100644 index 000000000..3b6461a40 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module open_file_ios { + umbrella header "open_file_ios-umbrella.h" + + export * + module * { export * } +} diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..4d677e75d --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/_CodeSignature/CodeResources @@ -0,0 +1,135 @@ + + + + + files + + Headers/OpenFilePlugin.h + + 18Qg2Sl04xpTsvNQ08CqwWu87WQ= + + Headers/open_file_ios-umbrella.h + + jpi33x/e6TqxsLobMgXnKSs6z5I= + + Info.plist + + t2lS3OfCvnlqSDlmDNh7Opo1yN4= + + Modules/module.modulemap + + 3X/QEi5jYjU4+Qyf+wzyDJYSL2A= + + + files2 + + Headers/OpenFilePlugin.h + + hash2 + + T2owQkjDsVyzaSxa3cSIrUQS+vwJK98xO+vpyKdWGAo= + + + Headers/open_file_ios-umbrella.h + + hash2 + + 8jAAsPE39oG9WM2cgDEdjU56KVP+P7wP09z/JV9HUQ8= + + + Modules/module.modulemap + + hash2 + + 7MQ5LBRq7ZCKJGt5Zzfc3Q5kWE1yu2pWinMtpmijEg4= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/open_file_ios b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/open_file_ios new file mode 100755 index 000000000..4ea4bc892 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/open_file_ios/open_file_ios.framework/open_file_ios differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Headers/path_provider_foundation-Swift.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Headers/path_provider_foundation-Swift.h new file mode 100644 index 000000000..287453716 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Headers/path_provider_foundation-Swift.h @@ -0,0 +1,648 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 6.2.1 effective-5.10 (swiftlang-6.2.1.4.8 clang-1700.4.4.1) +#ifndef PATH_PROVIDER_FOUNDATION_SWIFT_H +#define PATH_PROVIDER_FOUNDATION_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-modular-include-in-framework-module" +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#pragma clang diagnostic pop +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef unsigned char char8_t; +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +@import Flutter; +@import ObjectiveC; +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="path_provider_foundation",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +@protocol FlutterPluginRegistrar; +SWIFT_CLASS("_TtC24path_provider_foundation18PathProviderPlugin") +@interface PathProviderPlugin : NSObject ++ (void)registerWithRegistrar:(id _Nonnull)registrar; +- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; +@end + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#elif defined(__x86_64__) && __x86_64__ +// Generated by Apple Swift version 6.2.1 effective-5.10 (swiftlang-6.2.1.4.8 clang-1700.4.4.1) +#ifndef PATH_PROVIDER_FOUNDATION_SWIFT_H +#define PATH_PROVIDER_FOUNDATION_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-modular-include-in-framework-module" +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#pragma clang diagnostic pop +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef unsigned char char8_t; +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +@import Flutter; +@import ObjectiveC; +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" +#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="path_provider_foundation",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +@protocol FlutterPluginRegistrar; +SWIFT_CLASS("_TtC24path_provider_foundation18PathProviderPlugin") +@interface PathProviderPlugin : NSObject ++ (void)registerWithRegistrar:(id _Nonnull)registrar; +- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; +@end + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Headers/path_provider_foundation-umbrella.h b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Headers/path_provider_foundation-umbrella.h new file mode 100644 index 000000000..f62757e63 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Headers/path_provider_foundation-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double path_provider_foundationVersionNumber; +FOUNDATION_EXPORT const unsigned char path_provider_foundationVersionString[]; + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Info.plist new file mode 100644 index 000000000..3da0d7a47 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/module.modulemap b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/module.modulemap new file mode 100644 index 000000000..c32e75708 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/module.modulemap @@ -0,0 +1,11 @@ +framework module path_provider_foundation { + umbrella header "path_provider_foundation-umbrella.h" + + export * + module * { export * } +} + +module path_provider_foundation.Swift { + header "path_provider_foundation-Swift.h" + requires objc +} diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 000000000..837b28846 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 000000000..3c657410b Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.abi.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.abi.json new file mode 100644 index 000000000..d2f988e4e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.abi.json @@ -0,0 +1,9 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "NO_MODULE", + "printedName": "NO_MODULE", + "json_format_version": 8 + }, + "ConstValues": [] +} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftdoc new file mode 100644 index 000000000..4f5882e8b Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftdoc differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftmodule b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftmodule new file mode 100644 index 000000000..cdbccbc3b Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftmodule differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.abi.json b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.abi.json new file mode 100644 index 000000000..d2f988e4e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.abi.json @@ -0,0 +1,9 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "NO_MODULE", + "printedName": "NO_MODULE", + "json_format_version": 8 + }, + "ConstValues": [] +} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftdoc b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftdoc new file mode 100644 index 000000000..a7dd1d130 Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftdoc differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftmodule b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftmodule new file mode 100644 index 000000000..00b90879c Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftmodule differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/_CodeSignature/CodeResources b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/_CodeSignature/CodeResources new file mode 100644 index 000000000..f28fa292b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/_CodeSignature/CodeResources @@ -0,0 +1,245 @@ + + + + + files + + Headers/path_provider_foundation-Swift.h + + CPBR+EFi2RTfGqrWP8DujnSSpnk= + + Headers/path_provider_foundation-umbrella.h + + HLPUH7a1+Uud1CEb8ZVbUJlVow0= + + Info.plist + + 9tFT9ECNecWz1iEt2bkPXiS0OsU= + + Modules/module.modulemap + + 4ou7sfZJMUritXkWYrNLe8ROvJ8= + + Modules/path_provider_foundation.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo + + wR/ppVZ3JzScA0gsLm5j/FySSnY= + + Modules/path_provider_foundation.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo + + y4u5Wj8RI2t4BH12jDmyKI3JEHw= + + Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.abi.json + + gcwBsH4BgyFY4sVtNt+/xOKS3vY= + + Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftdoc + + wSS64VJJ+SJuj9VF93oOGw6jD/4= + + Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftmodule + + qW80DaRnPCM782RB3pTC39oNBWA= + + Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.abi.json + + gcwBsH4BgyFY4sVtNt+/xOKS3vY= + + Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftdoc + + VA8vfjCYULSzmoM0fK3TQmgGtrk= + + Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftmodule + + osYdqt2CHjJypyYftBnctQHpND8= + + path_provider_foundation_privacy.bundle/Info.plist + + uZhDvLtUFGGxUo04IxQgK3UPBUU= + + path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy + + /LX0ZlwxwIAIhjZaDB8EiH5KpXA= + + + files2 + + Headers/path_provider_foundation-Swift.h + + hash2 + + G4VGHbOmAXYFmWTMpOgZt0ewe/Og7WbkR1fq+JfmzJo= + + + Headers/path_provider_foundation-umbrella.h + + hash2 + + zQc9a/y7t7MqxTgSSmpfImDb6DSiKF26gJFqk0CuTBE= + + + Modules/module.modulemap + + hash2 + + GljPXu0mFl3W6UpwpsufQgltdn4I8vCubbMMs3ACbiw= + + + Modules/path_provider_foundation.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo + + hash2 + + dGekGUN6RdKle9wt1li8Fbwsn3ftaFYFAdDV1eV2AiQ= + + + Modules/path_provider_foundation.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo + + hash2 + + oESFWcfeszedEfitF3cUYuAngo704uhaM3oyAYVskIQ= + + + Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.abi.json + + hash2 + + Qnesa0n4URGWAopawg9bGx36dUwkYV00BoCJ8LFzlyg= + + + Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftdoc + + hash2 + + Gy0SxqU5EfrgfurN0aVicW/JlHk6KGppC3FBrjrG85s= + + + Modules/path_provider_foundation.swiftmodule/arm64-apple-ios-simulator.swiftmodule + + hash2 + + BORqp6eM9fKhZd+32kDpC8xdqn5a8OFQkn1/SHU5gcs= + + + Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.abi.json + + hash2 + + Qnesa0n4URGWAopawg9bGx36dUwkYV00BoCJ8LFzlyg= + + + Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftdoc + + hash2 + + UKKaj4NxlJOOWQF6A/hdsrJua/BBb9aSBOPKlBI4qq0= + + + Modules/path_provider_foundation.swiftmodule/x86_64-apple-ios-simulator.swiftmodule + + hash2 + + E7CkpL0VISWf2En/oIHkujW+x4HAEMpH16AVff95uXI= + + + path_provider_foundation_privacy.bundle/Info.plist + + hash2 + + yitl00ny/gjEcOnTGu8fNpoBtU5yAvzkXiMhBFgXnS0= + + + path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy + + hash2 + + bS2g2NkwIn1CjB2TY7CtbjoS4sm2jFzilxWKdBL8jDE= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation new file mode 100755 index 000000000..4aedf431f Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist new file mode 100644 index 000000000..529e057cd Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..a34b7e2e6 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation.framework/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation_privacy.bundle/Info.plist b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation_privacy.bundle/Info.plist new file mode 100644 index 000000000..529e057cd Binary files /dev/null and b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation_privacy.bundle/Info.plist differ diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy new file mode 100644 index 000000000..a34b7e2e6 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/Debug-iphonesimulator/path_provider_foundation/path_provider_foundation_privacy.bundle/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/packages/syncfusion_flutter_pdf/example/build/ios/pod_inputs.fingerprint b/packages/syncfusion_flutter_pdf/example/build/ios/pod_inputs.fingerprint new file mode 100644 index 000000000..df26e6b18 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/build/ios/pod_inputs.fingerprint @@ -0,0 +1 @@ +{"files":{"/Users/mac/Desktop/sample_pdf_translator/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.pbxproj":"57028017ec4ca1a7a26d57ecef7f16d6","/Users/mac/Desktop/sample_pdf_translator/syncfusion_flutter_pdf/example/ios/Podfile":"4b6e6a073385fbc5cf2f2c70abc34cda","/Users/mac/Desktop/sample_pdf_translator/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift":"ebc5087efcda2981863b17201f880725","/Users/mac/development/flutter/packages/flutter_tools/bin/podhelper.rb":"5a1ae3d5c945ab350e5c59aaf8b45c66"}} \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/ios/.gitignore b/packages/syncfusion_flutter_pdf/example/ios/.gitignore deleted file mode 100644 index 7a7f9873a..000000000 --- a/packages/syncfusion_flutter_pdf/example/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/AppFrameworkInfo.plist b/packages/syncfusion_flutter_pdf/example/ios/Flutter/AppFrameworkInfo.plist index 7c5696400..1dc6cf765 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Flutter/AppFrameworkInfo.plist +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 12.0 + 13.0 diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/Debug.xcconfig b/packages/syncfusion_flutter_pdf/example/ios/Flutter/Debug.xcconfig index ec97fc6f3..553cface1 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Flutter/Debug.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "Generated.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/Flutter.podspec b/packages/syncfusion_flutter_pdf/example/ios/Flutter/Flutter.podspec new file mode 100644 index 000000000..3aed58d35 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/Flutter.podspec @@ -0,0 +1,18 @@ +# +# This podspec is NOT to be published. It is only used as a local source! +# This is a generated file; do not edit or check into version control. +# + +Pod::Spec.new do |s| + s.name = 'Flutter' + s.version = '1.0.0' + s.summary = 'A UI toolkit for beautiful and fast apps.' + s.homepage = 'https://flutter.dev' + s.license = { :type => 'BSD' } + s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } + s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } + s.ios.deployment_target = '13.0' + # Framework linking is handled by Flutter tooling, not CocoaPods. + # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs. + s.vendored_frameworks = 'path/to/nothing' +end diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/Release.xcconfig b/packages/syncfusion_flutter_pdf/example/ios/Flutter/Release.xcconfig index c4855bfe2..4b6e1f664 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Flutter/Release.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "Generated.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift new file mode 100644 index 000000000..63cc62e3e --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift @@ -0,0 +1,25 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. +// +// Generated file. Do not edit. +// + +import PackageDescription + +let package = Package( + name: "FlutterGeneratedPluginSwiftPackage", + platforms: [ + .iOS("13.0") + ], + products: [ + .library(name: "FlutterGeneratedPluginSwiftPackage", type: .static, targets: ["FlutterGeneratedPluginSwiftPackage"]) + ], + dependencies: [ + + ], + targets: [ + .target( + name: "FlutterGeneratedPluginSwiftPackage" + ) + ] +) diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift new file mode 100644 index 000000000..62e7b11aa --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift @@ -0,0 +1,3 @@ +// +// Generated file. Do not edit. +// diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/flutter_lldb_helper.py b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 000000000..a88caf99d --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/flutter_lldbinit b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 000000000..e3ba6fbed --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/packages/syncfusion_flutter_pdf/example/ios/Podfile b/packages/syncfusion_flutter_pdf/example/ios/Podfile new file mode 100644 index 000000000..620e46eba --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/ios/Podfile @@ -0,0 +1,43 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '13.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/packages/syncfusion_flutter_pdf/example/ios/Podfile.lock b/packages/syncfusion_flutter_pdf/example/ios/Podfile.lock new file mode 100644 index 000000000..ca2f2588d --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/ios/Podfile.lock @@ -0,0 +1,29 @@ +PODS: + - Flutter (1.0.0) + - open_file_ios (0.0.1): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - Flutter (from `Flutter`) + - open_file_ios (from `.symlinks/plugins/open_file_ios/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + open_file_ios: + :path: ".symlinks/plugins/open_file_ios/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + +SPEC CHECKSUMS: + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 + open_file_ios: 5ff7526df64e4394b4fe207636b67a95e83078bb + path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 + +PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e + +COCOAPODS: 1.16.2 diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.pbxproj b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.pbxproj index b8112bec9..2c66d5e2c 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.pbxproj @@ -463,7 +463,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -593,7 +593,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -644,7 +644,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 919434a62..c4b79bd8c 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -1,7 +1,7 @@ - - - - - + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d981003..fc6bf8074 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index f9b0d7c5e..af0309c4d 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -1,8 +1,8 @@ - - - - - PreviewsEnabled - - - + + + + + PreviewsEnabled + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index d795332e1..ffc3ed253 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,117 +1,119 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - - - + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" + launchStyle = "0" + useCustomWorkingDirectory = "NO" + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + debugServiceExtension = "internal" + enableGPUValidationMode = "1" + allowLocationSimulation = "YES"> + + + + + + + + + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 21a3cc14c..17ccc03e6 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -1,10 +1,10 @@ - - - - - - - + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d981003..fc6bf8074 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index f9b0d7c5e..af0309c4d 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -1,8 +1,8 @@ - - - - - PreviewsEnabled - - - + + + + + PreviewsEnabled + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/AppDelegate.swift b/packages/syncfusion_flutter_pdf/example/ios/Runner/AppDelegate.swift index 626664468..8be1cecd1 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/AppDelegate.swift +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/AppDelegate.swift @@ -1,13 +1,13 @@ -import Flutter -import UIKit - -@main -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fab2..1950fd80e 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1,122 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json index 0bedcf2fd..d08a4de32 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -1,23 +1,23 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md index 89c2725b7..65a94b5db 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -1,5 +1,5 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/LaunchScreen.storyboard index f2e259c7c..497371ea2 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/Main.storyboard b/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/Main.storyboard index f3c28516f..bbb83caae 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/Main.storyboard +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/Base.lproj/Main.storyboard @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Info.plist b/packages/syncfusion_flutter_pdf/example/ios/Runner/Info.plist index 0cc49ee18..cf87f1c64 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Info.plist +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/Info.plist @@ -1,49 +1,49 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Pdf Example - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - pdf_example - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - - + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Pdf Example + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + pdf_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/packages/syncfusion_flutter_pdf/example/ios/Runner/Runner-Bridging-Header.h b/packages/syncfusion_flutter_pdf/example/ios/Runner/Runner-Bridging-Header.h index 308a2a560..fae207f9e 100644 --- a/packages/syncfusion_flutter_pdf/example/ios/Runner/Runner-Bridging-Header.h +++ b/packages/syncfusion_flutter_pdf/example/ios/Runner/Runner-Bridging-Header.h @@ -1 +1 @@ -#import "GeneratedPluginRegistrant.h" +#import "GeneratedPluginRegistrant.h" diff --git a/packages/syncfusion_flutter_pdf/example/lib/main.dart b/packages/syncfusion_flutter_pdf/example/lib/main.dart index 09dcdf665..67168813f 100644 --- a/packages/syncfusion_flutter_pdf/example/lib/main.dart +++ b/packages/syncfusion_flutter_pdf/example/lib/main.dart @@ -1,311 +1,311 @@ -import 'package:flutter/material.dart'; -// ignore: depend_on_referenced_packages -import 'package:intl/intl.dart'; -import 'package:syncfusion_flutter_pdf/pdf.dart'; - -//Local imports -import 'save_file_mobile.dart' if (dart.library.html) 'save_file_web.dart'; - -void main() { - runApp(const CreatePdfWidget()); -} - -/// Represents the PDF widget class. -class CreatePdfWidget extends StatelessWidget { - const CreatePdfWidget({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp(home: CreatePdfStatefulWidget()); - } -} - -/// Represents the PDF stateful widget class. -class CreatePdfStatefulWidget extends StatefulWidget { - /// Initalize the instance of the [CreatePdfStatefulWidget] class. - const CreatePdfStatefulWidget({Key? key}) : super(key: key); - - @override - _CreatePdfState createState() => _CreatePdfState(); -} - -class _CreatePdfState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: const Text('Create PDF document')), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextButton( - style: TextButton.styleFrom( - foregroundColor: Colors.white, - backgroundColor: Colors.lightBlue, - disabledForegroundColor: Colors.grey, - ), - onPressed: generateInvoice, - child: const Text('Generate PDF'), - ), - ], - ), - ), - ); - } - - Future generateInvoice() async { - //Create a PDF document. - final PdfDocument document = PdfDocument(); - //Add page to the PDF - final PdfPage page = document.pages.add(); - //Get page client size - final Size pageSize = page.getClientSize(); - //Draw rectangle - page.graphics.drawRectangle( - bounds: Rect.fromLTWH(0, 0, pageSize.width, pageSize.height), - pen: PdfPen(PdfColor(142, 170, 219)), - ); - //Generate PDF grid. - final PdfGrid grid = getGrid(); - //Draw the header section by creating text element - final PdfLayoutResult result = drawHeader(page, pageSize, grid); - //Draw grid - drawGrid(page, grid, result); - //Add invoice footer - drawFooter(page, pageSize); - //Save the PDF document - final List bytes = document.saveSync(); - //Dispose the document. - document.dispose(); - //Save and launch the file. - await saveAndLaunchFile(bytes, 'Invoice.pdf'); - } - - //Draws the invoice header - PdfLayoutResult drawHeader(PdfPage page, Size pageSize, PdfGrid grid) { - //Draw rectangle - page.graphics.drawRectangle( - brush: PdfSolidBrush(PdfColor(91, 126, 215)), - bounds: Rect.fromLTWH(0, 0, pageSize.width - 115, 90), - ); - //Draw string - page.graphics.drawString( - 'INVOICE', - PdfStandardFont(PdfFontFamily.helvetica, 30), - brush: PdfBrushes.white, - bounds: Rect.fromLTWH(25, 0, pageSize.width - 115, 90), - format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), - ); - - page.graphics.drawRectangle( - bounds: Rect.fromLTWH(400, 0, pageSize.width - 400, 90), - brush: PdfSolidBrush(PdfColor(65, 104, 205)), - ); - - page.graphics.drawString( - r'$' + getTotalAmount(grid).toString(), - PdfStandardFont(PdfFontFamily.helvetica, 18), - bounds: Rect.fromLTWH(400, 0, pageSize.width - 400, 100), - brush: PdfBrushes.white, - format: PdfStringFormat( - alignment: PdfTextAlignment.center, - lineAlignment: PdfVerticalAlignment.middle, - ), - ); - - final PdfFont contentFont = PdfStandardFont(PdfFontFamily.helvetica, 9); - //Draw string - page.graphics.drawString( - 'Amount', - contentFont, - brush: PdfBrushes.white, - bounds: Rect.fromLTWH(400, 0, pageSize.width - 400, 33), - format: PdfStringFormat( - alignment: PdfTextAlignment.center, - lineAlignment: PdfVerticalAlignment.bottom, - ), - ); - //Create data foramt and convert it to text. - final DateFormat format = DateFormat.yMMMMd('en_US'); - final String invoiceNumber = - 'Invoice Number: 2058557939\r\n\r\nDate: ${format.format(DateTime.now())}'; - final Size contentSize = contentFont.measureString(invoiceNumber); - // ignore: leading_newlines_in_multiline_strings - const String address = '''Bill To: \r\n\r\nAbraham Swearegin, - \r\n\r\nUnited States, California, San Mateo, - \r\n\r\n9920 BridgePointe Parkway, \r\n\r\n9365550136'''; - - PdfTextElement(text: invoiceNumber, font: contentFont).draw( - page: page, - bounds: Rect.fromLTWH( - pageSize.width - (contentSize.width + 30), - 120, - contentSize.width + 30, - pageSize.height - 120, - ), - ); - - return PdfTextElement(text: address, font: contentFont).draw( - page: page, - bounds: Rect.fromLTWH( - 30, - 120, - pageSize.width - (contentSize.width + 30), - pageSize.height - 120, - ), - )!; - } - - //Draws the grid - void drawGrid(PdfPage page, PdfGrid grid, PdfLayoutResult result) { - Rect? totalPriceCellBounds; - Rect? quantityCellBounds; - //Invoke the beginCellLayout event. - grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - final PdfGrid grid = sender as PdfGrid; - if (args.cellIndex == grid.columns.count - 1) { - totalPriceCellBounds = args.bounds; - } else if (args.cellIndex == grid.columns.count - 2) { - quantityCellBounds = args.bounds; - } - }; - //Draw the PDF grid and get the result. - result = - grid.draw( - page: page, - bounds: Rect.fromLTWH(0, result.bounds.bottom + 40, 0, 0), - )!; - - //Draw grand total. - page.graphics.drawString( - 'Grand Total', - PdfStandardFont(PdfFontFamily.helvetica, 9, style: PdfFontStyle.bold), - bounds: Rect.fromLTWH( - quantityCellBounds!.left, - result.bounds.bottom + 10, - quantityCellBounds!.width, - quantityCellBounds!.height, - ), - ); - page.graphics.drawString( - getTotalAmount(grid).toString(), - PdfStandardFont(PdfFontFamily.helvetica, 9, style: PdfFontStyle.bold), - bounds: Rect.fromLTWH( - totalPriceCellBounds!.left, - result.bounds.bottom + 10, - totalPriceCellBounds!.width, - totalPriceCellBounds!.height, - ), - ); - } - - //Draw the invoice footer data. - void drawFooter(PdfPage page, Size pageSize) { - final PdfPen linePen = PdfPen( - PdfColor(142, 170, 219), - dashStyle: PdfDashStyle.custom, - ); - linePen.dashPattern = [3, 3]; - //Draw line - page.graphics.drawLine( - linePen, - Offset(0, pageSize.height - 100), - Offset(pageSize.width, pageSize.height - 100), - ); - - const String footerContent = - // ignore: leading_newlines_in_multiline_strings - '''800 Interchange Blvd.\r\n\r\nSuite 2501, Austin, - TX 78721\r\n\r\nAny Questions? support@adventure-works.com'''; - - //Added 30 as a margin for the layout - page.graphics.drawString( - footerContent, - PdfStandardFont(PdfFontFamily.helvetica, 9), - format: PdfStringFormat(alignment: PdfTextAlignment.right), - bounds: Rect.fromLTWH(pageSize.width - 30, pageSize.height - 70, 0, 0), - ); - } - - //Create PDF grid and return - PdfGrid getGrid() { - //Create a PDF grid - final PdfGrid grid = PdfGrid(); - //Secify the columns count to the grid. - grid.columns.add(count: 5); - //Create the header row of the grid. - final PdfGridRow headerRow = grid.headers.add(1)[0]; - //Set style - headerRow.style.backgroundBrush = PdfSolidBrush(PdfColor(68, 114, 196)); - headerRow.style.textBrush = PdfBrushes.white; - headerRow.cells[0].value = 'Product Id'; - headerRow.cells[0].stringFormat.alignment = PdfTextAlignment.center; - headerRow.cells[1].value = 'Product Name'; - headerRow.cells[2].value = 'Price'; - headerRow.cells[3].value = 'Quantity'; - headerRow.cells[4].value = 'Total'; - //Add rows - addProducts('CA-1098', 'AWC Logo Cap', 8.99, 2, 17.98, grid); - addProducts('LJ-0192', 'Long-Sleeve Logo Jersey,M', 49.99, 3, 149.97, grid); - addProducts('So-B909-M', 'Mountain Bike Socks,M', 9.5, 2, 19, grid); - addProducts('LJ-0192', 'Long-Sleeve Logo Jersey,M', 49.99, 4, 199.96, grid); - addProducts('FK-5136', 'ML Fork', 175.49, 6, 1052.94, grid); - addProducts('HL-U509', 'Sports-100 Helmet,Black', 34.99, 1, 34.99, grid); - //Apply the table built-in style - grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable4Accent5); - //Set gird columns width - grid.columns[1].width = 200; - for (int i = 0; i < headerRow.cells.count; i++) { - headerRow.cells[i].style.cellPadding = PdfPaddings( - bottom: 5, - left: 5, - right: 5, - top: 5, - ); - } - for (int i = 0; i < grid.rows.count; i++) { - final PdfGridRow row = grid.rows[i]; - for (int j = 0; j < row.cells.count; j++) { - final PdfGridCell cell = row.cells[j]; - if (j == 0) { - cell.stringFormat.alignment = PdfTextAlignment.center; - } - cell.style.cellPadding = PdfPaddings( - bottom: 5, - left: 5, - right: 5, - top: 5, - ); - } - } - return grid; - } - - //Create and row for the grid. - void addProducts( - String productId, - String productName, - double price, - int quantity, - double total, - PdfGrid grid, - ) { - final PdfGridRow row = grid.rows.add(); - row.cells[0].value = productId; - row.cells[1].value = productName; - row.cells[2].value = price.toString(); - row.cells[3].value = quantity.toString(); - row.cells[4].value = total.toString(); - } - - //Get the total amount. - double getTotalAmount(PdfGrid grid) { - double total = 0; - for (int i = 0; i < grid.rows.count; i++) { - final String value = - grid.rows[i].cells[grid.columns.count - 1].value as String; - total += double.parse(value); - } - return total; - } -} +import 'package:flutter/material.dart'; +// ignore: depend_on_referenced_packages +import 'package:intl/intl.dart'; +import 'package:syncfusion_flutter_pdf/pdf.dart'; + +//Local imports +import 'save_file_mobile.dart' if (dart.library.html) 'save_file_web.dart'; + +void main() { + runApp(const CreatePdfWidget()); +} + +/// Represents the PDF widget class. +class CreatePdfWidget extends StatelessWidget { + const CreatePdfWidget({super.key}); + + @override + Widget build(BuildContext context) { + return const MaterialApp(home: CreatePdfStatefulWidget()); + } +} + +/// Represents the PDF stateful widget class. +class CreatePdfStatefulWidget extends StatefulWidget { + /// Initalize the instance of the [CreatePdfStatefulWidget] class. + const CreatePdfStatefulWidget({Key? key}) : super(key: key); + + @override + _CreatePdfState createState() => _CreatePdfState(); +} + +class _CreatePdfState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Create PDF document')), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + TextButton( + style: TextButton.styleFrom( + foregroundColor: Colors.white, + backgroundColor: Colors.lightBlue, + disabledForegroundColor: Colors.grey, + ), + onPressed: generateInvoice, + child: const Text('Generate PDF'), + ), + ], + ), + ), + ); + } + + Future generateInvoice() async { + //Create a PDF document. + final PdfDocument document = PdfDocument(); + //Add page to the PDF + final PdfPage page = document.pages.add(); + //Get page client size + final Size pageSize = page.getClientSize(); + //Draw rectangle + page.graphics.drawRectangle( + bounds: Rect.fromLTWH(0, 0, pageSize.width, pageSize.height), + pen: PdfPen(PdfColor(142, 170, 219)), + ); + //Generate PDF grid. + final PdfGrid grid = getGrid(); + //Draw the header section by creating text element + final PdfLayoutResult result = drawHeader(page, pageSize, grid); + //Draw grid + drawGrid(page, grid, result); + //Add invoice footer + drawFooter(page, pageSize); + //Save the PDF document + final List bytes = document.saveSync(); + //Dispose the document. + document.dispose(); + //Save and launch the file. + await saveAndLaunchFile(bytes, 'Invoice.pdf'); + } + + //Draws the invoice header + PdfLayoutResult drawHeader(PdfPage page, Size pageSize, PdfGrid grid) { + //Draw rectangle + page.graphics.drawRectangle( + brush: PdfSolidBrush(PdfColor(91, 126, 215)), + bounds: Rect.fromLTWH(0, 0, pageSize.width - 115, 90), + ); + //Draw string + page.graphics.drawString( + 'INVOICE', + PdfStandardFont(PdfFontFamily.helvetica, 30), + brush: PdfBrushes.white, + bounds: Rect.fromLTWH(25, 0, pageSize.width - 115, 90), + format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), + ); + + page.graphics.drawRectangle( + bounds: Rect.fromLTWH(400, 0, pageSize.width - 400, 90), + brush: PdfSolidBrush(PdfColor(65, 104, 205)), + ); + + page.graphics.drawString( + r'$' + getTotalAmount(grid).toString(), + PdfStandardFont(PdfFontFamily.helvetica, 18), + bounds: Rect.fromLTWH(400, 0, pageSize.width - 400, 100), + brush: PdfBrushes.white, + format: PdfStringFormat( + alignment: PdfTextAlignment.center, + lineAlignment: PdfVerticalAlignment.middle, + ), + ); + + final PdfFont contentFont = PdfStandardFont(PdfFontFamily.helvetica, 9); + //Draw string + page.graphics.drawString( + 'Amount', + contentFont, + brush: PdfBrushes.white, + bounds: Rect.fromLTWH(400, 0, pageSize.width - 400, 33), + format: PdfStringFormat( + alignment: PdfTextAlignment.center, + lineAlignment: PdfVerticalAlignment.bottom, + ), + ); + //Create data foramt and convert it to text. + final DateFormat format = DateFormat.yMMMMd('en_US'); + final String invoiceNumber = + 'Invoice Number: 2058557939\r\n\r\nDate: ${format.format(DateTime.now())}'; + final Size contentSize = contentFont.measureString(invoiceNumber); + // ignore: leading_newlines_in_multiline_strings + const String address = '''Bill To: \r\n\r\nAbraham Swearegin, + \r\n\r\nUnited States, California, San Mateo, + \r\n\r\n9920 BridgePointe Parkway, \r\n\r\n9365550136'''; + + PdfTextElement(text: invoiceNumber, font: contentFont).draw( + page: page, + bounds: Rect.fromLTWH( + pageSize.width - (contentSize.width + 30), + 120, + contentSize.width + 30, + pageSize.height - 120, + ), + ); + + return PdfTextElement(text: address, font: contentFont).draw( + page: page, + bounds: Rect.fromLTWH( + 30, + 120, + pageSize.width - (contentSize.width + 30), + pageSize.height - 120, + ), + )!; + } + + //Draws the grid + void drawGrid(PdfPage page, PdfGrid grid, PdfLayoutResult result) { + Rect? totalPriceCellBounds; + Rect? quantityCellBounds; + //Invoke the beginCellLayout event. + grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + final PdfGrid grid = sender as PdfGrid; + if (args.cellIndex == grid.columns.count - 1) { + totalPriceCellBounds = args.bounds; + } else if (args.cellIndex == grid.columns.count - 2) { + quantityCellBounds = args.bounds; + } + }; + //Draw the PDF grid and get the result. + result = + grid.draw( + page: page, + bounds: Rect.fromLTWH(0, result.bounds.bottom + 40, 0, 0), + )!; + + //Draw grand total. + page.graphics.drawString( + 'Grand Total', + PdfStandardFont(PdfFontFamily.helvetica, 9, style: PdfFontStyle.bold), + bounds: Rect.fromLTWH( + quantityCellBounds!.left, + result.bounds.bottom + 10, + quantityCellBounds!.width, + quantityCellBounds!.height, + ), + ); + page.graphics.drawString( + getTotalAmount(grid).toString(), + PdfStandardFont(PdfFontFamily.helvetica, 9, style: PdfFontStyle.bold), + bounds: Rect.fromLTWH( + totalPriceCellBounds!.left, + result.bounds.bottom + 10, + totalPriceCellBounds!.width, + totalPriceCellBounds!.height, + ), + ); + } + + //Draw the invoice footer data. + void drawFooter(PdfPage page, Size pageSize) { + final PdfPen linePen = PdfPen( + PdfColor(142, 170, 219), + dashStyle: PdfDashStyle.custom, + ); + linePen.dashPattern = [3, 3]; + //Draw line + page.graphics.drawLine( + linePen, + Offset(0, pageSize.height - 100), + Offset(pageSize.width, pageSize.height - 100), + ); + + const String footerContent = + // ignore: leading_newlines_in_multiline_strings + '''800 Interchange Blvd.\r\n\r\nSuite 2501, Austin, + TX 78721\r\n\r\nAny Questions? support@adventure-works.com'''; + + //Added 30 as a margin for the layout + page.graphics.drawString( + footerContent, + PdfStandardFont(PdfFontFamily.helvetica, 9), + format: PdfStringFormat(alignment: PdfTextAlignment.right), + bounds: Rect.fromLTWH(pageSize.width - 30, pageSize.height - 70, 0, 0), + ); + } + + //Create PDF grid and return + PdfGrid getGrid() { + //Create a PDF grid + final PdfGrid grid = PdfGrid(); + //Secify the columns count to the grid. + grid.columns.add(count: 5); + //Create the header row of the grid. + final PdfGridRow headerRow = grid.headers.add(1)[0]; + //Set style + headerRow.style.backgroundBrush = PdfSolidBrush(PdfColor(68, 114, 196)); + headerRow.style.textBrush = PdfBrushes.white; + headerRow.cells[0].value = 'Product Id'; + headerRow.cells[0].stringFormat.alignment = PdfTextAlignment.center; + headerRow.cells[1].value = 'Product Name'; + headerRow.cells[2].value = 'Price'; + headerRow.cells[3].value = 'Quantity'; + headerRow.cells[4].value = 'Total'; + //Add rows + addProducts('CA-1098', 'AWC Logo Cap', 8.99, 2, 17.98, grid); + addProducts('LJ-0192', 'Long-Sleeve Logo Jersey,M', 49.99, 3, 149.97, grid); + addProducts('So-B909-M', 'Mountain Bike Socks,M', 9.5, 2, 19, grid); + addProducts('LJ-0192', 'Long-Sleeve Logo Jersey,M', 49.99, 4, 199.96, grid); + addProducts('FK-5136', 'ML Fork', 175.49, 6, 1052.94, grid); + addProducts('HL-U509', 'Sports-100 Helmet,Black', 34.99, 1, 34.99, grid); + //Apply the table built-in style + grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable4Accent5); + //Set gird columns width + grid.columns[1].width = 200; + for (int i = 0; i < headerRow.cells.count; i++) { + headerRow.cells[i].style.cellPadding = PdfPaddings( + bottom: 5, + left: 5, + right: 5, + top: 5, + ); + } + for (int i = 0; i < grid.rows.count; i++) { + final PdfGridRow row = grid.rows[i]; + for (int j = 0; j < row.cells.count; j++) { + final PdfGridCell cell = row.cells[j]; + if (j == 0) { + cell.stringFormat.alignment = PdfTextAlignment.center; + } + cell.style.cellPadding = PdfPaddings( + bottom: 5, + left: 5, + right: 5, + top: 5, + ); + } + } + return grid; + } + + //Create and row for the grid. + void addProducts( + String productId, + String productName, + double price, + int quantity, + double total, + PdfGrid grid, + ) { + final PdfGridRow row = grid.rows.add(); + row.cells[0].value = productId; + row.cells[1].value = productName; + row.cells[2].value = price.toString(); + row.cells[3].value = quantity.toString(); + row.cells[4].value = total.toString(); + } + + //Get the total amount. + double getTotalAmount(PdfGrid grid) { + double total = 0; + for (int i = 0; i < grid.rows.count; i++) { + final String value = + grid.rows[i].cells[grid.columns.count - 1].value as String; + total += double.parse(value); + } + return total; + } +} diff --git a/packages/syncfusion_flutter_pdf/example/lib/save_file_mobile.dart b/packages/syncfusion_flutter_pdf/example/lib/save_file_mobile.dart index eb186a86d..ee31fbadc 100644 --- a/packages/syncfusion_flutter_pdf/example/lib/save_file_mobile.dart +++ b/packages/syncfusion_flutter_pdf/example/lib/save_file_mobile.dart @@ -1,38 +1,38 @@ -import 'dart:io'; - -import 'package:open_file/open_file.dart' as open_file; -import 'package:path_provider/path_provider.dart' as path_provider; -// ignore: depend_on_referenced_packages -import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; - -///To save the pdf file in the device -Future saveAndLaunchFile(List bytes, String fileName) async { - //Get the storage folder location using path_provider package. - String? path; - if (Platform.isAndroid || - Platform.isIOS || - Platform.isLinux || - Platform.isWindows) { - final Directory directory = - await path_provider.getApplicationSupportDirectory(); - path = directory.path; - } else { - path = await PathProviderPlatform.instance.getApplicationSupportPath(); - } - final File file = File( - Platform.isWindows ? '$path\\$fileName' : '$path/$fileName', - ); - await file.writeAsBytes(bytes, flush: true); - if (Platform.isAndroid || Platform.isIOS) { - //Launch the file (used open_file package) - await open_file.OpenFile.open('$path/$fileName'); - } else if (Platform.isWindows) { - await Process.run('start', ['$path\\$fileName'], runInShell: true); - } else if (Platform.isMacOS) { - await Process.run('open', ['$path/$fileName'], runInShell: true); - } else if (Platform.isLinux) { - await Process.run('xdg-open', [ - '$path/$fileName', - ], runInShell: true); - } -} +import 'dart:io'; + +import 'package:open_file/open_file.dart' as open_file; +import 'package:path_provider/path_provider.dart' as path_provider; +// ignore: depend_on_referenced_packages +import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; + +///To save the pdf file in the device +Future saveAndLaunchFile(List bytes, String fileName) async { + //Get the storage folder location using path_provider package. + String? path; + if (Platform.isAndroid || + Platform.isIOS || + Platform.isLinux || + Platform.isWindows) { + final Directory directory = + await path_provider.getApplicationSupportDirectory(); + path = directory.path; + } else { + path = await PathProviderPlatform.instance.getApplicationSupportPath(); + } + final File file = File( + Platform.isWindows ? '$path\\$fileName' : '$path/$fileName', + ); + await file.writeAsBytes(bytes, flush: true); + if (Platform.isAndroid || Platform.isIOS) { + //Launch the file (used open_file package) + await open_file.OpenFile.open('$path/$fileName'); + } else if (Platform.isWindows) { + await Process.run('start', ['$path\\$fileName'], runInShell: true); + } else if (Platform.isMacOS) { + await Process.run('open', ['$path/$fileName'], runInShell: true); + } else if (Platform.isLinux) { + await Process.run('xdg-open', [ + '$path/$fileName', + ], runInShell: true); + } +} diff --git a/packages/syncfusion_flutter_pdf/example/lib/save_file_web.dart b/packages/syncfusion_flutter_pdf/example/lib/save_file_web.dart index 82d87615c..3dbe4e103 100644 --- a/packages/syncfusion_flutter_pdf/example/lib/save_file_web.dart +++ b/packages/syncfusion_flutter_pdf/example/lib/save_file_web.dart @@ -1,22 +1,22 @@ -/// Dart imports -import 'dart:async'; -import 'dart:convert'; - -import 'package:web/web.dart'; - -// Function to save and launch a file for download in a web environment -Future saveAndLaunchFile(List bytes, String fileName) async { - final HTMLAnchorElement anchor = - document.createElement('a') as HTMLAnchorElement - ..href = 'data:application/octet-stream;base64,${base64Encode(bytes)}' - ..style.display = 'none' - ..download = fileName; - - // Insert the new element into the DOM - document.body!.appendChild(anchor); - - // Initiate the download - anchor.click(); - // Clean up the DOM by removing the anchor element - document.body!.removeChild(anchor); -} +/// Dart imports +import 'dart:async'; +import 'dart:convert'; + +import 'package:web/web.dart'; + +// Function to save and launch a file for download in a web environment +Future saveAndLaunchFile(List bytes, String fileName) async { + final HTMLAnchorElement anchor = + document.createElement('a') as HTMLAnchorElement + ..href = 'data:application/octet-stream;base64,${base64Encode(bytes)}' + ..style.display = 'none' + ..download = fileName; + + // Insert the new element into the DOM + document.body!.appendChild(anchor); + + // Initiate the download + anchor.click(); + // Clean up the DOM by removing the anchor element + document.body!.removeChild(anchor); +} diff --git a/packages/syncfusion_flutter_pdf/example/linux/.gitignore b/packages/syncfusion_flutter_pdf/example/linux/.gitignore deleted file mode 100644 index d3896c984..000000000 --- a/packages/syncfusion_flutter_pdf/example/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/packages/syncfusion_flutter_pdf/example/linux/CMakeLists.txt b/packages/syncfusion_flutter_pdf/example/linux/CMakeLists.txt index 5d04ce358..639d1d586 100644 --- a/packages/syncfusion_flutter_pdf/example/linux/CMakeLists.txt +++ b/packages/syncfusion_flutter_pdf/example/linux/CMakeLists.txt @@ -1,128 +1,128 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.13) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "pdf_example") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.pdf_example") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pdf_example") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.pdf_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/packages/syncfusion_flutter_pdf/example/linux/flutter/CMakeLists.txt b/packages/syncfusion_flutter_pdf/example/linux/flutter/CMakeLists.txt index d5bd01648..27860e801 100644 --- a/packages/syncfusion_flutter_pdf/example/linux/flutter/CMakeLists.txt +++ b/packages/syncfusion_flutter_pdf/example/linux/flutter/CMakeLists.txt @@ -1,88 +1,88 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/packages/syncfusion_flutter_pdf/example/linux/flutter/ephemeral/.plugin_symlinks/open_file_linux b/packages/syncfusion_flutter_pdf/example/linux/flutter/ephemeral/.plugin_symlinks/open_file_linux new file mode 120000 index 000000000..ecae2b54b --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/linux/flutter/ephemeral/.plugin_symlinks/open_file_linux @@ -0,0 +1 @@ +/Users/mac/.pub-cache/hosted/pub.dev/open_file_linux-0.0.5/ \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux b/packages/syncfusion_flutter_pdf/example/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux new file mode 120000 index 000000000..d281b64f9 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux @@ -0,0 +1 @@ +/Users/mac/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/linux/main.cc b/packages/syncfusion_flutter_pdf/example/linux/main.cc deleted file mode 100644 index e7c5c5437..000000000 --- a/packages/syncfusion_flutter_pdf/example/linux/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/packages/syncfusion_flutter_pdf/example/linux/my_application.cc b/packages/syncfusion_flutter_pdf/example/linux/my_application.cc deleted file mode 100644 index 634f4c519..000000000 --- a/packages/syncfusion_flutter_pdf/example/linux/my_application.cc +++ /dev/null @@ -1,105 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen *screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "example"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } - else { - gtk_window_set_title(window, "example"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject *object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} diff --git a/packages/syncfusion_flutter_pdf/example/linux/my_application.h b/packages/syncfusion_flutter_pdf/example/linux/my_application.h deleted file mode 100644 index 72271d5e4..000000000 --- a/packages/syncfusion_flutter_pdf/example/linux/my_application.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/packages/syncfusion_flutter_pdf/example/macos/.gitignore b/packages/syncfusion_flutter_pdf/example/macos/.gitignore deleted file mode 100644 index 746adbb6b..000000000 --- a/packages/syncfusion_flutter_pdf/example/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Debug.xcconfig b/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Debug.xcconfig index 4b81f9b2d..63eaa61da 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Debug.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Debug.xcconfig @@ -1,2 +1,2 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Release.xcconfig b/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Release.xcconfig index 5caa9d157..88d14e02d 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Release.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/macos/Flutter/Flutter-Release.xcconfig @@ -1,2 +1,2 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" -#include "ephemeral/Flutter-Generated.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 000000000..ba4b2bcd2 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=/Users/mac/development/flutter +FLUTTER_APPLICATION_PATH=/Users/mac/Desktop/syncfusion_flutter_pdf-31.2.16/example +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift new file mode 100644 index 000000000..e7ee760c9 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Package.swift @@ -0,0 +1,25 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. +// +// Generated file. Do not edit. +// + +import PackageDescription + +let package = Package( + name: "FlutterGeneratedPluginSwiftPackage", + platforms: [ + .macOS("10.15") + ], + products: [ + .library(name: "FlutterGeneratedPluginSwiftPackage", type: .static, targets: ["FlutterGeneratedPluginSwiftPackage"]) + ], + dependencies: [ + + ], + targets: [ + .target( + name: "FlutterGeneratedPluginSwiftPackage" + ) + ] +) diff --git a/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift new file mode 100644 index 000000000..62e7b11aa --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage/Sources/FlutterGeneratedPluginSwiftPackage/FlutterGeneratedPluginSwiftPackage.swift @@ -0,0 +1,3 @@ +// +// Generated file. Do not edit. +// diff --git a/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/flutter_export_environment.sh b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100755 index 000000000..aeb336bd4 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/mac/development/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/mac/Desktop/syncfusion_flutter_pdf-31.2.16/example" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/packages/syncfusion_flutter_pdf/example/macos/Podfile b/packages/syncfusion_flutter_pdf/example/macos/Podfile new file mode 100644 index 000000000..ff5ddb3b8 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/macos/Podfile @@ -0,0 +1,42 @@ +platform :osx, '10.15' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.pbxproj b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.pbxproj index a331b347a..e35aab46c 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.pbxproj +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.pbxproj @@ -1,823 +1,823 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 2ED92DA3D9D3A3ED79AD7C75 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E986FC827C8E061EBFCEC12 /* Pods_Runner.framework */; }; - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; - 3F152AB12F4BB1001C0554B7 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D380DCDE8813C5944FE430E /* Pods_RunnerTests.framework */; }; - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* pdf_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = pdf_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 58F59E5C0AEB6BEBB111AD0F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 5B3A2E269DB5970578E39075 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 7E4201B2BCAB0B259C6B97AB /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; - 7E986FC827C8E061EBFCEC12 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; - 991FD2FD7E9716C1F3A6147D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - 9D380DCDE8813C5944FE430E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - BEC548A05A7A0EB322E15DE3 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - C0D3138784DDCDC5BBB475DD /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 3F152AB12F4BB1001C0554B7 /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, - 2ED92DA3D9D3A3ED79AD7C75 /* Pods_Runner.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - C23F74D46DF053D8BEF98D7F /* Pods */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* pdf_example.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - C23F74D46DF053D8BEF98D7F /* Pods */ = { - isa = PBXGroup; - children = ( - C0D3138784DDCDC5BBB475DD /* Pods-Runner.debug.xcconfig */, - 991FD2FD7E9716C1F3A6147D /* Pods-Runner.release.xcconfig */, - 58F59E5C0AEB6BEBB111AD0F /* Pods-Runner.profile.xcconfig */, - BEC548A05A7A0EB322E15DE3 /* Pods-RunnerTests.debug.xcconfig */, - 5B3A2E269DB5970578E39075 /* Pods-RunnerTests.release.xcconfig */, - 7E4201B2BCAB0B259C6B97AB /* Pods-RunnerTests.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 7E986FC827C8E061EBFCEC12 /* Pods_Runner.framework */, - 9D380DCDE8813C5944FE430E /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 362177E064935B4FDFD58D4F /* [CP] Check Pods Manifest.lock */, - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - CC49A7046848B15EF8D1C77B /* [CP] Check Pods Manifest.lock */, - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - 7555243112C7AC1B43210A4E /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - packageProductDependencies = ( - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, - ); - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* pdf_example.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, - ); - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; - 362177E064935B4FDFD58D4F /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 7555243112C7AC1B43210A4E /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - CC49A7046848B15EF8D1C77B /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = BEC548A05A7A0EB322E15DE3 /* Pods-RunnerTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pdf_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pdf_example"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5B3A2E269DB5970578E39075 /* Pods-RunnerTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pdf_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pdf_example"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7E4201B2BCAB0B259C6B97AB /* Pods-RunnerTests.profile.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pdf_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pdf_example"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { - isa = XCLocalSwiftPackageReference; - relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; - }; -/* End XCLocalSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { - isa = XCSwiftPackageProductDependency; - productName = FlutterGeneratedPluginSwiftPackage; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 2ED92DA3D9D3A3ED79AD7C75 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E986FC827C8E061EBFCEC12 /* Pods_Runner.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 3F152AB12F4BB1001C0554B7 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D380DCDE8813C5944FE430E /* Pods_RunnerTests.framework */; }; + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* pdf_example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = pdf_example.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 58F59E5C0AEB6BEBB111AD0F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 5B3A2E269DB5970578E39075 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 7E4201B2BCAB0B259C6B97AB /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 7E986FC827C8E061EBFCEC12 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + 991FD2FD7E9716C1F3A6147D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 9D380DCDE8813C5944FE430E /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BEC548A05A7A0EB322E15DE3 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + C0D3138784DDCDC5BBB475DD /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 3F152AB12F4BB1001C0554B7 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */, + 2ED92DA3D9D3A3ED79AD7C75 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + C23F74D46DF053D8BEF98D7F /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* pdf_example.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + C23F74D46DF053D8BEF98D7F /* Pods */ = { + isa = PBXGroup; + children = ( + C0D3138784DDCDC5BBB475DD /* Pods-Runner.debug.xcconfig */, + 991FD2FD7E9716C1F3A6147D /* Pods-Runner.release.xcconfig */, + 58F59E5C0AEB6BEBB111AD0F /* Pods-Runner.profile.xcconfig */, + BEC548A05A7A0EB322E15DE3 /* Pods-RunnerTests.debug.xcconfig */, + 5B3A2E269DB5970578E39075 /* Pods-RunnerTests.release.xcconfig */, + 7E4201B2BCAB0B259C6B97AB /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7E986FC827C8E061EBFCEC12 /* Pods_Runner.framework */, + 9D380DCDE8813C5944FE430E /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 362177E064935B4FDFD58D4F /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + CC49A7046848B15EF8D1C77B /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 7555243112C7AC1B43210A4E /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + packageProductDependencies = ( + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */, + ); + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* pdf_example.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + packageReferences = ( + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, + ); + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 362177E064935B4FDFD58D4F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 7555243112C7AC1B43210A4E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + CC49A7046848B15EF8D1C77B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BEC548A05A7A0EB322E15DE3 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pdf_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pdf_example"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5B3A2E269DB5970578E39075 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pdf_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pdf_example"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7E4201B2BCAB0B259C6B97AB /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pdf_example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/pdf_example"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { + isa = XCSwiftPackageProductDependency; + productName = FlutterGeneratedPluginSwiftPackage; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d981003..fc6bf8074 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 1ddaf3330..ef82673b5 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,117 +1,117 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/contents.xcworkspacedata index 21a3cc14c..17ccc03e6 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/contents.xcworkspacedata +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -1,10 +1,10 @@ - - - - - - - + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist index 18d981003..fc6bf8074 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -1,8 +1,8 @@ - - - - - IDEDidComputeMac32BitWarning - - - + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/AppDelegate.swift b/packages/syncfusion_flutter_pdf/example/macos/Runner/AppDelegate.swift index b3c176141..c5c474d92 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/AppDelegate.swift +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/AppDelegate.swift @@ -1,13 +1,13 @@ -import Cocoa -import FlutterMacOS - -@main -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } - - override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { - return true - } -} +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/packages/syncfusion_flutter_pdf/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index a2ec33f19..8d4e7cb8e 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,68 +1,68 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Base.lproj/MainMenu.xib b/packages/syncfusion_flutter_pdf/example/macos/Runner/Base.lproj/MainMenu.xib index 80e867a4e..4632c6967 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Base.lproj/MainMenu.xib +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Base.lproj/MainMenu.xib @@ -1,343 +1,343 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/AppInfo.xcconfig b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/AppInfo.xcconfig index d01f00242..c4d756a79 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/AppInfo.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/AppInfo.xcconfig @@ -1,14 +1,14 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = pdf_example - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = pdf_example + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.pdfExample + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Debug.xcconfig b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Debug.xcconfig index 36b0fd946..b39882372 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Debug.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Release.xcconfig b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Release.xcconfig index dff4f4956..d93e5dc4a 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Release.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Release.xcconfig @@ -1,2 +1,2 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Warnings.xcconfig b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Warnings.xcconfig index 42bcbf478..fb4d7d3fb 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Warnings.xcconfig +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Configs/Warnings.xcconfig @@ -1,13 +1,13 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/DebugProfile.entitlements b/packages/syncfusion_flutter_pdf/example/macos/Runner/DebugProfile.entitlements index dddb8a30c..51d096708 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/DebugProfile.entitlements +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/DebugProfile.entitlements @@ -1,12 +1,12 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Info.plist b/packages/syncfusion_flutter_pdf/example/macos/Runner/Info.plist index 4789daa6a..3733c1a8e 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Info.plist +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Info.plist @@ -1,32 +1,32 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/MainFlutterWindow.swift b/packages/syncfusion_flutter_pdf/example/macos/Runner/MainFlutterWindow.swift index 3cc05eb23..ab30cba82 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/MainFlutterWindow.swift +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/MainFlutterWindow.swift @@ -1,15 +1,15 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/packages/syncfusion_flutter_pdf/example/macos/Runner/Release.entitlements b/packages/syncfusion_flutter_pdf/example/macos/Runner/Release.entitlements index 852fa1a47..04336df3c 100644 --- a/packages/syncfusion_flutter_pdf/example/macos/Runner/Release.entitlements +++ b/packages/syncfusion_flutter_pdf/example/macos/Runner/Release.entitlements @@ -1,8 +1,8 @@ - - - - - com.apple.security.app-sandbox - - - + + + + + com.apple.security.app-sandbox + + + diff --git a/packages/syncfusion_flutter_pdf/example/pubspec.lock b/packages/syncfusion_flutter_pdf/example/pubspec.lock new file mode 100644 index 000000000..0500974f0 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/pubspec.lock @@ -0,0 +1,340 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + ffi: + dependency: transitive + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + intl: + dependency: transitive + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + open_file: + dependency: "direct main" + description: + name: open_file + sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e + url: "https://pub.dev" + source: hosted + version: "3.5.10" + open_file_android: + dependency: transitive + description: + name: open_file_android + sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa" + url: "https://pub.dev" + source: hosted + version: "1.0.6" + open_file_ios: + dependency: transitive + description: + name: open_file_ios + sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + open_file_linux: + dependency: transitive + description: + name: open_file_linux + sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550 + url: "https://pub.dev" + source: hosted + version: "0.0.5" + open_file_mac: + dependency: transitive + description: + name: open_file_mac + sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + open_file_platform_interface: + dependency: transitive + description: + name: open_file_platform_interface + sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + open_file_web: + dependency: transitive + description: + name: open_file_web + sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f + url: "https://pub.dev" + source: hosted + version: "0.0.4" + open_file_windows: + dependency: transitive + description: + name: open_file_windows + sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875 + url: "https://pub.dev" + source: hosted + version: "0.0.3" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e + url: "https://pub.dev" + source: hosted + version: "2.2.22" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "6d13aece7b3f5c5a9731eaf553ff9dcbc2eff41087fd2df587fd0fed9a3eb0c4" + url: "https://pub.dev" + source: hosted + version: "2.5.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + syncfusion_flutter_core: + dependency: transitive + description: + name: syncfusion_flutter_core + sha256: e68a7e214659faf0df483c760d295ab58e376a639285d2a9f7d1e43351efcbb3 + url: "https://pub.dev" + source: hosted + version: "31.2.16" + syncfusion_flutter_pdf: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "31.2.16" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + web: + dependency: "direct main" + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" +sdks: + dart: ">=3.9.0 <4.0.0" + flutter: ">=3.35.1" diff --git a/packages/syncfusion_flutter_pdf/example/pubspec.yaml b/packages/syncfusion_flutter_pdf/example/pubspec.yaml index a9e4e8e02..b0ba031df 100644 --- a/packages/syncfusion_flutter_pdf/example/pubspec.yaml +++ b/packages/syncfusion_flutter_pdf/example/pubspec.yaml @@ -1,19 +1,18 @@ -name: pdf_example -description: Demo for creating a PDF file using syncfusion_flutter_pdf package. -version: 1.0.0+1 - -environment: - sdk: ^3.7.0-0 - -dependencies: - flutter: - sdk: flutter - path_provider: ^2.1.2 - open_file: ^3.3.2 - syncfusion_flutter_pdf: - path: ../ - web: ^1.1.0 - -# The following section is specific to Flutter. -flutter: - uses-material-design: true +name: pdf_example +description: Demo for creating a PDF file using syncfusion_flutter_pdf package. +version: 1.0.0+1 + +environment: + sdk: ^3.7.0 + +flutter: + uses-material-design: true + +dependencies: + flutter: + sdk: flutter + web: ^1.1.0 + open_file: ^3.3.2 + path_provider: ^2.1.2 + syncfusion_flutter_pdf: + path: ../ diff --git a/packages/syncfusion_flutter_pdf/example/web/index.html b/packages/syncfusion_flutter_pdf/example/web/index.html index 5d1087923..800260aea 100644 --- a/packages/syncfusion_flutter_pdf/example/web/index.html +++ b/packages/syncfusion_flutter_pdf/example/web/index.html @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - pdf_example - - - - - - + + + + + + + + + + + + + + + + + + + + pdf_example + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/web/manifest.json b/packages/syncfusion_flutter_pdf/example/web/manifest.json index aa2e1f5aa..ddabf050e 100644 --- a/packages/syncfusion_flutter_pdf/example/web/manifest.json +++ b/packages/syncfusion_flutter_pdf/example/web/manifest.json @@ -1,35 +1,35 @@ -{ - "name": "pdf_example", - "short_name": "pdf_example", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} +{ + "name": "pdf_example", + "short_name": "pdf_example", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/packages/syncfusion_flutter_pdf/example/windows/.gitignore b/packages/syncfusion_flutter_pdf/example/windows/.gitignore deleted file mode 100644 index d492d0d98..000000000 --- a/packages/syncfusion_flutter_pdf/example/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/packages/syncfusion_flutter_pdf/example/windows/CMakeLists.txt b/packages/syncfusion_flutter_pdf/example/windows/CMakeLists.txt index 54ef6a137..4a00ff124 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/CMakeLists.txt +++ b/packages/syncfusion_flutter_pdf/example/windows/CMakeLists.txt @@ -1,108 +1,108 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(pdf_example LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "pdf_example") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(VERSION 3.14...3.25) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(pdf_example LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "pdf_example") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/packages/syncfusion_flutter_pdf/example/windows/flutter/CMakeLists.txt b/packages/syncfusion_flutter_pdf/example/windows/flutter/CMakeLists.txt index 903f4899d..efb62ebe7 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/flutter/CMakeLists.txt +++ b/packages/syncfusion_flutter_pdf/example/windows/flutter/CMakeLists.txt @@ -1,109 +1,109 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# Set fallback configurations for older versions of the flutter tool. -if (NOT DEFINED FLUTTER_TARGET_PLATFORM) - set(FLUTTER_TARGET_PLATFORM "windows-x64") -endif() - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - ${FLUTTER_TARGET_PLATFORM} $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/packages/syncfusion_flutter_pdf/example/windows/flutter/ephemeral/.plugin_symlinks/open_file_windows b/packages/syncfusion_flutter_pdf/example/windows/flutter/ephemeral/.plugin_symlinks/open_file_windows new file mode 120000 index 000000000..ed5dc2e02 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/windows/flutter/ephemeral/.plugin_symlinks/open_file_windows @@ -0,0 +1 @@ +/Users/mac/.pub-cache/hosted/pub.dev/open_file_windows-0.0.3/ \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows b/packages/syncfusion_flutter_pdf/example/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows new file mode 120000 index 000000000..d4c7bc4e7 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/example/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows @@ -0,0 +1 @@ +/Users/mac/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/ \ No newline at end of file diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/CMakeLists.txt b/packages/syncfusion_flutter_pdf/example/windows/runner/CMakeLists.txt index 394917c05..2041a0441 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/CMakeLists.txt +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/CMakeLists.txt @@ -1,40 +1,40 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/Runner.rc b/packages/syncfusion_flutter_pdf/example/windows/runner/Runner.rc index a159e413f..bb6c78298 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/Runner.rc +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/Runner.rc @@ -1,121 +1,121 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "pdf_example" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "pdf_example" "\0" - VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "pdf_example.exe" "\0" - VALUE "ProductName", "pdf_example" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "pdf_example" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "pdf_example" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "pdf_example.exe" "\0" + VALUE "ProductName", "pdf_example" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.cpp b/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.cpp index 955ee3038..c819cb083 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.cpp +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.cpp @@ -1,71 +1,71 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - // Flutter can complete the first frame before the "show window" callback is - // registered. The following call ensures a frame is pending to ensure the - // window is shown. It is a no-op if the first frame hasn't completed yet. - flutter_controller_->ForceRedraw(); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.h b/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.h index 6da0652f0..28c23839b 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.h +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/flutter_window.h @@ -1,33 +1,33 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/main.cpp b/packages/syncfusion_flutter_pdf/example/windows/runner/main.cpp index a76006b34..081f10193 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/main.cpp +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/main.cpp @@ -1,43 +1,43 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"pdf_example", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"pdf_example", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/resource.h b/packages/syncfusion_flutter_pdf/example/windows/runner/resource.h index 66a65d1e4..ddc7f3efc 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/resource.h +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/resource.h @@ -1,16 +1,16 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.cpp b/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.cpp deleted file mode 100644 index 2d6636ab6..000000000 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "run_loop.h" - -#include - -#include - -RunLoop::RunLoop() {} - -RunLoop::~RunLoop() {} - -void RunLoop::Run() { - bool keep_running = true; - TimePoint next_flutter_event_time = TimePoint::clock::now(); - while (keep_running) { - std::chrono::nanoseconds wait_duration = - std::max(std::chrono::nanoseconds(0), - next_flutter_event_time - TimePoint::clock::now()); - ::MsgWaitForMultipleObjects( - 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000), - QS_ALLINPUT); - bool processed_events = false; - MSG message; - // All pending Windows messages must be processed; MsgWaitForMultipleObjects - // won't return again for items left in the queue after PeekMessage. - while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) { - processed_events = true; - if (message.message == WM_QUIT) { - keep_running = false; - break; - } - ::TranslateMessage(&message); - ::DispatchMessage(&message); - // Allow Flutter to process messages each time a Windows message is - // processed, to prevent starvation. - next_flutter_event_time = - std::min(next_flutter_event_time, ProcessFlutterMessages()); - } - // If the PeekMessage loop didn't run, process Flutter messages. - if (!processed_events) { - next_flutter_event_time = - std::min(next_flutter_event_time, ProcessFlutterMessages()); - } - } -} - -void RunLoop::RegisterFlutterInstance( - flutter::FlutterEngine* flutter_instance) { - flutter_instances_.insert(flutter_instance); -} - -void RunLoop::UnregisterFlutterInstance( - flutter::FlutterEngine* flutter_instance) { - flutter_instances_.erase(flutter_instance); -} - -RunLoop::TimePoint RunLoop::ProcessFlutterMessages() { - TimePoint next_event_time = TimePoint::max(); - for (auto instance : flutter_instances_) { - std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); - if (wait_duration != std::chrono::nanoseconds::max()) { - next_event_time = - std::min(next_event_time, TimePoint::clock::now() + wait_duration); - } - } - return next_event_time; -} diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.h b/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.h deleted file mode 100644 index 000d36246..000000000 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/run_loop.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef RUNNER_RUN_LOOP_H_ -#define RUNNER_RUN_LOOP_H_ - -#include - -#include -#include - -// A runloop that will service events for Flutter instances as well -// as native messages. -class RunLoop { - public: - RunLoop(); - ~RunLoop(); - - // Prevent copying - RunLoop(RunLoop const&) = delete; - RunLoop& operator=(RunLoop const&) = delete; - - // Runs the run loop until the application quits. - void Run(); - - // Registers the given Flutter instance for event servicing. - void RegisterFlutterInstance( - flutter::FlutterEngine* flutter_instance); - - // Unregisters the given Flutter instance from event servicing. - void UnregisterFlutterInstance( - flutter::FlutterEngine* flutter_instance); - - private: - using TimePoint = std::chrono::steady_clock::time_point; - - // Processes all currently pending messages for registered Flutter instances. - TimePoint ProcessFlutterMessages(); - - std::set flutter_instances_; -}; - -#endif // RUNNER_RUN_LOOP_H_ diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/runner.exe.manifest b/packages/syncfusion_flutter_pdf/example/windows/runner/runner.exe.manifest index 153653e8d..4b962bbeb 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/runner.exe.manifest +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/runner.exe.manifest @@ -1,14 +1,14 @@ - - - - - PerMonitorV2 - - - - - - - - - + + + + + PerMonitorV2 + + + + + + + + + diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/utils.cpp b/packages/syncfusion_flutter_pdf/example/windows/runner/utils.cpp index 3a0b46511..259d85bff 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/utils.cpp +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/utils.cpp @@ -1,65 +1,65 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - unsigned int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr) - -1; // remove the trailing null character - int input_length = (int)wcslen(utf16_string); - std::string utf8_string; - if (target_length == 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - input_length, utf8_string.data(), target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/utils.h b/packages/syncfusion_flutter_pdf/example/windows/runner/utils.h index 3879d5475..3f0e05cba 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/utils.h +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/utils.h @@ -1,19 +1,19 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.cpp b/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.cpp index 60608d0fe..b5ba2a099 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.cpp +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.cpp @@ -1,288 +1,288 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - -/// Window attribute that enables dark mode window decorations. -/// -/// Redefined in case the developer's machine has a Windows SDK older than -/// version 10.0.22000.0. -/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -/// Registry key for app theme preference. -/// -/// A value of 0 indicates apps should use dark mode. A non-zero or missing -/// value indicates apps should use light mode. -constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() { - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) { - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.h b/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.h index e901dde68..49b847f07 100644 --- a/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.h +++ b/packages/syncfusion_flutter_pdf/example/windows/runner/win32_window.h @@ -1,102 +1,102 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/packages/syncfusion_flutter_pdf/lib/pdf.dart b/packages/syncfusion_flutter_pdf/lib/pdf.dart index baaa4af70..f636a9062 100644 --- a/packages/syncfusion_flutter_pdf/lib/pdf.dart +++ b/packages/syncfusion_flutter_pdf/lib/pdf.dart @@ -1,290 +1,290 @@ -/// The Syncfusion Flutter PDF is a library written natively in Dart for -/// creating, reading, editing, and securing PDF files in Android, iOS, -/// and web platforms. -library pdf; - -export 'src/pdf/implementation/actions/pdf_action.dart' show PdfAction; -export 'src/pdf/implementation/actions/pdf_annotation_action.dart' - show PdfAnnotationActions; -export 'src/pdf/implementation/actions/pdf_field_actions.dart' - show PdfFieldActions, PdfJavaScriptAction; -export 'src/pdf/implementation/actions/pdf_submit_action.dart' - show PdfSubmitAction, PdfResetAction, PdfFormAction; -export 'src/pdf/implementation/actions/pdf_uri_action.dart' show PdfUriAction; -export 'src/pdf/implementation/annotations/enum.dart' - show - PdfHighlightMode, - PdfFilePathType, - PdfBorderStyle, - PdfLineIntent, - PdfLineCaptionType, - PdfLineEndingStyle, - PdfSubmitFormFlags, - SubmitDataFormat, - HttpMethod, - PdfTextMarkupAnnotationType, - PdfPopupIcon, - PdfAnnotationFlags, - PdfAnnotationDataFormat, - PdfAnnotationExportType; -export 'src/pdf/implementation/annotations/pdf_action_annotation.dart' - show PdfLinkAnnotation, PdfActionLinkAnnotation, PdfActionAnnotation; -export 'src/pdf/implementation/annotations/pdf_annotation.dart' - show PdfAnnotation; -export 'src/pdf/implementation/annotations/pdf_annotation_border.dart' - show PdfAnnotationBorder; -export 'src/pdf/implementation/annotations/pdf_annotation_collection.dart' - show PdfAnnotationCollection; -export 'src/pdf/implementation/annotations/pdf_appearance.dart' - show PdfAppearance; -export 'src/pdf/implementation/annotations/pdf_document_link_annotation.dart' - show PdfDocumentLinkAnnotation; -export 'src/pdf/implementation/annotations/pdf_ellipse_annotation.dart' - show PdfEllipseAnnotation; -export 'src/pdf/implementation/annotations/pdf_line_annotation.dart' - show PdfLineAnnotation; -export 'src/pdf/implementation/annotations/pdf_polygon_annotation.dart' - show PdfPolygonAnnotation; -export 'src/pdf/implementation/annotations/pdf_popup_annotation.dart' - show PdfPopupAnnotation; -export 'src/pdf/implementation/annotations/pdf_rectangle_annotation.dart' - show PdfRectangleAnnotation; -export 'src/pdf/implementation/annotations/pdf_text_markup_annotation.dart' - show PdfTextMarkupAnnotation; -export 'src/pdf/implementation/annotations/pdf_text_web_link.dart' - show PdfTextWebLink; -export 'src/pdf/implementation/annotations/pdf_uri_annotation.dart' - show PdfUriAnnotation; -export 'src/pdf/implementation/exporting/pdf_text_extractor/enums.dart'; -export 'src/pdf/implementation/exporting/pdf_text_extractor/matched_item.dart' - show MatchedItem; -export 'src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart'; -export 'src/pdf/implementation/exporting/pdf_text_extractor/text_glyph.dart' - show TextGlyph; -export 'src/pdf/implementation/exporting/pdf_text_extractor/text_line.dart' - show TextLine; -export 'src/pdf/implementation/exporting/pdf_text_extractor/text_word.dart' - show TextWord; -export 'src/pdf/implementation/forms/enum.dart' - show PdfCheckBoxStyle, DataFormat; -export 'src/pdf/implementation/forms/pdf_button_field.dart' show PdfButtonField; -export 'src/pdf/implementation/forms/pdf_check_box_field.dart' - show PdfCheckBoxField, PdfRadioButtonListItem, PdfCheckFieldBase; -export 'src/pdf/implementation/forms/pdf_combo_box_field.dart' - show PdfComboBoxField; -export 'src/pdf/implementation/forms/pdf_field.dart' show PdfField; -export 'src/pdf/implementation/forms/pdf_field_item.dart' - show PdfFieldItem, PdfTextBoxItem, PdfCheckBoxItem; -export 'src/pdf/implementation/forms/pdf_field_item_collection.dart' - show PdfFieldItemCollection; -export 'src/pdf/implementation/forms/pdf_form.dart' show PdfForm; -export 'src/pdf/implementation/forms/pdf_form_field_collection.dart' - show PdfFormFieldCollection; -export 'src/pdf/implementation/forms/pdf_list_box_field.dart' - show PdfListBoxField; -export 'src/pdf/implementation/forms/pdf_list_field.dart' show PdfListField; -export 'src/pdf/implementation/forms/pdf_list_field_item.dart' - show PdfListFieldItem; -export 'src/pdf/implementation/forms/pdf_list_field_item_collection.dart' - show PdfListFieldItemCollection; -export 'src/pdf/implementation/forms/pdf_radio_button_item_collection.dart' - show PdfRadioButtonItemCollection; -export 'src/pdf/implementation/forms/pdf_radio_button_list_field.dart' - show PdfRadioButtonListField; -export 'src/pdf/implementation/forms/pdf_signature_field.dart' - show PdfSignatureField; -export 'src/pdf/implementation/forms/pdf_text_box_field.dart' - show PdfTextBoxField; -export 'src/pdf/implementation/general/enum.dart'; -export 'src/pdf/implementation/general/pdf_collection.dart' - show PdfObjectCollection; -export 'src/pdf/implementation/general/pdf_destination.dart' - show PdfDestination; -export 'src/pdf/implementation/general/pdf_named_destination.dart' - show PdfNamedDestination; -export 'src/pdf/implementation/general/pdf_named_destination_collection.dart' - show PdfNamedDestinationCollection; -export 'src/pdf/implementation/graphics/brushes/pdf_brush.dart' show PdfBrushes; -export 'src/pdf/implementation/graphics/brushes/pdf_solid_brush.dart' - show PdfSolidBrush, PdfBrush; -export 'src/pdf/implementation/graphics/enums.dart' - show - PdfTextAlignment, - PdfVerticalAlignment, - PdfTextDirection, - PdfColorSpace, - PdfDashStyle, - PdfLineJoin, - PdfLineCap, - PdfFillMode, - PdfBlendMode; -export 'src/pdf/implementation/graphics/figures/base/element_layouter.dart' - show PdfLayoutFormat; -export 'src/pdf/implementation/graphics/figures/base/layout_element.dart' - show - PdfLayoutElement, - PdfCancelArgs, - BeginPageLayoutArgs, - BeginPageLayoutCallback, - EndPageLayoutArgs, - EndTextPageLayoutArgs, - EndPageLayoutCallback; -export 'src/pdf/implementation/graphics/figures/base/pdf_shape_element.dart' - show PdfShapeElement; -export 'src/pdf/implementation/graphics/figures/base/text_layouter.dart' - show PdfLayoutResult, PdfTextLayoutResult; -export 'src/pdf/implementation/graphics/figures/enums.dart' - show PdfLayoutType, PdfLayoutBreakType; -export 'src/pdf/implementation/graphics/figures/pdf_bezier_curve.dart' - show PdfBezierCurve; -export 'src/pdf/implementation/graphics/figures/pdf_path.dart' show PdfPath; -export 'src/pdf/implementation/graphics/figures/pdf_template.dart' - show PdfTemplate; -export 'src/pdf/implementation/graphics/figures/pdf_text_element.dart' - show PdfTextElement; -export 'src/pdf/implementation/graphics/fonts/enums.dart' - show - PdfFontStyle, - PdfFontFamily, - PdfSubSuperscript, - PdfCjkFontFamily, - PdfWordWrapType; -export 'src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font.dart' - show PdfCjkStandardFont; -export 'src/pdf/implementation/graphics/fonts/pdf_font.dart' show PdfFont; -export 'src/pdf/implementation/graphics/fonts/pdf_standard_font.dart' - show PdfStandardFont; -export 'src/pdf/implementation/graphics/fonts/pdf_string_format.dart' - show PdfStringFormat; -export 'src/pdf/implementation/graphics/fonts/pdf_true_type_font.dart' - show PdfTrueTypeFont; -export 'src/pdf/implementation/graphics/images/pdf_bitmap.dart' show PdfBitmap; -export 'src/pdf/implementation/graphics/images/pdf_image.dart' show PdfImage; -export 'src/pdf/implementation/graphics/pdf_color.dart' show PdfColor; -export 'src/pdf/implementation/graphics/pdf_graphics.dart' - show PdfGraphics, PdfGraphicsState; -export 'src/pdf/implementation/graphics/pdf_margins.dart' show PdfMargins; -export 'src/pdf/implementation/graphics/pdf_pen.dart' show PdfPen; -export 'src/pdf/implementation/graphics/pdf_pens.dart' show PdfPens; -export 'src/pdf/implementation/pages/enum.dart' - show - PdfPageOrientation, - PdfPageRotateAngle, - PdfDockStyle, - PdfAlignmentStyle, - PdfNumberStyle, - PdfFormFieldsTabOrder; -export 'src/pdf/implementation/pages/pdf_layer.dart' show PdfLayer; -export 'src/pdf/implementation/pages/pdf_layer_collection.dart' - show PdfLayerCollection; -export 'src/pdf/implementation/pages/pdf_page.dart' show PdfPage; -export 'src/pdf/implementation/pages/pdf_page_collection.dart' - show PdfPageCollection; -export 'src/pdf/implementation/pages/pdf_page_layer.dart' show PdfPageLayer; -export 'src/pdf/implementation/pages/pdf_page_layer_collection.dart' - show PdfPageLayerCollection; -export 'src/pdf/implementation/pages/pdf_page_settings.dart' - show PdfPageSettings, PdfPageSize; -export 'src/pdf/implementation/pages/pdf_page_template_element.dart' - show PdfPageTemplateElement; -export 'src/pdf/implementation/pages/pdf_section.dart' - show PdfSection, PageAddedArgs, PageAddedCallback; -export 'src/pdf/implementation/pages/pdf_section_collection.dart' - show PdfSectionCollection; -export 'src/pdf/implementation/pages/pdf_section_template.dart'; -export 'src/pdf/implementation/pdf_document/attachments/pdf_attachment.dart' - show PdfAttachment; -export 'src/pdf/implementation/pdf_document/attachments/pdf_attachment_collection.dart' - show PdfAttachmentCollection; -export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field.dart' - show PdfAutomaticField; -export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_composite_field.dart' - show PdfCompositeField; -export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_date_time_field.dart' - show PdfDateTimeField; -export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_destination_page_number_field.dart' - show PdfDestinationPageNumberField; -export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_page_count_field.dart' - show PdfPageCountField; -export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_page_number_field.dart' - show PdfPageNumberField; -export 'src/pdf/implementation/pdf_document/enums.dart' - show - PdfVersion, - PdfCrossReferenceType, - PdfConformanceLevel, - PdfAttachmentRelationship, - PdfCompressionLevel; -export 'src/pdf/implementation/pdf_document/outlines/enums.dart'; -export 'src/pdf/implementation/pdf_document/outlines/pdf_outline.dart' - show PdfBookmark, PdfBookmarkBase; -export 'src/pdf/implementation/pdf_document/pdf_document.dart' - show PdfDocument, PdfPasswordArgs, PdfPasswordCallback; -export 'src/pdf/implementation/pdf_document/pdf_document_information.dart' - show PdfDocumentInformation; -export 'src/pdf/implementation/pdf_document/pdf_document_template.dart' - show PdfDocumentTemplate, PdfStampCollection; -export 'src/pdf/implementation/pdf_document/pdf_file_structure.dart' - show PdfFileStructure; -export 'src/pdf/implementation/security/digital_signature/pdf_certificate.dart' - show PdfCertificate; -export 'src/pdf/implementation/security/digital_signature/pdf_external_signer.dart'; -export 'src/pdf/implementation/security/digital_signature/pdf_signature.dart' - show PdfSignature, RevocationType; -export 'src/pdf/implementation/security/digital_signature/time_stamp_server/time_stamp_server.dart' - show TimestampServer; -export 'src/pdf/implementation/security/enum.dart'; -export 'src/pdf/implementation/security/pdf_security.dart' - show PdfPermissions, PdfSecurity; -export 'src/pdf/implementation/structured_elements/grid/enums.dart' - show - PdfGridImagePosition, - PdfHorizontalOverflowType, - PdfBorderOverlapStyle, - PdfGridBuiltInStyle; -export 'src/pdf/implementation/structured_elements/grid/pdf_grid.dart' - show - PdfGrid, - PdfGridBeginCellLayoutArgs, - PdfGridBeginPageLayoutArgs, - PdfGridBuiltInStyleSettings, - PdfGridEndCellLayoutArgs, - PdfGridEndPageLayoutArgs, - GridCellLayoutArgs, - PdfGridBeginCellLayoutCallback, - PdfGridEndCellLayoutCallback; -export 'src/pdf/implementation/structured_elements/grid/pdf_grid_cell.dart' - show PdfGridCell, PdfGridCellCollection; -export 'src/pdf/implementation/structured_elements/grid/pdf_grid_column.dart' - show PdfGridColumn, PdfGridColumnCollection; -export 'src/pdf/implementation/structured_elements/grid/pdf_grid_row.dart' - show PdfGridRow, PdfGridRowCollection, PdfGridHeaderCollection; -export 'src/pdf/implementation/structured_elements/grid/styles/pdf_borders.dart' - show PdfPaddings, PdfBorders; -export 'src/pdf/implementation/structured_elements/grid/styles/style.dart' - show PdfGridStyleBase, PdfGridStyle, PdfGridRowStyle, PdfGridCellStyle; -export 'src/pdf/implementation/structured_elements/lists/bullets/enums.dart' - show PdfListMarkerAlignment, PdfUnorderedMarkerStyle; -export 'src/pdf/implementation/structured_elements/lists/bullets/pdf_marker.dart' - show PdfMarker; -export 'src/pdf/implementation/structured_elements/lists/bullets/pdf_ordered_marker.dart' - show PdfOrderedMarker; -export 'src/pdf/implementation/structured_elements/lists/bullets/pdf_unordered_marker.dart' - show PdfUnorderedMarker; -export 'src/pdf/implementation/structured_elements/lists/pdf_list.dart' - show - PdfList, - EndItemLayoutArgs, - EndItemLayoutCallback, - BeginItemLayoutArgs, - BeginItemLayoutCallback; -export 'src/pdf/implementation/structured_elements/lists/pdf_list_item.dart' - show PdfListItem; -export 'src/pdf/implementation/structured_elements/lists/pdf_list_item_collection.dart' - show PdfListItemCollection; -export 'src/pdf/implementation/structured_elements/lists/pdf_list_layouter.dart' - show ListBeginPageLayoutArgs, ListEndPageLayoutArgs; -export 'src/pdf/implementation/structured_elements/lists/pdf_ordered_list.dart' - show PdfOrderedList; -export 'src/pdf/implementation/structured_elements/lists/pdf_unordered_list.dart' - show PdfUnorderedList; +/// The Syncfusion Flutter PDF is a library written natively in Dart for +/// creating, reading, editing, and securing PDF files in Android, iOS, +/// and web platforms. +library pdf; + +export 'src/pdf/implementation/actions/pdf_action.dart' show PdfAction; +export 'src/pdf/implementation/actions/pdf_annotation_action.dart' + show PdfAnnotationActions; +export 'src/pdf/implementation/actions/pdf_field_actions.dart' + show PdfFieldActions, PdfJavaScriptAction; +export 'src/pdf/implementation/actions/pdf_submit_action.dart' + show PdfSubmitAction, PdfResetAction, PdfFormAction; +export 'src/pdf/implementation/actions/pdf_uri_action.dart' show PdfUriAction; +export 'src/pdf/implementation/annotations/enum.dart' + show + PdfHighlightMode, + PdfFilePathType, + PdfBorderStyle, + PdfLineIntent, + PdfLineCaptionType, + PdfLineEndingStyle, + PdfSubmitFormFlags, + SubmitDataFormat, + HttpMethod, + PdfTextMarkupAnnotationType, + PdfPopupIcon, + PdfAnnotationFlags, + PdfAnnotationDataFormat, + PdfAnnotationExportType; +export 'src/pdf/implementation/annotations/pdf_action_annotation.dart' + show PdfLinkAnnotation, PdfActionLinkAnnotation, PdfActionAnnotation; +export 'src/pdf/implementation/annotations/pdf_annotation.dart' + show PdfAnnotation; +export 'src/pdf/implementation/annotations/pdf_annotation_border.dart' + show PdfAnnotationBorder; +export 'src/pdf/implementation/annotations/pdf_annotation_collection.dart' + show PdfAnnotationCollection; +export 'src/pdf/implementation/annotations/pdf_appearance.dart' + show PdfAppearance; +export 'src/pdf/implementation/annotations/pdf_document_link_annotation.dart' + show PdfDocumentLinkAnnotation; +export 'src/pdf/implementation/annotations/pdf_ellipse_annotation.dart' + show PdfEllipseAnnotation; +export 'src/pdf/implementation/annotations/pdf_line_annotation.dart' + show PdfLineAnnotation; +export 'src/pdf/implementation/annotations/pdf_polygon_annotation.dart' + show PdfPolygonAnnotation; +export 'src/pdf/implementation/annotations/pdf_popup_annotation.dart' + show PdfPopupAnnotation; +export 'src/pdf/implementation/annotations/pdf_rectangle_annotation.dart' + show PdfRectangleAnnotation; +export 'src/pdf/implementation/annotations/pdf_text_markup_annotation.dart' + show PdfTextMarkupAnnotation; +export 'src/pdf/implementation/annotations/pdf_text_web_link.dart' + show PdfTextWebLink; +export 'src/pdf/implementation/annotations/pdf_uri_annotation.dart' + show PdfUriAnnotation; +export 'src/pdf/implementation/exporting/pdf_text_extractor/enums.dart'; +export 'src/pdf/implementation/exporting/pdf_text_extractor/matched_item.dart' + show MatchedItem; +export 'src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart'; +export 'src/pdf/implementation/exporting/pdf_text_extractor/text_glyph.dart' + show TextGlyph; +export 'src/pdf/implementation/exporting/pdf_text_extractor/text_line.dart' + show TextLine; +export 'src/pdf/implementation/exporting/pdf_text_extractor/text_word.dart' + show TextWord; +export 'src/pdf/implementation/forms/enum.dart' + show PdfCheckBoxStyle, DataFormat; +export 'src/pdf/implementation/forms/pdf_button_field.dart' show PdfButtonField; +export 'src/pdf/implementation/forms/pdf_check_box_field.dart' + show PdfCheckBoxField, PdfRadioButtonListItem, PdfCheckFieldBase; +export 'src/pdf/implementation/forms/pdf_combo_box_field.dart' + show PdfComboBoxField; +export 'src/pdf/implementation/forms/pdf_field.dart' show PdfField; +export 'src/pdf/implementation/forms/pdf_field_item.dart' + show PdfFieldItem, PdfTextBoxItem, PdfCheckBoxItem; +export 'src/pdf/implementation/forms/pdf_field_item_collection.dart' + show PdfFieldItemCollection; +export 'src/pdf/implementation/forms/pdf_form.dart' show PdfForm; +export 'src/pdf/implementation/forms/pdf_form_field_collection.dart' + show PdfFormFieldCollection; +export 'src/pdf/implementation/forms/pdf_list_box_field.dart' + show PdfListBoxField; +export 'src/pdf/implementation/forms/pdf_list_field.dart' show PdfListField; +export 'src/pdf/implementation/forms/pdf_list_field_item.dart' + show PdfListFieldItem; +export 'src/pdf/implementation/forms/pdf_list_field_item_collection.dart' + show PdfListFieldItemCollection; +export 'src/pdf/implementation/forms/pdf_radio_button_item_collection.dart' + show PdfRadioButtonItemCollection; +export 'src/pdf/implementation/forms/pdf_radio_button_list_field.dart' + show PdfRadioButtonListField; +export 'src/pdf/implementation/forms/pdf_signature_field.dart' + show PdfSignatureField; +export 'src/pdf/implementation/forms/pdf_text_box_field.dart' + show PdfTextBoxField; +export 'src/pdf/implementation/general/enum.dart'; +export 'src/pdf/implementation/general/pdf_collection.dart' + show PdfObjectCollection; +export 'src/pdf/implementation/general/pdf_destination.dart' + show PdfDestination; +export 'src/pdf/implementation/general/pdf_named_destination.dart' + show PdfNamedDestination; +export 'src/pdf/implementation/general/pdf_named_destination_collection.dart' + show PdfNamedDestinationCollection; +export 'src/pdf/implementation/graphics/brushes/pdf_brush.dart' show PdfBrushes; +export 'src/pdf/implementation/graphics/brushes/pdf_solid_brush.dart' + show PdfSolidBrush, PdfBrush; +export 'src/pdf/implementation/graphics/enums.dart' + show + PdfTextAlignment, + PdfVerticalAlignment, + PdfTextDirection, + PdfColorSpace, + PdfDashStyle, + PdfLineJoin, + PdfLineCap, + PdfFillMode, + PdfBlendMode; +export 'src/pdf/implementation/graphics/figures/base/element_layouter.dart' + show PdfLayoutFormat; +export 'src/pdf/implementation/graphics/figures/base/layout_element.dart' + show + PdfLayoutElement, + PdfCancelArgs, + BeginPageLayoutArgs, + BeginPageLayoutCallback, + EndPageLayoutArgs, + EndTextPageLayoutArgs, + EndPageLayoutCallback; +export 'src/pdf/implementation/graphics/figures/base/pdf_shape_element.dart' + show PdfShapeElement; +export 'src/pdf/implementation/graphics/figures/base/text_layouter.dart' + show PdfLayoutResult, PdfTextLayoutResult; +export 'src/pdf/implementation/graphics/figures/enums.dart' + show PdfLayoutType, PdfLayoutBreakType; +export 'src/pdf/implementation/graphics/figures/pdf_bezier_curve.dart' + show PdfBezierCurve; +export 'src/pdf/implementation/graphics/figures/pdf_path.dart' show PdfPath; +export 'src/pdf/implementation/graphics/figures/pdf_template.dart' + show PdfTemplate; +export 'src/pdf/implementation/graphics/figures/pdf_text_element.dart' + show PdfTextElement; +export 'src/pdf/implementation/graphics/fonts/enums.dart' + show + PdfFontStyle, + PdfFontFamily, + PdfSubSuperscript, + PdfCjkFontFamily, + PdfWordWrapType; +export 'src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font.dart' + show PdfCjkStandardFont; +export 'src/pdf/implementation/graphics/fonts/pdf_font.dart' show PdfFont; +export 'src/pdf/implementation/graphics/fonts/pdf_standard_font.dart' + show PdfStandardFont; +export 'src/pdf/implementation/graphics/fonts/pdf_string_format.dart' + show PdfStringFormat; +export 'src/pdf/implementation/graphics/fonts/pdf_true_type_font.dart' + show PdfTrueTypeFont; +export 'src/pdf/implementation/graphics/images/pdf_bitmap.dart' show PdfBitmap; +export 'src/pdf/implementation/graphics/images/pdf_image.dart' show PdfImage; +export 'src/pdf/implementation/graphics/pdf_color.dart' show PdfColor; +export 'src/pdf/implementation/graphics/pdf_graphics.dart' + show PdfGraphics, PdfGraphicsState; +export 'src/pdf/implementation/graphics/pdf_margins.dart' show PdfMargins; +export 'src/pdf/implementation/graphics/pdf_pen.dart' show PdfPen; +export 'src/pdf/implementation/graphics/pdf_pens.dart' show PdfPens; +export 'src/pdf/implementation/pages/enum.dart' + show + PdfPageOrientation, + PdfPageRotateAngle, + PdfDockStyle, + PdfAlignmentStyle, + PdfNumberStyle, + PdfFormFieldsTabOrder; +export 'src/pdf/implementation/pages/pdf_layer.dart' show PdfLayer; +export 'src/pdf/implementation/pages/pdf_layer_collection.dart' + show PdfLayerCollection; +export 'src/pdf/implementation/pages/pdf_page.dart' show PdfPage; +export 'src/pdf/implementation/pages/pdf_page_collection.dart' + show PdfPageCollection; +export 'src/pdf/implementation/pages/pdf_page_layer.dart' show PdfPageLayer; +export 'src/pdf/implementation/pages/pdf_page_layer_collection.dart' + show PdfPageLayerCollection; +export 'src/pdf/implementation/pages/pdf_page_settings.dart' + show PdfPageSettings, PdfPageSize; +export 'src/pdf/implementation/pages/pdf_page_template_element.dart' + show PdfPageTemplateElement; +export 'src/pdf/implementation/pages/pdf_section.dart' + show PdfSection, PageAddedArgs, PageAddedCallback; +export 'src/pdf/implementation/pages/pdf_section_collection.dart' + show PdfSectionCollection; +export 'src/pdf/implementation/pages/pdf_section_template.dart'; +export 'src/pdf/implementation/pdf_document/attachments/pdf_attachment.dart' + show PdfAttachment; +export 'src/pdf/implementation/pdf_document/attachments/pdf_attachment_collection.dart' + show PdfAttachmentCollection; +export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field.dart' + show PdfAutomaticField; +export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_composite_field.dart' + show PdfCompositeField; +export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_date_time_field.dart' + show PdfDateTimeField; +export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_destination_page_number_field.dart' + show PdfDestinationPageNumberField; +export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_page_count_field.dart' + show PdfPageCountField; +export 'src/pdf/implementation/pdf_document/automatic_fields/pdf_page_number_field.dart' + show PdfPageNumberField; +export 'src/pdf/implementation/pdf_document/enums.dart' + show + PdfVersion, + PdfCrossReferenceType, + PdfConformanceLevel, + PdfAttachmentRelationship, + PdfCompressionLevel; +export 'src/pdf/implementation/pdf_document/outlines/enums.dart'; +export 'src/pdf/implementation/pdf_document/outlines/pdf_outline.dart' + show PdfBookmark, PdfBookmarkBase; +export 'src/pdf/implementation/pdf_document/pdf_document.dart' + show PdfDocument, PdfPasswordArgs, PdfPasswordCallback; +export 'src/pdf/implementation/pdf_document/pdf_document_information.dart' + show PdfDocumentInformation; +export 'src/pdf/implementation/pdf_document/pdf_document_template.dart' + show PdfDocumentTemplate, PdfStampCollection; +export 'src/pdf/implementation/pdf_document/pdf_file_structure.dart' + show PdfFileStructure; +export 'src/pdf/implementation/security/digital_signature/pdf_certificate.dart' + show PdfCertificate; +export 'src/pdf/implementation/security/digital_signature/pdf_external_signer.dart'; +export 'src/pdf/implementation/security/digital_signature/pdf_signature.dart' + show PdfSignature, RevocationType; +export 'src/pdf/implementation/security/digital_signature/time_stamp_server/time_stamp_server.dart' + show TimestampServer; +export 'src/pdf/implementation/security/enum.dart'; +export 'src/pdf/implementation/security/pdf_security.dart' + show PdfPermissions, PdfSecurity; +export 'src/pdf/implementation/structured_elements/grid/enums.dart' + show + PdfGridImagePosition, + PdfHorizontalOverflowType, + PdfBorderOverlapStyle, + PdfGridBuiltInStyle; +export 'src/pdf/implementation/structured_elements/grid/pdf_grid.dart' + show + PdfGrid, + PdfGridBeginCellLayoutArgs, + PdfGridBeginPageLayoutArgs, + PdfGridBuiltInStyleSettings, + PdfGridEndCellLayoutArgs, + PdfGridEndPageLayoutArgs, + GridCellLayoutArgs, + PdfGridBeginCellLayoutCallback, + PdfGridEndCellLayoutCallback; +export 'src/pdf/implementation/structured_elements/grid/pdf_grid_cell.dart' + show PdfGridCell, PdfGridCellCollection; +export 'src/pdf/implementation/structured_elements/grid/pdf_grid_column.dart' + show PdfGridColumn, PdfGridColumnCollection; +export 'src/pdf/implementation/structured_elements/grid/pdf_grid_row.dart' + show PdfGridRow, PdfGridRowCollection, PdfGridHeaderCollection; +export 'src/pdf/implementation/structured_elements/grid/styles/pdf_borders.dart' + show PdfPaddings, PdfBorders; +export 'src/pdf/implementation/structured_elements/grid/styles/style.dart' + show PdfGridStyleBase, PdfGridStyle, PdfGridRowStyle, PdfGridCellStyle; +export 'src/pdf/implementation/structured_elements/lists/bullets/enums.dart' + show PdfListMarkerAlignment, PdfUnorderedMarkerStyle; +export 'src/pdf/implementation/structured_elements/lists/bullets/pdf_marker.dart' + show PdfMarker; +export 'src/pdf/implementation/structured_elements/lists/bullets/pdf_ordered_marker.dart' + show PdfOrderedMarker; +export 'src/pdf/implementation/structured_elements/lists/bullets/pdf_unordered_marker.dart' + show PdfUnorderedMarker; +export 'src/pdf/implementation/structured_elements/lists/pdf_list.dart' + show + PdfList, + EndItemLayoutArgs, + EndItemLayoutCallback, + BeginItemLayoutArgs, + BeginItemLayoutCallback; +export 'src/pdf/implementation/structured_elements/lists/pdf_list_item.dart' + show PdfListItem; +export 'src/pdf/implementation/structured_elements/lists/pdf_list_item_collection.dart' + show PdfListItemCollection; +export 'src/pdf/implementation/structured_elements/lists/pdf_list_layouter.dart' + show ListBeginPageLayoutArgs, ListEndPageLayoutArgs; +export 'src/pdf/implementation/structured_elements/lists/pdf_ordered_list.dart' + show PdfOrderedList; +export 'src/pdf/implementation/structured_elements/lists/pdf_unordered_list.dart' + show PdfUnorderedList; diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_action.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_action.dart index daa31aa06..6c267123c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_action.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_action.dart @@ -1,58 +1,58 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference_holder.dart'; - -/// Represents base class for all action types. -abstract class PdfAction implements IPdfWrapper { - //Fields - final PdfActionHelper _helper = PdfActionHelper(); - - // properties - /// Gets the next action - /// to be performed after the action represented by this instance. - PdfAction? get next => _helper.action; - - /// Sets the next action - /// to be performed after the action represented by this instance. - set next(PdfAction? value) { - if (value != null && _helper.action != value) { - _helper.action = value; - _helper.dictionary.setArray(PdfDictionaryProperties.next, [ - PdfReferenceHolder(_helper.action), - ]); - } - } -} - -/// [PdfAction] helper -class PdfActionHelper { - /// initialize a new instance - PdfActionHelper() { - initialize(); - } - - /// internal field - PdfAction? action; - - /// internal field - IPdfPrimitive? element; - - /// internal field - final PdfDictionary dictionary = PdfDictionary(); - - /// internal method - void initialize() { - dictionary.setProperty( - PdfName(PdfDictionaryProperties.type), - PdfName(PdfDictionaryProperties.action), - ); - element = dictionary; - } - - /// Get dictionary - static PdfActionHelper getHelper(PdfAction action) { - return action._helper; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference_holder.dart'; + +/// Represents base class for all action types. +abstract class PdfAction implements IPdfWrapper { + //Fields + final PdfActionHelper _helper = PdfActionHelper(); + + // properties + /// Gets the next action + /// to be performed after the action represented by this instance. + PdfAction? get next => _helper.action; + + /// Sets the next action + /// to be performed after the action represented by this instance. + set next(PdfAction? value) { + if (value != null && _helper.action != value) { + _helper.action = value; + _helper.dictionary.setArray(PdfDictionaryProperties.next, [ + PdfReferenceHolder(_helper.action), + ]); + } + } +} + +/// [PdfAction] helper +class PdfActionHelper { + /// initialize a new instance + PdfActionHelper() { + initialize(); + } + + /// internal field + PdfAction? action; + + /// internal field + IPdfPrimitive? element; + + /// internal field + final PdfDictionary dictionary = PdfDictionary(); + + /// internal method + void initialize() { + dictionary.setProperty( + PdfName(PdfDictionaryProperties.type), + PdfName(PdfDictionaryProperties.action), + ); + element = dictionary; + } + + /// Get dictionary + static PdfActionHelper getHelper(PdfAction action) { + return action._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_annotation_action.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_annotation_action.dart index 0280d03b0..6182babc5 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_annotation_action.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_annotation_action.dart @@ -1,162 +1,162 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import 'pdf_action.dart'; - -/// Represents additional actions of the annotations. -class PdfAnnotationActions implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfAnnotationActions] class. - PdfAnnotationActions({ - PdfAction? mouseEnter, - PdfAction? mouseLeave, - PdfAction? mouseUp, - PdfAction? mouseDown, - PdfAction? gotFocus, - PdfAction? lostFocus, - }) { - _helper = PdfAnnotationActionsHelper(); - _initValues( - mouseEnter, - mouseLeave, - mouseUp, - mouseDown, - gotFocus, - lostFocus, - ); - } - - PdfAnnotationActions._loaded(PdfDictionary? dictionary) { - _helper = PdfAnnotationActionsHelper(dictionary); - } - - //Fields - late PdfAnnotationActionsHelper _helper; - PdfAction? _mouseEnter; - PdfAction? _mouseLeave; - PdfAction? _mouseDown; - PdfAction? _mouseUp; - PdfAction? _gotFocus; - PdfAction? _lostFocus; - - //Properties - /// Gets or sets the action to be performed when the cursor - /// enters the annotation’s - PdfAction? get mouseEnter => _mouseEnter; - set mouseEnter(PdfAction? value) { - if (value != null && _mouseEnter != value) { - _mouseEnter = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.e, _mouseEnter); - } - } - - /// Gets or sets the action to be performed when the cursor - /// exits the annotation’s - PdfAction? get mouseLeave => _mouseLeave; - set mouseLeave(PdfAction? value) { - if (value != null && _mouseLeave != value) { - _mouseLeave = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.x, _mouseLeave); - } - } - - /// Gets or sets the action to be performed when the mouse button is pressed - /// inside the annotation’s active area. - PdfAction? get mouseDown => _mouseDown; - set mouseDown(PdfAction? value) { - if (value != null && _mouseDown != value) { - _mouseDown = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.d, _mouseDown); - } - } - - /// Gets or sets the action to be performed when the mouse button is released - PdfAction? get mouseUp => _mouseUp; - set mouseUp(PdfAction? value) { - if (value != null && _mouseUp != value) { - _mouseUp = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.u, _mouseUp); - } - } - - /// Gets or sets the action to be performed when the annotation receives - /// the input focus. - PdfAction? get gotFocus => _gotFocus; - set gotFocus(PdfAction? value) { - if (value != null && _gotFocus != value) { - _gotFocus = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.fo, _gotFocus); - } - } - - /// Gets or sets the action to be performed when the annotation loses the - /// input focus. - PdfAction? get lostFocus => _lostFocus; - set lostFocus(PdfAction? value) { - if (value != null && _lostFocus != value) { - _lostFocus = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.bl, _lostFocus); - } - } - - // Implementation - void _initValues( - PdfAction? mEnter, - PdfAction? mLeave, - PdfAction? mUp, - PdfAction? mDown, - PdfAction? gotF, - PdfAction? lostF, - ) { - if (mEnter != null) { - mouseEnter = mEnter; - } - if (mLeave != null) { - mouseLeave = mLeave; - } - if (mUp != null) { - mouseUp = mUp; - } - if (mDown != null) { - mouseDown = mDown; - } - if (gotF != null) { - gotFocus = gotF; - } - if (lostF != null) { - lostFocus = lostF; - } - } -} - -/// [PdfAnnotationActions] helper -class PdfAnnotationActionsHelper { - /// internal constructor - PdfAnnotationActionsHelper([PdfDictionary? dictionary]) { - this.dictionary = (dictionary != null) ? dictionary : PdfDictionary(); - } - - /// internal field - PdfDictionary? dictionary; - - /// internal property - IPdfPrimitive? get element => dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } - - /// internal method - static PdfAnnotationActionsHelper getHelper( - PdfAnnotationActions annotationActions, - ) { - return annotationActions._helper; - } - - /// internal method - static PdfAnnotationActions load(PdfDictionary? dictionary) { - return PdfAnnotationActions._loaded(dictionary); - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import 'pdf_action.dart'; + +/// Represents additional actions of the annotations. +class PdfAnnotationActions implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfAnnotationActions] class. + PdfAnnotationActions({ + PdfAction? mouseEnter, + PdfAction? mouseLeave, + PdfAction? mouseUp, + PdfAction? mouseDown, + PdfAction? gotFocus, + PdfAction? lostFocus, + }) { + _helper = PdfAnnotationActionsHelper(); + _initValues( + mouseEnter, + mouseLeave, + mouseUp, + mouseDown, + gotFocus, + lostFocus, + ); + } + + PdfAnnotationActions._loaded(PdfDictionary? dictionary) { + _helper = PdfAnnotationActionsHelper(dictionary); + } + + //Fields + late PdfAnnotationActionsHelper _helper; + PdfAction? _mouseEnter; + PdfAction? _mouseLeave; + PdfAction? _mouseDown; + PdfAction? _mouseUp; + PdfAction? _gotFocus; + PdfAction? _lostFocus; + + //Properties + /// Gets or sets the action to be performed when the cursor + /// enters the annotation’s + PdfAction? get mouseEnter => _mouseEnter; + set mouseEnter(PdfAction? value) { + if (value != null && _mouseEnter != value) { + _mouseEnter = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.e, _mouseEnter); + } + } + + /// Gets or sets the action to be performed when the cursor + /// exits the annotation’s + PdfAction? get mouseLeave => _mouseLeave; + set mouseLeave(PdfAction? value) { + if (value != null && _mouseLeave != value) { + _mouseLeave = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.x, _mouseLeave); + } + } + + /// Gets or sets the action to be performed when the mouse button is pressed + /// inside the annotation’s active area. + PdfAction? get mouseDown => _mouseDown; + set mouseDown(PdfAction? value) { + if (value != null && _mouseDown != value) { + _mouseDown = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.d, _mouseDown); + } + } + + /// Gets or sets the action to be performed when the mouse button is released + PdfAction? get mouseUp => _mouseUp; + set mouseUp(PdfAction? value) { + if (value != null && _mouseUp != value) { + _mouseUp = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.u, _mouseUp); + } + } + + /// Gets or sets the action to be performed when the annotation receives + /// the input focus. + PdfAction? get gotFocus => _gotFocus; + set gotFocus(PdfAction? value) { + if (value != null && _gotFocus != value) { + _gotFocus = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.fo, _gotFocus); + } + } + + /// Gets or sets the action to be performed when the annotation loses the + /// input focus. + PdfAction? get lostFocus => _lostFocus; + set lostFocus(PdfAction? value) { + if (value != null && _lostFocus != value) { + _lostFocus = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.bl, _lostFocus); + } + } + + // Implementation + void _initValues( + PdfAction? mEnter, + PdfAction? mLeave, + PdfAction? mUp, + PdfAction? mDown, + PdfAction? gotF, + PdfAction? lostF, + ) { + if (mEnter != null) { + mouseEnter = mEnter; + } + if (mLeave != null) { + mouseLeave = mLeave; + } + if (mUp != null) { + mouseUp = mUp; + } + if (mDown != null) { + mouseDown = mDown; + } + if (gotF != null) { + gotFocus = gotF; + } + if (lostF != null) { + lostFocus = lostF; + } + } +} + +/// [PdfAnnotationActions] helper +class PdfAnnotationActionsHelper { + /// internal constructor + PdfAnnotationActionsHelper([PdfDictionary? dictionary]) { + this.dictionary = (dictionary != null) ? dictionary : PdfDictionary(); + } + + /// internal field + PdfDictionary? dictionary; + + /// internal property + IPdfPrimitive? get element => dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } + + /// internal method + static PdfAnnotationActionsHelper getHelper( + PdfAnnotationActions annotationActions, + ) { + return annotationActions._helper; + } + + /// internal method + static PdfAnnotationActions load(PdfDictionary? dictionary) { + return PdfAnnotationActions._loaded(dictionary); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_field_actions.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_field_actions.dart index e29276a38..94e893dbf 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_field_actions.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_field_actions.dart @@ -1,232 +1,232 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_action.dart'; -import 'pdf_annotation_action.dart'; - -/// Represents actions to be performed as response to field events. -class PdfFieldActions implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfFieldActions] class with - /// the [PdfAnnotationActions] - PdfFieldActions( - PdfAnnotationActions annotationActions, { - PdfJavaScriptAction? keyPressed, - PdfJavaScriptAction? format, - PdfJavaScriptAction? validate, - PdfJavaScriptAction? calculate, - }) { - _helper.annotationActions = annotationActions; - _initValues(keyPressed, format, validate, calculate); - } - - PdfFieldActions._loaded(PdfDictionary dictionary) { - _helper.dictionary = dictionary; - _helper.annotationActions = PdfAnnotationActionsHelper.load(dictionary); - } - - //Fields - final PdfFieldActionsHelper _helper = PdfFieldActionsHelper(); - PdfJavaScriptAction? _keyPressed; - PdfJavaScriptAction? _format; - PdfJavaScriptAction? _validate; - PdfJavaScriptAction? _calculate; - - //Properties - /// Gets or sets the JavaScript action to be performed when - /// the user types a keystroke - PdfJavaScriptAction? get keyPressed => _keyPressed; - set keyPressed(PdfJavaScriptAction? value) { - if (value != null && _keyPressed != value) { - _keyPressed = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.k, _keyPressed); - _helper.changed = true; - } - } - - /// Gets or sets the JavaScript action to be performed before - /// the field is formatted - PdfJavaScriptAction? get format => _format; - set format(PdfJavaScriptAction? value) { - if (value != null && _format != value) { - _format = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.f, _format); - _helper.changed = true; - } - } - - /// Gets or sets the JavaScript action to be performed when - /// the field’s value is changed. - PdfJavaScriptAction? get validate => _validate; - set validate(PdfJavaScriptAction? value) { - if (value != null && _validate != value) { - _validate = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.v, _validate); - _helper.changed = true; - } - } - - /// Gets or sets the JavaScript action to be performed to recalculate - /// the value of this field when that of another field changes. - PdfJavaScriptAction? get calculate => _calculate; - set calculate(PdfJavaScriptAction? value) { - if (value != null && _calculate != value) { - _calculate = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.c, _calculate); - _helper.changed = true; - } - } - - /// Gets or sets the action to be performed when the mouse cursor enters - /// the fields’s area. - PdfAction? get mouseEnter => _helper.annotationActions.mouseEnter; - set mouseEnter(PdfAction? value) { - if (value != null) { - _helper.annotationActions.mouseEnter = value; - _helper.changed = true; - } - } - - /// Gets or sets the action to be performed when the cursor exits - /// the fields’s area. - PdfAction? get mouseLeave => _helper.annotationActions.mouseLeave; - set mouseLeave(PdfAction? value) { - if (value != null) { - _helper.annotationActions.mouseLeave = value; - _helper.changed = true; - } - } - - /// Gets or sets the action to be performed when the mouse button is released - /// inside the field’s area. - PdfAction? get mouseUp => _helper.annotationActions.mouseUp; - set mouseUp(PdfAction? value) { - if (value != null) { - _helper.annotationActions.mouseUp = value; - _helper.changed = true; - } - } - - /// Gets or sets the action to be performed when the mouse button is pressed inside the - /// field’s area. - PdfAction? get mouseDown => _helper.annotationActions.mouseDown; - set mouseDown(PdfAction? value) { - if (value != null) { - _helper.annotationActions.mouseDown = value; - _helper.changed = true; - } - } - - /// Gets or sets the action to be performed when the field receives the - /// input focus. - PdfAction? get gotFocus => _helper.annotationActions.gotFocus; - set gotFocus(PdfAction? value) { - if (value != null) { - _helper.annotationActions.gotFocus = value; - _helper.changed = true; - } - } - - /// Gets or sets the action to be performed when the field loses the - /// input focus. - PdfAction? get lostFocus => _helper.annotationActions.lostFocus; - set lostFocus(PdfAction? value) { - if (value != null) { - _helper.annotationActions.lostFocus = value; - _helper.changed = true; - } - } - - // Implementation - void _initValues( - PdfJavaScriptAction? keyPress, - PdfJavaScriptAction? fmt, - PdfJavaScriptAction? val, - PdfJavaScriptAction? cal, - ) { - if (keyPress != null) { - keyPressed = keyPress; - } - if (fmt != null) { - format = fmt; - } - if (val != null) { - validate = val; - } - if (cal != null) { - calculate = cal; - } - } -} - -/// [PdfFieldActions] helper -class PdfFieldActionsHelper { - /// internal field - bool changed = false; - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal field - late PdfAnnotationActions annotationActions; - - /// internal property - IPdfPrimitive? get element => dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } - - /// internal method - static PdfFieldActionsHelper getHelper(PdfFieldActions fieldActions) { - return fieldActions._helper; - } - - /// internal method - static PdfFieldActions load(PdfDictionary dictionary) { - return PdfFieldActions._loaded(dictionary); - } -} - -/// Represents an java script action in PDF document. -class PdfJavaScriptAction extends PdfAction { - //Constructor - /// Initializes a new instance of the [PdfJavaScriptAction] class with - /// the java script code - PdfJavaScriptAction(String javaScript) : super() { - _initValue(javaScript); - PdfActionHelper.getHelper(this).dictionary.setProperty( - PdfDictionaryProperties.s, - PdfName(PdfDictionaryProperties.javaScript), - ); - PdfActionHelper.getHelper(this).dictionary.setProperty( - PdfDictionaryProperties.js, - PdfString(_javaScript), - ); - } - - //Fields - String _javaScript = ''; - - //Properties - /// Gets or sets the javascript code to be executed when - /// this action is executed. - String get javaScript => _javaScript; - set javaScript(String value) { - if (_javaScript != value) { - _javaScript = value; - PdfActionHelper.getHelper( - this, - ).dictionary.setString(PdfDictionaryProperties.js, _javaScript); - } - } - - // ignore: use_setters_to_change_properties - void _initValue(String js) { - javaScript = js; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_action.dart'; +import 'pdf_annotation_action.dart'; + +/// Represents actions to be performed as response to field events. +class PdfFieldActions implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfFieldActions] class with + /// the [PdfAnnotationActions] + PdfFieldActions( + PdfAnnotationActions annotationActions, { + PdfJavaScriptAction? keyPressed, + PdfJavaScriptAction? format, + PdfJavaScriptAction? validate, + PdfJavaScriptAction? calculate, + }) { + _helper.annotationActions = annotationActions; + _initValues(keyPressed, format, validate, calculate); + } + + PdfFieldActions._loaded(PdfDictionary dictionary) { + _helper.dictionary = dictionary; + _helper.annotationActions = PdfAnnotationActionsHelper.load(dictionary); + } + + //Fields + final PdfFieldActionsHelper _helper = PdfFieldActionsHelper(); + PdfJavaScriptAction? _keyPressed; + PdfJavaScriptAction? _format; + PdfJavaScriptAction? _validate; + PdfJavaScriptAction? _calculate; + + //Properties + /// Gets or sets the JavaScript action to be performed when + /// the user types a keystroke + PdfJavaScriptAction? get keyPressed => _keyPressed; + set keyPressed(PdfJavaScriptAction? value) { + if (value != null && _keyPressed != value) { + _keyPressed = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.k, _keyPressed); + _helper.changed = true; + } + } + + /// Gets or sets the JavaScript action to be performed before + /// the field is formatted + PdfJavaScriptAction? get format => _format; + set format(PdfJavaScriptAction? value) { + if (value != null && _format != value) { + _format = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.f, _format); + _helper.changed = true; + } + } + + /// Gets or sets the JavaScript action to be performed when + /// the field’s value is changed. + PdfJavaScriptAction? get validate => _validate; + set validate(PdfJavaScriptAction? value) { + if (value != null && _validate != value) { + _validate = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.v, _validate); + _helper.changed = true; + } + } + + /// Gets or sets the JavaScript action to be performed to recalculate + /// the value of this field when that of another field changes. + PdfJavaScriptAction? get calculate => _calculate; + set calculate(PdfJavaScriptAction? value) { + if (value != null && _calculate != value) { + _calculate = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.c, _calculate); + _helper.changed = true; + } + } + + /// Gets or sets the action to be performed when the mouse cursor enters + /// the fields’s area. + PdfAction? get mouseEnter => _helper.annotationActions.mouseEnter; + set mouseEnter(PdfAction? value) { + if (value != null) { + _helper.annotationActions.mouseEnter = value; + _helper.changed = true; + } + } + + /// Gets or sets the action to be performed when the cursor exits + /// the fields’s area. + PdfAction? get mouseLeave => _helper.annotationActions.mouseLeave; + set mouseLeave(PdfAction? value) { + if (value != null) { + _helper.annotationActions.mouseLeave = value; + _helper.changed = true; + } + } + + /// Gets or sets the action to be performed when the mouse button is released + /// inside the field’s area. + PdfAction? get mouseUp => _helper.annotationActions.mouseUp; + set mouseUp(PdfAction? value) { + if (value != null) { + _helper.annotationActions.mouseUp = value; + _helper.changed = true; + } + } + + /// Gets or sets the action to be performed when the mouse button is pressed inside the + /// field’s area. + PdfAction? get mouseDown => _helper.annotationActions.mouseDown; + set mouseDown(PdfAction? value) { + if (value != null) { + _helper.annotationActions.mouseDown = value; + _helper.changed = true; + } + } + + /// Gets or sets the action to be performed when the field receives the + /// input focus. + PdfAction? get gotFocus => _helper.annotationActions.gotFocus; + set gotFocus(PdfAction? value) { + if (value != null) { + _helper.annotationActions.gotFocus = value; + _helper.changed = true; + } + } + + /// Gets or sets the action to be performed when the field loses the + /// input focus. + PdfAction? get lostFocus => _helper.annotationActions.lostFocus; + set lostFocus(PdfAction? value) { + if (value != null) { + _helper.annotationActions.lostFocus = value; + _helper.changed = true; + } + } + + // Implementation + void _initValues( + PdfJavaScriptAction? keyPress, + PdfJavaScriptAction? fmt, + PdfJavaScriptAction? val, + PdfJavaScriptAction? cal, + ) { + if (keyPress != null) { + keyPressed = keyPress; + } + if (fmt != null) { + format = fmt; + } + if (val != null) { + validate = val; + } + if (cal != null) { + calculate = cal; + } + } +} + +/// [PdfFieldActions] helper +class PdfFieldActionsHelper { + /// internal field + bool changed = false; + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal field + late PdfAnnotationActions annotationActions; + + /// internal property + IPdfPrimitive? get element => dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } + + /// internal method + static PdfFieldActionsHelper getHelper(PdfFieldActions fieldActions) { + return fieldActions._helper; + } + + /// internal method + static PdfFieldActions load(PdfDictionary dictionary) { + return PdfFieldActions._loaded(dictionary); + } +} + +/// Represents an java script action in PDF document. +class PdfJavaScriptAction extends PdfAction { + //Constructor + /// Initializes a new instance of the [PdfJavaScriptAction] class with + /// the java script code + PdfJavaScriptAction(String javaScript) : super() { + _initValue(javaScript); + PdfActionHelper.getHelper(this).dictionary.setProperty( + PdfDictionaryProperties.s, + PdfName(PdfDictionaryProperties.javaScript), + ); + PdfActionHelper.getHelper(this).dictionary.setProperty( + PdfDictionaryProperties.js, + PdfString(_javaScript), + ); + } + + //Fields + String _javaScript = ''; + + //Properties + /// Gets or sets the javascript code to be executed when + /// this action is executed. + String get javaScript => _javaScript; + set javaScript(String value) { + if (_javaScript != value) { + _javaScript = value; + PdfActionHelper.getHelper( + this, + ).dictionary.setString(PdfDictionaryProperties.js, _javaScript); + } + } + + // ignore: use_setters_to_change_properties + void _initValue(String js) { + javaScript = js; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_submit_action.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_submit_action.dart index 7552d0a49..bde70c7b1 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_submit_action.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_submit_action.dart @@ -1,374 +1,374 @@ -import '../annotations/enum.dart'; -import '../forms/pdf_field.dart'; -import '../forms/pdf_form_field_collection.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_action.dart'; - -/// Represents PDF form's submit action.submit action allows submission of data -/// that is entered in the PDF form -class PdfSubmitAction extends PdfFormAction { - //Constructor - /// Initializes a new instance of the [PdfSubmitAction] class with - /// URL to submit the form data - PdfSubmitAction( - String url, { - HttpMethod httpMethod = HttpMethod.post, - SubmitDataFormat dataFormat = SubmitDataFormat.fdf, - bool canonicalDateTimeFormat = false, - bool submitCoordinates = false, - bool includeNoValueFields = false, - bool includeIncrementalUpdates = false, - bool includeAnnotations = false, - bool excludeNonUserAnnotations = false, - bool embedForm = false, - bool include = false, - List? fields, - }) : super._() { - final PdfActionHelper helper = PdfActionHelper.getHelper(this); - helper.dictionary.beginSave = _dictionaryBeginSave; - helper.dictionary.setProperty( - PdfDictionaryProperties.s, - PdfName(PdfDictionaryProperties.submitForm), - ); - if (url.isEmpty) { - ArgumentError.value("The URL can't be an empty string."); - } - _url = url; - helper.dictionary.setProperty(PdfDictionaryProperties.f, PdfString(_url)); - _initValues( - httpMethod = HttpMethod.post, - dataFormat, - canonicalDateTimeFormat, - submitCoordinates, - includeNoValueFields, - includeIncrementalUpdates, - includeAnnotations, - excludeNonUserAnnotations, - embedForm, - include, - fields, - ); - } - - //Fields - String _url = ''; - HttpMethod _httpMethod = HttpMethod.post; - SubmitDataFormat _dataFormat = SubmitDataFormat.fdf; - final List _flags = []; - bool _canonicalDateTimeFormat = false; - bool _submitCoordinates = false; - bool _includeNoValueFields = false; - bool _includeIncrementalUpdates = false; - bool _includeAnnotations = false; - bool _excludeNonUserAnnotations = false; - bool _embedForm = false; - - //Properties - /// Gets an Url address where the data should be transferred. - String get url => _url; - - /// Gets or sets the [SubmitDataFormat]. - SubmitDataFormat get dataFormat => _dataFormat; - set dataFormat(SubmitDataFormat value) { - if (_dataFormat != value) { - _dataFormat = value; - switch (_dataFormat) { - case SubmitDataFormat.pdf: - _flags.add(PdfSubmitFormFlags.submitPdf); - break; - case SubmitDataFormat.xfdf: - _flags.add(PdfSubmitFormFlags.xfdf); - break; - case SubmitDataFormat.html: - _flags.add(PdfSubmitFormFlags.exportFormat); - break; - case SubmitDataFormat.fdf: - break; - } - } - } - - /// Gets or sets the HTTP method. - HttpMethod get httpMethod => _httpMethod; - set httpMethod(HttpMethod value) { - if (_httpMethod != value) { - _httpMethod = value; - if (_httpMethod == HttpMethod.getHttp) { - _flags.add(PdfSubmitFormFlags.getMethod); - } else { - _flags.remove(PdfSubmitFormFlags.getMethod); - } - } - } - - /// If set, any submitted field values representing dates are converted to - /// the standard format. - bool get canonicalDateTimeFormat => _canonicalDateTimeFormat; - set canonicalDateTimeFormat(bool value) { - if (_canonicalDateTimeFormat != value) { - _canonicalDateTimeFormat = value; - - if (_canonicalDateTimeFormat) { - _flags.add(PdfSubmitFormFlags.canonicalFormat); - } else { - _flags.remove(PdfSubmitFormFlags.canonicalFormat); - } - } - } - - /// Gets or sets a value indicating whether to submit mouse pointer coordinates. - bool get submitCoordinates => _submitCoordinates; - set submitCoordinates(bool value) { - if (_submitCoordinates != value) { - _submitCoordinates = value; - - if (_submitCoordinates) { - _flags.add(PdfSubmitFormFlags.submitCoordinates); - } else { - _flags.remove(PdfSubmitFormFlags.submitCoordinates); - } - } - } - - /// Gets or sets a value indicating whether to submit fields without value. - bool get includeNoValueFields => _includeNoValueFields; - set includeNoValueFields(bool value) { - if (_includeNoValueFields != value) { - _includeNoValueFields = value; - - if (_includeNoValueFields) { - _flags.add(PdfSubmitFormFlags.includeNoValueFields); - } else { - _flags.remove(PdfSubmitFormFlags.includeNoValueFields); - } - } - } - - /// Gets or sets a value indicating whether to submit - /// form's incremental updates. - bool get includeIncrementalUpdates => _includeIncrementalUpdates; - set includeIncrementalUpdates(bool value) { - if (_includeIncrementalUpdates != value) { - _includeIncrementalUpdates = value; - - if (_includeIncrementalUpdates) { - _flags.add(PdfSubmitFormFlags.includeAppendSaves); - } else { - _flags.remove(PdfSubmitFormFlags.includeAppendSaves); - } - } - } - - /// Gets or sets a value indicating whether to submit annotations. - bool get includeAnnotations => _includeAnnotations; - set includeAnnotations(bool value) { - if (_includeAnnotations != value) { - _includeAnnotations = value; - - if (_includeAnnotations) { - _flags.add(PdfSubmitFormFlags.includeAnnotations); - } else { - _flags.remove(PdfSubmitFormFlags.includeAnnotations); - } - } - } - - /// Gets or sets a value indicating whether to exclude non user annotations - /// form submit data stream. - bool get excludeNonUserAnnotations => _excludeNonUserAnnotations; - set excludeNonUserAnnotations(bool value) { - if (_excludeNonUserAnnotations != value) { - _excludeNonUserAnnotations = value; - - if (_excludeNonUserAnnotations) { - _flags.add(PdfSubmitFormFlags.exclNonUserAnnots); - } else { - _flags.remove(PdfSubmitFormFlags.exclNonUserAnnots); - } - } - } - - /// Gets or sets a value indicating whether to include form - /// to submit data stream. - bool get embedForm => _embedForm; - set embedForm(bool value) { - if (_embedForm != value) { - _embedForm = value; - if (_embedForm) { - _flags.add(PdfSubmitFormFlags.embedForm); - } else { - _flags.remove(PdfSubmitFormFlags.embedForm); - } - } - } - - @override - set include(bool value) { - if (super.include != value) { - super.include = value; - if (super.include) { - _flags.remove(PdfSubmitFormFlags.includeExclude); - } else { - _flags.add(PdfSubmitFormFlags.includeExclude); - } - } - } - - void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - PdfActionHelper.getHelper(this).dictionary.setProperty( - PdfDictionaryProperties.flags, - PdfNumber(_getFlagValue(_flags)), - ); - } - - void _initValues( - HttpMethod http, - SubmitDataFormat format, - bool canonicalDateTime, - bool submit, - bool includeNoValue, - bool includeIncremental, - bool includeAnnot, - bool excludeNonUserAnnot, - bool embed, - bool initInclude, - List? field, - ) { - httpMethod = http; - dataFormat = format; - canonicalDateTimeFormat = canonicalDateTime; - submitCoordinates = submit; - includeNoValueFields = includeNoValue; - includeIncrementalUpdates = includeIncremental; - includeAnnotations = includeAnnot; - excludeNonUserAnnotations = excludeNonUserAnnot; - embedForm = embed; - include = initInclude; - if (field != null) { - // ignore: avoid_function_literals_in_foreach_calls - field.forEach((PdfField f) => fields.add(f)); - } - } - - int _getFlagValue(List sumbitFlags) { - int result = 0; - for (final PdfSubmitFormFlags sumbitFlag in sumbitFlags) { - switch (sumbitFlag) { - case PdfSubmitFormFlags.includeExclude: - result = result + 1; - break; - case PdfSubmitFormFlags.includeNoValueFields: - result = result + 2; - break; - case PdfSubmitFormFlags.exportFormat: - result = result + 4; - break; - case PdfSubmitFormFlags.getMethod: - result = result + 8; - break; - case PdfSubmitFormFlags.submitCoordinates: - result = result + 16; - break; - case PdfSubmitFormFlags.xfdf: - result = result + 32; - break; - case PdfSubmitFormFlags.includeAppendSaves: - result = result + 64; - break; - case PdfSubmitFormFlags.includeAnnotations: - result = result + 128; - break; - case PdfSubmitFormFlags.submitPdf: - result = result + 256; - break; - case PdfSubmitFormFlags.canonicalFormat: - result = result + 512; - break; - case PdfSubmitFormFlags.exclNonUserAnnots: - result = result + 1024; - break; - case PdfSubmitFormFlags.exclFKey: - result = result + 2048; - break; - case PdfSubmitFormFlags.embedForm: - result = result + 4096; - break; - } - } - return result; - } -} - -/// Represents the action on form fields. -class PdfFormAction extends PdfAction { - //Constrcutor - /// Initializes a new instance of the [PdfFormAction] class. - PdfFormAction._() : super(); - - //Fields - PdfFormFieldCollection? _fields; - - /// Gets or sets a value indicating whether fields contained in the fields - /// collection will be included for resetting or submitting. - /// - /// If the [include] property is true, only the fields in this collection - /// will be reset or submitted. - /// If the [include] property is false, the fields in this collection - /// are not reset or submitted and only the remaining form fields are - /// reset or submitted. - /// If the collection is empty, then all the form fields are reset - /// and the [include] property is ignored. - bool include = false; - - ///Gets the fields. - PdfFormFieldCollection get fields { - if (_fields == null) { - _fields = PdfFormFieldCollectionHelper.getCollection(); - PdfActionHelper.getHelper( - this, - ).dictionary.setProperty(PdfDictionaryProperties.fields, _fields); - } - PdfFormFieldCollectionHelper.getHelper(_fields!).isAction = true; - return _fields!; - } -} - -/// Represents PDF form's reset action,this action allows a user to reset -/// the form fields to their default values. -class PdfResetAction extends PdfFormAction { - //Constructor - /// Initializes a new instance of the [PdfResetAction] class. - PdfResetAction({bool? include, List? fields}) : super._() { - PdfActionHelper.getHelper(this).dictionary.setProperty( - PdfDictionaryProperties.s, - PdfName(PdfDictionaryProperties.resetForm), - ); - _initValues(include, fields); - } - - //Properties - @override - set include(bool value) { - if (super.include != value) { - super.include = value; - PdfActionHelper.getHelper(this).dictionary.setNumber( - PdfDictionaryProperties.flags, - super.include ? 0 : 1, - ); - } - } - - void _initValues(bool? initInclude, List? field) { - if (initInclude != null) { - include = initInclude; - } - if (field != null) { - // ignore: avoid_function_literals_in_foreach_calls - field.forEach((PdfField f) => fields.add(f)); - } - } -} +import '../annotations/enum.dart'; +import '../forms/pdf_field.dart'; +import '../forms/pdf_form_field_collection.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_action.dart'; + +/// Represents PDF form's submit action.submit action allows submission of data +/// that is entered in the PDF form +class PdfSubmitAction extends PdfFormAction { + //Constructor + /// Initializes a new instance of the [PdfSubmitAction] class with + /// URL to submit the form data + PdfSubmitAction( + String url, { + HttpMethod httpMethod = HttpMethod.post, + SubmitDataFormat dataFormat = SubmitDataFormat.fdf, + bool canonicalDateTimeFormat = false, + bool submitCoordinates = false, + bool includeNoValueFields = false, + bool includeIncrementalUpdates = false, + bool includeAnnotations = false, + bool excludeNonUserAnnotations = false, + bool embedForm = false, + bool include = false, + List? fields, + }) : super._() { + final PdfActionHelper helper = PdfActionHelper.getHelper(this); + helper.dictionary.beginSave = _dictionaryBeginSave; + helper.dictionary.setProperty( + PdfDictionaryProperties.s, + PdfName(PdfDictionaryProperties.submitForm), + ); + if (url.isEmpty) { + ArgumentError.value("The URL can't be an empty string."); + } + _url = url; + helper.dictionary.setProperty(PdfDictionaryProperties.f, PdfString(_url)); + _initValues( + httpMethod = HttpMethod.post, + dataFormat, + canonicalDateTimeFormat, + submitCoordinates, + includeNoValueFields, + includeIncrementalUpdates, + includeAnnotations, + excludeNonUserAnnotations, + embedForm, + include, + fields, + ); + } + + //Fields + String _url = ''; + HttpMethod _httpMethod = HttpMethod.post; + SubmitDataFormat _dataFormat = SubmitDataFormat.fdf; + final List _flags = []; + bool _canonicalDateTimeFormat = false; + bool _submitCoordinates = false; + bool _includeNoValueFields = false; + bool _includeIncrementalUpdates = false; + bool _includeAnnotations = false; + bool _excludeNonUserAnnotations = false; + bool _embedForm = false; + + //Properties + /// Gets an Url address where the data should be transferred. + String get url => _url; + + /// Gets or sets the [SubmitDataFormat]. + SubmitDataFormat get dataFormat => _dataFormat; + set dataFormat(SubmitDataFormat value) { + if (_dataFormat != value) { + _dataFormat = value; + switch (_dataFormat) { + case SubmitDataFormat.pdf: + _flags.add(PdfSubmitFormFlags.submitPdf); + break; + case SubmitDataFormat.xfdf: + _flags.add(PdfSubmitFormFlags.xfdf); + break; + case SubmitDataFormat.html: + _flags.add(PdfSubmitFormFlags.exportFormat); + break; + case SubmitDataFormat.fdf: + break; + } + } + } + + /// Gets or sets the HTTP method. + HttpMethod get httpMethod => _httpMethod; + set httpMethod(HttpMethod value) { + if (_httpMethod != value) { + _httpMethod = value; + if (_httpMethod == HttpMethod.getHttp) { + _flags.add(PdfSubmitFormFlags.getMethod); + } else { + _flags.remove(PdfSubmitFormFlags.getMethod); + } + } + } + + /// If set, any submitted field values representing dates are converted to + /// the standard format. + bool get canonicalDateTimeFormat => _canonicalDateTimeFormat; + set canonicalDateTimeFormat(bool value) { + if (_canonicalDateTimeFormat != value) { + _canonicalDateTimeFormat = value; + + if (_canonicalDateTimeFormat) { + _flags.add(PdfSubmitFormFlags.canonicalFormat); + } else { + _flags.remove(PdfSubmitFormFlags.canonicalFormat); + } + } + } + + /// Gets or sets a value indicating whether to submit mouse pointer coordinates. + bool get submitCoordinates => _submitCoordinates; + set submitCoordinates(bool value) { + if (_submitCoordinates != value) { + _submitCoordinates = value; + + if (_submitCoordinates) { + _flags.add(PdfSubmitFormFlags.submitCoordinates); + } else { + _flags.remove(PdfSubmitFormFlags.submitCoordinates); + } + } + } + + /// Gets or sets a value indicating whether to submit fields without value. + bool get includeNoValueFields => _includeNoValueFields; + set includeNoValueFields(bool value) { + if (_includeNoValueFields != value) { + _includeNoValueFields = value; + + if (_includeNoValueFields) { + _flags.add(PdfSubmitFormFlags.includeNoValueFields); + } else { + _flags.remove(PdfSubmitFormFlags.includeNoValueFields); + } + } + } + + /// Gets or sets a value indicating whether to submit + /// form's incremental updates. + bool get includeIncrementalUpdates => _includeIncrementalUpdates; + set includeIncrementalUpdates(bool value) { + if (_includeIncrementalUpdates != value) { + _includeIncrementalUpdates = value; + + if (_includeIncrementalUpdates) { + _flags.add(PdfSubmitFormFlags.includeAppendSaves); + } else { + _flags.remove(PdfSubmitFormFlags.includeAppendSaves); + } + } + } + + /// Gets or sets a value indicating whether to submit annotations. + bool get includeAnnotations => _includeAnnotations; + set includeAnnotations(bool value) { + if (_includeAnnotations != value) { + _includeAnnotations = value; + + if (_includeAnnotations) { + _flags.add(PdfSubmitFormFlags.includeAnnotations); + } else { + _flags.remove(PdfSubmitFormFlags.includeAnnotations); + } + } + } + + /// Gets or sets a value indicating whether to exclude non user annotations + /// form submit data stream. + bool get excludeNonUserAnnotations => _excludeNonUserAnnotations; + set excludeNonUserAnnotations(bool value) { + if (_excludeNonUserAnnotations != value) { + _excludeNonUserAnnotations = value; + + if (_excludeNonUserAnnotations) { + _flags.add(PdfSubmitFormFlags.exclNonUserAnnots); + } else { + _flags.remove(PdfSubmitFormFlags.exclNonUserAnnots); + } + } + } + + /// Gets or sets a value indicating whether to include form + /// to submit data stream. + bool get embedForm => _embedForm; + set embedForm(bool value) { + if (_embedForm != value) { + _embedForm = value; + if (_embedForm) { + _flags.add(PdfSubmitFormFlags.embedForm); + } else { + _flags.remove(PdfSubmitFormFlags.embedForm); + } + } + } + + @override + set include(bool value) { + if (super.include != value) { + super.include = value; + if (super.include) { + _flags.remove(PdfSubmitFormFlags.includeExclude); + } else { + _flags.add(PdfSubmitFormFlags.includeExclude); + } + } + } + + void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + PdfActionHelper.getHelper(this).dictionary.setProperty( + PdfDictionaryProperties.flags, + PdfNumber(_getFlagValue(_flags)), + ); + } + + void _initValues( + HttpMethod http, + SubmitDataFormat format, + bool canonicalDateTime, + bool submit, + bool includeNoValue, + bool includeIncremental, + bool includeAnnot, + bool excludeNonUserAnnot, + bool embed, + bool initInclude, + List? field, + ) { + httpMethod = http; + dataFormat = format; + canonicalDateTimeFormat = canonicalDateTime; + submitCoordinates = submit; + includeNoValueFields = includeNoValue; + includeIncrementalUpdates = includeIncremental; + includeAnnotations = includeAnnot; + excludeNonUserAnnotations = excludeNonUserAnnot; + embedForm = embed; + include = initInclude; + if (field != null) { + // ignore: avoid_function_literals_in_foreach_calls + field.forEach((PdfField f) => fields.add(f)); + } + } + + int _getFlagValue(List sumbitFlags) { + int result = 0; + for (final PdfSubmitFormFlags sumbitFlag in sumbitFlags) { + switch (sumbitFlag) { + case PdfSubmitFormFlags.includeExclude: + result = result + 1; + break; + case PdfSubmitFormFlags.includeNoValueFields: + result = result + 2; + break; + case PdfSubmitFormFlags.exportFormat: + result = result + 4; + break; + case PdfSubmitFormFlags.getMethod: + result = result + 8; + break; + case PdfSubmitFormFlags.submitCoordinates: + result = result + 16; + break; + case PdfSubmitFormFlags.xfdf: + result = result + 32; + break; + case PdfSubmitFormFlags.includeAppendSaves: + result = result + 64; + break; + case PdfSubmitFormFlags.includeAnnotations: + result = result + 128; + break; + case PdfSubmitFormFlags.submitPdf: + result = result + 256; + break; + case PdfSubmitFormFlags.canonicalFormat: + result = result + 512; + break; + case PdfSubmitFormFlags.exclNonUserAnnots: + result = result + 1024; + break; + case PdfSubmitFormFlags.exclFKey: + result = result + 2048; + break; + case PdfSubmitFormFlags.embedForm: + result = result + 4096; + break; + } + } + return result; + } +} + +/// Represents the action on form fields. +class PdfFormAction extends PdfAction { + //Constrcutor + /// Initializes a new instance of the [PdfFormAction] class. + PdfFormAction._() : super(); + + //Fields + PdfFormFieldCollection? _fields; + + /// Gets or sets a value indicating whether fields contained in the fields + /// collection will be included for resetting or submitting. + /// + /// If the [include] property is true, only the fields in this collection + /// will be reset or submitted. + /// If the [include] property is false, the fields in this collection + /// are not reset or submitted and only the remaining form fields are + /// reset or submitted. + /// If the collection is empty, then all the form fields are reset + /// and the [include] property is ignored. + bool include = false; + + ///Gets the fields. + PdfFormFieldCollection get fields { + if (_fields == null) { + _fields = PdfFormFieldCollectionHelper.getCollection(); + PdfActionHelper.getHelper( + this, + ).dictionary.setProperty(PdfDictionaryProperties.fields, _fields); + } + PdfFormFieldCollectionHelper.getHelper(_fields!).isAction = true; + return _fields!; + } +} + +/// Represents PDF form's reset action,this action allows a user to reset +/// the form fields to their default values. +class PdfResetAction extends PdfFormAction { + //Constructor + /// Initializes a new instance of the [PdfResetAction] class. + PdfResetAction({bool? include, List? fields}) : super._() { + PdfActionHelper.getHelper(this).dictionary.setProperty( + PdfDictionaryProperties.s, + PdfName(PdfDictionaryProperties.resetForm), + ); + _initValues(include, fields); + } + + //Properties + @override + set include(bool value) { + if (super.include != value) { + super.include = value; + PdfActionHelper.getHelper(this).dictionary.setNumber( + PdfDictionaryProperties.flags, + super.include ? 0 : 1, + ); + } + } + + void _initValues(bool? initInclude, List? field) { + if (initInclude != null) { + include = initInclude; + } + if (field != null) { + // ignore: avoid_function_literals_in_foreach_calls + field.forEach((PdfField f) => fields.add(f)); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_uri_action.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_uri_action.dart index f71dc1c50..6e0080486 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_uri_action.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/actions/pdf_uri_action.dart @@ -1,35 +1,35 @@ -import '../io/pdf_constants.dart'; -import '../primitives/pdf_name.dart'; -import 'pdf_action.dart'; - -/// Represents an action which resolves unique resource identifier. -class PdfUriAction extends PdfAction { - // constructor - /// Initializes a new instance of the [PdfUriAction] class. - /// - /// [uri] - the unique resource identifier. - PdfUriAction([String? uri]) : super() { - if (uri != null) { - this.uri = uri; - } - PdfActionHelper.getHelper(this).dictionary.setProperty( - PdfName(PdfDictionaryProperties.s), - PdfName(PdfDictionaryProperties.uri), - ); - } - - // fields - String _uri = ''; - - // proporties - /// Gets the unique resource identifier. - String get uri => _uri; - - /// Sets the unique resource identifier. - set uri(String value) { - _uri = value; - PdfActionHelper.getHelper( - this, - ).dictionary.setString(PdfDictionaryProperties.uri, _uri); - } -} +import '../io/pdf_constants.dart'; +import '../primitives/pdf_name.dart'; +import 'pdf_action.dart'; + +/// Represents an action which resolves unique resource identifier. +class PdfUriAction extends PdfAction { + // constructor + /// Initializes a new instance of the [PdfUriAction] class. + /// + /// [uri] - the unique resource identifier. + PdfUriAction([String? uri]) : super() { + if (uri != null) { + this.uri = uri; + } + PdfActionHelper.getHelper(this).dictionary.setProperty( + PdfName(PdfDictionaryProperties.s), + PdfName(PdfDictionaryProperties.uri), + ); + } + + // fields + String _uri = ''; + + // proporties + /// Gets the unique resource identifier. + String get uri => _uri; + + /// Sets the unique resource identifier. + set uri(String value) { + _uri = value; + PdfActionHelper.getHelper( + this, + ).dictionary.setString(PdfDictionaryProperties.uri, _uri); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_appearance_state.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_appearance_state.dart index 060c3a90d..d13f51f98 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_appearance_state.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_appearance_state.dart @@ -1,64 +1,64 @@ -import '../../../interfaces/pdf_interface.dart'; -import '../../graphics/figures/pdf_template.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_reference_holder.dart'; - -/// Represents the states of an annotation's appearance. -class PdfAppearanceState implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfAppearanceState] class. - PdfAppearanceState() : super() { - dictionary = PdfDictionary(); - dictionary!.beginSave = _dictionaryBeginSave; - } - - //Fields - /// internal fields - PdfDictionary? dictionary; - PdfTemplate? _on; - PdfTemplate? _off; - - /// internal fields - // ignore: prefer_final_fields - String onMappingName = PdfDictionaryProperties.yes; - static const String _offMappingName = PdfDictionaryProperties.off; - - //Properties - /// Gets the active state template. - PdfTemplate? get activate => _on; - - /// Sets the active state template. - set activate(PdfTemplate? value) { - if (value != _on) { - _on = value; - } - } - - /// Gets or sets the inactive state. - PdfTemplate? get off => _off; - set off(PdfTemplate? value) { - if (value != _off) { - _off = value; - } - } - - //Implementation - void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (_on != null) { - dictionary!.setProperty(onMappingName, PdfReferenceHolder(_on)); - } - if (_off != null) { - dictionary!.setProperty(_offMappingName, PdfReferenceHolder(_off)); - } - } - - /// internal property - IPdfPrimitive? get element => dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } -} +import '../../../interfaces/pdf_interface.dart'; +import '../../graphics/figures/pdf_template.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_reference_holder.dart'; + +/// Represents the states of an annotation's appearance. +class PdfAppearanceState implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfAppearanceState] class. + PdfAppearanceState() : super() { + dictionary = PdfDictionary(); + dictionary!.beginSave = _dictionaryBeginSave; + } + + //Fields + /// internal fields + PdfDictionary? dictionary; + PdfTemplate? _on; + PdfTemplate? _off; + + /// internal fields + // ignore: prefer_final_fields + String onMappingName = PdfDictionaryProperties.yes; + static const String _offMappingName = PdfDictionaryProperties.off; + + //Properties + /// Gets the active state template. + PdfTemplate? get activate => _on; + + /// Sets the active state template. + set activate(PdfTemplate? value) { + if (value != _on) { + _on = value; + } + } + + /// Gets or sets the inactive state. + PdfTemplate? get off => _off; + set off(PdfTemplate? value) { + if (value != _off) { + _off = value; + } + } + + //Implementation + void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (_on != null) { + dictionary!.setProperty(onMappingName, PdfReferenceHolder(_on)); + } + if (_off != null) { + dictionary!.setProperty(_offMappingName, PdfReferenceHolder(_off)); + } + } + + /// internal property + IPdfPrimitive? get element => dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_extended_appearance.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_extended_appearance.dart index 73d402c69..50563dcf5 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_extended_appearance.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/appearance/pdf_extended_appearance.dart @@ -1,64 +1,64 @@ -import '../../../interfaces/pdf_interface.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import 'pdf_appearance_state.dart'; - -/// Represents extended appearance of the annotation. It has two states such as On state and Off state. -class PdfExtendedAppearance implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfExtendedAppearance] class. - PdfExtendedAppearance() : super(); - - //Fields - PdfDictionary? _dictionary = PdfDictionary(); - PdfAppearanceState? _normal; - PdfAppearanceState? _pressed; - PdfAppearanceState? _mouseHover; - - //Properties - /// Gets the normal appearance of the annotation. - PdfAppearanceState get normal { - if (_normal == null) { - _normal = PdfAppearanceState(); - _dictionary!.setProperty( - PdfDictionaryProperties.n, - PdfReferenceHolder(_normal), - ); - } - return _normal!; - } - - /// Gets the appearance when mouse is hovered. - PdfAppearanceState get mouseHover { - if (_mouseHover == null) { - _mouseHover = PdfAppearanceState(); - _dictionary!.setProperty( - PdfDictionaryProperties.r, - PdfReferenceHolder(_mouseHover), - ); - } - return _mouseHover!; - } - - /// Gets the pressed state annotation. - PdfAppearanceState get pressed { - if (_pressed == null) { - _pressed = PdfAppearanceState(); - _dictionary!.setProperty( - PdfDictionaryProperties.d, - PdfReferenceHolder(_pressed), - ); - } - return _pressed!; - } - - /// internal property - IPdfPrimitive? get element => _dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - _dictionary = value; - } - } -} +import '../../../interfaces/pdf_interface.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import 'pdf_appearance_state.dart'; + +/// Represents extended appearance of the annotation. It has two states such as On state and Off state. +class PdfExtendedAppearance implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfExtendedAppearance] class. + PdfExtendedAppearance() : super(); + + //Fields + PdfDictionary? _dictionary = PdfDictionary(); + PdfAppearanceState? _normal; + PdfAppearanceState? _pressed; + PdfAppearanceState? _mouseHover; + + //Properties + /// Gets the normal appearance of the annotation. + PdfAppearanceState get normal { + if (_normal == null) { + _normal = PdfAppearanceState(); + _dictionary!.setProperty( + PdfDictionaryProperties.n, + PdfReferenceHolder(_normal), + ); + } + return _normal!; + } + + /// Gets the appearance when mouse is hovered. + PdfAppearanceState get mouseHover { + if (_mouseHover == null) { + _mouseHover = PdfAppearanceState(); + _dictionary!.setProperty( + PdfDictionaryProperties.r, + PdfReferenceHolder(_mouseHover), + ); + } + return _mouseHover!; + } + + /// Gets the pressed state annotation. + PdfAppearanceState get pressed { + if (_pressed == null) { + _pressed = PdfAppearanceState(); + _dictionary!.setProperty( + PdfDictionaryProperties.d, + PdfReferenceHolder(_pressed), + ); + } + return _pressed!; + } + + /// internal property + IPdfPrimitive? get element => _dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + _dictionary = value; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/enum.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/enum.dart index 12ade3fce..f7dc0e456 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/enum.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/enum.dart @@ -1,364 +1,364 @@ -/// Specifies the highlight mode for a field. -enum PdfHighlightMode { - /// No highlighting. - noHighlighting, - - /// Invert the contents of the field rectangle. - invert, - - /// Invert the field's border. - outline, - - /// Pushed highlighting. - push, -} - -/// Specifies the file path type. -enum PdfFilePathType { - /// Specifies the file location with out including the domain name. - relative, - - /// Specifies the location, including the domain name. - absolute, -} - -/// Specifies the annotation types. -enum PdfAnnotationTypes { - /// DocumentLinkAnnotation type. - documentLinkAnnotation, - - /// Link annotation type. - linkAnnotation, - - /// Link annotation type. - textWebLinkAnnotation, - - /// LineAnnotation type. - lineAnnotation, - - /// CircleAnnotation type. - circleAnnotation, - - /// RectangleAnnotation type. - rectangleAnnotation, - - /// PolygonAnnotation type. - polygonAnnotation, - - /// WidgetAnnotation type - widgetAnnotation, - - /// Highlight type annotation. - highlight, - - /// Underline type annotation. - underline, - - /// StrikeOut type annotation. - strikeOut, - - /// Squiggly type annotation. - squiggly, - - /// PopupAnnotation type. - popupAnnotation, - - /// No annotation. - noAnnotation, -} - -/// Specifies the annotation export types. -enum PdfAnnotationExportType { - /// Line annotation type. - lineAnnotation, - - /// Circle annotation type. - circleAnnotation, - - /// Rectangle annotation type. - rectangleAnnotation, - - /// Polygon annotation type. - polygonAnnotation, - - /// Highlight annotation type. - highlightAnnotation, - - /// Underline annotation type. - underlineAnnotation, - - /// StrikeOut annotation type. - strikeOutAnnotation, - - /// Squiggly annotation type. - squigglyAnnotation, - - /// Popup annotation type. - popupAnnotation, -} - -/// Specifies the format of Export or Import data. -enum PdfAnnotationDataFormat { - /// Specifies FDF file format. - fdf, - - /// Specifies XFDF file format. - xfdf, - - /// Specifies JSON file format. - json, -} - -/// Specifies the available styles for a field border. -enum PdfBorderStyle { - /// A solid rectangle surrounding the annotation. - solid, - - /// A dashed rectangle surrounding the annotation. - dashed, - - /// A simulated embossed rectangle that appears to be raised above the surface - /// of the page. - beveled, - - /// A simulated engraved rectangle that appears to be recessed below the surface - /// of the page. - inset, - - /// A single line along the bottom of the annotation rectangle. - underline, - - /// A dotted rectangle surrounding the annotation. - dot, -} - -/// Gets or sets the line intent of the annotation. -enum PdfLineIntent { - /// Indicates Line Arrow as intent of the line annotation - lineArrow, - - /// Indicates LineDimension as intent of the line annotation - lineDimension, -} - -/// Gets or sets the caption type of the annotation. -enum PdfLineCaptionType { - /// Indicates Inline as annotation caption positioning - inline, - - /// Indicates Top as annotation caption positioning - top, -} - -/// Specifies the line ending style to be used in the Line annotation. -enum PdfLineEndingStyle { - /// Indicates None - none, - - /// Indicates OpenArrow - openArrow, - - /// Indicates ClosedArrow - closedArrow, - - /// Indicates ROpenArrow - rOpenArrow, - - /// Indicates RClosedArrow - rClosedArrow, - - /// Indicates Butt - butt, - - /// Indicates Diamond - diamond, - - /// Indicates Circle - circle, - - /// Indicates Square - square, - - /// Indicates Slash - slash, -} - -/// Specifies the available data formats for submitting the form data. -enum PdfSubmitFormFlags { - /// If clear, the Fields array specifies which fields to - /// include in the submission. (All descendants of the specified fields in - /// the field hierarchy are submitted as well.) - /// If set, the Fields array tells which fields to exclude. All fields in the - /// document’s interactive form are submitted except those listed in the - /// Fields array and those whose NoExport flag. - includeExclude, - - /// If set, all fields designated by the Fields array and the Include/ - /// Exclude flag are submitted, regardless of whether they have a value. - /// For fields without a value, only the - /// field name is transmitted. - includeNoValueFields, - - /// Meaningful only if the SubmitPDF and XFDF flags are clear. If set, - /// field names and values are submitted in HTML Form format. If - /// clear, they are submitted in Forms Data Format - exportFormat, - - /// If set, field names and values are submitted using an HTTP GET - /// request. If clear, they are submitted using a POST request. This flag - /// is meaningful only when the ExportFormat flag is set; if ExportFormat - /// is clear, this flag must also be clear. - getMethod, - - /// If set, the coordinates of the mouse click that caused the submitform - /// action are transmitted as part of the form data. The coordinate - /// values are relative to the upper-left corner of the field’s widget annotation - /// rectangle. - submitCoordinates, - - /// Meaningful only if the SubmitPDF flags are clear. If set, - /// field names and values are submitted as XML Forms Data Format. - xfdf, - - /// Meaningful only when the form is being submitted in - /// Forms Data Format (that is, when both the XFDF and ExportFormat - /// flags are clear). If set, the submitted FDF file includes the contents - /// of all incremental updates to the underlying PDF document, - /// as contained in the Differences entry in the FDF dictionary. - /// If clear, the incremental updates are not included. - includeAppendSaves, - - /// Meaningful only when the form is being submitted in - /// Forms Data Format (that is, when both the XFDF and ExportFormat - /// flags are clear). If set, the submitted FDF file includes all markup - /// annotations in the underlying PDF document. - /// If clear, markup annotations are not included. - includeAnnotations, - - /// If set, the document is submitted as PDF, using the - /// MIME content type application/pdf (described in Internet RFC - /// 2045, Multipurpose Internet Mail Extensions (MIME), Part One: - /// Format of Internet Message Bodies; see the Bibliography). If set, all - /// other flags are ignored except GetMethod. - submitPdf, - - /// If set, any submitted field values representing dates are - /// converted to the standard format described. - canonicalFormat, - - /// Meaningful only when the form is being submitted in - /// Forms Data Format (that is, when both the XFDF and - /// ExportFormat flags are clear) and the IncludeAnnotations flag is - /// set. If set, it includes only those markup annotations whose T entry - /// matches the name of the current user, as determined - /// by the remote server to which the form is being submitted. - exclNonUserAnnots, - - /// Meaningful only when the form is being submitted in - /// Forms Data Format (that is, when both the XFDF and ExportFormat - /// flags are clear). If set, the submitted FDF excludes the F entry. - exclFKey, - - /// Meaningful only when the form is being submitted in - /// Forms Data Format (that is, when both the XFDF and ExportFormat - /// flags are clear). If set, the F entry of the submitted FDF is a file - /// specification containing an embedded file stream representing the - /// PDF file from which the FDF is being submitted. - embedForm, -} - -/// Specifies the enumeration of submit data formats. -enum SubmitDataFormat { - /// Data should be transmitted as Html. - html, - - /// Data should be transmitted as Pdf. - pdf, - - /// Data should be transmitted as Forms Data Format. - fdf, - - /// Data should be transmitted as XML Forms Data Format. - xfdf, -} - -/// Specifies Http request method. -enum HttpMethod { - /// Data submitted using Http Get method. - getHttp, - - /// Data submitted using Http Post method. - post, -} - -/// Specifies the Style of the Text Markup Annotation -enum PdfTextMarkupAnnotationType { - /// Represents highlight text markup annotation type. - highlight, - - /// Represents underline text markup annotation type. - underline, - - /// Represents squiggly text markup annotation type. - squiggly, - - /// Represents strikethrough text markup annotation type. - strikethrough, -} - -/// Specifies the enumeration of popup annotation icons. -enum PdfPopupIcon { - /// Indicates note popup annotation. - note, - - /// Indicates comment popup annotation. - comment, - - /// Indicates help popup annotation. - help, - - /// Indicates insert popup annotation. - insert, - - /// Indicates key popup annotation. - key, - - /// Indicates new paragraph popup annotation. - newParagraph, - - /// Indicates paragraph popup annotation. - paragraph, -} - -/// Specifies the enumeration of the annotation flags. -enum PdfAnnotationFlags { - /// Default value. - defaultFlag, - - /// Represents invisible annotation flag's key. - invisible, - - /// Represents hidden annotation flag's key. - hidden, - - /// Represents print annotation flag's key. - print, - - /// Represents annotation flag's key with no zooming. - noZoom, - - /// Represents annotation flag's key with no rotation. - noRotate, - - /// Represents annotation flag's key with no view. - noView, - - /// Represents read only annotation flag's key. - readOnly, - - /// Represents locked annotation flag's key. - locked, - - /// Annotation flag's key with no toggle view. - toggleNoView, -} +/// Specifies the highlight mode for a field. +enum PdfHighlightMode { + /// No highlighting. + noHighlighting, + + /// Invert the contents of the field rectangle. + invert, + + /// Invert the field's border. + outline, + + /// Pushed highlighting. + push, +} + +/// Specifies the file path type. +enum PdfFilePathType { + /// Specifies the file location with out including the domain name. + relative, + + /// Specifies the location, including the domain name. + absolute, +} + +/// Specifies the annotation types. +enum PdfAnnotationTypes { + /// DocumentLinkAnnotation type. + documentLinkAnnotation, + + /// Link annotation type. + linkAnnotation, + + /// Link annotation type. + textWebLinkAnnotation, + + /// LineAnnotation type. + lineAnnotation, + + /// CircleAnnotation type. + circleAnnotation, + + /// RectangleAnnotation type. + rectangleAnnotation, + + /// PolygonAnnotation type. + polygonAnnotation, + + /// WidgetAnnotation type + widgetAnnotation, + + /// Highlight type annotation. + highlight, + + /// Underline type annotation. + underline, + + /// StrikeOut type annotation. + strikeOut, + + /// Squiggly type annotation. + squiggly, + + /// PopupAnnotation type. + popupAnnotation, + + /// No annotation. + noAnnotation, +} + +/// Specifies the annotation export types. +enum PdfAnnotationExportType { + /// Line annotation type. + lineAnnotation, + + /// Circle annotation type. + circleAnnotation, + + /// Rectangle annotation type. + rectangleAnnotation, + + /// Polygon annotation type. + polygonAnnotation, + + /// Highlight annotation type. + highlightAnnotation, + + /// Underline annotation type. + underlineAnnotation, + + /// StrikeOut annotation type. + strikeOutAnnotation, + + /// Squiggly annotation type. + squigglyAnnotation, + + /// Popup annotation type. + popupAnnotation, +} + +/// Specifies the format of Export or Import data. +enum PdfAnnotationDataFormat { + /// Specifies FDF file format. + fdf, + + /// Specifies XFDF file format. + xfdf, + + /// Specifies JSON file format. + json, +} + +/// Specifies the available styles for a field border. +enum PdfBorderStyle { + /// A solid rectangle surrounding the annotation. + solid, + + /// A dashed rectangle surrounding the annotation. + dashed, + + /// A simulated embossed rectangle that appears to be raised above the surface + /// of the page. + beveled, + + /// A simulated engraved rectangle that appears to be recessed below the surface + /// of the page. + inset, + + /// A single line along the bottom of the annotation rectangle. + underline, + + /// A dotted rectangle surrounding the annotation. + dot, +} + +/// Gets or sets the line intent of the annotation. +enum PdfLineIntent { + /// Indicates Line Arrow as intent of the line annotation + lineArrow, + + /// Indicates LineDimension as intent of the line annotation + lineDimension, +} + +/// Gets or sets the caption type of the annotation. +enum PdfLineCaptionType { + /// Indicates Inline as annotation caption positioning + inline, + + /// Indicates Top as annotation caption positioning + top, +} + +/// Specifies the line ending style to be used in the Line annotation. +enum PdfLineEndingStyle { + /// Indicates None + none, + + /// Indicates OpenArrow + openArrow, + + /// Indicates ClosedArrow + closedArrow, + + /// Indicates ROpenArrow + rOpenArrow, + + /// Indicates RClosedArrow + rClosedArrow, + + /// Indicates Butt + butt, + + /// Indicates Diamond + diamond, + + /// Indicates Circle + circle, + + /// Indicates Square + square, + + /// Indicates Slash + slash, +} + +/// Specifies the available data formats for submitting the form data. +enum PdfSubmitFormFlags { + /// If clear, the Fields array specifies which fields to + /// include in the submission. (All descendants of the specified fields in + /// the field hierarchy are submitted as well.) + /// If set, the Fields array tells which fields to exclude. All fields in the + /// document’s interactive form are submitted except those listed in the + /// Fields array and those whose NoExport flag. + includeExclude, + + /// If set, all fields designated by the Fields array and the Include/ + /// Exclude flag are submitted, regardless of whether they have a value. + /// For fields without a value, only the + /// field name is transmitted. + includeNoValueFields, + + /// Meaningful only if the SubmitPDF and XFDF flags are clear. If set, + /// field names and values are submitted in HTML Form format. If + /// clear, they are submitted in Forms Data Format + exportFormat, + + /// If set, field names and values are submitted using an HTTP GET + /// request. If clear, they are submitted using a POST request. This flag + /// is meaningful only when the ExportFormat flag is set; if ExportFormat + /// is clear, this flag must also be clear. + getMethod, + + /// If set, the coordinates of the mouse click that caused the submitform + /// action are transmitted as part of the form data. The coordinate + /// values are relative to the upper-left corner of the field’s widget annotation + /// rectangle. + submitCoordinates, + + /// Meaningful only if the SubmitPDF flags are clear. If set, + /// field names and values are submitted as XML Forms Data Format. + xfdf, + + /// Meaningful only when the form is being submitted in + /// Forms Data Format (that is, when both the XFDF and ExportFormat + /// flags are clear). If set, the submitted FDF file includes the contents + /// of all incremental updates to the underlying PDF document, + /// as contained in the Differences entry in the FDF dictionary. + /// If clear, the incremental updates are not included. + includeAppendSaves, + + /// Meaningful only when the form is being submitted in + /// Forms Data Format (that is, when both the XFDF and ExportFormat + /// flags are clear). If set, the submitted FDF file includes all markup + /// annotations in the underlying PDF document. + /// If clear, markup annotations are not included. + includeAnnotations, + + /// If set, the document is submitted as PDF, using the + /// MIME content type application/pdf (described in Internet RFC + /// 2045, Multipurpose Internet Mail Extensions (MIME), Part One: + /// Format of Internet Message Bodies; see the Bibliography). If set, all + /// other flags are ignored except GetMethod. + submitPdf, + + /// If set, any submitted field values representing dates are + /// converted to the standard format described. + canonicalFormat, + + /// Meaningful only when the form is being submitted in + /// Forms Data Format (that is, when both the XFDF and + /// ExportFormat flags are clear) and the IncludeAnnotations flag is + /// set. If set, it includes only those markup annotations whose T entry + /// matches the name of the current user, as determined + /// by the remote server to which the form is being submitted. + exclNonUserAnnots, + + /// Meaningful only when the form is being submitted in + /// Forms Data Format (that is, when both the XFDF and ExportFormat + /// flags are clear). If set, the submitted FDF excludes the F entry. + exclFKey, + + /// Meaningful only when the form is being submitted in + /// Forms Data Format (that is, when both the XFDF and ExportFormat + /// flags are clear). If set, the F entry of the submitted FDF is a file + /// specification containing an embedded file stream representing the + /// PDF file from which the FDF is being submitted. + embedForm, +} + +/// Specifies the enumeration of submit data formats. +enum SubmitDataFormat { + /// Data should be transmitted as Html. + html, + + /// Data should be transmitted as Pdf. + pdf, + + /// Data should be transmitted as Forms Data Format. + fdf, + + /// Data should be transmitted as XML Forms Data Format. + xfdf, +} + +/// Specifies Http request method. +enum HttpMethod { + /// Data submitted using Http Get method. + getHttp, + + /// Data submitted using Http Post method. + post, +} + +/// Specifies the Style of the Text Markup Annotation +enum PdfTextMarkupAnnotationType { + /// Represents highlight text markup annotation type. + highlight, + + /// Represents underline text markup annotation type. + underline, + + /// Represents squiggly text markup annotation type. + squiggly, + + /// Represents strikethrough text markup annotation type. + strikethrough, +} + +/// Specifies the enumeration of popup annotation icons. +enum PdfPopupIcon { + /// Indicates note popup annotation. + note, + + /// Indicates comment popup annotation. + comment, + + /// Indicates help popup annotation. + help, + + /// Indicates insert popup annotation. + insert, + + /// Indicates key popup annotation. + key, + + /// Indicates new paragraph popup annotation. + newParagraph, + + /// Indicates paragraph popup annotation. + paragraph, +} + +/// Specifies the enumeration of the annotation flags. +enum PdfAnnotationFlags { + /// Default value. + defaultFlag, + + /// Represents invisible annotation flag's key. + invisible, + + /// Represents hidden annotation flag's key. + hidden, + + /// Represents print annotation flag's key. + print, + + /// Represents annotation flag's key with no zooming. + noZoom, + + /// Represents annotation flag's key with no rotation. + noRotate, + + /// Represents annotation flag's key with no view. + noView, + + /// Represents read only annotation flag's key. + readOnly, + + /// Represents locked annotation flag's key. + locked, + + /// Annotation flag's key with no toggle view. + toggleNoView, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_document.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_document.dart index fa06b04a1..75c4ba1bf 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_document.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_document.dart @@ -1,359 +1,359 @@ -import 'dart:convert'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; - -/// Internal class -class FdfDocument { - /// Internal Consturctor - FdfDocument(this.dictionary, this.page); - - /// Internal field - late PdfDictionary dictionary; - - /// Internal field - late PdfPage page; - - /// Internal field - String _annotationID = ''; - - /// Internal method - Map exportAnnotations( - int currentID, - List annotID, - int pageIndex, - bool hasAppearance, - ) { - const String startObject = - '${PdfOperators.whiteSpace}0${PdfOperators.whiteSpace}${PdfOperators.obj}${PdfOperators.newLine}'; - const String endObject = - PdfOperators.newLine + PdfOperators.endobj + PdfOperators.newLine; - PdfDictionary dictionary = this.dictionary; - _annotationID = currentID.toString(); - final List exportData = []; - exportData.addAll(utf8.encode('$currentID$startObject<<')); - final Map subDictionaries = {}; - final List streamReferences = []; - annotID.add(_annotationID); - dictionary.items![PdfName('Page')] = PdfNumber(pageIndex); - Map exportDataDictionary = _getEntriesInDictionary( - subDictionaries, - streamReferences, - currentID, - dictionary, - hasAppearance, - ); - exportData.addAll(exportDataDictionary['exportData'] as List); - currentID = exportDataDictionary['currentID'] as int; - dictionary.remove('Page'); - exportData.addAll(utf8.encode('>>$endObject')); - while (subDictionaries.isNotEmpty) { - final List keys = subDictionaries.keys.toList(); - for (final int key in keys) { - if (subDictionaries[key] is PdfDictionary) { - dictionary = subDictionaries[key]! as PdfDictionary; - if (dictionary.containsKey(PdfDictionaryProperties.type)) { - final IPdfPrimitive? name = - dictionary[PdfDictionaryProperties.type]; - if (name != null && - name is PdfName && - name.name == PdfDictionaryProperties.annot) { - annotID.add(key.toString()); - dictionary.items![PdfName('Page')] = PdfNumber(pageIndex); - } - } - exportData.addAll(utf8.encode('$key$startObject<<')); - exportDataDictionary = _getEntriesInDictionary( - subDictionaries, - streamReferences, - currentID, - dictionary, - hasAppearance, - ); - exportData.addAll(exportDataDictionary['exportData'] as List); - currentID = exportDataDictionary['currentID'] as int; - if (dictionary.containsKey('Page')) { - dictionary.remove('Page'); - } - exportData.addAll(utf8.encode('>>')); - if (streamReferences.contains(key)) { - exportData.addAll(_appendStream(subDictionaries[key]!)); - } - exportData.addAll(utf8.encode(endObject)); - } else if (subDictionaries[key] is PdfName) { - final PdfName name = subDictionaries[key]! as PdfName; - exportData.addAll(utf8.encode('$key$startObject$name$endObject')); - } else if (subDictionaries[key] is PdfArray) { - final PdfArray array = subDictionaries[key]! as PdfArray; - exportData.addAll(utf8.encode('$key$startObject')); - final Map result = _appendArrayElements( - array, - currentID, - hasAppearance, - subDictionaries, - streamReferences, - ); - exportData.addAll(result['exportData'] as List); - currentID = result['currentID'] as int; - exportData.addAll(utf8.encode(endObject)); - } else if (subDictionaries[key] is PdfBoolean) { - final PdfBoolean boolean = subDictionaries[key]! as PdfBoolean; - exportData.addAll( - utf8.encode( - '$key$startObject${boolean.value! ? 'true' : 'false'}$endObject', - ), - ); - } else if (subDictionaries[key] is PdfString) { - final PdfString data = subDictionaries[key]! as PdfString; - if (data.value != null) { - exportData.addAll( - utf8.encode( - '$key$startObject(${_getFormattedStringFDF(data.value!)})$endObject', - ), - ); - } - } - subDictionaries.remove(key); - } - } - currentID++; - return {'exportData': exportData, 'currentID': currentID}; - } - - /// Internal method - List _appendStream(IPdfPrimitive stream) { - final List streamData = []; - if (stream is PdfStream && - stream.dataStream != null && - stream.dataStream!.isNotEmpty) { - streamData.addAll(utf8.encode('stream${PdfOperators.newLine}')); - streamData.addAll(stream.dataStream!); - streamData.addAll(utf8.encode('${PdfOperators.newLine}endstream')); - } - return streamData; - } - - Map _getEntriesInDictionary( - Map dictionaries, - List streamReferences, - int currentID, - PdfDictionary dictionary, - bool hasAppearance, - ) { - final List annotationData = []; - bool isStream = false; - final List keys = dictionary.items!.keys.toList(); - for (final PdfName? key in keys) { - if (!hasAppearance && key!.name == PdfDictionaryProperties.ap) { - continue; - } - if (key!.name != PdfDictionaryProperties.p) { - annotationData.addAll(utf8.encode(key.toString())); - } - if (key.name == 'Sound' || - key.name == PdfDictionaryProperties.f || - hasAppearance) { - isStream = true; - } - final IPdfPrimitive? primitive = dictionary[key]; - if (primitive is PdfString) { - if (primitive.value != null) { - annotationData.addAll( - utf8.encode('(${_getFormattedStringFDF(primitive.value!)})'), - ); - } - } else if (primitive is PdfName) { - annotationData.addAll(utf8.encode(primitive.toString())); - } else if (primitive is PdfArray) { - final Map result = _appendArrayElements( - primitive, - currentID, - isStream, - dictionaries, - streamReferences, - ); - annotationData.addAll(result['exportData'] as List); - currentID = result['currentID'] as int; - } else if (primitive is PdfNumber) { - annotationData.addAll(utf8.encode(' ${primitive.value!}')); - } else if (primitive is PdfBoolean) { - annotationData.addAll(utf8.encode(' ${primitive.value!}')); - } else if (primitive is PdfDictionary) { - annotationData.addAll(utf8.encode('<<')); - final Map data = _getEntriesInDictionary( - dictionaries, - streamReferences, - currentID, - primitive, - hasAppearance, - ); - annotationData.addAll(data['exportData'] as List); - currentID = data['currentID'] as int; - annotationData.addAll(utf8.encode('>>')); - } else if (primitive is PdfReferenceHolder) { - if (PdfPageHelper.getHelper(page).document != null) { - final int pageNumber = PdfPageHelper.getHelper( - page, - ).document!.pages.indexOf(page); - if (key.name == PdfDictionaryProperties.parent) { - annotationData.addAll(utf8.encode(' $_annotationID 0 R')); - annotationData.addAll(utf8.encode('/Page $pageNumber')); - } else if (key.name == PdfDictionaryProperties.irt) { - if (primitive.object != null && primitive.object is PdfDictionary) { - final IPdfPrimitive? inReplyTo = primitive.object; - if (inReplyTo != null && - inReplyTo is PdfDictionary && - inReplyTo.containsKey('NM')) { - final IPdfPrimitive? name = PdfCrossTable.dereference( - inReplyTo['NM'], - ); - if (name != null && name is PdfString) { - if (name.value != null) { - annotationData.addAll( - utf8.encode('(${_getFormattedStringFDF(name.value!)})'), - ); - } - } - } - } - } else if (key.name != PdfDictionaryProperties.p) { - currentID++; - annotationData.addAll(utf8.encode(' $currentID 0 R')); - if (isStream) { - streamReferences.add(currentID); - } - if (primitive.object != null) { - dictionaries[currentID] = primitive.object!; - } - } - } - } - isStream = false; - } - return { - 'exportData': annotationData, - 'currentID': currentID, - }; - } - - String _getFormattedStringFDF(String value) { - String result = ''; - for (int i = 0; i < value.length; i++) { - final int c = value.codeUnitAt(i); - if (c == 40 || c == 41) { - result += r'\'; - } - if (c == 13 || c == 10) { - if (c == 13) { - result += r'\r'; - } - if (c == 10) { - result += r'\n'; - } - continue; - } - result += String.fromCharCode(c); - } - return result; - } - - Map _appendArrayElements( - PdfArray array, - int currentID, - bool isStream, - Map dictionaries, - List streamReferences, - ) { - final List arrayData = []; - arrayData.addAll(utf8.encode('[')); - if (array.elements.isNotEmpty) { - final int count = array.elements.length; - for (int i = 0; i < count; i++) { - final IPdfPrimitive? element = array.elements[i]; - if (i != 0 && - element != null && - (element is PdfNumber || - element is PdfReferenceHolder || - element is PdfBoolean)) { - arrayData.addAll(utf8.encode(' ')); - } - final Map result = _appendElement( - element!, - currentID, - isStream, - dictionaries, - streamReferences, - ); - arrayData.addAll(result['exportData'] as List); - currentID = result['currentID'] as int; - } - } - arrayData.addAll(utf8.encode(']')); - return {'exportData': arrayData, 'currentID': currentID}; - } - - Map _appendElement( - IPdfPrimitive element, - int currentID, - bool isStream, - Map dictionaries, - List streamReferences, - ) { - final List exportData = []; - if (element is PdfNumber) { - exportData.addAll(utf8.encode(element.value!.toString())); - } else if (element is PdfName) { - exportData.addAll(utf8.encode(element.toString())); - } else if (element is PdfString) { - if (element.value != null) { - exportData.addAll( - utf8.encode('(${_getFormattedStringFDF(element.value!)})'), - ); - } - } else if (element is PdfBoolean) { - exportData.addAll(utf8.encode(element.value!.toString())); - } else if (element is PdfReferenceHolder) { - currentID++; - if (isStream) { - streamReferences.add(currentID); - } - if (element.object != null) { - dictionaries[currentID] = element.object!; - } - exportData.addAll(utf8.encode('$currentID 0 R')); - } else if (element is PdfArray) { - final Map result = _appendArrayElements( - element, - currentID, - isStream, - dictionaries, - streamReferences, - ); - currentID = result['currentID'] as int; - exportData.addAll(result['exportData'] as List); - } else if (element is PdfDictionary) { - exportData.addAll(utf8.encode('<<')); - final Map data = _getEntriesInDictionary( - dictionaries, - streamReferences, - currentID, - element, - isStream, - ); - exportData.addAll(data['exportData'] as List); - currentID = data['currentID'] as int; - exportData.addAll(utf8.encode('>>')); - } - return {'exportData': exportData, 'currentID': currentID}; - } -} +import 'dart:convert'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; + +/// Internal class +class FdfDocument { + /// Internal Consturctor + FdfDocument(this.dictionary, this.page); + + /// Internal field + late PdfDictionary dictionary; + + /// Internal field + late PdfPage page; + + /// Internal field + String _annotationID = ''; + + /// Internal method + Map exportAnnotations( + int currentID, + List annotID, + int pageIndex, + bool hasAppearance, + ) { + const String startObject = + '${PdfOperators.whiteSpace}0${PdfOperators.whiteSpace}${PdfOperators.obj}${PdfOperators.newLine}'; + const String endObject = + PdfOperators.newLine + PdfOperators.endobj + PdfOperators.newLine; + PdfDictionary dictionary = this.dictionary; + _annotationID = currentID.toString(); + final List exportData = []; + exportData.addAll(utf8.encode('$currentID$startObject<<')); + final Map subDictionaries = {}; + final List streamReferences = []; + annotID.add(_annotationID); + dictionary.items![PdfName('Page')] = PdfNumber(pageIndex); + Map exportDataDictionary = _getEntriesInDictionary( + subDictionaries, + streamReferences, + currentID, + dictionary, + hasAppearance, + ); + exportData.addAll(exportDataDictionary['exportData'] as List); + currentID = exportDataDictionary['currentID'] as int; + dictionary.remove('Page'); + exportData.addAll(utf8.encode('>>$endObject')); + while (subDictionaries.isNotEmpty) { + final List keys = subDictionaries.keys.toList(); + for (final int key in keys) { + if (subDictionaries[key] is PdfDictionary) { + dictionary = subDictionaries[key]! as PdfDictionary; + if (dictionary.containsKey(PdfDictionaryProperties.type)) { + final IPdfPrimitive? name = + dictionary[PdfDictionaryProperties.type]; + if (name != null && + name is PdfName && + name.name == PdfDictionaryProperties.annot) { + annotID.add(key.toString()); + dictionary.items![PdfName('Page')] = PdfNumber(pageIndex); + } + } + exportData.addAll(utf8.encode('$key$startObject<<')); + exportDataDictionary = _getEntriesInDictionary( + subDictionaries, + streamReferences, + currentID, + dictionary, + hasAppearance, + ); + exportData.addAll(exportDataDictionary['exportData'] as List); + currentID = exportDataDictionary['currentID'] as int; + if (dictionary.containsKey('Page')) { + dictionary.remove('Page'); + } + exportData.addAll(utf8.encode('>>')); + if (streamReferences.contains(key)) { + exportData.addAll(_appendStream(subDictionaries[key]!)); + } + exportData.addAll(utf8.encode(endObject)); + } else if (subDictionaries[key] is PdfName) { + final PdfName name = subDictionaries[key]! as PdfName; + exportData.addAll(utf8.encode('$key$startObject$name$endObject')); + } else if (subDictionaries[key] is PdfArray) { + final PdfArray array = subDictionaries[key]! as PdfArray; + exportData.addAll(utf8.encode('$key$startObject')); + final Map result = _appendArrayElements( + array, + currentID, + hasAppearance, + subDictionaries, + streamReferences, + ); + exportData.addAll(result['exportData'] as List); + currentID = result['currentID'] as int; + exportData.addAll(utf8.encode(endObject)); + } else if (subDictionaries[key] is PdfBoolean) { + final PdfBoolean boolean = subDictionaries[key]! as PdfBoolean; + exportData.addAll( + utf8.encode( + '$key$startObject${boolean.value! ? 'true' : 'false'}$endObject', + ), + ); + } else if (subDictionaries[key] is PdfString) { + final PdfString data = subDictionaries[key]! as PdfString; + if (data.value != null) { + exportData.addAll( + utf8.encode( + '$key$startObject(${_getFormattedStringFDF(data.value!)})$endObject', + ), + ); + } + } + subDictionaries.remove(key); + } + } + currentID++; + return {'exportData': exportData, 'currentID': currentID}; + } + + /// Internal method + List _appendStream(IPdfPrimitive stream) { + final List streamData = []; + if (stream is PdfStream && + stream.dataStream != null && + stream.dataStream!.isNotEmpty) { + streamData.addAll(utf8.encode('stream${PdfOperators.newLine}')); + streamData.addAll(stream.dataStream!); + streamData.addAll(utf8.encode('${PdfOperators.newLine}endstream')); + } + return streamData; + } + + Map _getEntriesInDictionary( + Map dictionaries, + List streamReferences, + int currentID, + PdfDictionary dictionary, + bool hasAppearance, + ) { + final List annotationData = []; + bool isStream = false; + final List keys = dictionary.items!.keys.toList(); + for (final PdfName? key in keys) { + if (!hasAppearance && key!.name == PdfDictionaryProperties.ap) { + continue; + } + if (key!.name != PdfDictionaryProperties.p) { + annotationData.addAll(utf8.encode(key.toString())); + } + if (key.name == 'Sound' || + key.name == PdfDictionaryProperties.f || + hasAppearance) { + isStream = true; + } + final IPdfPrimitive? primitive = dictionary[key]; + if (primitive is PdfString) { + if (primitive.value != null) { + annotationData.addAll( + utf8.encode('(${_getFormattedStringFDF(primitive.value!)})'), + ); + } + } else if (primitive is PdfName) { + annotationData.addAll(utf8.encode(primitive.toString())); + } else if (primitive is PdfArray) { + final Map result = _appendArrayElements( + primitive, + currentID, + isStream, + dictionaries, + streamReferences, + ); + annotationData.addAll(result['exportData'] as List); + currentID = result['currentID'] as int; + } else if (primitive is PdfNumber) { + annotationData.addAll(utf8.encode(' ${primitive.value!}')); + } else if (primitive is PdfBoolean) { + annotationData.addAll(utf8.encode(' ${primitive.value!}')); + } else if (primitive is PdfDictionary) { + annotationData.addAll(utf8.encode('<<')); + final Map data = _getEntriesInDictionary( + dictionaries, + streamReferences, + currentID, + primitive, + hasAppearance, + ); + annotationData.addAll(data['exportData'] as List); + currentID = data['currentID'] as int; + annotationData.addAll(utf8.encode('>>')); + } else if (primitive is PdfReferenceHolder) { + if (PdfPageHelper.getHelper(page).document != null) { + final int pageNumber = PdfPageHelper.getHelper( + page, + ).document!.pages.indexOf(page); + if (key.name == PdfDictionaryProperties.parent) { + annotationData.addAll(utf8.encode(' $_annotationID 0 R')); + annotationData.addAll(utf8.encode('/Page $pageNumber')); + } else if (key.name == PdfDictionaryProperties.irt) { + if (primitive.object != null && primitive.object is PdfDictionary) { + final IPdfPrimitive? inReplyTo = primitive.object; + if (inReplyTo != null && + inReplyTo is PdfDictionary && + inReplyTo.containsKey('NM')) { + final IPdfPrimitive? name = PdfCrossTable.dereference( + inReplyTo['NM'], + ); + if (name != null && name is PdfString) { + if (name.value != null) { + annotationData.addAll( + utf8.encode('(${_getFormattedStringFDF(name.value!)})'), + ); + } + } + } + } + } else if (key.name != PdfDictionaryProperties.p) { + currentID++; + annotationData.addAll(utf8.encode(' $currentID 0 R')); + if (isStream) { + streamReferences.add(currentID); + } + if (primitive.object != null) { + dictionaries[currentID] = primitive.object!; + } + } + } + } + isStream = false; + } + return { + 'exportData': annotationData, + 'currentID': currentID, + }; + } + + String _getFormattedStringFDF(String value) { + String result = ''; + for (int i = 0; i < value.length; i++) { + final int c = value.codeUnitAt(i); + if (c == 40 || c == 41) { + result += r'\'; + } + if (c == 13 || c == 10) { + if (c == 13) { + result += r'\r'; + } + if (c == 10) { + result += r'\n'; + } + continue; + } + result += String.fromCharCode(c); + } + return result; + } + + Map _appendArrayElements( + PdfArray array, + int currentID, + bool isStream, + Map dictionaries, + List streamReferences, + ) { + final List arrayData = []; + arrayData.addAll(utf8.encode('[')); + if (array.elements.isNotEmpty) { + final int count = array.elements.length; + for (int i = 0; i < count; i++) { + final IPdfPrimitive? element = array.elements[i]; + if (i != 0 && + element != null && + (element is PdfNumber || + element is PdfReferenceHolder || + element is PdfBoolean)) { + arrayData.addAll(utf8.encode(' ')); + } + final Map result = _appendElement( + element!, + currentID, + isStream, + dictionaries, + streamReferences, + ); + arrayData.addAll(result['exportData'] as List); + currentID = result['currentID'] as int; + } + } + arrayData.addAll(utf8.encode(']')); + return {'exportData': arrayData, 'currentID': currentID}; + } + + Map _appendElement( + IPdfPrimitive element, + int currentID, + bool isStream, + Map dictionaries, + List streamReferences, + ) { + final List exportData = []; + if (element is PdfNumber) { + exportData.addAll(utf8.encode(element.value!.toString())); + } else if (element is PdfName) { + exportData.addAll(utf8.encode(element.toString())); + } else if (element is PdfString) { + if (element.value != null) { + exportData.addAll( + utf8.encode('(${_getFormattedStringFDF(element.value!)})'), + ); + } + } else if (element is PdfBoolean) { + exportData.addAll(utf8.encode(element.value!.toString())); + } else if (element is PdfReferenceHolder) { + currentID++; + if (isStream) { + streamReferences.add(currentID); + } + if (element.object != null) { + dictionaries[currentID] = element.object!; + } + exportData.addAll(utf8.encode('$currentID 0 R')); + } else if (element is PdfArray) { + final Map result = _appendArrayElements( + element, + currentID, + isStream, + dictionaries, + streamReferences, + ); + currentID = result['currentID'] as int; + exportData.addAll(result['exportData'] as List); + } else if (element is PdfDictionary) { + exportData.addAll(utf8.encode('<<')); + final Map data = _getEntriesInDictionary( + dictionaries, + streamReferences, + currentID, + element, + isStream, + ); + exportData.addAll(data['exportData'] as List); + currentID = data['currentID'] as int; + exportData.addAll(utf8.encode('>>')); + } + return {'exportData': exportData, 'currentID': currentID}; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_parser.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_parser.dart index 293982667..cbfdb7f77 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_parser.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/fdf_parser.dart @@ -1,402 +1,402 @@ -import 'dart:convert'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_parser.dart'; -import '../io/pdf_reader.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'json_parser.dart'; - -/// The class provides methods and properties to handle the loaded annotations from the existing PDF document for Fdf export and import. -class FdfParser { - //Constructor. - /// Initializes a new instance of the [FdfParser] class with the specified data. - FdfParser(List data) { - _data = data; - _reader = PdfReader(data); - _fdfObjects = {}; - } - - //Fields - late List _data; - PdfReader? _reader; - late Map _fdfObjects; - PdfParser? _parser; - Map? _annotationObjects; - Map? _groupObjects; - - //Properties - /// Gets the grouped objects. - Map get groupedObjects { - _groupObjects ??= {}; - return _groupObjects!; - } - - //Implementations. - /// Parse the annotation data. - void parseAnnotationData() { - final PdfCrossTable table = PdfCrossTable.fromFdf(_data); - if (table.crossTable != null) { - _parser = table.crossTable!.parser; - final int startPos = _checkFdf(); - if (startPos != -1) { - final int? endPos = _reader!.seekEnd(); - _parser!.setOffset(startPos); - _parser!.advance(); - while (_parser!.next != null && _parser!.next! == PdfTokenType.number) { - _parseObject(_fdfObjects); - } - if (_parser!.lexer != null && - _parser!.lexer!.text == PdfOperators.trailer) { - final IPdfPrimitive trailer = _parser!.trailer(); - _fdfObjects[PdfOperators.trailer] = trailer; - } - _parser!.advance(); - while (_parser!.lexer != null && - _parser!.lexer!.position != endPos && - _parser!.next == PdfTokenType.number) { - _parseObject(_fdfObjects); - } - } - } - } - - /// Imports the annotation data from FDF stream - void importAnnotations(PdfDocument document) { - _annotationObjects = _getAnnotationObjects(); - final bool hasAnnotations = _groupAnnotations(); - if (hasAnnotations && _annotationObjects != null) { - for (final PdfReferenceHolder holder in _annotationObjects!.values) { - final IPdfPrimitive? dictionary = holder.object; - if (dictionary != null && - dictionary is PdfDictionary && - dictionary.items != null && - dictionary.items!.isNotEmpty) { - _parseDictionary(dictionary); - if (dictionary.containsKey(PdfDictionaryProperties.irt)) { - final IPdfPrimitive? inReplyTo = - dictionary[PdfDictionaryProperties.irt]; - if (inReplyTo != null && - inReplyTo is PdfString && - !isNullOrEmpty(inReplyTo.value)) { - if (groupedObjects.containsKey(inReplyTo.value)) { - final String referenceString = groupedObjects[inReplyTo.value]!; - dictionary[PdfDictionaryProperties.irt] = - _annotationObjects![referenceString]; - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.contents)) { - final IPdfPrimitive? content = - dictionary[PdfDictionaryProperties.contents]; - if (content != null && - content is PdfString && - !isNullOrEmpty(content.value)) { - String contentText = content.value!; - if (RegExp(r'[\u0085-\u00FF]').hasMatch(contentText)) { - final List bytes = content.pdfEncode(document); - contentText = utf8.decode(bytes); - if (contentText.startsWith('(') && contentText.endsWith(')')) { - while (contentText.startsWith('(')) { - contentText = contentText.substring(1); - } - while (contentText.endsWith(')')) { - contentText = contentText.substring( - 0, - contentText.length - 1, - ); - } - } - dictionary[PdfDictionaryProperties.contents] = PdfString( - contentText, - ); - if (dictionary.containsKey('RC')) { - dictionary.setString( - 'RC', - '

$contentText

', - ); - } - dictionary.modify(); - } - } - } - if (dictionary.containsKey('Page')) { - final IPdfPrimitive? pageNumber = dictionary['Page']; - if (pageNumber != null && pageNumber is PdfNumber) { - final int pageIndex = pageNumber.value!.toInt(); - if (pageIndex < document.pages.count) { - final PdfPage loadedPage = document.pages[pageIndex]; - PdfPageHelper.getHelper(loadedPage).importAnnotation = true; - final PdfDictionary? pageDictionary = - PdfPageHelper.getHelper(loadedPage).dictionary; - if (pageDictionary != null) { - if (!pageDictionary.containsKey( - PdfDictionaryProperties.annots, - )) { - pageDictionary[PdfDictionaryProperties.annots] = PdfArray(); - } - final IPdfPrimitive? annots = PdfCrossTable.dereference( - pageDictionary[PdfDictionaryProperties.annots], - ); - if (annots != null && annots is PdfArray) { - annots.elements.add(holder); - annots.changed = true; - pageDictionary.modify(); - } - } - } - dictionary.remove('Page'); - } - } - } - } - } - } - - /// internal method - void dispose() { - _fdfObjects.clear(); - _reader = null; - _reader = null; - _parser = null; - if (_annotationObjects != null) { - _annotationObjects!.clear(); - } - _annotationObjects = null; - } - - Map _getAnnotationObjects() { - final Map mappedObjects = - {}; - final Map objects = _fdfObjects; - if (objects.isNotEmpty && objects.containsKey(PdfOperators.trailer)) { - final IPdfPrimitive trailer = objects[PdfOperators.trailer]!; - if (trailer is PdfDictionary && - trailer.containsKey(PdfDictionaryProperties.root)) { - final IPdfPrimitive? holder = trailer[PdfDictionaryProperties.root]; - if (holder != null && holder is PdfReferenceHolder) { - PdfReference? reference = holder.reference; - if (reference != null) { - final String rootKey = '${reference.objNum} ${reference.genNum}'; - if (objects.containsKey(rootKey)) { - final IPdfPrimitive root = objects[rootKey]!; - if (root is PdfDictionary && root.containsKey('FDF')) { - final IPdfPrimitive? fdf = root['FDF']; - if (fdf != null && - fdf is PdfDictionary && - fdf.containsKey(PdfDictionaryProperties.annots)) { - final IPdfPrimitive? annots = - fdf[PdfDictionaryProperties.annots]; - if (annots != null && - annots is PdfArray && - annots.count != 0) { - for (final IPdfPrimitive? holder in annots.elements) { - if (holder != null && holder is PdfReferenceHolder) { - reference = holder.reference; - if (reference != null) { - final String key = - '${reference.objNum} ${reference.genNum}'; - if (objects.containsKey(key)) { - mappedObjects[key] = PdfReferenceHolder( - objects[key], - ); - objects.remove(key); - } - } - } - } - } - } - objects.remove(rootKey); - } - } - } - } - } - objects.remove(PdfOperators.trailer); - } - return mappedObjects; - } - - bool _groupAnnotations() { - if (_annotationObjects != null && _annotationObjects!.isNotEmpty) { - _annotationObjects!.forEach((String key, PdfReferenceHolder value) { - final IPdfPrimitive? dictionary = value.object; - if (dictionary != null && - dictionary is PdfDictionary && - dictionary.containsKey('NM')) { - final IPdfPrimitive? name = dictionary['NM']; - if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { - groupedObjects[name.value!] = key; - } - } - }); - return true; - } - return false; - } - - int _checkFdf() { - const int headerLength = 8; - final String header = utf8.decode(_data, allowMalformed: true); - final int index = header.indexOf('%FDF-'); - if (index < 0) { - throw ArgumentError( - 'The source is not a valid FDF file because it does not start with"%FDF-"', - ); - } - return index + headerLength; - } - - void _parseObject(Map objects) { - final FdfObject? obj = _parser!.parseObject(); - if (obj != null && obj.objectNumber > 0 && obj.generationNumber >= 0) { - final String key = '${obj.objectNumber} ${obj.generationNumber}'; - objects[key] = obj.object; - } - _parser!.advance(); - } - - void _parseDictionary(PdfDictionary dictionary, [PdfName? key]) { - if (key != null) { - final IPdfPrimitive? primitive = dictionary[key]; - if (primitive != null) { - if (primitive is PdfDictionary) { - _parseDictionary(primitive); - } else if (primitive is PdfArray) { - _parseArray(primitive); - } else if (primitive is PdfReferenceHolder) { - final PdfReference? reference = primitive.reference; - if (reference != null) { - final String objectKey = '${reference.objNum} ${reference.genNum}'; - if (_annotationObjects != null && - _annotationObjects!.containsKey(objectKey)) { - dictionary[key] = _annotationObjects![objectKey]; - dictionary.modify(); - } else if (_fdfObjects.containsKey(objectKey)) { - final Map objects = _fdfObjects; - if (objects[objectKey] is PdfReferenceHolder) { - dictionary[key] = objects[objectKey]; - dictionary.modify(); - } else if (objects[objectKey] is PdfName) { - final PdfName obj = objects[objectKey]! as PdfName; - final PdfReferenceHolder holder = PdfReferenceHolder(obj); - dictionary[key] = holder; - objects[objectKey] = holder; - dictionary.modify(); - } else if (objects[objectKey] is PdfArray) { - final PdfArray obj = objects[objectKey]! as PdfArray; - _parseArray(obj); - final PdfReferenceHolder holder = PdfReferenceHolder(obj); - dictionary[key] = holder; - objects[objectKey] = holder; - dictionary.modify(); - } else if (objects[objectKey] is PdfStream) { - final PdfStream obj = objects[objectKey]! as PdfStream; - _parseDictionary(obj); - final PdfReferenceHolder holder = PdfReferenceHolder(obj); - dictionary[key] = holder; - objects[objectKey] = holder; - dictionary.modify(); - } else if (objects[objectKey] is PdfDictionary) { - final PdfDictionary obj = objects[objectKey]! as PdfDictionary; - _parseDictionary(obj); - final PdfReferenceHolder holder = PdfReferenceHolder(obj); - dictionary[key] = holder; - objects[objectKey] = holder; - dictionary.modify(); - } - } else { - dictionary.remove(key); - } - } - } - } - } else { - final List names = _getKeys(dictionary); - for (int i = 0; i < names.length; i++) { - _parseDictionary(dictionary, names[i]); - } - } - } - - List _getKeys(PdfDictionary dictionary) { - final List names = []; - for (final PdfName? name in dictionary.items!.keys) { - if (name != null) { - names.add(name); - } - } - return names; - } - - void _parseArray(PdfArray array) { - final int count = array.elements.length; - for (int i = 0; i < count; i++) { - final IPdfPrimitive? element = array[i]; - if (element != null && element is PdfReferenceHolder) { - final PdfReference? reference = element.reference; - if (reference != null) { - final String objectKey = '${reference.objNum} ${reference.genNum}'; - if (_annotationObjects != null && - _annotationObjects!.containsKey(objectKey)) { - array.elements[i] = _annotationObjects![objectKey]; - array.changed = true; - } else if (_fdfObjects.containsKey(objectKey)) { - final Map objects = _fdfObjects; - if (objects[objectKey] is PdfReferenceHolder) { - array.elements[i] = objects[objectKey]; - array.changed = true; - } else if (objects[objectKey] != null && - objects[objectKey] is PdfDictionary) { - _parseDictionary(objects[objectKey]! as PdfDictionary); - final PdfReferenceHolder holder = PdfReferenceHolder( - objects[objectKey], - ); - array.elements[i] = holder; - objects[objectKey] = holder; - array.changed = true; - } - } - } - } - } - } -} - -/// The class provides fields and properties to handle objects in Fdf stream. -class FdfObject { - // Constructor - /// Initializes a new instance of the [FdfObject] class with the specified object number, generation number and object. - FdfObject(PdfNumber objNum, PdfNumber genNum, IPdfPrimitive obj) { - _objNumber = objNum.value!.toInt(); - _genNumber = genNum.value!.toInt(); - _object = obj; - } - - // Fields - late int? _objNumber; - late int? _genNumber; - late IPdfPrimitive? _object; - - // Properties - /// Gets the object number. - int get objectNumber => _objNumber!; - - /// Gets the generation number. - int get generationNumber => _genNumber!; - - /// Gets the object. - IPdfPrimitive get object => _object!; -} +import 'dart:convert'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_parser.dart'; +import '../io/pdf_reader.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'json_parser.dart'; + +/// The class provides methods and properties to handle the loaded annotations from the existing PDF document for Fdf export and import. +class FdfParser { + //Constructor. + /// Initializes a new instance of the [FdfParser] class with the specified data. + FdfParser(List data) { + _data = data; + _reader = PdfReader(data); + _fdfObjects = {}; + } + + //Fields + late List _data; + PdfReader? _reader; + late Map _fdfObjects; + PdfParser? _parser; + Map? _annotationObjects; + Map? _groupObjects; + + //Properties + /// Gets the grouped objects. + Map get groupedObjects { + _groupObjects ??= {}; + return _groupObjects!; + } + + //Implementations. + /// Parse the annotation data. + void parseAnnotationData() { + final PdfCrossTable table = PdfCrossTable.fromFdf(_data); + if (table.crossTable != null) { + _parser = table.crossTable!.parser; + final int startPos = _checkFdf(); + if (startPos != -1) { + final int? endPos = _reader!.seekEnd(); + _parser!.setOffset(startPos); + _parser!.advance(); + while (_parser!.next != null && _parser!.next! == PdfTokenType.number) { + _parseObject(_fdfObjects); + } + if (_parser!.lexer != null && + _parser!.lexer!.text == PdfOperators.trailer) { + final IPdfPrimitive trailer = _parser!.trailer(); + _fdfObjects[PdfOperators.trailer] = trailer; + } + _parser!.advance(); + while (_parser!.lexer != null && + _parser!.lexer!.position != endPos && + _parser!.next == PdfTokenType.number) { + _parseObject(_fdfObjects); + } + } + } + } + + /// Imports the annotation data from FDF stream + void importAnnotations(PdfDocument document) { + _annotationObjects = _getAnnotationObjects(); + final bool hasAnnotations = _groupAnnotations(); + if (hasAnnotations && _annotationObjects != null) { + for (final PdfReferenceHolder holder in _annotationObjects!.values) { + final IPdfPrimitive? dictionary = holder.object; + if (dictionary != null && + dictionary is PdfDictionary && + dictionary.items != null && + dictionary.items!.isNotEmpty) { + _parseDictionary(dictionary); + if (dictionary.containsKey(PdfDictionaryProperties.irt)) { + final IPdfPrimitive? inReplyTo = + dictionary[PdfDictionaryProperties.irt]; + if (inReplyTo != null && + inReplyTo is PdfString && + !isNullOrEmpty(inReplyTo.value)) { + if (groupedObjects.containsKey(inReplyTo.value)) { + final String referenceString = groupedObjects[inReplyTo.value]!; + dictionary[PdfDictionaryProperties.irt] = + _annotationObjects![referenceString]; + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.contents)) { + final IPdfPrimitive? content = + dictionary[PdfDictionaryProperties.contents]; + if (content != null && + content is PdfString && + !isNullOrEmpty(content.value)) { + String contentText = content.value!; + if (RegExp(r'[\u0085-\u00FF]').hasMatch(contentText)) { + final List bytes = content.pdfEncode(document); + contentText = utf8.decode(bytes); + if (contentText.startsWith('(') && contentText.endsWith(')')) { + while (contentText.startsWith('(')) { + contentText = contentText.substring(1); + } + while (contentText.endsWith(')')) { + contentText = contentText.substring( + 0, + contentText.length - 1, + ); + } + } + dictionary[PdfDictionaryProperties.contents] = PdfString( + contentText, + ); + if (dictionary.containsKey('RC')) { + dictionary.setString( + 'RC', + '

$contentText

', + ); + } + dictionary.modify(); + } + } + } + if (dictionary.containsKey('Page')) { + final IPdfPrimitive? pageNumber = dictionary['Page']; + if (pageNumber != null && pageNumber is PdfNumber) { + final int pageIndex = pageNumber.value!.toInt(); + if (pageIndex < document.pages.count) { + final PdfPage loadedPage = document.pages[pageIndex]; + PdfPageHelper.getHelper(loadedPage).importAnnotation = true; + final PdfDictionary? pageDictionary = + PdfPageHelper.getHelper(loadedPage).dictionary; + if (pageDictionary != null) { + if (!pageDictionary.containsKey( + PdfDictionaryProperties.annots, + )) { + pageDictionary[PdfDictionaryProperties.annots] = PdfArray(); + } + final IPdfPrimitive? annots = PdfCrossTable.dereference( + pageDictionary[PdfDictionaryProperties.annots], + ); + if (annots != null && annots is PdfArray) { + annots.elements.add(holder); + annots.changed = true; + pageDictionary.modify(); + } + } + } + dictionary.remove('Page'); + } + } + } + } + } + } + + /// internal method + void dispose() { + _fdfObjects.clear(); + _reader = null; + _reader = null; + _parser = null; + if (_annotationObjects != null) { + _annotationObjects!.clear(); + } + _annotationObjects = null; + } + + Map _getAnnotationObjects() { + final Map mappedObjects = + {}; + final Map objects = _fdfObjects; + if (objects.isNotEmpty && objects.containsKey(PdfOperators.trailer)) { + final IPdfPrimitive trailer = objects[PdfOperators.trailer]!; + if (trailer is PdfDictionary && + trailer.containsKey(PdfDictionaryProperties.root)) { + final IPdfPrimitive? holder = trailer[PdfDictionaryProperties.root]; + if (holder != null && holder is PdfReferenceHolder) { + PdfReference? reference = holder.reference; + if (reference != null) { + final String rootKey = '${reference.objNum} ${reference.genNum}'; + if (objects.containsKey(rootKey)) { + final IPdfPrimitive root = objects[rootKey]!; + if (root is PdfDictionary && root.containsKey('FDF')) { + final IPdfPrimitive? fdf = root['FDF']; + if (fdf != null && + fdf is PdfDictionary && + fdf.containsKey(PdfDictionaryProperties.annots)) { + final IPdfPrimitive? annots = + fdf[PdfDictionaryProperties.annots]; + if (annots != null && + annots is PdfArray && + annots.count != 0) { + for (final IPdfPrimitive? holder in annots.elements) { + if (holder != null && holder is PdfReferenceHolder) { + reference = holder.reference; + if (reference != null) { + final String key = + '${reference.objNum} ${reference.genNum}'; + if (objects.containsKey(key)) { + mappedObjects[key] = PdfReferenceHolder( + objects[key], + ); + objects.remove(key); + } + } + } + } + } + } + objects.remove(rootKey); + } + } + } + } + } + objects.remove(PdfOperators.trailer); + } + return mappedObjects; + } + + bool _groupAnnotations() { + if (_annotationObjects != null && _annotationObjects!.isNotEmpty) { + _annotationObjects!.forEach((String key, PdfReferenceHolder value) { + final IPdfPrimitive? dictionary = value.object; + if (dictionary != null && + dictionary is PdfDictionary && + dictionary.containsKey('NM')) { + final IPdfPrimitive? name = dictionary['NM']; + if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { + groupedObjects[name.value!] = key; + } + } + }); + return true; + } + return false; + } + + int _checkFdf() { + const int headerLength = 8; + final String header = utf8.decode(_data, allowMalformed: true); + final int index = header.indexOf('%FDF-'); + if (index < 0) { + throw ArgumentError( + 'The source is not a valid FDF file because it does not start with"%FDF-"', + ); + } + return index + headerLength; + } + + void _parseObject(Map objects) { + final FdfObject? obj = _parser!.parseObject(); + if (obj != null && obj.objectNumber > 0 && obj.generationNumber >= 0) { + final String key = '${obj.objectNumber} ${obj.generationNumber}'; + objects[key] = obj.object; + } + _parser!.advance(); + } + + void _parseDictionary(PdfDictionary dictionary, [PdfName? key]) { + if (key != null) { + final IPdfPrimitive? primitive = dictionary[key]; + if (primitive != null) { + if (primitive is PdfDictionary) { + _parseDictionary(primitive); + } else if (primitive is PdfArray) { + _parseArray(primitive); + } else if (primitive is PdfReferenceHolder) { + final PdfReference? reference = primitive.reference; + if (reference != null) { + final String objectKey = '${reference.objNum} ${reference.genNum}'; + if (_annotationObjects != null && + _annotationObjects!.containsKey(objectKey)) { + dictionary[key] = _annotationObjects![objectKey]; + dictionary.modify(); + } else if (_fdfObjects.containsKey(objectKey)) { + final Map objects = _fdfObjects; + if (objects[objectKey] is PdfReferenceHolder) { + dictionary[key] = objects[objectKey]; + dictionary.modify(); + } else if (objects[objectKey] is PdfName) { + final PdfName obj = objects[objectKey]! as PdfName; + final PdfReferenceHolder holder = PdfReferenceHolder(obj); + dictionary[key] = holder; + objects[objectKey] = holder; + dictionary.modify(); + } else if (objects[objectKey] is PdfArray) { + final PdfArray obj = objects[objectKey]! as PdfArray; + _parseArray(obj); + final PdfReferenceHolder holder = PdfReferenceHolder(obj); + dictionary[key] = holder; + objects[objectKey] = holder; + dictionary.modify(); + } else if (objects[objectKey] is PdfStream) { + final PdfStream obj = objects[objectKey]! as PdfStream; + _parseDictionary(obj); + final PdfReferenceHolder holder = PdfReferenceHolder(obj); + dictionary[key] = holder; + objects[objectKey] = holder; + dictionary.modify(); + } else if (objects[objectKey] is PdfDictionary) { + final PdfDictionary obj = objects[objectKey]! as PdfDictionary; + _parseDictionary(obj); + final PdfReferenceHolder holder = PdfReferenceHolder(obj); + dictionary[key] = holder; + objects[objectKey] = holder; + dictionary.modify(); + } + } else { + dictionary.remove(key); + } + } + } + } + } else { + final List names = _getKeys(dictionary); + for (int i = 0; i < names.length; i++) { + _parseDictionary(dictionary, names[i]); + } + } + } + + List _getKeys(PdfDictionary dictionary) { + final List names = []; + for (final PdfName? name in dictionary.items!.keys) { + if (name != null) { + names.add(name); + } + } + return names; + } + + void _parseArray(PdfArray array) { + final int count = array.elements.length; + for (int i = 0; i < count; i++) { + final IPdfPrimitive? element = array[i]; + if (element != null && element is PdfReferenceHolder) { + final PdfReference? reference = element.reference; + if (reference != null) { + final String objectKey = '${reference.objNum} ${reference.genNum}'; + if (_annotationObjects != null && + _annotationObjects!.containsKey(objectKey)) { + array.elements[i] = _annotationObjects![objectKey]; + array.changed = true; + } else if (_fdfObjects.containsKey(objectKey)) { + final Map objects = _fdfObjects; + if (objects[objectKey] is PdfReferenceHolder) { + array.elements[i] = objects[objectKey]; + array.changed = true; + } else if (objects[objectKey] != null && + objects[objectKey] is PdfDictionary) { + _parseDictionary(objects[objectKey]! as PdfDictionary); + final PdfReferenceHolder holder = PdfReferenceHolder( + objects[objectKey], + ); + array.elements[i] = holder; + objects[objectKey] = holder; + array.changed = true; + } + } + } + } + } + } +} + +/// The class provides fields and properties to handle objects in Fdf stream. +class FdfObject { + // Constructor + /// Initializes a new instance of the [FdfObject] class with the specified object number, generation number and object. + FdfObject(PdfNumber objNum, PdfNumber genNum, IPdfPrimitive obj) { + _objNumber = objNum.value!.toInt(); + _genNumber = genNum.value!.toInt(); + _object = obj; + } + + // Fields + late int? _objNumber; + late int? _genNumber; + late IPdfPrimitive? _object; + + // Properties + /// Gets the object number. + int get objectNumber => _objNumber!; + + /// Gets the generation number. + int get generationNumber => _genNumber!; + + /// Gets the object. + IPdfPrimitive get object => _object!; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_document.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_document.dart index bb6c50283..816027ba6 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_document.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_document.dart @@ -1,1217 +1,1217 @@ -import 'dart:convert'; - -import 'package:intl/intl.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../forms/pdf_xfdf_document.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'json_parser.dart'; -import 'pdf_annotation.dart'; - -/// Represents a class which contains the methods and properties to export annotations in JSON format. -class JsonDocument { - //Consturctor. - /// Initializes a new instance of the [JsonDocument] class. - JsonDocument(this._document); - - //Fields - late final PdfDocument _document; - // late String _fileName; - bool _skipBorderStyle = false; - - //Implementation - /// Internal method. - void exportAnnotationData( - Map table, - bool exportAppearance, - int pageIndex, - PdfDictionary dictionary, - ) { - bool hasAppearance = exportAppearance; - _skipBorderStyle = false; - final String? annotationType = _getAnnotationType(dictionary); - if (!isNullOrEmpty(annotationType)) { - table['type'] = annotationType!; - table['page'] = pageIndex.toString(); - switch (annotationType) { - case PdfDictionaryProperties.line: - if (dictionary.containsKey(PdfDictionaryProperties.l)) { - final IPdfPrimitive? linePoints = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.l], - ); - if (linePoints != null && - linePoints is PdfArray && - linePoints.count == 4 && - linePoints[0] != null && - linePoints[0] is PdfNumber && - linePoints[1] != null && - linePoints[1] is PdfNumber && - linePoints[2] != null && - linePoints[2] is PdfNumber && - linePoints[3] != null && - linePoints[3] is PdfNumber) { - table['start'] = - '${(linePoints[0]! as PdfNumber).value},${(linePoints[1]! as PdfNumber).value}'; - table['end'] = - '${(linePoints[2]! as PdfNumber).value},${(linePoints[3]! as PdfNumber).value}'; - } - } - break; - case 'Stamp': - if (!hasAppearance) { - hasAppearance = true; - } - break; - case 'Square': - if (!hasAppearance) { - hasAppearance = true; - } - break; - } - if (dictionary.containsKey(PdfDictionaryProperties.be) && - dictionary.containsKey(PdfDictionaryProperties.bs)) { - final IPdfPrimitive? borderEffect = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.be], - ); - if (borderEffect != null && - borderEffect is PdfDictionary && - borderEffect.containsKey(PdfDictionaryProperties.s)) { - _skipBorderStyle = true; - } - } - _writeDictionary(pageIndex, dictionary, hasAppearance, table); - } - } - - /// Internal method. - String convertToJson(Map value) { - int j = 0; - String json = '{'; - value.forEach((String fieldKey, String fieldValue) { - if (fieldValue.startsWith('{') || fieldValue.startsWith('[')) { - json = '$json"${_replaceJsonDelimiters(fieldKey)}":$fieldValue'; - } else { - if (fieldValue.startsWith(' ') && - fieldValue.length > 1 && - (fieldValue[1] == '[' || fieldValue[1] == '{')) { - fieldValue = fieldValue.trim(); - } - json = '$json"${_replaceJsonDelimiters(fieldKey)}":"$fieldValue"'; - } - if (j < value.length - 1) { - json = '$json,'; - } - j++; - }); - json = '$json}'; - return json; - } - - void _writeDictionary( - int pageIndex, - PdfDictionary dictionary, - bool hasAppearance, - Map table, - ) { - bool isBSdictionary = false; - if (dictionary.containsKey(PdfDictionaryProperties.type)) { - final IPdfPrimitive? name = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.type], - ); - if (name != null && - name is PdfName && - name.name != null && - name.name! == PdfDictionaryProperties.border && - _skipBorderStyle) { - isBSdictionary = true; - } - } - dictionary.items!.forEach((PdfName? name, IPdfPrimitive? value) { - final String? key = name!.name; - if (key != null && - !(key == PdfDictionaryProperties.p || - key == PdfDictionaryProperties.parent)) { - final IPdfPrimitive? primitive = value; - if (primitive != null) { - if (primitive is PdfReferenceHolder) { - final IPdfPrimitive? obj = primitive.object; - if (obj != null && obj is PdfDictionary) { - switch (key) { - case PdfDictionaryProperties.bs: - _writeDictionary(pageIndex, obj, false, table); - break; - case PdfDictionaryProperties.be: - _writeDictionary(pageIndex, obj, false, table); - break; - case PdfDictionaryProperties.irt: - if (obj.containsKey('NM')) { - final String? value = _getValue(obj['NM']); - if (value != null) { - table['inreplyto'] = value; - } - } - break; - } - } - } else if (primitive is PdfDictionary) { - _writeDictionary(pageIndex, primitive, false, table); - } else if (value != null && - (!isBSdictionary || - (isBSdictionary && key != PdfDictionaryProperties.s))) { - _writeAttribute(key, value, pageIndex, dictionary, table); - } - } - } - }); - if (dictionary.containsKey(PdfDictionaryProperties.measure)) { - _exportMeasureDictionary(dictionary, table); - } - if (hasAppearance && dictionary.containsKey(PdfDictionaryProperties.ap)) { - List? bytes = _getAppearanceString( - dictionary[PdfDictionaryProperties.ap]!, - ); - if (bytes.isNotEmpty) { - table['appearance'] = base64.encode(bytes); - } - bytes = null; - } - if (dictionary.containsKey('Sound')) { - final IPdfPrimitive? sound = PdfCrossTable.dereference( - dictionary['Sound'], - ); - if (sound != null && sound is PdfStream) { - if (sound.containsKey('B')) { - final String? bits = _getValue(sound['B']); - if (!isNullOrEmpty(bits)) { - table['bits'] = bits!; - } - } - if (sound.containsKey(PdfDictionaryProperties.c)) { - final String? channels = _getValue(sound[PdfDictionaryProperties.c]); - if (!isNullOrEmpty(channels)) { - table['channels'] = channels!; - } - } - if (sound.containsKey(PdfDictionaryProperties.e)) { - final String? encoding = _getValue(sound[PdfDictionaryProperties.e]); - if (!isNullOrEmpty(encoding)) { - table['encoding'] = encoding!; - } - } - if (sound.containsKey(PdfDictionaryProperties.r)) { - final String? rate = _getValue(sound[PdfDictionaryProperties.r]); - if (!isNullOrEmpty(rate)) { - table['rate'] = rate!; - } - } - if (sound.dataStream != null && sound.dataStream!.isNotEmpty) { - final String data = PdfString.bytesToHex(sound.dataStream!); - if (!isNullOrEmpty(data)) { - table[XfdfProperties.mode.toLowerCase()] = 'raw'; - table['encodings'] = 'hex'; - if (sound.containsKey(PdfDictionaryProperties.length)) { - final String? length = _getValue( - sound[PdfDictionaryProperties.length], - ); - if (!isNullOrEmpty(length)) { - table[PdfDictionaryProperties.length.toLowerCase()] = length!; - } - } - if (sound.containsKey(PdfDictionaryProperties.filter)) { - final String? filter = _getValue( - sound[PdfDictionaryProperties.filter], - ); - if (!isNullOrEmpty(filter)) { - table[PdfDictionaryProperties.filter.toLowerCase()] = filter!; - } - } - table['data'] = data; - } - } - } - } else if (dictionary.containsKey(PdfDictionaryProperties.fs)) { - final IPdfPrimitive? fsDictionary = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.fs], - ); - if (fsDictionary != null && fsDictionary is PdfDictionary) { - if (fsDictionary.containsKey(PdfDictionaryProperties.f)) { - final String? file = _getValue( - fsDictionary[PdfDictionaryProperties.f], - ); - if (!isNullOrEmpty(file)) { - table['file'] = file!; - } - } - if (fsDictionary.containsKey(PdfDictionaryProperties.ef)) { - final IPdfPrimitive? efDictionary = PdfCrossTable.dereference( - fsDictionary[PdfDictionaryProperties.ef], - ); - if (efDictionary != null && - efDictionary is PdfDictionary && - efDictionary.containsKey(PdfDictionaryProperties.f)) { - final IPdfPrimitive? fStream = PdfCrossTable.dereference( - efDictionary[PdfDictionaryProperties.f], - ); - if (fStream != null && fStream is PdfStream) { - if (fStream.containsKey(PdfDictionaryProperties.params)) { - final IPdfPrimitive? paramsDictionary = - PdfCrossTable.dereference( - fStream[PdfDictionaryProperties.params], - ); - if (paramsDictionary != null && - paramsDictionary is PdfDictionary) { - if (paramsDictionary.containsKey( - PdfDictionaryProperties.creationDate, - )) { - final IPdfPrimitive? creationDate = - PdfCrossTable.dereference( - paramsDictionary[PdfDictionaryProperties - .creationDate], - ); - if (creationDate != null && creationDate is PdfString) { - final DateTime dateTime = dictionary.getDateTime( - creationDate, - ); - table['creation'] = DateFormat( - 'M/d/yyyy h:mm:ss a', - ).format(dateTime); - } - } - if (paramsDictionary.containsKey( - PdfDictionaryProperties.modificationDate, - )) { - final IPdfPrimitive? modifyDate = PdfCrossTable.dereference( - paramsDictionary[PdfDictionaryProperties - .modificationDate], - ); - if (modifyDate != null && modifyDate is PdfString) { - final DateTime dateTime = dictionary.getDateTime( - modifyDate, - ); - table['modification'] = DateFormat( - 'M/d/yyyy h:mm:ss a', - ).format(dateTime); - } - } - if (paramsDictionary.containsKey( - PdfDictionaryProperties.size, - )) { - final String? size = _getValue( - paramsDictionary[PdfDictionaryProperties.size], - ); - if (!isNullOrEmpty(size)) { - table[PdfDictionaryProperties.size.toLowerCase()] = size!; - } - } - if (paramsDictionary.containsKey('CheckSum')) { - final String? checksumValue = _getValue( - paramsDictionary['CheckSum'], - ); - if (!isNullOrEmpty(checksumValue)) { - final List checksum = utf8.encode(checksumValue!); - final String hexString = PdfString.bytesToHex(checksum); - table['checksum'] = hexString; - } - } - } - } - if (fStream.dataStream != null && - fStream.dataStream!.isNotEmpty) { - final String data = PdfString.bytesToHex(fStream.dataStream!); - if (!isNullOrEmpty(data)) { - table[XfdfProperties.mode.toLowerCase()] = - XfdfProperties.raw.toLowerCase(); - table[PdfDictionaryProperties.encoding.toLowerCase()] = - XfdfProperties.hex.toLowerCase(); - if (fStream.containsKey(PdfDictionaryProperties.length)) { - final String? length = _getValue( - fStream[PdfDictionaryProperties.length], - ); - if (!isNullOrEmpty(length)) { - table[PdfDictionaryProperties.length.toLowerCase()] = - length!; - } - } - if (fStream.containsKey(PdfDictionaryProperties.filter)) { - final String? filter = _getValue( - fStream[PdfDictionaryProperties.filter], - ); - if (!isNullOrEmpty(filter)) { - table[PdfDictionaryProperties.filter.toLowerCase()] = - filter!; - } - } - table[XfdfProperties.data.toLowerCase()] = data; - } - } - } - } - } - } - } - } - - List _getAppearanceString(IPdfPrimitive primitive) { - final Map appearanceTable = {}; - final Map parentTable = {}; - final IPdfPrimitive? appearance = PdfCrossTable.dereference(primitive); - if (appearance != null && appearance is PdfDictionary) { - _writeAppearanceDictionary(appearanceTable, appearance); - } - parentTable['ap'] = convertToJson(appearanceTable); - final String jsonData = convertToJson(parentTable); - return utf8.encode(jsonData); - } - - void _writeAppearanceDictionary( - Map textWriter, - PdfDictionary dictionary, - ) { - if (dictionary.count > 0) { - dictionary.items!.forEach((PdfName? name, IPdfPrimitive? value) { - _writeObject(textWriter, name!.name, value, null); - }); - } - } - - void _writeObject( - Map? textWriter, - String? key, - IPdfPrimitive? primitive, - List>? arrayWriter, - ) { - if (primitive != null) { - final String type = primitive.runtimeType.toString(); - switch (type) { - case 'PdfReferenceHolder': - final PdfReferenceHolder holder = primitive as PdfReferenceHolder; - if (holder.object != null) { - _writeObject(textWriter, key, holder.object, arrayWriter); - } - break; - case 'PdfDictionary': - final PdfDictionary dictionaryElement = primitive as PdfDictionary; - final Map mainTable = {}; - final Map subtable = {}; - _writeAppearanceDictionary(subtable, dictionaryElement); - mainTable['dict'] = convertToJson(subtable); - if (key != null) { - textWriter![key] = convertToJson(mainTable); - } else { - arrayWriter!.add(mainTable); - } - break; - case 'PdfStream': - final IPdfPrimitive? streamElement = (primitive as PdfStream) - .cloneObject(PdfDocumentHelper.getHelper(_document).crossTable); - if (streamElement != null && streamElement is PdfStream) { - if (streamElement.dataStream != null && - streamElement.dataStream!.isNotEmpty) { - final Map streamTable = {}; - _writeAppearanceDictionary(streamTable, streamElement); - final Map dataTable = {}; - final String? type = _getValue( - streamElement[PdfDictionaryProperties.subtype], - ); - if ((streamElement.containsKey(PdfDictionaryProperties.subtype) && - !isNullOrEmpty(type) && - PdfDictionaryProperties.image == type!) || - (!streamElement.containsKey(PdfDictionaryProperties.type) && - !streamElement.containsKey( - PdfDictionaryProperties.subtype, - ))) { - dataTable['mode'] = 'raw'; - dataTable['encoding'] = 'hex'; - final String data = PdfString.bytesToHex( - streamElement.dataStream!, - ); - if (!isNullOrEmpty(data)) { - dataTable['bytes'] = data; - } - } else if (streamElement.containsKey( - PdfDictionaryProperties.subtype, - ) && - !isNullOrEmpty(type) && - (PdfDictionaryProperties.form == type || - 'CIDFontType0C' == type || - 'OpenType' == type)) { - dataTable['mode'] = 'raw'; - dataTable['encoding'] = 'hex'; - streamElement.decompress(); - final String data = PdfString.bytesToHex( - streamElement.dataStream!, - ); - if (!isNullOrEmpty(data)) { - dataTable['bytes'] = data; - } - } else { - dataTable['mode'] = 'filtered'; - dataTable['encoding'] = 'ascii'; - streamElement.decompress(); - final String ascii = PdfString.bytesToHex( - streamElement.dataStream!, - ); - if (!isNullOrEmpty(ascii)) { - dataTable['bytes'] = ascii; - } - } - streamTable['data'] = convertToJson(dataTable); - final Map keyValuePairs = {}; - keyValuePairs['stream'] = convertToJson(streamTable); - if (key != null) { - textWriter![key] = convertToJson(keyValuePairs); - } else { - arrayWriter!.add(keyValuePairs); - } - } - } - break; - case 'PdfBoolean': - final PdfBoolean booleanElement = primitive as PdfBoolean; - final Map boolean = {}; - boolean['boolean'] = booleanElement.value.toString(); - if (key != null) { - textWriter![key] = convertToJson(boolean); - } else { - arrayWriter!.add(boolean); - } - break; - case 'PdfName': - if (primitive is PdfName && primitive.name != null) { - final Map name = {}; - name['name'] = primitive.name!; - if (key != null) { - textWriter![key] = convertToJson(name); - } else { - arrayWriter!.add(name); - } - } - break; - case 'PdfString': - if (primitive is PdfString && primitive.value != null) { - final Map stringValue = {}; - stringValue['string'] = primitive.value!; - if (key != null) { - textWriter![key] = convertToJson(stringValue); - } else { - arrayWriter!.add(stringValue); - } - } - break; - case 'PdfNumber': - if (primitive is PdfNumber && primitive.value != null) { - if (primitive.value is int) { - final Map integer = {}; - integer['int'] = primitive.value!.toString(); - if (key != null) { - textWriter![key] = convertToJson(integer); - } else { - arrayWriter!.add(integer); - } - } else { - final String value = primitive.value!.toDouble().toStringAsFixed( - 6, - ); - final Map integer = {}; - integer['fixed'] = value; - if (key != null) { - textWriter![key] = convertToJson(integer); - } else { - arrayWriter!.add(integer); - } - } - } - break; - case 'PdfNull': - final Map nullValue = {}; - nullValue['null'] = 'null'; - if (key != null) { - textWriter![key] = convertToJson(nullValue); - } else { - arrayWriter!.add(nullValue); - } - break; - case 'PdfArray': - final List> arrayDict = >[]; - _writeArray(arrayDict, primitive as PdfArray); - final Map tempDict = {}; - tempDict['array'] = _convertListToJson(arrayDict); - if (key != null) { - textWriter![key] = convertToJson(tempDict); - } else { - arrayWriter!.add(tempDict); - } - break; - } - } - } - - void _writeArray(List> textWriter, PdfArray array) { - for (final IPdfPrimitive? element in array.elements) { - if (element != null) { - _writeObject(null, null, element, textWriter); - } - } - } - - String _convertListToJson(List> value) { - String json = '['; - for (int i = 0; i < value.length; i++) { - json += convertToJson(value[i]); - if (i < value.length - 1) { - json = '$json,'; - } - } - json += ']'; - return json; - } - - String? _getValue(IPdfPrimitive? primitive) { - String? value; - if (primitive != null) { - if (primitive is PdfName) { - value = primitive.name; - } else if (primitive is PdfBoolean) { - value = primitive.value.toString(); - } else if (primitive is PdfString) { - value = primitive.value; - if (value != null && (value.startsWith('[') || value.startsWith('{'))) { - value = ' $value'; - } - value = _getValidString(value); - } else if (primitive is PdfArray) { - if (primitive.elements.isNotEmpty) { - for (int i = 0; i < primitive.elements.length; i++) { - final String? colorValue = _getValue(primitive.elements[i]); - if (colorValue != null) { - value = i == 0 ? colorValue : '$value,$colorValue'; - } - } - } - } else if (primitive is PdfNumber) { - if (primitive.value != null) { - value = primitive.value!.toString(); - } - } - } - return value; - } - - String? _getValidString(String? value) { - if (value != null) { - if (value.contains('"')) { - final RegExp regExp = RegExp(r'(? table, - ) { - switch (key) { - case PdfDictionaryProperties.c: - final String color = _getColor(primitive); - if (!isNullOrEmpty(color)) { - table['color'] = color; - } - break; - case PdfDictionaryProperties.da: - final IPdfPrimitive? defaultAppearance = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.da], - ); - if (defaultAppearance != null && - defaultAppearance is PdfString && - !isNullOrEmpty(defaultAppearance.value)) { - table['defaultappearance'] = defaultAppearance.value!; - } - break; - case PdfDictionaryProperties.ic: - final String interiorColor = _getColor(primitive); - if (!isNullOrEmpty(interiorColor)) { - table['interior-color'] = interiorColor; - } - break; - case PdfDictionaryProperties.m: - final IPdfPrimitive? modifiedDate = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.m], - ); - if (modifiedDate != null && - modifiedDate is PdfString && - !isNullOrEmpty(modifiedDate.value)) { - final DateTime dateTime = dictionary.getDateTime(modifiedDate); - table['date'] = DateFormat('M/d/yyyy h:mm:ss a').format(dateTime); - } - break; - case 'NM': - final String? value = _getValue(primitive); - if (!isNullOrEmpty(value)) { - table[PdfDictionaryProperties.name.toLowerCase()] = value!; - } - break; - case PdfDictionaryProperties.name: - final String? value = _getValue(primitive); - if (!isNullOrEmpty(value)) { - table['icon'] = value!; - } - break; - case PdfDictionaryProperties.subj: - final String? value = _getValue(primitive); - if (!isNullOrEmpty(value)) { - table[PdfDictionaryProperties.subject.toLowerCase()] = value!; - } - break; - case PdfDictionaryProperties.t: - final String? value = _getValue(primitive); - if (!table.containsKey(PdfDictionaryProperties.title.toLowerCase())) { - table[PdfDictionaryProperties.title.toLowerCase()] = value!; - } - break; - case PdfDictionaryProperties.rect: - final String? rect = _getValue(primitive); - if (!isNullOrEmpty(rect)) { - final List styleArray = rect!.split(','); - final Map subTable = {}; - subTable['x'] = styleArray[0]; - subTable['y'] = styleArray[1]; - subTable['width'] = styleArray[2]; - subTable['height'] = styleArray[3]; - table[key.toLowerCase()] = convertToJson(subTable); - } - break; - case PdfDictionaryProperties.creationDate: - final IPdfPrimitive? createDate = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.creationDate], - ); - if (createDate != null && - createDate is PdfString && - !isNullOrEmpty(createDate.value)) { - final DateTime creationDate = dictionary.getDateTime(createDate); - table[key.toLowerCase()] = DateFormat( - 'M/d/yyyy h:mm:ss a', - ).format(creationDate); - } - break; - case PdfDictionaryProperties.rotate: - final String? rotation = _getValue(primitive); - if (!isNullOrEmpty(rotation)) { - table['rotation'] = rotation!; - } - break; - case PdfDictionaryProperties.w: - final String? width = _getValue(primitive); - if (!isNullOrEmpty(width)) { - table[PdfDictionaryProperties.width.toLowerCase()] = width!; - } - break; - case PdfDictionaryProperties.le: - if (primitive is PdfArray) { - if (primitive.count == 2) { - table['head'] = _getValue(primitive.elements[0])!; - table['tail'] = _getValue(primitive.elements[1])!; - } - } else if (primitive is PdfName) { - final String? head = _getValue(primitive); - if (!isNullOrEmpty(head)) { - table['head'] = head!; - } - } - break; - case 'S': - final String? style = _getValue(primitive); - if (!isNullOrEmpty(style)) { - switch (style) { - case PdfDictionaryProperties.d: - table['style'] = 'dash'; - break; - case PdfDictionaryProperties.c: - table['style'] = 'cloudy'; - break; - case PdfDictionaryProperties.s: - table['style'] = 'solid'; - break; - case 'B': - table['style'] = 'bevelled'; - break; - case PdfDictionaryProperties.i: - table['style'] = 'inset'; - break; - case PdfDictionaryProperties.u: - table['style'] = 'underline'; - break; - } - } - break; - case PdfDictionaryProperties.d: - if (!table.containsKey('dashes')) { - final String? dashes = _getValue(primitive); - if (!isNullOrEmpty(dashes)) { - table['dashes'] = dashes!; - } - } - break; - case PdfDictionaryProperties.i: - final String? intensity = _getValue(primitive); - if (!isNullOrEmpty(intensity)) { - table['intensity'] = intensity!; - } - break; - case PdfDictionaryProperties.rd: - final String? fringe = _getValue(primitive); - if (!isNullOrEmpty(fringe)) { - table['fringe'] = fringe!; - } - break; - case PdfDictionaryProperties.it: - final String? it = _getValue(primitive); - if (!isNullOrEmpty(it)) { - table[key] = it!; - } - break; - case 'RT': - final String? replyType = _getValue(primitive); - if (!isNullOrEmpty(replyType)) { - table['replyType'] = replyType!.toLowerCase(); - } - break; - case PdfDictionaryProperties.ll: - final String? leaderLength = _getValue(primitive); - if (!isNullOrEmpty(leaderLength)) { - table['leaderLength'] = leaderLength!; - } - break; - case PdfDictionaryProperties.lle: - final String? leaderExtend = _getValue(primitive); - if (!isNullOrEmpty(leaderExtend)) { - table['leaderExtend'] = leaderExtend!; - } - break; - case PdfDictionaryProperties.cap: - final String? caption = _getValue(primitive); - if (!isNullOrEmpty(caption)) { - table['caption'] = caption!; - } - break; - case PdfDictionaryProperties.cp: - final String? captionStyle = _getValue(primitive); - if (!isNullOrEmpty(captionStyle)) { - table['caption-style'] = captionStyle!; - } - break; - case 'CL': - final String? callout = _getValue(primitive); - if (!isNullOrEmpty(callout)) { - table['callout'] = callout!; - } - break; - case PdfDictionaryProperties.quadPoints: - final String? coords = _getValue(primitive); - if (!isNullOrEmpty(coords)) { - table['coords'] = coords!; - } - break; - case PdfDictionaryProperties.ca: - final String? opacity = _getValue(primitive); - if (!isNullOrEmpty(opacity)) { - table['opacity'] = opacity!; - } - break; - case PdfDictionaryProperties.f: - if (primitive is PdfNumber) { - final List annotationFlags = - PdfAnnotationHelper.obtainAnnotationFlags( - primitive.value!.toInt(), - ); - final String flag = - annotationFlags - .map((PdfAnnotationFlags flag) => getEnumName(flag)) - .toString() - .replaceAll(RegExp('[ ()]'), '') - .toLowerCase(); - table[PdfDictionaryProperties.flags.toLowerCase()] = flag; - } - break; - case PdfDictionaryProperties.contents: - final IPdfPrimitive? contents = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.contents], - ); - if (contents != null && - contents is PdfString && - !isNullOrEmpty(contents.value)) { - table['contents'] = _getValidString(contents.value)!; - } - break; - case 'InkList': - final Map points = {}; - final IPdfPrimitive? inkList = PdfCrossTable.dereference( - dictionary['InkList'], - ); - if (inkList != null && inkList is PdfArray && inkList.count > 0) { - final List element = []; - for (int j = 0; j < inkList.count; j++) { - if (inkList[j]! is PdfArray) { - element.add(inkList[j]! as PdfArray); - } - } - points['gesture'] = _convertToJsonArray(element); - table['inklist'] = convertToJson(points); - } - break; - case PdfDictionaryProperties.vertices: - final IPdfPrimitive? vertices = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.vertices], - ); - if (vertices != null && vertices is PdfArray && vertices.count > 0) { - if (vertices.count.isEven) { - String value = ''; - IPdfPrimitive? numberElement; - for (int i = 0; i < vertices.count - 1; i++) { - numberElement = vertices.elements[i]; - if (numberElement != null && numberElement is PdfNumber) { - final String? number = _getValue(numberElement); - if (!isNullOrEmpty(number)) { - value += number! + (i % 2 != 0 ? ';' : ','); - } - } - } - numberElement = vertices.elements[vertices.count - 1]; - if (numberElement != null && numberElement is PdfNumber) { - final String? number = _getValue(numberElement); - if (!isNullOrEmpty(number)) { - value += number!; - } - } - if (!isNullOrEmpty(value)) { - table['vertices'] = value; - } - } - } - break; - case 'DS': - if (dictionary.containsKey('DS')) { - final IPdfPrimitive? defaultStyle = PdfCrossTable.dereference( - dictionary['DS'], - ); - final Map styleTable = {}; - if (defaultStyle != null && - defaultStyle is PdfString && - !isNullOrEmpty(defaultStyle.value)) { - final List textStyle = defaultStyle.value!.split(';'); - for (int i = 0; i < textStyle.length; i++) { - if (!isNullOrEmpty(textStyle[i]) && textStyle[i].contains(',')) { - textStyle[i] = _replaceJsonDelimiters(textStyle[i]); - } - final List text = textStyle[i].split(':'); - styleTable[text[0]] = text[1]; - } - } - table['defaultStyle'] = convertToJson(styleTable); - } - break; - case 'RC': - if (dictionary.containsKey('RC')) { - final IPdfPrimitive? contentStyle = PdfCrossTable.dereference( - dictionary['RC'], - ); - if (contentStyle != null && - contentStyle is PdfString && - !isNullOrEmpty(contentStyle.value)) { - String value = contentStyle.value!; - final int index = value.indexOf(' 0) { - value = value.substring(index); - } - table['contents-richtext'] = _getValidString(value)!; - } - } - break; - case PdfDictionaryProperties.type: - case PdfDictionaryProperties.subtype: - case PdfDictionaryProperties.p: - case PdfDictionaryProperties.parent: - case PdfDictionaryProperties.l: - case PdfDictionaryProperties.fs: - case 'MeasurementTypes': - case 'GroupNesting': - case 'ITEx': - case 'Sound': - break; - case PdfDictionaryProperties.border: - case PdfDictionaryProperties.a: - case PdfDictionaryProperties.r: - case PdfDictionaryProperties.x: - final String? value = _getValue(primitive); - if (!isNullOrEmpty(value)) { - table[key.toLowerCase()] = value!; - } - break; - default: - final String? value = _getValue(primitive); - if (!isNullOrEmpty(value)) { - table[key] = value!; - } - break; - } - } - - String _convertToJsonArray(List value) { - String json = '['; - for (int i = 0; i < value.length; i++) { - final String? point = _getValue(value[i]); - if (point != null) { - json = '$json[$point]'; - } - if (i < value.length - 1) { - json = '$json,'; - } - } - json = '$json]'; - return json; - } - - String _getColor(IPdfPrimitive primitive) { - String color = ''; - if (primitive is PdfArray && primitive.count >= 3) { - final String r = - PdfString.bytesToHex([ - ((primitive.elements[0]! as PdfNumber).value! * 255).round(), - ]).toUpperCase(); - final String g = - PdfString.bytesToHex([ - ((primitive.elements[1]! as PdfNumber).value! * 255).round(), - ]).toUpperCase(); - final String b = - PdfString.bytesToHex([ - ((primitive.elements[2]! as PdfNumber).value! * 255).round(), - ]).toUpperCase(); - color = '#$r$g$b'; - } - return color; - } - - void _exportMeasureDictionary( - PdfDictionary dictionary, - Map table, - ) { - final IPdfPrimitive? mdictionary = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.measure], - ); - if (mdictionary != null && mdictionary is PdfDictionary) { - if (mdictionary.containsKey(PdfDictionaryProperties.type)) { - table['type1'] = 'Measure'; - } - if (mdictionary.containsKey(PdfDictionaryProperties.r)) { - final String? value = _getValue(mdictionary[PdfDictionaryProperties.r]); - if (!isNullOrEmpty(value)) { - table['ratevalue'] = value!; - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.subtype)) { - final String? value = _getValue( - mdictionary[PdfDictionaryProperties.subtype], - ); - if (!isNullOrEmpty(value)) { - table[PdfDictionaryProperties.subtype] = value!; - } - } - if (mdictionary.containsKey('TargetUnitConversion')) { - final String? value = _getValue(mdictionary['TargetUnitConversion']); - if (!isNullOrEmpty(value)) { - table['TargetUnitConversion'] = value!; - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.a)) { - final IPdfPrimitive? aArray = mdictionary[PdfDictionaryProperties.a]; - if (aArray != null && - aArray is PdfArray && - aArray.elements.isNotEmpty) { - final IPdfPrimitive? adictionary = PdfCrossTable.dereference( - aArray.elements[0], - ); - if (adictionary != null && adictionary is PdfDictionary) { - _exportMeasureFormatDetails('area', adictionary, table); - } - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.d)) { - final IPdfPrimitive? dArray = mdictionary[PdfDictionaryProperties.d]; - if (dArray != null && - dArray is PdfArray && - dArray.elements.isNotEmpty) { - final IPdfPrimitive? ddictionary = PdfCrossTable.dereference( - dArray.elements[0], - ); - if (ddictionary != null && ddictionary is PdfDictionary) { - _exportMeasureFormatDetails('distance', ddictionary, table); - } - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.x)) { - final IPdfPrimitive? xArray = mdictionary[PdfDictionaryProperties.x]; - if (xArray != null && - xArray is PdfArray && - xArray.elements.isNotEmpty) { - final IPdfPrimitive? xdictionary = PdfCrossTable.dereference( - xArray.elements[0], - ); - if (xdictionary != null && xdictionary is PdfDictionary) { - _exportMeasureFormatDetails('xformat', xdictionary, table); - } - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.t)) { - final IPdfPrimitive? tArray = mdictionary[PdfDictionaryProperties.t]; - if (tArray != null && - tArray is PdfArray && - tArray.elements.isNotEmpty) { - final IPdfPrimitive? tdictionary = PdfCrossTable.dereference( - tArray.elements[0], - ); - if (tdictionary != null && tdictionary is PdfDictionary) { - _exportMeasureFormatDetails('tformat', tdictionary, table); - } - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.v)) { - final IPdfPrimitive? vArray = mdictionary[PdfDictionaryProperties.v]; - if (vArray != null && - vArray is PdfArray && - vArray.elements.isNotEmpty) { - final IPdfPrimitive? vdictionary = PdfCrossTable.dereference( - vArray.elements[0], - ); - if (vdictionary != null && vdictionary is PdfDictionary) { - _exportMeasureFormatDetails('vformat', vdictionary, table); - } - } - } - } - } - - void _exportMeasureFormatDetails( - String key, - PdfDictionary measurementDetails, - Map table, - ) { - final Map subTable = {}; - if (measurementDetails.containsKey(PdfDictionaryProperties.c)) { - final String? value = _getValue( - measurementDetails[PdfDictionaryProperties.c], - ); - if (!isNullOrEmpty(value)) { - subTable['c'] = value!; - } - } - if (measurementDetails.containsKey(PdfDictionaryProperties.f)) { - final String? value = _getValue( - measurementDetails[PdfDictionaryProperties.f], - ); - if (!isNullOrEmpty(value)) { - subTable['f'] = value!; - } - } - if (measurementDetails.containsKey(PdfDictionaryProperties.d)) { - final String? value = _getValue( - measurementDetails[PdfDictionaryProperties.d], - ); - if (!isNullOrEmpty(value)) { - subTable['d'] = value!; - } - } - if (measurementDetails.containsKey(PdfDictionaryProperties.rd)) { - final String? value = _getValue( - measurementDetails[PdfDictionaryProperties.rd], - ); - if (!isNullOrEmpty(value)) { - subTable['rd'] = value!; - } - } - if (measurementDetails.containsKey(PdfDictionaryProperties.u)) { - final String? value = _getValue( - measurementDetails[PdfDictionaryProperties.u], - ); - if (!isNullOrEmpty(value)) { - subTable['u'] = value!; - } - } - if (measurementDetails.containsKey('RT')) { - final String? value = _getValue(measurementDetails['RT']); - if (!isNullOrEmpty(value)) { - subTable['rt'] = value!; - } - } - if (measurementDetails.containsKey('SS')) { - final String? value = _getValue(measurementDetails['SS']); - if (!isNullOrEmpty(value)) { - subTable['ss'] = value!; - } - } - if (measurementDetails.containsKey('FD')) { - final String? value = _getValue(measurementDetails['FD']); - if (!isNullOrEmpty(value)) { - subTable['fd'] = value!; - } - } - if (measurementDetails.containsKey(PdfDictionaryProperties.type)) { - final String? value = _getValue( - measurementDetails[PdfDictionaryProperties.type], - ); - if (!isNullOrEmpty(value)) { - subTable[PdfDictionaryProperties.type] = value!; - } - } - table[key] = convertToJson(subTable); - } - - String _replaceJsonDelimiters(String value) { - // ignore: unnecessary_string_escapes - return value.contains(RegExp('[":,{}]|[\[]|]')) - ? value - .replaceAll(',', '_x002C_') - .replaceAll('"', '_x0022_') - .replaceAll(':', '_x003A_') - .replaceAll('{', '_x007B_') - .replaceAll('}', '_x007D_') - .replaceAll('[', '_x005B_') - .replaceAll(']', '_x005D_') - : value; - } - - String? _getAnnotationType(PdfDictionary dictionary) { - if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? subtype = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.subtype], - ); - if (subtype != null && subtype is PdfName && subtype.name != null) { - return subtype.name!; - } - } - return null; - } -} +import 'dart:convert'; + +import 'package:intl/intl.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../forms/pdf_xfdf_document.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'json_parser.dart'; +import 'pdf_annotation.dart'; + +/// Represents a class which contains the methods and properties to export annotations in JSON format. +class JsonDocument { + //Consturctor. + /// Initializes a new instance of the [JsonDocument] class. + JsonDocument(this._document); + + //Fields + late final PdfDocument _document; + // late String _fileName; + bool _skipBorderStyle = false; + + //Implementation + /// Internal method. + void exportAnnotationData( + Map table, + bool exportAppearance, + int pageIndex, + PdfDictionary dictionary, + ) { + bool hasAppearance = exportAppearance; + _skipBorderStyle = false; + final String? annotationType = _getAnnotationType(dictionary); + if (!isNullOrEmpty(annotationType)) { + table['type'] = annotationType!; + table['page'] = pageIndex.toString(); + switch (annotationType) { + case PdfDictionaryProperties.line: + if (dictionary.containsKey(PdfDictionaryProperties.l)) { + final IPdfPrimitive? linePoints = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.l], + ); + if (linePoints != null && + linePoints is PdfArray && + linePoints.count == 4 && + linePoints[0] != null && + linePoints[0] is PdfNumber && + linePoints[1] != null && + linePoints[1] is PdfNumber && + linePoints[2] != null && + linePoints[2] is PdfNumber && + linePoints[3] != null && + linePoints[3] is PdfNumber) { + table['start'] = + '${(linePoints[0]! as PdfNumber).value},${(linePoints[1]! as PdfNumber).value}'; + table['end'] = + '${(linePoints[2]! as PdfNumber).value},${(linePoints[3]! as PdfNumber).value}'; + } + } + break; + case 'Stamp': + if (!hasAppearance) { + hasAppearance = true; + } + break; + case 'Square': + if (!hasAppearance) { + hasAppearance = true; + } + break; + } + if (dictionary.containsKey(PdfDictionaryProperties.be) && + dictionary.containsKey(PdfDictionaryProperties.bs)) { + final IPdfPrimitive? borderEffect = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.be], + ); + if (borderEffect != null && + borderEffect is PdfDictionary && + borderEffect.containsKey(PdfDictionaryProperties.s)) { + _skipBorderStyle = true; + } + } + _writeDictionary(pageIndex, dictionary, hasAppearance, table); + } + } + + /// Internal method. + String convertToJson(Map value) { + int j = 0; + String json = '{'; + value.forEach((String fieldKey, String fieldValue) { + if (fieldValue.startsWith('{') || fieldValue.startsWith('[')) { + json = '$json"${_replaceJsonDelimiters(fieldKey)}":$fieldValue'; + } else { + if (fieldValue.startsWith(' ') && + fieldValue.length > 1 && + (fieldValue[1] == '[' || fieldValue[1] == '{')) { + fieldValue = fieldValue.trim(); + } + json = '$json"${_replaceJsonDelimiters(fieldKey)}":"$fieldValue"'; + } + if (j < value.length - 1) { + json = '$json,'; + } + j++; + }); + json = '$json}'; + return json; + } + + void _writeDictionary( + int pageIndex, + PdfDictionary dictionary, + bool hasAppearance, + Map table, + ) { + bool isBSdictionary = false; + if (dictionary.containsKey(PdfDictionaryProperties.type)) { + final IPdfPrimitive? name = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.type], + ); + if (name != null && + name is PdfName && + name.name != null && + name.name! == PdfDictionaryProperties.border && + _skipBorderStyle) { + isBSdictionary = true; + } + } + dictionary.items!.forEach((PdfName? name, IPdfPrimitive? value) { + final String? key = name!.name; + if (key != null && + !(key == PdfDictionaryProperties.p || + key == PdfDictionaryProperties.parent)) { + final IPdfPrimitive? primitive = value; + if (primitive != null) { + if (primitive is PdfReferenceHolder) { + final IPdfPrimitive? obj = primitive.object; + if (obj != null && obj is PdfDictionary) { + switch (key) { + case PdfDictionaryProperties.bs: + _writeDictionary(pageIndex, obj, false, table); + break; + case PdfDictionaryProperties.be: + _writeDictionary(pageIndex, obj, false, table); + break; + case PdfDictionaryProperties.irt: + if (obj.containsKey('NM')) { + final String? value = _getValue(obj['NM']); + if (value != null) { + table['inreplyto'] = value; + } + } + break; + } + } + } else if (primitive is PdfDictionary) { + _writeDictionary(pageIndex, primitive, false, table); + } else if (value != null && + (!isBSdictionary || + (isBSdictionary && key != PdfDictionaryProperties.s))) { + _writeAttribute(key, value, pageIndex, dictionary, table); + } + } + } + }); + if (dictionary.containsKey(PdfDictionaryProperties.measure)) { + _exportMeasureDictionary(dictionary, table); + } + if (hasAppearance && dictionary.containsKey(PdfDictionaryProperties.ap)) { + List? bytes = _getAppearanceString( + dictionary[PdfDictionaryProperties.ap]!, + ); + if (bytes.isNotEmpty) { + table['appearance'] = base64.encode(bytes); + } + bytes = null; + } + if (dictionary.containsKey('Sound')) { + final IPdfPrimitive? sound = PdfCrossTable.dereference( + dictionary['Sound'], + ); + if (sound != null && sound is PdfStream) { + if (sound.containsKey('B')) { + final String? bits = _getValue(sound['B']); + if (!isNullOrEmpty(bits)) { + table['bits'] = bits!; + } + } + if (sound.containsKey(PdfDictionaryProperties.c)) { + final String? channels = _getValue(sound[PdfDictionaryProperties.c]); + if (!isNullOrEmpty(channels)) { + table['channels'] = channels!; + } + } + if (sound.containsKey(PdfDictionaryProperties.e)) { + final String? encoding = _getValue(sound[PdfDictionaryProperties.e]); + if (!isNullOrEmpty(encoding)) { + table['encoding'] = encoding!; + } + } + if (sound.containsKey(PdfDictionaryProperties.r)) { + final String? rate = _getValue(sound[PdfDictionaryProperties.r]); + if (!isNullOrEmpty(rate)) { + table['rate'] = rate!; + } + } + if (sound.dataStream != null && sound.dataStream!.isNotEmpty) { + final String data = PdfString.bytesToHex(sound.dataStream!); + if (!isNullOrEmpty(data)) { + table[XfdfProperties.mode.toLowerCase()] = 'raw'; + table['encodings'] = 'hex'; + if (sound.containsKey(PdfDictionaryProperties.length)) { + final String? length = _getValue( + sound[PdfDictionaryProperties.length], + ); + if (!isNullOrEmpty(length)) { + table[PdfDictionaryProperties.length.toLowerCase()] = length!; + } + } + if (sound.containsKey(PdfDictionaryProperties.filter)) { + final String? filter = _getValue( + sound[PdfDictionaryProperties.filter], + ); + if (!isNullOrEmpty(filter)) { + table[PdfDictionaryProperties.filter.toLowerCase()] = filter!; + } + } + table['data'] = data; + } + } + } + } else if (dictionary.containsKey(PdfDictionaryProperties.fs)) { + final IPdfPrimitive? fsDictionary = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.fs], + ); + if (fsDictionary != null && fsDictionary is PdfDictionary) { + if (fsDictionary.containsKey(PdfDictionaryProperties.f)) { + final String? file = _getValue( + fsDictionary[PdfDictionaryProperties.f], + ); + if (!isNullOrEmpty(file)) { + table['file'] = file!; + } + } + if (fsDictionary.containsKey(PdfDictionaryProperties.ef)) { + final IPdfPrimitive? efDictionary = PdfCrossTable.dereference( + fsDictionary[PdfDictionaryProperties.ef], + ); + if (efDictionary != null && + efDictionary is PdfDictionary && + efDictionary.containsKey(PdfDictionaryProperties.f)) { + final IPdfPrimitive? fStream = PdfCrossTable.dereference( + efDictionary[PdfDictionaryProperties.f], + ); + if (fStream != null && fStream is PdfStream) { + if (fStream.containsKey(PdfDictionaryProperties.params)) { + final IPdfPrimitive? paramsDictionary = + PdfCrossTable.dereference( + fStream[PdfDictionaryProperties.params], + ); + if (paramsDictionary != null && + paramsDictionary is PdfDictionary) { + if (paramsDictionary.containsKey( + PdfDictionaryProperties.creationDate, + )) { + final IPdfPrimitive? creationDate = + PdfCrossTable.dereference( + paramsDictionary[PdfDictionaryProperties + .creationDate], + ); + if (creationDate != null && creationDate is PdfString) { + final DateTime dateTime = dictionary.getDateTime( + creationDate, + ); + table['creation'] = DateFormat( + 'M/d/yyyy h:mm:ss a', + ).format(dateTime); + } + } + if (paramsDictionary.containsKey( + PdfDictionaryProperties.modificationDate, + )) { + final IPdfPrimitive? modifyDate = PdfCrossTable.dereference( + paramsDictionary[PdfDictionaryProperties + .modificationDate], + ); + if (modifyDate != null && modifyDate is PdfString) { + final DateTime dateTime = dictionary.getDateTime( + modifyDate, + ); + table['modification'] = DateFormat( + 'M/d/yyyy h:mm:ss a', + ).format(dateTime); + } + } + if (paramsDictionary.containsKey( + PdfDictionaryProperties.size, + )) { + final String? size = _getValue( + paramsDictionary[PdfDictionaryProperties.size], + ); + if (!isNullOrEmpty(size)) { + table[PdfDictionaryProperties.size.toLowerCase()] = size!; + } + } + if (paramsDictionary.containsKey('CheckSum')) { + final String? checksumValue = _getValue( + paramsDictionary['CheckSum'], + ); + if (!isNullOrEmpty(checksumValue)) { + final List checksum = utf8.encode(checksumValue!); + final String hexString = PdfString.bytesToHex(checksum); + table['checksum'] = hexString; + } + } + } + } + if (fStream.dataStream != null && + fStream.dataStream!.isNotEmpty) { + final String data = PdfString.bytesToHex(fStream.dataStream!); + if (!isNullOrEmpty(data)) { + table[XfdfProperties.mode.toLowerCase()] = + XfdfProperties.raw.toLowerCase(); + table[PdfDictionaryProperties.encoding.toLowerCase()] = + XfdfProperties.hex.toLowerCase(); + if (fStream.containsKey(PdfDictionaryProperties.length)) { + final String? length = _getValue( + fStream[PdfDictionaryProperties.length], + ); + if (!isNullOrEmpty(length)) { + table[PdfDictionaryProperties.length.toLowerCase()] = + length!; + } + } + if (fStream.containsKey(PdfDictionaryProperties.filter)) { + final String? filter = _getValue( + fStream[PdfDictionaryProperties.filter], + ); + if (!isNullOrEmpty(filter)) { + table[PdfDictionaryProperties.filter.toLowerCase()] = + filter!; + } + } + table[XfdfProperties.data.toLowerCase()] = data; + } + } + } + } + } + } + } + } + + List _getAppearanceString(IPdfPrimitive primitive) { + final Map appearanceTable = {}; + final Map parentTable = {}; + final IPdfPrimitive? appearance = PdfCrossTable.dereference(primitive); + if (appearance != null && appearance is PdfDictionary) { + _writeAppearanceDictionary(appearanceTable, appearance); + } + parentTable['ap'] = convertToJson(appearanceTable); + final String jsonData = convertToJson(parentTable); + return utf8.encode(jsonData); + } + + void _writeAppearanceDictionary( + Map textWriter, + PdfDictionary dictionary, + ) { + if (dictionary.count > 0) { + dictionary.items!.forEach((PdfName? name, IPdfPrimitive? value) { + _writeObject(textWriter, name!.name, value, null); + }); + } + } + + void _writeObject( + Map? textWriter, + String? key, + IPdfPrimitive? primitive, + List>? arrayWriter, + ) { + if (primitive != null) { + final String type = primitive.runtimeType.toString(); + switch (type) { + case 'PdfReferenceHolder': + final PdfReferenceHolder holder = primitive as PdfReferenceHolder; + if (holder.object != null) { + _writeObject(textWriter, key, holder.object, arrayWriter); + } + break; + case 'PdfDictionary': + final PdfDictionary dictionaryElement = primitive as PdfDictionary; + final Map mainTable = {}; + final Map subtable = {}; + _writeAppearanceDictionary(subtable, dictionaryElement); + mainTable['dict'] = convertToJson(subtable); + if (key != null) { + textWriter![key] = convertToJson(mainTable); + } else { + arrayWriter!.add(mainTable); + } + break; + case 'PdfStream': + final IPdfPrimitive? streamElement = (primitive as PdfStream) + .cloneObject(PdfDocumentHelper.getHelper(_document).crossTable); + if (streamElement != null && streamElement is PdfStream) { + if (streamElement.dataStream != null && + streamElement.dataStream!.isNotEmpty) { + final Map streamTable = {}; + _writeAppearanceDictionary(streamTable, streamElement); + final Map dataTable = {}; + final String? type = _getValue( + streamElement[PdfDictionaryProperties.subtype], + ); + if ((streamElement.containsKey(PdfDictionaryProperties.subtype) && + !isNullOrEmpty(type) && + PdfDictionaryProperties.image == type!) || + (!streamElement.containsKey(PdfDictionaryProperties.type) && + !streamElement.containsKey( + PdfDictionaryProperties.subtype, + ))) { + dataTable['mode'] = 'raw'; + dataTable['encoding'] = 'hex'; + final String data = PdfString.bytesToHex( + streamElement.dataStream!, + ); + if (!isNullOrEmpty(data)) { + dataTable['bytes'] = data; + } + } else if (streamElement.containsKey( + PdfDictionaryProperties.subtype, + ) && + !isNullOrEmpty(type) && + (PdfDictionaryProperties.form == type || + 'CIDFontType0C' == type || + 'OpenType' == type)) { + dataTable['mode'] = 'raw'; + dataTable['encoding'] = 'hex'; + streamElement.decompress(); + final String data = PdfString.bytesToHex( + streamElement.dataStream!, + ); + if (!isNullOrEmpty(data)) { + dataTable['bytes'] = data; + } + } else { + dataTable['mode'] = 'filtered'; + dataTable['encoding'] = 'ascii'; + streamElement.decompress(); + final String ascii = PdfString.bytesToHex( + streamElement.dataStream!, + ); + if (!isNullOrEmpty(ascii)) { + dataTable['bytes'] = ascii; + } + } + streamTable['data'] = convertToJson(dataTable); + final Map keyValuePairs = {}; + keyValuePairs['stream'] = convertToJson(streamTable); + if (key != null) { + textWriter![key] = convertToJson(keyValuePairs); + } else { + arrayWriter!.add(keyValuePairs); + } + } + } + break; + case 'PdfBoolean': + final PdfBoolean booleanElement = primitive as PdfBoolean; + final Map boolean = {}; + boolean['boolean'] = booleanElement.value.toString(); + if (key != null) { + textWriter![key] = convertToJson(boolean); + } else { + arrayWriter!.add(boolean); + } + break; + case 'PdfName': + if (primitive is PdfName && primitive.name != null) { + final Map name = {}; + name['name'] = primitive.name!; + if (key != null) { + textWriter![key] = convertToJson(name); + } else { + arrayWriter!.add(name); + } + } + break; + case 'PdfString': + if (primitive is PdfString && primitive.value != null) { + final Map stringValue = {}; + stringValue['string'] = primitive.value!; + if (key != null) { + textWriter![key] = convertToJson(stringValue); + } else { + arrayWriter!.add(stringValue); + } + } + break; + case 'PdfNumber': + if (primitive is PdfNumber && primitive.value != null) { + if (primitive.value is int) { + final Map integer = {}; + integer['int'] = primitive.value!.toString(); + if (key != null) { + textWriter![key] = convertToJson(integer); + } else { + arrayWriter!.add(integer); + } + } else { + final String value = primitive.value!.toDouble().toStringAsFixed( + 6, + ); + final Map integer = {}; + integer['fixed'] = value; + if (key != null) { + textWriter![key] = convertToJson(integer); + } else { + arrayWriter!.add(integer); + } + } + } + break; + case 'PdfNull': + final Map nullValue = {}; + nullValue['null'] = 'null'; + if (key != null) { + textWriter![key] = convertToJson(nullValue); + } else { + arrayWriter!.add(nullValue); + } + break; + case 'PdfArray': + final List> arrayDict = >[]; + _writeArray(arrayDict, primitive as PdfArray); + final Map tempDict = {}; + tempDict['array'] = _convertListToJson(arrayDict); + if (key != null) { + textWriter![key] = convertToJson(tempDict); + } else { + arrayWriter!.add(tempDict); + } + break; + } + } + } + + void _writeArray(List> textWriter, PdfArray array) { + for (final IPdfPrimitive? element in array.elements) { + if (element != null) { + _writeObject(null, null, element, textWriter); + } + } + } + + String _convertListToJson(List> value) { + String json = '['; + for (int i = 0; i < value.length; i++) { + json += convertToJson(value[i]); + if (i < value.length - 1) { + json = '$json,'; + } + } + json += ']'; + return json; + } + + String? _getValue(IPdfPrimitive? primitive) { + String? value; + if (primitive != null) { + if (primitive is PdfName) { + value = primitive.name; + } else if (primitive is PdfBoolean) { + value = primitive.value.toString(); + } else if (primitive is PdfString) { + value = primitive.value; + if (value != null && (value.startsWith('[') || value.startsWith('{'))) { + value = ' $value'; + } + value = _getValidString(value); + } else if (primitive is PdfArray) { + if (primitive.elements.isNotEmpty) { + for (int i = 0; i < primitive.elements.length; i++) { + final String? colorValue = _getValue(primitive.elements[i]); + if (colorValue != null) { + value = i == 0 ? colorValue : '$value,$colorValue'; + } + } + } + } else if (primitive is PdfNumber) { + if (primitive.value != null) { + value = primitive.value!.toString(); + } + } + } + return value; + } + + String? _getValidString(String? value) { + if (value != null) { + if (value.contains('"')) { + final RegExp regExp = RegExp(r'(? table, + ) { + switch (key) { + case PdfDictionaryProperties.c: + final String color = _getColor(primitive); + if (!isNullOrEmpty(color)) { + table['color'] = color; + } + break; + case PdfDictionaryProperties.da: + final IPdfPrimitive? defaultAppearance = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.da], + ); + if (defaultAppearance != null && + defaultAppearance is PdfString && + !isNullOrEmpty(defaultAppearance.value)) { + table['defaultappearance'] = defaultAppearance.value!; + } + break; + case PdfDictionaryProperties.ic: + final String interiorColor = _getColor(primitive); + if (!isNullOrEmpty(interiorColor)) { + table['interior-color'] = interiorColor; + } + break; + case PdfDictionaryProperties.m: + final IPdfPrimitive? modifiedDate = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.m], + ); + if (modifiedDate != null && + modifiedDate is PdfString && + !isNullOrEmpty(modifiedDate.value)) { + final DateTime dateTime = dictionary.getDateTime(modifiedDate); + table['date'] = DateFormat('M/d/yyyy h:mm:ss a').format(dateTime); + } + break; + case 'NM': + final String? value = _getValue(primitive); + if (!isNullOrEmpty(value)) { + table[PdfDictionaryProperties.name.toLowerCase()] = value!; + } + break; + case PdfDictionaryProperties.name: + final String? value = _getValue(primitive); + if (!isNullOrEmpty(value)) { + table['icon'] = value!; + } + break; + case PdfDictionaryProperties.subj: + final String? value = _getValue(primitive); + if (!isNullOrEmpty(value)) { + table[PdfDictionaryProperties.subject.toLowerCase()] = value!; + } + break; + case PdfDictionaryProperties.t: + final String? value = _getValue(primitive); + if (!table.containsKey(PdfDictionaryProperties.title.toLowerCase())) { + table[PdfDictionaryProperties.title.toLowerCase()] = value!; + } + break; + case PdfDictionaryProperties.rect: + final String? rect = _getValue(primitive); + if (!isNullOrEmpty(rect)) { + final List styleArray = rect!.split(','); + final Map subTable = {}; + subTable['x'] = styleArray[0]; + subTable['y'] = styleArray[1]; + subTable['width'] = styleArray[2]; + subTable['height'] = styleArray[3]; + table[key.toLowerCase()] = convertToJson(subTable); + } + break; + case PdfDictionaryProperties.creationDate: + final IPdfPrimitive? createDate = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.creationDate], + ); + if (createDate != null && + createDate is PdfString && + !isNullOrEmpty(createDate.value)) { + final DateTime creationDate = dictionary.getDateTime(createDate); + table[key.toLowerCase()] = DateFormat( + 'M/d/yyyy h:mm:ss a', + ).format(creationDate); + } + break; + case PdfDictionaryProperties.rotate: + final String? rotation = _getValue(primitive); + if (!isNullOrEmpty(rotation)) { + table['rotation'] = rotation!; + } + break; + case PdfDictionaryProperties.w: + final String? width = _getValue(primitive); + if (!isNullOrEmpty(width)) { + table[PdfDictionaryProperties.width.toLowerCase()] = width!; + } + break; + case PdfDictionaryProperties.le: + if (primitive is PdfArray) { + if (primitive.count == 2) { + table['head'] = _getValue(primitive.elements[0])!; + table['tail'] = _getValue(primitive.elements[1])!; + } + } else if (primitive is PdfName) { + final String? head = _getValue(primitive); + if (!isNullOrEmpty(head)) { + table['head'] = head!; + } + } + break; + case 'S': + final String? style = _getValue(primitive); + if (!isNullOrEmpty(style)) { + switch (style) { + case PdfDictionaryProperties.d: + table['style'] = 'dash'; + break; + case PdfDictionaryProperties.c: + table['style'] = 'cloudy'; + break; + case PdfDictionaryProperties.s: + table['style'] = 'solid'; + break; + case 'B': + table['style'] = 'bevelled'; + break; + case PdfDictionaryProperties.i: + table['style'] = 'inset'; + break; + case PdfDictionaryProperties.u: + table['style'] = 'underline'; + break; + } + } + break; + case PdfDictionaryProperties.d: + if (!table.containsKey('dashes')) { + final String? dashes = _getValue(primitive); + if (!isNullOrEmpty(dashes)) { + table['dashes'] = dashes!; + } + } + break; + case PdfDictionaryProperties.i: + final String? intensity = _getValue(primitive); + if (!isNullOrEmpty(intensity)) { + table['intensity'] = intensity!; + } + break; + case PdfDictionaryProperties.rd: + final String? fringe = _getValue(primitive); + if (!isNullOrEmpty(fringe)) { + table['fringe'] = fringe!; + } + break; + case PdfDictionaryProperties.it: + final String? it = _getValue(primitive); + if (!isNullOrEmpty(it)) { + table[key] = it!; + } + break; + case 'RT': + final String? replyType = _getValue(primitive); + if (!isNullOrEmpty(replyType)) { + table['replyType'] = replyType!.toLowerCase(); + } + break; + case PdfDictionaryProperties.ll: + final String? leaderLength = _getValue(primitive); + if (!isNullOrEmpty(leaderLength)) { + table['leaderLength'] = leaderLength!; + } + break; + case PdfDictionaryProperties.lle: + final String? leaderExtend = _getValue(primitive); + if (!isNullOrEmpty(leaderExtend)) { + table['leaderExtend'] = leaderExtend!; + } + break; + case PdfDictionaryProperties.cap: + final String? caption = _getValue(primitive); + if (!isNullOrEmpty(caption)) { + table['caption'] = caption!; + } + break; + case PdfDictionaryProperties.cp: + final String? captionStyle = _getValue(primitive); + if (!isNullOrEmpty(captionStyle)) { + table['caption-style'] = captionStyle!; + } + break; + case 'CL': + final String? callout = _getValue(primitive); + if (!isNullOrEmpty(callout)) { + table['callout'] = callout!; + } + break; + case PdfDictionaryProperties.quadPoints: + final String? coords = _getValue(primitive); + if (!isNullOrEmpty(coords)) { + table['coords'] = coords!; + } + break; + case PdfDictionaryProperties.ca: + final String? opacity = _getValue(primitive); + if (!isNullOrEmpty(opacity)) { + table['opacity'] = opacity!; + } + break; + case PdfDictionaryProperties.f: + if (primitive is PdfNumber) { + final List annotationFlags = + PdfAnnotationHelper.obtainAnnotationFlags( + primitive.value!.toInt(), + ); + final String flag = + annotationFlags + .map((PdfAnnotationFlags flag) => getEnumName(flag)) + .toString() + .replaceAll(RegExp('[ ()]'), '') + .toLowerCase(); + table[PdfDictionaryProperties.flags.toLowerCase()] = flag; + } + break; + case PdfDictionaryProperties.contents: + final IPdfPrimitive? contents = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.contents], + ); + if (contents != null && + contents is PdfString && + !isNullOrEmpty(contents.value)) { + table['contents'] = _getValidString(contents.value)!; + } + break; + case 'InkList': + final Map points = {}; + final IPdfPrimitive? inkList = PdfCrossTable.dereference( + dictionary['InkList'], + ); + if (inkList != null && inkList is PdfArray && inkList.count > 0) { + final List element = []; + for (int j = 0; j < inkList.count; j++) { + if (inkList[j]! is PdfArray) { + element.add(inkList[j]! as PdfArray); + } + } + points['gesture'] = _convertToJsonArray(element); + table['inklist'] = convertToJson(points); + } + break; + case PdfDictionaryProperties.vertices: + final IPdfPrimitive? vertices = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.vertices], + ); + if (vertices != null && vertices is PdfArray && vertices.count > 0) { + if (vertices.count.isEven) { + String value = ''; + IPdfPrimitive? numberElement; + for (int i = 0; i < vertices.count - 1; i++) { + numberElement = vertices.elements[i]; + if (numberElement != null && numberElement is PdfNumber) { + final String? number = _getValue(numberElement); + if (!isNullOrEmpty(number)) { + value += number! + (i % 2 != 0 ? ';' : ','); + } + } + } + numberElement = vertices.elements[vertices.count - 1]; + if (numberElement != null && numberElement is PdfNumber) { + final String? number = _getValue(numberElement); + if (!isNullOrEmpty(number)) { + value += number!; + } + } + if (!isNullOrEmpty(value)) { + table['vertices'] = value; + } + } + } + break; + case 'DS': + if (dictionary.containsKey('DS')) { + final IPdfPrimitive? defaultStyle = PdfCrossTable.dereference( + dictionary['DS'], + ); + final Map styleTable = {}; + if (defaultStyle != null && + defaultStyle is PdfString && + !isNullOrEmpty(defaultStyle.value)) { + final List textStyle = defaultStyle.value!.split(';'); + for (int i = 0; i < textStyle.length; i++) { + if (!isNullOrEmpty(textStyle[i]) && textStyle[i].contains(',')) { + textStyle[i] = _replaceJsonDelimiters(textStyle[i]); + } + final List text = textStyle[i].split(':'); + styleTable[text[0]] = text[1]; + } + } + table['defaultStyle'] = convertToJson(styleTable); + } + break; + case 'RC': + if (dictionary.containsKey('RC')) { + final IPdfPrimitive? contentStyle = PdfCrossTable.dereference( + dictionary['RC'], + ); + if (contentStyle != null && + contentStyle is PdfString && + !isNullOrEmpty(contentStyle.value)) { + String value = contentStyle.value!; + final int index = value.indexOf(' 0) { + value = value.substring(index); + } + table['contents-richtext'] = _getValidString(value)!; + } + } + break; + case PdfDictionaryProperties.type: + case PdfDictionaryProperties.subtype: + case PdfDictionaryProperties.p: + case PdfDictionaryProperties.parent: + case PdfDictionaryProperties.l: + case PdfDictionaryProperties.fs: + case 'MeasurementTypes': + case 'GroupNesting': + case 'ITEx': + case 'Sound': + break; + case PdfDictionaryProperties.border: + case PdfDictionaryProperties.a: + case PdfDictionaryProperties.r: + case PdfDictionaryProperties.x: + final String? value = _getValue(primitive); + if (!isNullOrEmpty(value)) { + table[key.toLowerCase()] = value!; + } + break; + default: + final String? value = _getValue(primitive); + if (!isNullOrEmpty(value)) { + table[key] = value!; + } + break; + } + } + + String _convertToJsonArray(List value) { + String json = '['; + for (int i = 0; i < value.length; i++) { + final String? point = _getValue(value[i]); + if (point != null) { + json = '$json[$point]'; + } + if (i < value.length - 1) { + json = '$json,'; + } + } + json = '$json]'; + return json; + } + + String _getColor(IPdfPrimitive primitive) { + String color = ''; + if (primitive is PdfArray && primitive.count >= 3) { + final String r = + PdfString.bytesToHex([ + ((primitive.elements[0]! as PdfNumber).value! * 255).round(), + ]).toUpperCase(); + final String g = + PdfString.bytesToHex([ + ((primitive.elements[1]! as PdfNumber).value! * 255).round(), + ]).toUpperCase(); + final String b = + PdfString.bytesToHex([ + ((primitive.elements[2]! as PdfNumber).value! * 255).round(), + ]).toUpperCase(); + color = '#$r$g$b'; + } + return color; + } + + void _exportMeasureDictionary( + PdfDictionary dictionary, + Map table, + ) { + final IPdfPrimitive? mdictionary = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.measure], + ); + if (mdictionary != null && mdictionary is PdfDictionary) { + if (mdictionary.containsKey(PdfDictionaryProperties.type)) { + table['type1'] = 'Measure'; + } + if (mdictionary.containsKey(PdfDictionaryProperties.r)) { + final String? value = _getValue(mdictionary[PdfDictionaryProperties.r]); + if (!isNullOrEmpty(value)) { + table['ratevalue'] = value!; + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.subtype)) { + final String? value = _getValue( + mdictionary[PdfDictionaryProperties.subtype], + ); + if (!isNullOrEmpty(value)) { + table[PdfDictionaryProperties.subtype] = value!; + } + } + if (mdictionary.containsKey('TargetUnitConversion')) { + final String? value = _getValue(mdictionary['TargetUnitConversion']); + if (!isNullOrEmpty(value)) { + table['TargetUnitConversion'] = value!; + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.a)) { + final IPdfPrimitive? aArray = mdictionary[PdfDictionaryProperties.a]; + if (aArray != null && + aArray is PdfArray && + aArray.elements.isNotEmpty) { + final IPdfPrimitive? adictionary = PdfCrossTable.dereference( + aArray.elements[0], + ); + if (adictionary != null && adictionary is PdfDictionary) { + _exportMeasureFormatDetails('area', adictionary, table); + } + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.d)) { + final IPdfPrimitive? dArray = mdictionary[PdfDictionaryProperties.d]; + if (dArray != null && + dArray is PdfArray && + dArray.elements.isNotEmpty) { + final IPdfPrimitive? ddictionary = PdfCrossTable.dereference( + dArray.elements[0], + ); + if (ddictionary != null && ddictionary is PdfDictionary) { + _exportMeasureFormatDetails('distance', ddictionary, table); + } + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.x)) { + final IPdfPrimitive? xArray = mdictionary[PdfDictionaryProperties.x]; + if (xArray != null && + xArray is PdfArray && + xArray.elements.isNotEmpty) { + final IPdfPrimitive? xdictionary = PdfCrossTable.dereference( + xArray.elements[0], + ); + if (xdictionary != null && xdictionary is PdfDictionary) { + _exportMeasureFormatDetails('xformat', xdictionary, table); + } + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.t)) { + final IPdfPrimitive? tArray = mdictionary[PdfDictionaryProperties.t]; + if (tArray != null && + tArray is PdfArray && + tArray.elements.isNotEmpty) { + final IPdfPrimitive? tdictionary = PdfCrossTable.dereference( + tArray.elements[0], + ); + if (tdictionary != null && tdictionary is PdfDictionary) { + _exportMeasureFormatDetails('tformat', tdictionary, table); + } + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.v)) { + final IPdfPrimitive? vArray = mdictionary[PdfDictionaryProperties.v]; + if (vArray != null && + vArray is PdfArray && + vArray.elements.isNotEmpty) { + final IPdfPrimitive? vdictionary = PdfCrossTable.dereference( + vArray.elements[0], + ); + if (vdictionary != null && vdictionary is PdfDictionary) { + _exportMeasureFormatDetails('vformat', vdictionary, table); + } + } + } + } + } + + void _exportMeasureFormatDetails( + String key, + PdfDictionary measurementDetails, + Map table, + ) { + final Map subTable = {}; + if (measurementDetails.containsKey(PdfDictionaryProperties.c)) { + final String? value = _getValue( + measurementDetails[PdfDictionaryProperties.c], + ); + if (!isNullOrEmpty(value)) { + subTable['c'] = value!; + } + } + if (measurementDetails.containsKey(PdfDictionaryProperties.f)) { + final String? value = _getValue( + measurementDetails[PdfDictionaryProperties.f], + ); + if (!isNullOrEmpty(value)) { + subTable['f'] = value!; + } + } + if (measurementDetails.containsKey(PdfDictionaryProperties.d)) { + final String? value = _getValue( + measurementDetails[PdfDictionaryProperties.d], + ); + if (!isNullOrEmpty(value)) { + subTable['d'] = value!; + } + } + if (measurementDetails.containsKey(PdfDictionaryProperties.rd)) { + final String? value = _getValue( + measurementDetails[PdfDictionaryProperties.rd], + ); + if (!isNullOrEmpty(value)) { + subTable['rd'] = value!; + } + } + if (measurementDetails.containsKey(PdfDictionaryProperties.u)) { + final String? value = _getValue( + measurementDetails[PdfDictionaryProperties.u], + ); + if (!isNullOrEmpty(value)) { + subTable['u'] = value!; + } + } + if (measurementDetails.containsKey('RT')) { + final String? value = _getValue(measurementDetails['RT']); + if (!isNullOrEmpty(value)) { + subTable['rt'] = value!; + } + } + if (measurementDetails.containsKey('SS')) { + final String? value = _getValue(measurementDetails['SS']); + if (!isNullOrEmpty(value)) { + subTable['ss'] = value!; + } + } + if (measurementDetails.containsKey('FD')) { + final String? value = _getValue(measurementDetails['FD']); + if (!isNullOrEmpty(value)) { + subTable['fd'] = value!; + } + } + if (measurementDetails.containsKey(PdfDictionaryProperties.type)) { + final String? value = _getValue( + measurementDetails[PdfDictionaryProperties.type], + ); + if (!isNullOrEmpty(value)) { + subTable[PdfDictionaryProperties.type] = value!; + } + } + table[key] = convertToJson(subTable); + } + + String _replaceJsonDelimiters(String value) { + // ignore: unnecessary_string_escapes + return value.contains(RegExp('[":,{}]|[\[]|]')) + ? value + .replaceAll(',', '_x002C_') + .replaceAll('"', '_x0022_') + .replaceAll(':', '_x003A_') + .replaceAll('{', '_x007B_') + .replaceAll('}', '_x007D_') + .replaceAll('[', '_x005B_') + .replaceAll(']', '_x005D_') + : value; + } + + String? _getAnnotationType(PdfDictionary dictionary) { + if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? subtype = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.subtype], + ); + if (subtype != null && subtype is PdfName && subtype.name != null) { + return subtype.name!; + } + } + return null; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_parser.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_parser.dart index 915d65ea4..916afaca2 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_parser.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/json_parser.dart @@ -1,1418 +1,1418 @@ -import 'dart:convert'; - -import 'package:convert/convert.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../forms/pdf_form.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'xfdf_parser.dart'; - -/// Internal class. -class JsonParser { - /// Internal Constructor. - JsonParser(this.document); - - /// Internal Field. - late PdfDocument document; - - /// Internal Field. - String? annotation; - - /// Internal Field. - String? style; - - /// Internal Field. - bool isBasicStyle = true; - - /// Internal Field. - String? beginLineStyle; - - /// Internal Field. - String? endLineStyle; - - /// Internal Field. - Map? dataStream; - - /// Internal Field. - String? values; - - /// Internal Field. - Map? groupReferences; - - /// Internal Field. - List? groupHolders; - - bool _isNormalAppearanceAdded = false; - - /// Internal Method. - void importAnnotationData(List? data) { - if (data != null) { - final Map jsonData = json.decode(utf8.decode(data)); - parseJsonData(jsonData); - jsonData.clear(); - if (groupHolders != null && groupHolders!.isNotEmpty) { - for (final PdfDictionary dictionary in groupHolders!) { - final IPdfPrimitive? inReplyTo = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.irt], - ); - if (inReplyTo != null && - inReplyTo is PdfString && - !isNullOrEmpty(inReplyTo.value)) { - if (groupReferences != null && - groupReferences!.containsKey(inReplyTo.value)) { - dictionary[PdfDictionaryProperties.irt] = - groupReferences![inReplyTo.value]; - } else { - dictionary.remove(PdfDictionaryProperties.irt); - } - } - } - } - if (groupReferences != null) { - groupReferences!.clear(); - } - if (groupHolders != null) { - groupHolders!.clear(); - } - groupReferences = null; - groupHolders = null; - } - } - - /// Internal Method. - void parseJsonData(Map data) { - if (data.containsKey('type')) { - parseAnnotationData(data); - } - for (final dynamic value in data.values) { - if (value is Map) { - parseJsonData(value); - } else if (value is List) { - // ignore: avoid_function_literals_in_foreach_calls - value.forEach((dynamic element) { - if (element is Map) { - parseJsonData(element); - } - }); - } - } - } - - /// Internal Method. - void parseAnnotationData(Map annotData) { - final String page = annotData.containsKey('page') ? annotData['page'] : ''; - final String type = annotData.containsKey('type') ? annotData['type'] : ''; - final int pageIndex = int.tryParse(page) ?? -1; - if (pageIndex >= 0 && pageIndex < document.pages.count) { - final PdfPage loadedPage = document.pages[pageIndex]; - PdfPageHelper.getHelper(loadedPage).importAnnotation = true; - final PdfDictionary annotDictionary = getAnnotationData( - type, - pageIndex, - annotData, - ); - if (annotDictionary.count > 0) { - final PdfReferenceHolder holder = PdfReferenceHolder(annotDictionary); - if (annotDictionary.containsKey(PdfDictionaryProperties.nm) || - annotDictionary.containsKey(PdfDictionaryProperties.irt)) { - addReferenceToGroup(holder, annotDictionary); - } - final PdfDictionary? pageDictionary = - PdfPageHelper.getHelper(document.pages[pageIndex]).dictionary; - if (pageDictionary != null) { - if (!pageDictionary.containsKey(PdfDictionaryProperties.annots)) { - pageDictionary[PdfDictionaryProperties.annots] = PdfArray(); - } - final IPdfPrimitive? annots = PdfCrossTable.dereference( - pageDictionary[PdfDictionaryProperties.annots], - ); - if (annots != null && annots is PdfArray) { - annots.elements.add(holder); - annots.changed = true; - } - } - } - } - beginLineStyle = null; - endLineStyle = null; - } - - /// Internal Method. - void addReferenceToGroup( - PdfReferenceHolder holder, - PdfDictionary dictionary, - ) { - IPdfPrimitive? name = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.nm], - ); - groupReferences ??= {}; - if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { - groupReferences![name.value!] = holder; - if (dictionary.containsKey(PdfDictionaryProperties.irt)) { - groupHolders ??= []; - groupHolders!.add(dictionary); - } - } else if (name == null) { - if (dictionary.containsKey(PdfDictionaryProperties.irt)) { - name = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.irt], - ); - } - if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { - if (groupReferences!.containsKey(name.value)) { - final PdfReferenceHolder referenceHolder = - groupReferences![name.value]!; - dictionary[PdfDictionaryProperties.irt] = referenceHolder; - } - } - } - } - - /// Internal Method. - PdfDictionary getAnnotationData( - String type, - int pageindex, - Map annotData, - ) { - final PdfDictionary annotDictionary = PdfDictionary(); - annotDictionary.setName( - PdfDictionaryProperties.type, - PdfDictionaryProperties.annot, - ); - bool isValidType = true; - switch (type.toLowerCase()) { - case 'line': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.line, - ); - break; - case 'circle': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.circle, - ); - break; - case 'square': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.square, - ); - break; - case 'polyline': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'PolyLine'); - break; - case 'polygon': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.polygon, - ); - break; - case 'ink': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'Ink'); - break; - case 'popup': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.popup, - ); - break; - case 'text': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.text, - ); - break; - case 'freetext': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'FreeText'); - break; - case 'stamp': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'Stamp'); - break; - case 'highlight': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.highlight, - ); - break; - case 'squiggly': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.squiggly, - ); - break; - case 'underline': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.underline, - ); - break; - case 'strikeout': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.strikeOut, - ); - break; - case 'fileattachment': - annotDictionary.setName( - PdfDictionaryProperties.subtype, - 'FileAttachment', - ); - break; - case 'sound': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'Sound'); - break; - case 'redact': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'Redact'); - annotation = 'redact'; - break; - case 'caret': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'Caret'); - break; - case 'watermark': - annotDictionary.setName(PdfDictionaryProperties.subtype, 'Watermark'); - break; - default: - isValidType = false; - break; - } - if (isValidType) { - addAnnotationData(annotDictionary, annotData, pageindex); - } - return annotDictionary; - } - - /// Internal method. - void addAnnotationData( - PdfDictionary annotDictionary, - Map annotData, - int index, - ) { - List? linePoints = []; - final PdfDictionary borderEffectDictionary = PdfDictionary(); - final PdfDictionary borderStyleDictionary = PdfDictionary(); - annotData.forEach((String key, dynamic value) { - if (value is String) { - value = PdfFormHelper.decodeXMLConversion(value); - } - switch (key.toLowerCase()) { - case 'start': - case 'end': - linePoints!.addAll(_obtainFloatPoints(value)); - if (linePoints!.length == 4) { - annotDictionary.setProperty( - PdfDictionaryProperties.l, - PdfArray(linePoints), - ); - linePoints!.clear(); - linePoints = null; - } - break; - case 'itex': - break; - case 'state': - addString(annotDictionary, 'State', value.toString()); - break; - case 'statemodel': - addString(annotDictionary, 'StateModel', value.toString()); - break; - case 'replytype': - if (value == 'group') { - annotDictionary.setName('RT', 'Group'); - } - break; - case 'inreplyto': - addString( - annotDictionary, - PdfDictionaryProperties.irt, - value.toString(), - ); - break; - case 'dashes': - case 'width': - case 'intensity': - case 'style': - addBorderStyle( - key, - value, - borderEffectDictionary, - borderStyleDictionary, - ); - break; - case 'rect': - final List points = _obtainFloatPoints(value.values.toList()); - if (points.length == 4) { - annotDictionary.setProperty( - PdfDictionaryProperties.rect, - PdfArray(points), - ); - } - break; - case 'color': - if (value is String && !isNullOrEmpty(value)) { - final PdfArray? colorArray = getColorArray(value); - if (colorArray != null) { - annotDictionary.setProperty( - PdfDictionaryProperties.c, - colorArray, - ); - } - } - break; - case 'oc': - if (annotation == 'redact') { - if (value is String && !isNullOrEmpty(value)) { - final PdfArray? colorArray = getColorArray(value); - if (colorArray != null) { - annotDictionary.setProperty( - PdfDictionaryProperties.ic, - colorArray, - ); - } - } - } - break; - case 'interior-color': - if (value is String && !isNullOrEmpty(value)) { - final PdfArray? colorArray = getColorArray(value); - if (colorArray != null) { - annotDictionary.setProperty( - PdfDictionaryProperties.ic, - colorArray, - ); - } - } - break; - case 'date': - addString( - annotDictionary, - PdfDictionaryProperties.m, - value.toString(), - ); - break; - case 'creationdate': - addString( - annotDictionary, - PdfDictionaryProperties.creationDate, - value.toString(), - ); - break; - case 'name': - addString( - annotDictionary, - PdfDictionaryProperties.nm, - value.toString(), - ); - break; - case 'icon': - if (value is String && !isNullOrEmpty(value)) { - annotDictionary.setName(PdfDictionaryProperties.name, value); - } - break; - case 'subject': - addString( - annotDictionary, - PdfDictionaryProperties.subj, - value.toString(), - ); - break; - case 'title': - addString(annotDictionary, PdfDictionaryProperties.t, value); - break; - case 'rotation': - addNumber(annotDictionary, PdfDictionaryProperties.rotate, value); - break; - case 'fringe': - addFloatPoints( - annotDictionary, - _obtainFloatPoints(value), - PdfDictionaryProperties.rd, - ); - break; - case 'it': - if (value is String && !isNullOrEmpty(value)) { - annotDictionary.setName(PdfDictionaryProperties.it, value); - } - break; - case 'leaderlength': - addNumber( - annotDictionary, - PdfDictionaryProperties.ll, - value.toString(), - ); - break; - case 'leaderextend': - addNumber( - annotDictionary, - PdfDictionaryProperties.lle, - value.toString(), - ); - break; - case 'caption': - if (value is String && !isNullOrEmpty(value)) { - annotDictionary.setBoolean( - PdfDictionaryProperties.cap, - value.toLowerCase() == 'yes' || value.toLowerCase() == 'true', - ); - } - break; - case 'caption-style': - if (value is String && !isNullOrEmpty(value)) { - annotDictionary.setName(PdfDictionaryProperties.cp, value); - } - break; - case 'callout': - addFloatPoints( - annotDictionary, - _obtainFloatPoints(value), - PdfDictionaryProperties.cl, - ); - break; - case 'coords': - addFloatPoints( - annotDictionary, - _obtainFloatPoints(value), - PdfDictionaryProperties.quadPoints, - ); - break; - case 'border': - addFloatPoints( - annotDictionary, - _obtainFloatPoints(value), - PdfDictionaryProperties.border, - ); - break; - case 'opacity': - addNumber(annotDictionary, PdfDictionaryProperties.ds, value); - break; - case 'defaultstyle': - addString( - annotDictionary, - PdfDictionaryProperties.ds, - value - .toString() - .replaceAll(RegExp(r'[{}]'), '') - .replaceAll(',', ';'), - ); - break; - case 'defaultappearance': - addString( - annotDictionary, - PdfDictionaryProperties.da, - value.toString().replaceAll(RegExp(r'[{},]'), ''), - ); - break; - case 'contents-richtext': - final String richtext = trimEscapeCharacters(value); - annotDictionary.setString(PdfDictionaryProperties.rc, richtext); - break; - case 'flags': - if (value is String && !isNullOrEmpty(value)) { - final List annotFlag = []; - if (value.contains(',')) { - final List values = value.split(','); - for (final String flag in values) { - final PdfAnnotationFlags flagType = - XfdfParser.mapAnnotationFlags(flag); - if (!annotFlag.contains(flagType)) { - annotFlag.add(flagType); - } - } - } else { - annotFlag.add(XfdfParser.mapAnnotationFlags(value)); - } - int flagValue = 0; - for (int i = 0; i < annotFlag.length; i++) { - flagValue |= PdfAnnotationHelper.getAnnotationFlagsValue( - annotFlag[i], - ); - } - if (flagValue > 0) { - annotDictionary.setNumber(PdfDictionaryProperties.f, flagValue); - } - } - break; - case 'open': - if (value is String && !isNullOrEmpty(value)) { - annotDictionary.setBoolean( - PdfDictionaryProperties.open, - value == 'true' || value == 'yes', - ); - } - break; - case 'repeat': - if (value is String && !isNullOrEmpty(value)) { - annotDictionary.setBoolean( - PdfDictionaryProperties.repeat, - value == 'true' || value == 'yes', - ); - } - break; - case 'overlaytext': - annotDictionary.setString(PdfDictionaryProperties.overlayText, value); - break; - case 'contents': - final String contents = trimEscapeCharacters(value); - if (!isNullOrEmpty(contents)) { - annotDictionary.setString( - PdfDictionaryProperties.contents, - contents, - ); - } - break; - case 'q': - final int? alignment = int.tryParse(value.toString()); - if (alignment != null) { - annotDictionary.setNumber(PdfDictionaryProperties.q, alignment); - } - break; - case 'inklist': - final PdfArray inkListCollection = PdfArray(); - final String inklist = value - .toString() - .replaceAll('gesture', '') - .replaceAll(RegExp(r'[\[\]{}:]'), ''); - final List pointsArray = inklist.split(','); - if (pointsArray.isNotEmpty) { - final List pointsList = []; - for (final String point in pointsArray) { - final num? result = num.tryParse(point); - if (result != null) { - pointsList.add(result); - } - } - if (pointsList.isNotEmpty && pointsList.length.isEven) { - inkListCollection.add(PdfArray(pointsList)); - } - pointsList.clear(); - } - annotDictionary.setProperty( - PdfDictionaryProperties.inkList, - inkListCollection, - ); - break; - case 'head': - beginLineStyle = getEnumName( - XfdfParser.mapLineEndingStyle(value.toString()), - ); - break; - case 'tail': - endLineStyle = getEnumName( - XfdfParser.mapLineEndingStyle(value.toString()), - ); - break; - case 'creation': - case 'modification': - case 'file': - case 'bits': - case 'channels': - case 'encoding': - case 'rate': - case 'length': - case 'filter': - case 'mode': - case 'size': - dataStream ??= {}; - dataStream![key] = value.toString(); - break; - case 'data': - values = value; - break; - case 'vertices': - if (value is String && !isNullOrEmpty(value)) { - final List vertices = value.split(RegExp('[;,]')); - if (vertices.isNotEmpty) { - final List verticesList = []; - for (final String vertice in vertices) { - addFloatPointsToCollection(verticesList, vertice); - } - if (verticesList.isNotEmpty && verticesList.length.isEven) { - annotDictionary.setProperty( - PdfDictionaryProperties.vertices, - PdfArray(verticesList), - ); - } - } - } - break; - case 'customdata': - addString( - annotDictionary, - PdfDictionaryProperties.customData, - trimEscapeCharacters(value.toString()), - ); - break; - case 'appearance': - _addAppearanceData(annotDictionary, value.toString()); - break; - default: - break; - } - }); - _addMeasureDictionary(annotDictionary, annotData); - if (!isNullOrEmpty(beginLineStyle)) { - if (!isNullOrEmpty(endLineStyle)) { - final PdfArray lineEndingStyles = PdfArray(); - lineEndingStyles.add(PdfName(beginLineStyle)); - lineEndingStyles.add(PdfName(endLineStyle)); - annotDictionary.setProperty( - PdfDictionaryProperties.le, - lineEndingStyles, - ); - } else { - annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); - } - } else if (!isNullOrEmpty(endLineStyle)) { - annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); - } - if (borderStyleDictionary.count > 0) { - borderStyleDictionary.setProperty( - PdfDictionaryProperties.type, - PdfName(PdfDictionaryProperties.border), - ); - annotDictionary.setProperty( - PdfDictionaryProperties.bs, - PdfReferenceHolder(borderStyleDictionary), - ); - } - if (borderEffectDictionary.count > 0) { - annotDictionary.setProperty( - PdfDictionaryProperties.be, - PdfReferenceHolder(borderEffectDictionary), - ); - } - if (dataStream != null && values != null) { - addStreamData(dataStream!, annotDictionary, values!); - } - } - - void _addMeasureDictionary( - PdfDictionary annotDictionary, - Map element, - ) { - Map? area; - Map? distance; - Map? xformat; - Map? tformat; - Map? vformat; - final PdfDictionary measureDictionary = PdfDictionary(); - final PdfArray dArray = PdfArray(); - final PdfArray aArray = PdfArray(); - final PdfArray xArray = PdfArray(); - final PdfArray tArray = PdfArray(); - final PdfArray vArray = PdfArray(); - final PdfDictionary dDict = PdfDictionary(); - final PdfDictionary aDict = PdfDictionary(); - final PdfDictionary xDict = PdfDictionary(); - final PdfDictionary tDict = PdfDictionary(); - final PdfDictionary vDict = PdfDictionary(); - measureDictionary.items![PdfName(PdfDictionaryProperties.a)] = aArray; - measureDictionary.items![PdfName(PdfDictionaryProperties.d)] = dArray; - measureDictionary.items![PdfName(PdfDictionaryProperties.x)] = xArray; - measureDictionary.items![PdfName(PdfDictionaryProperties.t)] = tArray; - measureDictionary.items![PdfName(PdfDictionaryProperties.v)] = vArray; - if (element.containsKey(PdfDictionaryProperties.type1.toLowerCase())) { - measureDictionary.setName( - PdfDictionaryProperties.type, - PdfDictionaryProperties.measure, - ); - } - element.forEach((String key, dynamic value) { - if (value is String) { - switch (key.toLowerCase()) { - case 'ratevalue': - measureDictionary.setString(PdfDictionaryProperties.r, value); - break; - case 'subtype': - measureDictionary.setString(PdfDictionaryProperties.subtype, value); - break; - case 'targetunitconversion': - measureDictionary.setString( - PdfDictionaryProperties.targetUnitConversion, - value, - ); - break; - case 'area': - area = {}; - area = _addDictionaryData(area!, value); - break; - case 'distance': - distance = {}; - distance = _addDictionaryData(distance!, value); - break; - case 'xformat': - xformat = {}; - xformat = _addDictionaryData(xformat!, value); - break; - case 'tformat': - tformat = {}; - tformat = _addDictionaryData(tformat!, value); - break; - case 'vformat': - vformat = {}; - vformat = _addDictionaryData(vformat!, value); - break; - } - } - }); - if (xformat != null) { - _addElements(xformat!, xDict); - xArray.add(xDict); - } - if (area != null) { - _addElements(area!, aDict); - aArray.add(aDict); - } - if (distance != null) { - _addElements(distance!, dDict); - dArray.add(dDict); - } - if (vformat != null) { - _addElements(vformat!, vDict); - vArray.add(vDict); - } - if (tformat != null) { - _addElements(tformat!, tDict); - tArray.add(tDict); - } - if (measureDictionary.count > 0 && - measureDictionary.containsKey(PdfDictionaryProperties.type)) { - annotDictionary.items![PdfName( - PdfDictionaryProperties.measure, - )] = PdfReferenceHolder(measureDictionary); - } - } - - void _addElements(Map element, PdfDictionary dictionary) { - element.forEach((String key, String value) { - final num? elementValue = num.tryParse(value); - if (elementValue != null) { - switch (key.toLowerCase()) { - case 'd': - dictionary.items![PdfName(PdfDictionaryProperties.d)] = PdfNumber( - elementValue, - ); - break; - case 'c': - dictionary.items![PdfName(PdfDictionaryProperties.c)] = PdfNumber( - elementValue, - ); - break; - case 'rt': - dictionary.items![PdfName(PdfDictionaryProperties.rt)] = PdfNumber( - elementValue, - ); - break; - case 'rd': - dictionary.items![PdfName(PdfDictionaryProperties.rd)] = PdfNumber( - elementValue, - ); - break; - case 'ss': - dictionary.items![PdfName(PdfDictionaryProperties.ss)] = PdfNumber( - elementValue, - ); - break; - case 'u': - dictionary.items![PdfName(PdfDictionaryProperties.u)] = PdfNumber( - elementValue, - ); - break; - case 'f': - dictionary.items![PdfName(PdfDictionaryProperties.f)] = PdfNumber( - elementValue, - ); - break; - case 'fd': - dictionary.items![PdfName(PdfDictionaryProperties.fd)] = PdfNumber( - elementValue, - ); - break; - case 'type': - dictionary.items![PdfName( - PdfDictionaryProperties.type, - )] = PdfNumber(elementValue); - break; - } - } - }); - } - - Map _addDictionaryData( - Map data, - String value, - ) { - String addValue = ''; - for (int k = 0; k < value.length; k++) { - addValue += (value[k] == ':' || value[k] == ';') ? '#' : value[k]; - } - final List valueSplit = addValue.split('#'); - for (int i = 0; i < valueSplit.length - 1; i += 2) { - data[valueSplit[i]] = valueSplit[i + 1]; - } - return data; - } - - void _addAppearanceData(PdfDictionary dictionary, String value) { - if (!isNullOrEmpty(value)) { - final List appearanceData = base64.decode(value); - if (appearanceData.isNotEmpty) { - final Map dict = json.decode( - utf8.decode(appearanceData), - ); - final PdfDictionary appearance = PdfDictionary(); - if (dict.isNotEmpty) { - for (final dynamic dictValue in dict.values) { - dictionary[PdfDictionaryProperties.ap] = PdfReferenceHolder( - _parseDictionaryItems(dictValue, appearance), - ); - } - } - } - } - _isNormalAppearanceAdded = false; - } - - IPdfPrimitive _parseDictionaryItems( - dynamic elementValue, - IPdfPrimitive primitive, - ) { - if (elementValue != null) { - if (elementValue is Map) { - for (String token in elementValue.keys) { - final dynamic value = elementValue[token]; - token = PdfFormHelper.decodeXMLConversion(token); - switch (token) { - case 'stream': - PdfStream stream = PdfStream(); - stream = _parseDictionaryItems(value, stream) as PdfStream; - return stream; - case 'array': - PdfArray array = PdfArray(); - array = _parseDictionaryItems(value, array) as PdfArray; - return array; - case 'name': - return PdfName(value.toString()); - case 'string': - return PdfString(value.toString()); - case 'boolean': - final bool test = value.toString().toLowerCase() == 'true'; - return PdfBoolean(test); - case 'dict': - PdfDictionary pdfDictionary = PdfDictionary(); - pdfDictionary = - _parseDictionaryItems(value, pdfDictionary) as PdfDictionary; - return pdfDictionary; - case 'int': - final int? result = int.tryParse(value.toString()); - if (result != null) { - return PdfNumber(result); - } - break; - case 'fixed': - final num? result = num.tryParse(value.toString()); - if (result != null) { - return PdfNumber(result); - } - break; - case 'data': - if (primitive is PdfStream && - value != null && - value is Map) { - primitive.data = _getStreamData(value); - if (!primitive.containsKey(PdfDictionaryProperties.type) && - !primitive.containsKey(PdfDictionaryProperties.subtype)) { - primitive.decompress(); - } - bool isImage = false; - if (primitive.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? subtype = PdfCrossTable.dereference( - primitive[PdfDictionaryProperties.subtype], - ); - if (subtype != null && - subtype is PdfName && - subtype.name == PdfDictionaryProperties.image) { - isImage = true; - } - } - if (isImage) { - primitive.compress = false; - } else { - if (primitive.containsKey(PdfDictionaryProperties.length)) { - primitive.remove(PdfDictionaryProperties.length); - } - if (primitive.containsKey(PdfDictionaryProperties.filter)) { - primitive.remove(PdfDictionaryProperties.filter); - } - } - } - break; - case 'N': - if (_isNormalAppearanceAdded && primitive is PdfDictionary) { - primitive[token] = _parseDictionaryItems(value, primitive); - } else if (primitive is PdfDictionary) { - _isNormalAppearanceAdded = true; - final PdfDictionary dic = PdfDictionary(); - primitive[token] = PdfReferenceHolder( - _parseDictionaryItems(value, dic), - ); - } else { - _isNormalAppearanceAdded = true; - final PdfDictionary dic = PdfDictionary(); - dic[token] = PdfReferenceHolder( - _parseDictionaryItems(value, dic), - ); - return dic; - } - break; - case 'BBox': - case 'Type': - case 'Subtype': - case 'Resources': - case 'BaseFont': - case 'ProcSet': - case 'Font': - case 'Encoding': - case 'Matrix': - case 'Length': - case 'CIDToGIDMap': - case 'DW': - case 'FontName': - case 'Flags': - case 'FontBBox': - case 'MissingWidth': - case 'StemV': - case 'ItalicAngle': - case 'CapHeight': - case 'Ascent': - case 'Descent': - case 'Leading': - case 'AvgWidth': - case 'MaxWidth': - case 'StemH': - case 'CIDSystemInfo': - case 'Registry': - case 'Ordering': - case 'Supplement': - case 'W': - case 'XObject': - case 'Filter': - case 'BitsPerComponent': - case 'ColorSpace': - case 'FormType': - case 'Name': - case 'Height': - case 'Width': - case 'Decode': - case 'DecodeParms': - case 'BlackIs1': - case 'Columns': - case 'K': - case 'Rows': - case 'ImageMask': - case 'Interpolate': - case 'ca': - case 'CA': - case 'AIS': - case 'BM': - case 'ExtGState': - case 'Pattern': - case 'PatternType': - case 'CS': - case 'I': - case 'S': - case 'Coords': - case 'Extend': - case 'ShadingType': - case 'Bounds': - case 'Domain': - case 'Encode': - case 'FunctionType': - case 'Widths': - case 'FirstChar': - case 'LastChar': - if (primitive is PdfDictionary) { - primitive[token] = _parseDictionaryItems(value, primitive); - } - break; - default: - if (primitive is PdfDictionary) { - final PdfDictionary temp = PdfDictionary(); - primitive[token] = PdfReferenceHolder( - _parseDictionaryItems(value, temp), - ); - } - break; - } - } - } else if (elementValue is List && primitive is PdfArray) { - final List list = elementValue; - for (int i = 0; i < list.length; i++) { - final dynamic listObject = list[i]; - if (listObject is Map) { - listObject.forEach((String token, dynamic value) { - token = PdfFormHelper.decodeXMLConversion(token); - switch (token) { - case 'int': - final int? result = int.tryParse(value.toString()); - if (result != null) { - primitive.add(PdfNumber(result)); - } - break; - case 'fixed': - final num? result = num.tryParse(value.toString()); - if (result != null) { - primitive.add(PdfNumber(result)); - } - break; - case 'name': - primitive.add(PdfName(value.toString())); - break; - case 'string': - primitive.add(PdfString(value.toString())); - break; - case 'dict': - PdfDictionary pdfDictionary = PdfDictionary(); - pdfDictionary = - _parseDictionaryItems(value, pdfDictionary) - as PdfDictionary; - primitive.add(PdfReferenceHolder(pdfDictionary)); - break; - case 'array': - PdfArray array = PdfArray(); - array = _parseDictionaryItems(value, array) as PdfArray; - primitive.add(array); - break; - case 'boolean': - final bool test = value.toString().toLowerCase() == 'true'; - primitive.add(PdfBoolean(test)); - break; - case 'stream': - PdfStream stream = PdfStream(); - stream = _parseDictionaryItems(value, stream) as PdfStream; - primitive.add(stream); - break; - } - }); - } - } - } - } - return primitive; - } - - List? _getStreamData(Map element) { - List? rawData; - String encoding = ''; - for (final String token in element.keys) { - final dynamic value = element[token]; - switch (token) { - case 'encoding': - encoding = value.toString(); - break; - case 'bytes': - if (value != null) { - if (encoding == 'hex') { - rawData = getBytes(value.toString()); - } else if (encoding == 'ascii') { - rawData = utf8.encode(value.toString()); - } - } - return rawData; - } - } - return rawData; - } - - /// Internal Methods. - void addString(PdfDictionary dictionary, String key, String value) { - value = PdfFormHelper.decodeXMLConversion(value); - if (!isNullOrEmpty(value)) { - dictionary.setString(key, value); - } - } - - /// Internal Methods. - void addNumber(PdfDictionary dictionary, String key, String value) { - final num? number = num.tryParse(value); - if (number != null) { - dictionary.setNumber(key, number); - } - } - - /// Internal Methods. - void addBorderStyle( - String key, - dynamic value, - PdfDictionary borderEffectDictionary, - PdfDictionary borderStyleDictionary, - ) { - if (value is String) { - switch (value) { - case 'dash': - style = PdfDictionaryProperties.d; - break; - case 'solid': - style = PdfDictionaryProperties.s; - break; - case 'bevelled': - style = PdfDictionaryProperties.b; - break; - case 'inset': - style = PdfDictionaryProperties.i; - break; - case 'underline': - style = PdfDictionaryProperties.u; - break; - case 'cloudy': - style = PdfDictionaryProperties.c; - isBasicStyle = false; - break; - } - } - if (key == 'width') { - final double? width = double.tryParse(value); - if (width != null) { - borderStyleDictionary.setNumber(PdfDictionaryProperties.w, width); - } - } - if (key == 'intensity') { - final double? intensity = double.tryParse(value); - if (intensity != null) { - borderEffectDictionary.setNumber(PdfDictionaryProperties.i, intensity); - } - } - if (!isNullOrEmpty(style)) { - (isBasicStyle ? borderStyleDictionary : borderEffectDictionary).setName( - PdfDictionaryProperties.s, - style, - ); - } - if (key == 'dashes') { - final List dashPoints = _obtainFloatPoints(value.toString()); - if (dashPoints.isNotEmpty) { - borderStyleDictionary.setProperty( - PdfDictionaryProperties.d, - PdfArray(dashPoints), - ); - } - } - } - - /// Internal Methods. - PdfArray? getColorArray(String value) { - if (!value.contains(',')) { - final String hex = value.replaceAll('#', ''); - final int r = int.parse(hex.substring(0, 2), radix: 16); - final int g = int.parse(hex.substring(2, 4), radix: 16); - final int b = int.parse(hex.substring(4, hex.length), radix: 16); - if (r >= 0 && g >= 0 && b >= 0) { - final PdfArray colorArray = PdfArray(); - colorArray.add(PdfNumber(r / 255)); - colorArray.add(PdfNumber(g / 255)); - colorArray.add(PdfNumber(b / 255)); - return colorArray; - } - } else { - final List colorValues = value.split(','); - final num? r = num.tryParse(colorValues[0]); - final num? g = num.tryParse(colorValues[1]); - final num? b = num.tryParse(colorValues[2]); - if (r != null && g != null && b != null) { - final PdfArray colorArray = PdfArray(); - colorArray.add(PdfNumber(r)); - colorArray.add(PdfNumber(g)); - colorArray.add(PdfNumber(b)); - return colorArray; - } - } - return null; - } - - /// Internal Methods. - void addFloatPoints(PdfDictionary dictionary, List? points, String key) { - if (points != null && points.isNotEmpty) { - dictionary.setProperty(key, PdfArray(points)); - } - } - - /// Internal Methods. - String trimEscapeCharacters(String value) { - if (value.contains(r'\\r')) { - value = value.replaceAll(r'\\r', '\r'); - } - if (value.contains(r'\\n')) { - value = value.replaceAll(r'\\n', '\n'); - } - if (value.contains(r'\\\"')) { - value = value.replaceAll(r'\\\"', '"'); - } - return value; - } - - /// Internal Methods. - void addFloatPointsToCollection(List collection, String value) { - final num? number = num.tryParse(value); - if (number != null) { - collection.add(number); - } - } - - /// Internal Methods. - void addStreamData( - Map dataValues, - PdfDictionary annotDictionary, - String values, - ) { - if (annotDictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? primitive = PdfCrossTable.dereference( - annotDictionary[PdfDictionaryProperties.subtype], - ); - if (primitive != null && primitive is PdfName && primitive.name != null) { - final String subtype = primitive.name!; - final List raw = List.from(hex.decode(values)); - if (raw.isNotEmpty) { - if (subtype.toLowerCase() == 'sound') { - final PdfStream soundStream = PdfStream(); - soundStream.setName( - PdfDictionaryProperties.type, - PdfDictionaryProperties.sound, - ); - dataValues.forEach((String key, String value) { - switch (key) { - case 'bits': - if (!isNullOrEmpty(value)) { - addNumber(soundStream, PdfDictionaryProperties.b, value); - } - break; - case 'rate': - if (!isNullOrEmpty(value)) { - addNumber(soundStream, PdfDictionaryProperties.r, value); - } - break; - case 'channels': - if (!isNullOrEmpty(value)) { - addNumber(soundStream, PdfDictionaryProperties.c, value); - } - break; - case 'encoding': - if (!isNullOrEmpty(value)) { - soundStream.setName(PdfDictionaryProperties.e, value); - } - break; - case 'filter': - soundStream.addFilter(PdfDictionaryProperties.flateDecode); - break; - } - }); - soundStream.data = raw; - annotDictionary.setProperty( - PdfDictionaryProperties.sound, - PdfReferenceHolder(soundStream), - ); - } else if (subtype.toLowerCase() == 'fileattachment') { - final PdfDictionary fileDictionary = PdfDictionary(); - final PdfStream fileStream = PdfStream(); - final PdfDictionary param = PdfDictionary(); - fileDictionary.setName( - PdfDictionaryProperties.type, - PdfDictionaryProperties.filespec, - ); - dataValues.forEach((String key, String value) { - switch (key) { - case 'file': - addString(fileDictionary, PdfDictionaryProperties.f, value); - addString(fileDictionary, PdfDictionaryProperties.uf, value); - break; - case 'size': - final int? size = int.tryParse(value); - if (size != null) { - param.setNumber(PdfDictionaryProperties.size, size); - fileStream.setNumber('DL', size); - } - break; - case 'creation': - addString( - param, - 'creation', - PdfDictionaryProperties.creationDate, - ); - break; - case 'modification': - addString( - param, - 'modification', - PdfDictionaryProperties.modificationDate, - ); - break; - } - }); - fileStream.setProperty(PdfDictionaryProperties.params, param); - fileStream.data = raw; - final PdfDictionary embeddedFile = PdfDictionary(); - embeddedFile.setProperty( - PdfDictionaryProperties.f, - PdfReferenceHolder(fileStream), - ); - fileDictionary.setProperty( - PdfDictionaryProperties.ef, - embeddedFile, - ); - annotDictionary.setProperty( - PdfDictionaryProperties.fs, - PdfReferenceHolder(fileDictionary), - ); - } - } - } - } - } - - /// Internal Methods. - List getBytes(String hex) { - final PdfString pdfString = PdfString(''); - return pdfString.hexToBytes(hex); - } - - List _obtainFloatPoints(dynamic points) { - final List pointsValue = points - .toString() - .replaceAll(RegExp(r'[\[\]{}:]'), '') - .split(','); - final List linePoints = []; - for (final dynamic value in pointsValue) { - if (value is String && !isNullOrEmpty(value)) { - final num? number = num.tryParse(value); - if (number != null) { - linePoints.add(number); - } - } - } - return linePoints; - } -} - -/// Internal method. -bool isNullOrEmpty(String? value) { - return value == null || value.isEmpty; -} - -/// Internal method. -String getEnumName(dynamic text) { - final int index = text.toString().indexOf('.'); - final String name = text.toString().substring(index + 1); - return name[0].toUpperCase() + name.substring(1); -} +import 'dart:convert'; + +import 'package:convert/convert.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../forms/pdf_form.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'xfdf_parser.dart'; + +/// Internal class. +class JsonParser { + /// Internal Constructor. + JsonParser(this.document); + + /// Internal Field. + late PdfDocument document; + + /// Internal Field. + String? annotation; + + /// Internal Field. + String? style; + + /// Internal Field. + bool isBasicStyle = true; + + /// Internal Field. + String? beginLineStyle; + + /// Internal Field. + String? endLineStyle; + + /// Internal Field. + Map? dataStream; + + /// Internal Field. + String? values; + + /// Internal Field. + Map? groupReferences; + + /// Internal Field. + List? groupHolders; + + bool _isNormalAppearanceAdded = false; + + /// Internal Method. + void importAnnotationData(List? data) { + if (data != null) { + final Map jsonData = json.decode(utf8.decode(data)); + parseJsonData(jsonData); + jsonData.clear(); + if (groupHolders != null && groupHolders!.isNotEmpty) { + for (final PdfDictionary dictionary in groupHolders!) { + final IPdfPrimitive? inReplyTo = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.irt], + ); + if (inReplyTo != null && + inReplyTo is PdfString && + !isNullOrEmpty(inReplyTo.value)) { + if (groupReferences != null && + groupReferences!.containsKey(inReplyTo.value)) { + dictionary[PdfDictionaryProperties.irt] = + groupReferences![inReplyTo.value]; + } else { + dictionary.remove(PdfDictionaryProperties.irt); + } + } + } + } + if (groupReferences != null) { + groupReferences!.clear(); + } + if (groupHolders != null) { + groupHolders!.clear(); + } + groupReferences = null; + groupHolders = null; + } + } + + /// Internal Method. + void parseJsonData(Map data) { + if (data.containsKey('type')) { + parseAnnotationData(data); + } + for (final dynamic value in data.values) { + if (value is Map) { + parseJsonData(value); + } else if (value is List) { + // ignore: avoid_function_literals_in_foreach_calls + value.forEach((dynamic element) { + if (element is Map) { + parseJsonData(element); + } + }); + } + } + } + + /// Internal Method. + void parseAnnotationData(Map annotData) { + final String page = annotData.containsKey('page') ? annotData['page'] : ''; + final String type = annotData.containsKey('type') ? annotData['type'] : ''; + final int pageIndex = int.tryParse(page) ?? -1; + if (pageIndex >= 0 && pageIndex < document.pages.count) { + final PdfPage loadedPage = document.pages[pageIndex]; + PdfPageHelper.getHelper(loadedPage).importAnnotation = true; + final PdfDictionary annotDictionary = getAnnotationData( + type, + pageIndex, + annotData, + ); + if (annotDictionary.count > 0) { + final PdfReferenceHolder holder = PdfReferenceHolder(annotDictionary); + if (annotDictionary.containsKey(PdfDictionaryProperties.nm) || + annotDictionary.containsKey(PdfDictionaryProperties.irt)) { + addReferenceToGroup(holder, annotDictionary); + } + final PdfDictionary? pageDictionary = + PdfPageHelper.getHelper(document.pages[pageIndex]).dictionary; + if (pageDictionary != null) { + if (!pageDictionary.containsKey(PdfDictionaryProperties.annots)) { + pageDictionary[PdfDictionaryProperties.annots] = PdfArray(); + } + final IPdfPrimitive? annots = PdfCrossTable.dereference( + pageDictionary[PdfDictionaryProperties.annots], + ); + if (annots != null && annots is PdfArray) { + annots.elements.add(holder); + annots.changed = true; + } + } + } + } + beginLineStyle = null; + endLineStyle = null; + } + + /// Internal Method. + void addReferenceToGroup( + PdfReferenceHolder holder, + PdfDictionary dictionary, + ) { + IPdfPrimitive? name = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.nm], + ); + groupReferences ??= {}; + if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { + groupReferences![name.value!] = holder; + if (dictionary.containsKey(PdfDictionaryProperties.irt)) { + groupHolders ??= []; + groupHolders!.add(dictionary); + } + } else if (name == null) { + if (dictionary.containsKey(PdfDictionaryProperties.irt)) { + name = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.irt], + ); + } + if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { + if (groupReferences!.containsKey(name.value)) { + final PdfReferenceHolder referenceHolder = + groupReferences![name.value]!; + dictionary[PdfDictionaryProperties.irt] = referenceHolder; + } + } + } + } + + /// Internal Method. + PdfDictionary getAnnotationData( + String type, + int pageindex, + Map annotData, + ) { + final PdfDictionary annotDictionary = PdfDictionary(); + annotDictionary.setName( + PdfDictionaryProperties.type, + PdfDictionaryProperties.annot, + ); + bool isValidType = true; + switch (type.toLowerCase()) { + case 'line': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.line, + ); + break; + case 'circle': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.circle, + ); + break; + case 'square': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.square, + ); + break; + case 'polyline': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'PolyLine'); + break; + case 'polygon': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.polygon, + ); + break; + case 'ink': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'Ink'); + break; + case 'popup': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.popup, + ); + break; + case 'text': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.text, + ); + break; + case 'freetext': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'FreeText'); + break; + case 'stamp': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'Stamp'); + break; + case 'highlight': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.highlight, + ); + break; + case 'squiggly': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.squiggly, + ); + break; + case 'underline': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.underline, + ); + break; + case 'strikeout': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.strikeOut, + ); + break; + case 'fileattachment': + annotDictionary.setName( + PdfDictionaryProperties.subtype, + 'FileAttachment', + ); + break; + case 'sound': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'Sound'); + break; + case 'redact': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'Redact'); + annotation = 'redact'; + break; + case 'caret': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'Caret'); + break; + case 'watermark': + annotDictionary.setName(PdfDictionaryProperties.subtype, 'Watermark'); + break; + default: + isValidType = false; + break; + } + if (isValidType) { + addAnnotationData(annotDictionary, annotData, pageindex); + } + return annotDictionary; + } + + /// Internal method. + void addAnnotationData( + PdfDictionary annotDictionary, + Map annotData, + int index, + ) { + List? linePoints = []; + final PdfDictionary borderEffectDictionary = PdfDictionary(); + final PdfDictionary borderStyleDictionary = PdfDictionary(); + annotData.forEach((String key, dynamic value) { + if (value is String) { + value = PdfFormHelper.decodeXMLConversion(value); + } + switch (key.toLowerCase()) { + case 'start': + case 'end': + linePoints!.addAll(_obtainFloatPoints(value)); + if (linePoints!.length == 4) { + annotDictionary.setProperty( + PdfDictionaryProperties.l, + PdfArray(linePoints), + ); + linePoints!.clear(); + linePoints = null; + } + break; + case 'itex': + break; + case 'state': + addString(annotDictionary, 'State', value.toString()); + break; + case 'statemodel': + addString(annotDictionary, 'StateModel', value.toString()); + break; + case 'replytype': + if (value == 'group') { + annotDictionary.setName('RT', 'Group'); + } + break; + case 'inreplyto': + addString( + annotDictionary, + PdfDictionaryProperties.irt, + value.toString(), + ); + break; + case 'dashes': + case 'width': + case 'intensity': + case 'style': + addBorderStyle( + key, + value, + borderEffectDictionary, + borderStyleDictionary, + ); + break; + case 'rect': + final List points = _obtainFloatPoints(value.values.toList()); + if (points.length == 4) { + annotDictionary.setProperty( + PdfDictionaryProperties.rect, + PdfArray(points), + ); + } + break; + case 'color': + if (value is String && !isNullOrEmpty(value)) { + final PdfArray? colorArray = getColorArray(value); + if (colorArray != null) { + annotDictionary.setProperty( + PdfDictionaryProperties.c, + colorArray, + ); + } + } + break; + case 'oc': + if (annotation == 'redact') { + if (value is String && !isNullOrEmpty(value)) { + final PdfArray? colorArray = getColorArray(value); + if (colorArray != null) { + annotDictionary.setProperty( + PdfDictionaryProperties.ic, + colorArray, + ); + } + } + } + break; + case 'interior-color': + if (value is String && !isNullOrEmpty(value)) { + final PdfArray? colorArray = getColorArray(value); + if (colorArray != null) { + annotDictionary.setProperty( + PdfDictionaryProperties.ic, + colorArray, + ); + } + } + break; + case 'date': + addString( + annotDictionary, + PdfDictionaryProperties.m, + value.toString(), + ); + break; + case 'creationdate': + addString( + annotDictionary, + PdfDictionaryProperties.creationDate, + value.toString(), + ); + break; + case 'name': + addString( + annotDictionary, + PdfDictionaryProperties.nm, + value.toString(), + ); + break; + case 'icon': + if (value is String && !isNullOrEmpty(value)) { + annotDictionary.setName(PdfDictionaryProperties.name, value); + } + break; + case 'subject': + addString( + annotDictionary, + PdfDictionaryProperties.subj, + value.toString(), + ); + break; + case 'title': + addString(annotDictionary, PdfDictionaryProperties.t, value); + break; + case 'rotation': + addNumber(annotDictionary, PdfDictionaryProperties.rotate, value); + break; + case 'fringe': + addFloatPoints( + annotDictionary, + _obtainFloatPoints(value), + PdfDictionaryProperties.rd, + ); + break; + case 'it': + if (value is String && !isNullOrEmpty(value)) { + annotDictionary.setName(PdfDictionaryProperties.it, value); + } + break; + case 'leaderlength': + addNumber( + annotDictionary, + PdfDictionaryProperties.ll, + value.toString(), + ); + break; + case 'leaderextend': + addNumber( + annotDictionary, + PdfDictionaryProperties.lle, + value.toString(), + ); + break; + case 'caption': + if (value is String && !isNullOrEmpty(value)) { + annotDictionary.setBoolean( + PdfDictionaryProperties.cap, + value.toLowerCase() == 'yes' || value.toLowerCase() == 'true', + ); + } + break; + case 'caption-style': + if (value is String && !isNullOrEmpty(value)) { + annotDictionary.setName(PdfDictionaryProperties.cp, value); + } + break; + case 'callout': + addFloatPoints( + annotDictionary, + _obtainFloatPoints(value), + PdfDictionaryProperties.cl, + ); + break; + case 'coords': + addFloatPoints( + annotDictionary, + _obtainFloatPoints(value), + PdfDictionaryProperties.quadPoints, + ); + break; + case 'border': + addFloatPoints( + annotDictionary, + _obtainFloatPoints(value), + PdfDictionaryProperties.border, + ); + break; + case 'opacity': + addNumber(annotDictionary, PdfDictionaryProperties.ds, value); + break; + case 'defaultstyle': + addString( + annotDictionary, + PdfDictionaryProperties.ds, + value + .toString() + .replaceAll(RegExp(r'[{}]'), '') + .replaceAll(',', ';'), + ); + break; + case 'defaultappearance': + addString( + annotDictionary, + PdfDictionaryProperties.da, + value.toString().replaceAll(RegExp(r'[{},]'), ''), + ); + break; + case 'contents-richtext': + final String richtext = trimEscapeCharacters(value); + annotDictionary.setString(PdfDictionaryProperties.rc, richtext); + break; + case 'flags': + if (value is String && !isNullOrEmpty(value)) { + final List annotFlag = []; + if (value.contains(',')) { + final List values = value.split(','); + for (final String flag in values) { + final PdfAnnotationFlags flagType = + XfdfParser.mapAnnotationFlags(flag); + if (!annotFlag.contains(flagType)) { + annotFlag.add(flagType); + } + } + } else { + annotFlag.add(XfdfParser.mapAnnotationFlags(value)); + } + int flagValue = 0; + for (int i = 0; i < annotFlag.length; i++) { + flagValue |= PdfAnnotationHelper.getAnnotationFlagsValue( + annotFlag[i], + ); + } + if (flagValue > 0) { + annotDictionary.setNumber(PdfDictionaryProperties.f, flagValue); + } + } + break; + case 'open': + if (value is String && !isNullOrEmpty(value)) { + annotDictionary.setBoolean( + PdfDictionaryProperties.open, + value == 'true' || value == 'yes', + ); + } + break; + case 'repeat': + if (value is String && !isNullOrEmpty(value)) { + annotDictionary.setBoolean( + PdfDictionaryProperties.repeat, + value == 'true' || value == 'yes', + ); + } + break; + case 'overlaytext': + annotDictionary.setString(PdfDictionaryProperties.overlayText, value); + break; + case 'contents': + final String contents = trimEscapeCharacters(value); + if (!isNullOrEmpty(contents)) { + annotDictionary.setString( + PdfDictionaryProperties.contents, + contents, + ); + } + break; + case 'q': + final int? alignment = int.tryParse(value.toString()); + if (alignment != null) { + annotDictionary.setNumber(PdfDictionaryProperties.q, alignment); + } + break; + case 'inklist': + final PdfArray inkListCollection = PdfArray(); + final String inklist = value + .toString() + .replaceAll('gesture', '') + .replaceAll(RegExp(r'[\[\]{}:]'), ''); + final List pointsArray = inklist.split(','); + if (pointsArray.isNotEmpty) { + final List pointsList = []; + for (final String point in pointsArray) { + final num? result = num.tryParse(point); + if (result != null) { + pointsList.add(result); + } + } + if (pointsList.isNotEmpty && pointsList.length.isEven) { + inkListCollection.add(PdfArray(pointsList)); + } + pointsList.clear(); + } + annotDictionary.setProperty( + PdfDictionaryProperties.inkList, + inkListCollection, + ); + break; + case 'head': + beginLineStyle = getEnumName( + XfdfParser.mapLineEndingStyle(value.toString()), + ); + break; + case 'tail': + endLineStyle = getEnumName( + XfdfParser.mapLineEndingStyle(value.toString()), + ); + break; + case 'creation': + case 'modification': + case 'file': + case 'bits': + case 'channels': + case 'encoding': + case 'rate': + case 'length': + case 'filter': + case 'mode': + case 'size': + dataStream ??= {}; + dataStream![key] = value.toString(); + break; + case 'data': + values = value; + break; + case 'vertices': + if (value is String && !isNullOrEmpty(value)) { + final List vertices = value.split(RegExp('[;,]')); + if (vertices.isNotEmpty) { + final List verticesList = []; + for (final String vertice in vertices) { + addFloatPointsToCollection(verticesList, vertice); + } + if (verticesList.isNotEmpty && verticesList.length.isEven) { + annotDictionary.setProperty( + PdfDictionaryProperties.vertices, + PdfArray(verticesList), + ); + } + } + } + break; + case 'customdata': + addString( + annotDictionary, + PdfDictionaryProperties.customData, + trimEscapeCharacters(value.toString()), + ); + break; + case 'appearance': + _addAppearanceData(annotDictionary, value.toString()); + break; + default: + break; + } + }); + _addMeasureDictionary(annotDictionary, annotData); + if (!isNullOrEmpty(beginLineStyle)) { + if (!isNullOrEmpty(endLineStyle)) { + final PdfArray lineEndingStyles = PdfArray(); + lineEndingStyles.add(PdfName(beginLineStyle)); + lineEndingStyles.add(PdfName(endLineStyle)); + annotDictionary.setProperty( + PdfDictionaryProperties.le, + lineEndingStyles, + ); + } else { + annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); + } + } else if (!isNullOrEmpty(endLineStyle)) { + annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); + } + if (borderStyleDictionary.count > 0) { + borderStyleDictionary.setProperty( + PdfDictionaryProperties.type, + PdfName(PdfDictionaryProperties.border), + ); + annotDictionary.setProperty( + PdfDictionaryProperties.bs, + PdfReferenceHolder(borderStyleDictionary), + ); + } + if (borderEffectDictionary.count > 0) { + annotDictionary.setProperty( + PdfDictionaryProperties.be, + PdfReferenceHolder(borderEffectDictionary), + ); + } + if (dataStream != null && values != null) { + addStreamData(dataStream!, annotDictionary, values!); + } + } + + void _addMeasureDictionary( + PdfDictionary annotDictionary, + Map element, + ) { + Map? area; + Map? distance; + Map? xformat; + Map? tformat; + Map? vformat; + final PdfDictionary measureDictionary = PdfDictionary(); + final PdfArray dArray = PdfArray(); + final PdfArray aArray = PdfArray(); + final PdfArray xArray = PdfArray(); + final PdfArray tArray = PdfArray(); + final PdfArray vArray = PdfArray(); + final PdfDictionary dDict = PdfDictionary(); + final PdfDictionary aDict = PdfDictionary(); + final PdfDictionary xDict = PdfDictionary(); + final PdfDictionary tDict = PdfDictionary(); + final PdfDictionary vDict = PdfDictionary(); + measureDictionary.items![PdfName(PdfDictionaryProperties.a)] = aArray; + measureDictionary.items![PdfName(PdfDictionaryProperties.d)] = dArray; + measureDictionary.items![PdfName(PdfDictionaryProperties.x)] = xArray; + measureDictionary.items![PdfName(PdfDictionaryProperties.t)] = tArray; + measureDictionary.items![PdfName(PdfDictionaryProperties.v)] = vArray; + if (element.containsKey(PdfDictionaryProperties.type1.toLowerCase())) { + measureDictionary.setName( + PdfDictionaryProperties.type, + PdfDictionaryProperties.measure, + ); + } + element.forEach((String key, dynamic value) { + if (value is String) { + switch (key.toLowerCase()) { + case 'ratevalue': + measureDictionary.setString(PdfDictionaryProperties.r, value); + break; + case 'subtype': + measureDictionary.setString(PdfDictionaryProperties.subtype, value); + break; + case 'targetunitconversion': + measureDictionary.setString( + PdfDictionaryProperties.targetUnitConversion, + value, + ); + break; + case 'area': + area = {}; + area = _addDictionaryData(area!, value); + break; + case 'distance': + distance = {}; + distance = _addDictionaryData(distance!, value); + break; + case 'xformat': + xformat = {}; + xformat = _addDictionaryData(xformat!, value); + break; + case 'tformat': + tformat = {}; + tformat = _addDictionaryData(tformat!, value); + break; + case 'vformat': + vformat = {}; + vformat = _addDictionaryData(vformat!, value); + break; + } + } + }); + if (xformat != null) { + _addElements(xformat!, xDict); + xArray.add(xDict); + } + if (area != null) { + _addElements(area!, aDict); + aArray.add(aDict); + } + if (distance != null) { + _addElements(distance!, dDict); + dArray.add(dDict); + } + if (vformat != null) { + _addElements(vformat!, vDict); + vArray.add(vDict); + } + if (tformat != null) { + _addElements(tformat!, tDict); + tArray.add(tDict); + } + if (measureDictionary.count > 0 && + measureDictionary.containsKey(PdfDictionaryProperties.type)) { + annotDictionary.items![PdfName( + PdfDictionaryProperties.measure, + )] = PdfReferenceHolder(measureDictionary); + } + } + + void _addElements(Map element, PdfDictionary dictionary) { + element.forEach((String key, String value) { + final num? elementValue = num.tryParse(value); + if (elementValue != null) { + switch (key.toLowerCase()) { + case 'd': + dictionary.items![PdfName(PdfDictionaryProperties.d)] = PdfNumber( + elementValue, + ); + break; + case 'c': + dictionary.items![PdfName(PdfDictionaryProperties.c)] = PdfNumber( + elementValue, + ); + break; + case 'rt': + dictionary.items![PdfName(PdfDictionaryProperties.rt)] = PdfNumber( + elementValue, + ); + break; + case 'rd': + dictionary.items![PdfName(PdfDictionaryProperties.rd)] = PdfNumber( + elementValue, + ); + break; + case 'ss': + dictionary.items![PdfName(PdfDictionaryProperties.ss)] = PdfNumber( + elementValue, + ); + break; + case 'u': + dictionary.items![PdfName(PdfDictionaryProperties.u)] = PdfNumber( + elementValue, + ); + break; + case 'f': + dictionary.items![PdfName(PdfDictionaryProperties.f)] = PdfNumber( + elementValue, + ); + break; + case 'fd': + dictionary.items![PdfName(PdfDictionaryProperties.fd)] = PdfNumber( + elementValue, + ); + break; + case 'type': + dictionary.items![PdfName( + PdfDictionaryProperties.type, + )] = PdfNumber(elementValue); + break; + } + } + }); + } + + Map _addDictionaryData( + Map data, + String value, + ) { + String addValue = ''; + for (int k = 0; k < value.length; k++) { + addValue += (value[k] == ':' || value[k] == ';') ? '#' : value[k]; + } + final List valueSplit = addValue.split('#'); + for (int i = 0; i < valueSplit.length - 1; i += 2) { + data[valueSplit[i]] = valueSplit[i + 1]; + } + return data; + } + + void _addAppearanceData(PdfDictionary dictionary, String value) { + if (!isNullOrEmpty(value)) { + final List appearanceData = base64.decode(value); + if (appearanceData.isNotEmpty) { + final Map dict = json.decode( + utf8.decode(appearanceData), + ); + final PdfDictionary appearance = PdfDictionary(); + if (dict.isNotEmpty) { + for (final dynamic dictValue in dict.values) { + dictionary[PdfDictionaryProperties.ap] = PdfReferenceHolder( + _parseDictionaryItems(dictValue, appearance), + ); + } + } + } + } + _isNormalAppearanceAdded = false; + } + + IPdfPrimitive _parseDictionaryItems( + dynamic elementValue, + IPdfPrimitive primitive, + ) { + if (elementValue != null) { + if (elementValue is Map) { + for (String token in elementValue.keys) { + final dynamic value = elementValue[token]; + token = PdfFormHelper.decodeXMLConversion(token); + switch (token) { + case 'stream': + PdfStream stream = PdfStream(); + stream = _parseDictionaryItems(value, stream) as PdfStream; + return stream; + case 'array': + PdfArray array = PdfArray(); + array = _parseDictionaryItems(value, array) as PdfArray; + return array; + case 'name': + return PdfName(value.toString()); + case 'string': + return PdfString(value.toString()); + case 'boolean': + final bool test = value.toString().toLowerCase() == 'true'; + return PdfBoolean(test); + case 'dict': + PdfDictionary pdfDictionary = PdfDictionary(); + pdfDictionary = + _parseDictionaryItems(value, pdfDictionary) as PdfDictionary; + return pdfDictionary; + case 'int': + final int? result = int.tryParse(value.toString()); + if (result != null) { + return PdfNumber(result); + } + break; + case 'fixed': + final num? result = num.tryParse(value.toString()); + if (result != null) { + return PdfNumber(result); + } + break; + case 'data': + if (primitive is PdfStream && + value != null && + value is Map) { + primitive.data = _getStreamData(value); + if (!primitive.containsKey(PdfDictionaryProperties.type) && + !primitive.containsKey(PdfDictionaryProperties.subtype)) { + primitive.decompress(); + } + bool isImage = false; + if (primitive.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? subtype = PdfCrossTable.dereference( + primitive[PdfDictionaryProperties.subtype], + ); + if (subtype != null && + subtype is PdfName && + subtype.name == PdfDictionaryProperties.image) { + isImage = true; + } + } + if (isImage) { + primitive.compress = false; + } else { + if (primitive.containsKey(PdfDictionaryProperties.length)) { + primitive.remove(PdfDictionaryProperties.length); + } + if (primitive.containsKey(PdfDictionaryProperties.filter)) { + primitive.remove(PdfDictionaryProperties.filter); + } + } + } + break; + case 'N': + if (_isNormalAppearanceAdded && primitive is PdfDictionary) { + primitive[token] = _parseDictionaryItems(value, primitive); + } else if (primitive is PdfDictionary) { + _isNormalAppearanceAdded = true; + final PdfDictionary dic = PdfDictionary(); + primitive[token] = PdfReferenceHolder( + _parseDictionaryItems(value, dic), + ); + } else { + _isNormalAppearanceAdded = true; + final PdfDictionary dic = PdfDictionary(); + dic[token] = PdfReferenceHolder( + _parseDictionaryItems(value, dic), + ); + return dic; + } + break; + case 'BBox': + case 'Type': + case 'Subtype': + case 'Resources': + case 'BaseFont': + case 'ProcSet': + case 'Font': + case 'Encoding': + case 'Matrix': + case 'Length': + case 'CIDToGIDMap': + case 'DW': + case 'FontName': + case 'Flags': + case 'FontBBox': + case 'MissingWidth': + case 'StemV': + case 'ItalicAngle': + case 'CapHeight': + case 'Ascent': + case 'Descent': + case 'Leading': + case 'AvgWidth': + case 'MaxWidth': + case 'StemH': + case 'CIDSystemInfo': + case 'Registry': + case 'Ordering': + case 'Supplement': + case 'W': + case 'XObject': + case 'Filter': + case 'BitsPerComponent': + case 'ColorSpace': + case 'FormType': + case 'Name': + case 'Height': + case 'Width': + case 'Decode': + case 'DecodeParms': + case 'BlackIs1': + case 'Columns': + case 'K': + case 'Rows': + case 'ImageMask': + case 'Interpolate': + case 'ca': + case 'CA': + case 'AIS': + case 'BM': + case 'ExtGState': + case 'Pattern': + case 'PatternType': + case 'CS': + case 'I': + case 'S': + case 'Coords': + case 'Extend': + case 'ShadingType': + case 'Bounds': + case 'Domain': + case 'Encode': + case 'FunctionType': + case 'Widths': + case 'FirstChar': + case 'LastChar': + if (primitive is PdfDictionary) { + primitive[token] = _parseDictionaryItems(value, primitive); + } + break; + default: + if (primitive is PdfDictionary) { + final PdfDictionary temp = PdfDictionary(); + primitive[token] = PdfReferenceHolder( + _parseDictionaryItems(value, temp), + ); + } + break; + } + } + } else if (elementValue is List && primitive is PdfArray) { + final List list = elementValue; + for (int i = 0; i < list.length; i++) { + final dynamic listObject = list[i]; + if (listObject is Map) { + listObject.forEach((String token, dynamic value) { + token = PdfFormHelper.decodeXMLConversion(token); + switch (token) { + case 'int': + final int? result = int.tryParse(value.toString()); + if (result != null) { + primitive.add(PdfNumber(result)); + } + break; + case 'fixed': + final num? result = num.tryParse(value.toString()); + if (result != null) { + primitive.add(PdfNumber(result)); + } + break; + case 'name': + primitive.add(PdfName(value.toString())); + break; + case 'string': + primitive.add(PdfString(value.toString())); + break; + case 'dict': + PdfDictionary pdfDictionary = PdfDictionary(); + pdfDictionary = + _parseDictionaryItems(value, pdfDictionary) + as PdfDictionary; + primitive.add(PdfReferenceHolder(pdfDictionary)); + break; + case 'array': + PdfArray array = PdfArray(); + array = _parseDictionaryItems(value, array) as PdfArray; + primitive.add(array); + break; + case 'boolean': + final bool test = value.toString().toLowerCase() == 'true'; + primitive.add(PdfBoolean(test)); + break; + case 'stream': + PdfStream stream = PdfStream(); + stream = _parseDictionaryItems(value, stream) as PdfStream; + primitive.add(stream); + break; + } + }); + } + } + } + } + return primitive; + } + + List? _getStreamData(Map element) { + List? rawData; + String encoding = ''; + for (final String token in element.keys) { + final dynamic value = element[token]; + switch (token) { + case 'encoding': + encoding = value.toString(); + break; + case 'bytes': + if (value != null) { + if (encoding == 'hex') { + rawData = getBytes(value.toString()); + } else if (encoding == 'ascii') { + rawData = utf8.encode(value.toString()); + } + } + return rawData; + } + } + return rawData; + } + + /// Internal Methods. + void addString(PdfDictionary dictionary, String key, String value) { + value = PdfFormHelper.decodeXMLConversion(value); + if (!isNullOrEmpty(value)) { + dictionary.setString(key, value); + } + } + + /// Internal Methods. + void addNumber(PdfDictionary dictionary, String key, String value) { + final num? number = num.tryParse(value); + if (number != null) { + dictionary.setNumber(key, number); + } + } + + /// Internal Methods. + void addBorderStyle( + String key, + dynamic value, + PdfDictionary borderEffectDictionary, + PdfDictionary borderStyleDictionary, + ) { + if (value is String) { + switch (value) { + case 'dash': + style = PdfDictionaryProperties.d; + break; + case 'solid': + style = PdfDictionaryProperties.s; + break; + case 'bevelled': + style = PdfDictionaryProperties.b; + break; + case 'inset': + style = PdfDictionaryProperties.i; + break; + case 'underline': + style = PdfDictionaryProperties.u; + break; + case 'cloudy': + style = PdfDictionaryProperties.c; + isBasicStyle = false; + break; + } + } + if (key == 'width') { + final double? width = double.tryParse(value); + if (width != null) { + borderStyleDictionary.setNumber(PdfDictionaryProperties.w, width); + } + } + if (key == 'intensity') { + final double? intensity = double.tryParse(value); + if (intensity != null) { + borderEffectDictionary.setNumber(PdfDictionaryProperties.i, intensity); + } + } + if (!isNullOrEmpty(style)) { + (isBasicStyle ? borderStyleDictionary : borderEffectDictionary).setName( + PdfDictionaryProperties.s, + style, + ); + } + if (key == 'dashes') { + final List dashPoints = _obtainFloatPoints(value.toString()); + if (dashPoints.isNotEmpty) { + borderStyleDictionary.setProperty( + PdfDictionaryProperties.d, + PdfArray(dashPoints), + ); + } + } + } + + /// Internal Methods. + PdfArray? getColorArray(String value) { + if (!value.contains(',')) { + final String hex = value.replaceAll('#', ''); + final int r = int.parse(hex.substring(0, 2), radix: 16); + final int g = int.parse(hex.substring(2, 4), radix: 16); + final int b = int.parse(hex.substring(4, hex.length), radix: 16); + if (r >= 0 && g >= 0 && b >= 0) { + final PdfArray colorArray = PdfArray(); + colorArray.add(PdfNumber(r / 255)); + colorArray.add(PdfNumber(g / 255)); + colorArray.add(PdfNumber(b / 255)); + return colorArray; + } + } else { + final List colorValues = value.split(','); + final num? r = num.tryParse(colorValues[0]); + final num? g = num.tryParse(colorValues[1]); + final num? b = num.tryParse(colorValues[2]); + if (r != null && g != null && b != null) { + final PdfArray colorArray = PdfArray(); + colorArray.add(PdfNumber(r)); + colorArray.add(PdfNumber(g)); + colorArray.add(PdfNumber(b)); + return colorArray; + } + } + return null; + } + + /// Internal Methods. + void addFloatPoints(PdfDictionary dictionary, List? points, String key) { + if (points != null && points.isNotEmpty) { + dictionary.setProperty(key, PdfArray(points)); + } + } + + /// Internal Methods. + String trimEscapeCharacters(String value) { + if (value.contains(r'\\r')) { + value = value.replaceAll(r'\\r', '\r'); + } + if (value.contains(r'\\n')) { + value = value.replaceAll(r'\\n', '\n'); + } + if (value.contains(r'\\\"')) { + value = value.replaceAll(r'\\\"', '"'); + } + return value; + } + + /// Internal Methods. + void addFloatPointsToCollection(List collection, String value) { + final num? number = num.tryParse(value); + if (number != null) { + collection.add(number); + } + } + + /// Internal Methods. + void addStreamData( + Map dataValues, + PdfDictionary annotDictionary, + String values, + ) { + if (annotDictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? primitive = PdfCrossTable.dereference( + annotDictionary[PdfDictionaryProperties.subtype], + ); + if (primitive != null && primitive is PdfName && primitive.name != null) { + final String subtype = primitive.name!; + final List raw = List.from(hex.decode(values)); + if (raw.isNotEmpty) { + if (subtype.toLowerCase() == 'sound') { + final PdfStream soundStream = PdfStream(); + soundStream.setName( + PdfDictionaryProperties.type, + PdfDictionaryProperties.sound, + ); + dataValues.forEach((String key, String value) { + switch (key) { + case 'bits': + if (!isNullOrEmpty(value)) { + addNumber(soundStream, PdfDictionaryProperties.b, value); + } + break; + case 'rate': + if (!isNullOrEmpty(value)) { + addNumber(soundStream, PdfDictionaryProperties.r, value); + } + break; + case 'channels': + if (!isNullOrEmpty(value)) { + addNumber(soundStream, PdfDictionaryProperties.c, value); + } + break; + case 'encoding': + if (!isNullOrEmpty(value)) { + soundStream.setName(PdfDictionaryProperties.e, value); + } + break; + case 'filter': + soundStream.addFilter(PdfDictionaryProperties.flateDecode); + break; + } + }); + soundStream.data = raw; + annotDictionary.setProperty( + PdfDictionaryProperties.sound, + PdfReferenceHolder(soundStream), + ); + } else if (subtype.toLowerCase() == 'fileattachment') { + final PdfDictionary fileDictionary = PdfDictionary(); + final PdfStream fileStream = PdfStream(); + final PdfDictionary param = PdfDictionary(); + fileDictionary.setName( + PdfDictionaryProperties.type, + PdfDictionaryProperties.filespec, + ); + dataValues.forEach((String key, String value) { + switch (key) { + case 'file': + addString(fileDictionary, PdfDictionaryProperties.f, value); + addString(fileDictionary, PdfDictionaryProperties.uf, value); + break; + case 'size': + final int? size = int.tryParse(value); + if (size != null) { + param.setNumber(PdfDictionaryProperties.size, size); + fileStream.setNumber('DL', size); + } + break; + case 'creation': + addString( + param, + 'creation', + PdfDictionaryProperties.creationDate, + ); + break; + case 'modification': + addString( + param, + 'modification', + PdfDictionaryProperties.modificationDate, + ); + break; + } + }); + fileStream.setProperty(PdfDictionaryProperties.params, param); + fileStream.data = raw; + final PdfDictionary embeddedFile = PdfDictionary(); + embeddedFile.setProperty( + PdfDictionaryProperties.f, + PdfReferenceHolder(fileStream), + ); + fileDictionary.setProperty( + PdfDictionaryProperties.ef, + embeddedFile, + ); + annotDictionary.setProperty( + PdfDictionaryProperties.fs, + PdfReferenceHolder(fileDictionary), + ); + } + } + } + } + } + + /// Internal Methods. + List getBytes(String hex) { + final PdfString pdfString = PdfString(''); + return pdfString.hexToBytes(hex); + } + + List _obtainFloatPoints(dynamic points) { + final List pointsValue = points + .toString() + .replaceAll(RegExp(r'[\[\]{}:]'), '') + .split(','); + final List linePoints = []; + for (final dynamic value in pointsValue) { + if (value is String && !isNullOrEmpty(value)) { + final num? number = num.tryParse(value); + if (number != null) { + linePoints.add(number); + } + } + } + return linePoints; + } +} + +/// Internal method. +bool isNullOrEmpty(String? value) { + return value == null || value.isEmpty; +} + +/// Internal method. +String getEnumName(dynamic text) { + final int index = text.toString().indexOf('.'); + final String name = text.toString().substring(index + 1); + return name[0].toUpperCase() + name.substring(1); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_action_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_action_annotation.dart index 27dd4d36d..669af626e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_action_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_action_annotation.dart @@ -1,209 +1,209 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../actions/pdf_action.dart'; -import '../graphics/pdf_color.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_border.dart'; - -/// Represents the base class for the link annotations. -abstract class PdfLinkAnnotation extends PdfAnnotation implements IPdfWrapper { - // fields - PdfHighlightMode _highlightMode = PdfHighlightMode.noHighlighting; - PdfAction? _action; - - //properties - /// Gets or sets the highlight mode of the link annotation. - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create document link annotation and add to the PDF page. - /// document.pages.add() - /// ..annotations.add(PdfDocumentLinkAnnotation(Rect.fromLTWH(10, 40, 30, 30), - /// PdfDestination(document.pages.add(), Offset(10, 0))) - /// ..highlightMode = PdfHighlightMode.outline); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfHighlightMode get highlightMode => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _obtainHighlightMode() - : _highlightMode; - set highlightMode(PdfHighlightMode value) { - _highlightMode = value; - final String mode = _getHighlightMode(_highlightMode); - PdfAnnotationHelper.getHelper( - this, - ).dictionary!.setName(PdfName(PdfDictionaryProperties.h), mode); - } - - String _getHighlightMode(PdfHighlightMode mode) { - String hightlightMode = 'N'; - switch (mode) { - case PdfHighlightMode.invert: - hightlightMode = 'I'; - break; - case PdfHighlightMode.noHighlighting: - hightlightMode = 'N'; - break; - case PdfHighlightMode.outline: - hightlightMode = 'O'; - break; - case PdfHighlightMode.push: - hightlightMode = 'P'; - break; - } - return hightlightMode; - } - - PdfHighlightMode _obtainHighlightMode() { - PdfHighlightMode mode = PdfHighlightMode.noHighlighting; - if (PdfAnnotationHelper.getHelper( - this, - ).dictionary!.containsKey(PdfDictionaryProperties.h)) { - final PdfName name = - PdfAnnotationHelper.getHelper( - this, - ).dictionary![PdfDictionaryProperties.h]! - as PdfName; - switch (name.name) { - case 'I': - mode = PdfHighlightMode.invert; - break; - case 'N': - mode = PdfHighlightMode.noHighlighting; - break; - case 'O': - mode = PdfHighlightMode.outline; - break; - case 'P': - mode = PdfHighlightMode.push; - break; - } - } - return mode; - } -} - -/// [PdfLinkAnnotation] helper -class PdfLinkAnnotationHelper extends PdfAnnotationHelper { - /// internal constructor - PdfLinkAnnotationHelper( - PdfLinkAnnotation super.linkAnnotation, - Rect? bounds, - ) { - initializeAnnotation(bounds: bounds); - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.subtype), - PdfName(PdfDictionaryProperties.link), - ); - } - - /// internal constructor - PdfLinkAnnotationHelper.load( - PdfLinkAnnotation super.linkAnnotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - initializeExistingAnnotation(dictionary, crossTable); - } -} - -/// Represents base class for link annotations with associated action. -abstract class PdfActionLinkAnnotation extends PdfLinkAnnotation { - // properties - /// Gets or sets the action for the link annotation. - PdfAction? get action => _action; - set action(PdfAction? value) { - if (value != null) { - _action = value; - } - } -} - -/// [PdfActionLinkAnnotation] helper -class PdfActionLinkAnnotationHelper extends PdfLinkAnnotationHelper { - /// internal constructor - PdfActionLinkAnnotationHelper( - PdfActionLinkAnnotation actionLinkAnnotation, - Rect bounds, [ - PdfAction? action, - ]) : super(actionLinkAnnotation, bounds) { - if (action != null) { - actionLinkAnnotation._action = action; - } - } - - /// internal constructor - PdfActionLinkAnnotationHelper.load( - PdfActionLinkAnnotation super.actionLinkAnnotation, - super.dictionary, - super.crossTable, - ) : super.load(); -} - -/// Represents the annotation with associated action. -class PdfActionAnnotation extends PdfActionLinkAnnotation { - // constructor - /// Initializes a new instance of the - /// [PdfActionAnnotation] class with specified bounds and action. - PdfActionAnnotation(Rect bounds, PdfAction action) { - _helper = PdfActionAnnotationHelper(this, bounds, action); - } - late PdfActionAnnotationHelper _helper; - - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - return _helper.border; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - _helper.border = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } -} - -/// [PdfActionAnnotation] helper -class PdfActionAnnotationHelper extends PdfActionLinkAnnotationHelper { - /// internal method - PdfActionAnnotationHelper( - this.actionAnnotation, - Rect bounds, - PdfAction action, - ) : super(actionAnnotation, bounds, action); - - /// internal method - PdfActionAnnotation actionAnnotation; - - /// internal method - static PdfActionAnnotationHelper getHelper(PdfActionAnnotation base) { - return base._helper; - } - - /// internal method - void save() { - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.a), - IPdfWrapper.getElement(actionAnnotation.action!), - ); - } - - /// internal method - @override - IPdfPrimitive? element; -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../actions/pdf_action.dart'; +import '../graphics/pdf_color.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_border.dart'; + +/// Represents the base class for the link annotations. +abstract class PdfLinkAnnotation extends PdfAnnotation implements IPdfWrapper { + // fields + PdfHighlightMode _highlightMode = PdfHighlightMode.noHighlighting; + PdfAction? _action; + + //properties + /// Gets or sets the highlight mode of the link annotation. + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create document link annotation and add to the PDF page. + /// document.pages.add() + /// ..annotations.add(PdfDocumentLinkAnnotation(Rect.fromLTWH(10, 40, 30, 30), + /// PdfDestination(document.pages.add(), Offset(10, 0))) + /// ..highlightMode = PdfHighlightMode.outline); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfHighlightMode get highlightMode => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _obtainHighlightMode() + : _highlightMode; + set highlightMode(PdfHighlightMode value) { + _highlightMode = value; + final String mode = _getHighlightMode(_highlightMode); + PdfAnnotationHelper.getHelper( + this, + ).dictionary!.setName(PdfName(PdfDictionaryProperties.h), mode); + } + + String _getHighlightMode(PdfHighlightMode mode) { + String hightlightMode = 'N'; + switch (mode) { + case PdfHighlightMode.invert: + hightlightMode = 'I'; + break; + case PdfHighlightMode.noHighlighting: + hightlightMode = 'N'; + break; + case PdfHighlightMode.outline: + hightlightMode = 'O'; + break; + case PdfHighlightMode.push: + hightlightMode = 'P'; + break; + } + return hightlightMode; + } + + PdfHighlightMode _obtainHighlightMode() { + PdfHighlightMode mode = PdfHighlightMode.noHighlighting; + if (PdfAnnotationHelper.getHelper( + this, + ).dictionary!.containsKey(PdfDictionaryProperties.h)) { + final PdfName name = + PdfAnnotationHelper.getHelper( + this, + ).dictionary![PdfDictionaryProperties.h]! + as PdfName; + switch (name.name) { + case 'I': + mode = PdfHighlightMode.invert; + break; + case 'N': + mode = PdfHighlightMode.noHighlighting; + break; + case 'O': + mode = PdfHighlightMode.outline; + break; + case 'P': + mode = PdfHighlightMode.push; + break; + } + } + return mode; + } +} + +/// [PdfLinkAnnotation] helper +class PdfLinkAnnotationHelper extends PdfAnnotationHelper { + /// internal constructor + PdfLinkAnnotationHelper( + PdfLinkAnnotation super.linkAnnotation, + Rect? bounds, + ) { + initializeAnnotation(bounds: bounds); + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.subtype), + PdfName(PdfDictionaryProperties.link), + ); + } + + /// internal constructor + PdfLinkAnnotationHelper.load( + PdfLinkAnnotation super.linkAnnotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + initializeExistingAnnotation(dictionary, crossTable); + } +} + +/// Represents base class for link annotations with associated action. +abstract class PdfActionLinkAnnotation extends PdfLinkAnnotation { + // properties + /// Gets or sets the action for the link annotation. + PdfAction? get action => _action; + set action(PdfAction? value) { + if (value != null) { + _action = value; + } + } +} + +/// [PdfActionLinkAnnotation] helper +class PdfActionLinkAnnotationHelper extends PdfLinkAnnotationHelper { + /// internal constructor + PdfActionLinkAnnotationHelper( + PdfActionLinkAnnotation actionLinkAnnotation, + Rect bounds, [ + PdfAction? action, + ]) : super(actionLinkAnnotation, bounds) { + if (action != null) { + actionLinkAnnotation._action = action; + } + } + + /// internal constructor + PdfActionLinkAnnotationHelper.load( + PdfActionLinkAnnotation super.actionLinkAnnotation, + super.dictionary, + super.crossTable, + ) : super.load(); +} + +/// Represents the annotation with associated action. +class PdfActionAnnotation extends PdfActionLinkAnnotation { + // constructor + /// Initializes a new instance of the + /// [PdfActionAnnotation] class with specified bounds and action. + PdfActionAnnotation(Rect bounds, PdfAction action) { + _helper = PdfActionAnnotationHelper(this, bounds, action); + } + late PdfActionAnnotationHelper _helper; + + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + return _helper.border; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + _helper.border = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } +} + +/// [PdfActionAnnotation] helper +class PdfActionAnnotationHelper extends PdfActionLinkAnnotationHelper { + /// internal method + PdfActionAnnotationHelper( + this.actionAnnotation, + Rect bounds, + PdfAction action, + ) : super(actionAnnotation, bounds, action); + + /// internal method + PdfActionAnnotation actionAnnotation; + + /// internal method + static PdfActionAnnotationHelper getHelper(PdfActionAnnotation base) { + return base._helper; + } + + /// internal method + void save() { + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.a), + IPdfWrapper.getElement(actionAnnotation.action!), + ); + } + + /// internal method + @override + IPdfPrimitive? element; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation.dart index 05a0f77df..1361a16fe 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation.dart @@ -1,2359 +1,2359 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../graphics/brushes/pdf_brush.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_path.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/fonts/pdf_string_format.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_margins.dart'; -import '../graphics/pdf_pen.dart'; -import '../graphics/pdf_pens.dart'; -import '../graphics/pdf_transformation_matrix.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_section.dart'; -import '../pages/pdf_section_collection.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_catalog.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_action_annotation.dart'; -import 'pdf_annotation_border.dart'; -import 'pdf_appearance.dart'; -import 'pdf_document_link_annotation.dart'; -import 'pdf_ellipse_annotation.dart'; -import 'pdf_line_annotation.dart'; -import 'pdf_polygon_annotation.dart'; -import 'pdf_popup_annotation.dart'; -import 'pdf_rectangle_annotation.dart'; -import 'pdf_text_markup_annotation.dart'; -import 'pdf_text_web_link.dart'; -import 'widget_annotation.dart'; - -/// Represents the base class for annotation objects. -abstract class PdfAnnotation implements IPdfWrapper { - // fields - late PdfAnnotationHelper _helper; - - /// Set whether the annotation requires an appearance. - bool get setAppearance => _helper.setAppearance; - set setAppearance(bool value) { - _helper.setAppearance = value; - } - - // properties - /// Gets a page of the annotation. Read-Only. - PdfPage? get page => _helper.page; - - /// Gets annotation's bounds in the PDF page. - Rect get bounds { - return _helper.bounds; - } - - /// Sets annotation's bounds in the PDF page. - set bounds(Rect value) { - _helper.bounds = value; - } - - /// Gets content of the annotation. - /// The string value specifies the text of the annotation. - String get text { - return _helper.text; - } - - /// Sets content of the annotation. - /// The string value specifies the text of the annotation. - set text(String value) { - _helper.text = value; - } - - /// Gets the author of the annotation. - String get author => _helper.author; - - /// Sets the author of the annotation. - set author(String value) { - _helper.author = value; - } - - /// Gets the subject of the annotation. - String get subject => _helper.subject; - - /// Sets the subject of the annotation. - set subject(String value) { - _helper.subject = value; - } - - /// Gets the ModifiedDate of the annotation. - DateTime? get modifiedDate => _helper.modifiedDate; - - /// Sets the ModifiedDate of the annotation. - set modifiedDate(DateTime? value) { - _helper.modifiedDate = value; - } - - /// Gets the opacity of the annotation. - double get opacity => _helper.opacity; - - /// Sets the opacity of the annotation. - /// - /// Opacity value should be between 0 to 1. - set opacity(double value) { - _helper.opacity = value; - } - - /// Gets appearance of the annotation. - PdfAppearance get appearance { - _helper.appearance ??= PdfAppearance(this); - return _helper.appearance!; - } - - /// Sets appearance of the annotation. - set appearance(PdfAppearance value) { - _helper.appearance = value; - } - - /// Gets or sets the annotation flags. - List get annotationFlags => _helper.annotationFlags; - set annotationFlags(List value) { - _helper.annotationFlags = value; - } - - //Public methods - /// Flatten the annotation. - /// - /// The flatten will add at the time of saving the current document. - void flatten() { - _helper.flatten = true; - } -} - -/// [PdfAnnotation] helper -class PdfAnnotationHelper { - /// internal constructor - PdfAnnotationHelper(this.base); - - /// internal field - PdfAnnotation base; - - /// internal method - static PdfAnnotationHelper getHelper(PdfAnnotation base) { - return base._helper; - } - - /// internal method - /// Initialize [PdfAnnotation] object - void initializeAnnotation({ - PdfPage? page, - String? text, - Rect? bounds, - PdfAnnotationBorder? border, - PdfColor? color, - PdfColor? innerColor, - String? author, - double? opacity, - String? subject, - DateTime? modifiedDate, - List? flags, - bool? setAppearance, - }) { - base._helper = this; - initializeAnnotationProperties( - page, - text, - bounds, - border, - color, - innerColor, - author, - opacity, - subject, - modifiedDate, - flags, - setAppearance, - ); - } - - /// internal method - /// Initialize [PdfAnnotation] object - void initializeExistingAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - base._helper = this; - this.dictionary = dictionary; - this.crossTable = crossTable; - isLoadedAnnotation = true; - PdfName? name; - if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - name = - dictionary.items![PdfName(PdfDictionaryProperties.subtype)] - as PdfName?; - } - if (name != null) { - if (name.name == PdfDictionaryProperties.circle || - name.name == PdfDictionaryProperties.square || - name.name == PdfDictionaryProperties.line || - name.name == PdfDictionaryProperties.polygon || - name.name == PdfDictionaryProperties.highlight || - name.name == PdfDictionaryProperties.underline || - name.name == PdfDictionaryProperties.squiggly || - name.name == PdfDictionaryProperties.strikeOut || - name.name == PdfDictionaryProperties.text) { - PdfDocumentHelper.getHelper(crossTable.document!).catalog.beginSave = - dictionaryBeginSave; - PdfDocumentHelper.getHelper(crossTable.document!).catalog.modify(); - } - } - } - - /// internal field - PdfPage? page; - - /// internal field - String? textValue = ''; - - /// internal field - PdfRectangle rectangle = PdfRectangle.empty; - - /// internal field - PdfColor? annotationInnerColor; - - /// internal field - PdfAnnotationBorder? annotationBorder; - - /// internal field - bool isLoadedAnnotation = false; - - /// internal field - PdfColor annotationColor = PdfColor.empty; - - /// internal field - PdfMargins? margins = PdfMargins(); - - /// internal field - String? annotationAuthor = ''; - - /// internal field - String? annotationSubject = ''; - - /// internal field - DateTime? annotationModifiedDate; - - /// internal field - double annotationOpacity = 1.0; - - /// internal field - PdfAppearance? appearance; - - /// internal field - bool saved = false; - - /// internal field - bool isBounds = false; - - /// internal field - PdfCrossTable? cTable; - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal field - bool setAppearance = false; - - /// internal field - bool isOldAnnotation = false; - - /// internal field - List? flag; - - ///Gets or sets the boolean flag to flatten the annotation, - ///by default, its become false. - bool flatten = false; - - /// Gets or sets flatten annotations popup. - // ignore: prefer_final_fields - bool flattenPopups = false; - - /// internal property - PdfCrossTable get crossTable => cTable!; - set crossTable(PdfCrossTable value) { - if (value != cTable) { - cTable = value; - } - } - - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// Gets annotation's bounds in the PDF page. - Rect get bounds { - if (!isLoadedAnnotation) { - return rectangle.rect; - } else { - final PdfRectangle rect = _getBounds(dictionary!, crossTable); - rect.y = - page != null - ? rect.y == 0 && rect.height == 0 - ? rect.y + rect.height - : page!.size.height - (rect.y + rect.height) - : rect.y - rect.height; - return rect.rect; - } - } - - /// Sets annotation's bounds in the PDF page. - set bounds(Rect value) { - if (!isLoadedAnnotation) { - final PdfRectangle rect = PdfRectangle.fromRect(value); - if (rectangle != rect) { - rectangle = rect; - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.rect), - PdfArray.fromRectangle(rect), - ); - } - } else { - isBounds = true; - if (value == Rect.zero) { - throw ArgumentError('rectangle'); - } - final double height = page!.size.height; - final List values = [ - PdfNumber(value.left), - PdfNumber(height - (value.top + value.height)), - PdfNumber(value.left + value.width), - PdfNumber(height - value.top), - ]; - final PdfDictionary dic = dictionary!; - dic.setArray(PdfDictionaryProperties.rect, values); - } - } - - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - if (!isLoadedAnnotation) { - annotationBorder ??= PdfAnnotationBorder(); - } else { - annotationBorder ??= _obtainBorder(); - if (!isLineBorder()) { - dictionary!.setProperty( - PdfDictionaryProperties.border, - annotationBorder, - ); - } - } - PdfAnnotationBorderHelper.getHelper(annotationBorder!).isLineBorder = - isLineBorder(); - return annotationBorder!; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - annotationBorder = value; - if (isLineBorder()) { - dictionary!.setProperty(PdfName(PdfDictionaryProperties.bs), border); - } else { - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.border), - annotationBorder, - ); - } - } - - /// Gets content of the annotation. - /// The string value specifies the text of the annotation. - String get text { - if (!isLoadedAnnotation) { - if (dictionary!.containsKey(PdfDictionaryProperties.contents)) { - textValue = - (dictionary![PdfDictionaryProperties.contents]! as PdfString).value; - } - return textValue!; - } else { - return textValue == null || textValue!.isEmpty - ? _obtainText()! - : textValue!; - } - } - - /// Sets content of the annotation. - /// The string value specifies the text of the annotation. - set text(String value) { - if (textValue != value) { - textValue = value; - dictionary!.setString(PdfDictionaryProperties.contents, textValue); - } - } - - /// Gets the annotation color. - PdfColor get color => isLoadedAnnotation ? _obtainColor() : annotationColor; - - /// Sets the annotation color. - set color(PdfColor value) { - if (annotationColor != value) { - annotationColor = value; - PdfColorSpace? cs = PdfColorSpace.rgb; - if (page != null && !PdfPageHelper.getHelper(page!).isLoadedPage) { - cs = - PdfSectionCollectionHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page!).section!, - ).parent!, - ).document!.colorSpace; - } - final PdfArray colours = PdfColorHelper.toArray(annotationColor, cs); - dictionary!.setProperty(PdfDictionaryProperties.c, colours); - } - } - - /// Gets the inner color of the annotation. - PdfColor get innerColor { - if (!isLoadedAnnotation) { - annotationInnerColor ??= PdfColor(0, 0, 0, 0); - } else { - annotationInnerColor = _obtainInnerColor(); - } - return annotationInnerColor!; - } - - /// Sets the inner color of the annotation. - set innerColor(PdfColor value) { - annotationInnerColor = value; - if (isLoadedAnnotation) { - if (PdfColorHelper.getHelper(annotationInnerColor!).alpha != 0) { - dictionary!.setProperty( - PdfDictionaryProperties.iC, - PdfColorHelper.toArray(annotationInnerColor!), - ); - } else if (dictionary!.containsKey(PdfDictionaryProperties.iC)) { - dictionary!.remove(PdfDictionaryProperties.iC); - } - } - } - - /// Gets the author of the annotation. - String get author { - if (!isLoadedAnnotation) { - if (dictionary!.containsKey(PdfDictionaryProperties.author)) { - annotationAuthor = - (dictionary![PdfDictionaryProperties.author]! as PdfString).value; - } else if (dictionary!.containsKey(PdfDictionaryProperties.t)) { - annotationAuthor = - (dictionary![PdfDictionaryProperties.t]! as PdfString).value; - } - } else { - annotationAuthor = _obtainAuthor(); - } - return annotationAuthor!; - } - - /// Sets the author of the annotation. - set author(String value) { - if (annotationAuthor != value) { - annotationAuthor = value; - dictionary!.setString(PdfDictionaryProperties.t, annotationAuthor); - } - } - - /// Gets the subject of the annotation. - String get subject { - if (isLoadedAnnotation) { - annotationSubject = _obtainSubject(); - } else { - if (dictionary!.containsKey(PdfDictionaryProperties.subject)) { - annotationSubject = - (dictionary![PdfDictionaryProperties.subject]! as PdfString).value; - } else if (dictionary!.containsKey(PdfDictionaryProperties.subj)) { - annotationSubject = - (dictionary![PdfDictionaryProperties.subj]! as PdfString).value; - } - } - return annotationSubject!; - } - - /// Sets the subject of the annotation. - set subject(String value) { - if (subject != value) { - annotationSubject = value; - dictionary!.setString(PdfDictionaryProperties.subj, annotationSubject); - } - } - - /// Gets the ModifiedDate of the annotation. - DateTime? get modifiedDate => - isLoadedAnnotation ? _obtainModifiedDate() : annotationModifiedDate; - - /// Sets the ModifiedDate of the annotation. - set modifiedDate(DateTime? value) { - if (annotationModifiedDate != value) { - annotationModifiedDate = value; - dictionary!.setDateTime( - PdfDictionaryProperties.m, - annotationModifiedDate!, - ); - } - } - - /// Gets the opacity of the annotation. - double get opacity { - if (isLoadedAnnotation) { - return _obtainOpacity()!; - } - if (dictionary!.items!.containsKey(PdfName('CA'))) { - final PdfNumber ca = dictionary!.items![PdfName('CA')]! as PdfNumber; - annotationOpacity = ca.value!.toDouble(); - } - return annotationOpacity; - } - - /// Sets the opacity of the annotation. - /// - /// Opacity value should be between 0 to 1. - set opacity(double value) { - if (value < 0 || value > 1) { - throw ArgumentError.value('Valid value should be between 0 to 1.'); - } - if (annotationOpacity != value) { - annotationOpacity = value; - dictionary!.setProperty( - PdfDictionaryProperties.ca, - PdfNumber(annotationOpacity), - ); - } - } - - /// Sets the annotation flags. - set annotationFlags(List value) { - flag = value; - } - - /// Gets the annotation flags. - List get annotationFlags { - if (isLoadedAnnotation && flag == null) { - flag ??= obtainAnnotationFlags(getFlagValue()); - } - return flag ??= []; - } - - /// internal method - bool isLineBorder() { - if (base is PdfRectangleAnnotation || - base is PdfPolygonAnnotation || - base is PdfEllipseAnnotation || - base is PdfLineAnnotation) { - return true; - } else { - return false; - } - } - - /// internal method - void initializeAnnotationProperties( - PdfPage? page, - String? annotText, - Rect? bounds, - PdfAnnotationBorder? border, - PdfColor? color, - PdfColor? innerColor, - String? author, - double? opacity, - String? subject, - DateTime? modifiedDate, - List? flags, - bool? setAppearance, - ) { - dictionary!.beginSave = dictionaryBeginSave; - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.type), - PdfName(PdfDictionaryProperties.annot), - ); - if (page != null) { - this.page = page; - } - if (bounds != null) { - this.bounds = bounds; - } - if (annotText != null) { - text = annotText; - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.contents), - PdfString(text), - ); - } - if (border != null) { - this.border = border; - } - if (color != null) { - this.color = color; - } - if (innerColor != null) { - this.innerColor = innerColor; - } - if (author != null) { - this.author = author; - } - if (opacity != null) { - this.opacity = opacity; - } - if (subject != null) { - this.subject = subject; - } - if (modifiedDate != null) { - this.modifiedDate = modifiedDate; - } - if (setAppearance != null) { - this.setAppearance = setAppearance; - } - if (flags != null) { - annotationFlags = flags; - } - } - - /// internal method - void dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (_isContainsAnnotation()) { - if (!saved) { - PdfAnnotationHelper.save(base); - saved = true; - } - } - } - - bool _isContainsAnnotation() { - bool contains = false; - PdfArray? annotation; - if (page != null && - PdfPageHelper.getHelper( - page!, - ).dictionary!.containsKey(PdfDictionaryProperties.annots)) { - annotation = - PdfCrossTable.dereference( - PdfPageHelper.getHelper( - page!, - ).dictionary![PdfDictionaryProperties.annots], - ) - as PdfArray?; - if (annotation != null && - annotation.elements.isNotEmpty && - annotation.contains(annotation.elements[0]!)) { - contains = true; - } - } - return contains; - } - - /// internal method - void saveAnnotation() { - final PdfDocument? document = PdfPageHelper.getHelper(page!).document; - if (document != null && - PdfDocumentHelper.getHelper(document).conformanceLevel != - PdfConformanceLevel.none) { - if (base is PdfActionAnnotation && - PdfDocumentHelper.getHelper(document).conformanceLevel == - PdfConformanceLevel.a1b) { - throw ArgumentError( - 'The specified annotation type is not supported by PDF/A1-B or PDF/A1-A standard documents.', - ); - } - //This is needed to attain specific PDF/A conformance. - if (base is! PdfLinkAnnotation && - !setAppearance && - (PdfDocumentHelper.getHelper(document).conformanceLevel == - PdfConformanceLevel.a2b || - PdfDocumentHelper.getHelper(document).conformanceLevel == - PdfConformanceLevel.a3b)) { - throw ArgumentError( - "The appearance dictionary doesn't contain an entry. Enable setAppearance in PdfAnnotation class to overcome this error.", - ); - } - dictionary!.setNumber(PdfDictionaryProperties.f, 4); - } - if (annotationBorder != null) { - if (isLineBorder()) { - dictionary!.setProperty(PdfDictionaryProperties.bs, border); - } else { - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.border), - border, - ); - } - } - if ((base is! PdfLinkAnnotation && base is! PdfTextWebLink) || - ((base is PdfLinkAnnotation || base is PdfTextWebLink) && - !isLoadedAnnotation)) { - final PdfRectangle nativeRectangle = _obtainNativeRectangle(); - if (annotationInnerColor != null && - !annotationInnerColor!.isEmpty && - PdfColorHelper.getHelper(annotationInnerColor!).alpha != 0.0) { - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.ic), - PdfColorHelper.toArray(annotationInnerColor!), - ); - } - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.rect), - PdfArray.fromRectangle(nativeRectangle), - ); - } - } - - PdfRectangle _obtainNativeRectangle() { - final PdfRectangle nativeRectangle = PdfRectangle( - bounds.left, - bounds.bottom, - bounds.width, - bounds.height, - ); - Size? size; - PdfArray? cropOrMediaBox; - if (page != null) { - if (!PdfPageHelper.getHelper(page!).isLoadedPage) { - final PdfSection section = PdfPageHelper.getHelper(page!).section!; - nativeRectangle.location = PdfSectionHelper.getHelper( - section, - ).pointToNativePdf(page!, nativeRectangle.location); - } else { - size = page!.size; - nativeRectangle.y = size.height - rectangle.bottom; - } - cropOrMediaBox = _getCropOrMediaBox(page!, cropOrMediaBox); - } - if (cropOrMediaBox != null) { - if (cropOrMediaBox.count > 2) { - if ((cropOrMediaBox[0]! as PdfNumber).value != 0 || - (cropOrMediaBox[1]! as PdfNumber).value != 0) { - nativeRectangle.x = - nativeRectangle.x + - (cropOrMediaBox[0]! as PdfNumber).value!.toDouble(); - nativeRectangle.y = - nativeRectangle.y + - (cropOrMediaBox[1]! as PdfNumber).value!.toDouble(); - } - } - } - return nativeRectangle; - } - - PdfArray? _getCropOrMediaBox(PdfPage page, PdfArray? cropOrMediaBox) { - final PdfDictionary dictionary = PdfPageHelper.getHelper(page).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.cropBox)) { - cropOrMediaBox = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.cropBox]) - as PdfArray?; - } else if (dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { - cropOrMediaBox = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.mediaBox], - ) - as PdfArray?; - } - return cropOrMediaBox; - } - - /// internal method - void setPage(PdfPage pdfPage) { - page = pdfPage; - final PdfDocument? document = PdfPageHelper.getHelper(page!).document; - if (!PdfPageHelper.getHelper(pdfPage).isLoadedPage) { - if (document != null) { - final PdfCatalog catalog = - PdfDocumentHelper.getHelper(document).catalog; - catalog.beginSaveList ??= []; - final PdfGraphics graphics = - pdfPage.graphics; //Accessed for creating page content. - ArgumentError.checkNotNull(graphics); - if (dictionary!.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName? name = - dictionary!.items![PdfName(PdfDictionaryProperties.subtype)] - as PdfName?; - if (name != null) { - if (name.name == PdfDictionaryProperties.text || - name.name == PdfDictionaryProperties.square || - name.name == PdfDictionaryProperties.highlight || - name.name == PdfDictionaryProperties.squiggly || - name.name == PdfDictionaryProperties.underline || - name.name == PdfDictionaryProperties.strikeOut || - flatten) { - catalog.beginSaveList!.add(dictionaryBeginSave); - catalog.modify(); - } - } - } else if (flatten) { - catalog.beginSaveList!.add(dictionaryBeginSave); - catalog.modify(); - } - } - } else { - if (document != null) { - final PdfCatalog catalog = - PdfDocumentHelper.getHelper(document).catalog; - if (dictionary!.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName? name = - dictionary!.items![PdfName(PdfDictionaryProperties.subtype)] - as PdfName?; - catalog.beginSaveList ??= []; - if (name != null) { - if (name.name == PdfDictionaryProperties.circle || - name.name == PdfDictionaryProperties.square || - name.name == PdfDictionaryProperties.line || - name.name == PdfDictionaryProperties.polygon || - name.name == PdfDictionaryProperties.highlight || - name.name == PdfDictionaryProperties.squiggly || - name.name == PdfDictionaryProperties.underline || - name.name == PdfDictionaryProperties.strikeOut || - name.name == PdfDictionaryProperties.text || - name.name == PdfDictionaryProperties.link) { - catalog.beginSaveList!.add(dictionaryBeginSave); - catalog.modify(); - } - } - } else if (flatten) { - catalog.beginSaveList!.add(dictionaryBeginSave); - catalog.modify(); - } - } - } - if (page != null && !PdfPageHelper.getHelper(page!).isLoadedPage) { - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.p), - PdfReferenceHolder(page), - ); - } - } - - /// Gets the bounds. - PdfRectangle _getBounds(PdfDictionary dictionary, PdfCrossTable crossTable) { - PdfArray? array; - if (dictionary.containsKey(PdfDictionaryProperties.rect)) { - array = - crossTable.getObject(dictionary[PdfDictionaryProperties.rect]) - as PdfArray?; - } - return array!.toRectangle(); - } - - // Gets the border. - PdfAnnotationBorder _obtainBorder() { - final PdfAnnotationBorder border = PdfAnnotationBorder(); - if (dictionary!.containsKey(PdfDictionaryProperties.border)) { - final PdfArray? borderArray = - PdfCrossTable.dereference(dictionary![PdfDictionaryProperties.border]) - as PdfArray?; - if (borderArray != null && borderArray.count >= 2) { - if (borderArray[0] is PdfNumber && - borderArray[1] is PdfNumber && - borderArray[2] is PdfNumber) { - final double width = (borderArray[0]! as PdfNumber).value!.toDouble(); - final double hRadius = - (borderArray[1]! as PdfNumber).value!.toDouble(); - final double vRadius = - (borderArray[2]! as PdfNumber).value!.toDouble(); - border.width = vRadius; - border.horizontalRadius = width; - border.verticalRadius = hRadius; - } - } - } else if (dictionary!.containsKey(PdfDictionaryProperties.bs)) { - final PdfDictionary lbDic = - crossTable.getObject(dictionary![PdfDictionaryProperties.bs])! - as PdfDictionary; - if (lbDic.containsKey(PdfDictionaryProperties.w)) { - final PdfNumber? value = lbDic[PdfDictionaryProperties.w] as PdfNumber?; - if (value != null) { - border.width = value.value!.toDouble(); - } - } - if (lbDic.containsKey(PdfDictionaryProperties.s)) { - final PdfName bstr = - PdfCrossTable.dereference(lbDic[PdfDictionaryProperties.s])! - as PdfName; - border.borderStyle = _getBorderStyle(bstr.name.toString()); - } - if (lbDic.containsKey(PdfDictionaryProperties.d)) { - final PdfArray? dasharray = - PdfCrossTable.dereference(lbDic[PdfDictionaryProperties.d]) - as PdfArray?; - if (dasharray != null) { - final PdfNumber dashArray = dasharray[0]! as PdfNumber; - final int dashArrayValue = dashArray.value!.toInt(); - dasharray.clear(); - dasharray.insert(0, PdfNumber(dashArrayValue)); - dasharray.insert(1, PdfNumber(dashArrayValue)); - border.dashArray = dashArrayValue; - } - } - } - return border; - } - - // Gets the text. - String? _obtainText() { - String tempText; - if (dictionary!.containsKey(PdfDictionaryProperties.contents)) { - final PdfString? mText = - PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.contents], - ) - as PdfString?; - if (mText != null) { - textValue = mText.value.toString(); - } - return textValue; - } else { - tempText = ''; - return tempText; - } - } - - // Gets the color. - PdfColor _obtainColor() { - PdfColor color = PdfColor.empty; - PdfArray? colours; - if (dictionary!.containsKey(PdfDictionaryProperties.c)) { - colours = dictionary![PdfDictionaryProperties.c] as PdfArray?; - } - if (colours != null && colours.elements.length == 1) { - //Convert the float color values into bytes - final PdfNumber? color0 = crossTable.getObject(colours[0]) as PdfNumber?; - if (color0 != null) { - color = PdfColorHelper.fromGray(color0.value! as double); - } - } else if (colours != null && colours.elements.length == 3) { - final PdfNumber color0 = colours[0]! as PdfNumber; - final PdfNumber color1 = colours[1]! as PdfNumber; - final PdfNumber color2 = colours[2]! as PdfNumber; - //Convert the float color values into bytes - final int red = (color0.value! * 255).round().toUnsigned(8); - final int green = (color1.value! * 255).round().toUnsigned(8); - final int blue = (color2.value! * 255).round().toUnsigned(8); - color = PdfColor(red, green, blue); - } else if (colours != null && colours.elements.length == 4) { - final PdfNumber? color0 = crossTable.getObject(colours[0]) as PdfNumber?; - final PdfNumber? color1 = crossTable.getObject(colours[1]) as PdfNumber?; - final PdfNumber? color2 = crossTable.getObject(colours[2]) as PdfNumber?; - final PdfNumber? color3 = crossTable.getObject(colours[3]) as PdfNumber?; - if (color0 != null && - color1 != null && - color2 != null && - color3 != null) { - //Convert the float color values into bytes - final double cyan = color0.value! as double; - final double magenta = color1.value! as double; - final double yellow = color2.value! as double; - final double black = color3.value! as double; - color = PdfColor.fromCMYK(cyan, magenta, yellow, black); - } - } - return color; - } - - // Gets the Opacity. - double? _obtainOpacity() { - if (dictionary!.containsKey(PdfDictionaryProperties.ca)) { - annotationOpacity = _getNumber(PdfDictionaryProperties.ca)!; - } - return annotationOpacity; - } - - // Gets the number value. - double? _getNumber(String keyName) { - double? result = 0; - final PdfNumber? numb = dictionary![keyName] as PdfNumber?; - if (numb != null) { - result = numb.value as double?; - } - return result; - } - - // Gets the Author. - String _obtainAuthor() { - String author = ''; - if (dictionary!.containsKey(PdfDictionaryProperties.author)) { - final IPdfPrimitive? tempAuthor = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.author], - ); - if (tempAuthor != null && - tempAuthor is PdfString && - tempAuthor.value != null) { - author = tempAuthor.value!; - } - } else if (dictionary!.containsKey(PdfDictionaryProperties.t)) { - final IPdfPrimitive? tempAuthor = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.t], - ); - if (tempAuthor != null && - tempAuthor is PdfString && - tempAuthor.value != null) { - author = tempAuthor.value!; - } - } - return author; - } - - // Gets the Subject. - String _obtainSubject() { - String subject = ''; - if (dictionary!.containsKey(PdfDictionaryProperties.subject)) { - final IPdfPrimitive? tempSubject = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.subject], - ); - if (tempSubject != null && - tempSubject is PdfString && - tempSubject.value != null) { - subject = tempSubject.value!; - } - } else if (dictionary!.containsKey(PdfDictionaryProperties.subj)) { - final IPdfPrimitive? tempSubject = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.subj], - ); - if (tempSubject != null && - tempSubject is PdfString && - tempSubject.value != null) { - subject = tempSubject.value!; - } - } - return subject; - } - - // Gets the ModifiedDate. - DateTime? _obtainModifiedDate() { - if (dictionary!.containsKey(PdfDictionaryProperties.modificationDate) || - dictionary!.containsKey(PdfDictionaryProperties.m)) { - PdfString? modifiedDate = - dictionary![PdfDictionaryProperties.modificationDate] as PdfString?; - modifiedDate ??= dictionary![PdfDictionaryProperties.m] as PdfString?; - annotationModifiedDate = dictionary!.getDateTime(modifiedDate!); - } - return annotationModifiedDate; - } - - /// internal method - String getEnumName(dynamic annotText) { - final int index = annotText.toString().indexOf('.'); - final String name = annotText.toString().substring(index + 1); - return name[0].toUpperCase() + name.substring(1); - } - - //Get the inner line color - PdfColor _obtainInnerColor() { - PdfColor color = PdfColor.empty; - PdfArray? colours; - if (dictionary!.containsKey(PdfDictionaryProperties.iC)) { - colours = - PdfCrossTable.dereference(dictionary![PdfDictionaryProperties.iC]) - as PdfArray?; - if (colours != null && colours.count > 0) { - final int red = ((colours[0]! as PdfNumber).value! * 255) - .round() - .toUnsigned(8); - final int green = ((colours[1]! as PdfNumber).value! * 255) - .round() - .toUnsigned(8); - final int blue = ((colours[2]! as PdfNumber).value! * 255) - .round() - .toUnsigned(8); - color = PdfColor(red, green, blue); - } - } - return color; - } - - /// internal method - PdfMargins? obtainMargin() { - if (page != null && PdfPageHelper.getHelper(page!).section != null) { - margins = PdfPageHelper.getHelper(page!).section!.pageSettings.margins; - } - return margins; - } - - /// internal method - void flattenPopup() { - if (page != null && !isLoadedAnnotation) { - _flattenAnnotationPopups( - page!, - color, - bounds, - border, - author, - subject, - text, - ); - } - } - - void _flattenAnnotationPopups( - PdfPage page, - PdfColor color, - Rect annotBounds, - PdfAnnotationBorder border, - String author, - String subject, - String text, - ) { - final Size clientSize = - PdfPageHelper.getHelper(page).isLoadedPage - ? page.size - : page.getClientSize(); - final double x = clientSize.width - 180; - final double y = - (annotBounds.top + 142) < clientSize.height - ? annotBounds.top - : clientSize.height - 142; - Rect bounds = Rect.fromLTWH(x, y, 180, 142); - // Draw annotation based on bounds - if (dictionary![PdfDictionaryProperties.popup] != null) { - final IPdfPrimitive? obj = dictionary![PdfDictionaryProperties.popup]; - final PdfDictionary? tempDictionary = - PdfCrossTable.dereference(obj) as PdfDictionary?; - if (tempDictionary != null) { - final PdfArray? rectValue = - PdfCrossTable.dereference( - tempDictionary[PdfDictionaryProperties.rect], - ) - as PdfArray?; - final PdfCrossTable? crosstable = - PdfPageHelper.getHelper(page).crossTable; - if (rectValue != null) { - final PdfNumber left = - crosstable!.getReference(rectValue[0]) as PdfNumber; - final PdfNumber top = - crosstable.getReference(rectValue[1]) as PdfNumber; - final PdfNumber width = - crosstable.getReference(rectValue[2]) as PdfNumber; - final PdfNumber height = - crosstable.getReference(rectValue[3]) as PdfNumber; - bounds = Rect.fromLTWH( - left.value! as double, - top.value! as double, - width.value! - (left.value! as double), - height.value! - (top.value! as double), - ); - } - } - } - final PdfBrush backBrush = PdfSolidBrush(color); - final double borderWidth = border.width / 2; - double? trackingHeight = 0; - final PdfBrush aBrush = PdfSolidBrush(_getForeColor(color)); - if (author != '') { - final Map returnedValue = _drawAuthor( - author, - subject, - bounds, - backBrush, - aBrush, - page, - trackingHeight, - border, - ); - trackingHeight = returnedValue['height']; - } else if (subject != '') { - final Rect titleRect = Rect.fromLTWH( - bounds.left + borderWidth, - bounds.top + borderWidth, - bounds.width - border.width, - 40, - ); - _saveGraphics(page, PdfBlendMode.hardLight); - page.graphics.drawRectangle( - pen: PdfPens.black, - brush: backBrush, - bounds: titleRect, - ); - page.graphics.restore(); - Rect contentRect = Rect.fromLTWH( - titleRect.left + 11, - titleRect.top, - titleRect.width, - titleRect.height / 2, - ); - contentRect = Rect.fromLTWH( - contentRect.left, - contentRect.top + contentRect.height - 2, - contentRect.width, - titleRect.height / 2, - ); - _saveGraphics(page, PdfBlendMode.normal); - _drawSubject(subject, contentRect, page); - page.graphics.restore(); - trackingHeight = 40; - } else { - _saveGraphics(page, PdfBlendMode.hardLight); - final Rect titleRect = Rect.fromLTWH( - bounds.left + borderWidth, - bounds.top + borderWidth, - bounds.width - border.width, - 20, - ); - page.graphics.drawRectangle( - pen: PdfPens.black, - brush: backBrush, - bounds: titleRect, - ); - trackingHeight = 20; - page.graphics.restore(); - } - Rect cRect = Rect.fromLTWH( - bounds.left + borderWidth, - bounds.top + borderWidth + trackingHeight!, - bounds.width - border.width, - bounds.height - (trackingHeight + border.width), - ); - _saveGraphics(page, PdfBlendMode.hardLight); - page.graphics.drawRectangle( - pen: PdfPens.black, - brush: PdfBrushes.white, - bounds: cRect, - ); - cRect = Rect.fromLTWH( - cRect.left + 11, - cRect.top + 5, - cRect.width - 22, - cRect.height, - ); - page.graphics.restore(); - _saveGraphics(page, PdfBlendMode.normal); - page.graphics.drawString( - text, - PdfStandardFont(PdfFontFamily.helvetica, 10.5), - brush: PdfBrushes.black, - bounds: cRect, - ); - page.graphics.restore(); - } - - void _drawSubject(String subject, Rect bounds, PdfPage page) { - page.graphics.drawString( - subject, - PdfStandardFont(PdfFontFamily.helvetica, 10.5, style: PdfFontStyle.bold), - brush: PdfBrushes.black, - bounds: bounds, - format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), - ); - } - - void _saveGraphics(PdfPage page, PdfBlendMode mode) { - page.graphics.save(); - PdfGraphicsHelper.getHelper( - page.graphics, - ).applyTransparency(0.8, 8.0, mode); - } - - PdfColor _getForeColor(PdfColor c) { - return (((c.r + c.b + c.g) / 3) > 128) - ? PdfColor(0, 0, 0) - : PdfColor(255, 255, 255); - } - - Map _drawAuthor( - String author, - String subject, - Rect bounds, - PdfBrush backBrush, - PdfBrush aBrush, - PdfPage page, - double? trackingHeight, - PdfAnnotationBorder border, - ) { - final double borderWidth = border.width / 2; - final PdfRectangle titleRect = PdfRectangle.fromRect( - Rect.fromLTWH( - bounds.left + borderWidth, - bounds.top + borderWidth, - bounds.width - border.width, - 20, - ), - ); - if (subject != '') { - titleRect.height += 20; - trackingHeight = titleRect.height; - _saveGraphics(page, PdfBlendMode.hardLight); - page.graphics.drawRectangle( - pen: PdfPens.black, - brush: backBrush, - bounds: titleRect.rect, - ); - page.graphics.restore(); - Rect contentRect = Rect.fromLTWH( - titleRect.x + 11, - titleRect.y, - titleRect.width, - titleRect.height / 2, - ); - _saveGraphics(page, PdfBlendMode.normal); - page.graphics.drawString( - author, - PdfStandardFont( - PdfFontFamily.helvetica, - 10.5, - style: PdfFontStyle.bold, - ), - brush: aBrush, - bounds: contentRect, - format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), - ); - contentRect = Rect.fromLTWH( - contentRect.left, - contentRect.top + contentRect.height - 2, - contentRect.width, - titleRect.height / 2, - ); - _drawSubject(subject, contentRect, page); - page.graphics.restore(); - } else { - _saveGraphics(page, PdfBlendMode.hardLight); - page.graphics.drawRectangle( - pen: PdfPens.black, - brush: backBrush, - bounds: titleRect.rect, - ); - page.graphics.restore(); - final Rect contentRect = Rect.fromLTWH( - titleRect.x + 11, - titleRect.y, - titleRect.width, - titleRect.height, - ); - _saveGraphics(page, PdfBlendMode.normal); - page.graphics.drawString( - author, - PdfStandardFont(PdfFontFamily.helvetica, 10.5), - brush: aBrush, - bounds: contentRect, - format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), - ); - trackingHeight = titleRect.height; - page.graphics.restore(); - } - return {'height': trackingHeight}; - } - - /// internal method - Rect calculateTemplateBounds( - Rect bounds, - PdfPage? page, - PdfTemplate? template, - bool isNormalMatrix, - ) { - double x = bounds.left, - y = bounds.top, - width = bounds.width, - height = bounds.height; - if (page != null) { - final int graphicsRotation = _obtainGraphicsRotation( - PdfGraphicsHelper.getHelper(page.graphics).matrix, - ); - if (graphicsRotation == 0 && !isNormalMatrix) { - x = bounds.left; - y = bounds.top + bounds.height - bounds.width; - width = bounds.height; - height = bounds.width; - } - } - return Rect.fromLTWH(x, y, width, height); - } - - int _obtainGraphicsRotation(PdfTransformationMatrix matrix) { - int angle = 0; - final double radians = atan2( - matrix.matrix.elements[2], - matrix.matrix.elements[0], - ); - angle = (radians * 180 / pi).round(); - switch (angle) { - case -90: - angle = 90; - break; - case -180: - angle = 180; - break; - case 90: - angle = 270; - break; - } - return angle; - } - - /// internal method - static void setMatrixToZeroRotation(PdfDictionary template) { - final PdfArray? bbox = template[PdfDictionaryProperties.bBox] as PdfArray?; - if (bbox != null) { - final List elements = [ - 1, - 0, - 0, - 1, - -(bbox[0]! as PdfNumber).value! as double, - -(bbox[1]! as PdfNumber).value! as double, - ]; - template[PdfDictionaryProperties.matrix] = PdfArray(elements); - } - } - - PdfBorderStyle _getBorderStyle(String bstyle) { - PdfBorderStyle style = PdfBorderStyle.solid; - switch (bstyle) { - case 'S': - style = PdfBorderStyle.solid; - break; - case 'D': - style = PdfBorderStyle.dashed; - break; - case 'B': - style = PdfBorderStyle.beveled; - break; - case 'I': - style = PdfBorderStyle.inset; - break; - case 'U': - style = PdfBorderStyle.underline; - break; - } - return style; - } - - /// internal method - PdfRectangle calculateLineBounds( - List linePoints, - int leaderLineExt, - int leaderLineValue, - int leaderOffset, - PdfArray lineStyle, - double borderLength, - ) { - PdfRectangle tempBounds = PdfRectangle.fromRect(bounds); - final PdfPath path = PdfPath(); - if (linePoints.length == 4) { - final double x1 = linePoints[0].toDouble(); - final double y1 = linePoints[1].toDouble(); - final double x2 = linePoints[2].toDouble(); - final double y2 = linePoints[3].toDouble(); - double angle = 0; - if (x2 - x1 == 0) { - if (y2 > y1) { - angle = 90; - } else { - angle = 270; - } - } else { - angle = getAngle(x1, y1, x2, y2); - } - int leaderLine = 0; - double lineAngle = 0; - if (leaderLineValue < 0) { - leaderLine = leaderLineValue * -1; - lineAngle = angle + 180; - } else { - leaderLine = leaderLineValue; - lineAngle = angle; - } - final List x1y1 = [x1, y1]; - final List x2y2 = [x2, y2]; - if (leaderOffset != 0) { - final List offsetPoint1 = getAxisValue( - x1y1, - lineAngle + 90, - leaderOffset.toDouble(), - ); - final List offsetPoint2 = getAxisValue( - x2y2, - lineAngle + 90, - leaderOffset.toDouble(), - ); - linePoints[0] = offsetPoint1[0].toInt(); - linePoints[1] = offsetPoint1[1].toInt(); - linePoints[2] = offsetPoint2[0].toInt(); - linePoints[3] = offsetPoint2[1].toInt(); - } - - final List startingPoint = getAxisValue( - x1y1, - lineAngle + 90, - (leaderLine + leaderOffset).toDouble(), - ); - final List endingPoint = getAxisValue( - x2y2, - lineAngle + 90, - (leaderLine + leaderOffset).toDouble(), - ); - - final List beginLineLeader = getAxisValue( - x1y1, - lineAngle + 90, - (leaderLineExt + leaderLine + leaderOffset).toDouble(), - ); - - final List endLineLeader = getAxisValue( - x2y2, - lineAngle + 90, - (leaderLineExt + leaderLine + leaderOffset).toDouble(), - ); - - final List stylePoint = []; - - for (int i = 0; i < lineStyle.count; i++) { - final PdfName lineEndingStyle = lineStyle[i]! as PdfName; - final PdfPoint point = PdfPoint.empty; - switch (getEnumName(lineEndingStyle.name)) { - case 'Square': - case 'Circle': - case 'Diamond': - { - point.x = 3; - point.y = 3; - } - break; - case 'OpenArrow': - case 'ClosedArrow': - { - point.x = 1; - point.y = 5; - } - break; - case 'ROpenArrow': - case 'RClosedArrow': - { - point.x = 9 + (borderLength / 2); - point.y = 5 + (borderLength / 2); - } - break; - case 'Slash': - { - point.x = 5; - point.y = 9; - } - break; - case 'Butt': - { - point.x = 1; - point.y = 3; - } - break; - default: - { - point.x = 0; - point.y = 0; - } - break; - } - stylePoint.add(point); - } - final List widthX = List.filled(2, 0); - final List heightY = List.filled(2, 0); - - if ((lineAngle >= 45 && lineAngle <= 135) || - (lineAngle >= 225 && lineAngle <= 315)) { - widthX[0] = stylePoint[0].y; - heightY[0] = stylePoint[0].x; - widthX[1] = stylePoint[1].y; - heightY[1] = stylePoint[1].x; - } else { - widthX[0] = stylePoint[0].x; - heightY[0] = stylePoint[0].y; - widthX[1] = stylePoint[1].x; - heightY[1] = stylePoint[1].y; - } - - final double height = max(heightY[0], heightY[1]); - if (startingPoint[0] == - [startingPoint[0], endingPoint[0]].reduce(min)) { - startingPoint[0] -= widthX[0] * borderLength; - endingPoint[0] += widthX[1] * borderLength; - startingPoint[0] = [ - startingPoint[0], - linePoints[0].toDouble(), - ].reduce(min); - startingPoint[0] = min(startingPoint[0], beginLineLeader[0]); - endingPoint[0] = max(endingPoint[0], linePoints[2].toDouble()); - endingPoint[0] = max(endingPoint[0], endLineLeader[0]); - } else { - startingPoint[0] += widthX[0] * borderLength; - endingPoint[0] -= widthX[1] * borderLength; - startingPoint[0] = max(startingPoint[0], linePoints[0].toDouble()); - startingPoint[0] = max(startingPoint[0], beginLineLeader[0]); - endingPoint[0] = min(endingPoint[0], linePoints[2].toDouble()); - endingPoint[0] = min(endingPoint[0], endLineLeader[0]); - } - if (startingPoint[1] == min(startingPoint[1], endingPoint[1])) { - startingPoint[1] -= height * borderLength; - endingPoint[1] += height * borderLength; - startingPoint[1] = min(startingPoint[1], linePoints[1].toDouble()); - startingPoint[1] = min(startingPoint[1], beginLineLeader[1]); - endingPoint[1] = max(endingPoint[1], linePoints[3].toDouble()); - endingPoint[1] = max(endingPoint[1], endLineLeader[1]); - } else { - startingPoint[1] += height * borderLength; - endingPoint[1] -= height * borderLength; - startingPoint[1] = max(startingPoint[1], linePoints[1].toDouble()); - startingPoint[1] = max(startingPoint[1], beginLineLeader[1]); - endingPoint[1] = min(endingPoint[1], linePoints[3].toDouble()); - endingPoint[1] = min(endingPoint[1], endLineLeader[1]); - } - path.addLine( - Offset(startingPoint[0], startingPoint[1]), - Offset(endingPoint[0], endingPoint[1]), - ); - tempBounds = PdfPathHelper.getHelper(path).getBoundsInternal(); - } - return tempBounds; - } - - /// internal method - List getAxisValue(List value, double angle, double length) { - const double degToRad = pi / 180.0; - final List xy = List.filled(2, 0); - xy[0] = value[0] + cos(angle * degToRad) * length; - xy[1] = value[1] + sin(angle * degToRad) * length; - - return xy; - } - - /// internal method - double getAngle(double x1, double y1, double x2, double y2) { - double angle = 0; - final double angleRatio = (y2 - y1) / (x2 - x1); - final double radians = atan(angleRatio); - angle = radians * (180 / pi); - - if ((x2 - x1) < 0 || (y2 - y1) < 0) { - angle += 180; - } - if ((x2 - x1) > 0 && (y2 - y1) < 0) { - angle -= 180; - } - if (angle < 0) { - angle += 360; - } - - return angle; - } - - /// internal method - void setLineEndingStyles( - List startingPoint, - List endingPoint, - PdfGraphics? graphics, - double angle, - PdfPen? borderPen, - PdfBrush? backBrush, - PdfArray lineStyle, - double borderLength, - ) { - List axisPoint; - if (borderLength == 0) { - borderLength = 1; - borderPen = null; - } - if (backBrush is PdfSolidBrush) { - if (backBrush.color.isEmpty) { - backBrush = null; - } - } - for (int i = 0; i < lineStyle.count; i++) { - final PdfName lineEndingStyle = lineStyle[i]! as PdfName; - if (i == 0) { - axisPoint = startingPoint; - } else { - axisPoint = endingPoint; - } - switch (lineEndingStyle.name) { - case 'Square': - { - final Rect rect = Rect.fromLTWH( - axisPoint[0] - (3 * borderLength), - -(axisPoint[1] + (3 * borderLength)), - 6 * borderLength, - 6 * borderLength, - ); - graphics!.drawRectangle( - bounds: rect, - pen: borderPen, - brush: backBrush, - ); - } - break; - case 'Circle': - { - final Rect rect = Rect.fromLTWH( - axisPoint[0] - (3 * borderLength), - -(axisPoint[1] + (3 * borderLength)), - 6 * borderLength, - 6 * borderLength, - ); - graphics!.drawEllipse(rect, pen: borderPen, brush: backBrush); - } - break; - case 'OpenArrow': - { - int arraowAngle = 0; - if (i == 0) { - arraowAngle = 30; - } else { - arraowAngle = 150; - } - final double length = 9 * borderLength; - List startPoint; - if (i == 0) { - startPoint = getAxisValue(axisPoint, angle, borderLength); - } else { - startPoint = getAxisValue(axisPoint, angle, -borderLength); - } - final List point1 = getAxisValue( - startPoint, - angle + arraowAngle, - length, - ); - final List point2 = getAxisValue( - startPoint, - angle - arraowAngle, - length, - ); - - final PdfPath path = PdfPath(pen: borderPen); - path.addLine( - Offset(startPoint[0], -startPoint[1]), - Offset(point1[0], -point1[1]), - ); - path.addLine( - Offset(startPoint[0], -startPoint[1]), - Offset(point2[0], -point2[1]), - ); - graphics!.drawPath(path, pen: borderPen); - } - break; - case 'ClosedArrow': - { - int arraowAngle = 0; - if (i == 0) { - arraowAngle = 30; - } else { - arraowAngle = 150; - } - final double length = 9 * borderLength; - List startPoint; - if (i == 0) { - startPoint = getAxisValue(axisPoint, angle, borderLength); - } else { - startPoint = getAxisValue(axisPoint, angle, -borderLength); - } - final List point1 = getAxisValue( - startPoint, - angle + arraowAngle, - length, - ); - final List point2 = getAxisValue( - startPoint, - angle - arraowAngle, - length, - ); - final List points = [ - Offset(startPoint[0], -startPoint[1]), - Offset(point1[0], -point1[1]), - Offset(point2[0], -point2[1]), - ]; - graphics!.drawPolygon(points, pen: borderPen, brush: backBrush); - } - break; - case 'ROpenArrow': - { - int arraowAngle = 0; - if (i == 0) { - arraowAngle = 150; - } else { - arraowAngle = 30; - } - final double length = 9 * borderLength; - List startPoint; - if (i == 0) { - startPoint = getAxisValue(axisPoint, angle, -borderLength); - } else { - startPoint = getAxisValue(axisPoint, angle, borderLength); - } - final List point1 = getAxisValue( - startPoint, - angle + arraowAngle, - length, - ); - final List point2 = getAxisValue( - startPoint, - angle - arraowAngle, - length, - ); - - final PdfPath path = PdfPath(pen: borderPen); - path.addLine( - Offset(startPoint[0], -startPoint[1]), - Offset(point1[0], -point1[1]), - ); - path.addLine( - Offset(startPoint[0], -startPoint[1]), - Offset(point2[0], -point2[1]), - ); - graphics!.drawPath(path, pen: borderPen); - } - break; - case 'RClosedArrow': - { - int arraowAngle = 0; - if (i == 0) { - arraowAngle = 150; - } else { - arraowAngle = 30; - } - final double length = 9 * borderLength; - List startPoint; - if (i == 0) { - startPoint = getAxisValue(axisPoint, angle, -borderLength); - } else { - startPoint = getAxisValue(axisPoint, angle, borderLength); - } - - final List point1 = getAxisValue( - startPoint, - angle + arraowAngle, - length, - ); - final List point2 = getAxisValue( - startPoint, - angle - arraowAngle, - length, - ); - final List points = [ - Offset(startPoint[0], -startPoint[1]), - Offset(point1[0], -point1[1]), - Offset(point2[0], -point2[1]), - ]; - graphics!.drawPolygon(points, pen: borderPen, brush: backBrush); - } - break; - case 'Slash': - { - final double length = 9 * borderLength; - final List point1 = getAxisValue( - axisPoint, - angle + 60, - length, - ); - final List point2 = getAxisValue( - axisPoint, - angle - 120, - length, - ); - graphics!.drawLine( - borderPen!, - Offset(axisPoint[0], -axisPoint[1]), - Offset(point1[0], -point1[1]), - ); - graphics.drawLine( - borderPen, - Offset(axisPoint[0], -axisPoint[1]), - Offset(point2[0], -point2[1]), - ); - } - break; - case 'Diamond': - { - final double length = 3 * borderLength; - final List point1 = getAxisValue(axisPoint, 180, length); - final List point2 = getAxisValue(axisPoint, 90, length); - final List point3 = getAxisValue(axisPoint, 0, length); - final List point4 = getAxisValue(axisPoint, -90, length); - final List points = [ - Offset(point1[0], -point1[1]), - Offset(point2[0], -point2[1]), - Offset(point3[0], -point3[1]), - Offset(point4[0], -point4[1]), - ]; - graphics!.drawPolygon(points, pen: borderPen, brush: backBrush); - } - break; - case 'Butt': - { - final double length = 3 * borderLength; - final List point1 = getAxisValue( - axisPoint, - angle + 90, - length, - ); - final List point2 = getAxisValue( - axisPoint, - angle - 90, - length, - ); - - graphics!.drawLine( - borderPen!, - Offset(point1[0], -point1[1]), - Offset(point2[0], -point2[1]), - ); - } - break; - } - } - } - - /// Returns the appearance matrix is rotated or not - bool validateTemplateMatrix(PdfDictionary dictionary) { - bool isRotatedMatrix = false; - if (dictionary.containsKey(PdfDictionaryProperties.matrix)) { - final PdfArray? matrix = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.matrix]) - as PdfArray?; - if (matrix != null && matrix.count > 3) { - if ((matrix[0]! as PdfNumber).value == 1 && - (matrix[1]! as PdfNumber).value == 0 && - (matrix[2]! as PdfNumber).value == 0 && - (matrix[3]! as PdfNumber).value == 1) { - isRotatedMatrix = true; - } - } - } else { - isRotatedMatrix = true; - } - return isRotatedMatrix; - } - - /// Returns the boolean if the template matrix is valid or not - bool isValidTemplateMatrix( - PdfDictionary dictionary, - Offset bounds, - PdfTemplate template, - ) { - bool isValidMatrix = true; - Offset point = bounds; - if (dictionary.containsKey(PdfDictionaryProperties.matrix)) { - final IPdfPrimitive? bbox = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.bBox], - ); - final IPdfPrimitive? matrix = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.matrix], - ); - if (matrix != null && - bbox != null && - matrix is PdfArray && - bbox is PdfArray && - matrix.count > 3 && - bbox.count > 2) { - if ((matrix[0]! as PdfNumber).value == 1 && - (matrix[1]! as PdfNumber).value == 0 && - (matrix[2]! as PdfNumber).value == 0 && - (matrix[3]! as PdfNumber).value == 1) { - if ((((bbox[0]! as PdfNumber).value!.toDouble() != - -(matrix[4]! as PdfNumber).value!.toDouble()) && - ((bbox[1]! as PdfNumber).value!.toDouble() != - -(matrix[5]! as PdfNumber).value!.toDouble())) || - ((bbox[0]! as PdfNumber).value!.toDouble() == 0 && - -(matrix[4]! as PdfNumber).value!.toDouble() == 0)) { - final PdfGraphics pageGraphics = page!.graphics; - final PdfGraphicsState state = pageGraphics.save(); - if (opacity < 1) { - pageGraphics.setTransparency(opacity); - } - point = Offset( - point.dx - (bbox[0]! as PdfNumber).value!.toDouble(), - point.dy + (bbox[1]! as PdfNumber).value!.toDouble(), - ); - pageGraphics.drawPdfTemplate(template, point); - pageGraphics.restore(state); - page!.annotations.remove(base); - isValidMatrix = false; - } - } else if ((matrix[0]! as PdfNumber).value == 0 && - (matrix[1]! as PdfNumber).value == -1 && - (matrix[2]! as PdfNumber).value == 1 && - (matrix[3]! as PdfNumber).value == 0) { - if ((bbox[0]! as PdfNumber).value! > 0) { - isValidMatrix = false; - } - } else { - if ((bbox[0]! as PdfNumber).value! > 0) { - isValidMatrix = false; - } - } - } - } - return isValidMatrix; - } - - /// Flatten annotation template - void flattenAnnotationTemplate(PdfTemplate appearance, bool isNormalMatrix) { - final PdfGraphicsState state = page!.graphics.save(); - if (opacity < 1) { - page!.graphics.setTransparency(opacity); - } - final Rect bound = calculateTemplateBounds( - bounds, - page, - appearance, - isNormalMatrix, - ); - page!.graphics.drawPdfTemplate(appearance, bound.topLeft, bounds.size); - page!.graphics.restore(state); - page!.annotations.remove(base); - } - - /// Draw CloudStye to the Shapes - void drawCloudStyle( - PdfGraphics graphics, - PdfBrush? brush, - PdfPen? pen, - double radius, - double overlap, - List points, - bool isAppearance, - ) { - if (_isClockWise(points)) { - points = List.generate( - points.length, - (int i) => points[points.length - (i + 1)], - ); - } - - // Create a list of circles - final List<_CloudStyleArc> circles = <_CloudStyleArc>[]; - final double circleOverlap = 2 * radius * overlap; - Offset previousPoint = points[points.length - 1]; - for (int i = 0; i < points.length; i++) { - final Offset currentPoint = points[i]; - double dx = currentPoint.dx - previousPoint.dx; - double dy = currentPoint.dy - previousPoint.dy; - final double len = sqrt(dx * dx + dy * dy); - dx = dx / len; - dy = dy / len; - final double d = circleOverlap; - for (double a = 0; a + 0.1 * d < len; a += d) { - final _CloudStyleArc cur = _CloudStyleArc(); - cur.point = Offset( - previousPoint.dx + a * dx, - previousPoint.dy + a * dy, - ); - circles.add(cur); - } - previousPoint = currentPoint; - } - final PdfPath gpath = PdfPath(); - gpath.addPolygon(points); - - // Determine intersection angles of circles - _CloudStyleArc previousCurvedStyleArc = circles[circles.length - 1]; - for (int i = 0; i < circles.length; i++) { - final _CloudStyleArc currentCurvedStyleArc = circles[i]; - final Offset angle = _getIntersectionDegrees( - previousCurvedStyleArc.point, - currentCurvedStyleArc.point, - radius, - ); - previousCurvedStyleArc.endAngle = angle.dx; - currentCurvedStyleArc.startAngle = angle.dy; - previousCurvedStyleArc = currentCurvedStyleArc; - } - - // Draw the cloud - PdfPath path = PdfPath(); - for (int i = 0; i < circles.length; i++) { - final _CloudStyleArc curr = circles[i]; - final double angle = - curr.startAngle < 0 - ? ((curr.startAngle * -1) % 360) * -1 - : curr.startAngle % 360; - final double angle1 = - curr.endAngle < 0 - ? ((curr.endAngle * -1) % 360) * -1 - : curr.endAngle % 360; - double sweepAngel = 0; - if (angle > 0 && angle1 < 0) { - sweepAngel = (180 - angle) + (180 - (angle1 < 0 ? -angle1 : angle1)); - } else if (angle < 0 && angle1 > 0) { - sweepAngel = -angle + angle1; - } else if (angle > 0 && angle1 > 0) { - double difference = 0; - if (angle > angle1) { - difference = angle - angle1; - sweepAngel = 360 - difference; - } else { - sweepAngel = angle1 - angle; - } - } else if (angle < 0 && angle1 < 0) { - double difference = 0; - if (angle > angle1) { - difference = angle - angle1; - sweepAngel = 360 - difference; - } else { - sweepAngel = -(angle + (-angle1)); - } - } - if (sweepAngel < 0) { - sweepAngel = -sweepAngel; - } - curr.endAngle = sweepAngel; - path.addArc( - Rect.fromLTWH( - curr.point.dx - radius, - curr.point.dy - radius, - 2 * radius, - 2 * radius, - ), - angle, - sweepAngel, - ); - } - path.closeFigure(); - PdfPath pdfPath = PdfPath(); - if (isAppearance) { - for (int i = 0; i < PdfPathHelper.getHelper(path).points.length; i++) { - PdfPathHelper.getHelper(pdfPath).points.add( - Offset( - PdfPathHelper.getHelper(path).points[i].dx, - -PdfPathHelper.getHelper(path).points[i].dy, - ), - ); - } - } else { - PdfPathHelper.getHelper( - pdfPath, - ).points.addAll(PdfPathHelper.getHelper(path).points); - } - PdfPathHelper.getHelper( - pdfPath, - ).pathTypes.addAll(PdfPathHelper.getHelper(path).pathTypes); - if (brush != null) { - graphics.drawPath(pdfPath, brush: brush); - } - const double incise = 180 / (pi * 3); - path = PdfPath(); - for (int i = 0; i < circles.length; i++) { - final _CloudStyleArc curr = circles[i]; - path.addArc( - Rect.fromLTWH( - curr.point.dx - radius, - curr.point.dy - radius, - 2 * radius, - 2 * radius, - ), - curr.startAngle, - curr.endAngle + incise, - ); - } - path.closeFigure(); - pdfPath = PdfPath(); - if (isAppearance) { - for (int i = 0; i < PdfPathHelper.getHelper(path).points.length; i++) { - PdfPathHelper.getHelper(pdfPath).points.add( - Offset( - PdfPathHelper.getHelper(path).points[i].dx, - -PdfPathHelper.getHelper(path).points[i].dy, - ), - ); - } - } else { - PdfPathHelper.getHelper( - pdfPath, - ).points.addAll(PdfPathHelper.getHelper(path).points); - } - PdfPathHelper.getHelper( - pdfPath, - ).pathTypes.addAll(PdfPathHelper.getHelper(path).pathTypes); - graphics.drawPath(pdfPath, pen: pen); - } - - bool _isClockWise(List points) { - double sum = 0.0; - for (int i = 0; i < points.length; i++) { - final Offset v1 = points[i]; - final Offset v2 = points[(i + 1) % points.length]; - sum += (v2.dx - v1.dx) * (v2.dy + v1.dy); - } - return sum > 0.0; - } - - Offset _getIntersectionDegrees(Offset point1, Offset point2, double radius) { - final double dx = point2.dx - point1.dx; - final double dy = point2.dy - point1.dy; - final double len = sqrt(dx * dx + dy * dy); - double a = 0.5 * len / radius; - if (a < -1) { - a = -1; - } - if (a > 1) { - a = 1; - } - final double radian = atan2(dy, dx); - final double cosvalue = acos(a); - return Offset( - (radian - cosvalue) * (180 / pi), - (pi + radian + cosvalue) * (180 / pi), - ); - } - - // Searches the in parents. - static IPdfPrimitive? _searchInParents( - PdfDictionary dictionary, - PdfCrossTable? crossTable, - String value, - ) { - IPdfPrimitive? primitive; - PdfDictionary? dic = dictionary; - while ((primitive == null) && (dic != null)) { - if (dic.containsKey(value)) { - primitive = crossTable!.getObject(dic[value]); - } else { - if (dic.containsKey(PdfDictionaryProperties.parent)) { - dic = - crossTable!.getObject(dic[PdfDictionaryProperties.parent]) - as PdfDictionary?; - } else { - dic = null; - } - } - } - return primitive; - } - - /// internal method - static IPdfPrimitive? getValue( - PdfDictionary dictionary, - PdfCrossTable? crossTable, - String value, - bool inheritable, - ) { - IPdfPrimitive? primitive; - if (dictionary.containsKey(value)) { - primitive = crossTable!.getObject(dictionary[value]); - } else { - if (inheritable) { - primitive = _searchInParents(dictionary, crossTable, value); - } - } - return primitive; - } - - /// internal method - static void save(PdfAnnotation annotation) { - bool isSaveComplete = false; - if (annotation is PdfActionAnnotation) { - PdfActionAnnotationHelper.getHelper(annotation).save(); - } else if (annotation is PdfDocumentLinkAnnotation) { - PdfDocumentLinkAnnotationHelper.getHelper(annotation).save(); - } else if (annotation is PdfEllipseAnnotation) { - PdfEllipseAnnotationHelper.getHelper(annotation).save(); - isSaveComplete = true; - } else if (annotation is PdfLineAnnotation) { - PdfLineAnnotationHelper.getHelper(annotation).save(); - isSaveComplete = true; - } else if (annotation is PdfPolygonAnnotation) { - PdfPolygonAnnotationHelper.getHelper(annotation).save(); - isSaveComplete = true; - } else if (annotation is PdfRectangleAnnotation) { - PdfRectangleAnnotationHelper.getHelper(annotation).save(); - isSaveComplete = true; - } else if (annotation is WidgetAnnotation) { - WidgetAnnotationHelper.getHelper(annotation).save(); - isSaveComplete = true; - } else if (annotation is PdfTextMarkupAnnotation) { - PdfTextMarkupAnnotationHelper.getHelper(annotation).save(); - isSaveComplete = true; - } else if (annotation is PdfPopupAnnotation) { - PdfPopupAnnotationHelper.getHelper(annotation).save(); - isSaveComplete = true; - } - if (!PdfAnnotationHelper.getHelper(annotation).flatten) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - if (helper.flag != null) { - int flagValue = 0; - for (int i = 0; i < helper.flag!.length; i++) { - flagValue |= getAnnotationFlagsValue(helper.flag![i]); - } - helper.dictionary!.setNumber(PdfDictionaryProperties.f, flagValue); - } - } - if (!isSaveComplete) { - PdfAnnotationHelper.getHelper(annotation).saveAnnotation(); - } - } - - /// Internal method. - int? getFlagValue() { - if (dictionary!.containsKey(PdfDictionaryProperties.f)) { - final IPdfPrimitive? annotFlags = getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.f, - false, - ); - if (annotFlags != null && - annotFlags is PdfNumber && - annotFlags.value != null) { - return annotFlags.value!.toInt(); - } - } - return null; - } - - /// Internal method. - static List obtainAnnotationFlags(int? flagValue) { - final List flags = []; - if (flagValue != null) { - for (final PdfAnnotationFlags flag in PdfAnnotationFlags.values) { - if (flagValue == 0) { - return flags..add(flag); - } - if (getAnnotationFlagsValue(flag) & flagValue != 0) { - flags.add(flag); - } - } - } - return flags; - } - - /// internal method - static int getAnnotationFlagsValue(PdfAnnotationFlags value) { - switch (value) { - case PdfAnnotationFlags.defaultFlag: - return 0; - case PdfAnnotationFlags.invisible: - return 1; - case PdfAnnotationFlags.hidden: - return 2; - case PdfAnnotationFlags.print: - return 4; - case PdfAnnotationFlags.noZoom: - return 8; - case PdfAnnotationFlags.noRotate: - return 16; - case PdfAnnotationFlags.noView: - return 32; - case PdfAnnotationFlags.readOnly: - return 64; - case PdfAnnotationFlags.locked: - return 128; - case PdfAnnotationFlags.toggleNoView: - return 256; - } - } -} - -class _CloudStyleArc { - late Offset point; - double endAngle = 0; - double startAngle = 0; -} +import 'dart:math'; +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../graphics/brushes/pdf_brush.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_path.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/fonts/pdf_string_format.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_margins.dart'; +import '../graphics/pdf_pen.dart'; +import '../graphics/pdf_pens.dart'; +import '../graphics/pdf_transformation_matrix.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_section.dart'; +import '../pages/pdf_section_collection.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_catalog.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_action_annotation.dart'; +import 'pdf_annotation_border.dart'; +import 'pdf_appearance.dart'; +import 'pdf_document_link_annotation.dart'; +import 'pdf_ellipse_annotation.dart'; +import 'pdf_line_annotation.dart'; +import 'pdf_polygon_annotation.dart'; +import 'pdf_popup_annotation.dart'; +import 'pdf_rectangle_annotation.dart'; +import 'pdf_text_markup_annotation.dart'; +import 'pdf_text_web_link.dart'; +import 'widget_annotation.dart'; + +/// Represents the base class for annotation objects. +abstract class PdfAnnotation implements IPdfWrapper { + // fields + late PdfAnnotationHelper _helper; + + /// Set whether the annotation requires an appearance. + bool get setAppearance => _helper.setAppearance; + set setAppearance(bool value) { + _helper.setAppearance = value; + } + + // properties + /// Gets a page of the annotation. Read-Only. + PdfPage? get page => _helper.page; + + /// Gets annotation's bounds in the PDF page. + Rect get bounds { + return _helper.bounds; + } + + /// Sets annotation's bounds in the PDF page. + set bounds(Rect value) { + _helper.bounds = value; + } + + /// Gets content of the annotation. + /// The string value specifies the text of the annotation. + String get text { + return _helper.text; + } + + /// Sets content of the annotation. + /// The string value specifies the text of the annotation. + set text(String value) { + _helper.text = value; + } + + /// Gets the author of the annotation. + String get author => _helper.author; + + /// Sets the author of the annotation. + set author(String value) { + _helper.author = value; + } + + /// Gets the subject of the annotation. + String get subject => _helper.subject; + + /// Sets the subject of the annotation. + set subject(String value) { + _helper.subject = value; + } + + /// Gets the ModifiedDate of the annotation. + DateTime? get modifiedDate => _helper.modifiedDate; + + /// Sets the ModifiedDate of the annotation. + set modifiedDate(DateTime? value) { + _helper.modifiedDate = value; + } + + /// Gets the opacity of the annotation. + double get opacity => _helper.opacity; + + /// Sets the opacity of the annotation. + /// + /// Opacity value should be between 0 to 1. + set opacity(double value) { + _helper.opacity = value; + } + + /// Gets appearance of the annotation. + PdfAppearance get appearance { + _helper.appearance ??= PdfAppearance(this); + return _helper.appearance!; + } + + /// Sets appearance of the annotation. + set appearance(PdfAppearance value) { + _helper.appearance = value; + } + + /// Gets or sets the annotation flags. + List get annotationFlags => _helper.annotationFlags; + set annotationFlags(List value) { + _helper.annotationFlags = value; + } + + //Public methods + /// Flatten the annotation. + /// + /// The flatten will add at the time of saving the current document. + void flatten() { + _helper.flatten = true; + } +} + +/// [PdfAnnotation] helper +class PdfAnnotationHelper { + /// internal constructor + PdfAnnotationHelper(this.base); + + /// internal field + PdfAnnotation base; + + /// internal method + static PdfAnnotationHelper getHelper(PdfAnnotation base) { + return base._helper; + } + + /// internal method + /// Initialize [PdfAnnotation] object + void initializeAnnotation({ + PdfPage? page, + String? text, + Rect? bounds, + PdfAnnotationBorder? border, + PdfColor? color, + PdfColor? innerColor, + String? author, + double? opacity, + String? subject, + DateTime? modifiedDate, + List? flags, + bool? setAppearance, + }) { + base._helper = this; + initializeAnnotationProperties( + page, + text, + bounds, + border, + color, + innerColor, + author, + opacity, + subject, + modifiedDate, + flags, + setAppearance, + ); + } + + /// internal method + /// Initialize [PdfAnnotation] object + void initializeExistingAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + base._helper = this; + this.dictionary = dictionary; + this.crossTable = crossTable; + isLoadedAnnotation = true; + PdfName? name; + if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + name = + dictionary.items![PdfName(PdfDictionaryProperties.subtype)] + as PdfName?; + } + if (name != null) { + if (name.name == PdfDictionaryProperties.circle || + name.name == PdfDictionaryProperties.square || + name.name == PdfDictionaryProperties.line || + name.name == PdfDictionaryProperties.polygon || + name.name == PdfDictionaryProperties.highlight || + name.name == PdfDictionaryProperties.underline || + name.name == PdfDictionaryProperties.squiggly || + name.name == PdfDictionaryProperties.strikeOut || + name.name == PdfDictionaryProperties.text) { + PdfDocumentHelper.getHelper(crossTable.document!).catalog.beginSave = + dictionaryBeginSave; + PdfDocumentHelper.getHelper(crossTable.document!).catalog.modify(); + } + } + } + + /// internal field + PdfPage? page; + + /// internal field + String? textValue = ''; + + /// internal field + PdfRectangle rectangle = PdfRectangle.empty; + + /// internal field + PdfColor? annotationInnerColor; + + /// internal field + PdfAnnotationBorder? annotationBorder; + + /// internal field + bool isLoadedAnnotation = false; + + /// internal field + PdfColor annotationColor = PdfColor.empty; + + /// internal field + PdfMargins? margins = PdfMargins(); + + /// internal field + String? annotationAuthor = ''; + + /// internal field + String? annotationSubject = ''; + + /// internal field + DateTime? annotationModifiedDate; + + /// internal field + double annotationOpacity = 1.0; + + /// internal field + PdfAppearance? appearance; + + /// internal field + bool saved = false; + + /// internal field + bool isBounds = false; + + /// internal field + PdfCrossTable? cTable; + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal field + bool setAppearance = false; + + /// internal field + bool isOldAnnotation = false; + + /// internal field + List? flag; + + ///Gets or sets the boolean flag to flatten the annotation, + ///by default, its become false. + bool flatten = false; + + /// Gets or sets flatten annotations popup. + // ignore: prefer_final_fields + bool flattenPopups = false; + + /// internal property + PdfCrossTable get crossTable => cTable!; + set crossTable(PdfCrossTable value) { + if (value != cTable) { + cTable = value; + } + } + + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// Gets annotation's bounds in the PDF page. + Rect get bounds { + if (!isLoadedAnnotation) { + return rectangle.rect; + } else { + final PdfRectangle rect = _getBounds(dictionary!, crossTable); + rect.y = + page != null + ? rect.y == 0 && rect.height == 0 + ? rect.y + rect.height + : page!.size.height - (rect.y + rect.height) + : rect.y - rect.height; + return rect.rect; + } + } + + /// Sets annotation's bounds in the PDF page. + set bounds(Rect value) { + if (!isLoadedAnnotation) { + final PdfRectangle rect = PdfRectangle.fromRect(value); + if (rectangle != rect) { + rectangle = rect; + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.rect), + PdfArray.fromRectangle(rect), + ); + } + } else { + isBounds = true; + if (value == Rect.zero) { + throw ArgumentError('rectangle'); + } + final double height = page!.size.height; + final List values = [ + PdfNumber(value.left), + PdfNumber(height - (value.top + value.height)), + PdfNumber(value.left + value.width), + PdfNumber(height - value.top), + ]; + final PdfDictionary dic = dictionary!; + dic.setArray(PdfDictionaryProperties.rect, values); + } + } + + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + if (!isLoadedAnnotation) { + annotationBorder ??= PdfAnnotationBorder(); + } else { + annotationBorder ??= _obtainBorder(); + if (!isLineBorder()) { + dictionary!.setProperty( + PdfDictionaryProperties.border, + annotationBorder, + ); + } + } + PdfAnnotationBorderHelper.getHelper(annotationBorder!).isLineBorder = + isLineBorder(); + return annotationBorder!; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + annotationBorder = value; + if (isLineBorder()) { + dictionary!.setProperty(PdfName(PdfDictionaryProperties.bs), border); + } else { + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.border), + annotationBorder, + ); + } + } + + /// Gets content of the annotation. + /// The string value specifies the text of the annotation. + String get text { + if (!isLoadedAnnotation) { + if (dictionary!.containsKey(PdfDictionaryProperties.contents)) { + textValue = + (dictionary![PdfDictionaryProperties.contents]! as PdfString).value; + } + return textValue!; + } else { + return textValue == null || textValue!.isEmpty + ? _obtainText()! + : textValue!; + } + } + + /// Sets content of the annotation. + /// The string value specifies the text of the annotation. + set text(String value) { + if (textValue != value) { + textValue = value; + dictionary!.setString(PdfDictionaryProperties.contents, textValue); + } + } + + /// Gets the annotation color. + PdfColor get color => isLoadedAnnotation ? _obtainColor() : annotationColor; + + /// Sets the annotation color. + set color(PdfColor value) { + if (annotationColor != value) { + annotationColor = value; + PdfColorSpace? cs = PdfColorSpace.rgb; + if (page != null && !PdfPageHelper.getHelper(page!).isLoadedPage) { + cs = + PdfSectionCollectionHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page!).section!, + ).parent!, + ).document!.colorSpace; + } + final PdfArray colours = PdfColorHelper.toArray(annotationColor, cs); + dictionary!.setProperty(PdfDictionaryProperties.c, colours); + } + } + + /// Gets the inner color of the annotation. + PdfColor get innerColor { + if (!isLoadedAnnotation) { + annotationInnerColor ??= PdfColor(0, 0, 0, 0); + } else { + annotationInnerColor = _obtainInnerColor(); + } + return annotationInnerColor!; + } + + /// Sets the inner color of the annotation. + set innerColor(PdfColor value) { + annotationInnerColor = value; + if (isLoadedAnnotation) { + if (PdfColorHelper.getHelper(annotationInnerColor!).alpha != 0) { + dictionary!.setProperty( + PdfDictionaryProperties.iC, + PdfColorHelper.toArray(annotationInnerColor!), + ); + } else if (dictionary!.containsKey(PdfDictionaryProperties.iC)) { + dictionary!.remove(PdfDictionaryProperties.iC); + } + } + } + + /// Gets the author of the annotation. + String get author { + if (!isLoadedAnnotation) { + if (dictionary!.containsKey(PdfDictionaryProperties.author)) { + annotationAuthor = + (dictionary![PdfDictionaryProperties.author]! as PdfString).value; + } else if (dictionary!.containsKey(PdfDictionaryProperties.t)) { + annotationAuthor = + (dictionary![PdfDictionaryProperties.t]! as PdfString).value; + } + } else { + annotationAuthor = _obtainAuthor(); + } + return annotationAuthor!; + } + + /// Sets the author of the annotation. + set author(String value) { + if (annotationAuthor != value) { + annotationAuthor = value; + dictionary!.setString(PdfDictionaryProperties.t, annotationAuthor); + } + } + + /// Gets the subject of the annotation. + String get subject { + if (isLoadedAnnotation) { + annotationSubject = _obtainSubject(); + } else { + if (dictionary!.containsKey(PdfDictionaryProperties.subject)) { + annotationSubject = + (dictionary![PdfDictionaryProperties.subject]! as PdfString).value; + } else if (dictionary!.containsKey(PdfDictionaryProperties.subj)) { + annotationSubject = + (dictionary![PdfDictionaryProperties.subj]! as PdfString).value; + } + } + return annotationSubject!; + } + + /// Sets the subject of the annotation. + set subject(String value) { + if (subject != value) { + annotationSubject = value; + dictionary!.setString(PdfDictionaryProperties.subj, annotationSubject); + } + } + + /// Gets the ModifiedDate of the annotation. + DateTime? get modifiedDate => + isLoadedAnnotation ? _obtainModifiedDate() : annotationModifiedDate; + + /// Sets the ModifiedDate of the annotation. + set modifiedDate(DateTime? value) { + if (annotationModifiedDate != value) { + annotationModifiedDate = value; + dictionary!.setDateTime( + PdfDictionaryProperties.m, + annotationModifiedDate!, + ); + } + } + + /// Gets the opacity of the annotation. + double get opacity { + if (isLoadedAnnotation) { + return _obtainOpacity()!; + } + if (dictionary!.items!.containsKey(PdfName('CA'))) { + final PdfNumber ca = dictionary!.items![PdfName('CA')]! as PdfNumber; + annotationOpacity = ca.value!.toDouble(); + } + return annotationOpacity; + } + + /// Sets the opacity of the annotation. + /// + /// Opacity value should be between 0 to 1. + set opacity(double value) { + if (value < 0 || value > 1) { + throw ArgumentError.value('Valid value should be between 0 to 1.'); + } + if (annotationOpacity != value) { + annotationOpacity = value; + dictionary!.setProperty( + PdfDictionaryProperties.ca, + PdfNumber(annotationOpacity), + ); + } + } + + /// Sets the annotation flags. + set annotationFlags(List value) { + flag = value; + } + + /// Gets the annotation flags. + List get annotationFlags { + if (isLoadedAnnotation && flag == null) { + flag ??= obtainAnnotationFlags(getFlagValue()); + } + return flag ??= []; + } + + /// internal method + bool isLineBorder() { + if (base is PdfRectangleAnnotation || + base is PdfPolygonAnnotation || + base is PdfEllipseAnnotation || + base is PdfLineAnnotation) { + return true; + } else { + return false; + } + } + + /// internal method + void initializeAnnotationProperties( + PdfPage? page, + String? annotText, + Rect? bounds, + PdfAnnotationBorder? border, + PdfColor? color, + PdfColor? innerColor, + String? author, + double? opacity, + String? subject, + DateTime? modifiedDate, + List? flags, + bool? setAppearance, + ) { + dictionary!.beginSave = dictionaryBeginSave; + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.type), + PdfName(PdfDictionaryProperties.annot), + ); + if (page != null) { + this.page = page; + } + if (bounds != null) { + this.bounds = bounds; + } + if (annotText != null) { + text = annotText; + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.contents), + PdfString(text), + ); + } + if (border != null) { + this.border = border; + } + if (color != null) { + this.color = color; + } + if (innerColor != null) { + this.innerColor = innerColor; + } + if (author != null) { + this.author = author; + } + if (opacity != null) { + this.opacity = opacity; + } + if (subject != null) { + this.subject = subject; + } + if (modifiedDate != null) { + this.modifiedDate = modifiedDate; + } + if (setAppearance != null) { + this.setAppearance = setAppearance; + } + if (flags != null) { + annotationFlags = flags; + } + } + + /// internal method + void dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (_isContainsAnnotation()) { + if (!saved) { + PdfAnnotationHelper.save(base); + saved = true; + } + } + } + + bool _isContainsAnnotation() { + bool contains = false; + PdfArray? annotation; + if (page != null && + PdfPageHelper.getHelper( + page!, + ).dictionary!.containsKey(PdfDictionaryProperties.annots)) { + annotation = + PdfCrossTable.dereference( + PdfPageHelper.getHelper( + page!, + ).dictionary![PdfDictionaryProperties.annots], + ) + as PdfArray?; + if (annotation != null && + annotation.elements.isNotEmpty && + annotation.contains(annotation.elements[0]!)) { + contains = true; + } + } + return contains; + } + + /// internal method + void saveAnnotation() { + final PdfDocument? document = PdfPageHelper.getHelper(page!).document; + if (document != null && + PdfDocumentHelper.getHelper(document).conformanceLevel != + PdfConformanceLevel.none) { + if (base is PdfActionAnnotation && + PdfDocumentHelper.getHelper(document).conformanceLevel == + PdfConformanceLevel.a1b) { + throw ArgumentError( + 'The specified annotation type is not supported by PDF/A1-B or PDF/A1-A standard documents.', + ); + } + //This is needed to attain specific PDF/A conformance. + if (base is! PdfLinkAnnotation && + !setAppearance && + (PdfDocumentHelper.getHelper(document).conformanceLevel == + PdfConformanceLevel.a2b || + PdfDocumentHelper.getHelper(document).conformanceLevel == + PdfConformanceLevel.a3b)) { + throw ArgumentError( + "The appearance dictionary doesn't contain an entry. Enable setAppearance in PdfAnnotation class to overcome this error.", + ); + } + dictionary!.setNumber(PdfDictionaryProperties.f, 4); + } + if (annotationBorder != null) { + if (isLineBorder()) { + dictionary!.setProperty(PdfDictionaryProperties.bs, border); + } else { + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.border), + border, + ); + } + } + if ((base is! PdfLinkAnnotation && base is! PdfTextWebLink) || + ((base is PdfLinkAnnotation || base is PdfTextWebLink) && + !isLoadedAnnotation)) { + final PdfRectangle nativeRectangle = _obtainNativeRectangle(); + if (annotationInnerColor != null && + !annotationInnerColor!.isEmpty && + PdfColorHelper.getHelper(annotationInnerColor!).alpha != 0.0) { + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.ic), + PdfColorHelper.toArray(annotationInnerColor!), + ); + } + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.rect), + PdfArray.fromRectangle(nativeRectangle), + ); + } + } + + PdfRectangle _obtainNativeRectangle() { + final PdfRectangle nativeRectangle = PdfRectangle( + bounds.left, + bounds.bottom, + bounds.width, + bounds.height, + ); + Size? size; + PdfArray? cropOrMediaBox; + if (page != null) { + if (!PdfPageHelper.getHelper(page!).isLoadedPage) { + final PdfSection section = PdfPageHelper.getHelper(page!).section!; + nativeRectangle.location = PdfSectionHelper.getHelper( + section, + ).pointToNativePdf(page!, nativeRectangle.location); + } else { + size = page!.size; + nativeRectangle.y = size.height - rectangle.bottom; + } + cropOrMediaBox = _getCropOrMediaBox(page!, cropOrMediaBox); + } + if (cropOrMediaBox != null) { + if (cropOrMediaBox.count > 2) { + if ((cropOrMediaBox[0]! as PdfNumber).value != 0 || + (cropOrMediaBox[1]! as PdfNumber).value != 0) { + nativeRectangle.x = + nativeRectangle.x + + (cropOrMediaBox[0]! as PdfNumber).value!.toDouble(); + nativeRectangle.y = + nativeRectangle.y + + (cropOrMediaBox[1]! as PdfNumber).value!.toDouble(); + } + } + } + return nativeRectangle; + } + + PdfArray? _getCropOrMediaBox(PdfPage page, PdfArray? cropOrMediaBox) { + final PdfDictionary dictionary = PdfPageHelper.getHelper(page).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.cropBox)) { + cropOrMediaBox = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.cropBox]) + as PdfArray?; + } else if (dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { + cropOrMediaBox = + PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.mediaBox], + ) + as PdfArray?; + } + return cropOrMediaBox; + } + + /// internal method + void setPage(PdfPage pdfPage) { + page = pdfPage; + final PdfDocument? document = PdfPageHelper.getHelper(page!).document; + if (!PdfPageHelper.getHelper(pdfPage).isLoadedPage) { + if (document != null) { + final PdfCatalog catalog = + PdfDocumentHelper.getHelper(document).catalog; + catalog.beginSaveList ??= []; + final PdfGraphics graphics = + pdfPage.graphics; //Accessed for creating page content. + ArgumentError.checkNotNull(graphics); + if (dictionary!.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName? name = + dictionary!.items![PdfName(PdfDictionaryProperties.subtype)] + as PdfName?; + if (name != null) { + if (name.name == PdfDictionaryProperties.text || + name.name == PdfDictionaryProperties.square || + name.name == PdfDictionaryProperties.highlight || + name.name == PdfDictionaryProperties.squiggly || + name.name == PdfDictionaryProperties.underline || + name.name == PdfDictionaryProperties.strikeOut || + flatten) { + catalog.beginSaveList!.add(dictionaryBeginSave); + catalog.modify(); + } + } + } else if (flatten) { + catalog.beginSaveList!.add(dictionaryBeginSave); + catalog.modify(); + } + } + } else { + if (document != null) { + final PdfCatalog catalog = + PdfDocumentHelper.getHelper(document).catalog; + if (dictionary!.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName? name = + dictionary!.items![PdfName(PdfDictionaryProperties.subtype)] + as PdfName?; + catalog.beginSaveList ??= []; + if (name != null) { + if (name.name == PdfDictionaryProperties.circle || + name.name == PdfDictionaryProperties.square || + name.name == PdfDictionaryProperties.line || + name.name == PdfDictionaryProperties.polygon || + name.name == PdfDictionaryProperties.highlight || + name.name == PdfDictionaryProperties.squiggly || + name.name == PdfDictionaryProperties.underline || + name.name == PdfDictionaryProperties.strikeOut || + name.name == PdfDictionaryProperties.text || + name.name == PdfDictionaryProperties.link) { + catalog.beginSaveList!.add(dictionaryBeginSave); + catalog.modify(); + } + } + } else if (flatten) { + catalog.beginSaveList!.add(dictionaryBeginSave); + catalog.modify(); + } + } + } + if (page != null && !PdfPageHelper.getHelper(page!).isLoadedPage) { + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.p), + PdfReferenceHolder(page), + ); + } + } + + /// Gets the bounds. + PdfRectangle _getBounds(PdfDictionary dictionary, PdfCrossTable crossTable) { + PdfArray? array; + if (dictionary.containsKey(PdfDictionaryProperties.rect)) { + array = + crossTable.getObject(dictionary[PdfDictionaryProperties.rect]) + as PdfArray?; + } + return array!.toRectangle(); + } + + // Gets the border. + PdfAnnotationBorder _obtainBorder() { + final PdfAnnotationBorder border = PdfAnnotationBorder(); + if (dictionary!.containsKey(PdfDictionaryProperties.border)) { + final PdfArray? borderArray = + PdfCrossTable.dereference(dictionary![PdfDictionaryProperties.border]) + as PdfArray?; + if (borderArray != null && borderArray.count >= 2) { + if (borderArray[0] is PdfNumber && + borderArray[1] is PdfNumber && + borderArray[2] is PdfNumber) { + final double width = (borderArray[0]! as PdfNumber).value!.toDouble(); + final double hRadius = + (borderArray[1]! as PdfNumber).value!.toDouble(); + final double vRadius = + (borderArray[2]! as PdfNumber).value!.toDouble(); + border.width = vRadius; + border.horizontalRadius = width; + border.verticalRadius = hRadius; + } + } + } else if (dictionary!.containsKey(PdfDictionaryProperties.bs)) { + final PdfDictionary lbDic = + crossTable.getObject(dictionary![PdfDictionaryProperties.bs])! + as PdfDictionary; + if (lbDic.containsKey(PdfDictionaryProperties.w)) { + final PdfNumber? value = lbDic[PdfDictionaryProperties.w] as PdfNumber?; + if (value != null) { + border.width = value.value!.toDouble(); + } + } + if (lbDic.containsKey(PdfDictionaryProperties.s)) { + final PdfName bstr = + PdfCrossTable.dereference(lbDic[PdfDictionaryProperties.s])! + as PdfName; + border.borderStyle = _getBorderStyle(bstr.name.toString()); + } + if (lbDic.containsKey(PdfDictionaryProperties.d)) { + final PdfArray? dasharray = + PdfCrossTable.dereference(lbDic[PdfDictionaryProperties.d]) + as PdfArray?; + if (dasharray != null) { + final PdfNumber dashArray = dasharray[0]! as PdfNumber; + final int dashArrayValue = dashArray.value!.toInt(); + dasharray.clear(); + dasharray.insert(0, PdfNumber(dashArrayValue)); + dasharray.insert(1, PdfNumber(dashArrayValue)); + border.dashArray = dashArrayValue; + } + } + } + return border; + } + + // Gets the text. + String? _obtainText() { + String tempText; + if (dictionary!.containsKey(PdfDictionaryProperties.contents)) { + final PdfString? mText = + PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.contents], + ) + as PdfString?; + if (mText != null) { + textValue = mText.value.toString(); + } + return textValue; + } else { + tempText = ''; + return tempText; + } + } + + // Gets the color. + PdfColor _obtainColor() { + PdfColor color = PdfColor.empty; + PdfArray? colours; + if (dictionary!.containsKey(PdfDictionaryProperties.c)) { + colours = dictionary![PdfDictionaryProperties.c] as PdfArray?; + } + if (colours != null && colours.elements.length == 1) { + //Convert the float color values into bytes + final PdfNumber? color0 = crossTable.getObject(colours[0]) as PdfNumber?; + if (color0 != null) { + color = PdfColorHelper.fromGray(color0.value! as double); + } + } else if (colours != null && colours.elements.length == 3) { + final PdfNumber color0 = colours[0]! as PdfNumber; + final PdfNumber color1 = colours[1]! as PdfNumber; + final PdfNumber color2 = colours[2]! as PdfNumber; + //Convert the float color values into bytes + final int red = (color0.value! * 255).round().toUnsigned(8); + final int green = (color1.value! * 255).round().toUnsigned(8); + final int blue = (color2.value! * 255).round().toUnsigned(8); + color = PdfColor(red, green, blue); + } else if (colours != null && colours.elements.length == 4) { + final PdfNumber? color0 = crossTable.getObject(colours[0]) as PdfNumber?; + final PdfNumber? color1 = crossTable.getObject(colours[1]) as PdfNumber?; + final PdfNumber? color2 = crossTable.getObject(colours[2]) as PdfNumber?; + final PdfNumber? color3 = crossTable.getObject(colours[3]) as PdfNumber?; + if (color0 != null && + color1 != null && + color2 != null && + color3 != null) { + //Convert the float color values into bytes + final double cyan = color0.value! as double; + final double magenta = color1.value! as double; + final double yellow = color2.value! as double; + final double black = color3.value! as double; + color = PdfColor.fromCMYK(cyan, magenta, yellow, black); + } + } + return color; + } + + // Gets the Opacity. + double? _obtainOpacity() { + if (dictionary!.containsKey(PdfDictionaryProperties.ca)) { + annotationOpacity = _getNumber(PdfDictionaryProperties.ca)!; + } + return annotationOpacity; + } + + // Gets the number value. + double? _getNumber(String keyName) { + double? result = 0; + final PdfNumber? numb = dictionary![keyName] as PdfNumber?; + if (numb != null) { + result = numb.value as double?; + } + return result; + } + + // Gets the Author. + String _obtainAuthor() { + String author = ''; + if (dictionary!.containsKey(PdfDictionaryProperties.author)) { + final IPdfPrimitive? tempAuthor = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.author], + ); + if (tempAuthor != null && + tempAuthor is PdfString && + tempAuthor.value != null) { + author = tempAuthor.value!; + } + } else if (dictionary!.containsKey(PdfDictionaryProperties.t)) { + final IPdfPrimitive? tempAuthor = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.t], + ); + if (tempAuthor != null && + tempAuthor is PdfString && + tempAuthor.value != null) { + author = tempAuthor.value!; + } + } + return author; + } + + // Gets the Subject. + String _obtainSubject() { + String subject = ''; + if (dictionary!.containsKey(PdfDictionaryProperties.subject)) { + final IPdfPrimitive? tempSubject = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.subject], + ); + if (tempSubject != null && + tempSubject is PdfString && + tempSubject.value != null) { + subject = tempSubject.value!; + } + } else if (dictionary!.containsKey(PdfDictionaryProperties.subj)) { + final IPdfPrimitive? tempSubject = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.subj], + ); + if (tempSubject != null && + tempSubject is PdfString && + tempSubject.value != null) { + subject = tempSubject.value!; + } + } + return subject; + } + + // Gets the ModifiedDate. + DateTime? _obtainModifiedDate() { + if (dictionary!.containsKey(PdfDictionaryProperties.modificationDate) || + dictionary!.containsKey(PdfDictionaryProperties.m)) { + PdfString? modifiedDate = + dictionary![PdfDictionaryProperties.modificationDate] as PdfString?; + modifiedDate ??= dictionary![PdfDictionaryProperties.m] as PdfString?; + annotationModifiedDate = dictionary!.getDateTime(modifiedDate!); + } + return annotationModifiedDate; + } + + /// internal method + String getEnumName(dynamic annotText) { + final int index = annotText.toString().indexOf('.'); + final String name = annotText.toString().substring(index + 1); + return name[0].toUpperCase() + name.substring(1); + } + + //Get the inner line color + PdfColor _obtainInnerColor() { + PdfColor color = PdfColor.empty; + PdfArray? colours; + if (dictionary!.containsKey(PdfDictionaryProperties.iC)) { + colours = + PdfCrossTable.dereference(dictionary![PdfDictionaryProperties.iC]) + as PdfArray?; + if (colours != null && colours.count > 0) { + final int red = ((colours[0]! as PdfNumber).value! * 255) + .round() + .toUnsigned(8); + final int green = ((colours[1]! as PdfNumber).value! * 255) + .round() + .toUnsigned(8); + final int blue = ((colours[2]! as PdfNumber).value! * 255) + .round() + .toUnsigned(8); + color = PdfColor(red, green, blue); + } + } + return color; + } + + /// internal method + PdfMargins? obtainMargin() { + if (page != null && PdfPageHelper.getHelper(page!).section != null) { + margins = PdfPageHelper.getHelper(page!).section!.pageSettings.margins; + } + return margins; + } + + /// internal method + void flattenPopup() { + if (page != null && !isLoadedAnnotation) { + _flattenAnnotationPopups( + page!, + color, + bounds, + border, + author, + subject, + text, + ); + } + } + + void _flattenAnnotationPopups( + PdfPage page, + PdfColor color, + Rect annotBounds, + PdfAnnotationBorder border, + String author, + String subject, + String text, + ) { + final Size clientSize = + PdfPageHelper.getHelper(page).isLoadedPage + ? page.size + : page.getClientSize(); + final double x = clientSize.width - 180; + final double y = + (annotBounds.top + 142) < clientSize.height + ? annotBounds.top + : clientSize.height - 142; + Rect bounds = Rect.fromLTWH(x, y, 180, 142); + // Draw annotation based on bounds + if (dictionary![PdfDictionaryProperties.popup] != null) { + final IPdfPrimitive? obj = dictionary![PdfDictionaryProperties.popup]; + final PdfDictionary? tempDictionary = + PdfCrossTable.dereference(obj) as PdfDictionary?; + if (tempDictionary != null) { + final PdfArray? rectValue = + PdfCrossTable.dereference( + tempDictionary[PdfDictionaryProperties.rect], + ) + as PdfArray?; + final PdfCrossTable? crosstable = + PdfPageHelper.getHelper(page).crossTable; + if (rectValue != null) { + final PdfNumber left = + crosstable!.getReference(rectValue[0]) as PdfNumber; + final PdfNumber top = + crosstable.getReference(rectValue[1]) as PdfNumber; + final PdfNumber width = + crosstable.getReference(rectValue[2]) as PdfNumber; + final PdfNumber height = + crosstable.getReference(rectValue[3]) as PdfNumber; + bounds = Rect.fromLTWH( + left.value! as double, + top.value! as double, + width.value! - (left.value! as double), + height.value! - (top.value! as double), + ); + } + } + } + final PdfBrush backBrush = PdfSolidBrush(color); + final double borderWidth = border.width / 2; + double? trackingHeight = 0; + final PdfBrush aBrush = PdfSolidBrush(_getForeColor(color)); + if (author != '') { + final Map returnedValue = _drawAuthor( + author, + subject, + bounds, + backBrush, + aBrush, + page, + trackingHeight, + border, + ); + trackingHeight = returnedValue['height']; + } else if (subject != '') { + final Rect titleRect = Rect.fromLTWH( + bounds.left + borderWidth, + bounds.top + borderWidth, + bounds.width - border.width, + 40, + ); + _saveGraphics(page, PdfBlendMode.hardLight); + page.graphics.drawRectangle( + pen: PdfPens.black, + brush: backBrush, + bounds: titleRect, + ); + page.graphics.restore(); + Rect contentRect = Rect.fromLTWH( + titleRect.left + 11, + titleRect.top, + titleRect.width, + titleRect.height / 2, + ); + contentRect = Rect.fromLTWH( + contentRect.left, + contentRect.top + contentRect.height - 2, + contentRect.width, + titleRect.height / 2, + ); + _saveGraphics(page, PdfBlendMode.normal); + _drawSubject(subject, contentRect, page); + page.graphics.restore(); + trackingHeight = 40; + } else { + _saveGraphics(page, PdfBlendMode.hardLight); + final Rect titleRect = Rect.fromLTWH( + bounds.left + borderWidth, + bounds.top + borderWidth, + bounds.width - border.width, + 20, + ); + page.graphics.drawRectangle( + pen: PdfPens.black, + brush: backBrush, + bounds: titleRect, + ); + trackingHeight = 20; + page.graphics.restore(); + } + Rect cRect = Rect.fromLTWH( + bounds.left + borderWidth, + bounds.top + borderWidth + trackingHeight!, + bounds.width - border.width, + bounds.height - (trackingHeight + border.width), + ); + _saveGraphics(page, PdfBlendMode.hardLight); + page.graphics.drawRectangle( + pen: PdfPens.black, + brush: PdfBrushes.white, + bounds: cRect, + ); + cRect = Rect.fromLTWH( + cRect.left + 11, + cRect.top + 5, + cRect.width - 22, + cRect.height, + ); + page.graphics.restore(); + _saveGraphics(page, PdfBlendMode.normal); + page.graphics.drawString( + text, + PdfStandardFont(PdfFontFamily.helvetica, 10.5), + brush: PdfBrushes.black, + bounds: cRect, + ); + page.graphics.restore(); + } + + void _drawSubject(String subject, Rect bounds, PdfPage page) { + page.graphics.drawString( + subject, + PdfStandardFont(PdfFontFamily.helvetica, 10.5, style: PdfFontStyle.bold), + brush: PdfBrushes.black, + bounds: bounds, + format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), + ); + } + + void _saveGraphics(PdfPage page, PdfBlendMode mode) { + page.graphics.save(); + PdfGraphicsHelper.getHelper( + page.graphics, + ).applyTransparency(0.8, 8.0, mode); + } + + PdfColor _getForeColor(PdfColor c) { + return (((c.r + c.b + c.g) / 3) > 128) + ? PdfColor(0, 0, 0) + : PdfColor(255, 255, 255); + } + + Map _drawAuthor( + String author, + String subject, + Rect bounds, + PdfBrush backBrush, + PdfBrush aBrush, + PdfPage page, + double? trackingHeight, + PdfAnnotationBorder border, + ) { + final double borderWidth = border.width / 2; + final PdfRectangle titleRect = PdfRectangle.fromRect( + Rect.fromLTWH( + bounds.left + borderWidth, + bounds.top + borderWidth, + bounds.width - border.width, + 20, + ), + ); + if (subject != '') { + titleRect.height += 20; + trackingHeight = titleRect.height; + _saveGraphics(page, PdfBlendMode.hardLight); + page.graphics.drawRectangle( + pen: PdfPens.black, + brush: backBrush, + bounds: titleRect.rect, + ); + page.graphics.restore(); + Rect contentRect = Rect.fromLTWH( + titleRect.x + 11, + titleRect.y, + titleRect.width, + titleRect.height / 2, + ); + _saveGraphics(page, PdfBlendMode.normal); + page.graphics.drawString( + author, + PdfStandardFont( + PdfFontFamily.helvetica, + 10.5, + style: PdfFontStyle.bold, + ), + brush: aBrush, + bounds: contentRect, + format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), + ); + contentRect = Rect.fromLTWH( + contentRect.left, + contentRect.top + contentRect.height - 2, + contentRect.width, + titleRect.height / 2, + ); + _drawSubject(subject, contentRect, page); + page.graphics.restore(); + } else { + _saveGraphics(page, PdfBlendMode.hardLight); + page.graphics.drawRectangle( + pen: PdfPens.black, + brush: backBrush, + bounds: titleRect.rect, + ); + page.graphics.restore(); + final Rect contentRect = Rect.fromLTWH( + titleRect.x + 11, + titleRect.y, + titleRect.width, + titleRect.height, + ); + _saveGraphics(page, PdfBlendMode.normal); + page.graphics.drawString( + author, + PdfStandardFont(PdfFontFamily.helvetica, 10.5), + brush: aBrush, + bounds: contentRect, + format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle), + ); + trackingHeight = titleRect.height; + page.graphics.restore(); + } + return {'height': trackingHeight}; + } + + /// internal method + Rect calculateTemplateBounds( + Rect bounds, + PdfPage? page, + PdfTemplate? template, + bool isNormalMatrix, + ) { + double x = bounds.left, + y = bounds.top, + width = bounds.width, + height = bounds.height; + if (page != null) { + final int graphicsRotation = _obtainGraphicsRotation( + PdfGraphicsHelper.getHelper(page.graphics).matrix, + ); + if (graphicsRotation == 0 && !isNormalMatrix) { + x = bounds.left; + y = bounds.top + bounds.height - bounds.width; + width = bounds.height; + height = bounds.width; + } + } + return Rect.fromLTWH(x, y, width, height); + } + + int _obtainGraphicsRotation(PdfTransformationMatrix matrix) { + int angle = 0; + final double radians = atan2( + matrix.matrix.elements[2], + matrix.matrix.elements[0], + ); + angle = (radians * 180 / pi).round(); + switch (angle) { + case -90: + angle = 90; + break; + case -180: + angle = 180; + break; + case 90: + angle = 270; + break; + } + return angle; + } + + /// internal method + static void setMatrixToZeroRotation(PdfDictionary template) { + final PdfArray? bbox = template[PdfDictionaryProperties.bBox] as PdfArray?; + if (bbox != null) { + final List elements = [ + 1, + 0, + 0, + 1, + -(bbox[0]! as PdfNumber).value! as double, + -(bbox[1]! as PdfNumber).value! as double, + ]; + template[PdfDictionaryProperties.matrix] = PdfArray(elements); + } + } + + PdfBorderStyle _getBorderStyle(String bstyle) { + PdfBorderStyle style = PdfBorderStyle.solid; + switch (bstyle) { + case 'S': + style = PdfBorderStyle.solid; + break; + case 'D': + style = PdfBorderStyle.dashed; + break; + case 'B': + style = PdfBorderStyle.beveled; + break; + case 'I': + style = PdfBorderStyle.inset; + break; + case 'U': + style = PdfBorderStyle.underline; + break; + } + return style; + } + + /// internal method + PdfRectangle calculateLineBounds( + List linePoints, + int leaderLineExt, + int leaderLineValue, + int leaderOffset, + PdfArray lineStyle, + double borderLength, + ) { + PdfRectangle tempBounds = PdfRectangle.fromRect(bounds); + final PdfPath path = PdfPath(); + if (linePoints.length == 4) { + final double x1 = linePoints[0].toDouble(); + final double y1 = linePoints[1].toDouble(); + final double x2 = linePoints[2].toDouble(); + final double y2 = linePoints[3].toDouble(); + double angle = 0; + if (x2 - x1 == 0) { + if (y2 > y1) { + angle = 90; + } else { + angle = 270; + } + } else { + angle = getAngle(x1, y1, x2, y2); + } + int leaderLine = 0; + double lineAngle = 0; + if (leaderLineValue < 0) { + leaderLine = leaderLineValue * -1; + lineAngle = angle + 180; + } else { + leaderLine = leaderLineValue; + lineAngle = angle; + } + final List x1y1 = [x1, y1]; + final List x2y2 = [x2, y2]; + if (leaderOffset != 0) { + final List offsetPoint1 = getAxisValue( + x1y1, + lineAngle + 90, + leaderOffset.toDouble(), + ); + final List offsetPoint2 = getAxisValue( + x2y2, + lineAngle + 90, + leaderOffset.toDouble(), + ); + linePoints[0] = offsetPoint1[0].toInt(); + linePoints[1] = offsetPoint1[1].toInt(); + linePoints[2] = offsetPoint2[0].toInt(); + linePoints[3] = offsetPoint2[1].toInt(); + } + + final List startingPoint = getAxisValue( + x1y1, + lineAngle + 90, + (leaderLine + leaderOffset).toDouble(), + ); + final List endingPoint = getAxisValue( + x2y2, + lineAngle + 90, + (leaderLine + leaderOffset).toDouble(), + ); + + final List beginLineLeader = getAxisValue( + x1y1, + lineAngle + 90, + (leaderLineExt + leaderLine + leaderOffset).toDouble(), + ); + + final List endLineLeader = getAxisValue( + x2y2, + lineAngle + 90, + (leaderLineExt + leaderLine + leaderOffset).toDouble(), + ); + + final List stylePoint = []; + + for (int i = 0; i < lineStyle.count; i++) { + final PdfName lineEndingStyle = lineStyle[i]! as PdfName; + final PdfPoint point = PdfPoint.empty; + switch (getEnumName(lineEndingStyle.name)) { + case 'Square': + case 'Circle': + case 'Diamond': + { + point.x = 3; + point.y = 3; + } + break; + case 'OpenArrow': + case 'ClosedArrow': + { + point.x = 1; + point.y = 5; + } + break; + case 'ROpenArrow': + case 'RClosedArrow': + { + point.x = 9 + (borderLength / 2); + point.y = 5 + (borderLength / 2); + } + break; + case 'Slash': + { + point.x = 5; + point.y = 9; + } + break; + case 'Butt': + { + point.x = 1; + point.y = 3; + } + break; + default: + { + point.x = 0; + point.y = 0; + } + break; + } + stylePoint.add(point); + } + final List widthX = List.filled(2, 0); + final List heightY = List.filled(2, 0); + + if ((lineAngle >= 45 && lineAngle <= 135) || + (lineAngle >= 225 && lineAngle <= 315)) { + widthX[0] = stylePoint[0].y; + heightY[0] = stylePoint[0].x; + widthX[1] = stylePoint[1].y; + heightY[1] = stylePoint[1].x; + } else { + widthX[0] = stylePoint[0].x; + heightY[0] = stylePoint[0].y; + widthX[1] = stylePoint[1].x; + heightY[1] = stylePoint[1].y; + } + + final double height = max(heightY[0], heightY[1]); + if (startingPoint[0] == + [startingPoint[0], endingPoint[0]].reduce(min)) { + startingPoint[0] -= widthX[0] * borderLength; + endingPoint[0] += widthX[1] * borderLength; + startingPoint[0] = [ + startingPoint[0], + linePoints[0].toDouble(), + ].reduce(min); + startingPoint[0] = min(startingPoint[0], beginLineLeader[0]); + endingPoint[0] = max(endingPoint[0], linePoints[2].toDouble()); + endingPoint[0] = max(endingPoint[0], endLineLeader[0]); + } else { + startingPoint[0] += widthX[0] * borderLength; + endingPoint[0] -= widthX[1] * borderLength; + startingPoint[0] = max(startingPoint[0], linePoints[0].toDouble()); + startingPoint[0] = max(startingPoint[0], beginLineLeader[0]); + endingPoint[0] = min(endingPoint[0], linePoints[2].toDouble()); + endingPoint[0] = min(endingPoint[0], endLineLeader[0]); + } + if (startingPoint[1] == min(startingPoint[1], endingPoint[1])) { + startingPoint[1] -= height * borderLength; + endingPoint[1] += height * borderLength; + startingPoint[1] = min(startingPoint[1], linePoints[1].toDouble()); + startingPoint[1] = min(startingPoint[1], beginLineLeader[1]); + endingPoint[1] = max(endingPoint[1], linePoints[3].toDouble()); + endingPoint[1] = max(endingPoint[1], endLineLeader[1]); + } else { + startingPoint[1] += height * borderLength; + endingPoint[1] -= height * borderLength; + startingPoint[1] = max(startingPoint[1], linePoints[1].toDouble()); + startingPoint[1] = max(startingPoint[1], beginLineLeader[1]); + endingPoint[1] = min(endingPoint[1], linePoints[3].toDouble()); + endingPoint[1] = min(endingPoint[1], endLineLeader[1]); + } + path.addLine( + Offset(startingPoint[0], startingPoint[1]), + Offset(endingPoint[0], endingPoint[1]), + ); + tempBounds = PdfPathHelper.getHelper(path).getBoundsInternal(); + } + return tempBounds; + } + + /// internal method + List getAxisValue(List value, double angle, double length) { + const double degToRad = pi / 180.0; + final List xy = List.filled(2, 0); + xy[0] = value[0] + cos(angle * degToRad) * length; + xy[1] = value[1] + sin(angle * degToRad) * length; + + return xy; + } + + /// internal method + double getAngle(double x1, double y1, double x2, double y2) { + double angle = 0; + final double angleRatio = (y2 - y1) / (x2 - x1); + final double radians = atan(angleRatio); + angle = radians * (180 / pi); + + if ((x2 - x1) < 0 || (y2 - y1) < 0) { + angle += 180; + } + if ((x2 - x1) > 0 && (y2 - y1) < 0) { + angle -= 180; + } + if (angle < 0) { + angle += 360; + } + + return angle; + } + + /// internal method + void setLineEndingStyles( + List startingPoint, + List endingPoint, + PdfGraphics? graphics, + double angle, + PdfPen? borderPen, + PdfBrush? backBrush, + PdfArray lineStyle, + double borderLength, + ) { + List axisPoint; + if (borderLength == 0) { + borderLength = 1; + borderPen = null; + } + if (backBrush is PdfSolidBrush) { + if (backBrush.color.isEmpty) { + backBrush = null; + } + } + for (int i = 0; i < lineStyle.count; i++) { + final PdfName lineEndingStyle = lineStyle[i]! as PdfName; + if (i == 0) { + axisPoint = startingPoint; + } else { + axisPoint = endingPoint; + } + switch (lineEndingStyle.name) { + case 'Square': + { + final Rect rect = Rect.fromLTWH( + axisPoint[0] - (3 * borderLength), + -(axisPoint[1] + (3 * borderLength)), + 6 * borderLength, + 6 * borderLength, + ); + graphics!.drawRectangle( + bounds: rect, + pen: borderPen, + brush: backBrush, + ); + } + break; + case 'Circle': + { + final Rect rect = Rect.fromLTWH( + axisPoint[0] - (3 * borderLength), + -(axisPoint[1] + (3 * borderLength)), + 6 * borderLength, + 6 * borderLength, + ); + graphics!.drawEllipse(rect, pen: borderPen, brush: backBrush); + } + break; + case 'OpenArrow': + { + int arraowAngle = 0; + if (i == 0) { + arraowAngle = 30; + } else { + arraowAngle = 150; + } + final double length = 9 * borderLength; + List startPoint; + if (i == 0) { + startPoint = getAxisValue(axisPoint, angle, borderLength); + } else { + startPoint = getAxisValue(axisPoint, angle, -borderLength); + } + final List point1 = getAxisValue( + startPoint, + angle + arraowAngle, + length, + ); + final List point2 = getAxisValue( + startPoint, + angle - arraowAngle, + length, + ); + + final PdfPath path = PdfPath(pen: borderPen); + path.addLine( + Offset(startPoint[0], -startPoint[1]), + Offset(point1[0], -point1[1]), + ); + path.addLine( + Offset(startPoint[0], -startPoint[1]), + Offset(point2[0], -point2[1]), + ); + graphics!.drawPath(path, pen: borderPen); + } + break; + case 'ClosedArrow': + { + int arraowAngle = 0; + if (i == 0) { + arraowAngle = 30; + } else { + arraowAngle = 150; + } + final double length = 9 * borderLength; + List startPoint; + if (i == 0) { + startPoint = getAxisValue(axisPoint, angle, borderLength); + } else { + startPoint = getAxisValue(axisPoint, angle, -borderLength); + } + final List point1 = getAxisValue( + startPoint, + angle + arraowAngle, + length, + ); + final List point2 = getAxisValue( + startPoint, + angle - arraowAngle, + length, + ); + final List points = [ + Offset(startPoint[0], -startPoint[1]), + Offset(point1[0], -point1[1]), + Offset(point2[0], -point2[1]), + ]; + graphics!.drawPolygon(points, pen: borderPen, brush: backBrush); + } + break; + case 'ROpenArrow': + { + int arraowAngle = 0; + if (i == 0) { + arraowAngle = 150; + } else { + arraowAngle = 30; + } + final double length = 9 * borderLength; + List startPoint; + if (i == 0) { + startPoint = getAxisValue(axisPoint, angle, -borderLength); + } else { + startPoint = getAxisValue(axisPoint, angle, borderLength); + } + final List point1 = getAxisValue( + startPoint, + angle + arraowAngle, + length, + ); + final List point2 = getAxisValue( + startPoint, + angle - arraowAngle, + length, + ); + + final PdfPath path = PdfPath(pen: borderPen); + path.addLine( + Offset(startPoint[0], -startPoint[1]), + Offset(point1[0], -point1[1]), + ); + path.addLine( + Offset(startPoint[0], -startPoint[1]), + Offset(point2[0], -point2[1]), + ); + graphics!.drawPath(path, pen: borderPen); + } + break; + case 'RClosedArrow': + { + int arraowAngle = 0; + if (i == 0) { + arraowAngle = 150; + } else { + arraowAngle = 30; + } + final double length = 9 * borderLength; + List startPoint; + if (i == 0) { + startPoint = getAxisValue(axisPoint, angle, -borderLength); + } else { + startPoint = getAxisValue(axisPoint, angle, borderLength); + } + + final List point1 = getAxisValue( + startPoint, + angle + arraowAngle, + length, + ); + final List point2 = getAxisValue( + startPoint, + angle - arraowAngle, + length, + ); + final List points = [ + Offset(startPoint[0], -startPoint[1]), + Offset(point1[0], -point1[1]), + Offset(point2[0], -point2[1]), + ]; + graphics!.drawPolygon(points, pen: borderPen, brush: backBrush); + } + break; + case 'Slash': + { + final double length = 9 * borderLength; + final List point1 = getAxisValue( + axisPoint, + angle + 60, + length, + ); + final List point2 = getAxisValue( + axisPoint, + angle - 120, + length, + ); + graphics!.drawLine( + borderPen!, + Offset(axisPoint[0], -axisPoint[1]), + Offset(point1[0], -point1[1]), + ); + graphics.drawLine( + borderPen, + Offset(axisPoint[0], -axisPoint[1]), + Offset(point2[0], -point2[1]), + ); + } + break; + case 'Diamond': + { + final double length = 3 * borderLength; + final List point1 = getAxisValue(axisPoint, 180, length); + final List point2 = getAxisValue(axisPoint, 90, length); + final List point3 = getAxisValue(axisPoint, 0, length); + final List point4 = getAxisValue(axisPoint, -90, length); + final List points = [ + Offset(point1[0], -point1[1]), + Offset(point2[0], -point2[1]), + Offset(point3[0], -point3[1]), + Offset(point4[0], -point4[1]), + ]; + graphics!.drawPolygon(points, pen: borderPen, brush: backBrush); + } + break; + case 'Butt': + { + final double length = 3 * borderLength; + final List point1 = getAxisValue( + axisPoint, + angle + 90, + length, + ); + final List point2 = getAxisValue( + axisPoint, + angle - 90, + length, + ); + + graphics!.drawLine( + borderPen!, + Offset(point1[0], -point1[1]), + Offset(point2[0], -point2[1]), + ); + } + break; + } + } + } + + /// Returns the appearance matrix is rotated or not + bool validateTemplateMatrix(PdfDictionary dictionary) { + bool isRotatedMatrix = false; + if (dictionary.containsKey(PdfDictionaryProperties.matrix)) { + final PdfArray? matrix = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.matrix]) + as PdfArray?; + if (matrix != null && matrix.count > 3) { + if ((matrix[0]! as PdfNumber).value == 1 && + (matrix[1]! as PdfNumber).value == 0 && + (matrix[2]! as PdfNumber).value == 0 && + (matrix[3]! as PdfNumber).value == 1) { + isRotatedMatrix = true; + } + } + } else { + isRotatedMatrix = true; + } + return isRotatedMatrix; + } + + /// Returns the boolean if the template matrix is valid or not + bool isValidTemplateMatrix( + PdfDictionary dictionary, + Offset bounds, + PdfTemplate template, + ) { + bool isValidMatrix = true; + Offset point = bounds; + if (dictionary.containsKey(PdfDictionaryProperties.matrix)) { + final IPdfPrimitive? bbox = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.bBox], + ); + final IPdfPrimitive? matrix = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.matrix], + ); + if (matrix != null && + bbox != null && + matrix is PdfArray && + bbox is PdfArray && + matrix.count > 3 && + bbox.count > 2) { + if ((matrix[0]! as PdfNumber).value == 1 && + (matrix[1]! as PdfNumber).value == 0 && + (matrix[2]! as PdfNumber).value == 0 && + (matrix[3]! as PdfNumber).value == 1) { + if ((((bbox[0]! as PdfNumber).value!.toDouble() != + -(matrix[4]! as PdfNumber).value!.toDouble()) && + ((bbox[1]! as PdfNumber).value!.toDouble() != + -(matrix[5]! as PdfNumber).value!.toDouble())) || + ((bbox[0]! as PdfNumber).value!.toDouble() == 0 && + -(matrix[4]! as PdfNumber).value!.toDouble() == 0)) { + final PdfGraphics pageGraphics = page!.graphics; + final PdfGraphicsState state = pageGraphics.save(); + if (opacity < 1) { + pageGraphics.setTransparency(opacity); + } + point = Offset( + point.dx - (bbox[0]! as PdfNumber).value!.toDouble(), + point.dy + (bbox[1]! as PdfNumber).value!.toDouble(), + ); + pageGraphics.drawPdfTemplate(template, point); + pageGraphics.restore(state); + page!.annotations.remove(base); + isValidMatrix = false; + } + } else if ((matrix[0]! as PdfNumber).value == 0 && + (matrix[1]! as PdfNumber).value == -1 && + (matrix[2]! as PdfNumber).value == 1 && + (matrix[3]! as PdfNumber).value == 0) { + if ((bbox[0]! as PdfNumber).value! > 0) { + isValidMatrix = false; + } + } else { + if ((bbox[0]! as PdfNumber).value! > 0) { + isValidMatrix = false; + } + } + } + } + return isValidMatrix; + } + + /// Flatten annotation template + void flattenAnnotationTemplate(PdfTemplate appearance, bool isNormalMatrix) { + final PdfGraphicsState state = page!.graphics.save(); + if (opacity < 1) { + page!.graphics.setTransparency(opacity); + } + final Rect bound = calculateTemplateBounds( + bounds, + page, + appearance, + isNormalMatrix, + ); + page!.graphics.drawPdfTemplate(appearance, bound.topLeft, bounds.size); + page!.graphics.restore(state); + page!.annotations.remove(base); + } + + /// Draw CloudStye to the Shapes + void drawCloudStyle( + PdfGraphics graphics, + PdfBrush? brush, + PdfPen? pen, + double radius, + double overlap, + List points, + bool isAppearance, + ) { + if (_isClockWise(points)) { + points = List.generate( + points.length, + (int i) => points[points.length - (i + 1)], + ); + } + + // Create a list of circles + final List<_CloudStyleArc> circles = <_CloudStyleArc>[]; + final double circleOverlap = 2 * radius * overlap; + Offset previousPoint = points[points.length - 1]; + for (int i = 0; i < points.length; i++) { + final Offset currentPoint = points[i]; + double dx = currentPoint.dx - previousPoint.dx; + double dy = currentPoint.dy - previousPoint.dy; + final double len = sqrt(dx * dx + dy * dy); + dx = dx / len; + dy = dy / len; + final double d = circleOverlap; + for (double a = 0; a + 0.1 * d < len; a += d) { + final _CloudStyleArc cur = _CloudStyleArc(); + cur.point = Offset( + previousPoint.dx + a * dx, + previousPoint.dy + a * dy, + ); + circles.add(cur); + } + previousPoint = currentPoint; + } + final PdfPath gpath = PdfPath(); + gpath.addPolygon(points); + + // Determine intersection angles of circles + _CloudStyleArc previousCurvedStyleArc = circles[circles.length - 1]; + for (int i = 0; i < circles.length; i++) { + final _CloudStyleArc currentCurvedStyleArc = circles[i]; + final Offset angle = _getIntersectionDegrees( + previousCurvedStyleArc.point, + currentCurvedStyleArc.point, + radius, + ); + previousCurvedStyleArc.endAngle = angle.dx; + currentCurvedStyleArc.startAngle = angle.dy; + previousCurvedStyleArc = currentCurvedStyleArc; + } + + // Draw the cloud + PdfPath path = PdfPath(); + for (int i = 0; i < circles.length; i++) { + final _CloudStyleArc curr = circles[i]; + final double angle = + curr.startAngle < 0 + ? ((curr.startAngle * -1) % 360) * -1 + : curr.startAngle % 360; + final double angle1 = + curr.endAngle < 0 + ? ((curr.endAngle * -1) % 360) * -1 + : curr.endAngle % 360; + double sweepAngel = 0; + if (angle > 0 && angle1 < 0) { + sweepAngel = (180 - angle) + (180 - (angle1 < 0 ? -angle1 : angle1)); + } else if (angle < 0 && angle1 > 0) { + sweepAngel = -angle + angle1; + } else if (angle > 0 && angle1 > 0) { + double difference = 0; + if (angle > angle1) { + difference = angle - angle1; + sweepAngel = 360 - difference; + } else { + sweepAngel = angle1 - angle; + } + } else if (angle < 0 && angle1 < 0) { + double difference = 0; + if (angle > angle1) { + difference = angle - angle1; + sweepAngel = 360 - difference; + } else { + sweepAngel = -(angle + (-angle1)); + } + } + if (sweepAngel < 0) { + sweepAngel = -sweepAngel; + } + curr.endAngle = sweepAngel; + path.addArc( + Rect.fromLTWH( + curr.point.dx - radius, + curr.point.dy - radius, + 2 * radius, + 2 * radius, + ), + angle, + sweepAngel, + ); + } + path.closeFigure(); + PdfPath pdfPath = PdfPath(); + if (isAppearance) { + for (int i = 0; i < PdfPathHelper.getHelper(path).points.length; i++) { + PdfPathHelper.getHelper(pdfPath).points.add( + Offset( + PdfPathHelper.getHelper(path).points[i].dx, + -PdfPathHelper.getHelper(path).points[i].dy, + ), + ); + } + } else { + PdfPathHelper.getHelper( + pdfPath, + ).points.addAll(PdfPathHelper.getHelper(path).points); + } + PdfPathHelper.getHelper( + pdfPath, + ).pathTypes.addAll(PdfPathHelper.getHelper(path).pathTypes); + if (brush != null) { + graphics.drawPath(pdfPath, brush: brush); + } + const double incise = 180 / (pi * 3); + path = PdfPath(); + for (int i = 0; i < circles.length; i++) { + final _CloudStyleArc curr = circles[i]; + path.addArc( + Rect.fromLTWH( + curr.point.dx - radius, + curr.point.dy - radius, + 2 * radius, + 2 * radius, + ), + curr.startAngle, + curr.endAngle + incise, + ); + } + path.closeFigure(); + pdfPath = PdfPath(); + if (isAppearance) { + for (int i = 0; i < PdfPathHelper.getHelper(path).points.length; i++) { + PdfPathHelper.getHelper(pdfPath).points.add( + Offset( + PdfPathHelper.getHelper(path).points[i].dx, + -PdfPathHelper.getHelper(path).points[i].dy, + ), + ); + } + } else { + PdfPathHelper.getHelper( + pdfPath, + ).points.addAll(PdfPathHelper.getHelper(path).points); + } + PdfPathHelper.getHelper( + pdfPath, + ).pathTypes.addAll(PdfPathHelper.getHelper(path).pathTypes); + graphics.drawPath(pdfPath, pen: pen); + } + + bool _isClockWise(List points) { + double sum = 0.0; + for (int i = 0; i < points.length; i++) { + final Offset v1 = points[i]; + final Offset v2 = points[(i + 1) % points.length]; + sum += (v2.dx - v1.dx) * (v2.dy + v1.dy); + } + return sum > 0.0; + } + + Offset _getIntersectionDegrees(Offset point1, Offset point2, double radius) { + final double dx = point2.dx - point1.dx; + final double dy = point2.dy - point1.dy; + final double len = sqrt(dx * dx + dy * dy); + double a = 0.5 * len / radius; + if (a < -1) { + a = -1; + } + if (a > 1) { + a = 1; + } + final double radian = atan2(dy, dx); + final double cosvalue = acos(a); + return Offset( + (radian - cosvalue) * (180 / pi), + (pi + radian + cosvalue) * (180 / pi), + ); + } + + // Searches the in parents. + static IPdfPrimitive? _searchInParents( + PdfDictionary dictionary, + PdfCrossTable? crossTable, + String value, + ) { + IPdfPrimitive? primitive; + PdfDictionary? dic = dictionary; + while ((primitive == null) && (dic != null)) { + if (dic.containsKey(value)) { + primitive = crossTable!.getObject(dic[value]); + } else { + if (dic.containsKey(PdfDictionaryProperties.parent)) { + dic = + crossTable!.getObject(dic[PdfDictionaryProperties.parent]) + as PdfDictionary?; + } else { + dic = null; + } + } + } + return primitive; + } + + /// internal method + static IPdfPrimitive? getValue( + PdfDictionary dictionary, + PdfCrossTable? crossTable, + String value, + bool inheritable, + ) { + IPdfPrimitive? primitive; + if (dictionary.containsKey(value)) { + primitive = crossTable!.getObject(dictionary[value]); + } else { + if (inheritable) { + primitive = _searchInParents(dictionary, crossTable, value); + } + } + return primitive; + } + + /// internal method + static void save(PdfAnnotation annotation) { + bool isSaveComplete = false; + if (annotation is PdfActionAnnotation) { + PdfActionAnnotationHelper.getHelper(annotation).save(); + } else if (annotation is PdfDocumentLinkAnnotation) { + PdfDocumentLinkAnnotationHelper.getHelper(annotation).save(); + } else if (annotation is PdfEllipseAnnotation) { + PdfEllipseAnnotationHelper.getHelper(annotation).save(); + isSaveComplete = true; + } else if (annotation is PdfLineAnnotation) { + PdfLineAnnotationHelper.getHelper(annotation).save(); + isSaveComplete = true; + } else if (annotation is PdfPolygonAnnotation) { + PdfPolygonAnnotationHelper.getHelper(annotation).save(); + isSaveComplete = true; + } else if (annotation is PdfRectangleAnnotation) { + PdfRectangleAnnotationHelper.getHelper(annotation).save(); + isSaveComplete = true; + } else if (annotation is WidgetAnnotation) { + WidgetAnnotationHelper.getHelper(annotation).save(); + isSaveComplete = true; + } else if (annotation is PdfTextMarkupAnnotation) { + PdfTextMarkupAnnotationHelper.getHelper(annotation).save(); + isSaveComplete = true; + } else if (annotation is PdfPopupAnnotation) { + PdfPopupAnnotationHelper.getHelper(annotation).save(); + isSaveComplete = true; + } + if (!PdfAnnotationHelper.getHelper(annotation).flatten) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + if (helper.flag != null) { + int flagValue = 0; + for (int i = 0; i < helper.flag!.length; i++) { + flagValue |= getAnnotationFlagsValue(helper.flag![i]); + } + helper.dictionary!.setNumber(PdfDictionaryProperties.f, flagValue); + } + } + if (!isSaveComplete) { + PdfAnnotationHelper.getHelper(annotation).saveAnnotation(); + } + } + + /// Internal method. + int? getFlagValue() { + if (dictionary!.containsKey(PdfDictionaryProperties.f)) { + final IPdfPrimitive? annotFlags = getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.f, + false, + ); + if (annotFlags != null && + annotFlags is PdfNumber && + annotFlags.value != null) { + return annotFlags.value!.toInt(); + } + } + return null; + } + + /// Internal method. + static List obtainAnnotationFlags(int? flagValue) { + final List flags = []; + if (flagValue != null) { + for (final PdfAnnotationFlags flag in PdfAnnotationFlags.values) { + if (flagValue == 0) { + return flags..add(flag); + } + if (getAnnotationFlagsValue(flag) & flagValue != 0) { + flags.add(flag); + } + } + } + return flags; + } + + /// internal method + static int getAnnotationFlagsValue(PdfAnnotationFlags value) { + switch (value) { + case PdfAnnotationFlags.defaultFlag: + return 0; + case PdfAnnotationFlags.invisible: + return 1; + case PdfAnnotationFlags.hidden: + return 2; + case PdfAnnotationFlags.print: + return 4; + case PdfAnnotationFlags.noZoom: + return 8; + case PdfAnnotationFlags.noRotate: + return 16; + case PdfAnnotationFlags.noView: + return 32; + case PdfAnnotationFlags.readOnly: + return 64; + case PdfAnnotationFlags.locked: + return 128; + case PdfAnnotationFlags.toggleNoView: + return 256; + } + } +} + +class _CloudStyleArc { + late Offset point; + double endAngle = 0; + double startAngle = 0; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_border.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_border.dart index 963a61508..aaf9a0142 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_border.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_border.dart @@ -1,190 +1,190 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import 'enum.dart'; - -/// Represents the appearance of an annotation's border. -/// [PdfAnnotationBorder] class is used to create the annotation border -class PdfAnnotationBorder implements IPdfWrapper { - //constructor - /// Initializes a new instance of the - /// [PdfAnnotationBorder] class with specified border width, - /// horizontal and vertical radius. - /// - /// The borderStyle and dashArray only used for shape annotations. - PdfAnnotationBorder([ - double? borderWidth, - double? horizontalRadius, - double? verticalRadius, - PdfBorderStyle? borderStyle, - int? dashArray, - ]) { - _helper.array.add(PdfNumber(0)); - _helper.array.add(PdfNumber(0)); - _helper.array.add(PdfNumber(1)); - this.horizontalRadius = horizontalRadius ??= 0; - width = borderWidth ??= 1; - this.verticalRadius = verticalRadius ??= 0; - _borderStyle = borderStyle ??= PdfBorderStyle.solid; - _helper.dictionary.setName( - PdfName(PdfDictionaryProperties.s), - _styleToString(_borderStyle), - ); - if (dashArray != null) { - this.dashArray = dashArray; - } - } - - PdfAnnotationBorder._asWidgetBorder() { - _helper.dictionary.setProperty( - PdfDictionaryProperties.type, - PdfName(PdfDictionaryProperties.border), - ); - _borderStyle = PdfBorderStyle.solid; - _helper.dictionary.setName( - PdfName(PdfDictionaryProperties.s), - _styleToString(_borderStyle), - ); - _helper.isWidgetBorder = true; - } - - // fields - final PdfAnnotationBorderHelper _helper = PdfAnnotationBorderHelper(); - double _horizontalRadius = 0; - double _verticalRadius = 0; - double _borderWidth = 1; - int? _dashArray; - late PdfBorderStyle _borderStyle; - - // properties - /// Gets or sets the horizontal corner radius of the annotations. - double get horizontalRadius => _horizontalRadius; - - set horizontalRadius(double value) { - if (value != _horizontalRadius) { - _horizontalRadius = value; - _setNumber(0, value); - } - } - - /// Gets or sets the vertical corner radius of the annotation. - double get verticalRadius => _verticalRadius; - - set verticalRadius(double value) { - if (value != _verticalRadius) { - _verticalRadius = value; - _setNumber(1, value); - } - } - - /// Gets or sets the width of annotation's border. - double get width => _borderWidth; - - set width(double value) { - if (value != _borderWidth) { - _borderWidth = value; - if (!_helper.isWidgetBorder) { - _setNumber(2, value); - } - _helper.dictionary.setNumber( - PdfDictionaryProperties.w, - _borderWidth.toInt(), - ); - } - } - - /// Gets or sets the border style. - PdfBorderStyle get borderStyle => _borderStyle; - - set borderStyle(PdfBorderStyle value) { - if (value != _borderStyle) { - _borderStyle = value; - _helper.dictionary.setName( - PdfName(PdfDictionaryProperties.s), - _styleToString(_borderStyle), - ); - } - } - - /// Gets or sets the line dash of the annotation. - int? get dashArray => _dashArray; - - set dashArray(int? value) { - if (value != null && _dashArray != value) { - _dashArray = value; - final PdfArray dasharray = PdfArray(); - dasharray.add(PdfNumber(_dashArray!)); - dasharray.add(PdfNumber(_dashArray!)); - _helper.dictionary.setProperty(PdfDictionaryProperties.d, dasharray); - } - } - - //Implementation - void _setNumber(int index, double value) { - final PdfNumber number = _helper.array[index]! as PdfNumber; - number.value = value; - } - - String _styleToString(PdfBorderStyle? borderStyle) { - switch (borderStyle) { - case PdfBorderStyle.beveled: - return 'B'; - case PdfBorderStyle.dashed: - case PdfBorderStyle.dot: - return 'D'; - case PdfBorderStyle.inset: - return 'I'; - case PdfBorderStyle.underline: - return 'U'; - // ignore: no_default_cases - default: - return 'S'; - } - } -} - -/// [PdfAnnotationBorder] helper -class PdfAnnotationBorderHelper { - /// internal field - bool isLineBorder = false; - - /// internal field - PdfDictionary dictionary = PdfDictionary(); - - /// internal field - bool isWidgetBorder = false; - - /// internal field - final PdfArray array = PdfArray(); - - /// internal property - IPdfPrimitive get element { - if (isLineBorder || isWidgetBorder) { - return dictionary; - } else { - return array; - } - } - - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } - - /// internal method - static PdfAnnotationBorder getWidgetBorder() { - return PdfAnnotationBorder._asWidgetBorder(); - } - - /// internal method - static PdfAnnotationBorderHelper getHelper( - PdfAnnotationBorder annotationBorder, - ) { - return annotationBorder._helper; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import 'enum.dart'; + +/// Represents the appearance of an annotation's border. +/// [PdfAnnotationBorder] class is used to create the annotation border +class PdfAnnotationBorder implements IPdfWrapper { + //constructor + /// Initializes a new instance of the + /// [PdfAnnotationBorder] class with specified border width, + /// horizontal and vertical radius. + /// + /// The borderStyle and dashArray only used for shape annotations. + PdfAnnotationBorder([ + double? borderWidth, + double? horizontalRadius, + double? verticalRadius, + PdfBorderStyle? borderStyle, + int? dashArray, + ]) { + _helper.array.add(PdfNumber(0)); + _helper.array.add(PdfNumber(0)); + _helper.array.add(PdfNumber(1)); + this.horizontalRadius = horizontalRadius ??= 0; + width = borderWidth ??= 1; + this.verticalRadius = verticalRadius ??= 0; + _borderStyle = borderStyle ??= PdfBorderStyle.solid; + _helper.dictionary.setName( + PdfName(PdfDictionaryProperties.s), + _styleToString(_borderStyle), + ); + if (dashArray != null) { + this.dashArray = dashArray; + } + } + + PdfAnnotationBorder._asWidgetBorder() { + _helper.dictionary.setProperty( + PdfDictionaryProperties.type, + PdfName(PdfDictionaryProperties.border), + ); + _borderStyle = PdfBorderStyle.solid; + _helper.dictionary.setName( + PdfName(PdfDictionaryProperties.s), + _styleToString(_borderStyle), + ); + _helper.isWidgetBorder = true; + } + + // fields + final PdfAnnotationBorderHelper _helper = PdfAnnotationBorderHelper(); + double _horizontalRadius = 0; + double _verticalRadius = 0; + double _borderWidth = 1; + int? _dashArray; + late PdfBorderStyle _borderStyle; + + // properties + /// Gets or sets the horizontal corner radius of the annotations. + double get horizontalRadius => _horizontalRadius; + + set horizontalRadius(double value) { + if (value != _horizontalRadius) { + _horizontalRadius = value; + _setNumber(0, value); + } + } + + /// Gets or sets the vertical corner radius of the annotation. + double get verticalRadius => _verticalRadius; + + set verticalRadius(double value) { + if (value != _verticalRadius) { + _verticalRadius = value; + _setNumber(1, value); + } + } + + /// Gets or sets the width of annotation's border. + double get width => _borderWidth; + + set width(double value) { + if (value != _borderWidth) { + _borderWidth = value; + if (!_helper.isWidgetBorder) { + _setNumber(2, value); + } + _helper.dictionary.setNumber( + PdfDictionaryProperties.w, + _borderWidth.toInt(), + ); + } + } + + /// Gets or sets the border style. + PdfBorderStyle get borderStyle => _borderStyle; + + set borderStyle(PdfBorderStyle value) { + if (value != _borderStyle) { + _borderStyle = value; + _helper.dictionary.setName( + PdfName(PdfDictionaryProperties.s), + _styleToString(_borderStyle), + ); + } + } + + /// Gets or sets the line dash of the annotation. + int? get dashArray => _dashArray; + + set dashArray(int? value) { + if (value != null && _dashArray != value) { + _dashArray = value; + final PdfArray dasharray = PdfArray(); + dasharray.add(PdfNumber(_dashArray!)); + dasharray.add(PdfNumber(_dashArray!)); + _helper.dictionary.setProperty(PdfDictionaryProperties.d, dasharray); + } + } + + //Implementation + void _setNumber(int index, double value) { + final PdfNumber number = _helper.array[index]! as PdfNumber; + number.value = value; + } + + String _styleToString(PdfBorderStyle? borderStyle) { + switch (borderStyle) { + case PdfBorderStyle.beveled: + return 'B'; + case PdfBorderStyle.dashed: + case PdfBorderStyle.dot: + return 'D'; + case PdfBorderStyle.inset: + return 'I'; + case PdfBorderStyle.underline: + return 'U'; + // ignore: no_default_cases + default: + return 'S'; + } + } +} + +/// [PdfAnnotationBorder] helper +class PdfAnnotationBorderHelper { + /// internal field + bool isLineBorder = false; + + /// internal field + PdfDictionary dictionary = PdfDictionary(); + + /// internal field + bool isWidgetBorder = false; + + /// internal field + final PdfArray array = PdfArray(); + + /// internal property + IPdfPrimitive get element { + if (isLineBorder || isWidgetBorder) { + return dictionary; + } else { + return array; + } + } + + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } + + /// internal method + static PdfAnnotationBorder getWidgetBorder() { + return PdfAnnotationBorder._asWidgetBorder(); + } + + /// internal method + static PdfAnnotationBorderHelper getHelper( + PdfAnnotationBorder annotationBorder, + ) { + return annotationBorder._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_collection.dart index 020e09c75..ff82d5223 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_annotation_collection.dart @@ -1,763 +1,763 @@ -import '../../interfaces/pdf_interface.dart'; -import '../general/pdf_collection.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_document_link_annotation.dart'; -import 'pdf_ellipse_annotation.dart'; -import 'pdf_line_annotation.dart'; -import 'pdf_polygon_annotation.dart'; -import 'pdf_popup_annotation.dart'; -import 'pdf_rectangle_annotation.dart'; -import 'pdf_text_markup_annotation.dart'; -import 'pdf_text_web_link.dart'; -import 'pdf_uri_annotation.dart'; -import 'widget_annotation.dart'; - -/// Represents the collection of [PdfAnnotation] objects. -class PdfAnnotationCollection extends PdfObjectCollection - implements IPdfWrapper { - // constructor - /// Initializes a new instance of the [PdfAnnotationCollection] - /// class with the specified page. - PdfAnnotationCollection(PdfPage page) : super() { - _helper = PdfAnnotationCollectionHelper(this, page); - } - - PdfAnnotationCollection._(PdfPage page) : super() { - _helper = PdfAnnotationCollectionHelper._(this, page); - } - - // Fields - late PdfAnnotationCollectionHelper _helper; - - // public methods - /// Gets the PdfAnnotation at the specified index. - PdfAnnotation operator [](int index) => _helper.getValue(index); - - /// Adds a new annotation to the collection. - int add(PdfAnnotation annotation) { - return _helper._doAdd(annotation); - } - - /// Removes the specified annotation from the collection. - void remove(PdfAnnotation annot) { - _helper._doRemove(annot); - } - - /// Determines whether a specified annotation is in the annotation collection. - bool contains(PdfAnnotation annotation) { - return _helper.contains(annotation); - } - - /// Flatten all the annotations. - /// - /// The flatten will add at the time of saving the current document. - void flattenAllAnnotations() { - _helper.setFlattenAll(true); - } -} - -/// [PdfAnnotationCollection] helper -class PdfAnnotationCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfAnnotationCollectionHelper(this.base, this.page) : super(base); - PdfAnnotationCollectionHelper._(this.base, this.page) : super(base) { - for ( - int i = 0; - i < PdfPageHelper.getHelper(page).terminalAnnotation.length; - ++i - ) { - final PdfAnnotation? annot = _getAnnotation(i); - if (annot != null) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(annot); - helper.isOldAnnotation = true; - _doAdd(annot); - helper.isOldAnnotation = false; - } - } - } - - /// internal field - IPdfPrimitive? element; - - /// internal field - late PdfAnnotationCollection base; - - /// internal field - PdfArray annotations = PdfArray(); - - /// internal field - bool flatten = false; - - /// internal field - late PdfPage page; - - /// Gets the annotations array. - PdfArray get internalAnnotations => annotations; - set internalAnnotations(PdfArray? value) { - if (value != null) { - annotations = value; - } - } - - /// internal method - PdfArray? rearrange(PdfReference reference, int tabIndex, int index) { - final PdfArray? annots = - PdfPageHelper.getHelper(page).crossTable!.getObject( - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .annots], - ) - as PdfArray?; - if (annots != null) { - if (tabIndex > annots.count) { - tabIndex = 0; - } - if (index >= annots.count) { - index = PdfPageHelper.getHelper( - page, - ).annotsReference.indexOf(reference); - } - final IPdfPrimitive? annotReference = annots.elements[index]; - if (annotReference != null && annotReference is PdfReferenceHolder) { - final IPdfPrimitive? annotObject = annotReference.object; - if (annotObject != null && - annotObject is PdfDictionary && - annotObject.containsKey(PdfDictionaryProperties.parent)) { - final IPdfPrimitive? annotParent = - annotObject[PdfDictionaryProperties.parent]; - if (annotReference.reference == reference || - (annotParent != null && - annotParent is PdfReferenceHolder && - reference == annotParent.reference)) { - final IPdfPrimitive? temp = annots[index]; - if (temp != null) { - annots.elements[index] = annots[tabIndex]; - annots.elements[tabIndex] = temp; - } - } - } - } - } - return annots; - } - - /// Sets the annotation flatten. - void setFlattenAll(bool value) { - flatten = value; - if (flatten && PdfPageHelper.getHelper(page).document != null) { - final PdfCrossTable? cross = PdfPageHelper.getHelper(page).crossTable; - if (cross != null && - PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.annots)) { - final PdfArray? annots = - cross.getObject( - PdfPageHelper.getHelper( - page, - ).dictionary![PdfDictionaryProperties.annots], - ) - as PdfArray?; - if (annots != null) { - for (int count = 0; count < annots.count; ++count) { - final PdfDictionary? annotDicrionary = - cross.getObject(annots[count]) as PdfDictionary?; - if (annotDicrionary != null) { - if (annotDicrionary.containsKey(PdfDictionaryProperties.ft)) { - annotDicrionary.remove(PdfDictionaryProperties.ft); - } - if (annotDicrionary.containsKey(PdfDictionaryProperties.v)) { - annotDicrionary.remove(PdfDictionaryProperties.v); - } - } - } - } - } - } - } - - /// internal method - PdfAnnotation getValue(int index) { - if (index < 0 || index >= base.count) { - throw ArgumentError('$index, Index is out of range.'); - } - final PdfAnnotation annotation = list[index] as PdfAnnotation; - if (!PdfPageHelper.getHelper(page).isLoadedPage) { - return annotation; - } else { - PdfAnnotationHelper.getHelper(annotation).isLoadedAnnotation - ? PdfAnnotationHelper.getHelper(annotation).page = page - : PdfAnnotationHelper.getHelper(annotation).setPage(page); - } - return annotation; - } - - // implementation - int _doAdd(PdfAnnotation annot) { - if (flatten) { - PdfAnnotationHelper.getHelper(annot).flatten = true; - } - PdfAnnotationHelper.getHelper(annot).setPage(page); - if (!PdfAnnotationHelper.getHelper(annot).isLoadedAnnotation && - annot is PdfTextMarkupAnnotation) { - PdfTextMarkupAnnotationHelper.getHelper(annot).setQuadPoints(page.size); - } - if (PdfPageHelper.getHelper(page).isLoadedPage) { - PdfArray? array; - final PdfDictionary dictionary = - PdfPageHelper.getHelper(page).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.annots)) { - array = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.annots], - ) - as PdfArray?; - } - array ??= PdfArray(); - final PdfReferenceHolder reference = PdfReferenceHolder( - PdfAnnotationHelper.getHelper(annot).dictionary, - ); - if (!PdfAnnotationHelper.getHelper(annot).isOldAnnotation && - !_checkPresence(array, reference)) { - array.add(reference); - dictionary.setProperty(PdfDictionaryProperties.annots, array); - } - } - final IPdfPrimitive? tempElement = IPdfWrapper.getElement(annot); - if (tempElement == null) { - IPdfWrapper.setElement( - annot, - PdfAnnotationHelper.getHelper(annot).dictionary, - ); - } - annotations.add(PdfReferenceHolder(annot)); - list.add(annot); - return base.count - 1; - } - - bool _checkPresence(PdfArray array, PdfReferenceHolder reference) { - bool result = false; - result = array.contains(reference); - if (!result) { - for (int i = 0; i < array.elements.length; i++) { - if (array.elements[i] is PdfReferenceHolder) { - final PdfReferenceHolder holder = - array.elements[i]! as PdfReferenceHolder; - if (holder.object == reference.object) { - result = true; - break; - } - } - } - } - return result; - } - - void _doRemove(PdfAnnotation annot) { - if (PdfPageHelper.getHelper(page).isLoadedPage) { - _removeFromDictionaries(annot); - } - final int index = list.indexOf(annot); - annotations.elements.removeAt(index); - list.removeAt(index); - } - - void _removeFromDictionaries(PdfAnnotation annot) { - final PdfDictionary pageDic = PdfPageHelper.getHelper(page).dictionary!; - PdfArray? annots; - if (pageDic.containsKey(PdfDictionaryProperties.annots)) { - annots = - PdfPageHelper.getHelper( - page, - ).crossTable!.getObject(pageDic[PdfDictionaryProperties.annots]) - as PdfArray?; - } else { - annots = PdfArray(); - } - if (PdfAnnotationHelper.getHelper( - annot, - ).dictionary!.containsKey(PdfDictionaryProperties.popup)) { - final IPdfPrimitive? popUpDictionary = - (PdfAnnotationHelper.getHelper(annot).dictionary![PdfName( - PdfDictionaryProperties.popup, - )] - is PdfReferenceHolder) - ? (PdfAnnotationHelper.getHelper(annot).dictionary![PdfName( - PdfDictionaryProperties.popup, - )]! - as PdfReferenceHolder) - .object - : PdfAnnotationHelper.getHelper(annot).dictionary![PdfName( - PdfDictionaryProperties.popup, - )]; - if (popUpDictionary is PdfDictionary) { - for (int i = 0; i < annots!.count; i++) { - if (popUpDictionary == - PdfPageHelper.getHelper(page).crossTable!.getObject(annots[i]) - as PdfDictionary?) { - annots.elements.removeAt(i); - annots.changed = true; - break; - } - } - final IPdfPrimitive popUpObj = - PdfPageHelper.getHelper( - page, - ).crossTable!.getObject(popUpDictionary)!; - final int? popUpIndex = PdfPageHelper.getHelper( - page, - ).crossTable!.items!.lookFor(popUpObj); - if (popUpIndex != null && popUpIndex != -1) { - PdfPageHelper.getHelper( - page, - ).crossTable!.items!.objectCollection!.removeAt(popUpIndex); - } - _removeAllReference(popUpObj); - PdfPageHelper.getHelper( - page, - ).terminalAnnotation.remove(popUpDictionary); - } - } - for (int i = 0; i < annots!.count; i++) { - if (PdfAnnotationHelper.getHelper(annot).dictionary == - PdfPageHelper.getHelper(page).crossTable!.getObject(annots[i]) - as PdfDictionary?) { - annots.elements.removeAt(i); - annots.changed = true; - break; - } - } - PdfAnnotationHelper.getHelper(annot).dictionary!.changed = false; - PdfPageHelper.getHelper( - page, - ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); - } - - void _removeAllReference(IPdfPrimitive obj) { - final IPdfPrimitive? dictionary = - obj is PdfReferenceHolder ? obj.object : obj; - if (dictionary is PdfDictionary) { - dictionary.items!.forEach((PdfName? k, IPdfPrimitive? v) { - if ((v is PdfReferenceHolder || v is PdfDictionary) && - k!.name != PdfDictionaryProperties.p && - k.name != PdfDictionaryProperties.parent) { - final IPdfPrimitive newobj = - PdfPageHelper.getHelper(page).crossTable!.getObject(v)!; - final int? index = PdfPageHelper.getHelper( - page, - ).crossTable!.items!.lookFor(newobj); - if (index != null && index != -1) { - PdfPageHelper.getHelper( - page, - ).crossTable!.items!.objectCollection!.removeAt(index); - } - _removeAllReference(v!); - (PdfCrossTable.dereference(v)! as PdfStream) - ..dispose() - ..changed = false; - } - }); - } - } - - // Gets the annotation. - PdfAnnotation? _getAnnotation(int index) { - final PdfDictionary dictionary = - PdfPageHelper.getHelper(page).terminalAnnotation[index]; - final PdfCrossTable? crossTable = PdfPageHelper.getHelper(page).crossTable; - PdfAnnotation? annot; - if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName name = - PdfAnnotationHelper.getValue( - dictionary, - crossTable, - PdfDictionaryProperties.subtype, - true, - )! - as PdfName; - final PdfAnnotationTypes type = getAnnotationType( - name, - dictionary, - crossTable, - ); - final PdfArray? rectValue = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.rect]) - as PdfArray?; - if (rectValue != null) { - String text = ''; - if (dictionary.containsKey(PdfDictionaryProperties.contents)) { - final IPdfPrimitive? str = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.contents], - ); - if (str != null && str is PdfString) { - text = str.value.toString(); - } - } - switch (type) { - case PdfAnnotationTypes.documentLinkAnnotation: - annot = _createDocumentLinkAnnotation(dictionary, crossTable!); - break; - case PdfAnnotationTypes.linkAnnotation: - if (dictionary.containsKey(PdfDictionaryProperties.a)) { - final PdfDictionary? remoteLinkDic = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.a], - ) - as PdfDictionary?; - if (remoteLinkDic != null && - remoteLinkDic.containsKey(PdfDictionaryProperties.s)) { - PdfName? gotor; - gotor = - PdfCrossTable.dereference( - remoteLinkDic[PdfDictionaryProperties.s], - ) - as PdfName?; - if (gotor != null && gotor.name == 'URI') { - annot = _createLinkAnnotation(dictionary, crossTable!, text); - } - } - } else { - annot = _createLinkAnnotation(dictionary, crossTable!, text); - } - break; - case PdfAnnotationTypes.lineAnnotation: - annot = _createLineAnnotation(dictionary, crossTable!, text); - break; - case PdfAnnotationTypes.circleAnnotation: - annot = _createEllipseAnnotation(dictionary, crossTable!, text); - break; - case PdfAnnotationTypes.rectangleAnnotation: - annot = _createRectangleAnnotation(dictionary, crossTable!, text); - break; - case PdfAnnotationTypes.polygonAnnotation: - annot = _createPolygonAnnotation(dictionary, crossTable!, text); - break; - case PdfAnnotationTypes.textWebLinkAnnotation: - annot = _createTextWebLinkAnnotation(dictionary, crossTable!, text); - break; - case PdfAnnotationTypes.widgetAnnotation: - annot = _createWidgetAnnotation(dictionary, crossTable!); - break; - case PdfAnnotationTypes.highlight: - case PdfAnnotationTypes.squiggly: - case PdfAnnotationTypes.strikeOut: - case PdfAnnotationTypes.underline: - annot = _createMarkupAnnotation(dictionary, crossTable!); - break; - case PdfAnnotationTypes.popupAnnotation: - annot = _createPopupAnnotation(dictionary, crossTable!, text); - break; - // ignore: no_default_cases - default: - break; - } - return annot; - } else { - return annot; - } - } - return annot; - } - - /// Gets the type of the annotation. - static PdfAnnotationTypes getAnnotationType( - PdfName name, - PdfDictionary dictionary, - PdfCrossTable? crossTable, - ) { - final String str = name.name!; - PdfAnnotationTypes type = PdfAnnotationTypes.noAnnotation; - switch (str.toLowerCase()) { - case 'link': - PdfDictionary? linkDic; - if (dictionary.containsKey(PdfDictionaryProperties.a)) { - linkDic = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.a]) - as PdfDictionary?; - } - if (linkDic != null && linkDic.containsKey(PdfDictionaryProperties.s)) { - name = - PdfCrossTable.dereference(linkDic[PdfDictionaryProperties.s])! - as PdfName; - final PdfArray? border = - (PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.border], - ) - is PdfArray) - ? PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.border], - ) - as PdfArray? - : null; - final bool mType = _findAnnotation(border); - if (name.name == 'URI') { - type = PdfAnnotationTypes.linkAnnotation; - if (!mType) { - type = PdfAnnotationTypes.linkAnnotation; - } else { - type = PdfAnnotationTypes.textWebLinkAnnotation; - } - } else if (name.name == 'GoToR') { - type = PdfAnnotationTypes.linkAnnotation; - } else if (name.name == 'GoTo') { - type = PdfAnnotationTypes.documentLinkAnnotation; - } - } else if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName? strText = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.subtype], - ) - as PdfName?; - if (strText != null) { - switch (strText.name) { - case 'Link': - type = PdfAnnotationTypes.documentLinkAnnotation; - break; - } - } - } - break; - case 'line': - type = PdfAnnotationTypes.lineAnnotation; - break; - case 'circle': - type = PdfAnnotationTypes.circleAnnotation; - break; - case 'square': - type = PdfAnnotationTypes.rectangleAnnotation; - break; - case 'polygon': - type = PdfAnnotationTypes.polygonAnnotation; - break; - case 'widget': - type = PdfAnnotationTypes.widgetAnnotation; - break; - case 'highlight': - type = PdfAnnotationTypes.highlight; - break; - case 'underline': - type = PdfAnnotationTypes.underline; - break; - case 'strikeout': - type = PdfAnnotationTypes.strikeOut; - break; - case 'squiggly': - type = PdfAnnotationTypes.squiggly; - break; - case 'text': - if (!dictionary.containsKey(PdfDictionaryProperties.irt)) { - type = PdfAnnotationTypes.popupAnnotation; - } - break; - default: - break; - } - return type; - } - - // Creates the file link annotation. - PdfAnnotation _createDocumentLinkAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final PdfAnnotation annot = PdfDocumentLinkAnnotationHelper.load( - dictionary, - crossTable, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - PdfAnnotationHelper.getHelper(annot).page = page; - return annot; - } - - PdfAnnotation _createLinkAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - final PdfAnnotation annot = PdfUriAnnotationHelper.load( - dictionary, - crossTable, - text, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - return annot; - } - - // Creates the Line Annotation. - PdfAnnotation _createLineAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - final PdfAnnotation annot = PdfLineAnnotationHelper.load( - dictionary, - crossTable, - text, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - PdfAnnotationHelper.getHelper(annot).page = page; - return annot; - } - - // Creates the Ellipse Annotation. - PdfAnnotation _createEllipseAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - final PdfAnnotation annot = PdfEllipseAnnotationHelper.load( - dictionary, - crossTable, - text, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - PdfAnnotationHelper.getHelper(annot).page = page; - return annot; - } - - // Creates the Rectangle Annotation. - PdfAnnotation _createRectangleAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - final PdfAnnotation annot = PdfRectangleAnnotationHelper.load( - dictionary, - crossTable, - text, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - PdfAnnotationHelper.getHelper(annot).page = page; - return annot; - } - - // Creates the Polygon Annotation. - PdfAnnotation _createPolygonAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - final PdfAnnotation annot = PdfPolygonAnnotationHelper.load( - dictionary, - crossTable, - text, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - PdfAnnotationHelper.getHelper(annot).page = page; - return annot; - } - - PdfAnnotation _createTextWebLinkAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - final PdfAnnotation annot = PdfTextWebLinkHelper.load( - dictionary, - crossTable, - text, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - return annot; - } - - //Creates the widget annotation. - PdfAnnotation _createWidgetAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final PdfAnnotation annot = WidgetAnnotationHelper.load( - dictionary, - crossTable, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - return annot; - } - - /// Creates the Markup Annotation. - PdfAnnotation _createMarkupAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final PdfAnnotation annot = PdfTextMarkupAnnotationHelper.load( - dictionary, - crossTable, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - return annot; - } - - PdfAnnotation _createPopupAnnotation( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - final PdfAnnotation annot = PdfPopupAnnotationHelper.load( - dictionary, - crossTable, - text, - ); - PdfAnnotationHelper.getHelper(annot).setPage(page); - return annot; - } - - static bool _findAnnotation(PdfArray? arr) { - if (arr == null) { - return false; - } - for (int i = 0; i < arr.count; i++) { - if (arr[i] is PdfArray) { - final PdfArray temp = arr[i]! as PdfArray; - for (int j = 0; j < temp.count; j++) { - final PdfNumber? value = - (temp[j] is PdfNumber) ? temp[j] as PdfNumber? : null; - int? val = 0; - if (value != null) { - val = value.value?.toInt(); - } - if (val! > 0) { - return false; - } - } - } else { - int val = 0; - final PdfNumber? value = - (arr[i] is PdfNumber) ? arr[i] as PdfNumber? : null; - if (value != null) { - val = value.value!.toInt(); - } - if (val > 0) { - return false; - } - } - } - return true; - } - - /// internal method - bool contains(PdfAnnotation annotation) { - return list.contains(annotation); - } - - /// internal method - static PdfAnnotationCollectionHelper getHelper( - PdfAnnotationCollection annotationCollection, - ) { - return annotationCollection._helper; - } - - /// internal method - static PdfAnnotationCollection load(PdfPage page) { - return PdfAnnotationCollection._(page); - } -} +import '../../interfaces/pdf_interface.dart'; +import '../general/pdf_collection.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_document_link_annotation.dart'; +import 'pdf_ellipse_annotation.dart'; +import 'pdf_line_annotation.dart'; +import 'pdf_polygon_annotation.dart'; +import 'pdf_popup_annotation.dart'; +import 'pdf_rectangle_annotation.dart'; +import 'pdf_text_markup_annotation.dart'; +import 'pdf_text_web_link.dart'; +import 'pdf_uri_annotation.dart'; +import 'widget_annotation.dart'; + +/// Represents the collection of [PdfAnnotation] objects. +class PdfAnnotationCollection extends PdfObjectCollection + implements IPdfWrapper { + // constructor + /// Initializes a new instance of the [PdfAnnotationCollection] + /// class with the specified page. + PdfAnnotationCollection(PdfPage page) : super() { + _helper = PdfAnnotationCollectionHelper(this, page); + } + + PdfAnnotationCollection._(PdfPage page) : super() { + _helper = PdfAnnotationCollectionHelper._(this, page); + } + + // Fields + late PdfAnnotationCollectionHelper _helper; + + // public methods + /// Gets the PdfAnnotation at the specified index. + PdfAnnotation operator [](int index) => _helper.getValue(index); + + /// Adds a new annotation to the collection. + int add(PdfAnnotation annotation) { + return _helper._doAdd(annotation); + } + + /// Removes the specified annotation from the collection. + void remove(PdfAnnotation annot) { + _helper._doRemove(annot); + } + + /// Determines whether a specified annotation is in the annotation collection. + bool contains(PdfAnnotation annotation) { + return _helper.contains(annotation); + } + + /// Flatten all the annotations. + /// + /// The flatten will add at the time of saving the current document. + void flattenAllAnnotations() { + _helper.setFlattenAll(true); + } +} + +/// [PdfAnnotationCollection] helper +class PdfAnnotationCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfAnnotationCollectionHelper(this.base, this.page) : super(base); + PdfAnnotationCollectionHelper._(this.base, this.page) : super(base) { + for ( + int i = 0; + i < PdfPageHelper.getHelper(page).terminalAnnotation.length; + ++i + ) { + final PdfAnnotation? annot = _getAnnotation(i); + if (annot != null) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(annot); + helper.isOldAnnotation = true; + _doAdd(annot); + helper.isOldAnnotation = false; + } + } + } + + /// internal field + IPdfPrimitive? element; + + /// internal field + late PdfAnnotationCollection base; + + /// internal field + PdfArray annotations = PdfArray(); + + /// internal field + bool flatten = false; + + /// internal field + late PdfPage page; + + /// Gets the annotations array. + PdfArray get internalAnnotations => annotations; + set internalAnnotations(PdfArray? value) { + if (value != null) { + annotations = value; + } + } + + /// internal method + PdfArray? rearrange(PdfReference reference, int tabIndex, int index) { + final PdfArray? annots = + PdfPageHelper.getHelper(page).crossTable!.getObject( + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .annots], + ) + as PdfArray?; + if (annots != null) { + if (tabIndex > annots.count) { + tabIndex = 0; + } + if (index >= annots.count) { + index = PdfPageHelper.getHelper( + page, + ).annotsReference.indexOf(reference); + } + final IPdfPrimitive? annotReference = annots.elements[index]; + if (annotReference != null && annotReference is PdfReferenceHolder) { + final IPdfPrimitive? annotObject = annotReference.object; + if (annotObject != null && + annotObject is PdfDictionary && + annotObject.containsKey(PdfDictionaryProperties.parent)) { + final IPdfPrimitive? annotParent = + annotObject[PdfDictionaryProperties.parent]; + if (annotReference.reference == reference || + (annotParent != null && + annotParent is PdfReferenceHolder && + reference == annotParent.reference)) { + final IPdfPrimitive? temp = annots[index]; + if (temp != null) { + annots.elements[index] = annots[tabIndex]; + annots.elements[tabIndex] = temp; + } + } + } + } + } + return annots; + } + + /// Sets the annotation flatten. + void setFlattenAll(bool value) { + flatten = value; + if (flatten && PdfPageHelper.getHelper(page).document != null) { + final PdfCrossTable? cross = PdfPageHelper.getHelper(page).crossTable; + if (cross != null && + PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.annots)) { + final PdfArray? annots = + cross.getObject( + PdfPageHelper.getHelper( + page, + ).dictionary![PdfDictionaryProperties.annots], + ) + as PdfArray?; + if (annots != null) { + for (int count = 0; count < annots.count; ++count) { + final PdfDictionary? annotDicrionary = + cross.getObject(annots[count]) as PdfDictionary?; + if (annotDicrionary != null) { + if (annotDicrionary.containsKey(PdfDictionaryProperties.ft)) { + annotDicrionary.remove(PdfDictionaryProperties.ft); + } + if (annotDicrionary.containsKey(PdfDictionaryProperties.v)) { + annotDicrionary.remove(PdfDictionaryProperties.v); + } + } + } + } + } + } + } + + /// internal method + PdfAnnotation getValue(int index) { + if (index < 0 || index >= base.count) { + throw ArgumentError('$index, Index is out of range.'); + } + final PdfAnnotation annotation = list[index] as PdfAnnotation; + if (!PdfPageHelper.getHelper(page).isLoadedPage) { + return annotation; + } else { + PdfAnnotationHelper.getHelper(annotation).isLoadedAnnotation + ? PdfAnnotationHelper.getHelper(annotation).page = page + : PdfAnnotationHelper.getHelper(annotation).setPage(page); + } + return annotation; + } + + // implementation + int _doAdd(PdfAnnotation annot) { + if (flatten) { + PdfAnnotationHelper.getHelper(annot).flatten = true; + } + PdfAnnotationHelper.getHelper(annot).setPage(page); + if (!PdfAnnotationHelper.getHelper(annot).isLoadedAnnotation && + annot is PdfTextMarkupAnnotation) { + PdfTextMarkupAnnotationHelper.getHelper(annot).setQuadPoints(page.size); + } + if (PdfPageHelper.getHelper(page).isLoadedPage) { + PdfArray? array; + final PdfDictionary dictionary = + PdfPageHelper.getHelper(page).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.annots)) { + array = + PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.annots], + ) + as PdfArray?; + } + array ??= PdfArray(); + final PdfReferenceHolder reference = PdfReferenceHolder( + PdfAnnotationHelper.getHelper(annot).dictionary, + ); + if (!PdfAnnotationHelper.getHelper(annot).isOldAnnotation && + !_checkPresence(array, reference)) { + array.add(reference); + dictionary.setProperty(PdfDictionaryProperties.annots, array); + } + } + final IPdfPrimitive? tempElement = IPdfWrapper.getElement(annot); + if (tempElement == null) { + IPdfWrapper.setElement( + annot, + PdfAnnotationHelper.getHelper(annot).dictionary, + ); + } + annotations.add(PdfReferenceHolder(annot)); + list.add(annot); + return base.count - 1; + } + + bool _checkPresence(PdfArray array, PdfReferenceHolder reference) { + bool result = false; + result = array.contains(reference); + if (!result) { + for (int i = 0; i < array.elements.length; i++) { + if (array.elements[i] is PdfReferenceHolder) { + final PdfReferenceHolder holder = + array.elements[i]! as PdfReferenceHolder; + if (holder.object == reference.object) { + result = true; + break; + } + } + } + } + return result; + } + + void _doRemove(PdfAnnotation annot) { + if (PdfPageHelper.getHelper(page).isLoadedPage) { + _removeFromDictionaries(annot); + } + final int index = list.indexOf(annot); + annotations.elements.removeAt(index); + list.removeAt(index); + } + + void _removeFromDictionaries(PdfAnnotation annot) { + final PdfDictionary pageDic = PdfPageHelper.getHelper(page).dictionary!; + PdfArray? annots; + if (pageDic.containsKey(PdfDictionaryProperties.annots)) { + annots = + PdfPageHelper.getHelper( + page, + ).crossTable!.getObject(pageDic[PdfDictionaryProperties.annots]) + as PdfArray?; + } else { + annots = PdfArray(); + } + if (PdfAnnotationHelper.getHelper( + annot, + ).dictionary!.containsKey(PdfDictionaryProperties.popup)) { + final IPdfPrimitive? popUpDictionary = + (PdfAnnotationHelper.getHelper(annot).dictionary![PdfName( + PdfDictionaryProperties.popup, + )] + is PdfReferenceHolder) + ? (PdfAnnotationHelper.getHelper(annot).dictionary![PdfName( + PdfDictionaryProperties.popup, + )]! + as PdfReferenceHolder) + .object + : PdfAnnotationHelper.getHelper(annot).dictionary![PdfName( + PdfDictionaryProperties.popup, + )]; + if (popUpDictionary is PdfDictionary) { + for (int i = 0; i < annots!.count; i++) { + if (popUpDictionary == + PdfPageHelper.getHelper(page).crossTable!.getObject(annots[i]) + as PdfDictionary?) { + annots.elements.removeAt(i); + annots.changed = true; + break; + } + } + final IPdfPrimitive popUpObj = + PdfPageHelper.getHelper( + page, + ).crossTable!.getObject(popUpDictionary)!; + final int? popUpIndex = PdfPageHelper.getHelper( + page, + ).crossTable!.items!.lookFor(popUpObj); + if (popUpIndex != null && popUpIndex != -1) { + PdfPageHelper.getHelper( + page, + ).crossTable!.items!.objectCollection!.removeAt(popUpIndex); + } + _removeAllReference(popUpObj); + PdfPageHelper.getHelper( + page, + ).terminalAnnotation.remove(popUpDictionary); + } + } + for (int i = 0; i < annots!.count; i++) { + if (PdfAnnotationHelper.getHelper(annot).dictionary == + PdfPageHelper.getHelper(page).crossTable!.getObject(annots[i]) + as PdfDictionary?) { + annots.elements.removeAt(i); + annots.changed = true; + break; + } + } + PdfAnnotationHelper.getHelper(annot).dictionary!.changed = false; + PdfPageHelper.getHelper( + page, + ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); + } + + void _removeAllReference(IPdfPrimitive obj) { + final IPdfPrimitive? dictionary = + obj is PdfReferenceHolder ? obj.object : obj; + if (dictionary is PdfDictionary) { + dictionary.items!.forEach((PdfName? k, IPdfPrimitive? v) { + if ((v is PdfReferenceHolder || v is PdfDictionary) && + k!.name != PdfDictionaryProperties.p && + k.name != PdfDictionaryProperties.parent) { + final IPdfPrimitive newobj = + PdfPageHelper.getHelper(page).crossTable!.getObject(v)!; + final int? index = PdfPageHelper.getHelper( + page, + ).crossTable!.items!.lookFor(newobj); + if (index != null && index != -1) { + PdfPageHelper.getHelper( + page, + ).crossTable!.items!.objectCollection!.removeAt(index); + } + _removeAllReference(v!); + (PdfCrossTable.dereference(v)! as PdfStream) + ..dispose() + ..changed = false; + } + }); + } + } + + // Gets the annotation. + PdfAnnotation? _getAnnotation(int index) { + final PdfDictionary dictionary = + PdfPageHelper.getHelper(page).terminalAnnotation[index]; + final PdfCrossTable? crossTable = PdfPageHelper.getHelper(page).crossTable; + PdfAnnotation? annot; + if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName name = + PdfAnnotationHelper.getValue( + dictionary, + crossTable, + PdfDictionaryProperties.subtype, + true, + )! + as PdfName; + final PdfAnnotationTypes type = getAnnotationType( + name, + dictionary, + crossTable, + ); + final PdfArray? rectValue = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.rect]) + as PdfArray?; + if (rectValue != null) { + String text = ''; + if (dictionary.containsKey(PdfDictionaryProperties.contents)) { + final IPdfPrimitive? str = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.contents], + ); + if (str != null && str is PdfString) { + text = str.value.toString(); + } + } + switch (type) { + case PdfAnnotationTypes.documentLinkAnnotation: + annot = _createDocumentLinkAnnotation(dictionary, crossTable!); + break; + case PdfAnnotationTypes.linkAnnotation: + if (dictionary.containsKey(PdfDictionaryProperties.a)) { + final PdfDictionary? remoteLinkDic = + PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.a], + ) + as PdfDictionary?; + if (remoteLinkDic != null && + remoteLinkDic.containsKey(PdfDictionaryProperties.s)) { + PdfName? gotor; + gotor = + PdfCrossTable.dereference( + remoteLinkDic[PdfDictionaryProperties.s], + ) + as PdfName?; + if (gotor != null && gotor.name == 'URI') { + annot = _createLinkAnnotation(dictionary, crossTable!, text); + } + } + } else { + annot = _createLinkAnnotation(dictionary, crossTable!, text); + } + break; + case PdfAnnotationTypes.lineAnnotation: + annot = _createLineAnnotation(dictionary, crossTable!, text); + break; + case PdfAnnotationTypes.circleAnnotation: + annot = _createEllipseAnnotation(dictionary, crossTable!, text); + break; + case PdfAnnotationTypes.rectangleAnnotation: + annot = _createRectangleAnnotation(dictionary, crossTable!, text); + break; + case PdfAnnotationTypes.polygonAnnotation: + annot = _createPolygonAnnotation(dictionary, crossTable!, text); + break; + case PdfAnnotationTypes.textWebLinkAnnotation: + annot = _createTextWebLinkAnnotation(dictionary, crossTable!, text); + break; + case PdfAnnotationTypes.widgetAnnotation: + annot = _createWidgetAnnotation(dictionary, crossTable!); + break; + case PdfAnnotationTypes.highlight: + case PdfAnnotationTypes.squiggly: + case PdfAnnotationTypes.strikeOut: + case PdfAnnotationTypes.underline: + annot = _createMarkupAnnotation(dictionary, crossTable!); + break; + case PdfAnnotationTypes.popupAnnotation: + annot = _createPopupAnnotation(dictionary, crossTable!, text); + break; + // ignore: no_default_cases + default: + break; + } + return annot; + } else { + return annot; + } + } + return annot; + } + + /// Gets the type of the annotation. + static PdfAnnotationTypes getAnnotationType( + PdfName name, + PdfDictionary dictionary, + PdfCrossTable? crossTable, + ) { + final String str = name.name!; + PdfAnnotationTypes type = PdfAnnotationTypes.noAnnotation; + switch (str.toLowerCase()) { + case 'link': + PdfDictionary? linkDic; + if (dictionary.containsKey(PdfDictionaryProperties.a)) { + linkDic = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.a]) + as PdfDictionary?; + } + if (linkDic != null && linkDic.containsKey(PdfDictionaryProperties.s)) { + name = + PdfCrossTable.dereference(linkDic[PdfDictionaryProperties.s])! + as PdfName; + final PdfArray? border = + (PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.border], + ) + is PdfArray) + ? PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.border], + ) + as PdfArray? + : null; + final bool mType = _findAnnotation(border); + if (name.name == 'URI') { + type = PdfAnnotationTypes.linkAnnotation; + if (!mType) { + type = PdfAnnotationTypes.linkAnnotation; + } else { + type = PdfAnnotationTypes.textWebLinkAnnotation; + } + } else if (name.name == 'GoToR') { + type = PdfAnnotationTypes.linkAnnotation; + } else if (name.name == 'GoTo') { + type = PdfAnnotationTypes.documentLinkAnnotation; + } + } else if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName? strText = + PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.subtype], + ) + as PdfName?; + if (strText != null) { + switch (strText.name) { + case 'Link': + type = PdfAnnotationTypes.documentLinkAnnotation; + break; + } + } + } + break; + case 'line': + type = PdfAnnotationTypes.lineAnnotation; + break; + case 'circle': + type = PdfAnnotationTypes.circleAnnotation; + break; + case 'square': + type = PdfAnnotationTypes.rectangleAnnotation; + break; + case 'polygon': + type = PdfAnnotationTypes.polygonAnnotation; + break; + case 'widget': + type = PdfAnnotationTypes.widgetAnnotation; + break; + case 'highlight': + type = PdfAnnotationTypes.highlight; + break; + case 'underline': + type = PdfAnnotationTypes.underline; + break; + case 'strikeout': + type = PdfAnnotationTypes.strikeOut; + break; + case 'squiggly': + type = PdfAnnotationTypes.squiggly; + break; + case 'text': + if (!dictionary.containsKey(PdfDictionaryProperties.irt)) { + type = PdfAnnotationTypes.popupAnnotation; + } + break; + default: + break; + } + return type; + } + + // Creates the file link annotation. + PdfAnnotation _createDocumentLinkAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final PdfAnnotation annot = PdfDocumentLinkAnnotationHelper.load( + dictionary, + crossTable, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + PdfAnnotationHelper.getHelper(annot).page = page; + return annot; + } + + PdfAnnotation _createLinkAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + final PdfAnnotation annot = PdfUriAnnotationHelper.load( + dictionary, + crossTable, + text, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + return annot; + } + + // Creates the Line Annotation. + PdfAnnotation _createLineAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + final PdfAnnotation annot = PdfLineAnnotationHelper.load( + dictionary, + crossTable, + text, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + PdfAnnotationHelper.getHelper(annot).page = page; + return annot; + } + + // Creates the Ellipse Annotation. + PdfAnnotation _createEllipseAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + final PdfAnnotation annot = PdfEllipseAnnotationHelper.load( + dictionary, + crossTable, + text, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + PdfAnnotationHelper.getHelper(annot).page = page; + return annot; + } + + // Creates the Rectangle Annotation. + PdfAnnotation _createRectangleAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + final PdfAnnotation annot = PdfRectangleAnnotationHelper.load( + dictionary, + crossTable, + text, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + PdfAnnotationHelper.getHelper(annot).page = page; + return annot; + } + + // Creates the Polygon Annotation. + PdfAnnotation _createPolygonAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + final PdfAnnotation annot = PdfPolygonAnnotationHelper.load( + dictionary, + crossTable, + text, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + PdfAnnotationHelper.getHelper(annot).page = page; + return annot; + } + + PdfAnnotation _createTextWebLinkAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + final PdfAnnotation annot = PdfTextWebLinkHelper.load( + dictionary, + crossTable, + text, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + return annot; + } + + //Creates the widget annotation. + PdfAnnotation _createWidgetAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final PdfAnnotation annot = WidgetAnnotationHelper.load( + dictionary, + crossTable, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + return annot; + } + + /// Creates the Markup Annotation. + PdfAnnotation _createMarkupAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final PdfAnnotation annot = PdfTextMarkupAnnotationHelper.load( + dictionary, + crossTable, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + return annot; + } + + PdfAnnotation _createPopupAnnotation( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + final PdfAnnotation annot = PdfPopupAnnotationHelper.load( + dictionary, + crossTable, + text, + ); + PdfAnnotationHelper.getHelper(annot).setPage(page); + return annot; + } + + static bool _findAnnotation(PdfArray? arr) { + if (arr == null) { + return false; + } + for (int i = 0; i < arr.count; i++) { + if (arr[i] is PdfArray) { + final PdfArray temp = arr[i]! as PdfArray; + for (int j = 0; j < temp.count; j++) { + final PdfNumber? value = + (temp[j] is PdfNumber) ? temp[j] as PdfNumber? : null; + int? val = 0; + if (value != null) { + val = value.value?.toInt(); + } + if (val! > 0) { + return false; + } + } + } else { + int val = 0; + final PdfNumber? value = + (arr[i] is PdfNumber) ? arr[i] as PdfNumber? : null; + if (value != null) { + val = value.value!.toInt(); + } + if (val > 0) { + return false; + } + } + } + return true; + } + + /// internal method + bool contains(PdfAnnotation annotation) { + return list.contains(annotation); + } + + /// internal method + static PdfAnnotationCollectionHelper getHelper( + PdfAnnotationCollection annotationCollection, + ) { + return annotationCollection._helper; + } + + /// internal method + static PdfAnnotationCollection load(PdfPage page) { + return PdfAnnotationCollection._(page); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_appearance.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_appearance.dart index 7bd34408c..142a5a81e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_appearance.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_appearance.dart @@ -1,97 +1,97 @@ -import '../../interfaces/pdf_interface.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'pdf_annotation.dart'; - -/// Represents the appearance of an annotation. -class PdfAppearance implements IPdfWrapper { - // Constructor - /// Initializes a instance of the [PdfAppearance] class. - PdfAppearance(PdfAnnotation annotation) : super() { - _annotation = annotation; - } - - // Fields - final PdfAppearanceHelper _helper = PdfAppearanceHelper(); - late PdfAnnotation _annotation; - - // Properties - /// Gets PdfTmplate object which applied to annotation in normal state. - PdfTemplate get normal { - if (_helper.templateNormal == null) { - _helper.templateNormal = PdfTemplate( - _annotation.bounds.size.width, - _annotation.bounds.size.height, - ); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.n, - PdfReferenceHolder(_helper.templateNormal), - ); - } - return _helper.templateNormal!; - } - - /// Sets PdfTmplate object which applied to annotation in normal state. - set normal(PdfTemplate value) { - if (_helper.templateNormal != value) { - _helper.templateNormal = value; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.n, - PdfReferenceHolder(_helper.templateNormal), - ); - } - } - - /// Gets or sets [PdfTemplate] object which applied to an annotation when mouse button is pressed. - PdfTemplate get pressed { - if (_helper.templatePressed == null) { - _helper.templatePressed = PdfTemplate( - _annotation.bounds.width, - _annotation.bounds.height, - ); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.d, - PdfReferenceHolder(_helper.templatePressed), - ); - } - return _helper.templatePressed!; - } - - set pressed(PdfTemplate value) { - if (value != _helper.templatePressed) { - _helper.templatePressed = value; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.d, - PdfReferenceHolder(_helper.templatePressed), - ); - } - } -} - -/// [PdfAppearance] helper -class PdfAppearanceHelper { - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal field - PdfTemplate? templateNormal; - - /// internal field - PdfTemplate? templatePressed; - - /// internal property - IPdfPrimitive? get element => dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } - - /// internal method - static PdfAppearanceHelper getHelper(PdfAppearance appearance) { - return appearance._helper; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'pdf_annotation.dart'; + +/// Represents the appearance of an annotation. +class PdfAppearance implements IPdfWrapper { + // Constructor + /// Initializes a instance of the [PdfAppearance] class. + PdfAppearance(PdfAnnotation annotation) : super() { + _annotation = annotation; + } + + // Fields + final PdfAppearanceHelper _helper = PdfAppearanceHelper(); + late PdfAnnotation _annotation; + + // Properties + /// Gets PdfTmplate object which applied to annotation in normal state. + PdfTemplate get normal { + if (_helper.templateNormal == null) { + _helper.templateNormal = PdfTemplate( + _annotation.bounds.size.width, + _annotation.bounds.size.height, + ); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.n, + PdfReferenceHolder(_helper.templateNormal), + ); + } + return _helper.templateNormal!; + } + + /// Sets PdfTmplate object which applied to annotation in normal state. + set normal(PdfTemplate value) { + if (_helper.templateNormal != value) { + _helper.templateNormal = value; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.n, + PdfReferenceHolder(_helper.templateNormal), + ); + } + } + + /// Gets or sets [PdfTemplate] object which applied to an annotation when mouse button is pressed. + PdfTemplate get pressed { + if (_helper.templatePressed == null) { + _helper.templatePressed = PdfTemplate( + _annotation.bounds.width, + _annotation.bounds.height, + ); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.d, + PdfReferenceHolder(_helper.templatePressed), + ); + } + return _helper.templatePressed!; + } + + set pressed(PdfTemplate value) { + if (value != _helper.templatePressed) { + _helper.templatePressed = value; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.d, + PdfReferenceHolder(_helper.templatePressed), + ); + } + } +} + +/// [PdfAppearance] helper +class PdfAppearanceHelper { + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal field + PdfTemplate? templateNormal; + + /// internal field + PdfTemplate? templatePressed; + + /// internal property + IPdfPrimitive? get element => dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } + + /// internal method + static PdfAppearanceHelper getHelper(PdfAppearance appearance) { + return appearance._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_document_link_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_document_link_annotation.dart index 79f1c428b..6abff64d3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_document_link_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_document_link_annotation.dart @@ -1,341 +1,341 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../general/enum.dart'; -import '../general/pdf_destination.dart'; -import '../graphics/pdf_color.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_collection.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_action_annotation.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_border.dart'; - -/// Represents an annotation object with holds link on -/// another location within a document. -/// ```dart -/// //Create a new Pdf document -/// PdfDocument document = PdfDocument(); -/// //Create a document link and add to the PDF page. -/// document.pages.add().annotations.add(PdfDocumentLinkAnnotation( -/// Rect.fromLTWH(10, 40, 30, 30), -/// PdfDestination(document.pages.add(), Offset(10, 0)))); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfDocumentLinkAnnotation extends PdfLinkAnnotation { - // constructor - /// Initializes new [PdfDocumentLinkAnnotation] instance - /// with specified bounds and destination. - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create a document link and add to the PDF page. - /// document.pages.add().annotations.add(PdfDocumentLinkAnnotation( - /// Rect.fromLTWH(10, 40, 30, 30), - /// PdfDestination(document.pages.add(), Offset(10, 0)))); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfDocumentLinkAnnotation(Rect bounds, PdfDestination destination) { - _helper = PdfDocumentLinkAnnotationHelper(this, bounds); - this.destination = destination; - } - - PdfDocumentLinkAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - _helper = PdfDocumentLinkAnnotationHelper._(this, dictionary, crossTable); - } - - // fields - late PdfDocumentLinkAnnotationHelper _helper; - - // properties - /// Gets or sets the destination of the annotation. - /// - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create PDF page. - /// PdfPage page = document.pages.add(); - /// //Create a document link - /// PdfDocumentLinkAnnotation documentLinkAnnotation = PdfDocumentLinkAnnotation( - /// Rect.fromLTWH(10, 40, 30, 30), - /// PdfDestination(document.pages.add(), Offset(10, 0))); - /// //Gets the destination and set the destination mode. - /// documentLinkAnnotation.destination!.mode = PdfDestinationMode.fitToPage; - /// //Add the document link to the page - /// page.annotations.add(documentLinkAnnotation); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfDestination? get destination => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _obtainDestination() - : _helper.destination; - set destination(PdfDestination? value) { - if (value != null) { - if (value != _helper.destination) { - _helper.destination = value; - } - if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { - PdfAnnotationHelper.getHelper( - this, - ).dictionary!.setProperty(PdfDictionaryProperties.dest, value); - } - } - } - - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - return _helper.border; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - _helper.border = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } - - // Gets the destination of the document link annotation - PdfDestination? _obtainDestination() { - PdfDestination? dest; - final PdfDictionary dictionary = - PdfAnnotationHelper.getHelper(this).dictionary!; - final PdfCrossTable crossTable = - PdfAnnotationHelper.getHelper(this).crossTable; - if (dictionary.containsKey(PdfDictionaryProperties.dest)) { - final IPdfPrimitive? obj = crossTable.getObject( - dictionary[PdfDictionaryProperties.dest], - ); - PdfArray? array; - if (obj is PdfArray) { - array = obj; - } else if (crossTable.document != null && - PdfDocumentHelper.getHelper(crossTable.document!).isLoadedDocument) { - if (obj is PdfName || obj is PdfString) { - array = PdfDocumentHelper.getHelper( - crossTable.document!, - ).getNamedDestination(obj!); - } - } - PdfPage page; - if (array != null && array[0] is PdfReferenceHolder) { - final PdfDictionary? dic = - crossTable.getObject(array[0]! as PdfReferenceHolder) - as PdfDictionary?; - page = PdfPageCollectionHelper.getHelper( - crossTable.document!.pages, - ).getPage(dic); - final PdfName? mode = array[1] as PdfName?; - if (mode != null) { - if (mode.name == 'XYZ') { - PdfNumber? left; - PdfNumber? top; - PdfNumber? zoom; - if (array[2] is PdfNumber) { - left = array[2]! as PdfNumber; - } - if (array[3] is PdfNumber) { - top = array[3]! as PdfNumber; - } - if (array[4] is PdfNumber) { - zoom = array[4]! as PdfNumber; - } - final double topValue = - (top == null) ? 0 : page.size.height - (top.value!.toDouble()); - final double leftValue = - (left == null) ? 0 : left.value!.toDouble(); - dest = PdfDestination(page, Offset(leftValue, topValue)); - if (zoom != null) { - dest.zoom = zoom.value!.toDouble(); - } - dest.mode = PdfDestinationMode.location; - } else if (mode.name == 'Fit' || mode.name == 'FitV') { - dest = PdfDestination(page); - dest.mode = PdfDestinationMode.fitToPage; - } else if (mode.name == 'FitH') { - late PdfNumber top; - if (array[2] is PdfNumber) { - top = array[2]! as PdfNumber; - } - final double topValue = page.size.height - top.value!; - dest = PdfDestination(page, Offset(0, topValue)); - dest.mode = PdfDestinationMode.fitH; - } else if (mode.name == 'FitR') { - if (array.count == 6) { - final double left = (array[2]! as PdfNumber).value!.toDouble(); - final double top = (array[3]! as PdfNumber).value!.toDouble(); - final double width = (array[4]! as PdfNumber).value!.toDouble(); - final double height = (array[5]! as PdfNumber).value!.toDouble(); - dest = PdfDestinationHelper.getDestination( - page, - PdfRectangle(left, top, width, height), - ); - dest.mode = PdfDestinationMode.fitR; - } - } - } - } - } else if (dictionary.containsKey(PdfDictionaryProperties.a)) { - IPdfPrimitive obj = - crossTable.getObject(dictionary[PdfDictionaryProperties.a])!; - final PdfDictionary destDic = obj as PdfDictionary; - obj = destDic[PdfDictionaryProperties.d]!; - if (obj is PdfReferenceHolder) { - obj = obj.object!; - } - PdfArray? array; - if (obj is PdfArray) { - array = obj; - } else if (crossTable.document != null && - PdfDocumentHelper.getHelper(crossTable.document!).isLoadedDocument) { - if (obj is PdfName || obj is PdfString) { - array = PdfDocumentHelper.getHelper( - crossTable.document!, - ).getNamedDestination(obj); - } - } - if (array != null && array[0] is PdfReferenceHolder) { - final PdfReferenceHolder holder = array[0]! as PdfReferenceHolder; - PdfPage? page; - final IPdfPrimitive? primitiveObj = PdfCrossTable.dereference(holder); - final PdfDictionary? dic = primitiveObj as PdfDictionary?; - if (dic != null) { - page = PdfPageCollectionHelper.getHelper( - crossTable.document!.pages, - ).getPage(dic); - } - if (page != null) { - final PdfName mode = array[1]! as PdfName; - if (mode.name == 'FitBH' || mode.name == 'FitH') { - PdfNumber? top; - if (array[2] is PdfNumber) { - top = array[2]! as PdfNumber; - } - final double topValue = - (top == null) ? 0 : page.size.height - (top.value!.toDouble()); - dest = PdfDestination(page, Offset(0, topValue)); - dest.mode = PdfDestinationMode.fitH; - } else if (mode.name == 'XYZ') { - PdfNumber? left; - PdfNumber? top; - PdfNumber? zoom; - if (array[2] is PdfNumber) { - left = array[2]! as PdfNumber; - } - if (array[3] is PdfNumber) { - top = array[3]! as PdfNumber; - } - if (array[4] is PdfNumber) { - zoom = array[4]! as PdfNumber; - } - final double topValue = - (top == null) ? 0 : page.size.height - (top.value!.toDouble()); - final double leftValue = - (left == null) ? 0 : left.value!.toDouble(); - dest = PdfDestination(page, Offset(leftValue, topValue)); - if (zoom != null) { - dest.zoom = zoom.value!.toDouble(); - } - dest.mode = PdfDestinationMode.location; - } else if (mode.name == 'FitR') { - if (array.count == 6) { - final PdfNumber left = array[2]! as PdfNumber; - final PdfNumber bottom = array[3]! as PdfNumber; - final PdfNumber right = array[4]! as PdfNumber; - final PdfNumber top = array[5]! as PdfNumber; - dest = PdfDestinationHelper.getDestination( - page, - PdfRectangle( - left.value!.toDouble(), - bottom.value!.toDouble(), - right.value!.toDouble(), - top.value!.toDouble(), - ), - ); - dest.mode = PdfDestinationMode.fitR; - } - } else { - if (mode.name == 'Fit' || mode.name == 'FitV') { - dest = PdfDestination(page); - dest.mode = PdfDestinationMode.fitToPage; - } - } - } - } - } - return dest; - } -} - -/// [PdfDocumentLinkAnnotation] helper -class PdfDocumentLinkAnnotationHelper extends PdfLinkAnnotationHelper { - /// internal constructor - PdfDocumentLinkAnnotationHelper(this.documentLinkHelper, Rect bounds) - : super(documentLinkHelper, bounds); - PdfDocumentLinkAnnotationHelper._( - this.documentLinkHelper, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super.load(documentLinkHelper, dictionary, crossTable); - - /// internal field - PdfDocumentLinkAnnotation documentLinkHelper; - - /// internal field - PdfDestination? destination; - - /// internal field - @override - IPdfPrimitive? element; - - /// internal method - void save() { - if (destination != null) { - PdfAnnotationHelper.getHelper(base).dictionary!.setProperty( - PdfName(PdfDictionaryProperties.dest), - IPdfWrapper.getElement(destination!), - ); - } - } - - /// internal method - static PdfDocumentLinkAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfDocumentLinkAnnotation._(dictionary, crossTable); - } - - /// internal method - static PdfDocumentLinkAnnotationHelper getHelper( - PdfDocumentLinkAnnotation annotation, - ) { - return annotation._helper; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../general/enum.dart'; +import '../general/pdf_destination.dart'; +import '../graphics/pdf_color.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_collection.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_action_annotation.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_border.dart'; + +/// Represents an annotation object with holds link on +/// another location within a document. +/// ```dart +/// //Create a new Pdf document +/// PdfDocument document = PdfDocument(); +/// //Create a document link and add to the PDF page. +/// document.pages.add().annotations.add(PdfDocumentLinkAnnotation( +/// Rect.fromLTWH(10, 40, 30, 30), +/// PdfDestination(document.pages.add(), Offset(10, 0)))); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfDocumentLinkAnnotation extends PdfLinkAnnotation { + // constructor + /// Initializes new [PdfDocumentLinkAnnotation] instance + /// with specified bounds and destination. + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create a document link and add to the PDF page. + /// document.pages.add().annotations.add(PdfDocumentLinkAnnotation( + /// Rect.fromLTWH(10, 40, 30, 30), + /// PdfDestination(document.pages.add(), Offset(10, 0)))); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfDocumentLinkAnnotation(Rect bounds, PdfDestination destination) { + _helper = PdfDocumentLinkAnnotationHelper(this, bounds); + this.destination = destination; + } + + PdfDocumentLinkAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + _helper = PdfDocumentLinkAnnotationHelper._(this, dictionary, crossTable); + } + + // fields + late PdfDocumentLinkAnnotationHelper _helper; + + // properties + /// Gets or sets the destination of the annotation. + /// + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create PDF page. + /// PdfPage page = document.pages.add(); + /// //Create a document link + /// PdfDocumentLinkAnnotation documentLinkAnnotation = PdfDocumentLinkAnnotation( + /// Rect.fromLTWH(10, 40, 30, 30), + /// PdfDestination(document.pages.add(), Offset(10, 0))); + /// //Gets the destination and set the destination mode. + /// documentLinkAnnotation.destination!.mode = PdfDestinationMode.fitToPage; + /// //Add the document link to the page + /// page.annotations.add(documentLinkAnnotation); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfDestination? get destination => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _obtainDestination() + : _helper.destination; + set destination(PdfDestination? value) { + if (value != null) { + if (value != _helper.destination) { + _helper.destination = value; + } + if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { + PdfAnnotationHelper.getHelper( + this, + ).dictionary!.setProperty(PdfDictionaryProperties.dest, value); + } + } + } + + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + return _helper.border; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + _helper.border = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } + + // Gets the destination of the document link annotation + PdfDestination? _obtainDestination() { + PdfDestination? dest; + final PdfDictionary dictionary = + PdfAnnotationHelper.getHelper(this).dictionary!; + final PdfCrossTable crossTable = + PdfAnnotationHelper.getHelper(this).crossTable; + if (dictionary.containsKey(PdfDictionaryProperties.dest)) { + final IPdfPrimitive? obj = crossTable.getObject( + dictionary[PdfDictionaryProperties.dest], + ); + PdfArray? array; + if (obj is PdfArray) { + array = obj; + } else if (crossTable.document != null && + PdfDocumentHelper.getHelper(crossTable.document!).isLoadedDocument) { + if (obj is PdfName || obj is PdfString) { + array = PdfDocumentHelper.getHelper( + crossTable.document!, + ).getNamedDestination(obj!); + } + } + PdfPage page; + if (array != null && array[0] is PdfReferenceHolder) { + final PdfDictionary? dic = + crossTable.getObject(array[0]! as PdfReferenceHolder) + as PdfDictionary?; + page = PdfPageCollectionHelper.getHelper( + crossTable.document!.pages, + ).getPage(dic); + final PdfName? mode = array[1] as PdfName?; + if (mode != null) { + if (mode.name == 'XYZ') { + PdfNumber? left; + PdfNumber? top; + PdfNumber? zoom; + if (array[2] is PdfNumber) { + left = array[2]! as PdfNumber; + } + if (array[3] is PdfNumber) { + top = array[3]! as PdfNumber; + } + if (array[4] is PdfNumber) { + zoom = array[4]! as PdfNumber; + } + final double topValue = + (top == null) ? 0 : page.size.height - (top.value!.toDouble()); + final double leftValue = + (left == null) ? 0 : left.value!.toDouble(); + dest = PdfDestination(page, Offset(leftValue, topValue)); + if (zoom != null) { + dest.zoom = zoom.value!.toDouble(); + } + dest.mode = PdfDestinationMode.location; + } else if (mode.name == 'Fit' || mode.name == 'FitV') { + dest = PdfDestination(page); + dest.mode = PdfDestinationMode.fitToPage; + } else if (mode.name == 'FitH') { + late PdfNumber top; + if (array[2] is PdfNumber) { + top = array[2]! as PdfNumber; + } + final double topValue = page.size.height - top.value!; + dest = PdfDestination(page, Offset(0, topValue)); + dest.mode = PdfDestinationMode.fitH; + } else if (mode.name == 'FitR') { + if (array.count == 6) { + final double left = (array[2]! as PdfNumber).value!.toDouble(); + final double top = (array[3]! as PdfNumber).value!.toDouble(); + final double width = (array[4]! as PdfNumber).value!.toDouble(); + final double height = (array[5]! as PdfNumber).value!.toDouble(); + dest = PdfDestinationHelper.getDestination( + page, + PdfRectangle(left, top, width, height), + ); + dest.mode = PdfDestinationMode.fitR; + } + } + } + } + } else if (dictionary.containsKey(PdfDictionaryProperties.a)) { + IPdfPrimitive obj = + crossTable.getObject(dictionary[PdfDictionaryProperties.a])!; + final PdfDictionary destDic = obj as PdfDictionary; + obj = destDic[PdfDictionaryProperties.d]!; + if (obj is PdfReferenceHolder) { + obj = obj.object!; + } + PdfArray? array; + if (obj is PdfArray) { + array = obj; + } else if (crossTable.document != null && + PdfDocumentHelper.getHelper(crossTable.document!).isLoadedDocument) { + if (obj is PdfName || obj is PdfString) { + array = PdfDocumentHelper.getHelper( + crossTable.document!, + ).getNamedDestination(obj); + } + } + if (array != null && array[0] is PdfReferenceHolder) { + final PdfReferenceHolder holder = array[0]! as PdfReferenceHolder; + PdfPage? page; + final IPdfPrimitive? primitiveObj = PdfCrossTable.dereference(holder); + final PdfDictionary? dic = primitiveObj as PdfDictionary?; + if (dic != null) { + page = PdfPageCollectionHelper.getHelper( + crossTable.document!.pages, + ).getPage(dic); + } + if (page != null) { + final PdfName mode = array[1]! as PdfName; + if (mode.name == 'FitBH' || mode.name == 'FitH') { + PdfNumber? top; + if (array[2] is PdfNumber) { + top = array[2]! as PdfNumber; + } + final double topValue = + (top == null) ? 0 : page.size.height - (top.value!.toDouble()); + dest = PdfDestination(page, Offset(0, topValue)); + dest.mode = PdfDestinationMode.fitH; + } else if (mode.name == 'XYZ') { + PdfNumber? left; + PdfNumber? top; + PdfNumber? zoom; + if (array[2] is PdfNumber) { + left = array[2]! as PdfNumber; + } + if (array[3] is PdfNumber) { + top = array[3]! as PdfNumber; + } + if (array[4] is PdfNumber) { + zoom = array[4]! as PdfNumber; + } + final double topValue = + (top == null) ? 0 : page.size.height - (top.value!.toDouble()); + final double leftValue = + (left == null) ? 0 : left.value!.toDouble(); + dest = PdfDestination(page, Offset(leftValue, topValue)); + if (zoom != null) { + dest.zoom = zoom.value!.toDouble(); + } + dest.mode = PdfDestinationMode.location; + } else if (mode.name == 'FitR') { + if (array.count == 6) { + final PdfNumber left = array[2]! as PdfNumber; + final PdfNumber bottom = array[3]! as PdfNumber; + final PdfNumber right = array[4]! as PdfNumber; + final PdfNumber top = array[5]! as PdfNumber; + dest = PdfDestinationHelper.getDestination( + page, + PdfRectangle( + left.value!.toDouble(), + bottom.value!.toDouble(), + right.value!.toDouble(), + top.value!.toDouble(), + ), + ); + dest.mode = PdfDestinationMode.fitR; + } + } else { + if (mode.name == 'Fit' || mode.name == 'FitV') { + dest = PdfDestination(page); + dest.mode = PdfDestinationMode.fitToPage; + } + } + } + } + } + return dest; + } +} + +/// [PdfDocumentLinkAnnotation] helper +class PdfDocumentLinkAnnotationHelper extends PdfLinkAnnotationHelper { + /// internal constructor + PdfDocumentLinkAnnotationHelper(this.documentLinkHelper, Rect bounds) + : super(documentLinkHelper, bounds); + PdfDocumentLinkAnnotationHelper._( + this.documentLinkHelper, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super.load(documentLinkHelper, dictionary, crossTable); + + /// internal field + PdfDocumentLinkAnnotation documentLinkHelper; + + /// internal field + PdfDestination? destination; + + /// internal field + @override + IPdfPrimitive? element; + + /// internal method + void save() { + if (destination != null) { + PdfAnnotationHelper.getHelper(base).dictionary!.setProperty( + PdfName(PdfDictionaryProperties.dest), + IPdfWrapper.getElement(destination!), + ); + } + } + + /// internal method + static PdfDocumentLinkAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfDocumentLinkAnnotation._(dictionary, crossTable); + } + + /// internal method + static PdfDocumentLinkAnnotationHelper getHelper( + PdfDocumentLinkAnnotation annotation, + ) { + return annotation._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_ellipse_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_ellipse_annotation.dart index fc78ded91..ddc125f22 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_ellipse_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_ellipse_annotation.dart @@ -1,606 +1,606 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/pdf_annotation_border.dart'; -import '../drawing/drawing.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_path.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_collection.dart'; -import 'pdf_appearance.dart'; -import 'pdf_paintparams.dart'; - -/// Represents a PDF ellipse annotation -class PdfEllipseAnnotation extends PdfAnnotation { - // Constructor - /// Initializes new instance of the [PdfEllipseAnnotation] class. - /// ``` dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a page. - /// PdfPage page = document.pages.add(); - /// //Create a PDF Ellipse annotation. - /// PdfEllipseAnnotation ellipseAnnotation = PdfEllipseAnnotation( - /// const Rect.fromLTWH(0, 30, 100, 50), 'EllipseAnnotation', - /// innerColor: PdfColor(255, 0, 0), color: PdfColor(255, 255, 0)); - /// //Add annotation to the page. - /// page.annotations.add(ellipseAnnotation); - /// //Saves the document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfEllipseAnnotation( - Rect bounds, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - DateTime? modifiedDate, - double? opacity, - List? flags, - bool? setAppearance, - }) { - _helper = PdfEllipseAnnotationHelper( - this, - bounds, - text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - } - - PdfEllipseAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - _helper = PdfEllipseAnnotationHelper._(this, dictionary, crossTable); - this.text = text; - } - - // fields - late PdfEllipseAnnotationHelper _helper; - - // properties - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - return _helper.border; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - _helper.border = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } - - /// Gets the inner color of the annotation. - PdfColor get innerColor => _helper.innerColor; - - /// Sets the inner color of the annotation. - set innerColor(PdfColor value) { - _helper.innerColor = value; - } - - IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; - set _element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - PdfAnnotationHelper.getHelper(this).dictionary = value; - } - } -} - -/// [PdfEllipseAnnotation] helper -class PdfEllipseAnnotationHelper extends PdfAnnotationHelper { - /// internal constructor - PdfEllipseAnnotationHelper( - this.annotation, - Rect bounds, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - DateTime? modifiedDate, - double? opacity, - List? flags, - bool? setAppearance, - }) : super(annotation) { - initializeAnnotation( - bounds: bounds, - text: text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(PdfDictionaryProperties.circle), - ); - } - - PdfEllipseAnnotationHelper._( - this.annotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super(annotation) { - initializeExistingAnnotation(dictionary, crossTable); - } - - /// internal field - late PdfEllipseAnnotation annotation; - - /// internal method - void save() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - if (PdfAnnotationCollectionHelper.getHelper( - annotation.page!.annotations, - ).flatten) { - helper.flatten = true; - } - final PdfAppearance? pdfAppearance = helper.appearance; - final bool isLoadedAnnotation = helper.isLoadedAnnotation; - if (helper.flatten || annotation.setAppearance || pdfAppearance != null) { - PdfTemplate? appearance; - if (pdfAppearance != null) { - appearance = pdfAppearance.normal; - } else { - appearance = _createAppearance(); - } - if (helper.flatten) { - if (appearance != null || isLoadedAnnotation) { - if (annotation.page != null) { - _flattenAnnotation(annotation.page, appearance); - } - } - } else { - if (appearance != null) { - annotation.appearance.normal = appearance; - helper.dictionary!.setProperty( - PdfDictionaryProperties.ap, - PdfReferenceHolder(annotation.appearance), - ); - } - } - } - if (!helper.flatten && !isLoadedAnnotation) { - helper.saveAnnotation(); - helper.dictionary!.setProperty( - PdfDictionaryProperties.bs, - annotation.border, - ); - } - if (helper.flattenPopups) { - helper.flattenPopup(); - } - } - - void _flattenAnnotation(PdfPage? page, PdfTemplate? appearance) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - if (helper.isLoadedAnnotation) { - final bool isContainsAP = helper.dictionary!.containsKey( - PdfDictionaryProperties.ap, - ); - if (appearance == null) { - if (isContainsAP) { - PdfDictionary? appearanceDictionary = - PdfCrossTable.dereference( - helper.dictionary![PdfDictionaryProperties.ap], - ) - as PdfDictionary?; - if (appearanceDictionary != null) { - appearanceDictionary = - PdfCrossTable.dereference( - appearanceDictionary[PdfDictionaryProperties.n], - ) - as PdfDictionary?; - if (appearanceDictionary != null) { - final PdfStream appearanceStream = - appearanceDictionary as PdfStream; - appearance = PdfTemplateHelper.fromPdfStream(appearanceStream); - final bool isNormalMatrix = helper.validateTemplateMatrix( - appearanceDictionary, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } else { - annotation.setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } - } - } else { - annotation.setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } - } else { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } else { - page!.graphics.save(); - final Rect rectangle = helper.calculateTemplateBounds( - annotation.bounds, - page, - appearance, - true, - ); - if (annotation.opacity < 1) { - page.graphics.setTransparency(annotation.opacity); - } - page.graphics.drawPdfTemplate( - appearance!, - Offset(rectangle.left, rectangle.top), - rectangle.size, - ); - page.annotations.remove(annotation); - page.graphics.restore(); - } - } - - PdfTemplate? _createAppearance() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - final bool isLoadedAnnotation = helper.isLoadedAnnotation; - if (isLoadedAnnotation && !annotation.setAppearance) { - return null; - } - final PdfRectangle nativeRectangle = PdfRectangle( - 0, - 0, - annotation.bounds.width, - annotation.bounds.height, - ); - final PdfTemplate template = PdfTemplateHelper.fromRect( - nativeRectangle.rect, - ); - PdfAnnotationHelper.setMatrixToZeroRotation( - PdfTemplateHelper.getHelper(template).content, - ); - if (isLoadedAnnotation && - helper.dictionary!.containsKey(PdfDictionaryProperties.be)) { - PdfTemplateHelper.getHelper(template).writeTransformation = false; - } - final PaintParams paintParams = PaintParams(); - final double borderWidth = annotation.border.width / 2; - final PdfPen mBorderPen = PdfPen( - annotation.color, - width: annotation.border.width, - ); - if (annotation.border.width > 0 && - PdfColorHelper.getHelper(annotation.color).alpha != 0) { - paintParams.borderPen = mBorderPen; - } - PdfBrush? mBackBrush; - if (PdfColorHelper.getHelper(annotation.color).alpha != 0) { - mBackBrush = PdfSolidBrush(annotation.innerColor); - } - paintParams.foreBrush = PdfSolidBrush(annotation.color); - paintParams.backBrush = mBackBrush; - final PdfGraphics? graphics = template.graphics; - if (annotation.opacity < 1) { - graphics!.save(); - graphics.setTransparency(annotation.opacity); - } - if (isLoadedAnnotation) { - final PdfRectangle rectangle = _obtainStyle( - mBorderPen, - nativeRectangle, - borderWidth, - ); - if (helper.dictionary!.containsKey(PdfDictionaryProperties.be)) { - _drawAppearance(rectangle, borderWidth, graphics, paintParams); - } else { - graphics!.drawEllipse( - Rect.fromLTWH( - rectangle.x + borderWidth, - rectangle.y, - rectangle.width - annotation.border.width, - rectangle.height, - ), - pen: paintParams.borderPen, - brush: paintParams.backBrush, - ); - } - } else { - final Rect rect = Rect.fromLTWH( - nativeRectangle.left, - nativeRectangle.top, - nativeRectangle.width, - nativeRectangle.height, - ); - graphics!.drawEllipse( - Rect.fromLTWH( - rect.left + borderWidth, - rect.top + borderWidth, - rect.width - annotation.border.width, - rect.height - annotation.border.width, - ), - pen: paintParams.borderPen, - brush: paintParams.backBrush, - ); - } - if (annotation.opacity < 1) { - graphics!.restore(); - } - return template; - } - - // Obtain Style for annotation - PdfRectangle _obtainStyle( - PdfPen mBorderPen, - PdfRectangle rectangle, - double borderWidth, - ) { - final PdfDictionary dictionary = - PdfAnnotationHelper.getHelper(annotation).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.bs)) { - final PdfDictionary? bSDictionary = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.bs]) - as PdfDictionary?; - - if (bSDictionary != null && - bSDictionary.containsKey(PdfDictionaryProperties.d)) { - final PdfArray dashPatternArray = - PdfCrossTable.dereference(bSDictionary[PdfDictionaryProperties.d])! - as PdfArray; - final List dashPattern = []; - for (int i = 0; i < dashPatternArray.count; i++) { - dashPattern.add( - (dashPatternArray.elements[i]! as PdfNumber).value!.toDouble(), - ); - } - mBorderPen.dashStyle = PdfDashStyle.dash; - mBorderPen.dashPattern = dashPattern; - } - } - if (!PdfAnnotationHelper.getHelper(annotation).isBounds && - dictionary[PdfDictionaryProperties.rd] != null) { - final PdfArray? mRdArray = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.rd]) - as PdfArray?; - if (mRdArray != null) { - final PdfNumber num1 = mRdArray.elements[0]! as PdfNumber; - final PdfNumber num2 = mRdArray.elements[1]! as PdfNumber; - final PdfNumber num3 = mRdArray.elements[2]! as PdfNumber; - final PdfNumber num4 = mRdArray.elements[3]! as PdfNumber; - rectangle.x += num1.value!; - rectangle.y += borderWidth + num2.value!; - rectangle.width = rectangle.width - (2 * num3.value!); - rectangle.height = rectangle.height - annotation.border.width; - rectangle.height = rectangle.height - (2 * num4.value!); - } - } else { - rectangle.y += borderWidth; - rectangle.height = annotation.bounds.height - annotation.border.width; - } - return rectangle; - } - - // Draw appearance for annotation - void _drawAppearance( - PdfRectangle rectangle, - double borderWidth, - PdfGraphics? graphics, - PaintParams paintParams, - ) { - final PdfPath graphicsPath = PdfPath(); - graphicsPath.addEllipse( - Rect.fromLTWH( - rectangle.x + borderWidth, - -rectangle.y - rectangle.height, - rectangle.width - annotation.border.width, - rectangle.height, - ), - ); - double? radius = 0; - if (PdfAnnotationHelper.getHelper( - annotation, - ).dictionary!.containsKey(PdfDictionaryProperties.rd)) { - final PdfArray? rdArray = - PdfCrossTable.dereference( - PdfAnnotationHelper.getHelper( - annotation, - ).dictionary!.items![PdfName(PdfDictionaryProperties.rd)], - ) - as PdfArray?; - if (rdArray != null) { - radius = (rdArray.elements[0]! as PdfNumber).value as double?; - } - } - if (radius! > 0) { - final PdfRectangle rect = PdfRectangle( - rectangle.x + borderWidth, - -rectangle.y - rectangle.height, - rectangle.width - annotation.border.width, - rectangle.height, - ); - final List startPointList = []; - final List controlPointList = []; - final List endPointList = []; - final List points = []; - - controlPointList.add(Offset(rect.right, rect.bottom)); - controlPointList.add(Offset(rect.left, rect.bottom)); - controlPointList.add(Offset(rect.left, rect.top)); - controlPointList.add(Offset(rect.right, rect.top)); - - startPointList.add(Offset(rect.right, rect.top + (rect.height / 2))); - startPointList.add(Offset(rect.left + rect.width / 2, rect.bottom)); - startPointList.add(Offset(rect.left, rect.top + (rect.height / 2))); - startPointList.add(Offset(rect.left + (rect.width / 2), rect.top)); - - endPointList.add(Offset(rect.left + rect.width / 2, rect.bottom)); - endPointList.add(Offset(rect.left, rect.top + (rect.height / 2))); - endPointList.add(Offset(rect.left + (rect.width / 2), rect.top)); - endPointList.add(Offset(rect.right, rect.top + (rect.height / 2))); - - for (int i = 0; i < controlPointList.length; i++) { - _createBezier( - startPointList[i], - controlPointList[i], - endPointList[i], - points, - ); - } - PdfAnnotationHelper.getHelper(annotation).drawCloudStyle( - graphics!, - paintParams.backBrush, - paintParams.borderPen, - radius, - 0.833, - points, - false, - ); - startPointList.clear(); - controlPointList.clear(); - endPointList.clear(); - points.clear(); - } else { - graphics!.drawEllipse( - Rect.fromLTWH( - rectangle.x + borderWidth, - -rectangle.y, - rectangle.width - annotation.border.width, - -rectangle.height, - ), - pen: paintParams.borderPen, - brush: paintParams.backBrush, - ); - } - } - - // Create bezier curve - void _createBezier( - Offset ctrl1, - Offset ctrl2, - Offset ctrl3, - List bezierPoints, - ) { - bezierPoints.add(ctrl1); // add the first control point - _populateBezierPoints(ctrl1, ctrl2, ctrl3, 0, bezierPoints); - bezierPoints.add(ctrl3); // add the last control point - } - - // calculate bezier points - void _populateBezierPoints( - Offset ctrl1, - Offset ctrl2, - Offset ctrl3, - int currentIteration, - List bezierPoints, - ) { - if (currentIteration < 2) { - //calculate next mid points - final Offset midPoint1 = Offset( - (ctrl1.dx + ctrl2.dx) / 2, - (ctrl1.dy + ctrl2.dy) / 2, - ); - final Offset midPoint2 = Offset( - (ctrl2.dx + ctrl3.dx) / 2, - (ctrl2.dy + ctrl3.dy) / 2, - ); - final Offset midPoint3 = Offset( - (midPoint1.dx + midPoint2.dx) / 2, - (midPoint1.dy + midPoint2.dy) / 2, - ); - //the next control point - currentIteration++; - _populateBezierPoints( - ctrl1, - midPoint1, - midPoint3, - currentIteration, - bezierPoints, - ); //left branch - bezierPoints.add(midPoint3); - //add the next control point - _populateBezierPoints( - midPoint3, - midPoint2, - ctrl3, - currentIteration, - bezierPoints, - ); //right branch - } - } - - /// internal property - @override - IPdfPrimitive? get element { - return annotation._element; - } - - @override - set element(IPdfPrimitive? element) { - annotation._element = element; - } - - /// internal method - static PdfEllipseAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - return PdfEllipseAnnotation._(dictionary, crossTable, text); - } - - /// internal method - static PdfEllipseAnnotationHelper getHelper(PdfEllipseAnnotation annotation) { - return annotation._helper; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/pdf_annotation_border.dart'; +import '../drawing/drawing.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_path.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_collection.dart'; +import 'pdf_appearance.dart'; +import 'pdf_paintparams.dart'; + +/// Represents a PDF ellipse annotation +class PdfEllipseAnnotation extends PdfAnnotation { + // Constructor + /// Initializes new instance of the [PdfEllipseAnnotation] class. + /// ``` dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a page. + /// PdfPage page = document.pages.add(); + /// //Create a PDF Ellipse annotation. + /// PdfEllipseAnnotation ellipseAnnotation = PdfEllipseAnnotation( + /// const Rect.fromLTWH(0, 30, 100, 50), 'EllipseAnnotation', + /// innerColor: PdfColor(255, 0, 0), color: PdfColor(255, 255, 0)); + /// //Add annotation to the page. + /// page.annotations.add(ellipseAnnotation); + /// //Saves the document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfEllipseAnnotation( + Rect bounds, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + DateTime? modifiedDate, + double? opacity, + List? flags, + bool? setAppearance, + }) { + _helper = PdfEllipseAnnotationHelper( + this, + bounds, + text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + } + + PdfEllipseAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + _helper = PdfEllipseAnnotationHelper._(this, dictionary, crossTable); + this.text = text; + } + + // fields + late PdfEllipseAnnotationHelper _helper; + + // properties + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + return _helper.border; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + _helper.border = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } + + /// Gets the inner color of the annotation. + PdfColor get innerColor => _helper.innerColor; + + /// Sets the inner color of the annotation. + set innerColor(PdfColor value) { + _helper.innerColor = value; + } + + IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; + set _element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + PdfAnnotationHelper.getHelper(this).dictionary = value; + } + } +} + +/// [PdfEllipseAnnotation] helper +class PdfEllipseAnnotationHelper extends PdfAnnotationHelper { + /// internal constructor + PdfEllipseAnnotationHelper( + this.annotation, + Rect bounds, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + DateTime? modifiedDate, + double? opacity, + List? flags, + bool? setAppearance, + }) : super(annotation) { + initializeAnnotation( + bounds: bounds, + text: text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(PdfDictionaryProperties.circle), + ); + } + + PdfEllipseAnnotationHelper._( + this.annotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super(annotation) { + initializeExistingAnnotation(dictionary, crossTable); + } + + /// internal field + late PdfEllipseAnnotation annotation; + + /// internal method + void save() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + if (PdfAnnotationCollectionHelper.getHelper( + annotation.page!.annotations, + ).flatten) { + helper.flatten = true; + } + final PdfAppearance? pdfAppearance = helper.appearance; + final bool isLoadedAnnotation = helper.isLoadedAnnotation; + if (helper.flatten || annotation.setAppearance || pdfAppearance != null) { + PdfTemplate? appearance; + if (pdfAppearance != null) { + appearance = pdfAppearance.normal; + } else { + appearance = _createAppearance(); + } + if (helper.flatten) { + if (appearance != null || isLoadedAnnotation) { + if (annotation.page != null) { + _flattenAnnotation(annotation.page, appearance); + } + } + } else { + if (appearance != null) { + annotation.appearance.normal = appearance; + helper.dictionary!.setProperty( + PdfDictionaryProperties.ap, + PdfReferenceHolder(annotation.appearance), + ); + } + } + } + if (!helper.flatten && !isLoadedAnnotation) { + helper.saveAnnotation(); + helper.dictionary!.setProperty( + PdfDictionaryProperties.bs, + annotation.border, + ); + } + if (helper.flattenPopups) { + helper.flattenPopup(); + } + } + + void _flattenAnnotation(PdfPage? page, PdfTemplate? appearance) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + if (helper.isLoadedAnnotation) { + final bool isContainsAP = helper.dictionary!.containsKey( + PdfDictionaryProperties.ap, + ); + if (appearance == null) { + if (isContainsAP) { + PdfDictionary? appearanceDictionary = + PdfCrossTable.dereference( + helper.dictionary![PdfDictionaryProperties.ap], + ) + as PdfDictionary?; + if (appearanceDictionary != null) { + appearanceDictionary = + PdfCrossTable.dereference( + appearanceDictionary[PdfDictionaryProperties.n], + ) + as PdfDictionary?; + if (appearanceDictionary != null) { + final PdfStream appearanceStream = + appearanceDictionary as PdfStream; + appearance = PdfTemplateHelper.fromPdfStream(appearanceStream); + final bool isNormalMatrix = helper.validateTemplateMatrix( + appearanceDictionary, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } else { + annotation.setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } + } + } else { + annotation.setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } + } else { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } else { + page!.graphics.save(); + final Rect rectangle = helper.calculateTemplateBounds( + annotation.bounds, + page, + appearance, + true, + ); + if (annotation.opacity < 1) { + page.graphics.setTransparency(annotation.opacity); + } + page.graphics.drawPdfTemplate( + appearance!, + Offset(rectangle.left, rectangle.top), + rectangle.size, + ); + page.annotations.remove(annotation); + page.graphics.restore(); + } + } + + PdfTemplate? _createAppearance() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + final bool isLoadedAnnotation = helper.isLoadedAnnotation; + if (isLoadedAnnotation && !annotation.setAppearance) { + return null; + } + final PdfRectangle nativeRectangle = PdfRectangle( + 0, + 0, + annotation.bounds.width, + annotation.bounds.height, + ); + final PdfTemplate template = PdfTemplateHelper.fromRect( + nativeRectangle.rect, + ); + PdfAnnotationHelper.setMatrixToZeroRotation( + PdfTemplateHelper.getHelper(template).content, + ); + if (isLoadedAnnotation && + helper.dictionary!.containsKey(PdfDictionaryProperties.be)) { + PdfTemplateHelper.getHelper(template).writeTransformation = false; + } + final PaintParams paintParams = PaintParams(); + final double borderWidth = annotation.border.width / 2; + final PdfPen mBorderPen = PdfPen( + annotation.color, + width: annotation.border.width, + ); + if (annotation.border.width > 0 && + PdfColorHelper.getHelper(annotation.color).alpha != 0) { + paintParams.borderPen = mBorderPen; + } + PdfBrush? mBackBrush; + if (PdfColorHelper.getHelper(annotation.color).alpha != 0) { + mBackBrush = PdfSolidBrush(annotation.innerColor); + } + paintParams.foreBrush = PdfSolidBrush(annotation.color); + paintParams.backBrush = mBackBrush; + final PdfGraphics? graphics = template.graphics; + if (annotation.opacity < 1) { + graphics!.save(); + graphics.setTransparency(annotation.opacity); + } + if (isLoadedAnnotation) { + final PdfRectangle rectangle = _obtainStyle( + mBorderPen, + nativeRectangle, + borderWidth, + ); + if (helper.dictionary!.containsKey(PdfDictionaryProperties.be)) { + _drawAppearance(rectangle, borderWidth, graphics, paintParams); + } else { + graphics!.drawEllipse( + Rect.fromLTWH( + rectangle.x + borderWidth, + rectangle.y, + rectangle.width - annotation.border.width, + rectangle.height, + ), + pen: paintParams.borderPen, + brush: paintParams.backBrush, + ); + } + } else { + final Rect rect = Rect.fromLTWH( + nativeRectangle.left, + nativeRectangle.top, + nativeRectangle.width, + nativeRectangle.height, + ); + graphics!.drawEllipse( + Rect.fromLTWH( + rect.left + borderWidth, + rect.top + borderWidth, + rect.width - annotation.border.width, + rect.height - annotation.border.width, + ), + pen: paintParams.borderPen, + brush: paintParams.backBrush, + ); + } + if (annotation.opacity < 1) { + graphics!.restore(); + } + return template; + } + + // Obtain Style for annotation + PdfRectangle _obtainStyle( + PdfPen mBorderPen, + PdfRectangle rectangle, + double borderWidth, + ) { + final PdfDictionary dictionary = + PdfAnnotationHelper.getHelper(annotation).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.bs)) { + final PdfDictionary? bSDictionary = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.bs]) + as PdfDictionary?; + + if (bSDictionary != null && + bSDictionary.containsKey(PdfDictionaryProperties.d)) { + final PdfArray dashPatternArray = + PdfCrossTable.dereference(bSDictionary[PdfDictionaryProperties.d])! + as PdfArray; + final List dashPattern = []; + for (int i = 0; i < dashPatternArray.count; i++) { + dashPattern.add( + (dashPatternArray.elements[i]! as PdfNumber).value!.toDouble(), + ); + } + mBorderPen.dashStyle = PdfDashStyle.dash; + mBorderPen.dashPattern = dashPattern; + } + } + if (!PdfAnnotationHelper.getHelper(annotation).isBounds && + dictionary[PdfDictionaryProperties.rd] != null) { + final PdfArray? mRdArray = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.rd]) + as PdfArray?; + if (mRdArray != null) { + final PdfNumber num1 = mRdArray.elements[0]! as PdfNumber; + final PdfNumber num2 = mRdArray.elements[1]! as PdfNumber; + final PdfNumber num3 = mRdArray.elements[2]! as PdfNumber; + final PdfNumber num4 = mRdArray.elements[3]! as PdfNumber; + rectangle.x += num1.value!; + rectangle.y += borderWidth + num2.value!; + rectangle.width = rectangle.width - (2 * num3.value!); + rectangle.height = rectangle.height - annotation.border.width; + rectangle.height = rectangle.height - (2 * num4.value!); + } + } else { + rectangle.y += borderWidth; + rectangle.height = annotation.bounds.height - annotation.border.width; + } + return rectangle; + } + + // Draw appearance for annotation + void _drawAppearance( + PdfRectangle rectangle, + double borderWidth, + PdfGraphics? graphics, + PaintParams paintParams, + ) { + final PdfPath graphicsPath = PdfPath(); + graphicsPath.addEllipse( + Rect.fromLTWH( + rectangle.x + borderWidth, + -rectangle.y - rectangle.height, + rectangle.width - annotation.border.width, + rectangle.height, + ), + ); + double? radius = 0; + if (PdfAnnotationHelper.getHelper( + annotation, + ).dictionary!.containsKey(PdfDictionaryProperties.rd)) { + final PdfArray? rdArray = + PdfCrossTable.dereference( + PdfAnnotationHelper.getHelper( + annotation, + ).dictionary!.items![PdfName(PdfDictionaryProperties.rd)], + ) + as PdfArray?; + if (rdArray != null) { + radius = (rdArray.elements[0]! as PdfNumber).value as double?; + } + } + if (radius! > 0) { + final PdfRectangle rect = PdfRectangle( + rectangle.x + borderWidth, + -rectangle.y - rectangle.height, + rectangle.width - annotation.border.width, + rectangle.height, + ); + final List startPointList = []; + final List controlPointList = []; + final List endPointList = []; + final List points = []; + + controlPointList.add(Offset(rect.right, rect.bottom)); + controlPointList.add(Offset(rect.left, rect.bottom)); + controlPointList.add(Offset(rect.left, rect.top)); + controlPointList.add(Offset(rect.right, rect.top)); + + startPointList.add(Offset(rect.right, rect.top + (rect.height / 2))); + startPointList.add(Offset(rect.left + rect.width / 2, rect.bottom)); + startPointList.add(Offset(rect.left, rect.top + (rect.height / 2))); + startPointList.add(Offset(rect.left + (rect.width / 2), rect.top)); + + endPointList.add(Offset(rect.left + rect.width / 2, rect.bottom)); + endPointList.add(Offset(rect.left, rect.top + (rect.height / 2))); + endPointList.add(Offset(rect.left + (rect.width / 2), rect.top)); + endPointList.add(Offset(rect.right, rect.top + (rect.height / 2))); + + for (int i = 0; i < controlPointList.length; i++) { + _createBezier( + startPointList[i], + controlPointList[i], + endPointList[i], + points, + ); + } + PdfAnnotationHelper.getHelper(annotation).drawCloudStyle( + graphics!, + paintParams.backBrush, + paintParams.borderPen, + radius, + 0.833, + points, + false, + ); + startPointList.clear(); + controlPointList.clear(); + endPointList.clear(); + points.clear(); + } else { + graphics!.drawEllipse( + Rect.fromLTWH( + rectangle.x + borderWidth, + -rectangle.y, + rectangle.width - annotation.border.width, + -rectangle.height, + ), + pen: paintParams.borderPen, + brush: paintParams.backBrush, + ); + } + } + + // Create bezier curve + void _createBezier( + Offset ctrl1, + Offset ctrl2, + Offset ctrl3, + List bezierPoints, + ) { + bezierPoints.add(ctrl1); // add the first control point + _populateBezierPoints(ctrl1, ctrl2, ctrl3, 0, bezierPoints); + bezierPoints.add(ctrl3); // add the last control point + } + + // calculate bezier points + void _populateBezierPoints( + Offset ctrl1, + Offset ctrl2, + Offset ctrl3, + int currentIteration, + List bezierPoints, + ) { + if (currentIteration < 2) { + //calculate next mid points + final Offset midPoint1 = Offset( + (ctrl1.dx + ctrl2.dx) / 2, + (ctrl1.dy + ctrl2.dy) / 2, + ); + final Offset midPoint2 = Offset( + (ctrl2.dx + ctrl3.dx) / 2, + (ctrl2.dy + ctrl3.dy) / 2, + ); + final Offset midPoint3 = Offset( + (midPoint1.dx + midPoint2.dx) / 2, + (midPoint1.dy + midPoint2.dy) / 2, + ); + //the next control point + currentIteration++; + _populateBezierPoints( + ctrl1, + midPoint1, + midPoint3, + currentIteration, + bezierPoints, + ); //left branch + bezierPoints.add(midPoint3); + //add the next control point + _populateBezierPoints( + midPoint3, + midPoint2, + ctrl3, + currentIteration, + bezierPoints, + ); //right branch + } + } + + /// internal property + @override + IPdfPrimitive? get element { + return annotation._element; + } + + @override + set element(IPdfPrimitive? element) { + annotation._element = element; + } + + /// internal method + static PdfEllipseAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + return PdfEllipseAnnotation._(dictionary, crossTable, text); + } + + /// internal method + static PdfEllipseAnnotationHelper getHelper(PdfEllipseAnnotation annotation) { + return annotation._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_line_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_line_annotation.dart index fc0bf5321..b3e65719e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_line_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_line_annotation.dart @@ -1,1186 +1,1186 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/pdf_annotation_border.dart'; -import '../drawing/drawing.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/fonts/pdf_string_format.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_margins.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_collection.dart'; -import 'pdf_paintparams.dart'; - -/// Represents a line annotation. -class PdfLineAnnotation extends PdfAnnotation { - // Constructor - /// Initializes new instance of [PdfLineAnnotation] class. - /// ``` dart - /// PdfDocument document = PdfDocument(); - /// PdfPage page = document.pages.add(); - /// List points = [80, 420, 250, 420]; - /// PdfLineAnnotation lineAnnotation = PdfLineAnnotation( - /// points, 'Line Annotation', - /// opacity: 0.95, - /// border: PdfAnnotationBorder(1), - /// lineIntent: PdfLineIntent.lineDimension, - /// beginLineStyle: PdfLineEndingStyle.butt, - /// endLineStyle: PdfLineEndingStyle.none, - /// innerColor: PdfColor(0, 255, 0), - /// color: PdfColor(0, 255, 255), - /// leaderLineExt: 10, - /// leaderLine: 2, - /// lineCaption: true, - /// captionType: PdfLineCaptionType.top); - /// page.annotations.add(lineAnnotation); - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfLineAnnotation( - List linePoints, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - DateTime? modifiedDate, - double? opacity, - bool? setAppearance, - PdfLineEndingStyle beginLineStyle = PdfLineEndingStyle.none, - PdfLineEndingStyle endLineStyle = PdfLineEndingStyle.none, - PdfLineCaptionType captionType = PdfLineCaptionType.inline, - PdfLineIntent lineIntent = PdfLineIntent.lineArrow, - int? leaderLine, - int? leaderLineExt, - bool lineCaption = false, - List? flags, - }) { - _helper = PdfLineAnnotationHelper( - this, - linePoints, - text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - this.beginLineStyle = beginLineStyle; - this.endLineStyle = endLineStyle; - this.captionType = captionType; - this.lineIntent = lineIntent; - this.lineCaption = lineCaption; - if (leaderLine != null) { - this.leaderLine = leaderLine; - } - if (leaderLineExt != null) { - this.leaderLineExt = leaderLineExt; - } - } - - PdfLineAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String annotText, - ) { - _helper = PdfLineAnnotationHelper._(this, dictionary, crossTable); - text = annotText; - } - - // Fields - late PdfLineAnnotationHelper _helper; - late PdfLineEndingStyle _beginLineStyle; - late PdfLineEndingStyle _endLineStyle; - int _leaderLineExt = 0; - late bool _lineCaption; - late PdfLineIntent _lineIntent; - late PdfLineCaptionType _captionType; - - // Properties - /// Gets the leader line. - int get leaderLine => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._obtainLeaderLine() - : _helper.leaderLine; - - /// Sets the leader line. - set leaderLine(int value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - final bool isLoadedAnnotation = helper.isLoadedAnnotation; - if (value != 0 && !isLoadedAnnotation) { - _helper.leaderLine = value; - } else if (isLoadedAnnotation) { - helper.dictionary!.setNumber(PdfDictionaryProperties.ll, value); - } - } - - /// Gets the line points of the annotation. - List get linePoints => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._obtainLinePoints() - : _helper.points; - - /// Sets the line points of the annotation. - set linePoints(List value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - _helper.points = value; - _helper.linePoints = PdfArray(_helper.points); - if (helper.isLoadedAnnotation) { - helper.dictionary!.setProperty( - PdfDictionaryProperties.l, - _helper.linePoints, - ); - } - } - - /// Gets the line intent of the annotation. - PdfLineIntent get lineIntent => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._obtainLineIntent() - : _lineIntent; - - /// Sets the line intent of the annotation. - set lineIntent(PdfLineIntent value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - if (!helper.isLoadedAnnotation) { - _lineIntent = value; - } else { - helper.dictionary!.setName( - PdfName(PdfDictionaryProperties.it), - helper.getEnumName(value), - ); - } - } - - /// Gets the line caption of the annotation. - bool get lineCaption => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._obtainLineCaption() - : _lineCaption; - - /// Sets the line caption of the annotation. - set lineCaption(bool value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - if (!helper.isLoadedAnnotation) { - _lineCaption = value; - } else { - helper.dictionary!.setBoolean(PdfDictionaryProperties.cap, value); - } - } - - /// Gets the leader line extension. - int get leaderLineExt => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._obtainLeaderExt() - : _leaderLineExt; - - /// Sets the leader line extension. - set leaderLineExt(int value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - if (!helper.isLoadedAnnotation) { - _leaderLineExt = value; - } else { - helper.dictionary!.setNumber(PdfDictionaryProperties.lle, value); - } - } - - /// Gets the begin line style of the annotation. - PdfLineEndingStyle get beginLineStyle => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._getLineStyle(0) - : _beginLineStyle; - - /// Sets the end line style of the annotation. - set beginLineStyle(PdfLineEndingStyle value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - if (!helper.isLoadedAnnotation) { - _beginLineStyle = value; - } else { - PdfArray? lineStyle = _helper._obtainLineStyle(); - if (lineStyle == null) { - lineStyle = PdfArray(); - } else { - lineStyle.elements.removeAt(0); - } - lineStyle.insert( - 0, - PdfName( - helper.getEnumName( - _helper._getLineStyle(helper.getEnumName(value.toString())), - ), - ), - ); - helper.dictionary!.setProperty(PdfDictionaryProperties.le, lineStyle); - } - } - - /// Gets the end line style of the annotation. - PdfLineEndingStyle get endLineStyle => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._getLineStyle(1) - : _endLineStyle; - - /// Sets the end line style of the annotation. - set endLineStyle(PdfLineEndingStyle value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - if (!helper.isLoadedAnnotation) { - _endLineStyle = value; - } else { - PdfArray? lineStyle = _helper._obtainLineStyle(); - if (lineStyle == null) { - lineStyle = PdfArray(); - } else { - lineStyle.elements.removeAt(1); - } - lineStyle.insert( - 1, - PdfName( - helper.getEnumName( - _helper._getLineStyle(helper.getEnumName(value.toString())), - ), - ), - ); - helper.dictionary!.setProperty(PdfDictionaryProperties.le, lineStyle); - } - } - - /// Gets the caption type of the annotation. - PdfLineCaptionType get captionType => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._obtainCaptionType() - : _captionType; - - /// Sets the caption type of the annotation. - set captionType(PdfLineCaptionType value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - if (!helper.isLoadedAnnotation) { - _captionType = value; - } else { - helper.dictionary!.setProperty( - PdfDictionaryProperties.cp, - PdfName( - helper.getEnumName( - _helper._getCaptionType(helper.getEnumName(value.toString())), - ), - ), - ); - } - } - - /// Gets or sets the content of the annotation. - /// - /// The string value specifies the text of the annotation. - @override - String get text => super.text; - @override - set text(String value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - if (helper.textValue != value) { - helper.textValue = value; - helper.dictionary!.setString( - PdfDictionaryProperties.contents, - helper.textValue, - ); - } - } - - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - return _helper.border; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - _helper.border = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } - - /// Gets the inner color of the annotation. - PdfColor get innerColor => _helper.innerColor; - - /// Sets the inner color of the annotation. - set innerColor(PdfColor value) { - _helper.innerColor = value; - } - - IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; - - set _element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - PdfAnnotationHelper.getHelper(this).dictionary = value; - } - } -} - -/// [PdfLineAnnotation] helper -class PdfLineAnnotationHelper extends PdfAnnotationHelper { - /// internal constructor - PdfLineAnnotationHelper( - this.lineAnnotation, - List linePoints, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - DateTime? modifiedDate, - double? opacity, - List? flags, - bool? setAppearance, - }) : super(lineAnnotation) { - initializeAnnotation( - text: text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - this.linePoints = PdfArray(linePoints); - points = linePoints; - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(PdfDictionaryProperties.line), - ); - } - PdfLineAnnotationHelper._( - this.lineAnnotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super(lineAnnotation) { - initializeExistingAnnotation(dictionary, crossTable); - } - - /// internal field - late PdfLineAnnotation lineAnnotation; - - /// internal field - PdfArray? lineStyle; - - /// internal field - PdfArray? linePoints; - - /// internal field - int leaderLine = 0; - - /// internal field - List points = []; - - /// internal property - @override - IPdfPrimitive? get element => lineAnnotation._element; - - @override - set element(IPdfPrimitive? value) { - lineAnnotation._element = value; - } - - /// internal method - void save() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - if (PdfAnnotationCollectionHelper.getHelper( - lineAnnotation.page!.annotations, - ).flatten) { - helper.flatten = true; - } - if (helper.flatten || lineAnnotation.setAppearance) { - final PdfTemplate? appearance = _createAppearance(); - if (helper.flatten) { - if (appearance != null || helper.isLoadedAnnotation) { - if (lineAnnotation.page != null) { - _flattenAnnotation(lineAnnotation.page, appearance); - } - } - } else { - if (appearance != null) { - lineAnnotation.appearance.normal = appearance; - helper.dictionary!.setProperty( - PdfDictionaryProperties.ap, - PdfReferenceHolder(lineAnnotation.appearance), - ); - } - } - } - if (!helper.flatten && !helper.isLoadedAnnotation) { - helper.saveAnnotation(); - _savePdfLineDictionary(); - } - if (helper.flattenPopups) { - helper.flattenPopup(); - } - } - - void _savePdfLineDictionary() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - helper.saveAnnotation(); - lineStyle = PdfArray(); - if (lineStyle!.elements.isNotEmpty) { - lineStyle!.insert( - 0, - PdfName(helper.getEnumName(lineAnnotation.beginLineStyle)), - ); - lineStyle!.insert( - 1, - PdfName(helper.getEnumName(lineAnnotation.endLineStyle)), - ); - } else { - lineStyle!.add( - PdfName(helper.getEnumName(lineAnnotation.beginLineStyle)), - ); - lineStyle!.add(PdfName(helper.getEnumName(lineAnnotation.endLineStyle))); - } - final PdfDictionary dictionary = helper.dictionary!; - dictionary.setProperty(PdfDictionaryProperties.le, lineStyle); - if (linePoints != null) { - dictionary.setProperty(PdfDictionaryProperties.l, linePoints); - } else { - throw ArgumentError.value('LinePoints cannot be null'); - } - if (lineAnnotation.border.dashArray == 0) { - if (lineAnnotation.border.borderStyle == PdfBorderStyle.dashed) { - lineAnnotation.border.dashArray = 4; - } else if (lineAnnotation.border.borderStyle == PdfBorderStyle.dot) { - lineAnnotation.border.dashArray = 2; - } - } - dictionary.setProperty(PdfDictionaryProperties.bs, lineAnnotation.border); - if (!lineAnnotation.innerColor.isEmpty && - PdfColorHelper.getHelper(lineAnnotation.innerColor).alpha != 0) { - dictionary.setProperty( - PdfDictionaryProperties.ic, - PdfColorHelper.toArray(lineAnnotation.innerColor), - ); - } - dictionary[PdfDictionaryProperties.c] = PdfColorHelper.toArray( - lineAnnotation.color, - ); - - dictionary.setProperty( - PdfDictionaryProperties.it, - PdfName(helper.getEnumName(lineAnnotation.lineIntent)), - ); - - dictionary.setProperty( - PdfDictionaryProperties.lle, - PdfNumber(lineAnnotation.leaderLineExt), - ); - - dictionary.setProperty(PdfDictionaryProperties.ll, PdfNumber(leaderLine)); - - dictionary.setProperty( - PdfDictionaryProperties.cp, - PdfName(helper.getEnumName(lineAnnotation.captionType)), - ); - - dictionary.setProperty( - PdfDictionaryProperties.cap, - PdfBoolean(lineAnnotation.lineCaption), - ); - - dictionary.setProperty( - PdfDictionaryProperties.rect, - PdfArray.fromRectangle(_obtainLineBounds()), - ); - } - - void _flattenAnnotation(PdfPage? page, PdfTemplate? appearance) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - final PdfDictionary dictionary = helper.dictionary!; - if (helper.isLoadedAnnotation) { - final bool isContainsAP = dictionary.containsKey( - PdfDictionaryProperties.ap, - ); - if (isContainsAP && appearance == null) { - PdfDictionary? appearanceDictionary = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ap]) - as PdfDictionary?; - if (appearanceDictionary != null) { - appearanceDictionary = - PdfCrossTable.dereference( - appearanceDictionary[PdfDictionaryProperties.n], - ) - as PdfDictionary?; - if (appearanceDictionary != null) { - final PdfStream appearanceStream = - appearanceDictionary as PdfStream; - appearance = PdfTemplateHelper.fromPdfStream(appearanceStream); - final bool isNormalMatrix = helper.validateTemplateMatrix( - appearanceDictionary, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } else { - lineAnnotation.setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } - } - } else if (!isContainsAP && appearance == null) { - lineAnnotation.setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } else { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance!).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } else { - page!.graphics.save(); - final Rect rectangle = helper.calculateTemplateBounds( - lineAnnotation.bounds, - page, - appearance, - true, - ); - if (lineAnnotation.opacity < 1) { - page.graphics.setTransparency(lineAnnotation.opacity); - } - page.graphics.drawPdfTemplate( - appearance!, - Offset(rectangle.left, rectangle.top), - rectangle.size, - ); - page.annotations.remove(lineAnnotation); - page.graphics.restore(); - } - } - - PdfTemplate? _createAppearance() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - final bool isLoadedAnnotation = helper.isLoadedAnnotation; - if (isLoadedAnnotation && !lineAnnotation.setAppearance) { - return null; - } - final Rect nativeRectangle = _obtainLineBounds().rect; - final PdfTemplate template = PdfTemplateHelper.fromRect(nativeRectangle); - PdfAnnotationHelper.setMatrixToZeroRotation( - PdfTemplateHelper.getHelper(template).content, - ); - PdfTemplateHelper.getHelper(template).writeTransformation = false; - final PaintParams paintParams = PaintParams(); - final PdfGraphics? graphics = template.graphics; - final PdfPen mBorderPen = PdfPen( - lineAnnotation.color, - width: lineAnnotation.border.width, - ); - if (lineAnnotation.border.borderStyle == PdfBorderStyle.dashed) { - mBorderPen.dashStyle = PdfDashStyle.dash; - } else if (lineAnnotation.border.borderStyle == PdfBorderStyle.dot) { - mBorderPen.dashStyle = PdfDashStyle.dot; - } - paintParams.borderPen = mBorderPen; - paintParams.foreBrush = PdfSolidBrush(lineAnnotation.color); - final PdfFont mFont = PdfStandardFont( - PdfFontFamily.helvetica, - isLoadedAnnotation ? 10 : 9, - style: PdfFontStyle.regular, - ); - final PdfStringFormat format = PdfStringFormat(); - format.alignment = PdfTextAlignment.center; - format.lineAlignment = PdfVerticalAlignment.middle; - final double lineWidth = - mFont.measureString(lineAnnotation.text, format: format).width; - final List linePoints = _obtainLinePoints(); - if (linePoints.length == 4) { - final double x1 = linePoints[0].toDouble(); - final double y1 = linePoints[1].toDouble(); - final double x2 = linePoints[2].toDouble(); - final double y2 = linePoints[3].toDouble(); - double angle = 0; - if (x2 - x1 == 0) { - if (y2 > y1) { - angle = 90; - } else { - angle = 270; - } - } else { - angle = helper.getAngle(x1, y1, x2, y2); - } - double leadLine = 0; - double lineAngle = 0; - if (lineAnnotation.leaderLine < 0) { - leadLine = -lineAnnotation.leaderLine.toDouble(); - lineAngle = angle + 180; - } else { - leadLine = lineAnnotation.leaderLine.toDouble(); - lineAngle = angle; - } - final List x1y1 = [x1, y1]; - final List x2y2 = [x2, y2]; - final double line = - leadLine + - (isLoadedAnnotation ? _obtainLeaderOffset().toDouble() : 0); - final List startingPoint = helper.getAxisValue( - x1y1, - lineAngle + 90, - line, - ); - final List endingPoint = helper.getAxisValue( - x2y2, - lineAngle + 90, - line, - ); - final double lineDistance = sqrt( - pow(endingPoint[0] - startingPoint[0], 2) + - pow(endingPoint[1] - startingPoint[1], 2), - ); - final double centerWidth = - lineDistance / 2 - ((lineWidth / 2) + lineAnnotation.border.width); - final List middlePoint1 = helper.getAxisValue( - startingPoint, - angle, - centerWidth, - ); - final List middlePoint2 = helper.getAxisValue( - endingPoint, - angle + 180, - centerWidth, - ); - List lineStartingPoint; - List lineEndingPoint; - if (lineAnnotation.beginLineStyle == PdfLineEndingStyle.openArrow || - lineAnnotation.beginLineStyle == PdfLineEndingStyle.closedArrow) { - lineStartingPoint = helper.getAxisValue( - startingPoint, - angle, - lineAnnotation.border.width, - ); - } else { - lineStartingPoint = startingPoint; - } - if (lineAnnotation.endLineStyle == PdfLineEndingStyle.openArrow || - lineAnnotation.endLineStyle == PdfLineEndingStyle.closedArrow) { - lineEndingPoint = helper.getAxisValue( - endingPoint, - angle, - -lineAnnotation.border.width, - ); - } else { - lineEndingPoint = endingPoint; - } - final String caption = helper.getEnumName(lineAnnotation.captionType); - if (lineAnnotation.opacity < 1) { - graphics!.save(); - graphics.setTransparency(lineAnnotation.opacity); - } - if (lineAnnotation.text.isEmpty || - caption == 'Top' || - !lineAnnotation.lineCaption) { - graphics!.drawLine( - mBorderPen, - Offset(lineStartingPoint[0], -lineStartingPoint[1]), - Offset(lineEndingPoint[0], -lineEndingPoint[1]), - ); - } else { - graphics!.drawLine( - mBorderPen, - Offset(lineStartingPoint[0], -lineStartingPoint[1]), - Offset(middlePoint1[0], -middlePoint1[1]), - ); - graphics.drawLine( - mBorderPen, - Offset(lineEndingPoint[0], -lineEndingPoint[1]), - Offset(middlePoint2[0], -middlePoint2[1]), - ); - } - if (lineAnnotation.opacity < 1) { - graphics.restore(); - } - //Set begin and end line style. - final PdfBrush backBrush = PdfSolidBrush(lineAnnotation.innerColor); - final PdfArray lineStyle = PdfArray(); - lineStyle.insert( - 0, - PdfName(helper.getEnumName(lineAnnotation.beginLineStyle)), - ); - lineStyle.insert( - 1, - PdfName(helper.getEnumName(lineAnnotation.endLineStyle)), - ); - final double borderLength = lineAnnotation.border.width; - helper.setLineEndingStyles( - startingPoint, - endingPoint, - graphics, - angle, - mBorderPen, - backBrush, - lineStyle, - borderLength, - ); - //Set leader extension. - final List beginLineExt = helper.getAxisValue( - startingPoint, - lineAngle + 90, - lineAnnotation.leaderLineExt.toDouble(), - ); - graphics.drawLine( - mBorderPen, - Offset(startingPoint[0], -startingPoint[1]), - Offset(beginLineExt[0], -beginLineExt[1]), - ); - final List endLineExt = helper.getAxisValue( - endingPoint, - lineAngle + 90, - lineAnnotation.leaderLineExt.toDouble(), - ); - graphics.drawLine( - mBorderPen, - Offset(endingPoint[0], -endingPoint[1]), - Offset(endLineExt[0], -endLineExt[1]), - ); - //Set leader line - final List beginLeaderLine = helper.getAxisValue( - startingPoint, - lineAngle - 90, - leadLine, - ); - graphics.drawLine( - mBorderPen, - Offset(startingPoint[0], -startingPoint[1]), - Offset(beginLeaderLine[0], -beginLeaderLine[1]), - ); - final List endLeaderLine = helper.getAxisValue( - endingPoint, - lineAngle - 90, - leadLine, - ); - graphics.drawLine( - mBorderPen, - Offset(endingPoint[0], -endingPoint[1]), - Offset(endLeaderLine[0], -endLeaderLine[1]), - ); - //Set caption Type. - if (lineAnnotation.lineCaption) { - final double midpoint = lineDistance / 2; - final List centerPoint = helper.getAxisValue( - startingPoint, - angle, - midpoint, - ); - final List captionPosition = _getCaptionPosition( - caption, - centerPoint, - angle, - mFont, - ); - graphics.translateTransform(captionPosition[0], -captionPosition[1]); - graphics.rotateTransform(-angle); - graphics.drawString( - lineAnnotation.text, - mFont, - brush: backBrush, - bounds: Rect.fromLTWH(-lineWidth / 2, 0, 0, 0), - ); - } - } - if (isLoadedAnnotation) { - helper.dictionary!.setProperty( - PdfDictionaryProperties.rect, - PdfArray.fromRectangle(_obtainLineBounds()), - ); - } - if (!isLoadedAnnotation && helper.flatten) { - final double pageHeight = lineAnnotation.page!.size.height; - final PdfMargins? margins = helper.obtainMargin(); - if (lineAnnotation.page != null) { - lineAnnotation.bounds = Rect.fromLTWH( - nativeRectangle.left - margins!.left, - pageHeight - - (nativeRectangle.top + nativeRectangle.height) - - margins.top, - nativeRectangle.width, - nativeRectangle.height, - ); - } else { - lineAnnotation.bounds = Rect.fromLTWH( - nativeRectangle.left, - pageHeight - (nativeRectangle.top + nativeRectangle.height), - nativeRectangle.width, - nativeRectangle.height, - ); - } - } - return template; - } - - List _getCaptionPosition( - String caption, - List centerPoint, - double angle, - PdfFont font, - ) { - List captionPosition = List.filled(2, 0); - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - if (helper.isLoadedAnnotation) { - final bool isContainsMeasure = helper.dictionary!.items!.containsKey( - PdfName(PdfDictionaryProperties.measure), - ); - final double length = - caption == 'Top' - ? isContainsMeasure - ? 2 * font.height - : font.height - : isContainsMeasure - ? 3 * (font.height / 2) - : font.height / 2; - captionPosition = helper.getAxisValue(centerPoint, angle + 90, length); - } else { - captionPosition = helper.getAxisValue( - centerPoint, - angle + 90, - caption == 'Top' ? font.height : font.height / 2, - ); - } - return captionPosition; - } - - // Gets leader line of the lineAnnotation. - int _obtainLeaderLine() { - int lLine = 0; - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - if (helper.dictionary!.containsKey(PdfDictionaryProperties.ll)) { - final PdfNumber ll = - helper.dictionary![PdfDictionaryProperties.ll]! as PdfNumber; - lLine = ll.value!.toInt(); - } - return lLine; - } - - // Gets the line intent of the annotation. - PdfLineIntent _obtainLineIntent() { - PdfLineIntent lineintentValue = PdfLineIntent.lineArrow; - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - if (helper.dictionary!.containsKey(PdfDictionaryProperties.it)) { - final PdfName lineintent = - helper.crossTable.getObject( - helper.dictionary![PdfDictionaryProperties.it], - )! - as PdfName; - lineintentValue = _getLineIntentText(lineintent.name.toString()); - } - return lineintentValue; - } - - // Get the Line Intent Text. - PdfLineIntent _getLineIntentText(String lintent) { - PdfLineIntent lineintent = PdfLineIntent.lineArrow; - switch (lintent) { - case 'LineArrow': - lineintent = PdfLineIntent.lineArrow; - break; - case 'LineDimension': - lineintent = PdfLineIntent.lineDimension; - break; - } - return lineintent; - } - - List _obtainLinePoints() { - List points = []; - if (!PdfAnnotationHelper.getHelper(lineAnnotation).isLoadedAnnotation) { - if (linePoints != null) { - // ignore: prefer_final_in_for_each - for (IPdfPrimitive? linePoint in linePoints!.elements) { - if (linePoint is PdfNumber) { - points.add(linePoint.value!.toInt()); - } - } - } - } else { - if (PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary!.containsKey(PdfDictionaryProperties.l)) { - linePoints = - PdfCrossTable.dereference( - PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary![PdfDictionaryProperties.l], - ) - as PdfArray?; - if (linePoints != null) { - points = []; - // ignore: prefer_final_in_for_each - for (IPdfPrimitive? value in linePoints!.elements) { - if (value is PdfNumber) { - points.add(value.value!.toInt()); - } - } - } - } - } - return points; - } - - // Gets line caption of the annotation. - bool _obtainLineCaption() { - bool lCaption = false; - if (PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary!.containsKey(PdfDictionaryProperties.cap)) { - final PdfBoolean lCap = - PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary![PdfDictionaryProperties.cap]! - as PdfBoolean; - lCaption = lCap.value!; - } - return lCaption; - } - - // Gets leader ext of the annotation. - int _obtainLeaderExt() { - int lLineExt = 0; - if (PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary!.containsKey(PdfDictionaryProperties.lle)) { - final PdfNumber lExt = - PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary![PdfDictionaryProperties.lle]! - as PdfNumber; - lLineExt = lExt.value!.toInt(); - } - return lLineExt; - } - - // Gets line style of the annotation. - PdfLineEndingStyle _getLineStyle(dynamic value) { - PdfLineEndingStyle linestyle = PdfLineEndingStyle.none; - if (value is int) { - final PdfArray? array = _obtainLineStyle(); - if (array != null) { - final PdfName style = array[value]! as PdfName; - linestyle = _getLineStyle(style.name); - } - } else if (value is String) { - switch (value) { - case 'Square': - linestyle = PdfLineEndingStyle.square; - break; - case 'Circle': - linestyle = PdfLineEndingStyle.circle; - break; - case 'Diamond': - linestyle = PdfLineEndingStyle.diamond; - break; - case 'OpenArrow': - linestyle = PdfLineEndingStyle.openArrow; - break; - case 'ClosedArrow': - linestyle = PdfLineEndingStyle.closedArrow; - break; - case 'None': - linestyle = PdfLineEndingStyle.none; - break; - case 'ROpenArrow': - linestyle = PdfLineEndingStyle.rOpenArrow; - break; - case 'Butt': - linestyle = PdfLineEndingStyle.butt; - break; - case 'RClosedArrow': - linestyle = PdfLineEndingStyle.rClosedArrow; - break; - case 'Slash': - linestyle = PdfLineEndingStyle.slash; - break; - } - } - return linestyle; - } - - PdfRectangle _obtainLineBounds() { - PdfRectangle bounds = PdfRectangle.fromRect(lineAnnotation.bounds); - if (points.length == 4 || - PdfAnnotationHelper.getHelper(lineAnnotation).isLoadedAnnotation) { - final List lPoints = _obtainLinePoints(); - if (lPoints.length == 4) { - final PdfArray lineStyle = PdfArray(); - if (lineStyle.elements.isNotEmpty) { - lineStyle.insert( - 0, - PdfName( - PdfAnnotationHelper.getHelper( - lineAnnotation, - ).getEnumName(lineAnnotation.beginLineStyle), - ), - ); - lineStyle.insert( - 1, - PdfName( - PdfAnnotationHelper.getHelper( - lineAnnotation, - ).getEnumName(lineAnnotation.endLineStyle), - ), - ); - } else { - lineStyle.add(PdfName(lineAnnotation.beginLineStyle.toString())); - lineStyle.add(PdfName(lineAnnotation.endLineStyle.toString())); - } - bounds = - PdfAnnotationHelper.getHelper(lineAnnotation).isLoadedAnnotation - ? PdfAnnotationHelper.getHelper( - lineAnnotation, - ).calculateLineBounds( - lPoints, - lineAnnotation.leaderLineExt, - lineAnnotation.leaderLine, - _obtainLeaderOffset(), - lineStyle, - lineAnnotation.border.width, - ) - : PdfAnnotationHelper.getHelper( - lineAnnotation, - ).calculateLineBounds( - lPoints, - lineAnnotation.leaderLineExt, - leaderLine, - 0, - lineStyle, - lineAnnotation.border.width, - ); - bounds = PdfRectangle( - bounds.left - 8, - bounds.top - 8, - bounds.width + 2 * 8, - bounds.height + 2 * 8, - ); - } - } - return bounds; - } - - // Gets leader offset of the annotation. - int _obtainLeaderOffset() { - int lLineOffset = 0; - if (PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary!.containsKey(PdfDictionaryProperties.llo)) { - final PdfNumber lOffset = - PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary![PdfDictionaryProperties.llo]! - as PdfNumber; - lLineOffset = lOffset.value!.toInt(); - } - return lLineOffset; - } - - // Gets line style of the annotation. - PdfArray? _obtainLineStyle() { - PdfArray? array; - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - lineAnnotation, - ); - if (helper.dictionary!.containsKey(PdfDictionaryProperties.le)) { - array = - helper.crossTable.getObject( - helper.dictionary![PdfDictionaryProperties.le], - ) - as PdfArray?; - } - return array; - } - - // Gets caption type of the annotation. - PdfLineCaptionType _obtainCaptionType() { - PdfLineCaptionType captiontypeValue = PdfLineCaptionType.inline; - if (PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary!.containsKey(PdfDictionaryProperties.cp)) { - final PdfName cType = - PdfAnnotationHelper.getHelper( - lineAnnotation, - ).dictionary![PdfDictionaryProperties.cp]! - as PdfName; - captiontypeValue = _getCaptionType(cType.name.toString()); - } - return captiontypeValue; - } - - // Gets caption type of the annotation. - PdfLineCaptionType _getCaptionType(String cType) { - PdfLineCaptionType captiontype = PdfLineCaptionType.inline; - if (cType == 'Inline') { - captiontype = PdfLineCaptionType.inline; - } else { - captiontype = PdfLineCaptionType.top; - } - return captiontype; - } - - /// internal method - static PdfLineAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - return PdfLineAnnotation._(dictionary, crossTable, text); - } - - /// internal method - static PdfLineAnnotationHelper getHelper(PdfLineAnnotation annotation) { - return annotation._helper; - } -} +import 'dart:math'; +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/pdf_annotation_border.dart'; +import '../drawing/drawing.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/fonts/pdf_string_format.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_margins.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_collection.dart'; +import 'pdf_paintparams.dart'; + +/// Represents a line annotation. +class PdfLineAnnotation extends PdfAnnotation { + // Constructor + /// Initializes new instance of [PdfLineAnnotation] class. + /// ``` dart + /// PdfDocument document = PdfDocument(); + /// PdfPage page = document.pages.add(); + /// List points = [80, 420, 250, 420]; + /// PdfLineAnnotation lineAnnotation = PdfLineAnnotation( + /// points, 'Line Annotation', + /// opacity: 0.95, + /// border: PdfAnnotationBorder(1), + /// lineIntent: PdfLineIntent.lineDimension, + /// beginLineStyle: PdfLineEndingStyle.butt, + /// endLineStyle: PdfLineEndingStyle.none, + /// innerColor: PdfColor(0, 255, 0), + /// color: PdfColor(0, 255, 255), + /// leaderLineExt: 10, + /// leaderLine: 2, + /// lineCaption: true, + /// captionType: PdfLineCaptionType.top); + /// page.annotations.add(lineAnnotation); + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfLineAnnotation( + List linePoints, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + DateTime? modifiedDate, + double? opacity, + bool? setAppearance, + PdfLineEndingStyle beginLineStyle = PdfLineEndingStyle.none, + PdfLineEndingStyle endLineStyle = PdfLineEndingStyle.none, + PdfLineCaptionType captionType = PdfLineCaptionType.inline, + PdfLineIntent lineIntent = PdfLineIntent.lineArrow, + int? leaderLine, + int? leaderLineExt, + bool lineCaption = false, + List? flags, + }) { + _helper = PdfLineAnnotationHelper( + this, + linePoints, + text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + this.beginLineStyle = beginLineStyle; + this.endLineStyle = endLineStyle; + this.captionType = captionType; + this.lineIntent = lineIntent; + this.lineCaption = lineCaption; + if (leaderLine != null) { + this.leaderLine = leaderLine; + } + if (leaderLineExt != null) { + this.leaderLineExt = leaderLineExt; + } + } + + PdfLineAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String annotText, + ) { + _helper = PdfLineAnnotationHelper._(this, dictionary, crossTable); + text = annotText; + } + + // Fields + late PdfLineAnnotationHelper _helper; + late PdfLineEndingStyle _beginLineStyle; + late PdfLineEndingStyle _endLineStyle; + int _leaderLineExt = 0; + late bool _lineCaption; + late PdfLineIntent _lineIntent; + late PdfLineCaptionType _captionType; + + // Properties + /// Gets the leader line. + int get leaderLine => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._obtainLeaderLine() + : _helper.leaderLine; + + /// Sets the leader line. + set leaderLine(int value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + final bool isLoadedAnnotation = helper.isLoadedAnnotation; + if (value != 0 && !isLoadedAnnotation) { + _helper.leaderLine = value; + } else if (isLoadedAnnotation) { + helper.dictionary!.setNumber(PdfDictionaryProperties.ll, value); + } + } + + /// Gets the line points of the annotation. + List get linePoints => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._obtainLinePoints() + : _helper.points; + + /// Sets the line points of the annotation. + set linePoints(List value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + _helper.points = value; + _helper.linePoints = PdfArray(_helper.points); + if (helper.isLoadedAnnotation) { + helper.dictionary!.setProperty( + PdfDictionaryProperties.l, + _helper.linePoints, + ); + } + } + + /// Gets the line intent of the annotation. + PdfLineIntent get lineIntent => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._obtainLineIntent() + : _lineIntent; + + /// Sets the line intent of the annotation. + set lineIntent(PdfLineIntent value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + if (!helper.isLoadedAnnotation) { + _lineIntent = value; + } else { + helper.dictionary!.setName( + PdfName(PdfDictionaryProperties.it), + helper.getEnumName(value), + ); + } + } + + /// Gets the line caption of the annotation. + bool get lineCaption => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._obtainLineCaption() + : _lineCaption; + + /// Sets the line caption of the annotation. + set lineCaption(bool value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + if (!helper.isLoadedAnnotation) { + _lineCaption = value; + } else { + helper.dictionary!.setBoolean(PdfDictionaryProperties.cap, value); + } + } + + /// Gets the leader line extension. + int get leaderLineExt => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._obtainLeaderExt() + : _leaderLineExt; + + /// Sets the leader line extension. + set leaderLineExt(int value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + if (!helper.isLoadedAnnotation) { + _leaderLineExt = value; + } else { + helper.dictionary!.setNumber(PdfDictionaryProperties.lle, value); + } + } + + /// Gets the begin line style of the annotation. + PdfLineEndingStyle get beginLineStyle => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._getLineStyle(0) + : _beginLineStyle; + + /// Sets the end line style of the annotation. + set beginLineStyle(PdfLineEndingStyle value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + if (!helper.isLoadedAnnotation) { + _beginLineStyle = value; + } else { + PdfArray? lineStyle = _helper._obtainLineStyle(); + if (lineStyle == null) { + lineStyle = PdfArray(); + } else { + lineStyle.elements.removeAt(0); + } + lineStyle.insert( + 0, + PdfName( + helper.getEnumName( + _helper._getLineStyle(helper.getEnumName(value.toString())), + ), + ), + ); + helper.dictionary!.setProperty(PdfDictionaryProperties.le, lineStyle); + } + } + + /// Gets the end line style of the annotation. + PdfLineEndingStyle get endLineStyle => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._getLineStyle(1) + : _endLineStyle; + + /// Sets the end line style of the annotation. + set endLineStyle(PdfLineEndingStyle value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + if (!helper.isLoadedAnnotation) { + _endLineStyle = value; + } else { + PdfArray? lineStyle = _helper._obtainLineStyle(); + if (lineStyle == null) { + lineStyle = PdfArray(); + } else { + lineStyle.elements.removeAt(1); + } + lineStyle.insert( + 1, + PdfName( + helper.getEnumName( + _helper._getLineStyle(helper.getEnumName(value.toString())), + ), + ), + ); + helper.dictionary!.setProperty(PdfDictionaryProperties.le, lineStyle); + } + } + + /// Gets the caption type of the annotation. + PdfLineCaptionType get captionType => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._obtainCaptionType() + : _captionType; + + /// Sets the caption type of the annotation. + set captionType(PdfLineCaptionType value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + if (!helper.isLoadedAnnotation) { + _captionType = value; + } else { + helper.dictionary!.setProperty( + PdfDictionaryProperties.cp, + PdfName( + helper.getEnumName( + _helper._getCaptionType(helper.getEnumName(value.toString())), + ), + ), + ); + } + } + + /// Gets or sets the content of the annotation. + /// + /// The string value specifies the text of the annotation. + @override + String get text => super.text; + @override + set text(String value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + if (helper.textValue != value) { + helper.textValue = value; + helper.dictionary!.setString( + PdfDictionaryProperties.contents, + helper.textValue, + ); + } + } + + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + return _helper.border; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + _helper.border = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } + + /// Gets the inner color of the annotation. + PdfColor get innerColor => _helper.innerColor; + + /// Sets the inner color of the annotation. + set innerColor(PdfColor value) { + _helper.innerColor = value; + } + + IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; + + set _element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + PdfAnnotationHelper.getHelper(this).dictionary = value; + } + } +} + +/// [PdfLineAnnotation] helper +class PdfLineAnnotationHelper extends PdfAnnotationHelper { + /// internal constructor + PdfLineAnnotationHelper( + this.lineAnnotation, + List linePoints, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + DateTime? modifiedDate, + double? opacity, + List? flags, + bool? setAppearance, + }) : super(lineAnnotation) { + initializeAnnotation( + text: text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + this.linePoints = PdfArray(linePoints); + points = linePoints; + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(PdfDictionaryProperties.line), + ); + } + PdfLineAnnotationHelper._( + this.lineAnnotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super(lineAnnotation) { + initializeExistingAnnotation(dictionary, crossTable); + } + + /// internal field + late PdfLineAnnotation lineAnnotation; + + /// internal field + PdfArray? lineStyle; + + /// internal field + PdfArray? linePoints; + + /// internal field + int leaderLine = 0; + + /// internal field + List points = []; + + /// internal property + @override + IPdfPrimitive? get element => lineAnnotation._element; + + @override + set element(IPdfPrimitive? value) { + lineAnnotation._element = value; + } + + /// internal method + void save() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + if (PdfAnnotationCollectionHelper.getHelper( + lineAnnotation.page!.annotations, + ).flatten) { + helper.flatten = true; + } + if (helper.flatten || lineAnnotation.setAppearance) { + final PdfTemplate? appearance = _createAppearance(); + if (helper.flatten) { + if (appearance != null || helper.isLoadedAnnotation) { + if (lineAnnotation.page != null) { + _flattenAnnotation(lineAnnotation.page, appearance); + } + } + } else { + if (appearance != null) { + lineAnnotation.appearance.normal = appearance; + helper.dictionary!.setProperty( + PdfDictionaryProperties.ap, + PdfReferenceHolder(lineAnnotation.appearance), + ); + } + } + } + if (!helper.flatten && !helper.isLoadedAnnotation) { + helper.saveAnnotation(); + _savePdfLineDictionary(); + } + if (helper.flattenPopups) { + helper.flattenPopup(); + } + } + + void _savePdfLineDictionary() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + helper.saveAnnotation(); + lineStyle = PdfArray(); + if (lineStyle!.elements.isNotEmpty) { + lineStyle!.insert( + 0, + PdfName(helper.getEnumName(lineAnnotation.beginLineStyle)), + ); + lineStyle!.insert( + 1, + PdfName(helper.getEnumName(lineAnnotation.endLineStyle)), + ); + } else { + lineStyle!.add( + PdfName(helper.getEnumName(lineAnnotation.beginLineStyle)), + ); + lineStyle!.add(PdfName(helper.getEnumName(lineAnnotation.endLineStyle))); + } + final PdfDictionary dictionary = helper.dictionary!; + dictionary.setProperty(PdfDictionaryProperties.le, lineStyle); + if (linePoints != null) { + dictionary.setProperty(PdfDictionaryProperties.l, linePoints); + } else { + throw ArgumentError.value('LinePoints cannot be null'); + } + if (lineAnnotation.border.dashArray == 0) { + if (lineAnnotation.border.borderStyle == PdfBorderStyle.dashed) { + lineAnnotation.border.dashArray = 4; + } else if (lineAnnotation.border.borderStyle == PdfBorderStyle.dot) { + lineAnnotation.border.dashArray = 2; + } + } + dictionary.setProperty(PdfDictionaryProperties.bs, lineAnnotation.border); + if (!lineAnnotation.innerColor.isEmpty && + PdfColorHelper.getHelper(lineAnnotation.innerColor).alpha != 0) { + dictionary.setProperty( + PdfDictionaryProperties.ic, + PdfColorHelper.toArray(lineAnnotation.innerColor), + ); + } + dictionary[PdfDictionaryProperties.c] = PdfColorHelper.toArray( + lineAnnotation.color, + ); + + dictionary.setProperty( + PdfDictionaryProperties.it, + PdfName(helper.getEnumName(lineAnnotation.lineIntent)), + ); + + dictionary.setProperty( + PdfDictionaryProperties.lle, + PdfNumber(lineAnnotation.leaderLineExt), + ); + + dictionary.setProperty(PdfDictionaryProperties.ll, PdfNumber(leaderLine)); + + dictionary.setProperty( + PdfDictionaryProperties.cp, + PdfName(helper.getEnumName(lineAnnotation.captionType)), + ); + + dictionary.setProperty( + PdfDictionaryProperties.cap, + PdfBoolean(lineAnnotation.lineCaption), + ); + + dictionary.setProperty( + PdfDictionaryProperties.rect, + PdfArray.fromRectangle(_obtainLineBounds()), + ); + } + + void _flattenAnnotation(PdfPage? page, PdfTemplate? appearance) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + final PdfDictionary dictionary = helper.dictionary!; + if (helper.isLoadedAnnotation) { + final bool isContainsAP = dictionary.containsKey( + PdfDictionaryProperties.ap, + ); + if (isContainsAP && appearance == null) { + PdfDictionary? appearanceDictionary = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ap]) + as PdfDictionary?; + if (appearanceDictionary != null) { + appearanceDictionary = + PdfCrossTable.dereference( + appearanceDictionary[PdfDictionaryProperties.n], + ) + as PdfDictionary?; + if (appearanceDictionary != null) { + final PdfStream appearanceStream = + appearanceDictionary as PdfStream; + appearance = PdfTemplateHelper.fromPdfStream(appearanceStream); + final bool isNormalMatrix = helper.validateTemplateMatrix( + appearanceDictionary, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } else { + lineAnnotation.setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } + } + } else if (!isContainsAP && appearance == null) { + lineAnnotation.setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } else { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance!).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } else { + page!.graphics.save(); + final Rect rectangle = helper.calculateTemplateBounds( + lineAnnotation.bounds, + page, + appearance, + true, + ); + if (lineAnnotation.opacity < 1) { + page.graphics.setTransparency(lineAnnotation.opacity); + } + page.graphics.drawPdfTemplate( + appearance!, + Offset(rectangle.left, rectangle.top), + rectangle.size, + ); + page.annotations.remove(lineAnnotation); + page.graphics.restore(); + } + } + + PdfTemplate? _createAppearance() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + final bool isLoadedAnnotation = helper.isLoadedAnnotation; + if (isLoadedAnnotation && !lineAnnotation.setAppearance) { + return null; + } + final Rect nativeRectangle = _obtainLineBounds().rect; + final PdfTemplate template = PdfTemplateHelper.fromRect(nativeRectangle); + PdfAnnotationHelper.setMatrixToZeroRotation( + PdfTemplateHelper.getHelper(template).content, + ); + PdfTemplateHelper.getHelper(template).writeTransformation = false; + final PaintParams paintParams = PaintParams(); + final PdfGraphics? graphics = template.graphics; + final PdfPen mBorderPen = PdfPen( + lineAnnotation.color, + width: lineAnnotation.border.width, + ); + if (lineAnnotation.border.borderStyle == PdfBorderStyle.dashed) { + mBorderPen.dashStyle = PdfDashStyle.dash; + } else if (lineAnnotation.border.borderStyle == PdfBorderStyle.dot) { + mBorderPen.dashStyle = PdfDashStyle.dot; + } + paintParams.borderPen = mBorderPen; + paintParams.foreBrush = PdfSolidBrush(lineAnnotation.color); + final PdfFont mFont = PdfStandardFont( + PdfFontFamily.helvetica, + isLoadedAnnotation ? 10 : 9, + style: PdfFontStyle.regular, + ); + final PdfStringFormat format = PdfStringFormat(); + format.alignment = PdfTextAlignment.center; + format.lineAlignment = PdfVerticalAlignment.middle; + final double lineWidth = + mFont.measureString(lineAnnotation.text, format: format).width; + final List linePoints = _obtainLinePoints(); + if (linePoints.length == 4) { + final double x1 = linePoints[0].toDouble(); + final double y1 = linePoints[1].toDouble(); + final double x2 = linePoints[2].toDouble(); + final double y2 = linePoints[3].toDouble(); + double angle = 0; + if (x2 - x1 == 0) { + if (y2 > y1) { + angle = 90; + } else { + angle = 270; + } + } else { + angle = helper.getAngle(x1, y1, x2, y2); + } + double leadLine = 0; + double lineAngle = 0; + if (lineAnnotation.leaderLine < 0) { + leadLine = -lineAnnotation.leaderLine.toDouble(); + lineAngle = angle + 180; + } else { + leadLine = lineAnnotation.leaderLine.toDouble(); + lineAngle = angle; + } + final List x1y1 = [x1, y1]; + final List x2y2 = [x2, y2]; + final double line = + leadLine + + (isLoadedAnnotation ? _obtainLeaderOffset().toDouble() : 0); + final List startingPoint = helper.getAxisValue( + x1y1, + lineAngle + 90, + line, + ); + final List endingPoint = helper.getAxisValue( + x2y2, + lineAngle + 90, + line, + ); + final double lineDistance = sqrt( + pow(endingPoint[0] - startingPoint[0], 2) + + pow(endingPoint[1] - startingPoint[1], 2), + ); + final double centerWidth = + lineDistance / 2 - ((lineWidth / 2) + lineAnnotation.border.width); + final List middlePoint1 = helper.getAxisValue( + startingPoint, + angle, + centerWidth, + ); + final List middlePoint2 = helper.getAxisValue( + endingPoint, + angle + 180, + centerWidth, + ); + List lineStartingPoint; + List lineEndingPoint; + if (lineAnnotation.beginLineStyle == PdfLineEndingStyle.openArrow || + lineAnnotation.beginLineStyle == PdfLineEndingStyle.closedArrow) { + lineStartingPoint = helper.getAxisValue( + startingPoint, + angle, + lineAnnotation.border.width, + ); + } else { + lineStartingPoint = startingPoint; + } + if (lineAnnotation.endLineStyle == PdfLineEndingStyle.openArrow || + lineAnnotation.endLineStyle == PdfLineEndingStyle.closedArrow) { + lineEndingPoint = helper.getAxisValue( + endingPoint, + angle, + -lineAnnotation.border.width, + ); + } else { + lineEndingPoint = endingPoint; + } + final String caption = helper.getEnumName(lineAnnotation.captionType); + if (lineAnnotation.opacity < 1) { + graphics!.save(); + graphics.setTransparency(lineAnnotation.opacity); + } + if (lineAnnotation.text.isEmpty || + caption == 'Top' || + !lineAnnotation.lineCaption) { + graphics!.drawLine( + mBorderPen, + Offset(lineStartingPoint[0], -lineStartingPoint[1]), + Offset(lineEndingPoint[0], -lineEndingPoint[1]), + ); + } else { + graphics!.drawLine( + mBorderPen, + Offset(lineStartingPoint[0], -lineStartingPoint[1]), + Offset(middlePoint1[0], -middlePoint1[1]), + ); + graphics.drawLine( + mBorderPen, + Offset(lineEndingPoint[0], -lineEndingPoint[1]), + Offset(middlePoint2[0], -middlePoint2[1]), + ); + } + if (lineAnnotation.opacity < 1) { + graphics.restore(); + } + //Set begin and end line style. + final PdfBrush backBrush = PdfSolidBrush(lineAnnotation.innerColor); + final PdfArray lineStyle = PdfArray(); + lineStyle.insert( + 0, + PdfName(helper.getEnumName(lineAnnotation.beginLineStyle)), + ); + lineStyle.insert( + 1, + PdfName(helper.getEnumName(lineAnnotation.endLineStyle)), + ); + final double borderLength = lineAnnotation.border.width; + helper.setLineEndingStyles( + startingPoint, + endingPoint, + graphics, + angle, + mBorderPen, + backBrush, + lineStyle, + borderLength, + ); + //Set leader extension. + final List beginLineExt = helper.getAxisValue( + startingPoint, + lineAngle + 90, + lineAnnotation.leaderLineExt.toDouble(), + ); + graphics.drawLine( + mBorderPen, + Offset(startingPoint[0], -startingPoint[1]), + Offset(beginLineExt[0], -beginLineExt[1]), + ); + final List endLineExt = helper.getAxisValue( + endingPoint, + lineAngle + 90, + lineAnnotation.leaderLineExt.toDouble(), + ); + graphics.drawLine( + mBorderPen, + Offset(endingPoint[0], -endingPoint[1]), + Offset(endLineExt[0], -endLineExt[1]), + ); + //Set leader line + final List beginLeaderLine = helper.getAxisValue( + startingPoint, + lineAngle - 90, + leadLine, + ); + graphics.drawLine( + mBorderPen, + Offset(startingPoint[0], -startingPoint[1]), + Offset(beginLeaderLine[0], -beginLeaderLine[1]), + ); + final List endLeaderLine = helper.getAxisValue( + endingPoint, + lineAngle - 90, + leadLine, + ); + graphics.drawLine( + mBorderPen, + Offset(endingPoint[0], -endingPoint[1]), + Offset(endLeaderLine[0], -endLeaderLine[1]), + ); + //Set caption Type. + if (lineAnnotation.lineCaption) { + final double midpoint = lineDistance / 2; + final List centerPoint = helper.getAxisValue( + startingPoint, + angle, + midpoint, + ); + final List captionPosition = _getCaptionPosition( + caption, + centerPoint, + angle, + mFont, + ); + graphics.translateTransform(captionPosition[0], -captionPosition[1]); + graphics.rotateTransform(-angle); + graphics.drawString( + lineAnnotation.text, + mFont, + brush: backBrush, + bounds: Rect.fromLTWH(-lineWidth / 2, 0, 0, 0), + ); + } + } + if (isLoadedAnnotation) { + helper.dictionary!.setProperty( + PdfDictionaryProperties.rect, + PdfArray.fromRectangle(_obtainLineBounds()), + ); + } + if (!isLoadedAnnotation && helper.flatten) { + final double pageHeight = lineAnnotation.page!.size.height; + final PdfMargins? margins = helper.obtainMargin(); + if (lineAnnotation.page != null) { + lineAnnotation.bounds = Rect.fromLTWH( + nativeRectangle.left - margins!.left, + pageHeight - + (nativeRectangle.top + nativeRectangle.height) - + margins.top, + nativeRectangle.width, + nativeRectangle.height, + ); + } else { + lineAnnotation.bounds = Rect.fromLTWH( + nativeRectangle.left, + pageHeight - (nativeRectangle.top + nativeRectangle.height), + nativeRectangle.width, + nativeRectangle.height, + ); + } + } + return template; + } + + List _getCaptionPosition( + String caption, + List centerPoint, + double angle, + PdfFont font, + ) { + List captionPosition = List.filled(2, 0); + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + if (helper.isLoadedAnnotation) { + final bool isContainsMeasure = helper.dictionary!.items!.containsKey( + PdfName(PdfDictionaryProperties.measure), + ); + final double length = + caption == 'Top' + ? isContainsMeasure + ? 2 * font.height + : font.height + : isContainsMeasure + ? 3 * (font.height / 2) + : font.height / 2; + captionPosition = helper.getAxisValue(centerPoint, angle + 90, length); + } else { + captionPosition = helper.getAxisValue( + centerPoint, + angle + 90, + caption == 'Top' ? font.height : font.height / 2, + ); + } + return captionPosition; + } + + // Gets leader line of the lineAnnotation. + int _obtainLeaderLine() { + int lLine = 0; + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + if (helper.dictionary!.containsKey(PdfDictionaryProperties.ll)) { + final PdfNumber ll = + helper.dictionary![PdfDictionaryProperties.ll]! as PdfNumber; + lLine = ll.value!.toInt(); + } + return lLine; + } + + // Gets the line intent of the annotation. + PdfLineIntent _obtainLineIntent() { + PdfLineIntent lineintentValue = PdfLineIntent.lineArrow; + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + if (helper.dictionary!.containsKey(PdfDictionaryProperties.it)) { + final PdfName lineintent = + helper.crossTable.getObject( + helper.dictionary![PdfDictionaryProperties.it], + )! + as PdfName; + lineintentValue = _getLineIntentText(lineintent.name.toString()); + } + return lineintentValue; + } + + // Get the Line Intent Text. + PdfLineIntent _getLineIntentText(String lintent) { + PdfLineIntent lineintent = PdfLineIntent.lineArrow; + switch (lintent) { + case 'LineArrow': + lineintent = PdfLineIntent.lineArrow; + break; + case 'LineDimension': + lineintent = PdfLineIntent.lineDimension; + break; + } + return lineintent; + } + + List _obtainLinePoints() { + List points = []; + if (!PdfAnnotationHelper.getHelper(lineAnnotation).isLoadedAnnotation) { + if (linePoints != null) { + // ignore: prefer_final_in_for_each + for (IPdfPrimitive? linePoint in linePoints!.elements) { + if (linePoint is PdfNumber) { + points.add(linePoint.value!.toInt()); + } + } + } + } else { + if (PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary!.containsKey(PdfDictionaryProperties.l)) { + linePoints = + PdfCrossTable.dereference( + PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary![PdfDictionaryProperties.l], + ) + as PdfArray?; + if (linePoints != null) { + points = []; + // ignore: prefer_final_in_for_each + for (IPdfPrimitive? value in linePoints!.elements) { + if (value is PdfNumber) { + points.add(value.value!.toInt()); + } + } + } + } + } + return points; + } + + // Gets line caption of the annotation. + bool _obtainLineCaption() { + bool lCaption = false; + if (PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary!.containsKey(PdfDictionaryProperties.cap)) { + final PdfBoolean lCap = + PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary![PdfDictionaryProperties.cap]! + as PdfBoolean; + lCaption = lCap.value!; + } + return lCaption; + } + + // Gets leader ext of the annotation. + int _obtainLeaderExt() { + int lLineExt = 0; + if (PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary!.containsKey(PdfDictionaryProperties.lle)) { + final PdfNumber lExt = + PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary![PdfDictionaryProperties.lle]! + as PdfNumber; + lLineExt = lExt.value!.toInt(); + } + return lLineExt; + } + + // Gets line style of the annotation. + PdfLineEndingStyle _getLineStyle(dynamic value) { + PdfLineEndingStyle linestyle = PdfLineEndingStyle.none; + if (value is int) { + final PdfArray? array = _obtainLineStyle(); + if (array != null) { + final PdfName style = array[value]! as PdfName; + linestyle = _getLineStyle(style.name); + } + } else if (value is String) { + switch (value) { + case 'Square': + linestyle = PdfLineEndingStyle.square; + break; + case 'Circle': + linestyle = PdfLineEndingStyle.circle; + break; + case 'Diamond': + linestyle = PdfLineEndingStyle.diamond; + break; + case 'OpenArrow': + linestyle = PdfLineEndingStyle.openArrow; + break; + case 'ClosedArrow': + linestyle = PdfLineEndingStyle.closedArrow; + break; + case 'None': + linestyle = PdfLineEndingStyle.none; + break; + case 'ROpenArrow': + linestyle = PdfLineEndingStyle.rOpenArrow; + break; + case 'Butt': + linestyle = PdfLineEndingStyle.butt; + break; + case 'RClosedArrow': + linestyle = PdfLineEndingStyle.rClosedArrow; + break; + case 'Slash': + linestyle = PdfLineEndingStyle.slash; + break; + } + } + return linestyle; + } + + PdfRectangle _obtainLineBounds() { + PdfRectangle bounds = PdfRectangle.fromRect(lineAnnotation.bounds); + if (points.length == 4 || + PdfAnnotationHelper.getHelper(lineAnnotation).isLoadedAnnotation) { + final List lPoints = _obtainLinePoints(); + if (lPoints.length == 4) { + final PdfArray lineStyle = PdfArray(); + if (lineStyle.elements.isNotEmpty) { + lineStyle.insert( + 0, + PdfName( + PdfAnnotationHelper.getHelper( + lineAnnotation, + ).getEnumName(lineAnnotation.beginLineStyle), + ), + ); + lineStyle.insert( + 1, + PdfName( + PdfAnnotationHelper.getHelper( + lineAnnotation, + ).getEnumName(lineAnnotation.endLineStyle), + ), + ); + } else { + lineStyle.add(PdfName(lineAnnotation.beginLineStyle.toString())); + lineStyle.add(PdfName(lineAnnotation.endLineStyle.toString())); + } + bounds = + PdfAnnotationHelper.getHelper(lineAnnotation).isLoadedAnnotation + ? PdfAnnotationHelper.getHelper( + lineAnnotation, + ).calculateLineBounds( + lPoints, + lineAnnotation.leaderLineExt, + lineAnnotation.leaderLine, + _obtainLeaderOffset(), + lineStyle, + lineAnnotation.border.width, + ) + : PdfAnnotationHelper.getHelper( + lineAnnotation, + ).calculateLineBounds( + lPoints, + lineAnnotation.leaderLineExt, + leaderLine, + 0, + lineStyle, + lineAnnotation.border.width, + ); + bounds = PdfRectangle( + bounds.left - 8, + bounds.top - 8, + bounds.width + 2 * 8, + bounds.height + 2 * 8, + ); + } + } + return bounds; + } + + // Gets leader offset of the annotation. + int _obtainLeaderOffset() { + int lLineOffset = 0; + if (PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary!.containsKey(PdfDictionaryProperties.llo)) { + final PdfNumber lOffset = + PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary![PdfDictionaryProperties.llo]! + as PdfNumber; + lLineOffset = lOffset.value!.toInt(); + } + return lLineOffset; + } + + // Gets line style of the annotation. + PdfArray? _obtainLineStyle() { + PdfArray? array; + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + lineAnnotation, + ); + if (helper.dictionary!.containsKey(PdfDictionaryProperties.le)) { + array = + helper.crossTable.getObject( + helper.dictionary![PdfDictionaryProperties.le], + ) + as PdfArray?; + } + return array; + } + + // Gets caption type of the annotation. + PdfLineCaptionType _obtainCaptionType() { + PdfLineCaptionType captiontypeValue = PdfLineCaptionType.inline; + if (PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary!.containsKey(PdfDictionaryProperties.cp)) { + final PdfName cType = + PdfAnnotationHelper.getHelper( + lineAnnotation, + ).dictionary![PdfDictionaryProperties.cp]! + as PdfName; + captiontypeValue = _getCaptionType(cType.name.toString()); + } + return captiontypeValue; + } + + // Gets caption type of the annotation. + PdfLineCaptionType _getCaptionType(String cType) { + PdfLineCaptionType captiontype = PdfLineCaptionType.inline; + if (cType == 'Inline') { + captiontype = PdfLineCaptionType.inline; + } else { + captiontype = PdfLineCaptionType.top; + } + return captiontype; + } + + /// internal method + static PdfLineAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + return PdfLineAnnotation._(dictionary, crossTable, text); + } + + /// internal method + static PdfLineAnnotationHelper getHelper(PdfLineAnnotation annotation) { + return annotation._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_paintparams.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_paintparams.dart index b6ba3862e..c4c1cb1b0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_paintparams.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_paintparams.dart @@ -1,40 +1,40 @@ -import 'dart:ui'; - -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/pdf_pen.dart'; -import 'enum.dart'; - -/// internal class -class PaintParams { - /// internal constructor - PaintParams({ - this.backBrush, - this.foreBrush, - this.borderPen, - this.bounds, - this.style, - this.borderWidth, - this.shadowBrush, - }); - - /// internal field - PdfBrush? backBrush; - - /// internal field - PdfBrush? foreBrush; - - /// internal field - PdfPen? borderPen; - - /// internal field - Rect? bounds; - - /// internal field - PdfBorderStyle? style; - - /// internal field - int? borderWidth; - - /// internal field - PdfBrush? shadowBrush; -} +import 'dart:ui'; + +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/pdf_pen.dart'; +import 'enum.dart'; + +/// internal class +class PaintParams { + /// internal constructor + PaintParams({ + this.backBrush, + this.foreBrush, + this.borderPen, + this.bounds, + this.style, + this.borderWidth, + this.shadowBrush, + }); + + /// internal field + PdfBrush? backBrush; + + /// internal field + PdfBrush? foreBrush; + + /// internal field + PdfPen? borderPen; + + /// internal field + Rect? bounds; + + /// internal field + PdfBorderStyle? style; + + /// internal field + int? borderWidth; + + /// internal field + PdfBrush? shadowBrush; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_polygon_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_polygon_annotation.dart index c581177ab..7f5985506 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_polygon_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_polygon_annotation.dart @@ -1,743 +1,743 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/pdf_annotation_border.dart'; -import '../drawing/drawing.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_collection.dart'; - -/// Represents a Polygon annotation. -class PdfPolygonAnnotation extends PdfAnnotation { - // Constructor - /// Initializes new instance of the [PdfPolygonAnnotation] class. - /// - /// ``` dart - /// PdfDocument document = PdfDocument(); - /// PdfPage page = document.pages.add(); - /// List polypoints = [ - /// 50, - /// 298, - /// 100, - /// 325, - /// 200, - /// 355, - /// 300, - /// 230, - /// 180, - /// 230 - /// ]; - /// PdfPolygonAnnotation polygonAnnotation = - /// PdfPolygonAnnotation(polypoints, 'PolygonAnnotation'); - /// polygonAnnotation.color = PdfColor(255, 0, 0); - /// polygonAnnotation.innerColor = PdfColor(255, 0, 255); - /// page.annotations.add(polygonAnnotation); - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfPolygonAnnotation( - List points, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - DateTime? modifiedDate, - double? opacity, - List? flags, - bool? setAppearance, - }) { - _helper = PdfPolygonAnnotationHelper( - this, - points, - text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - } - - PdfPolygonAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - _helper = PdfPolygonAnnotationHelper._(this, dictionary, crossTable); - this.text = text; - } - - // Fields - late PdfPolygonAnnotationHelper _helper; - - /// Gets the polygon points of the annotation. - List get polygonPoints { - if (_helper.isLoadedAnnotation) { - final List points = []; - final PdfDictionary dictionary = - PdfAnnotationHelper.getHelper(this).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.vertices)) { - final PdfArray? linePoints = - dictionary[PdfDictionaryProperties.vertices] as PdfArray?; - if (linePoints != null) { - // ignore: avoid_function_literals_in_foreach_calls - linePoints.elements.forEach((IPdfPrimitive? element) { - if (element != null && element is PdfNumber) { - points.add(element.value!.toInt()); - } - }); - } - } - return points; - } else { - return _helper._polygonPoints; - } - } - - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - return _helper.border; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - _helper.border = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } - - /// Gets the inner color of the annotation. - PdfColor get innerColor => _helper.innerColor; - - /// Sets the inner color of the annotation. - set innerColor(PdfColor value) { - _helper.innerColor = value; - } - - IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; - - set _element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - PdfAnnotationHelper.getHelper(this).dictionary = value; - } - } -} - -/// [PdfPolygonAnnotation] helper -class PdfPolygonAnnotationHelper extends PdfAnnotationHelper { - /// internal constructor - PdfPolygonAnnotationHelper( - this.annotation, - List points, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - DateTime? modifiedDate, - double? opacity, - List? flags, - bool? setAppearance, - }) : super(annotation) { - initializeAnnotation( - text: text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(PdfDictionaryProperties.polygon), - ); - linePoints = PdfArray(points); - _polygonPoints = points; - } - PdfPolygonAnnotationHelper._( - this.annotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super(annotation) { - initializeExistingAnnotation(dictionary, crossTable); - } - - /// internal field - late PdfPolygonAnnotation annotation; - - /// internal field - PdfArray? linePoints; - late List _polygonPoints; - - /// internal method - static PdfPolygonAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - return PdfPolygonAnnotation._(dictionary, crossTable, text); - } - - /// internal property - @override - IPdfPrimitive? get element => annotation._element; - - @override - set element(IPdfPrimitive? value) { - annotation._element = value; - } - - /// internal method - static PdfPolygonAnnotationHelper getHelper(PdfPolygonAnnotation annotation) { - return annotation._helper; - } - - /// internal method - void save() { - if (PdfAnnotationCollectionHelper.getHelper( - annotation.page!.annotations, - ).flatten) { - PdfAnnotationHelper.getHelper(annotation).flatten = true; - } - if (PdfAnnotationHelper.getHelper(annotation).isLoadedAnnotation) { - _saveOldPolygonAnnotation(); - } else { - _saveNewPolygonAnnotation(); - } - } - - void _saveNewPolygonAnnotation() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - final PdfDictionary dictionary = helper.dictionary!; - Rect nativeRectangle = Rect.zero; - if (annotation.setAppearance) { - _getBoundsValue(); - nativeRectangle = Rect.fromLTWH( - annotation.bounds.left - annotation.border.width, - annotation.bounds.top - (annotation.border.width), - annotation.bounds.width + (2 * annotation.border.width), - annotation.bounds.height + (2 * annotation.border.width), - ); - dictionary.setProperty(PdfDictionaryProperties.ap, annotation.appearance); - if (dictionary[PdfDictionaryProperties.ap] != null) { - annotation.appearance.normal = PdfTemplateHelper.fromRect( - nativeRectangle, - ); - final PdfTemplate template = annotation.appearance.normal; - PdfTemplateHelper.getHelper(template).writeTransformation = false; - final PdfGraphics? graphics = template.graphics; - final PdfBrush? backBrushColor = - annotation.innerColor.isEmpty - ? null - : PdfSolidBrush(annotation.innerColor); - PdfPen? borderPenColor; - if (annotation.border.width > 0 && - PdfColorHelper.getHelper(annotation.color).alpha != 0) { - borderPenColor = PdfPen( - annotation.color, - width: annotation.border.width, - ); - } - if (helper.flatten) { - annotation.page!.annotations.remove(annotation); - annotation.page!.graphics.drawPolygon( - _getLinePoints()!, - pen: borderPenColor, - brush: backBrushColor, - ); - } else { - graphics!.drawPolygon( - _getLinePoints()!, - pen: borderPenColor, - brush: backBrushColor, - ); - } - } - } - if (helper.flatten && !annotation.setAppearance) { - annotation.page!.annotations.remove(annotation); - PdfPen? borderPenColor; - if (annotation.border.width > 0 && - PdfColorHelper.getHelper(annotation.color).alpha != 0) { - borderPenColor = PdfPen( - annotation.color, - width: annotation.border.width, - ); - } - final PdfBrush? backBrushColor = - annotation.innerColor.isEmpty - ? null - : PdfSolidBrush(annotation.innerColor); - annotation.page!.graphics.drawPolygon( - _getLinePoints()!, - pen: borderPenColor, - brush: backBrushColor, - ); - } else if (!helper.flatten) { - helper.saveAnnotation(); - dictionary.setProperty( - PdfDictionaryProperties.vertices, - PdfArray(linePoints), - ); - dictionary.setProperty(PdfDictionaryProperties.bs, annotation.border); - _getBoundsValue(); - dictionary.setProperty( - PdfDictionaryProperties.rect, - PdfArray.fromRectangle(PdfRectangle.fromRect(annotation.bounds)), - ); - if (annotation.setAppearance) { - dictionary.setProperty( - PdfDictionaryProperties.rect, - PdfArray.fromRectangle(PdfRectangle.fromRect(nativeRectangle)), - ); - } - } - } - - void _saveOldPolygonAnnotation() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - PdfGraphicsState? state; - PdfRectangle nativeRectangle = PdfRectangle.empty; - final PdfDictionary dictionary = helper.dictionary!; - if (annotation.setAppearance) { - _getBoundsValue(); - nativeRectangle = PdfRectangle( - annotation.bounds.left - annotation.border.width, - annotation.page!.size.height - - annotation.bounds.top - - (annotation.border.width) - - annotation.bounds.height, - annotation.bounds.width + (2 * annotation.border.width), - annotation.bounds.height + (2 * annotation.border.width), - ); - dictionary.setProperty(PdfDictionaryProperties.ap, annotation.appearance); - if (dictionary[PdfDictionaryProperties.ap] != null) { - annotation.appearance.normal = PdfTemplateHelper.fromRect( - nativeRectangle.rect, - ); - final PdfTemplate template = annotation.appearance.normal; - PdfTemplateHelper.getHelper(template).writeTransformation = false; - final PdfGraphics? graphics = annotation.appearance.normal.graphics; - PdfBrush? backgroundBrush; - if (PdfColorHelper.getHelper(annotation.innerColor).alpha != 0) { - backgroundBrush = PdfSolidBrush(annotation.innerColor); - } - PdfPen? borderPenColor; - if (annotation.border.width > 0) { - borderPenColor = PdfPen( - annotation.color, - width: annotation.border.width, - ); - } - if (dictionary.containsKey(PdfDictionaryProperties.bs)) { - PdfDictionary? bSDictionary; - if (dictionary.items![PdfName(PdfDictionaryProperties.bs)] - is PdfReferenceHolder) { - bSDictionary = - (dictionary.items![PdfName(PdfDictionaryProperties.bs)]! - as PdfReferenceHolder) - .object - as PdfDictionary?; - } else { - bSDictionary = - dictionary.items![PdfName(PdfDictionaryProperties.bs)] - as PdfDictionary?; - } - if (bSDictionary!.containsKey(PdfDictionaryProperties.d)) { - final PdfArray? dashPatternArray = - PdfCrossTable.dereference( - bSDictionary.items![PdfName(PdfDictionaryProperties.d)], - ) - as PdfArray?; - if (dashPatternArray != null) { - final List dashPattern = List.filled( - dashPatternArray.count, - 0, - growable: true, - ); - for (int i = 0; i < dashPatternArray.count; i++) { - final IPdfPrimitive? pdfPrimitive = - dashPatternArray.elements[i]; - if (pdfPrimitive != null && pdfPrimitive is PdfNumber) { - dashPattern[i] = pdfPrimitive.value!.toDouble(); - } - } - borderPenColor!.dashStyle = PdfDashStyle.dash; - PdfPenHelper.getHelper(borderPenColor).isSkipPatternWidth = true; - borderPenColor.dashPattern = dashPattern; - } - } - } - if (helper.flatten) { - annotation.page!.annotations.remove(annotation); - if (annotation.opacity < 1) { - state = annotation.page!.graphics.save(); - annotation.page!.graphics.setTransparency(annotation.opacity); - } - if (dictionary.containsKey(PdfDictionaryProperties.be)) { - final PdfDictionary beDictionary = - dictionary[PdfName(PdfDictionaryProperties.be)]! - as PdfDictionary; - final double? iNumber = - (beDictionary.items![PdfName(PdfDictionaryProperties.i)]! - as PdfNumber) - .value - as double?; - final double radius = iNumber == 1 ? 5 : 10; - if (radius > 0) { - final List points = _getLinePoints()!; - if (points[0].dy > points[points.length - 1].dy) { - helper.drawCloudStyle( - graphics!, - backgroundBrush, - borderPenColor, - radius, - 0.833, - _getLinePoints()!, - false, - ); - } - helper.drawCloudStyle( - annotation.page!.graphics, - backgroundBrush, - borderPenColor, - radius, - 0.833, - _getLinePoints()!, - false, - ); - } else { - annotation.page!.graphics.drawPolygon( - _getLinePoints()!, - pen: borderPenColor, - brush: backgroundBrush, - ); - } - } else { - annotation.page!.graphics.drawPolygon( - _getLinePoints()!, - pen: borderPenColor, - brush: backgroundBrush, - ); - } - if (annotation.opacity < 1) { - annotation.page!.graphics.restore(state); - } - } else { - if (annotation.opacity < 1) { - state = graphics!.save(); - graphics.setTransparency(annotation.opacity); - } - if (dictionary.containsKey(PdfDictionaryProperties.be)) { - final PdfDictionary beDictionary = - dictionary[PdfName(PdfDictionaryProperties.be)]! - as PdfDictionary; - final double? iNumber = - (beDictionary.items![PdfName(PdfDictionaryProperties.i)]! - as PdfNumber) - .value - as double?; - final double radius = iNumber == 1 ? 5 : 10; - List points = _getLinePoints()!; - if (points[0].dy > points[points.length - 1].dy) { - final List point = []; - for (int i = 0; i < points.length; i++) { - point.add(Offset(points[i].dx, -points[i].dy)); - } - points = point; - helper.drawCloudStyle( - graphics!, - backgroundBrush, - borderPenColor, - radius, - 0.833, - points, - true, - ); - } else { - helper.drawCloudStyle( - graphics!, - backgroundBrush, - borderPenColor, - radius, - 0.833, - points, - false, - ); - } - } else { - graphics!.drawPolygon( - _getLinePoints()!, - pen: borderPenColor, - brush: backgroundBrush, - ); - } - if (annotation.opacity < 1) { - graphics.restore(state); - } - } - dictionary.setProperty( - PdfDictionaryProperties.rect, - PdfArray.fromRectangle(nativeRectangle), - ); - } - } - if (helper.flatten && !annotation.setAppearance) { - if (dictionary[PdfDictionaryProperties.ap] != null) { - IPdfPrimitive? obj = dictionary[PdfDictionaryProperties.ap]; - PdfDictionary? dic = PdfCrossTable.dereference(obj) as PdfDictionary?; - PdfTemplate? template; - if (dic != null) { - obj = dic[PdfDictionaryProperties.n]; - dic = PdfCrossTable.dereference(obj) as PdfDictionary?; - if (dic != null && dic is PdfStream) { - final PdfStream stream = dic; - template = PdfTemplateHelper.fromPdfStream(stream); - state = annotation.page!.graphics.save(); - if (annotation.opacity < 1) { - annotation.page!.graphics.setTransparency(annotation.opacity); - } - final bool isNormalMatrix = helper.validateTemplateMatrix(dic); - final Rect rect = helper.calculateTemplateBounds( - annotation.bounds, - annotation.page, - template, - isNormalMatrix, - ); - annotation.page!.graphics.drawPdfTemplate( - template, - rect.topLeft, - rect.size, - ); - annotation.page!.graphics.restore(state); - annotation.page!.annotations.remove(annotation); - } - } - } else { - annotation.page!.annotations.remove(annotation); - final PdfPen borderPenColor = PdfPen( - annotation.color, - width: annotation.border.width, - ); - final PdfBrush? backgroundBrush = - annotation.innerColor.isEmpty - ? null - : PdfSolidBrush(annotation.innerColor); - if (annotation.opacity < 1) { - state = annotation.page!.graphics.save(); - annotation.page!.graphics.setTransparency(annotation.opacity); - } - if (dictionary.containsKey(PdfDictionaryProperties.be)) { - final IPdfPrimitive? primitive = - dictionary[PdfName(PdfDictionaryProperties.be)]; - final PdfDictionary beDictionary = - (primitive is PdfReferenceHolder ? primitive.object : primitive)! - as PdfDictionary; - final double? iNumber = - (beDictionary.items![PdfName(PdfDictionaryProperties.i)]! - as PdfNumber) - .value - as double?; - final double radius = iNumber == 1 ? 5 : 10; - helper.drawCloudStyle( - annotation.page!.graphics, - backgroundBrush, - borderPenColor, - radius, - 0.833, - _getLinePoints()!, - false, - ); - } else { - annotation.page!.graphics.drawPolygon( - _getLinePoints()!, - pen: borderPenColor, - brush: backgroundBrush, - ); - } - if (annotation.opacity < 1) { - annotation.page!.graphics.restore(state); - } - } - if (helper.flattenPopups) { - helper.flattenPopup(); - } - } - } - - List? _getLinePoints() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - if (helper.isLoadedAnnotation) { - List? points; - if (helper.dictionary!.containsKey(PdfDictionaryProperties.vertices)) { - final PdfArray? linePoints = - helper.dictionary![PdfDictionaryProperties.vertices] as PdfArray?; - if (linePoints != null) { - final List point = []; - for (int i = 0; i < linePoints.count; i++) { - final PdfNumber number = linePoints[i]! as PdfNumber; - point.add(number.value!.toDouble()); - } - points = []; - for (int j = 0; j < point.length; j = j + 2) { - if (helper.flatten) { - points.add( - Offset(point[j], annotation.page!.size.height - point[j + 1]), - ); - } else { - points.add(Offset(point[j], -point[j + 1])); - } - } - } - } - return points; - } else { - final List points = []; - if (linePoints != null) { - final List pointsValue = []; - // ignore: prefer_final_in_for_each - for (IPdfPrimitive? linePoint in linePoints!.elements) { - if (linePoint is PdfNumber) { - pointsValue.add(linePoint.value!.toDouble()); - } - } - for (int j = 0; j < pointsValue.length; j = j + 2) { - final double pageHeight = annotation.page!.size.height; - if (helper.flatten) { - PdfPageHelper.getHelper(annotation.page!).isLoadedPage - ? points.add( - Offset(pointsValue[j], pageHeight - pointsValue[j + 1]), - ) - : points.add( - Offset( - pointsValue[j] - - PdfPageHelper.getHelper( - annotation.page!, - ).section!.pageSettings.margins.left, - pageHeight - - pointsValue[j + 1] - - PdfPageHelper.getHelper( - annotation.page!, - ).section!.pageSettings.margins.right, - ), - ); - } else { - points.add(Offset(pointsValue[j], -pointsValue[j + 1])); - } - } - } - return points; - } - } - - void _getBoundsValue() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - if (helper.isLoadedAnnotation) { - final PdfArray rect = - helper.dictionary![PdfDictionaryProperties.rect]! as PdfArray; - annotation.bounds = rect.toRectangle().rect; - final List xval = []; - final List yval = []; - if (helper.dictionary!.containsKey(PdfDictionaryProperties.vertices)) { - final PdfArray linePoints = - PdfCrossTable.dereference( - helper.dictionary![PdfDictionaryProperties.vertices], - )! - as PdfArray; - if (linePoints.count > 0) { - final List points = List.filled( - linePoints.count, - 0, - growable: true, - ); - for (int j = 0; j < linePoints.count; j++) { - final PdfNumber number = linePoints[j]! as PdfNumber; - points[j] = number.value!.toDouble(); - } - for (int i = 0; i < points.length; i++) { - if (i.isEven) { - xval.add(points[i]); - } else { - yval.add(points[i]); - } - } - } - } - xval.sort(); - yval.sort(); - annotation.bounds = Rect.fromLTWH( - xval[0], - yval[0], - xval[xval.length - 1] - xval[0], - yval[yval.length - 1] - yval[0], - ); - } else { - final List xval = []; - final List yval = []; - if (linePoints!.count > 0) { - final List pointsValue = []; - // ignore: prefer_final_in_for_each - for (IPdfPrimitive? linePoint in linePoints!.elements) { - if (linePoint is PdfNumber) { - pointsValue.add(linePoint.value!.toDouble()); - } - } - for (int i = 0; i < pointsValue.length; i++) { - if (i.isEven) { - xval.add(pointsValue[i]); - } else { - yval.add(pointsValue[i]); - } - } - } - xval.sort(); - yval.sort(); - annotation.bounds = Rect.fromLTWH( - xval[0], - yval[0], - xval[xval.length - 1] - xval[0], - yval[yval.length - 1] - yval[0], - ); - } - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/pdf_annotation_border.dart'; +import '../drawing/drawing.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_collection.dart'; + +/// Represents a Polygon annotation. +class PdfPolygonAnnotation extends PdfAnnotation { + // Constructor + /// Initializes new instance of the [PdfPolygonAnnotation] class. + /// + /// ``` dart + /// PdfDocument document = PdfDocument(); + /// PdfPage page = document.pages.add(); + /// List polypoints = [ + /// 50, + /// 298, + /// 100, + /// 325, + /// 200, + /// 355, + /// 300, + /// 230, + /// 180, + /// 230 + /// ]; + /// PdfPolygonAnnotation polygonAnnotation = + /// PdfPolygonAnnotation(polypoints, 'PolygonAnnotation'); + /// polygonAnnotation.color = PdfColor(255, 0, 0); + /// polygonAnnotation.innerColor = PdfColor(255, 0, 255); + /// page.annotations.add(polygonAnnotation); + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfPolygonAnnotation( + List points, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + DateTime? modifiedDate, + double? opacity, + List? flags, + bool? setAppearance, + }) { + _helper = PdfPolygonAnnotationHelper( + this, + points, + text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + } + + PdfPolygonAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + _helper = PdfPolygonAnnotationHelper._(this, dictionary, crossTable); + this.text = text; + } + + // Fields + late PdfPolygonAnnotationHelper _helper; + + /// Gets the polygon points of the annotation. + List get polygonPoints { + if (_helper.isLoadedAnnotation) { + final List points = []; + final PdfDictionary dictionary = + PdfAnnotationHelper.getHelper(this).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.vertices)) { + final PdfArray? linePoints = + dictionary[PdfDictionaryProperties.vertices] as PdfArray?; + if (linePoints != null) { + // ignore: avoid_function_literals_in_foreach_calls + linePoints.elements.forEach((IPdfPrimitive? element) { + if (element != null && element is PdfNumber) { + points.add(element.value!.toInt()); + } + }); + } + } + return points; + } else { + return _helper._polygonPoints; + } + } + + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + return _helper.border; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + _helper.border = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } + + /// Gets the inner color of the annotation. + PdfColor get innerColor => _helper.innerColor; + + /// Sets the inner color of the annotation. + set innerColor(PdfColor value) { + _helper.innerColor = value; + } + + IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; + + set _element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + PdfAnnotationHelper.getHelper(this).dictionary = value; + } + } +} + +/// [PdfPolygonAnnotation] helper +class PdfPolygonAnnotationHelper extends PdfAnnotationHelper { + /// internal constructor + PdfPolygonAnnotationHelper( + this.annotation, + List points, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + DateTime? modifiedDate, + double? opacity, + List? flags, + bool? setAppearance, + }) : super(annotation) { + initializeAnnotation( + text: text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(PdfDictionaryProperties.polygon), + ); + linePoints = PdfArray(points); + _polygonPoints = points; + } + PdfPolygonAnnotationHelper._( + this.annotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super(annotation) { + initializeExistingAnnotation(dictionary, crossTable); + } + + /// internal field + late PdfPolygonAnnotation annotation; + + /// internal field + PdfArray? linePoints; + late List _polygonPoints; + + /// internal method + static PdfPolygonAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + return PdfPolygonAnnotation._(dictionary, crossTable, text); + } + + /// internal property + @override + IPdfPrimitive? get element => annotation._element; + + @override + set element(IPdfPrimitive? value) { + annotation._element = value; + } + + /// internal method + static PdfPolygonAnnotationHelper getHelper(PdfPolygonAnnotation annotation) { + return annotation._helper; + } + + /// internal method + void save() { + if (PdfAnnotationCollectionHelper.getHelper( + annotation.page!.annotations, + ).flatten) { + PdfAnnotationHelper.getHelper(annotation).flatten = true; + } + if (PdfAnnotationHelper.getHelper(annotation).isLoadedAnnotation) { + _saveOldPolygonAnnotation(); + } else { + _saveNewPolygonAnnotation(); + } + } + + void _saveNewPolygonAnnotation() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + final PdfDictionary dictionary = helper.dictionary!; + Rect nativeRectangle = Rect.zero; + if (annotation.setAppearance) { + _getBoundsValue(); + nativeRectangle = Rect.fromLTWH( + annotation.bounds.left - annotation.border.width, + annotation.bounds.top - (annotation.border.width), + annotation.bounds.width + (2 * annotation.border.width), + annotation.bounds.height + (2 * annotation.border.width), + ); + dictionary.setProperty(PdfDictionaryProperties.ap, annotation.appearance); + if (dictionary[PdfDictionaryProperties.ap] != null) { + annotation.appearance.normal = PdfTemplateHelper.fromRect( + nativeRectangle, + ); + final PdfTemplate template = annotation.appearance.normal; + PdfTemplateHelper.getHelper(template).writeTransformation = false; + final PdfGraphics? graphics = template.graphics; + final PdfBrush? backBrushColor = + annotation.innerColor.isEmpty + ? null + : PdfSolidBrush(annotation.innerColor); + PdfPen? borderPenColor; + if (annotation.border.width > 0 && + PdfColorHelper.getHelper(annotation.color).alpha != 0) { + borderPenColor = PdfPen( + annotation.color, + width: annotation.border.width, + ); + } + if (helper.flatten) { + annotation.page!.annotations.remove(annotation); + annotation.page!.graphics.drawPolygon( + _getLinePoints()!, + pen: borderPenColor, + brush: backBrushColor, + ); + } else { + graphics!.drawPolygon( + _getLinePoints()!, + pen: borderPenColor, + brush: backBrushColor, + ); + } + } + } + if (helper.flatten && !annotation.setAppearance) { + annotation.page!.annotations.remove(annotation); + PdfPen? borderPenColor; + if (annotation.border.width > 0 && + PdfColorHelper.getHelper(annotation.color).alpha != 0) { + borderPenColor = PdfPen( + annotation.color, + width: annotation.border.width, + ); + } + final PdfBrush? backBrushColor = + annotation.innerColor.isEmpty + ? null + : PdfSolidBrush(annotation.innerColor); + annotation.page!.graphics.drawPolygon( + _getLinePoints()!, + pen: borderPenColor, + brush: backBrushColor, + ); + } else if (!helper.flatten) { + helper.saveAnnotation(); + dictionary.setProperty( + PdfDictionaryProperties.vertices, + PdfArray(linePoints), + ); + dictionary.setProperty(PdfDictionaryProperties.bs, annotation.border); + _getBoundsValue(); + dictionary.setProperty( + PdfDictionaryProperties.rect, + PdfArray.fromRectangle(PdfRectangle.fromRect(annotation.bounds)), + ); + if (annotation.setAppearance) { + dictionary.setProperty( + PdfDictionaryProperties.rect, + PdfArray.fromRectangle(PdfRectangle.fromRect(nativeRectangle)), + ); + } + } + } + + void _saveOldPolygonAnnotation() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + PdfGraphicsState? state; + PdfRectangle nativeRectangle = PdfRectangle.empty; + final PdfDictionary dictionary = helper.dictionary!; + if (annotation.setAppearance) { + _getBoundsValue(); + nativeRectangle = PdfRectangle( + annotation.bounds.left - annotation.border.width, + annotation.page!.size.height - + annotation.bounds.top - + (annotation.border.width) - + annotation.bounds.height, + annotation.bounds.width + (2 * annotation.border.width), + annotation.bounds.height + (2 * annotation.border.width), + ); + dictionary.setProperty(PdfDictionaryProperties.ap, annotation.appearance); + if (dictionary[PdfDictionaryProperties.ap] != null) { + annotation.appearance.normal = PdfTemplateHelper.fromRect( + nativeRectangle.rect, + ); + final PdfTemplate template = annotation.appearance.normal; + PdfTemplateHelper.getHelper(template).writeTransformation = false; + final PdfGraphics? graphics = annotation.appearance.normal.graphics; + PdfBrush? backgroundBrush; + if (PdfColorHelper.getHelper(annotation.innerColor).alpha != 0) { + backgroundBrush = PdfSolidBrush(annotation.innerColor); + } + PdfPen? borderPenColor; + if (annotation.border.width > 0) { + borderPenColor = PdfPen( + annotation.color, + width: annotation.border.width, + ); + } + if (dictionary.containsKey(PdfDictionaryProperties.bs)) { + PdfDictionary? bSDictionary; + if (dictionary.items![PdfName(PdfDictionaryProperties.bs)] + is PdfReferenceHolder) { + bSDictionary = + (dictionary.items![PdfName(PdfDictionaryProperties.bs)]! + as PdfReferenceHolder) + .object + as PdfDictionary?; + } else { + bSDictionary = + dictionary.items![PdfName(PdfDictionaryProperties.bs)] + as PdfDictionary?; + } + if (bSDictionary!.containsKey(PdfDictionaryProperties.d)) { + final PdfArray? dashPatternArray = + PdfCrossTable.dereference( + bSDictionary.items![PdfName(PdfDictionaryProperties.d)], + ) + as PdfArray?; + if (dashPatternArray != null) { + final List dashPattern = List.filled( + dashPatternArray.count, + 0, + growable: true, + ); + for (int i = 0; i < dashPatternArray.count; i++) { + final IPdfPrimitive? pdfPrimitive = + dashPatternArray.elements[i]; + if (pdfPrimitive != null && pdfPrimitive is PdfNumber) { + dashPattern[i] = pdfPrimitive.value!.toDouble(); + } + } + borderPenColor!.dashStyle = PdfDashStyle.dash; + PdfPenHelper.getHelper(borderPenColor).isSkipPatternWidth = true; + borderPenColor.dashPattern = dashPattern; + } + } + } + if (helper.flatten) { + annotation.page!.annotations.remove(annotation); + if (annotation.opacity < 1) { + state = annotation.page!.graphics.save(); + annotation.page!.graphics.setTransparency(annotation.opacity); + } + if (dictionary.containsKey(PdfDictionaryProperties.be)) { + final PdfDictionary beDictionary = + dictionary[PdfName(PdfDictionaryProperties.be)]! + as PdfDictionary; + final double? iNumber = + (beDictionary.items![PdfName(PdfDictionaryProperties.i)]! + as PdfNumber) + .value + as double?; + final double radius = iNumber == 1 ? 5 : 10; + if (radius > 0) { + final List points = _getLinePoints()!; + if (points[0].dy > points[points.length - 1].dy) { + helper.drawCloudStyle( + graphics!, + backgroundBrush, + borderPenColor, + radius, + 0.833, + _getLinePoints()!, + false, + ); + } + helper.drawCloudStyle( + annotation.page!.graphics, + backgroundBrush, + borderPenColor, + radius, + 0.833, + _getLinePoints()!, + false, + ); + } else { + annotation.page!.graphics.drawPolygon( + _getLinePoints()!, + pen: borderPenColor, + brush: backgroundBrush, + ); + } + } else { + annotation.page!.graphics.drawPolygon( + _getLinePoints()!, + pen: borderPenColor, + brush: backgroundBrush, + ); + } + if (annotation.opacity < 1) { + annotation.page!.graphics.restore(state); + } + } else { + if (annotation.opacity < 1) { + state = graphics!.save(); + graphics.setTransparency(annotation.opacity); + } + if (dictionary.containsKey(PdfDictionaryProperties.be)) { + final PdfDictionary beDictionary = + dictionary[PdfName(PdfDictionaryProperties.be)]! + as PdfDictionary; + final double? iNumber = + (beDictionary.items![PdfName(PdfDictionaryProperties.i)]! + as PdfNumber) + .value + as double?; + final double radius = iNumber == 1 ? 5 : 10; + List points = _getLinePoints()!; + if (points[0].dy > points[points.length - 1].dy) { + final List point = []; + for (int i = 0; i < points.length; i++) { + point.add(Offset(points[i].dx, -points[i].dy)); + } + points = point; + helper.drawCloudStyle( + graphics!, + backgroundBrush, + borderPenColor, + radius, + 0.833, + points, + true, + ); + } else { + helper.drawCloudStyle( + graphics!, + backgroundBrush, + borderPenColor, + radius, + 0.833, + points, + false, + ); + } + } else { + graphics!.drawPolygon( + _getLinePoints()!, + pen: borderPenColor, + brush: backgroundBrush, + ); + } + if (annotation.opacity < 1) { + graphics.restore(state); + } + } + dictionary.setProperty( + PdfDictionaryProperties.rect, + PdfArray.fromRectangle(nativeRectangle), + ); + } + } + if (helper.flatten && !annotation.setAppearance) { + if (dictionary[PdfDictionaryProperties.ap] != null) { + IPdfPrimitive? obj = dictionary[PdfDictionaryProperties.ap]; + PdfDictionary? dic = PdfCrossTable.dereference(obj) as PdfDictionary?; + PdfTemplate? template; + if (dic != null) { + obj = dic[PdfDictionaryProperties.n]; + dic = PdfCrossTable.dereference(obj) as PdfDictionary?; + if (dic != null && dic is PdfStream) { + final PdfStream stream = dic; + template = PdfTemplateHelper.fromPdfStream(stream); + state = annotation.page!.graphics.save(); + if (annotation.opacity < 1) { + annotation.page!.graphics.setTransparency(annotation.opacity); + } + final bool isNormalMatrix = helper.validateTemplateMatrix(dic); + final Rect rect = helper.calculateTemplateBounds( + annotation.bounds, + annotation.page, + template, + isNormalMatrix, + ); + annotation.page!.graphics.drawPdfTemplate( + template, + rect.topLeft, + rect.size, + ); + annotation.page!.graphics.restore(state); + annotation.page!.annotations.remove(annotation); + } + } + } else { + annotation.page!.annotations.remove(annotation); + final PdfPen borderPenColor = PdfPen( + annotation.color, + width: annotation.border.width, + ); + final PdfBrush? backgroundBrush = + annotation.innerColor.isEmpty + ? null + : PdfSolidBrush(annotation.innerColor); + if (annotation.opacity < 1) { + state = annotation.page!.graphics.save(); + annotation.page!.graphics.setTransparency(annotation.opacity); + } + if (dictionary.containsKey(PdfDictionaryProperties.be)) { + final IPdfPrimitive? primitive = + dictionary[PdfName(PdfDictionaryProperties.be)]; + final PdfDictionary beDictionary = + (primitive is PdfReferenceHolder ? primitive.object : primitive)! + as PdfDictionary; + final double? iNumber = + (beDictionary.items![PdfName(PdfDictionaryProperties.i)]! + as PdfNumber) + .value + as double?; + final double radius = iNumber == 1 ? 5 : 10; + helper.drawCloudStyle( + annotation.page!.graphics, + backgroundBrush, + borderPenColor, + radius, + 0.833, + _getLinePoints()!, + false, + ); + } else { + annotation.page!.graphics.drawPolygon( + _getLinePoints()!, + pen: borderPenColor, + brush: backgroundBrush, + ); + } + if (annotation.opacity < 1) { + annotation.page!.graphics.restore(state); + } + } + if (helper.flattenPopups) { + helper.flattenPopup(); + } + } + } + + List? _getLinePoints() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + if (helper.isLoadedAnnotation) { + List? points; + if (helper.dictionary!.containsKey(PdfDictionaryProperties.vertices)) { + final PdfArray? linePoints = + helper.dictionary![PdfDictionaryProperties.vertices] as PdfArray?; + if (linePoints != null) { + final List point = []; + for (int i = 0; i < linePoints.count; i++) { + final PdfNumber number = linePoints[i]! as PdfNumber; + point.add(number.value!.toDouble()); + } + points = []; + for (int j = 0; j < point.length; j = j + 2) { + if (helper.flatten) { + points.add( + Offset(point[j], annotation.page!.size.height - point[j + 1]), + ); + } else { + points.add(Offset(point[j], -point[j + 1])); + } + } + } + } + return points; + } else { + final List points = []; + if (linePoints != null) { + final List pointsValue = []; + // ignore: prefer_final_in_for_each + for (IPdfPrimitive? linePoint in linePoints!.elements) { + if (linePoint is PdfNumber) { + pointsValue.add(linePoint.value!.toDouble()); + } + } + for (int j = 0; j < pointsValue.length; j = j + 2) { + final double pageHeight = annotation.page!.size.height; + if (helper.flatten) { + PdfPageHelper.getHelper(annotation.page!).isLoadedPage + ? points.add( + Offset(pointsValue[j], pageHeight - pointsValue[j + 1]), + ) + : points.add( + Offset( + pointsValue[j] - + PdfPageHelper.getHelper( + annotation.page!, + ).section!.pageSettings.margins.left, + pageHeight - + pointsValue[j + 1] - + PdfPageHelper.getHelper( + annotation.page!, + ).section!.pageSettings.margins.right, + ), + ); + } else { + points.add(Offset(pointsValue[j], -pointsValue[j + 1])); + } + } + } + return points; + } + } + + void _getBoundsValue() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + if (helper.isLoadedAnnotation) { + final PdfArray rect = + helper.dictionary![PdfDictionaryProperties.rect]! as PdfArray; + annotation.bounds = rect.toRectangle().rect; + final List xval = []; + final List yval = []; + if (helper.dictionary!.containsKey(PdfDictionaryProperties.vertices)) { + final PdfArray linePoints = + PdfCrossTable.dereference( + helper.dictionary![PdfDictionaryProperties.vertices], + )! + as PdfArray; + if (linePoints.count > 0) { + final List points = List.filled( + linePoints.count, + 0, + growable: true, + ); + for (int j = 0; j < linePoints.count; j++) { + final PdfNumber number = linePoints[j]! as PdfNumber; + points[j] = number.value!.toDouble(); + } + for (int i = 0; i < points.length; i++) { + if (i.isEven) { + xval.add(points[i]); + } else { + yval.add(points[i]); + } + } + } + } + xval.sort(); + yval.sort(); + annotation.bounds = Rect.fromLTWH( + xval[0], + yval[0], + xval[xval.length - 1] - xval[0], + yval[yval.length - 1] - yval[0], + ); + } else { + final List xval = []; + final List yval = []; + if (linePoints!.count > 0) { + final List pointsValue = []; + // ignore: prefer_final_in_for_each + for (IPdfPrimitive? linePoint in linePoints!.elements) { + if (linePoint is PdfNumber) { + pointsValue.add(linePoint.value!.toDouble()); + } + } + for (int i = 0; i < pointsValue.length; i++) { + if (i.isEven) { + xval.add(pointsValue[i]); + } else { + yval.add(pointsValue[i]); + } + } + } + xval.sort(); + yval.sort(); + annotation.bounds = Rect.fromLTWH( + xval[0], + yval[0], + xval[xval.length - 1] - xval[0], + yval[yval.length - 1] - yval[0], + ); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_popup_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_popup_annotation.dart index cc00b2785..94387522c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_popup_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_popup_annotation.dart @@ -1,396 +1,396 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../graphics/brushes/pdf_brush.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/figures/pdf_path.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_collection.dart'; - -/// Represents a base class for popup annotation which can be either in open or closed state. -class PdfPopupAnnotation extends PdfAnnotation { - // Constructor - /// Initializes a instance of the [PdfPopupAnnotation] class specified with bounds, text, open, color, author, subject, opacity, icon, modifiedDate, and flags. - /// ``` dart - /// final PdfDocument document = PdfDocument(); - /// final PdfPage page = document.pages.add(); - /// final PdfPopupAnnotation popup = - /// PdfPopupAnnotation(Rect.fromLTWH(10, 10, 30, 30), 'Popup Annotation'); - /// page.annotations.add(popup); - /// final List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfPopupAnnotation( - Rect bounds, - String text, { - bool? open, - String? author, - PdfColor? color, - String? subject, - double? opacity, - DateTime? modifiedDate, - PdfPopupIcon? icon, - List? flags, - bool? setAppearance, - }) { - _helper = PdfPopupAnnotationHelper( - this, - bounds, - text, - open, - author, - color, - subject, - opacity, - modifiedDate, - icon, - flags, - setAppearance, - ); - } - - PdfPopupAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - _helper = PdfPopupAnnotationHelper._(this, dictionary, crossTable, text); - } - - // Fields - late PdfPopupAnnotationHelper _helper; - - // Properties - /// Gets value whether annotation is initially open or closed. - bool get open => _helper.open; - - /// Sets value whether annotation is initially open or closed. - set open(bool value) { - _helper.open = value; - } - - /// Gets the icon style of the annotation. - PdfPopupIcon get icon => _helper.icon; - - /// Sets the icon style of the annotation. - set icon(PdfPopupIcon value) { - _helper.icon = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } -} - -/// [PdfPopupAnnotationHelper] helper -class PdfPopupAnnotationHelper extends PdfAnnotationHelper { - //Constructor - /// internal constructor - PdfPopupAnnotationHelper( - this.popupAnnotation, - Rect bounds, - String text, - bool? open, - String? author, - PdfColor? color, - String? subject, - double? opacity, - DateTime? modifiedDate, - PdfPopupIcon? icon, - List? flags, - bool? setAppearance, - ) : super(popupAnnotation) { - initializeAnnotation( - bounds: bounds, - text: text, - color: color, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - this.open = open ??= false; - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(PdfDictionaryProperties.text), - ); - this.icon = icon ?? PdfPopupIcon.note; - } - - PdfPopupAnnotationHelper._( - this.popupAnnotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) : super(popupAnnotation) { - this.text = text; - initializeExistingAnnotation(dictionary, crossTable); - } - - // Fields - /// Internal fields - late PdfPopupAnnotation popupAnnotation; - bool _open = false; - PdfPopupIcon? _icon; - - /// internal method - static PdfPopupAnnotationHelper getHelper(PdfPopupAnnotation annotation) { - return annotation._helper; - } - - /// internal method - static PdfPopupAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - return PdfPopupAnnotation._(dictionary, crossTable, text); - } - - // Properties - /// Gets value whether annotation is initially open or closed. - bool get open => isLoadedAnnotation ? obtainOpen() : _open; - - /// Sets value whether annotation is initially open or closed. - set open(bool value) { - if (_open != value) { - _open = value; - dictionary!.setBoolean(PdfDictionaryProperties.open, _open); - } - } - - /// Gets the icon style of the annotation. - PdfPopupIcon get icon => - isLoadedAnnotation ? obtainIcon() : _icon ?? PdfPopupIcon.note; - - /// Sets the icon style of the annotation. - set icon(PdfPopupIcon value) { - if (_icon != value) { - _icon = value; - dictionary!.setName( - PdfName(PdfDictionaryProperties.name), - getEnumName(_icon), - ); - } - } - - /// Internal method. - bool obtainOpen() { - if (dictionary!.containsKey(PdfDictionaryProperties.open)) { - final IPdfPrimitive? open = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.open], - ); - if (open != null && open is PdfBoolean) { - return open.value ?? false; - } - } - return false; - } - - /// Internal method. - PdfPopupIcon obtainIcon() { - if (dictionary!.containsKey(PdfDictionaryProperties.name)) { - final IPdfPrimitive? icon = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.name], - ); - if (icon != null && icon is PdfName) { - return getIconName(icon.name.toString()); - } else if (icon != null && icon is PdfString) { - return getIconName(icon.value.toString()); - } - } - return PdfPopupIcon.note; - } - - /// Internal method. - PdfPopupIcon getIconName(String name) { - switch (name.toLowerCase()) { - case 'note': - return PdfPopupIcon.note; - case 'comment': - return PdfPopupIcon.comment; - case 'help': - return PdfPopupIcon.help; - case 'insert': - return PdfPopupIcon.insert; - case 'key': - return PdfPopupIcon.key; - case 'newparagraph': - return PdfPopupIcon.newParagraph; - case 'paragraph': - return PdfPopupIcon.paragraph; - } - return PdfPopupIcon.note; - } - - /// Internal method. - void save() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - popupAnnotation, - ); - if (PdfAnnotationCollectionHelper.getHelper( - popupAnnotation.page!.annotations, - ).flatten) { - helper.flatten = true; - } - if (helper.isLoadedAnnotation) { - if (helper.setAppearance) { - popupAnnotation.appearance.normal = PdfTemplate( - bounds.width, - bounds.height, - ); - drawIcon(popupAnnotation.appearance.normal.graphics!); - dictionary!.setProperty( - PdfDictionaryProperties.ap, - popupAnnotation.appearance, - ); - } - if (helper.flatten) { - bool isFlattenPopup = true; - if (dictionary!.containsKey(PdfDictionaryProperties.f)) { - final IPdfPrimitive? flag = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.f], - ); - if (flag != null && flag is PdfNumber && flag.value == 30) { - if (!helper.flattenPopups) { - isFlattenPopup = false; - } - } - } - if (dictionary![PdfDictionaryProperties.ap] != null && isFlattenPopup) { - IPdfPrimitive? dic = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.ap], - ); - PdfTemplate template; - if (dic != null && dic is PdfDictionary) { - dic = PdfCrossTable.dereference(dic[PdfDictionaryProperties.n]); - if (dic != null && dic is PdfStream) { - final PdfStream stream = dic; - template = PdfTemplateHelper.fromPdfStream(stream); - if (!setAppearance && opacity < 1) { - page!.graphics.save(); - page!.graphics.setTransparency(opacity); - } - page!.graphics.drawPdfTemplate( - template, - bounds.topLeft, - bounds.size, - ); - if (!setAppearance && opacity < 1) { - page!.graphics.restore(); - } - } - } - } - page!.annotations.remove(popupAnnotation); - } - } else { - helper.saveAnnotation(); - if (helper.setAppearance || helper.flatten) { - drawIcon(popupAnnotation.appearance.normal.graphics!); - if (helper.flatten) { - page!.graphics.drawPdfTemplate( - popupAnnotation.appearance.normal, - bounds.topLeft, - popupAnnotation.appearance.normal.size, - ); - page!.annotations.remove(popupAnnotation); - } else { - dictionary!.setProperty( - PdfDictionaryProperties.ap, - popupAnnotation.appearance, - ); - } - } - } - if (helper.flattenPopups) { - helper.flattenPopup(); - } - } - - /// Internal method. - void drawIcon(PdfGraphics graphics) { - if (dictionary!.containsKey(PdfDictionaryProperties.name)) { - final IPdfPrimitive? name = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.name], - ); - if (name != null && name is PdfName && name.name == 'Comment') { - if (flatten) { - popupAnnotation.appearance.normal = PdfTemplate( - bounds.width > 24 ? bounds.width : 24, - bounds.height > 22 ? bounds.height : 22, - ); - graphics = popupAnnotation.appearance.normal.graphics!; - } - final PdfPen pen = PdfPen(PdfColor(0, 0, 0), width: 0.3); - PdfBrush brush = PdfSolidBrush(color); - final PdfPen pen1 = PdfPen(PdfColor(255, 255, 255), width: 0.35); - final List points = [ - const Offset(7, 15.45), - const Offset(9, 16.15), - const Offset(4, 19), - ]; - final PdfPath path = PdfPath(); - if (color.isEmpty == true) { - brush = PdfBrushes.gold; - } - final PdfTemplate template = PdfTemplate(24, 22); - if (opacity < 1) { - template.graphics!.save(); - template.graphics!.setTransparency(opacity); - } - template.graphics!.drawRectangle( - bounds: const Rect.fromLTWH(0, 0, 24, 22), - pen: pen, - brush: brush, - ); - template.graphics!.drawPolygon( - points, - pen: pen, - brush: PdfBrushes.white, - ); - path.addEllipse(const Rect.fromLTWH(2.5, 2.5, 19, 14)); - template.graphics!.drawPath(pen: pen, brush: PdfBrushes.white, path); - template.graphics!.drawArc( - const Rect.fromLTWH(2.5, 2.5, 19, 14), - 110.7, - 10.3, - pen: pen1, - ); - if (opacity < 1) { - template.graphics!.restore(); - } - graphics.drawPdfTemplate(template, Offset.zero, const Size(17, 17)); - } - } - } - - /// internal method - @override - IPdfPrimitive? get element => dictionary; - @override - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../graphics/brushes/pdf_brush.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/figures/pdf_path.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_collection.dart'; + +/// Represents a base class for popup annotation which can be either in open or closed state. +class PdfPopupAnnotation extends PdfAnnotation { + // Constructor + /// Initializes a instance of the [PdfPopupAnnotation] class specified with bounds, text, open, color, author, subject, opacity, icon, modifiedDate, and flags. + /// ``` dart + /// final PdfDocument document = PdfDocument(); + /// final PdfPage page = document.pages.add(); + /// final PdfPopupAnnotation popup = + /// PdfPopupAnnotation(Rect.fromLTWH(10, 10, 30, 30), 'Popup Annotation'); + /// page.annotations.add(popup); + /// final List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfPopupAnnotation( + Rect bounds, + String text, { + bool? open, + String? author, + PdfColor? color, + String? subject, + double? opacity, + DateTime? modifiedDate, + PdfPopupIcon? icon, + List? flags, + bool? setAppearance, + }) { + _helper = PdfPopupAnnotationHelper( + this, + bounds, + text, + open, + author, + color, + subject, + opacity, + modifiedDate, + icon, + flags, + setAppearance, + ); + } + + PdfPopupAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + _helper = PdfPopupAnnotationHelper._(this, dictionary, crossTable, text); + } + + // Fields + late PdfPopupAnnotationHelper _helper; + + // Properties + /// Gets value whether annotation is initially open or closed. + bool get open => _helper.open; + + /// Sets value whether annotation is initially open or closed. + set open(bool value) { + _helper.open = value; + } + + /// Gets the icon style of the annotation. + PdfPopupIcon get icon => _helper.icon; + + /// Sets the icon style of the annotation. + set icon(PdfPopupIcon value) { + _helper.icon = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } +} + +/// [PdfPopupAnnotationHelper] helper +class PdfPopupAnnotationHelper extends PdfAnnotationHelper { + //Constructor + /// internal constructor + PdfPopupAnnotationHelper( + this.popupAnnotation, + Rect bounds, + String text, + bool? open, + String? author, + PdfColor? color, + String? subject, + double? opacity, + DateTime? modifiedDate, + PdfPopupIcon? icon, + List? flags, + bool? setAppearance, + ) : super(popupAnnotation) { + initializeAnnotation( + bounds: bounds, + text: text, + color: color, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + this.open = open ??= false; + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(PdfDictionaryProperties.text), + ); + this.icon = icon ?? PdfPopupIcon.note; + } + + PdfPopupAnnotationHelper._( + this.popupAnnotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) : super(popupAnnotation) { + this.text = text; + initializeExistingAnnotation(dictionary, crossTable); + } + + // Fields + /// Internal fields + late PdfPopupAnnotation popupAnnotation; + bool _open = false; + PdfPopupIcon? _icon; + + /// internal method + static PdfPopupAnnotationHelper getHelper(PdfPopupAnnotation annotation) { + return annotation._helper; + } + + /// internal method + static PdfPopupAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + return PdfPopupAnnotation._(dictionary, crossTable, text); + } + + // Properties + /// Gets value whether annotation is initially open or closed. + bool get open => isLoadedAnnotation ? obtainOpen() : _open; + + /// Sets value whether annotation is initially open or closed. + set open(bool value) { + if (_open != value) { + _open = value; + dictionary!.setBoolean(PdfDictionaryProperties.open, _open); + } + } + + /// Gets the icon style of the annotation. + PdfPopupIcon get icon => + isLoadedAnnotation ? obtainIcon() : _icon ?? PdfPopupIcon.note; + + /// Sets the icon style of the annotation. + set icon(PdfPopupIcon value) { + if (_icon != value) { + _icon = value; + dictionary!.setName( + PdfName(PdfDictionaryProperties.name), + getEnumName(_icon), + ); + } + } + + /// Internal method. + bool obtainOpen() { + if (dictionary!.containsKey(PdfDictionaryProperties.open)) { + final IPdfPrimitive? open = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.open], + ); + if (open != null && open is PdfBoolean) { + return open.value ?? false; + } + } + return false; + } + + /// Internal method. + PdfPopupIcon obtainIcon() { + if (dictionary!.containsKey(PdfDictionaryProperties.name)) { + final IPdfPrimitive? icon = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.name], + ); + if (icon != null && icon is PdfName) { + return getIconName(icon.name.toString()); + } else if (icon != null && icon is PdfString) { + return getIconName(icon.value.toString()); + } + } + return PdfPopupIcon.note; + } + + /// Internal method. + PdfPopupIcon getIconName(String name) { + switch (name.toLowerCase()) { + case 'note': + return PdfPopupIcon.note; + case 'comment': + return PdfPopupIcon.comment; + case 'help': + return PdfPopupIcon.help; + case 'insert': + return PdfPopupIcon.insert; + case 'key': + return PdfPopupIcon.key; + case 'newparagraph': + return PdfPopupIcon.newParagraph; + case 'paragraph': + return PdfPopupIcon.paragraph; + } + return PdfPopupIcon.note; + } + + /// Internal method. + void save() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + popupAnnotation, + ); + if (PdfAnnotationCollectionHelper.getHelper( + popupAnnotation.page!.annotations, + ).flatten) { + helper.flatten = true; + } + if (helper.isLoadedAnnotation) { + if (helper.setAppearance) { + popupAnnotation.appearance.normal = PdfTemplate( + bounds.width, + bounds.height, + ); + drawIcon(popupAnnotation.appearance.normal.graphics!); + dictionary!.setProperty( + PdfDictionaryProperties.ap, + popupAnnotation.appearance, + ); + } + if (helper.flatten) { + bool isFlattenPopup = true; + if (dictionary!.containsKey(PdfDictionaryProperties.f)) { + final IPdfPrimitive? flag = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.f], + ); + if (flag != null && flag is PdfNumber && flag.value == 30) { + if (!helper.flattenPopups) { + isFlattenPopup = false; + } + } + } + if (dictionary![PdfDictionaryProperties.ap] != null && isFlattenPopup) { + IPdfPrimitive? dic = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.ap], + ); + PdfTemplate template; + if (dic != null && dic is PdfDictionary) { + dic = PdfCrossTable.dereference(dic[PdfDictionaryProperties.n]); + if (dic != null && dic is PdfStream) { + final PdfStream stream = dic; + template = PdfTemplateHelper.fromPdfStream(stream); + if (!setAppearance && opacity < 1) { + page!.graphics.save(); + page!.graphics.setTransparency(opacity); + } + page!.graphics.drawPdfTemplate( + template, + bounds.topLeft, + bounds.size, + ); + if (!setAppearance && opacity < 1) { + page!.graphics.restore(); + } + } + } + } + page!.annotations.remove(popupAnnotation); + } + } else { + helper.saveAnnotation(); + if (helper.setAppearance || helper.flatten) { + drawIcon(popupAnnotation.appearance.normal.graphics!); + if (helper.flatten) { + page!.graphics.drawPdfTemplate( + popupAnnotation.appearance.normal, + bounds.topLeft, + popupAnnotation.appearance.normal.size, + ); + page!.annotations.remove(popupAnnotation); + } else { + dictionary!.setProperty( + PdfDictionaryProperties.ap, + popupAnnotation.appearance, + ); + } + } + } + if (helper.flattenPopups) { + helper.flattenPopup(); + } + } + + /// Internal method. + void drawIcon(PdfGraphics graphics) { + if (dictionary!.containsKey(PdfDictionaryProperties.name)) { + final IPdfPrimitive? name = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.name], + ); + if (name != null && name is PdfName && name.name == 'Comment') { + if (flatten) { + popupAnnotation.appearance.normal = PdfTemplate( + bounds.width > 24 ? bounds.width : 24, + bounds.height > 22 ? bounds.height : 22, + ); + graphics = popupAnnotation.appearance.normal.graphics!; + } + final PdfPen pen = PdfPen(PdfColor(0, 0, 0), width: 0.3); + PdfBrush brush = PdfSolidBrush(color); + final PdfPen pen1 = PdfPen(PdfColor(255, 255, 255), width: 0.35); + final List points = [ + const Offset(7, 15.45), + const Offset(9, 16.15), + const Offset(4, 19), + ]; + final PdfPath path = PdfPath(); + if (color.isEmpty == true) { + brush = PdfBrushes.gold; + } + final PdfTemplate template = PdfTemplate(24, 22); + if (opacity < 1) { + template.graphics!.save(); + template.graphics!.setTransparency(opacity); + } + template.graphics!.drawRectangle( + bounds: const Rect.fromLTWH(0, 0, 24, 22), + pen: pen, + brush: brush, + ); + template.graphics!.drawPolygon( + points, + pen: pen, + brush: PdfBrushes.white, + ); + path.addEllipse(const Rect.fromLTWH(2.5, 2.5, 19, 14)); + template.graphics!.drawPath(pen: pen, brush: PdfBrushes.white, path); + template.graphics!.drawArc( + const Rect.fromLTWH(2.5, 2.5, 19, 14), + 110.7, + 10.3, + pen: pen1, + ); + if (opacity < 1) { + template.graphics!.restore(); + } + graphics.drawPdfTemplate(template, Offset.zero, const Size(17, 17)); + } + } + } + + /// internal method + @override + IPdfPrimitive? get element => dictionary; + @override + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_rectangle_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_rectangle_annotation.dart index e17202bff..5a2aea74d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_rectangle_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_rectangle_annotation.dart @@ -1,645 +1,645 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/pdf_annotation_border.dart'; -import '../drawing/drawing.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_path.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_collection.dart'; -import 'pdf_paintparams.dart'; - -/// Represents a PDF rectangle annotation -class PdfRectangleAnnotation extends PdfAnnotation { - // Constructor - /// Initializes new instance of the [PdfRectangleAnnotation] with bounds, text, border, color, innerColor, author, rotate, subject, modifiedDate, and flags. - /// ``` dart - /// PdfDocument document = PdfDocument(); - /// PdfPage page = document.pages.add(); - /// PdfRectangleAnnotation rectangleAnnotation = PdfRectangleAnnotation( - /// const Rect.fromLTWH(0, 30, 80, 80), 'SquareAnnotation', - /// innerColor: PdfColor(255, 0, 0), color: PdfColor(255, 255, 0)); - /// page.annotations.add(rectangleAnnotation); - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfRectangleAnnotation( - Rect bounds, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - double? opacity, - DateTime? modifiedDate, - List? flags, - bool? setAppearance, - }) { - _helper = PdfRectangleAnnotationHelper( - this, - bounds, - text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - } - - PdfRectangleAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - _helper = PdfRectangleAnnotationHelper._(this, dictionary, crossTable); - this.text = text; - } - - // Fields - late PdfRectangleAnnotationHelper _helper; - - // Properites - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - return _helper.border; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - _helper.border = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } - - /// Gets the inner color of the annotation. - PdfColor get innerColor => _helper.innerColor; - - /// Sets the inner color of the annotation. - set innerColor(PdfColor value) { - _helper.innerColor = value; - } - - IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; - - set _element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - PdfAnnotationHelper.getHelper(this).dictionary = value; - } - } -} - -/// [PdfRectangleAnnotation] helper -class PdfRectangleAnnotationHelper extends PdfAnnotationHelper { - /// internal constructor - PdfRectangleAnnotationHelper( - this.rectangleAnnotation, - Rect bounds, - String text, { - PdfColor? color, - PdfColor? innerColor, - PdfAnnotationBorder? border, - String? author, - String? subject, - double? opacity, - DateTime? modifiedDate, - List? flags, - bool? setAppearance, - }) : super(rectangleAnnotation) { - initializeAnnotation( - bounds: bounds, - text: text, - color: color, - innerColor: innerColor, - border: border, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(PdfDictionaryProperties.square), - ); - } - PdfRectangleAnnotationHelper._( - this.rectangleAnnotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super(rectangleAnnotation) { - initializeExistingAnnotation(dictionary, crossTable); - } - - /// internal field - late PdfRectangleAnnotation rectangleAnnotation; - - /// internal method - static PdfRectangleAnnotationHelper getHelper( - PdfRectangleAnnotation annotation, - ) { - return annotation._helper; - } - - /// internal method - static PdfRectangleAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - return PdfRectangleAnnotation._(dictionary, crossTable, text); - } - - /// internal method - @override - IPdfPrimitive? get element => rectangleAnnotation._element; - @override - set element(IPdfPrimitive? value) { - rectangleAnnotation._element = value; - } - - /// internal method - void save() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - rectangleAnnotation, - ); - if (PdfAnnotationCollectionHelper.getHelper( - rectangleAnnotation.page!.annotations, - ).flatten) { - helper.flatten = true; - } - if (helper.flatten || - rectangleAnnotation.setAppearance || - helper.appearance != null) { - PdfTemplate? appearance; - if (helper.appearance != null) { - appearance = helper.appearance!.normal; - } else { - appearance = _createAppearance(); - } - if (helper.flatten) { - if (appearance != null || helper.isLoadedAnnotation) { - if (rectangleAnnotation.page != null) { - _flattenAnnotation(rectangleAnnotation.page, appearance); - } - } - } else { - if (appearance != null) { - rectangleAnnotation.appearance.normal = appearance; - helper.dictionary!.setProperty( - PdfDictionaryProperties.ap, - PdfReferenceHolder(rectangleAnnotation.appearance), - ); - } - } - } - if (!helper.flatten && !helper.isLoadedAnnotation) { - helper.saveAnnotation(); - helper.dictionary!.setProperty( - PdfDictionaryProperties.bs, - rectangleAnnotation.border, - ); - } - if (helper.flattenPopups) { - helper.flattenPopup(); - } - } - - PdfTemplate? _createAppearance() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - rectangleAnnotation, - ); - if (helper.isLoadedAnnotation) { - if (rectangleAnnotation.setAppearance) { - final PaintParams paintParams = PaintParams(); - final double borderWidth = rectangleAnnotation.border.width / 2; - final PdfPen mBorderPen = PdfPen( - rectangleAnnotation.color, - width: rectangleAnnotation.border.width, - ); - PdfBrush? mBackBrush; - final Map result = _calculateCloudBorderBounds(); - final double borderIntensity = result['borderIntensity'] as double; - final String? borderStyle = result['borderStyle'] as String?; - final PdfRectangle nativeRectangle = PdfRectangle( - 0, - 0, - rectangleAnnotation.bounds.width, - rectangleAnnotation.bounds.height, - ); - final PdfTemplate template = PdfTemplateHelper.fromRect( - nativeRectangle.rect, - ); - PdfAnnotationHelper.setMatrixToZeroRotation( - PdfTemplateHelper.getHelper(template).content, - ); - if (borderIntensity > 0 && borderStyle == 'C') { - PdfTemplateHelper.getHelper(template).writeTransformation = false; - } - final PdfGraphics? graphics = template.graphics; - if (PdfColorHelper.getHelper(rectangleAnnotation.innerColor).alpha != - 0) { - mBackBrush = PdfSolidBrush(rectangleAnnotation.innerColor); - } - if (rectangleAnnotation.border.width > 0) { - paintParams.borderPen = mBorderPen; - } - paintParams.foreBrush = PdfSolidBrush(rectangleAnnotation.color); - paintParams.backBrush = mBackBrush; - final PdfRectangle rectangle = _obtainStyle( - mBorderPen, - nativeRectangle, - borderWidth, - borderIntensity: borderIntensity, - borderStyle: borderStyle, - ); - if (rectangleAnnotation.opacity < 1) { - graphics!.save(); - graphics.setTransparency(rectangleAnnotation.opacity); - } - if (borderIntensity > 0 && borderStyle == 'C') { - _drawAppearance( - rectangle, - borderWidth, - graphics, - paintParams, - borderIntensity, - ); - } else { - graphics!.drawRectangle( - pen: paintParams.borderPen, - brush: paintParams.backBrush, - bounds: Rect.fromLTWH( - rectangle.x, - rectangle.y, - rectangle.width, - rectangle.height, - ), - ); - } - if (rectangleAnnotation.opacity < 1) { - graphics!.restore(); - } - return template; - } - return null; - } else { - final Rect nativeRectangle = Rect.fromLTWH( - 0, - 0, - rectangleAnnotation.bounds.width, - rectangleAnnotation.bounds.height, - ); - final PdfTemplate template = PdfTemplate( - rectangleAnnotation.bounds.width, - rectangleAnnotation.bounds.height, - ); - PdfAnnotationHelper.setMatrixToZeroRotation( - PdfTemplateHelper.getHelper(template).content, - ); - final PaintParams paintParams = PaintParams(); - final PdfGraphics graphics = template.graphics!; - if (rectangleAnnotation.border.width > 0 && - PdfColorHelper.getHelper(rectangleAnnotation.color).alpha != 0) { - final PdfPen mBorderPen = PdfPen( - rectangleAnnotation.color, - width: rectangleAnnotation.border.width, - ); - paintParams.borderPen = mBorderPen; - } - PdfBrush? mBackBrush; - if (PdfColorHelper.getHelper(rectangleAnnotation.innerColor).alpha != 0) { - mBackBrush = PdfSolidBrush(rectangleAnnotation.innerColor); - } - final double width = rectangleAnnotation.border.width / 2; - - paintParams.backBrush = mBackBrush; - if (paintParams.foreBrush != PdfSolidBrush(rectangleAnnotation.color)) { - paintParams.foreBrush = PdfSolidBrush(rectangleAnnotation.color); - } - final Rect rect = Rect.fromLTWH( - nativeRectangle.left, - nativeRectangle.top, - nativeRectangle.width, - nativeRectangle.height, - ); - if (rectangleAnnotation.opacity < 1) { - graphics.save(); - graphics.setTransparency(rectangleAnnotation.opacity); - } - graphics.drawRectangle( - bounds: Rect.fromLTWH( - rect.left + width, - rect.top + width, - rect.width - rectangleAnnotation.border.width, - rect.height - rectangleAnnotation.border.width, - ), - pen: paintParams.borderPen, - brush: paintParams.backBrush, - ); - if (rectangleAnnotation.opacity < 1) { - graphics.restore(); - } - return template; - } - } - - Map _calculateCloudBorderBounds() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - rectangleAnnotation, - ); - double borderIntensity = 0; - String borderStyle = ''; - final PdfDictionary dictionary = helper.dictionary!; - if (!dictionary.containsKey(PdfDictionaryProperties.rd) && - dictionary.containsKey(PdfDictionaryProperties.be)) { - final PdfDictionary dict = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.be])! - as PdfDictionary; - if (dict.containsKey(PdfDictionaryProperties.s)) { - borderStyle = helper.getEnumName( - (dict[PdfDictionaryProperties.s]! as PdfName).name, - ); - } - if (dict.containsKey(PdfDictionaryProperties.i)) { - borderIntensity = - (dict[PdfDictionaryProperties.i]! as PdfNumber).value!.toDouble(); - } - if (borderIntensity != 0 && borderStyle == 'C') { - final Rect cloudRectangle = Rect.fromLTWH( - rectangleAnnotation.bounds.left - - borderIntensity * 5 - - rectangleAnnotation.border.width / 2, - rectangleAnnotation.bounds.top - - borderIntensity * 5 - - rectangleAnnotation.border.width / 2, - rectangleAnnotation.bounds.width + - borderIntensity * 10 + - rectangleAnnotation.border.width, - rectangleAnnotation.bounds.height + - borderIntensity * 10 + - rectangleAnnotation.border.width, - ); - final double radius = borderIntensity * 5; - final List arr = [ - radius + rectangleAnnotation.border.width / 2, - radius + rectangleAnnotation.border.width / 2, - radius + rectangleAnnotation.border.width / 2, - radius + rectangleAnnotation.border.width / 2, - ]; - dictionary.setProperty(PdfDictionaryProperties.rd, PdfArray(arr)); - rectangleAnnotation.bounds = cloudRectangle; - } - } - if (!helper.isBounds && dictionary[PdfDictionaryProperties.rd] != null) { - final PdfArray mRdArray = - dictionary[PdfDictionaryProperties.rd]! as PdfArray; - final PdfNumber num1 = mRdArray.elements[0]! as PdfNumber; - final PdfNumber num2 = mRdArray.elements[1]! as PdfNumber; - final PdfNumber num3 = mRdArray.elements[2]! as PdfNumber; - final PdfNumber num4 = mRdArray.elements[3]! as PdfNumber; - Rect cloudRectangle = Rect.fromLTWH( - rectangleAnnotation.bounds.left + num1.value!.toDouble(), - rectangleAnnotation.bounds.top + num2.value!.toDouble(), - rectangleAnnotation.bounds.width - num3.value!.toDouble() * 2, - rectangleAnnotation.bounds.height - num4.value!.toDouble() * 2, - ); - if (borderIntensity != 0 && borderStyle == 'C') { - cloudRectangle = Rect.fromLTWH( - cloudRectangle.left - - borderIntensity * 5 - - rectangleAnnotation.border.width / 2, - cloudRectangle.top - - borderIntensity * 5 - - rectangleAnnotation.border.width / 2, - cloudRectangle.width + - borderIntensity * 10 + - rectangleAnnotation.border.width, - cloudRectangle.height + - borderIntensity * 10 + - rectangleAnnotation.border.width, - ); - final double radius = borderIntensity * 5; - final List arr = [ - radius + rectangleAnnotation.border.width / 2, - radius + rectangleAnnotation.border.width / 2, - radius + rectangleAnnotation.border.width / 2, - radius + rectangleAnnotation.border.width / 2, - ]; - dictionary.setProperty(PdfDictionaryProperties.rd, PdfArray(arr)); - } else { - dictionary.remove(PdfDictionaryProperties.rd); - } - rectangleAnnotation.bounds = cloudRectangle; - } - return { - 'borderIntensity': borderIntensity, - 'borderStyle': borderStyle, - }; - } - - void _flattenAnnotation(PdfPage? page, PdfTemplate? appearance) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - rectangleAnnotation, - ); - final PdfDictionary dictionary = helper.dictionary!; - if (helper.isLoadedAnnotation) { - final bool isContainsAP = dictionary.containsKey( - PdfDictionaryProperties.ap, - ); - if (isContainsAP && appearance == null) { - PdfDictionary? appearanceDictionary = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ap]) - as PdfDictionary?; - if (appearanceDictionary != null) { - appearanceDictionary = - PdfCrossTable.dereference( - appearanceDictionary[PdfDictionaryProperties.n], - ) - as PdfDictionary?; - if (appearanceDictionary != null) { - final PdfStream appearanceStream = - appearanceDictionary as PdfStream; - appearance = PdfTemplateHelper.fromPdfStream(appearanceStream); - final bool isNormalMatrix = helper.validateTemplateMatrix( - appearanceDictionary, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } else { - rectangleAnnotation.setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } - } - } else if (!isContainsAP && appearance == null) { - rectangleAnnotation.setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } else { - final bool isNormalMatrix = helper.validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance!).content, - ); - helper.flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } else { - page!.graphics.save(); - final Rect rectangle = helper.calculateTemplateBounds( - rectangleAnnotation.bounds, - page, - appearance, - true, - ); - - if (rectangleAnnotation.opacity < 1) { - page.graphics.setTransparency(rectangleAnnotation.opacity); - } - page.graphics.drawPdfTemplate( - appearance!, - Offset(rectangle.left, rectangle.top), - rectangle.size, - ); - page.annotations.remove(rectangleAnnotation); - page.graphics.restore(); - } - } - - // Obtain Style from annotation - PdfRectangle _obtainStyle( - PdfPen mBorderPen, - PdfRectangle rectangle, - double borderWidth, { - double? borderIntensity, - String? borderStyle, - }) { - if (PdfAnnotationHelper.getHelper( - rectangleAnnotation, - ).dictionary!.containsKey(PdfDictionaryProperties.bs)) { - final PdfDictionary? bSDictionary = - PdfCrossTable.dereference( - PdfAnnotationHelper.getHelper( - rectangleAnnotation, - ).dictionary![PdfDictionaryProperties.bs], - ) - as PdfDictionary?; - if (bSDictionary != null && - bSDictionary.containsKey(PdfDictionaryProperties.d)) { - final PdfArray dashPatternArray = - PdfCrossTable.dereference(bSDictionary[PdfDictionaryProperties.d])! - as PdfArray; - final List dashPattern = []; - for (int i = 0; i < dashPatternArray.count; i++) { - dashPattern.add( - (dashPatternArray.elements[i]! as PdfNumber).value!.toDouble(), - ); - } - mBorderPen.dashStyle = PdfDashStyle.dash; - mBorderPen.dashPattern = dashPattern; - } - } - if (borderIntensity != null && - borderIntensity > 0 && - borderStyle != null && - borderStyle == 'C') { - final double radius = borderIntensity * 5; - rectangle.x = rectangle.x + radius + borderWidth; - rectangle.y = rectangle.y + radius + borderWidth; - rectangle.width = rectangle.width - (2 * radius) - 2 * borderWidth; - rectangle.height = rectangle.height - (2 * radius) - 2 * borderWidth; - } else { - rectangle.x += borderWidth; - rectangle.y += borderWidth; - rectangle.width -= rectangleAnnotation.border.width; - rectangle.height -= rectangleAnnotation.border.width; - } - return rectangle; - } - - // Draw appearance for annotation - void _drawAppearance( - PdfRectangle rectangle, - double borderWidth, - PdfGraphics? graphics, - PaintParams paintParams, - double borderIntensity, - ) { - final PdfPath graphicsPath = PdfPath(); - graphicsPath.addRectangle(rectangle.rect); - final double radius = borderIntensity * 4.25; - if (radius > 0) { - if (PdfPathHelper.getHelper(graphicsPath).points.length == 5 && - PdfPathHelper.getHelper(graphicsPath).points[4] == Offset.zero) { - PdfPathHelper.getHelper(graphicsPath).points.removeAt(4); - } - final List points = []; - for ( - int i = 0; - i < PdfPathHelper.getHelper(graphicsPath).points.length; - i++ - ) { - points.add( - Offset( - PdfPathHelper.getHelper(graphicsPath).points[i].dx, - -PdfPathHelper.getHelper(graphicsPath).points[i].dy, - ), - ); - } - PdfAnnotationHelper.getHelper(rectangleAnnotation).drawCloudStyle( - graphics!, - paintParams.backBrush, - paintParams.borderPen, - radius, - 0.833, - points, - false, - ); - } else { - graphics!.drawRectangle( - pen: paintParams.borderPen, - brush: paintParams.backBrush, - bounds: Rect.fromLTWH( - rectangle.x + borderWidth, - rectangle.y, - rectangle.width - rectangleAnnotation.border.width, - rectangle.height, - ), - ); - } - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/pdf_annotation_border.dart'; +import '../drawing/drawing.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_path.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_collection.dart'; +import 'pdf_paintparams.dart'; + +/// Represents a PDF rectangle annotation +class PdfRectangleAnnotation extends PdfAnnotation { + // Constructor + /// Initializes new instance of the [PdfRectangleAnnotation] with bounds, text, border, color, innerColor, author, rotate, subject, modifiedDate, and flags. + /// ``` dart + /// PdfDocument document = PdfDocument(); + /// PdfPage page = document.pages.add(); + /// PdfRectangleAnnotation rectangleAnnotation = PdfRectangleAnnotation( + /// const Rect.fromLTWH(0, 30, 80, 80), 'SquareAnnotation', + /// innerColor: PdfColor(255, 0, 0), color: PdfColor(255, 255, 0)); + /// page.annotations.add(rectangleAnnotation); + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfRectangleAnnotation( + Rect bounds, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + double? opacity, + DateTime? modifiedDate, + List? flags, + bool? setAppearance, + }) { + _helper = PdfRectangleAnnotationHelper( + this, + bounds, + text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + } + + PdfRectangleAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + _helper = PdfRectangleAnnotationHelper._(this, dictionary, crossTable); + this.text = text; + } + + // Fields + late PdfRectangleAnnotationHelper _helper; + + // Properites + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + return _helper.border; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + _helper.border = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } + + /// Gets the inner color of the annotation. + PdfColor get innerColor => _helper.innerColor; + + /// Sets the inner color of the annotation. + set innerColor(PdfColor value) { + _helper.innerColor = value; + } + + IPdfPrimitive? get _element => PdfAnnotationHelper.getHelper(this).dictionary; + + set _element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + PdfAnnotationHelper.getHelper(this).dictionary = value; + } + } +} + +/// [PdfRectangleAnnotation] helper +class PdfRectangleAnnotationHelper extends PdfAnnotationHelper { + /// internal constructor + PdfRectangleAnnotationHelper( + this.rectangleAnnotation, + Rect bounds, + String text, { + PdfColor? color, + PdfColor? innerColor, + PdfAnnotationBorder? border, + String? author, + String? subject, + double? opacity, + DateTime? modifiedDate, + List? flags, + bool? setAppearance, + }) : super(rectangleAnnotation) { + initializeAnnotation( + bounds: bounds, + text: text, + color: color, + innerColor: innerColor, + border: border, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(PdfDictionaryProperties.square), + ); + } + PdfRectangleAnnotationHelper._( + this.rectangleAnnotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super(rectangleAnnotation) { + initializeExistingAnnotation(dictionary, crossTable); + } + + /// internal field + late PdfRectangleAnnotation rectangleAnnotation; + + /// internal method + static PdfRectangleAnnotationHelper getHelper( + PdfRectangleAnnotation annotation, + ) { + return annotation._helper; + } + + /// internal method + static PdfRectangleAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + return PdfRectangleAnnotation._(dictionary, crossTable, text); + } + + /// internal method + @override + IPdfPrimitive? get element => rectangleAnnotation._element; + @override + set element(IPdfPrimitive? value) { + rectangleAnnotation._element = value; + } + + /// internal method + void save() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + rectangleAnnotation, + ); + if (PdfAnnotationCollectionHelper.getHelper( + rectangleAnnotation.page!.annotations, + ).flatten) { + helper.flatten = true; + } + if (helper.flatten || + rectangleAnnotation.setAppearance || + helper.appearance != null) { + PdfTemplate? appearance; + if (helper.appearance != null) { + appearance = helper.appearance!.normal; + } else { + appearance = _createAppearance(); + } + if (helper.flatten) { + if (appearance != null || helper.isLoadedAnnotation) { + if (rectangleAnnotation.page != null) { + _flattenAnnotation(rectangleAnnotation.page, appearance); + } + } + } else { + if (appearance != null) { + rectangleAnnotation.appearance.normal = appearance; + helper.dictionary!.setProperty( + PdfDictionaryProperties.ap, + PdfReferenceHolder(rectangleAnnotation.appearance), + ); + } + } + } + if (!helper.flatten && !helper.isLoadedAnnotation) { + helper.saveAnnotation(); + helper.dictionary!.setProperty( + PdfDictionaryProperties.bs, + rectangleAnnotation.border, + ); + } + if (helper.flattenPopups) { + helper.flattenPopup(); + } + } + + PdfTemplate? _createAppearance() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + rectangleAnnotation, + ); + if (helper.isLoadedAnnotation) { + if (rectangleAnnotation.setAppearance) { + final PaintParams paintParams = PaintParams(); + final double borderWidth = rectangleAnnotation.border.width / 2; + final PdfPen mBorderPen = PdfPen( + rectangleAnnotation.color, + width: rectangleAnnotation.border.width, + ); + PdfBrush? mBackBrush; + final Map result = _calculateCloudBorderBounds(); + final double borderIntensity = result['borderIntensity'] as double; + final String? borderStyle = result['borderStyle'] as String?; + final PdfRectangle nativeRectangle = PdfRectangle( + 0, + 0, + rectangleAnnotation.bounds.width, + rectangleAnnotation.bounds.height, + ); + final PdfTemplate template = PdfTemplateHelper.fromRect( + nativeRectangle.rect, + ); + PdfAnnotationHelper.setMatrixToZeroRotation( + PdfTemplateHelper.getHelper(template).content, + ); + if (borderIntensity > 0 && borderStyle == 'C') { + PdfTemplateHelper.getHelper(template).writeTransformation = false; + } + final PdfGraphics? graphics = template.graphics; + if (PdfColorHelper.getHelper(rectangleAnnotation.innerColor).alpha != + 0) { + mBackBrush = PdfSolidBrush(rectangleAnnotation.innerColor); + } + if (rectangleAnnotation.border.width > 0) { + paintParams.borderPen = mBorderPen; + } + paintParams.foreBrush = PdfSolidBrush(rectangleAnnotation.color); + paintParams.backBrush = mBackBrush; + final PdfRectangle rectangle = _obtainStyle( + mBorderPen, + nativeRectangle, + borderWidth, + borderIntensity: borderIntensity, + borderStyle: borderStyle, + ); + if (rectangleAnnotation.opacity < 1) { + graphics!.save(); + graphics.setTransparency(rectangleAnnotation.opacity); + } + if (borderIntensity > 0 && borderStyle == 'C') { + _drawAppearance( + rectangle, + borderWidth, + graphics, + paintParams, + borderIntensity, + ); + } else { + graphics!.drawRectangle( + pen: paintParams.borderPen, + brush: paintParams.backBrush, + bounds: Rect.fromLTWH( + rectangle.x, + rectangle.y, + rectangle.width, + rectangle.height, + ), + ); + } + if (rectangleAnnotation.opacity < 1) { + graphics!.restore(); + } + return template; + } + return null; + } else { + final Rect nativeRectangle = Rect.fromLTWH( + 0, + 0, + rectangleAnnotation.bounds.width, + rectangleAnnotation.bounds.height, + ); + final PdfTemplate template = PdfTemplate( + rectangleAnnotation.bounds.width, + rectangleAnnotation.bounds.height, + ); + PdfAnnotationHelper.setMatrixToZeroRotation( + PdfTemplateHelper.getHelper(template).content, + ); + final PaintParams paintParams = PaintParams(); + final PdfGraphics graphics = template.graphics!; + if (rectangleAnnotation.border.width > 0 && + PdfColorHelper.getHelper(rectangleAnnotation.color).alpha != 0) { + final PdfPen mBorderPen = PdfPen( + rectangleAnnotation.color, + width: rectangleAnnotation.border.width, + ); + paintParams.borderPen = mBorderPen; + } + PdfBrush? mBackBrush; + if (PdfColorHelper.getHelper(rectangleAnnotation.innerColor).alpha != 0) { + mBackBrush = PdfSolidBrush(rectangleAnnotation.innerColor); + } + final double width = rectangleAnnotation.border.width / 2; + + paintParams.backBrush = mBackBrush; + if (paintParams.foreBrush != PdfSolidBrush(rectangleAnnotation.color)) { + paintParams.foreBrush = PdfSolidBrush(rectangleAnnotation.color); + } + final Rect rect = Rect.fromLTWH( + nativeRectangle.left, + nativeRectangle.top, + nativeRectangle.width, + nativeRectangle.height, + ); + if (rectangleAnnotation.opacity < 1) { + graphics.save(); + graphics.setTransparency(rectangleAnnotation.opacity); + } + graphics.drawRectangle( + bounds: Rect.fromLTWH( + rect.left + width, + rect.top + width, + rect.width - rectangleAnnotation.border.width, + rect.height - rectangleAnnotation.border.width, + ), + pen: paintParams.borderPen, + brush: paintParams.backBrush, + ); + if (rectangleAnnotation.opacity < 1) { + graphics.restore(); + } + return template; + } + } + + Map _calculateCloudBorderBounds() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + rectangleAnnotation, + ); + double borderIntensity = 0; + String borderStyle = ''; + final PdfDictionary dictionary = helper.dictionary!; + if (!dictionary.containsKey(PdfDictionaryProperties.rd) && + dictionary.containsKey(PdfDictionaryProperties.be)) { + final PdfDictionary dict = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.be])! + as PdfDictionary; + if (dict.containsKey(PdfDictionaryProperties.s)) { + borderStyle = helper.getEnumName( + (dict[PdfDictionaryProperties.s]! as PdfName).name, + ); + } + if (dict.containsKey(PdfDictionaryProperties.i)) { + borderIntensity = + (dict[PdfDictionaryProperties.i]! as PdfNumber).value!.toDouble(); + } + if (borderIntensity != 0 && borderStyle == 'C') { + final Rect cloudRectangle = Rect.fromLTWH( + rectangleAnnotation.bounds.left - + borderIntensity * 5 - + rectangleAnnotation.border.width / 2, + rectangleAnnotation.bounds.top - + borderIntensity * 5 - + rectangleAnnotation.border.width / 2, + rectangleAnnotation.bounds.width + + borderIntensity * 10 + + rectangleAnnotation.border.width, + rectangleAnnotation.bounds.height + + borderIntensity * 10 + + rectangleAnnotation.border.width, + ); + final double radius = borderIntensity * 5; + final List arr = [ + radius + rectangleAnnotation.border.width / 2, + radius + rectangleAnnotation.border.width / 2, + radius + rectangleAnnotation.border.width / 2, + radius + rectangleAnnotation.border.width / 2, + ]; + dictionary.setProperty(PdfDictionaryProperties.rd, PdfArray(arr)); + rectangleAnnotation.bounds = cloudRectangle; + } + } + if (!helper.isBounds && dictionary[PdfDictionaryProperties.rd] != null) { + final PdfArray mRdArray = + dictionary[PdfDictionaryProperties.rd]! as PdfArray; + final PdfNumber num1 = mRdArray.elements[0]! as PdfNumber; + final PdfNumber num2 = mRdArray.elements[1]! as PdfNumber; + final PdfNumber num3 = mRdArray.elements[2]! as PdfNumber; + final PdfNumber num4 = mRdArray.elements[3]! as PdfNumber; + Rect cloudRectangle = Rect.fromLTWH( + rectangleAnnotation.bounds.left + num1.value!.toDouble(), + rectangleAnnotation.bounds.top + num2.value!.toDouble(), + rectangleAnnotation.bounds.width - num3.value!.toDouble() * 2, + rectangleAnnotation.bounds.height - num4.value!.toDouble() * 2, + ); + if (borderIntensity != 0 && borderStyle == 'C') { + cloudRectangle = Rect.fromLTWH( + cloudRectangle.left - + borderIntensity * 5 - + rectangleAnnotation.border.width / 2, + cloudRectangle.top - + borderIntensity * 5 - + rectangleAnnotation.border.width / 2, + cloudRectangle.width + + borderIntensity * 10 + + rectangleAnnotation.border.width, + cloudRectangle.height + + borderIntensity * 10 + + rectangleAnnotation.border.width, + ); + final double radius = borderIntensity * 5; + final List arr = [ + radius + rectangleAnnotation.border.width / 2, + radius + rectangleAnnotation.border.width / 2, + radius + rectangleAnnotation.border.width / 2, + radius + rectangleAnnotation.border.width / 2, + ]; + dictionary.setProperty(PdfDictionaryProperties.rd, PdfArray(arr)); + } else { + dictionary.remove(PdfDictionaryProperties.rd); + } + rectangleAnnotation.bounds = cloudRectangle; + } + return { + 'borderIntensity': borderIntensity, + 'borderStyle': borderStyle, + }; + } + + void _flattenAnnotation(PdfPage? page, PdfTemplate? appearance) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + rectangleAnnotation, + ); + final PdfDictionary dictionary = helper.dictionary!; + if (helper.isLoadedAnnotation) { + final bool isContainsAP = dictionary.containsKey( + PdfDictionaryProperties.ap, + ); + if (isContainsAP && appearance == null) { + PdfDictionary? appearanceDictionary = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ap]) + as PdfDictionary?; + if (appearanceDictionary != null) { + appearanceDictionary = + PdfCrossTable.dereference( + appearanceDictionary[PdfDictionaryProperties.n], + ) + as PdfDictionary?; + if (appearanceDictionary != null) { + final PdfStream appearanceStream = + appearanceDictionary as PdfStream; + appearance = PdfTemplateHelper.fromPdfStream(appearanceStream); + final bool isNormalMatrix = helper.validateTemplateMatrix( + appearanceDictionary, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } else { + rectangleAnnotation.setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } + } + } else if (!isContainsAP && appearance == null) { + rectangleAnnotation.setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } else { + final bool isNormalMatrix = helper.validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance!).content, + ); + helper.flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } else { + page!.graphics.save(); + final Rect rectangle = helper.calculateTemplateBounds( + rectangleAnnotation.bounds, + page, + appearance, + true, + ); + + if (rectangleAnnotation.opacity < 1) { + page.graphics.setTransparency(rectangleAnnotation.opacity); + } + page.graphics.drawPdfTemplate( + appearance!, + Offset(rectangle.left, rectangle.top), + rectangle.size, + ); + page.annotations.remove(rectangleAnnotation); + page.graphics.restore(); + } + } + + // Obtain Style from annotation + PdfRectangle _obtainStyle( + PdfPen mBorderPen, + PdfRectangle rectangle, + double borderWidth, { + double? borderIntensity, + String? borderStyle, + }) { + if (PdfAnnotationHelper.getHelper( + rectangleAnnotation, + ).dictionary!.containsKey(PdfDictionaryProperties.bs)) { + final PdfDictionary? bSDictionary = + PdfCrossTable.dereference( + PdfAnnotationHelper.getHelper( + rectangleAnnotation, + ).dictionary![PdfDictionaryProperties.bs], + ) + as PdfDictionary?; + if (bSDictionary != null && + bSDictionary.containsKey(PdfDictionaryProperties.d)) { + final PdfArray dashPatternArray = + PdfCrossTable.dereference(bSDictionary[PdfDictionaryProperties.d])! + as PdfArray; + final List dashPattern = []; + for (int i = 0; i < dashPatternArray.count; i++) { + dashPattern.add( + (dashPatternArray.elements[i]! as PdfNumber).value!.toDouble(), + ); + } + mBorderPen.dashStyle = PdfDashStyle.dash; + mBorderPen.dashPattern = dashPattern; + } + } + if (borderIntensity != null && + borderIntensity > 0 && + borderStyle != null && + borderStyle == 'C') { + final double radius = borderIntensity * 5; + rectangle.x = rectangle.x + radius + borderWidth; + rectangle.y = rectangle.y + radius + borderWidth; + rectangle.width = rectangle.width - (2 * radius) - 2 * borderWidth; + rectangle.height = rectangle.height - (2 * radius) - 2 * borderWidth; + } else { + rectangle.x += borderWidth; + rectangle.y += borderWidth; + rectangle.width -= rectangleAnnotation.border.width; + rectangle.height -= rectangleAnnotation.border.width; + } + return rectangle; + } + + // Draw appearance for annotation + void _drawAppearance( + PdfRectangle rectangle, + double borderWidth, + PdfGraphics? graphics, + PaintParams paintParams, + double borderIntensity, + ) { + final PdfPath graphicsPath = PdfPath(); + graphicsPath.addRectangle(rectangle.rect); + final double radius = borderIntensity * 4.25; + if (radius > 0) { + if (PdfPathHelper.getHelper(graphicsPath).points.length == 5 && + PdfPathHelper.getHelper(graphicsPath).points[4] == Offset.zero) { + PdfPathHelper.getHelper(graphicsPath).points.removeAt(4); + } + final List points = []; + for ( + int i = 0; + i < PdfPathHelper.getHelper(graphicsPath).points.length; + i++ + ) { + points.add( + Offset( + PdfPathHelper.getHelper(graphicsPath).points[i].dx, + -PdfPathHelper.getHelper(graphicsPath).points[i].dy, + ), + ); + } + PdfAnnotationHelper.getHelper(rectangleAnnotation).drawCloudStyle( + graphics!, + paintParams.backBrush, + paintParams.borderPen, + radius, + 0.833, + points, + false, + ); + } else { + graphics!.drawRectangle( + pen: paintParams.borderPen, + brush: paintParams.backBrush, + bounds: Rect.fromLTWH( + rectangle.x + borderWidth, + rectangle.y, + rectangle.width - rectangleAnnotation.border.width, + rectangle.height, + ), + ); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_markup_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_markup_annotation.dart index cad794afe..872a8afb6 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_markup_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_markup_annotation.dart @@ -1,756 +1,756 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_path.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_margins.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/enum.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_collection.dart'; - -/// Represents the text markup annotation. -class PdfTextMarkupAnnotation extends PdfAnnotation { - // Constructor - /// Initializes new instance of [PdfTextMarkupAnnotation] class with bounds, text, color, author, subject, modifiedDate, boundsCollection, flags and textMarkupAnnotationType. - /// ``` dart - /// //Create a new PDF document. - /// final PdfDocument document = PdfDocument(); - /// //Create a new page. - /// final PdfPage page = document.pages.add(); - /// //Create PDF font with font style. - /// final PdfFont font = - /// PdfStandardFont(PdfFontFamily.courier, 10, style: PdfFontStyle.bold); - /// const String markupText = 'Text Markup'; - /// final Size textSize = font.measureString(markupText); - /// page.graphics.drawString(markupText, font, - /// brush: PdfBrushes.black, bounds: const Rect.fromLTWH(175, 40, 0, 0)); - /// //Create a text markup annotation. - /// final PdfTextMarkupAnnotation markupAnnotation = PdfTextMarkupAnnotation( - /// Rect.fromLTWH(175, 40, textSize.width, textSize.height), - /// 'Markup annotation', - /// PdfColor(128, 43, 226)); - /// markupAnnotation.author = 'MarkUp'; - /// markupAnnotation.textMarkupAnnotationType = - /// PdfTextMarkupAnnotationType.highlight; - /// //Adds the annotation to the page - /// page.annotations.add(markupAnnotation); - /// final List bytes = document.saveSync(); - /// document.dispose(); - /// ``` - PdfTextMarkupAnnotation( - Rect bounds, - String text, - PdfColor color, { - String? author, - String? subject, - double? opacity, - DateTime? modifiedDate, - bool? setAppearance, - List? boundsCollection, - List? flags, - PdfTextMarkupAnnotationType? textMarkupAnnotationType, - }) { - _helper = PdfTextMarkupAnnotationHelper( - this, - bounds, - text, - color, - author, - subject, - opacity, - modifiedDate, - setAppearance, - flags, - textMarkupAnnotationType, - ); - if (boundsCollection != null) { - this.boundsCollection = boundsCollection; - } - } - - PdfTextMarkupAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - _helper = PdfTextMarkupAnnotationHelper._(this, dictionary, crossTable); - } - - // Fields - late PdfTextMarkupAnnotationHelper _helper; - - // Properties - /// Gets the text markup annotation bounds collection. - List get boundsCollection => _helper.boundsCollection; - - /// Sets the text markup annotation bounds collection. - set boundsCollection(List value) { - _helper.boundsCollection = value; - } - - /// Gets text markup annotation Type. - PdfTextMarkupAnnotationType get textMarkupAnnotationType => - _helper.textMarkupAnnotationType; - - /// Sets text markup annotation Type. - set textMarkupAnnotationType(PdfTextMarkupAnnotationType value) { - _helper.textMarkupAnnotationType = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } -} - -/// [PdfTextMarkupAnnotation] helper -class PdfTextMarkupAnnotationHelper extends PdfAnnotationHelper { - //Constructor - /// internal constructor - PdfTextMarkupAnnotationHelper( - this.textMarkupAnnotation, - Rect bounds, - String text, - PdfColor color, - String? author, - String? subject, - double? opacity, - DateTime? modifiedDate, - bool? setAppearance, - List? flags, - PdfTextMarkupAnnotationType? textMarkupAnnotationType, - ) : super(textMarkupAnnotation) { - initializeAnnotation( - bounds: bounds, - text: text, - color: color, - author: author, - subject: subject, - modifiedDate: modifiedDate, - opacity: opacity, - flags: flags, - setAppearance: setAppearance, - ); - this.textMarkupAnnotationType = - textMarkupAnnotationType ?? PdfTextMarkupAnnotationType.highlight; - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(getEnumName(this.textMarkupAnnotationType.toString())), - ); - } - - PdfTextMarkupAnnotationHelper._( - this.textMarkupAnnotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super(textMarkupAnnotation) { - initializeExistingAnnotation(dictionary, crossTable); - } - - //Fields - /// internal field - late PdfTextMarkupAnnotation textMarkupAnnotation; - List _boundsCollection = []; - - /// internal field - PdfArray? points; - - /// internal field - PdfTextMarkupAnnotationType? _textMarkupAnnotationType; - - /// internal method - static PdfTextMarkupAnnotationHelper getHelper( - PdfTextMarkupAnnotation annotation, - ) { - return annotation._helper; - } - - /// internal method - static PdfTextMarkupAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfTextMarkupAnnotation._(dictionary, crossTable); - } - - //Properties - /// Gets the text markup annotation bounds collection. - List get boundsCollection { - if (isLoadedAnnotation) { - _boundsCollection = _obtainBoundsValue(); - } - return _boundsCollection; - } - - /// Sets the text markup annotation bounds collection. - set boundsCollection(List value) { - if (!isLoadedAnnotation) { - if (_boundsCollection.isNotEmpty) { - for (int i = 0; i < value.length; i++) { - _boundsCollection.add(value[i]); - } - } else { - _boundsCollection = value; - } - } else { - _boundsCollection = value; - setQuadPoints(page!.size); - } - } - - /// Gets text markup annotation Type. - PdfTextMarkupAnnotationType get textMarkupAnnotationType => - isLoadedAnnotation - ? _obtainTextMarkupAnnotationType() - : _textMarkupAnnotationType!; - - /// Sets text markup annotation Type. - set textMarkupAnnotationType(PdfTextMarkupAnnotationType value) { - _textMarkupAnnotationType = value; - if (isLoadedAnnotation) { - dictionary![PdfDictionaryProperties.subtype] = PdfName( - getEnumName(_textMarkupAnnotationType), - ); - } - } - - //Implementation - /// Internal method. - void setQuadPoints(Size pageSize) { - if (!isLoadedAnnotation) { - final double pageHeight = pageSize.height; - final PdfMargins margins = obtainMargin()!; - if (bounds.width == 0 && bounds.height == 0) { - bounds = Rect.fromLTWH( - bounds.left, - bounds.top, - bounds.width, - bounds.height, - ); - } - if (_boundsCollection.isEmpty && !_boundsCollection.contains(bounds)) { - _boundsCollection.add(bounds); - } - final int length = _boundsCollection.length * 8; - final List textQuadLocation = List.filled(length, 0); - final int noofRect = length ~/ 8; - for (int i = 0; i < noofRect; i++) { - final double locationX = _boundsCollection[i].left, - locationY = _boundsCollection[i].top; - textQuadLocation[0 + (i * 8)] = locationX + margins.left; - textQuadLocation[1 + (i * 8)] = (pageHeight - locationY) - margins.top; - textQuadLocation[2 + (i * 8)] = - (locationX + _boundsCollection[i].width) + margins.left; - textQuadLocation[3 + (i * 8)] = (pageHeight - locationY) - margins.top; - textQuadLocation[4 + (i * 8)] = locationX + margins.left; - textQuadLocation[5 + (i * 8)] = - textQuadLocation[1 + (i * 8)] - _boundsCollection[i].height; - textQuadLocation[6 + (i * 8)] = - (locationX + _boundsCollection[i].width) + margins.left; - textQuadLocation[7 + (i * 8)] = textQuadLocation[5 + (i * 8)]; - } - points = PdfArray(textQuadLocation); - dictionary!.setProperty(PdfDictionaryProperties.quadPoints, points); - } else { - final List textQuadLocation = List.filled( - _boundsCollection.length * 8, - 0, - ); - final double pageHeight = pageSize.height; - for (int i = 0; i < _boundsCollection.length; i++) { - final double locationX = _boundsCollection[i].left, - locationY = _boundsCollection[i].top; - textQuadLocation[0 + (i * 8)] = locationX; - textQuadLocation[1 + (i * 8)] = pageHeight - locationY; - textQuadLocation[2 + (i * 8)] = locationX + _boundsCollection[i].width; - textQuadLocation[3 + (i * 8)] = pageHeight - locationY; - textQuadLocation[4 + (i * 8)] = locationX; - textQuadLocation[5 + (i * 8)] = - textQuadLocation[1 + (i * 8)] - _boundsCollection[i].height; - textQuadLocation[6 + (i * 8)] = locationX + _boundsCollection[i].width; - textQuadLocation[7 + (i * 8)] = textQuadLocation[5 + (i * 8)]; - } - dictionary!.setProperty( - PdfDictionaryProperties.quadPoints, - PdfArray(textQuadLocation), - ); - } - } - - List _obtainBoundsValue() { - final List collection = []; - if (dictionary!.containsKey(PdfDictionaryProperties.quadPoints)) { - final IPdfPrimitive? points = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.quadPoints], - ); - double x, y, width, height; - if (points != null && points is PdfArray) { - for (int i = 0; i < (points.count / 8).round(); i++) { - final double q1 = - (points[0 + (i * 8)]! as PdfNumber).value!.toDouble(); - final double q2 = - (points[1 + (i * 8)]! as PdfNumber).value!.toDouble(); - final double q3 = - (points[2 + (i * 8)]! as PdfNumber).value!.toDouble(); - final double q4 = - (points[3 + (i * 8)]! as PdfNumber).value!.toDouble(); - final double q5 = - (points[4 + (i * 8)]! as PdfNumber).value!.toDouble(); - final double q6 = - (points[5 + (i * 8)]! as PdfNumber).value!.toDouble(); - final double q7 = - (points[6 + (i * 8)]! as PdfNumber).value!.toDouble(); - final double q8 = - (points[7 + (i * 8)]! as PdfNumber).value!.toDouble(); - x = q5 - q1; - y = q6 - q2; - height = sqrt((x * x) + (y * y)); - x = q7 - q5; - y = q8 - q6; - width = sqrt((x * x) + (y * y)); - final double m = [q1, q3, q5, q7].reduce(min); - final double n = page!.size.height - [q2, q4, q6, q8].reduce(max); - final Rect rect = Rect.fromLTWH(m, n, width, height); - collection.add(rect); - } - } - } - return collection; - } - - PdfTextMarkupAnnotationType _getTextMarkupAnnotation(String aType) { - PdfTextMarkupAnnotationType annotType = - PdfTextMarkupAnnotationType.highlight; - switch (aType) { - case 'Highlight': - annotType = PdfTextMarkupAnnotationType.highlight; - break; - case 'Squiggly': - annotType = PdfTextMarkupAnnotationType.squiggly; - break; - case 'StrikeOut': - annotType = PdfTextMarkupAnnotationType.strikethrough; - break; - case 'Underline': - annotType = PdfTextMarkupAnnotationType.underline; - break; - } - return annotType; - } - - /// internal method - void save() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - textMarkupAnnotation, - ); - if (PdfAnnotationCollectionHelper.getHelper( - textMarkupAnnotation.page!.annotations, - ).flatten) { - helper.flatten = true; - } - if (!helper.isLoadedAnnotation) { - final PdfArray textMarkupColor = PdfArray(); - if (!color.isEmpty) { - final double red = color.r / 255; - final double green = color.g / 255; - final double blue = color.b / 255; - if (textMarkupColor.elements.isEmpty) { - textMarkupColor.add(PdfNumber(red)); - textMarkupColor.add(PdfNumber(green)); - textMarkupColor.add(PdfNumber(blue)); - } else { - textMarkupColor.insert(0, PdfNumber(red)); - textMarkupColor.insert(1, PdfNumber(green)); - textMarkupColor.insert(2, PdfNumber(blue)); - } - dictionary!.setProperty(PdfDictionaryProperties.c, textMarkupColor); - } else { - throw ArgumentError.value('TextMarkupColor is not null'); - } - } - if (helper.flatten || helper.setAppearance) { - final PdfTemplate? appearance = _createAppearance(); - if (helper.flatten) { - if (textMarkupAnnotation.page != null) { - _flattenAnnotation(textMarkupAnnotation.page!, appearance); - } - } else { - if (appearance != null) { - textMarkupAnnotation.appearance.normal = appearance; - dictionary!.setProperty( - PdfDictionaryProperties.ap, - PdfReferenceHolder(textMarkupAnnotation.appearance), - ); - } - } - } - if (!helper.flatten && !helper.isLoadedAnnotation) { - super.saveAnnotation(); - _saveTextMarkUpDictionary(); - } - if (helper.flattenPopups) { - helper.flattenPopup(); - } - } - - String _getMarkupAnnotationType() { - switch (textMarkupAnnotationType) { - case PdfTextMarkupAnnotationType.highlight: - return 'Highlight'; - case PdfTextMarkupAnnotationType.underline: - return 'Underline'; - case PdfTextMarkupAnnotationType.squiggly: - return 'Squiggly'; - case PdfTextMarkupAnnotationType.strikethrough: - return 'StrikeOut'; - } - } - - void _saveTextMarkUpDictionary() { - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(_getMarkupAnnotationType()), - ); - } - - PdfTemplate? _createAppearance() { - if (!isLoadedAnnotation || (isLoadedAnnotation && setAppearance)) { - double x, y; - double width = 0, height = 0; - PdfRectangle? rectangle; - if (boundsCollection.length > 1) { - final PdfPath pdfPath = PdfPath(); - for (int i = 0; i < boundsCollection.length; i++) { - pdfPath.addRectangle(boundsCollection[i]); - } - rectangle = PdfPathHelper.getHelper(pdfPath).getBoundsInternal(); - bounds = rectangle.rect; - width = rectangle.width; - height = rectangle.height; - } else { - if (dictionary!.containsKey(PdfDictionaryProperties.quadPoints)) { - final IPdfPrimitive? mQuadPoints = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.quadPoints], - ); - if (mQuadPoints != null && mQuadPoints is PdfArray) { - for (int i = 0; i < (mQuadPoints.count / 8); i++) { - if (isLoadedAnnotation) { - final List quadPoints = List.filled( - mQuadPoints.count ~/ 2, - Offset.zero, - ); - int j = 0; - for (int k = 0; k < mQuadPoints.count;) { - final double x1 = - (mQuadPoints[k]! as PdfNumber).value!.toDouble(); - final double y1 = - (mQuadPoints[k + 1]! as PdfNumber).value!.toDouble(); - quadPoints[j] = Offset(x1, y1); - k = k + 2; - j++; - } - final PdfPath path = PdfPath(); - PdfPathHelper.getHelper(path).addLines(quadPoints); - rectangle = PdfPathHelper.getHelper(path).getBoundsInternal(); - height = rectangle.height; - width = rectangle.width; - } else { - x = - ((mQuadPoints[4 + (i * 8)]! as PdfNumber).value! - - (mQuadPoints[0 + (i * 8)]! as PdfNumber).value!) - .toDouble(); - y = - ((mQuadPoints[5 + (i * 8)]! as PdfNumber).value! - - (mQuadPoints[1 + (i * 8)]! as PdfNumber).value!) - .toDouble(); - height = sqrt((x * x) + (y * y)); - x = - ((mQuadPoints[6 + (i * 8)]! as PdfNumber).value! - - (mQuadPoints[4 + (i * 8)]! as PdfNumber).value!) - .toDouble(); - y = - ((mQuadPoints[7 + (i * 8)]! as PdfNumber).value! - - (mQuadPoints[5 + (i * 8)]! as PdfNumber).value!) - .toDouble(); - width = sqrt((x * x) + (y * y)); - bounds = Rect.fromLTWH(bounds.left, bounds.top, width, height); - } - } - } - } - } - final PdfTemplate template = PdfTemplate(width, height); - PdfAnnotationHelper.setMatrixToZeroRotation( - PdfTemplateHelper.getHelper(template).content, - ); - final PdfGraphics graphics = template.graphics!; - graphics.setTransparency(opacity, mode: PdfBlendMode.multiply); - if (boundsCollection.length > 1) { - for (int i = 0; i < boundsCollection.length; i++) { - if (textMarkupAnnotationType == - PdfTextMarkupAnnotationType.highlight) { - graphics.drawRectangle( - brush: PdfSolidBrush(color), - bounds: Rect.fromLTWH( - boundsCollection[i].left - rectangle!.x, - boundsCollection[i].top - rectangle.y, - boundsCollection[i].width, - boundsCollection[i].height, - ), - ); - } else if (textMarkupAnnotationType == - PdfTextMarkupAnnotationType.underline) { - graphics.drawLine( - PdfPen(color, width: boundsCollection[i].height * 0.05), - Offset( - boundsCollection[i].left - rectangle!.x, - (boundsCollection[i].top - rectangle.y) + - (boundsCollection[i].height - - ((boundsCollection[i].height / 2) / 3)), - ), - Offset( - boundsCollection[i].width + - (boundsCollection[i].left - rectangle.x), - (boundsCollection[i].top - rectangle.y) + - (boundsCollection[i].height - - ((boundsCollection[i].height / 2) / 3)), - ), - ); - } else if (textMarkupAnnotationType == - PdfTextMarkupAnnotationType.strikethrough) { - graphics.drawLine( - PdfPen(color, width: boundsCollection[i].height * 0.05), - Offset( - boundsCollection[i].left - rectangle!.x, - (boundsCollection[i].top - rectangle.y) + - (boundsCollection[i].height - - (boundsCollection[i].height / 2)), - ), - Offset( - boundsCollection[i].width + - (boundsCollection[i].left - rectangle.x), - (boundsCollection[i].top - rectangle.y) + - (boundsCollection[i].height - - (boundsCollection[i].height / 2)), - ), - ); - } else if (textMarkupAnnotationType == - PdfTextMarkupAnnotationType.squiggly) { - final PdfPen pdfPen = PdfPen( - color, - width: boundsCollection[i].height * 0.02, - ); - graphics.save(); - graphics.translateTransform( - boundsCollection[i].left - rectangle!.x, - boundsCollection[i].top - rectangle.y, - ); - graphics.setClip( - bounds: Rect.fromLTWH( - 0, - 0, - boundsCollection[i].width, - boundsCollection[i].height, - ), - ); - graphics.drawPath( - _drawSquiggly( - boundsCollection[i].width, - boundsCollection[i].height, - ), - pen: pdfPen, - ); - graphics.restore(); - } - } - } else { - if (textMarkupAnnotationType == PdfTextMarkupAnnotationType.highlight) { - graphics.drawRectangle( - brush: PdfSolidBrush(color), - bounds: Rect.fromLTWH(0, 0, width, height), - ); - } else if (textMarkupAnnotationType == - PdfTextMarkupAnnotationType.underline) { - graphics.drawLine( - PdfPen(color, width: height * 0.05), - Offset(0, height - ((height / 2) / 3)), - Offset(width, height - ((height / 2) / 3)), - ); - } else if (textMarkupAnnotationType == - PdfTextMarkupAnnotationType.strikethrough) { - graphics.drawLine( - PdfPen(color, width: height * 0.05), - Offset(0, height / 2), - Offset(width, height / 2), - ); - } else if (textMarkupAnnotationType == - PdfTextMarkupAnnotationType.squiggly) { - final PdfPen pdfPen = PdfPen(color, width: height * 0.02); - graphics.drawPath(_drawSquiggly(width, height), pen: pdfPen); - } - if (isLoadedAnnotation) { - dictionary![PdfDictionaryProperties.rect] = PdfArray.fromRectangle( - rectangle!, - ); - } - } - return template; - } - return null; - } - - PdfPath _drawSquiggly(double width, double height) { - if (width.toInt() % 2 != 0 || width.round() > width) { - width = width + 1; - } - final PdfPath path = PdfPath(); - final List mPathPoints = List.filled( - ((width / height) * 16).ceil(), - Offset.zero, - ); - final double length = width / (mPathPoints.length / 2); - final double location = (length + length) * 0.6; - double zigZag = location; - double x = 0; - for (int i = 0; i < mPathPoints.length; i++, x += length) { - mPathPoints[i] = Offset( - x, - ((height - location) + zigZag) - (height * 0.02), - ); - if (zigZag == 0) { - zigZag = location; - } else { - zigZag = 0; - } - } - PdfPathHelper.getHelper(path).addLines(mPathPoints); - return path; - } - - void _flattenAnnotation(PdfPage page, PdfTemplate? appearance) { - if (!isLoadedAnnotation) { - if (appearance != null) { - page.graphics.save(); - final Rect rectangle = calculateTemplateBounds( - bounds, - page, - appearance, - true, - ); - if (opacity < 1) { - page.graphics.setTransparency(opacity); - } - page.graphics.drawPdfTemplate( - appearance, - Offset(rectangle.left, rectangle.top), - rectangle.size, - ); - page.annotations.remove(textMarkupAnnotation); - page.graphics.restore(); - } - } else { - if (dictionary != null && - dictionary!.containsKey(PdfDictionaryProperties.ap) && - appearance == null) { - IPdfPrimitive? appearanceDictionary = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.ap], - ); - if (appearanceDictionary != null && - appearanceDictionary is PdfDictionary) { - appearanceDictionary = PdfCrossTable.dereference( - appearanceDictionary[PdfDictionaryProperties.n], - ); - if (appearanceDictionary != null && - appearanceDictionary is PdfStream) { - appearance = PdfTemplateHelper.fromPdfStream(appearanceDictionary); - final bool isNormalMatrix = validateTemplateMatrix( - appearanceDictionary, - ); - if (isNormalMatrix && - page.rotation != PdfPageRotateAngle.rotateAngle0) { - flattenAnnotationTemplate(appearance, isNormalMatrix); - } else if (isNormalMatrix && - isValidTemplateMatrix( - appearanceDictionary, - bounds.topLeft, - appearance, - )) { - flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } else { - setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } - } - } else if (!dictionary!.containsKey(PdfDictionaryProperties.ap) && - appearance == null) { - setAppearance = true; - appearance = _createAppearance(); - if (appearance != null) { - final bool isNormalMatrix = validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } else if (!dictionary!.containsKey(PdfDictionaryProperties.ap) && - appearance != null) { - final bool isNormalMatrix = validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - flattenAnnotationTemplate(appearance, isNormalMatrix); - } else if (dictionary!.containsKey(PdfDictionaryProperties.ap) && - appearance != null) { - final bool isNormalMatrix = validateTemplateMatrix( - PdfTemplateHelper.getHelper(appearance).content, - ); - flattenAnnotationTemplate(appearance, isNormalMatrix); - } - } - } - - PdfTextMarkupAnnotationType _obtainTextMarkupAnnotationType() { - final IPdfPrimitive? annotType = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.subtype], - ); - if (annotType != null && annotType is PdfName) { - final String aType = annotType.name.toString(); - return _getTextMarkupAnnotation(aType); - } - return PdfTextMarkupAnnotationType.highlight; - } - - /// internal method - @override - IPdfPrimitive? get element => dictionary; - @override - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } -} +import 'dart:math'; +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_path.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_margins.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/enum.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_collection.dart'; + +/// Represents the text markup annotation. +class PdfTextMarkupAnnotation extends PdfAnnotation { + // Constructor + /// Initializes new instance of [PdfTextMarkupAnnotation] class with bounds, text, color, author, subject, modifiedDate, boundsCollection, flags and textMarkupAnnotationType. + /// ``` dart + /// //Create a new PDF document. + /// final PdfDocument document = PdfDocument(); + /// //Create a new page. + /// final PdfPage page = document.pages.add(); + /// //Create PDF font with font style. + /// final PdfFont font = + /// PdfStandardFont(PdfFontFamily.courier, 10, style: PdfFontStyle.bold); + /// const String markupText = 'Text Markup'; + /// final Size textSize = font.measureString(markupText); + /// page.graphics.drawString(markupText, font, + /// brush: PdfBrushes.black, bounds: const Rect.fromLTWH(175, 40, 0, 0)); + /// //Create a text markup annotation. + /// final PdfTextMarkupAnnotation markupAnnotation = PdfTextMarkupAnnotation( + /// Rect.fromLTWH(175, 40, textSize.width, textSize.height), + /// 'Markup annotation', + /// PdfColor(128, 43, 226)); + /// markupAnnotation.author = 'MarkUp'; + /// markupAnnotation.textMarkupAnnotationType = + /// PdfTextMarkupAnnotationType.highlight; + /// //Adds the annotation to the page + /// page.annotations.add(markupAnnotation); + /// final List bytes = document.saveSync(); + /// document.dispose(); + /// ``` + PdfTextMarkupAnnotation( + Rect bounds, + String text, + PdfColor color, { + String? author, + String? subject, + double? opacity, + DateTime? modifiedDate, + bool? setAppearance, + List? boundsCollection, + List? flags, + PdfTextMarkupAnnotationType? textMarkupAnnotationType, + }) { + _helper = PdfTextMarkupAnnotationHelper( + this, + bounds, + text, + color, + author, + subject, + opacity, + modifiedDate, + setAppearance, + flags, + textMarkupAnnotationType, + ); + if (boundsCollection != null) { + this.boundsCollection = boundsCollection; + } + } + + PdfTextMarkupAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + _helper = PdfTextMarkupAnnotationHelper._(this, dictionary, crossTable); + } + + // Fields + late PdfTextMarkupAnnotationHelper _helper; + + // Properties + /// Gets the text markup annotation bounds collection. + List get boundsCollection => _helper.boundsCollection; + + /// Sets the text markup annotation bounds collection. + set boundsCollection(List value) { + _helper.boundsCollection = value; + } + + /// Gets text markup annotation Type. + PdfTextMarkupAnnotationType get textMarkupAnnotationType => + _helper.textMarkupAnnotationType; + + /// Sets text markup annotation Type. + set textMarkupAnnotationType(PdfTextMarkupAnnotationType value) { + _helper.textMarkupAnnotationType = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } +} + +/// [PdfTextMarkupAnnotation] helper +class PdfTextMarkupAnnotationHelper extends PdfAnnotationHelper { + //Constructor + /// internal constructor + PdfTextMarkupAnnotationHelper( + this.textMarkupAnnotation, + Rect bounds, + String text, + PdfColor color, + String? author, + String? subject, + double? opacity, + DateTime? modifiedDate, + bool? setAppearance, + List? flags, + PdfTextMarkupAnnotationType? textMarkupAnnotationType, + ) : super(textMarkupAnnotation) { + initializeAnnotation( + bounds: bounds, + text: text, + color: color, + author: author, + subject: subject, + modifiedDate: modifiedDate, + opacity: opacity, + flags: flags, + setAppearance: setAppearance, + ); + this.textMarkupAnnotationType = + textMarkupAnnotationType ?? PdfTextMarkupAnnotationType.highlight; + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(getEnumName(this.textMarkupAnnotationType.toString())), + ); + } + + PdfTextMarkupAnnotationHelper._( + this.textMarkupAnnotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super(textMarkupAnnotation) { + initializeExistingAnnotation(dictionary, crossTable); + } + + //Fields + /// internal field + late PdfTextMarkupAnnotation textMarkupAnnotation; + List _boundsCollection = []; + + /// internal field + PdfArray? points; + + /// internal field + PdfTextMarkupAnnotationType? _textMarkupAnnotationType; + + /// internal method + static PdfTextMarkupAnnotationHelper getHelper( + PdfTextMarkupAnnotation annotation, + ) { + return annotation._helper; + } + + /// internal method + static PdfTextMarkupAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfTextMarkupAnnotation._(dictionary, crossTable); + } + + //Properties + /// Gets the text markup annotation bounds collection. + List get boundsCollection { + if (isLoadedAnnotation) { + _boundsCollection = _obtainBoundsValue(); + } + return _boundsCollection; + } + + /// Sets the text markup annotation bounds collection. + set boundsCollection(List value) { + if (!isLoadedAnnotation) { + if (_boundsCollection.isNotEmpty) { + for (int i = 0; i < value.length; i++) { + _boundsCollection.add(value[i]); + } + } else { + _boundsCollection = value; + } + } else { + _boundsCollection = value; + setQuadPoints(page!.size); + } + } + + /// Gets text markup annotation Type. + PdfTextMarkupAnnotationType get textMarkupAnnotationType => + isLoadedAnnotation + ? _obtainTextMarkupAnnotationType() + : _textMarkupAnnotationType!; + + /// Sets text markup annotation Type. + set textMarkupAnnotationType(PdfTextMarkupAnnotationType value) { + _textMarkupAnnotationType = value; + if (isLoadedAnnotation) { + dictionary![PdfDictionaryProperties.subtype] = PdfName( + getEnumName(_textMarkupAnnotationType), + ); + } + } + + //Implementation + /// Internal method. + void setQuadPoints(Size pageSize) { + if (!isLoadedAnnotation) { + final double pageHeight = pageSize.height; + final PdfMargins margins = obtainMargin()!; + if (bounds.width == 0 && bounds.height == 0) { + bounds = Rect.fromLTWH( + bounds.left, + bounds.top, + bounds.width, + bounds.height, + ); + } + if (_boundsCollection.isEmpty && !_boundsCollection.contains(bounds)) { + _boundsCollection.add(bounds); + } + final int length = _boundsCollection.length * 8; + final List textQuadLocation = List.filled(length, 0); + final int noofRect = length ~/ 8; + for (int i = 0; i < noofRect; i++) { + final double locationX = _boundsCollection[i].left, + locationY = _boundsCollection[i].top; + textQuadLocation[0 + (i * 8)] = locationX + margins.left; + textQuadLocation[1 + (i * 8)] = (pageHeight - locationY) - margins.top; + textQuadLocation[2 + (i * 8)] = + (locationX + _boundsCollection[i].width) + margins.left; + textQuadLocation[3 + (i * 8)] = (pageHeight - locationY) - margins.top; + textQuadLocation[4 + (i * 8)] = locationX + margins.left; + textQuadLocation[5 + (i * 8)] = + textQuadLocation[1 + (i * 8)] - _boundsCollection[i].height; + textQuadLocation[6 + (i * 8)] = + (locationX + _boundsCollection[i].width) + margins.left; + textQuadLocation[7 + (i * 8)] = textQuadLocation[5 + (i * 8)]; + } + points = PdfArray(textQuadLocation); + dictionary!.setProperty(PdfDictionaryProperties.quadPoints, points); + } else { + final List textQuadLocation = List.filled( + _boundsCollection.length * 8, + 0, + ); + final double pageHeight = pageSize.height; + for (int i = 0; i < _boundsCollection.length; i++) { + final double locationX = _boundsCollection[i].left, + locationY = _boundsCollection[i].top; + textQuadLocation[0 + (i * 8)] = locationX; + textQuadLocation[1 + (i * 8)] = pageHeight - locationY; + textQuadLocation[2 + (i * 8)] = locationX + _boundsCollection[i].width; + textQuadLocation[3 + (i * 8)] = pageHeight - locationY; + textQuadLocation[4 + (i * 8)] = locationX; + textQuadLocation[5 + (i * 8)] = + textQuadLocation[1 + (i * 8)] - _boundsCollection[i].height; + textQuadLocation[6 + (i * 8)] = locationX + _boundsCollection[i].width; + textQuadLocation[7 + (i * 8)] = textQuadLocation[5 + (i * 8)]; + } + dictionary!.setProperty( + PdfDictionaryProperties.quadPoints, + PdfArray(textQuadLocation), + ); + } + } + + List _obtainBoundsValue() { + final List collection = []; + if (dictionary!.containsKey(PdfDictionaryProperties.quadPoints)) { + final IPdfPrimitive? points = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.quadPoints], + ); + double x, y, width, height; + if (points != null && points is PdfArray) { + for (int i = 0; i < (points.count / 8).round(); i++) { + final double q1 = + (points[0 + (i * 8)]! as PdfNumber).value!.toDouble(); + final double q2 = + (points[1 + (i * 8)]! as PdfNumber).value!.toDouble(); + final double q3 = + (points[2 + (i * 8)]! as PdfNumber).value!.toDouble(); + final double q4 = + (points[3 + (i * 8)]! as PdfNumber).value!.toDouble(); + final double q5 = + (points[4 + (i * 8)]! as PdfNumber).value!.toDouble(); + final double q6 = + (points[5 + (i * 8)]! as PdfNumber).value!.toDouble(); + final double q7 = + (points[6 + (i * 8)]! as PdfNumber).value!.toDouble(); + final double q8 = + (points[7 + (i * 8)]! as PdfNumber).value!.toDouble(); + x = q5 - q1; + y = q6 - q2; + height = sqrt((x * x) + (y * y)); + x = q7 - q5; + y = q8 - q6; + width = sqrt((x * x) + (y * y)); + final double m = [q1, q3, q5, q7].reduce(min); + final double n = page!.size.height - [q2, q4, q6, q8].reduce(max); + final Rect rect = Rect.fromLTWH(m, n, width, height); + collection.add(rect); + } + } + } + return collection; + } + + PdfTextMarkupAnnotationType _getTextMarkupAnnotation(String aType) { + PdfTextMarkupAnnotationType annotType = + PdfTextMarkupAnnotationType.highlight; + switch (aType) { + case 'Highlight': + annotType = PdfTextMarkupAnnotationType.highlight; + break; + case 'Squiggly': + annotType = PdfTextMarkupAnnotationType.squiggly; + break; + case 'StrikeOut': + annotType = PdfTextMarkupAnnotationType.strikethrough; + break; + case 'Underline': + annotType = PdfTextMarkupAnnotationType.underline; + break; + } + return annotType; + } + + /// internal method + void save() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + textMarkupAnnotation, + ); + if (PdfAnnotationCollectionHelper.getHelper( + textMarkupAnnotation.page!.annotations, + ).flatten) { + helper.flatten = true; + } + if (!helper.isLoadedAnnotation) { + final PdfArray textMarkupColor = PdfArray(); + if (!color.isEmpty) { + final double red = color.r / 255; + final double green = color.g / 255; + final double blue = color.b / 255; + if (textMarkupColor.elements.isEmpty) { + textMarkupColor.add(PdfNumber(red)); + textMarkupColor.add(PdfNumber(green)); + textMarkupColor.add(PdfNumber(blue)); + } else { + textMarkupColor.insert(0, PdfNumber(red)); + textMarkupColor.insert(1, PdfNumber(green)); + textMarkupColor.insert(2, PdfNumber(blue)); + } + dictionary!.setProperty(PdfDictionaryProperties.c, textMarkupColor); + } else { + throw ArgumentError.value('TextMarkupColor is not null'); + } + } + if (helper.flatten || helper.setAppearance) { + final PdfTemplate? appearance = _createAppearance(); + if (helper.flatten) { + if (textMarkupAnnotation.page != null) { + _flattenAnnotation(textMarkupAnnotation.page!, appearance); + } + } else { + if (appearance != null) { + textMarkupAnnotation.appearance.normal = appearance; + dictionary!.setProperty( + PdfDictionaryProperties.ap, + PdfReferenceHolder(textMarkupAnnotation.appearance), + ); + } + } + } + if (!helper.flatten && !helper.isLoadedAnnotation) { + super.saveAnnotation(); + _saveTextMarkUpDictionary(); + } + if (helper.flattenPopups) { + helper.flattenPopup(); + } + } + + String _getMarkupAnnotationType() { + switch (textMarkupAnnotationType) { + case PdfTextMarkupAnnotationType.highlight: + return 'Highlight'; + case PdfTextMarkupAnnotationType.underline: + return 'Underline'; + case PdfTextMarkupAnnotationType.squiggly: + return 'Squiggly'; + case PdfTextMarkupAnnotationType.strikethrough: + return 'StrikeOut'; + } + } + + void _saveTextMarkUpDictionary() { + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(_getMarkupAnnotationType()), + ); + } + + PdfTemplate? _createAppearance() { + if (!isLoadedAnnotation || (isLoadedAnnotation && setAppearance)) { + double x, y; + double width = 0, height = 0; + PdfRectangle? rectangle; + if (boundsCollection.length > 1) { + final PdfPath pdfPath = PdfPath(); + for (int i = 0; i < boundsCollection.length; i++) { + pdfPath.addRectangle(boundsCollection[i]); + } + rectangle = PdfPathHelper.getHelper(pdfPath).getBoundsInternal(); + bounds = rectangle.rect; + width = rectangle.width; + height = rectangle.height; + } else { + if (dictionary!.containsKey(PdfDictionaryProperties.quadPoints)) { + final IPdfPrimitive? mQuadPoints = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.quadPoints], + ); + if (mQuadPoints != null && mQuadPoints is PdfArray) { + for (int i = 0; i < (mQuadPoints.count / 8); i++) { + if (isLoadedAnnotation) { + final List quadPoints = List.filled( + mQuadPoints.count ~/ 2, + Offset.zero, + ); + int j = 0; + for (int k = 0; k < mQuadPoints.count;) { + final double x1 = + (mQuadPoints[k]! as PdfNumber).value!.toDouble(); + final double y1 = + (mQuadPoints[k + 1]! as PdfNumber).value!.toDouble(); + quadPoints[j] = Offset(x1, y1); + k = k + 2; + j++; + } + final PdfPath path = PdfPath(); + PdfPathHelper.getHelper(path).addLines(quadPoints); + rectangle = PdfPathHelper.getHelper(path).getBoundsInternal(); + height = rectangle.height; + width = rectangle.width; + } else { + x = + ((mQuadPoints[4 + (i * 8)]! as PdfNumber).value! - + (mQuadPoints[0 + (i * 8)]! as PdfNumber).value!) + .toDouble(); + y = + ((mQuadPoints[5 + (i * 8)]! as PdfNumber).value! - + (mQuadPoints[1 + (i * 8)]! as PdfNumber).value!) + .toDouble(); + height = sqrt((x * x) + (y * y)); + x = + ((mQuadPoints[6 + (i * 8)]! as PdfNumber).value! - + (mQuadPoints[4 + (i * 8)]! as PdfNumber).value!) + .toDouble(); + y = + ((mQuadPoints[7 + (i * 8)]! as PdfNumber).value! - + (mQuadPoints[5 + (i * 8)]! as PdfNumber).value!) + .toDouble(); + width = sqrt((x * x) + (y * y)); + bounds = Rect.fromLTWH(bounds.left, bounds.top, width, height); + } + } + } + } + } + final PdfTemplate template = PdfTemplate(width, height); + PdfAnnotationHelper.setMatrixToZeroRotation( + PdfTemplateHelper.getHelper(template).content, + ); + final PdfGraphics graphics = template.graphics!; + graphics.setTransparency(opacity, mode: PdfBlendMode.multiply); + if (boundsCollection.length > 1) { + for (int i = 0; i < boundsCollection.length; i++) { + if (textMarkupAnnotationType == + PdfTextMarkupAnnotationType.highlight) { + graphics.drawRectangle( + brush: PdfSolidBrush(color), + bounds: Rect.fromLTWH( + boundsCollection[i].left - rectangle!.x, + boundsCollection[i].top - rectangle.y, + boundsCollection[i].width, + boundsCollection[i].height, + ), + ); + } else if (textMarkupAnnotationType == + PdfTextMarkupAnnotationType.underline) { + graphics.drawLine( + PdfPen(color, width: boundsCollection[i].height * 0.05), + Offset( + boundsCollection[i].left - rectangle!.x, + (boundsCollection[i].top - rectangle.y) + + (boundsCollection[i].height - + ((boundsCollection[i].height / 2) / 3)), + ), + Offset( + boundsCollection[i].width + + (boundsCollection[i].left - rectangle.x), + (boundsCollection[i].top - rectangle.y) + + (boundsCollection[i].height - + ((boundsCollection[i].height / 2) / 3)), + ), + ); + } else if (textMarkupAnnotationType == + PdfTextMarkupAnnotationType.strikethrough) { + graphics.drawLine( + PdfPen(color, width: boundsCollection[i].height * 0.05), + Offset( + boundsCollection[i].left - rectangle!.x, + (boundsCollection[i].top - rectangle.y) + + (boundsCollection[i].height - + (boundsCollection[i].height / 2)), + ), + Offset( + boundsCollection[i].width + + (boundsCollection[i].left - rectangle.x), + (boundsCollection[i].top - rectangle.y) + + (boundsCollection[i].height - + (boundsCollection[i].height / 2)), + ), + ); + } else if (textMarkupAnnotationType == + PdfTextMarkupAnnotationType.squiggly) { + final PdfPen pdfPen = PdfPen( + color, + width: boundsCollection[i].height * 0.02, + ); + graphics.save(); + graphics.translateTransform( + boundsCollection[i].left - rectangle!.x, + boundsCollection[i].top - rectangle.y, + ); + graphics.setClip( + bounds: Rect.fromLTWH( + 0, + 0, + boundsCollection[i].width, + boundsCollection[i].height, + ), + ); + graphics.drawPath( + _drawSquiggly( + boundsCollection[i].width, + boundsCollection[i].height, + ), + pen: pdfPen, + ); + graphics.restore(); + } + } + } else { + if (textMarkupAnnotationType == PdfTextMarkupAnnotationType.highlight) { + graphics.drawRectangle( + brush: PdfSolidBrush(color), + bounds: Rect.fromLTWH(0, 0, width, height), + ); + } else if (textMarkupAnnotationType == + PdfTextMarkupAnnotationType.underline) { + graphics.drawLine( + PdfPen(color, width: height * 0.05), + Offset(0, height - ((height / 2) / 3)), + Offset(width, height - ((height / 2) / 3)), + ); + } else if (textMarkupAnnotationType == + PdfTextMarkupAnnotationType.strikethrough) { + graphics.drawLine( + PdfPen(color, width: height * 0.05), + Offset(0, height / 2), + Offset(width, height / 2), + ); + } else if (textMarkupAnnotationType == + PdfTextMarkupAnnotationType.squiggly) { + final PdfPen pdfPen = PdfPen(color, width: height * 0.02); + graphics.drawPath(_drawSquiggly(width, height), pen: pdfPen); + } + if (isLoadedAnnotation) { + dictionary![PdfDictionaryProperties.rect] = PdfArray.fromRectangle( + rectangle!, + ); + } + } + return template; + } + return null; + } + + PdfPath _drawSquiggly(double width, double height) { + if (width.toInt() % 2 != 0 || width.round() > width) { + width = width + 1; + } + final PdfPath path = PdfPath(); + final List mPathPoints = List.filled( + ((width / height) * 16).ceil(), + Offset.zero, + ); + final double length = width / (mPathPoints.length / 2); + final double location = (length + length) * 0.6; + double zigZag = location; + double x = 0; + for (int i = 0; i < mPathPoints.length; i++, x += length) { + mPathPoints[i] = Offset( + x, + ((height - location) + zigZag) - (height * 0.02), + ); + if (zigZag == 0) { + zigZag = location; + } else { + zigZag = 0; + } + } + PdfPathHelper.getHelper(path).addLines(mPathPoints); + return path; + } + + void _flattenAnnotation(PdfPage page, PdfTemplate? appearance) { + if (!isLoadedAnnotation) { + if (appearance != null) { + page.graphics.save(); + final Rect rectangle = calculateTemplateBounds( + bounds, + page, + appearance, + true, + ); + if (opacity < 1) { + page.graphics.setTransparency(opacity); + } + page.graphics.drawPdfTemplate( + appearance, + Offset(rectangle.left, rectangle.top), + rectangle.size, + ); + page.annotations.remove(textMarkupAnnotation); + page.graphics.restore(); + } + } else { + if (dictionary != null && + dictionary!.containsKey(PdfDictionaryProperties.ap) && + appearance == null) { + IPdfPrimitive? appearanceDictionary = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.ap], + ); + if (appearanceDictionary != null && + appearanceDictionary is PdfDictionary) { + appearanceDictionary = PdfCrossTable.dereference( + appearanceDictionary[PdfDictionaryProperties.n], + ); + if (appearanceDictionary != null && + appearanceDictionary is PdfStream) { + appearance = PdfTemplateHelper.fromPdfStream(appearanceDictionary); + final bool isNormalMatrix = validateTemplateMatrix( + appearanceDictionary, + ); + if (isNormalMatrix && + page.rotation != PdfPageRotateAngle.rotateAngle0) { + flattenAnnotationTemplate(appearance, isNormalMatrix); + } else if (isNormalMatrix && + isValidTemplateMatrix( + appearanceDictionary, + bounds.topLeft, + appearance, + )) { + flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } else { + setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } + } + } else if (!dictionary!.containsKey(PdfDictionaryProperties.ap) && + appearance == null) { + setAppearance = true; + appearance = _createAppearance(); + if (appearance != null) { + final bool isNormalMatrix = validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } else if (!dictionary!.containsKey(PdfDictionaryProperties.ap) && + appearance != null) { + final bool isNormalMatrix = validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + flattenAnnotationTemplate(appearance, isNormalMatrix); + } else if (dictionary!.containsKey(PdfDictionaryProperties.ap) && + appearance != null) { + final bool isNormalMatrix = validateTemplateMatrix( + PdfTemplateHelper.getHelper(appearance).content, + ); + flattenAnnotationTemplate(appearance, isNormalMatrix); + } + } + } + + PdfTextMarkupAnnotationType _obtainTextMarkupAnnotationType() { + final IPdfPrimitive? annotType = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.subtype], + ); + if (annotType != null && annotType is PdfName) { + final String aType = annotType.name.toString(); + return _getTextMarkupAnnotation(aType); + } + return PdfTextMarkupAnnotationType.highlight; + } + + /// internal method + @override + IPdfPrimitive? get element => dictionary; + @override + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_web_link.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_web_link.dart index 978ab2008..3354160ab 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_web_link.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_text_web_link.dart @@ -1,368 +1,368 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/fonts/pdf_string_format.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_border.dart'; -import 'pdf_uri_annotation.dart'; - -/// Represents the class for text web link annotation. -/// ``` dart -/// //Create a new Pdf document -/// PdfDocument document = PdfDocument(); -/// //Create and draw the web link in the PDF page -/// PdfTextWebLink( -/// url: 'www.google.co.in', -/// text: 'google', -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), -/// pen: PdfPens.brown, -/// format: PdfStringFormat( -/// alignment: PdfTextAlignment.center, -/// lineAlignment: PdfVerticalAlignment.middle)) -/// .draw(document.pages.add(), Offset(50, 40)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfTextWebLink extends PdfAnnotation { - // Constructor - /// Initializes a new instance of the [PdfTextWebLink] class. - /// ``` dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create and draw the web link in the PDF page - /// PdfTextWebLink( - /// url: 'www.google.co.in', - /// text: 'google', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// pen: PdfPens.brown, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle)) - /// .draw(document.pages.add(), Offset(50, 40)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfTextWebLink({ - required String url, - String? text, - PdfBrush? brush, - PdfFont? font, - PdfPen? pen, - PdfStringFormat? format, - }) { - _helper = PdfTextWebLinkHelper(this); - _initializeWebLink(text, font, pen, brush, format); - this.url = url; - } - - PdfTextWebLink._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String? annotText, - ) { - _helper = PdfTextWebLinkHelper._(this, dictionary, crossTable); - text = annotText != null && annotText.isNotEmpty ? annotText : ''; - } - - // fields - String? _url; - late PdfUriAnnotation _uriAnnotation; - late PdfTextWebLinkHelper _helper; - - /// Get or sets the font. - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create the web link in the PDF page - /// PdfTextWebLink textWebLink = PdfTextWebLink( - /// url: 'www.google.co.in', - /// text: 'google', - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// pen: PdfPens.brown, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle)); - /// //Gets or sets the font - /// textWebLink.font = PdfStandardFont(PdfFontFamily.timesRoman, 14); - /// //Draw the web link in the PDF page - /// textWebLink.draw(document.pages.add(), Offset(50, 40)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfFont? font; - - /// Get or sets the pen. - ///```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create the web link in the PDF page - /// PdfTextWebLink textWebLink = PdfTextWebLink( - /// url: 'www.google.co.in', - /// text: 'google', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle)); - /// //Gets or sets the pen - /// textWebLink.pen = PdfPens.brown; - /// //Draw the web link in the PDF page - /// textWebLink.draw(document.pages.add(), Offset(50, 40)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPen? pen; - - /// Get or sets the brush. - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create the web link in the PDF page - /// PdfTextWebLink textWebLink = PdfTextWebLink( - /// url: 'www.google.co.in', - /// text: 'google', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), - /// pen: PdfPens.brown, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle)); - /// //Gets or sets the brush - /// textWebLink.brush = PdfSolidBrush(PdfColor(0, 0, 0)); - /// //Draw the web link in the PDF page - /// textWebLink.draw(document.pages.add(), Offset(50, 40)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBrush? brush; - - /// Get or sets the stringFormat. - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create the web link in the PDF page - /// PdfTextWebLink textWebLink = PdfTextWebLink( - /// url: 'www.google.co.in', - /// text: 'google', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// pen: PdfPens.brown); - /// //Gets or sets the stringFormat - /// textWebLink.stringFormat = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle); - /// //Draw the web link in the PDF page - /// textWebLink.draw(document.pages.add(), Offset(50, 40)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfStringFormat? stringFormat; - - // properties - /// Gets or sets the Uri address. - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create the web link in the PDF page - /// PdfTextWebLink textWebLink = PdfTextWebLink( - /// url: 'www.google.co.in', - /// text: 'google', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// pen: PdfPens.brown, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle)); - /// //Sets the url - /// textWebLink.url = 'www.google.co.in'; - /// //Draw the web link in the PDF page - /// textWebLink.draw(document.pages.add(), Offset(50, 40)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String get url { - if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { - return _obtainUrl()!; - } else { - return _url!; - } - } - - set url(String value) { - if (value == '') { - throw ArgumentError.value('Url - string can not be empty'); - } - _url = value; - if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { - final PdfDictionary tempDictionary = - PdfAnnotationHelper.getHelper(this).dictionary!; - if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { - final PdfDictionary? dictionary = - PdfCrossTable.dereference(tempDictionary[PdfDictionaryProperties.a]) - as PdfDictionary?; - if (dictionary != null) { - dictionary.setString(PdfDictionaryProperties.uri, _url); - } - tempDictionary.modify(); - } - } - } - - // implementation - void _initializeWebLink( - String? annotText, - PdfFont? font, - PdfPen? pen, - PdfBrush? brush, - PdfStringFormat? format, - ) { - text = annotText != null && annotText.isNotEmpty ? annotText : ''; - if (font != null) { - this.font = font; - } - if (brush != null) { - this.brush = brush; - } - if (pen != null) { - this.pen = pen; - } - if (format != null) { - stringFormat = format; - } - } - - /// Draws a text web link on the PDF page. - /// ```dart - /// //Create a new Pdf document - /// PdfDocument document = PdfDocument(); - /// //Create the web link in the PDF page - /// PdfTextWebLink textWebLink = PdfTextWebLink( - /// url: 'www.google.co.in', - /// text: 'google', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// pen: PdfPens.brown, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle)); - /// //Draw the web link in the PDF page - /// textWebLink.draw(document.pages.add(), Offset(50, 40)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void draw(PdfPage page, Offset location) { - if (!PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { - final PdfFont pdfFont = - font != null ? font! : PdfStandardFont(PdfFontFamily.helvetica, 8); - final Size textSize = pdfFont.measureString(text); - final Rect rect = Rect.fromLTWH( - location.dx, - location.dy, - textSize.width, - textSize.height, - ); - _uriAnnotation = PdfUriAnnotation(bounds: rect, uri: url); - _uriAnnotation.border = PdfAnnotationBorder(0, 0, 0); - page.annotations.add(_uriAnnotation); - _drawInternal(page.graphics, rect, pdfFont); - } - } - - void _drawInternal(PdfGraphics graphics, Rect bounds, PdfFont pdfFont) { - graphics.drawString( - text, - pdfFont, - pen: pen, - brush: brush, - bounds: bounds, - format: stringFormat, - ); - } - - String? _obtainUrl() { - String? url = ''; - final PdfDictionary tempDictionary = - PdfAnnotationHelper.getHelper(this).dictionary!; - if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { - final PdfDictionary? dictionary = - PdfCrossTable.dereference(tempDictionary[PdfDictionaryProperties.a]) - as PdfDictionary?; - if (dictionary != null && - dictionary.containsKey(PdfDictionaryProperties.uri)) { - final PdfString? uriText = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.uri]) - as PdfString?; - if (uriText != null) { - url = uriText.value; - } - } - } - return url; - } -} - -/// [PdfTextWebLink] helper -class PdfTextWebLinkHelper extends PdfAnnotationHelper { - /// internal constructor - PdfTextWebLinkHelper(this.webLinkHelper) : super(webLinkHelper) { - initializeAnnotation(); - } - - /// internal constructor - PdfTextWebLinkHelper._( - this.webLinkHelper, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super(webLinkHelper) { - initializeExistingAnnotation(dictionary, crossTable); - } - - /// internal field - late PdfTextWebLink webLinkHelper; - - /// internal field - @override - IPdfPrimitive? element; - - /// internal method - static PdfTextWebLink load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - return PdfTextWebLink._(dictionary, crossTable, text); - } - - /// internal method - static PdfTextWebLinkHelper getHelper(PdfTextWebLink annotation) { - return annotation._helper; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/fonts/pdf_string_format.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_border.dart'; +import 'pdf_uri_annotation.dart'; + +/// Represents the class for text web link annotation. +/// ``` dart +/// //Create a new Pdf document +/// PdfDocument document = PdfDocument(); +/// //Create and draw the web link in the PDF page +/// PdfTextWebLink( +/// url: 'www.google.co.in', +/// text: 'google', +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), +/// pen: PdfPens.brown, +/// format: PdfStringFormat( +/// alignment: PdfTextAlignment.center, +/// lineAlignment: PdfVerticalAlignment.middle)) +/// .draw(document.pages.add(), Offset(50, 40)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfTextWebLink extends PdfAnnotation { + // Constructor + /// Initializes a new instance of the [PdfTextWebLink] class. + /// ``` dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create and draw the web link in the PDF page + /// PdfTextWebLink( + /// url: 'www.google.co.in', + /// text: 'google', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// pen: PdfPens.brown, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle)) + /// .draw(document.pages.add(), Offset(50, 40)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfTextWebLink({ + required String url, + String? text, + PdfBrush? brush, + PdfFont? font, + PdfPen? pen, + PdfStringFormat? format, + }) { + _helper = PdfTextWebLinkHelper(this); + _initializeWebLink(text, font, pen, brush, format); + this.url = url; + } + + PdfTextWebLink._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String? annotText, + ) { + _helper = PdfTextWebLinkHelper._(this, dictionary, crossTable); + text = annotText != null && annotText.isNotEmpty ? annotText : ''; + } + + // fields + String? _url; + late PdfUriAnnotation _uriAnnotation; + late PdfTextWebLinkHelper _helper; + + /// Get or sets the font. + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create the web link in the PDF page + /// PdfTextWebLink textWebLink = PdfTextWebLink( + /// url: 'www.google.co.in', + /// text: 'google', + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// pen: PdfPens.brown, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle)); + /// //Gets or sets the font + /// textWebLink.font = PdfStandardFont(PdfFontFamily.timesRoman, 14); + /// //Draw the web link in the PDF page + /// textWebLink.draw(document.pages.add(), Offset(50, 40)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfFont? font; + + /// Get or sets the pen. + ///```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create the web link in the PDF page + /// PdfTextWebLink textWebLink = PdfTextWebLink( + /// url: 'www.google.co.in', + /// text: 'google', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle)); + /// //Gets or sets the pen + /// textWebLink.pen = PdfPens.brown; + /// //Draw the web link in the PDF page + /// textWebLink.draw(document.pages.add(), Offset(50, 40)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPen? pen; + + /// Get or sets the brush. + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create the web link in the PDF page + /// PdfTextWebLink textWebLink = PdfTextWebLink( + /// url: 'www.google.co.in', + /// text: 'google', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), + /// pen: PdfPens.brown, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle)); + /// //Gets or sets the brush + /// textWebLink.brush = PdfSolidBrush(PdfColor(0, 0, 0)); + /// //Draw the web link in the PDF page + /// textWebLink.draw(document.pages.add(), Offset(50, 40)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBrush? brush; + + /// Get or sets the stringFormat. + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create the web link in the PDF page + /// PdfTextWebLink textWebLink = PdfTextWebLink( + /// url: 'www.google.co.in', + /// text: 'google', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// pen: PdfPens.brown); + /// //Gets or sets the stringFormat + /// textWebLink.stringFormat = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle); + /// //Draw the web link in the PDF page + /// textWebLink.draw(document.pages.add(), Offset(50, 40)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfStringFormat? stringFormat; + + // properties + /// Gets or sets the Uri address. + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create the web link in the PDF page + /// PdfTextWebLink textWebLink = PdfTextWebLink( + /// url: 'www.google.co.in', + /// text: 'google', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// pen: PdfPens.brown, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle)); + /// //Sets the url + /// textWebLink.url = 'www.google.co.in'; + /// //Draw the web link in the PDF page + /// textWebLink.draw(document.pages.add(), Offset(50, 40)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String get url { + if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { + return _obtainUrl()!; + } else { + return _url!; + } + } + + set url(String value) { + if (value == '') { + throw ArgumentError.value('Url - string can not be empty'); + } + _url = value; + if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { + final PdfDictionary tempDictionary = + PdfAnnotationHelper.getHelper(this).dictionary!; + if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { + final PdfDictionary? dictionary = + PdfCrossTable.dereference(tempDictionary[PdfDictionaryProperties.a]) + as PdfDictionary?; + if (dictionary != null) { + dictionary.setString(PdfDictionaryProperties.uri, _url); + } + tempDictionary.modify(); + } + } + } + + // implementation + void _initializeWebLink( + String? annotText, + PdfFont? font, + PdfPen? pen, + PdfBrush? brush, + PdfStringFormat? format, + ) { + text = annotText != null && annotText.isNotEmpty ? annotText : ''; + if (font != null) { + this.font = font; + } + if (brush != null) { + this.brush = brush; + } + if (pen != null) { + this.pen = pen; + } + if (format != null) { + stringFormat = format; + } + } + + /// Draws a text web link on the PDF page. + /// ```dart + /// //Create a new Pdf document + /// PdfDocument document = PdfDocument(); + /// //Create the web link in the PDF page + /// PdfTextWebLink textWebLink = PdfTextWebLink( + /// url: 'www.google.co.in', + /// text: 'google', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 14), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// pen: PdfPens.brown, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle)); + /// //Draw the web link in the PDF page + /// textWebLink.draw(document.pages.add(), Offset(50, 40)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void draw(PdfPage page, Offset location) { + if (!PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { + final PdfFont pdfFont = + font != null ? font! : PdfStandardFont(PdfFontFamily.helvetica, 8); + final Size textSize = pdfFont.measureString(text); + final Rect rect = Rect.fromLTWH( + location.dx, + location.dy, + textSize.width, + textSize.height, + ); + _uriAnnotation = PdfUriAnnotation(bounds: rect, uri: url); + _uriAnnotation.border = PdfAnnotationBorder(0, 0, 0); + page.annotations.add(_uriAnnotation); + _drawInternal(page.graphics, rect, pdfFont); + } + } + + void _drawInternal(PdfGraphics graphics, Rect bounds, PdfFont pdfFont) { + graphics.drawString( + text, + pdfFont, + pen: pen, + brush: brush, + bounds: bounds, + format: stringFormat, + ); + } + + String? _obtainUrl() { + String? url = ''; + final PdfDictionary tempDictionary = + PdfAnnotationHelper.getHelper(this).dictionary!; + if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { + final PdfDictionary? dictionary = + PdfCrossTable.dereference(tempDictionary[PdfDictionaryProperties.a]) + as PdfDictionary?; + if (dictionary != null && + dictionary.containsKey(PdfDictionaryProperties.uri)) { + final PdfString? uriText = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.uri]) + as PdfString?; + if (uriText != null) { + url = uriText.value; + } + } + } + return url; + } +} + +/// [PdfTextWebLink] helper +class PdfTextWebLinkHelper extends PdfAnnotationHelper { + /// internal constructor + PdfTextWebLinkHelper(this.webLinkHelper) : super(webLinkHelper) { + initializeAnnotation(); + } + + /// internal constructor + PdfTextWebLinkHelper._( + this.webLinkHelper, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super(webLinkHelper) { + initializeExistingAnnotation(dictionary, crossTable); + } + + /// internal field + late PdfTextWebLink webLinkHelper; + + /// internal field + @override + IPdfPrimitive? element; + + /// internal method + static PdfTextWebLink load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + return PdfTextWebLink._(dictionary, crossTable, text); + } + + /// internal method + static PdfTextWebLinkHelper getHelper(PdfTextWebLink annotation) { + return annotation._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_uri_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_uri_annotation.dart index 9b8d80576..937ee11f9 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_uri_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/pdf_uri_annotation.dart @@ -1,189 +1,189 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../actions/pdf_action.dart'; -import '../actions/pdf_uri_action.dart'; -import '../graphics/pdf_color.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_action_annotation.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_border.dart'; - -/// Represents the Uri annotation. -class PdfUriAnnotation extends PdfActionLinkAnnotation { - // constructor - /// Initializes a new instance of the - /// [PdfUriAnnotation] class with specified bounds and Uri. - PdfUriAnnotation({required Rect bounds, required String uri}) { - _helper = PdfUriAnnotationHelper(this, bounds); - this.uri = uri; - } - - PdfUriAnnotation._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - _helper = PdfUriAnnotationHelper._(this, dictionary, crossTable); - super.text = text; - } - - // fields - String _uri = ''; - late PdfUriAnnotationHelper _helper; - - // properties - /// Gets the Uri address. - String get uri { - if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { - return _getUriText()!; - } else { - return _uri; - } - } - - /// Sets the Uri address. - set uri(String value) { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); - final PdfDictionary tempDictionary = helper.dictionary!; - if (helper.isLoadedAnnotation) { - if (_uri != value) { - _uri = value; - if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { - final PdfDictionary? dictionary = - PdfCrossTable.dereference( - tempDictionary[PdfDictionaryProperties.a], - ) - as PdfDictionary?; - if (dictionary != null) { - dictionary.setString(PdfDictionaryProperties.uri, _uri); - dictionary.modify(); - } - } - } - } else { - _uri = value; - if (_helper._uriAction!.uri != value) { - _helper._uriAction!.uri = value; - if (helper.isLoadedAnnotation) { - PdfDictionary? dictionary = tempDictionary; - if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { - dictionary = - PdfCrossTable.dereference( - tempDictionary[PdfDictionaryProperties.a], - ) - as PdfDictionary?; - if (dictionary != null) { - dictionary.setString(PdfDictionaryProperties.uri, _uri); - } - tempDictionary.modify(); - } - } - } - } - } - - /// Gets annotation's border properties like width, horizontal radius etc. - PdfAnnotationBorder get border { - return _helper.border; - } - - /// Sets annotation's border properties like width, horizontal radius etc. - set border(PdfAnnotationBorder value) { - _helper.border = value; - } - - /// Gets the annotation color. - PdfColor get color => _helper.color; - - /// Sets the annotation color. - set color(PdfColor value) { - _helper.color = value; - } - - /// Gets the action. - @override - PdfAction? get action => super.action; - - /// Sets the action. - @override - set action(PdfAction? value) { - if (value != null) { - super.action = value; - _helper._uriAction!.next = value; - } - } - - String? _getUriText() { - String? uriText = ''; - final PdfDictionary tempDictionary = - PdfAnnotationHelper.getHelper(this).dictionary!; - if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { - final PdfDictionary? dictionary = - PdfCrossTable.dereference(tempDictionary[PdfDictionaryProperties.a]) - as PdfDictionary?; - if (dictionary != null && - dictionary.containsKey(PdfDictionaryProperties.uri)) { - final PdfString? tempText = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.uri]) - as PdfString?; - if (tempText != null) { - uriText = tempText.value; - } - } - } - return uriText; - } -} - -/// [PdfUriAnnotation] helper -class PdfUriAnnotationHelper extends PdfActionLinkAnnotationHelper { - /// internal constructor - PdfUriAnnotationHelper(this.uriAnnotation, Rect bounds) - : super(uriAnnotation, bounds) { - _uriAction ??= PdfUriAction(); - dictionary!.setProperty( - PdfName(PdfDictionaryProperties.subtype), - PdfName(PdfDictionaryProperties.link), - ); - final IPdfPrimitive? element = IPdfWrapper.getElement(_uriAction!); - if (element == null) { - IPdfWrapper.setElement( - _uriAction!, - PdfActionHelper.getHelper(_uriAction!).dictionary, - ); - } - dictionary!.setProperty(PdfName(PdfDictionaryProperties.a), element); - } - PdfUriAnnotationHelper._( - this.uriAnnotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super.load(uriAnnotation, dictionary, crossTable); - - /// internal field - late PdfUriAnnotation uriAnnotation; - PdfUriAction? _uriAction; - - /// internal field - @override - IPdfPrimitive? element; - - /// internal method - static PdfUriAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - String text, - ) { - return PdfUriAnnotation._(dictionary, crossTable, text); - } - - /// internal method - static PdfUriAnnotationHelper getHelper(PdfUriAnnotation annotation) { - return annotation._helper; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../actions/pdf_action.dart'; +import '../actions/pdf_uri_action.dart'; +import '../graphics/pdf_color.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_action_annotation.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_border.dart'; + +/// Represents the Uri annotation. +class PdfUriAnnotation extends PdfActionLinkAnnotation { + // constructor + /// Initializes a new instance of the + /// [PdfUriAnnotation] class with specified bounds and Uri. + PdfUriAnnotation({required Rect bounds, required String uri}) { + _helper = PdfUriAnnotationHelper(this, bounds); + this.uri = uri; + } + + PdfUriAnnotation._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + _helper = PdfUriAnnotationHelper._(this, dictionary, crossTable); + super.text = text; + } + + // fields + String _uri = ''; + late PdfUriAnnotationHelper _helper; + + // properties + /// Gets the Uri address. + String get uri { + if (PdfAnnotationHelper.getHelper(this).isLoadedAnnotation) { + return _getUriText()!; + } else { + return _uri; + } + } + + /// Sets the Uri address. + set uri(String value) { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(this); + final PdfDictionary tempDictionary = helper.dictionary!; + if (helper.isLoadedAnnotation) { + if (_uri != value) { + _uri = value; + if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { + final PdfDictionary? dictionary = + PdfCrossTable.dereference( + tempDictionary[PdfDictionaryProperties.a], + ) + as PdfDictionary?; + if (dictionary != null) { + dictionary.setString(PdfDictionaryProperties.uri, _uri); + dictionary.modify(); + } + } + } + } else { + _uri = value; + if (_helper._uriAction!.uri != value) { + _helper._uriAction!.uri = value; + if (helper.isLoadedAnnotation) { + PdfDictionary? dictionary = tempDictionary; + if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { + dictionary = + PdfCrossTable.dereference( + tempDictionary[PdfDictionaryProperties.a], + ) + as PdfDictionary?; + if (dictionary != null) { + dictionary.setString(PdfDictionaryProperties.uri, _uri); + } + tempDictionary.modify(); + } + } + } + } + } + + /// Gets annotation's border properties like width, horizontal radius etc. + PdfAnnotationBorder get border { + return _helper.border; + } + + /// Sets annotation's border properties like width, horizontal radius etc. + set border(PdfAnnotationBorder value) { + _helper.border = value; + } + + /// Gets the annotation color. + PdfColor get color => _helper.color; + + /// Sets the annotation color. + set color(PdfColor value) { + _helper.color = value; + } + + /// Gets the action. + @override + PdfAction? get action => super.action; + + /// Sets the action. + @override + set action(PdfAction? value) { + if (value != null) { + super.action = value; + _helper._uriAction!.next = value; + } + } + + String? _getUriText() { + String? uriText = ''; + final PdfDictionary tempDictionary = + PdfAnnotationHelper.getHelper(this).dictionary!; + if (tempDictionary.containsKey(PdfDictionaryProperties.a)) { + final PdfDictionary? dictionary = + PdfCrossTable.dereference(tempDictionary[PdfDictionaryProperties.a]) + as PdfDictionary?; + if (dictionary != null && + dictionary.containsKey(PdfDictionaryProperties.uri)) { + final PdfString? tempText = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.uri]) + as PdfString?; + if (tempText != null) { + uriText = tempText.value; + } + } + } + return uriText; + } +} + +/// [PdfUriAnnotation] helper +class PdfUriAnnotationHelper extends PdfActionLinkAnnotationHelper { + /// internal constructor + PdfUriAnnotationHelper(this.uriAnnotation, Rect bounds) + : super(uriAnnotation, bounds) { + _uriAction ??= PdfUriAction(); + dictionary!.setProperty( + PdfName(PdfDictionaryProperties.subtype), + PdfName(PdfDictionaryProperties.link), + ); + final IPdfPrimitive? element = IPdfWrapper.getElement(_uriAction!); + if (element == null) { + IPdfWrapper.setElement( + _uriAction!, + PdfActionHelper.getHelper(_uriAction!).dictionary, + ); + } + dictionary!.setProperty(PdfName(PdfDictionaryProperties.a), element); + } + PdfUriAnnotationHelper._( + this.uriAnnotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super.load(uriAnnotation, dictionary, crossTable); + + /// internal field + late PdfUriAnnotation uriAnnotation; + PdfUriAction? _uriAction; + + /// internal field + @override + IPdfPrimitive? element; + + /// internal method + static PdfUriAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + String text, + ) { + return PdfUriAnnotation._(dictionary, crossTable, text); + } + + /// internal method + static PdfUriAnnotationHelper getHelper(PdfUriAnnotation annotation) { + return annotation._helper; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_annotation.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_annotation.dart index 063f425ba..4c2d29203 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_annotation.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_annotation.dart @@ -1,286 +1,286 @@ -import '../actions/pdf_annotation_action.dart'; -import '../forms/pdf_field.dart'; -import '../general/pdf_default_appearance.dart'; -import '../graphics/enums.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'appearance/pdf_extended_appearance.dart'; -import 'enum.dart'; -import 'pdf_annotation.dart'; -import 'pdf_annotation_border.dart'; -import 'pdf_appearance.dart'; -import 'widget_appearance.dart'; - -/// Represents the widget annotation. -class WidgetAnnotation extends PdfAnnotation { - /// internal Constructor - WidgetAnnotation() : super() { - _helper = WidgetAnnotationHelper(this); - alignment = PdfTextAlignment.left; - _highlightMode = PdfHighlightMode.invert; - } - - WidgetAnnotation._(PdfDictionary dictionary, PdfCrossTable crossTable) { - _helper = WidgetAnnotationHelper._(this, dictionary, crossTable); - } - - PdfField? _parent; - PdfHighlightMode? _highlightMode; - String? _appearState; - PdfAnnotationActions? _actions; - late WidgetAnnotationHelper _helper; - - /// internal field - PdfTextAlignment? alignment; - - /// internal field - PdfAnnotationBorder? widgetBorder; - - //Properties - /// Gets the default appearance. - PdfDefaultAppearance get defaultAppearance { - return _helper.pdfDefaultAppearance ??= PdfDefaultAppearance(); - } - - /// Sets the parent. - // ignore: avoid_setters_without_getters - set parent(PdfField? value) { - if (_parent != value) { - _parent = value; - _parent != null - ? PdfAnnotationHelper.getHelper(this).dictionary!.setProperty( - PdfDictionaryProperties.parent, - PdfReferenceHolder(_parent), - ) - : PdfAnnotationHelper.getHelper( - this, - ).dictionary!.remove(PdfDictionaryProperties.parent); - } - } - - /// Gets and sets the text alignment. - PdfTextAlignment? get textAlignment => alignment; - set textAlignment(PdfTextAlignment? value) { - if (alignment != value) { - alignment = value; - PdfAnnotationHelper.getHelper(this).dictionary!.setProperty( - PdfDictionaryProperties.q, - PdfNumber(alignment!.index), - ); - } - } - - /// Gets or sets the highlighting mode. - PdfHighlightMode? get highlightMode => - PdfAnnotationHelper.getHelper(this).isLoadedAnnotation - ? _helper._obtainHighlightMode() - : _highlightMode; - set highlightMode(PdfHighlightMode? value) { - _highlightMode = value; - PdfAnnotationHelper.getHelper(this).dictionary!.setName( - PdfName(PdfDictionaryProperties.h), - _helper.highlightModeToString(_highlightMode), - ); - } - - /// internal property - PdfExtendedAppearance? get extendedAppearance { - _helper.extendedAppearance ??= PdfExtendedAppearance(); - return _helper.extendedAppearance; - } - - set extendedAppearance(PdfExtendedAppearance? value) { - _helper.extendedAppearance = value; - } - - /// internal property - // ignore: avoid_setters_without_getters - set appearanceState(String value) { - if (_appearState != value) { - _appearState = value; - PdfAnnotationHelper.getHelper(this).dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - _appearState, - ); - } - } - - /// internal property - PdfAnnotationActions? get actions { - if (_actions == null) { - _actions = PdfAnnotationActions(); - PdfAnnotationHelper.getHelper( - this, - ).dictionary!.setProperty(PdfDictionaryProperties.aa, _actions); - } - return _actions; - } - - set actions(PdfAnnotationActions? value) { - if (value != null) { - _actions = value; - PdfAnnotationHelper.getHelper( - this, - ).dictionary!.setProperty(PdfDictionaryProperties.aa, _actions); - } - } -} - -/// [WidgetAnnotation] helper -class WidgetAnnotationHelper extends PdfAnnotationHelper { - /// internal constructor - WidgetAnnotationHelper(this.widgetAnnotation) : super(widgetAnnotation) { - initializeAnnotation(); - dictionary!.setNumber(PdfDictionaryProperties.f, 4); //Sets print. - dictionary!.setProperty( - PdfDictionaryProperties.subtype, - PdfName(PdfDictionaryProperties.widget), - ); - widgetAnnotation.widgetBorder ??= - PdfAnnotationBorderHelper.getWidgetBorder(); - dictionary!.setProperty( - PdfDictionaryProperties.bs, - widgetAnnotation.widgetBorder, - ); - widgetAppearance = WidgetAppearance(); - } - WidgetAnnotationHelper._( - this.widgetAnnotation, - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) : super(widgetAnnotation) { - initializeExistingAnnotation(dictionary, crossTable); - } - - /// internal field - WidgetAnnotation widgetAnnotation; - - /// internal field - PdfExtendedAppearance? extendedAppearance; - - /// internal field - PdfDefaultAppearance? pdfDefaultAppearance; - - /// internal field - WidgetAppearance? widgetAppearance; - - /// internal event - SavePdfPrimitiveCallback? beginSave; - - /// internal method - static WidgetAnnotation load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return WidgetAnnotation._(dictionary, crossTable); - } - - /// internal method - static WidgetAnnotationHelper getHelper(WidgetAnnotation annotation) { - return annotation._helper; - } - - /// internal method - void save() { - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(base); - final PdfDocument? document = - PdfPageHelper.getHelper(helper.page!).document; - if (helper.appearance == null && - document != null && - (PdfDocumentHelper.getHelper(document).conformanceLevel == - PdfConformanceLevel.a1b || - PdfDocumentHelper.getHelper(document).conformanceLevel == - PdfConformanceLevel.a2b || - PdfDocumentHelper.getHelper(document).conformanceLevel == - PdfConformanceLevel.a3b)) { - throw ArgumentError( - "The appearance dictionary doesn't contain an entry in the conformance PDF.", - ); - } - helper.saveAnnotation(); - _onBeginSave(); - final PdfDictionary dictionary = helper.dictionary!; - if (extendedAppearance != null) { - dictionary.setProperty(PdfDictionaryProperties.ap, extendedAppearance); - dictionary.setProperty(PdfDictionaryProperties.mk, widgetAppearance); - } else { - dictionary.setProperty(PdfDictionaryProperties.ap, null); - final PdfAppearance? tempAppearance = helper.appearance; - dictionary.setProperty( - PdfDictionaryProperties.ap, - tempAppearance != null && - PdfAppearanceHelper.getHelper(tempAppearance).templateNormal != - null - ? tempAppearance - : null, - ); - if (widgetAppearance != null && widgetAppearance!.dictionary!.count > 0) { - dictionary.setProperty(PdfDictionaryProperties.mk, widgetAppearance); - } - dictionary.setProperty(PdfDictionaryProperties.usageApplication, null); - } - if (pdfDefaultAppearance != null) { - dictionary.setProperty( - PdfDictionaryProperties.da, - PdfString(pdfDefaultAppearance!.getString()), - ); - } - } - - /// internal method - String highlightModeToString(PdfHighlightMode? highlightingMode) { - switch (highlightingMode) { - case PdfHighlightMode.noHighlighting: - return 'N'; - case PdfHighlightMode.outline: - return 'O'; - case PdfHighlightMode.push: - return 'P'; - // ignore: no_default_cases - default: - return 'I'; - } - } - - void _onBeginSave({SavePdfPrimitiveArgs? args}) { - if (beginSave != null) { - beginSave!(base, args); - } - } - - PdfHighlightMode _obtainHighlightMode() { - PdfHighlightMode mode = PdfHighlightMode.noHighlighting; - if (PdfAnnotationHelper.getHelper( - base, - ).dictionary!.containsKey(PdfDictionaryProperties.h)) { - final PdfName name = - PdfAnnotationHelper.getHelper( - base, - ).dictionary![PdfDictionaryProperties.h]! - as PdfName; - switch (name.name) { - case 'I': - mode = PdfHighlightMode.invert; - break; - case 'N': - mode = PdfHighlightMode.noHighlighting; - break; - case 'O': - mode = PdfHighlightMode.outline; - break; - case 'P': - mode = PdfHighlightMode.push; - break; - } - } - return mode; - } -} +import '../actions/pdf_annotation_action.dart'; +import '../forms/pdf_field.dart'; +import '../general/pdf_default_appearance.dart'; +import '../graphics/enums.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'appearance/pdf_extended_appearance.dart'; +import 'enum.dart'; +import 'pdf_annotation.dart'; +import 'pdf_annotation_border.dart'; +import 'pdf_appearance.dart'; +import 'widget_appearance.dart'; + +/// Represents the widget annotation. +class WidgetAnnotation extends PdfAnnotation { + /// internal Constructor + WidgetAnnotation() : super() { + _helper = WidgetAnnotationHelper(this); + alignment = PdfTextAlignment.left; + _highlightMode = PdfHighlightMode.invert; + } + + WidgetAnnotation._(PdfDictionary dictionary, PdfCrossTable crossTable) { + _helper = WidgetAnnotationHelper._(this, dictionary, crossTable); + } + + PdfField? _parent; + PdfHighlightMode? _highlightMode; + String? _appearState; + PdfAnnotationActions? _actions; + late WidgetAnnotationHelper _helper; + + /// internal field + PdfTextAlignment? alignment; + + /// internal field + PdfAnnotationBorder? widgetBorder; + + //Properties + /// Gets the default appearance. + PdfDefaultAppearance get defaultAppearance { + return _helper.pdfDefaultAppearance ??= PdfDefaultAppearance(); + } + + /// Sets the parent. + // ignore: avoid_setters_without_getters + set parent(PdfField? value) { + if (_parent != value) { + _parent = value; + _parent != null + ? PdfAnnotationHelper.getHelper(this).dictionary!.setProperty( + PdfDictionaryProperties.parent, + PdfReferenceHolder(_parent), + ) + : PdfAnnotationHelper.getHelper( + this, + ).dictionary!.remove(PdfDictionaryProperties.parent); + } + } + + /// Gets and sets the text alignment. + PdfTextAlignment? get textAlignment => alignment; + set textAlignment(PdfTextAlignment? value) { + if (alignment != value) { + alignment = value; + PdfAnnotationHelper.getHelper(this).dictionary!.setProperty( + PdfDictionaryProperties.q, + PdfNumber(alignment!.index), + ); + } + } + + /// Gets or sets the highlighting mode. + PdfHighlightMode? get highlightMode => + PdfAnnotationHelper.getHelper(this).isLoadedAnnotation + ? _helper._obtainHighlightMode() + : _highlightMode; + set highlightMode(PdfHighlightMode? value) { + _highlightMode = value; + PdfAnnotationHelper.getHelper(this).dictionary!.setName( + PdfName(PdfDictionaryProperties.h), + _helper.highlightModeToString(_highlightMode), + ); + } + + /// internal property + PdfExtendedAppearance? get extendedAppearance { + _helper.extendedAppearance ??= PdfExtendedAppearance(); + return _helper.extendedAppearance; + } + + set extendedAppearance(PdfExtendedAppearance? value) { + _helper.extendedAppearance = value; + } + + /// internal property + // ignore: avoid_setters_without_getters + set appearanceState(String value) { + if (_appearState != value) { + _appearState = value; + PdfAnnotationHelper.getHelper(this).dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + _appearState, + ); + } + } + + /// internal property + PdfAnnotationActions? get actions { + if (_actions == null) { + _actions = PdfAnnotationActions(); + PdfAnnotationHelper.getHelper( + this, + ).dictionary!.setProperty(PdfDictionaryProperties.aa, _actions); + } + return _actions; + } + + set actions(PdfAnnotationActions? value) { + if (value != null) { + _actions = value; + PdfAnnotationHelper.getHelper( + this, + ).dictionary!.setProperty(PdfDictionaryProperties.aa, _actions); + } + } +} + +/// [WidgetAnnotation] helper +class WidgetAnnotationHelper extends PdfAnnotationHelper { + /// internal constructor + WidgetAnnotationHelper(this.widgetAnnotation) : super(widgetAnnotation) { + initializeAnnotation(); + dictionary!.setNumber(PdfDictionaryProperties.f, 4); //Sets print. + dictionary!.setProperty( + PdfDictionaryProperties.subtype, + PdfName(PdfDictionaryProperties.widget), + ); + widgetAnnotation.widgetBorder ??= + PdfAnnotationBorderHelper.getWidgetBorder(); + dictionary!.setProperty( + PdfDictionaryProperties.bs, + widgetAnnotation.widgetBorder, + ); + widgetAppearance = WidgetAppearance(); + } + WidgetAnnotationHelper._( + this.widgetAnnotation, + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) : super(widgetAnnotation) { + initializeExistingAnnotation(dictionary, crossTable); + } + + /// internal field + WidgetAnnotation widgetAnnotation; + + /// internal field + PdfExtendedAppearance? extendedAppearance; + + /// internal field + PdfDefaultAppearance? pdfDefaultAppearance; + + /// internal field + WidgetAppearance? widgetAppearance; + + /// internal event + SavePdfPrimitiveCallback? beginSave; + + /// internal method + static WidgetAnnotation load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return WidgetAnnotation._(dictionary, crossTable); + } + + /// internal method + static WidgetAnnotationHelper getHelper(WidgetAnnotation annotation) { + return annotation._helper; + } + + /// internal method + void save() { + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper(base); + final PdfDocument? document = + PdfPageHelper.getHelper(helper.page!).document; + if (helper.appearance == null && + document != null && + (PdfDocumentHelper.getHelper(document).conformanceLevel == + PdfConformanceLevel.a1b || + PdfDocumentHelper.getHelper(document).conformanceLevel == + PdfConformanceLevel.a2b || + PdfDocumentHelper.getHelper(document).conformanceLevel == + PdfConformanceLevel.a3b)) { + throw ArgumentError( + "The appearance dictionary doesn't contain an entry in the conformance PDF.", + ); + } + helper.saveAnnotation(); + _onBeginSave(); + final PdfDictionary dictionary = helper.dictionary!; + if (extendedAppearance != null) { + dictionary.setProperty(PdfDictionaryProperties.ap, extendedAppearance); + dictionary.setProperty(PdfDictionaryProperties.mk, widgetAppearance); + } else { + dictionary.setProperty(PdfDictionaryProperties.ap, null); + final PdfAppearance? tempAppearance = helper.appearance; + dictionary.setProperty( + PdfDictionaryProperties.ap, + tempAppearance != null && + PdfAppearanceHelper.getHelper(tempAppearance).templateNormal != + null + ? tempAppearance + : null, + ); + if (widgetAppearance != null && widgetAppearance!.dictionary!.count > 0) { + dictionary.setProperty(PdfDictionaryProperties.mk, widgetAppearance); + } + dictionary.setProperty(PdfDictionaryProperties.usageApplication, null); + } + if (pdfDefaultAppearance != null) { + dictionary.setProperty( + PdfDictionaryProperties.da, + PdfString(pdfDefaultAppearance!.getString()), + ); + } + } + + /// internal method + String highlightModeToString(PdfHighlightMode? highlightingMode) { + switch (highlightingMode) { + case PdfHighlightMode.noHighlighting: + return 'N'; + case PdfHighlightMode.outline: + return 'O'; + case PdfHighlightMode.push: + return 'P'; + // ignore: no_default_cases + default: + return 'I'; + } + } + + void _onBeginSave({SavePdfPrimitiveArgs? args}) { + if (beginSave != null) { + beginSave!(base, args); + } + } + + PdfHighlightMode _obtainHighlightMode() { + PdfHighlightMode mode = PdfHighlightMode.noHighlighting; + if (PdfAnnotationHelper.getHelper( + base, + ).dictionary!.containsKey(PdfDictionaryProperties.h)) { + final PdfName name = + PdfAnnotationHelper.getHelper( + base, + ).dictionary![PdfDictionaryProperties.h]! + as PdfName; + switch (name.name) { + case 'I': + mode = PdfHighlightMode.invert; + break; + case 'N': + mode = PdfHighlightMode.noHighlighting; + break; + case 'O': + mode = PdfHighlightMode.outline; + break; + case 'P': + mode = PdfHighlightMode.push; + break; + } + } + return mode; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_appearance.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_appearance.dart index 6c0bb474e..b52bb730d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_appearance.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/widget_appearance.dart @@ -1,76 +1,76 @@ -import '../../interfaces/pdf_interface.dart'; -import '../graphics/pdf_color.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; - -/// The Syncfusion.Pdf.Interactive namespace contains classes used to create interactive elements. -class WidgetAppearance implements IPdfWrapper { - /// internal Constructor - WidgetAppearance() : super() { - dictionary!.setProperty( - PdfDictionaryProperties.bc, - PdfColorHelper.toArray(_borderColor), - ); - } - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - PdfColor _borderColor = PdfColor(0, 0, 0); - PdfColor _backColor = PdfColor.empty; - String? _normalCaption = ''; - - //Overrides - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - //Properties - /// Gets or sets the color of the border. - PdfColor get borderColor => _borderColor; - set borderColor(PdfColor value) { - if (_borderColor != value) { - _borderColor = value; - PdfColorHelper.getHelper(value).alpha == 0 - ? dictionary!.setProperty( - PdfDictionaryProperties.bc, - PdfArray([]), - ) - : dictionary!.setProperty( - PdfDictionaryProperties.bc, - PdfColorHelper.toArray(_borderColor), - ); - } - } - - /// Gets or sets the color of the background. - PdfColor get backColor => _backColor; - set backColor(PdfColor value) { - if (_backColor != value) { - _backColor = value; - if (PdfColorHelper.getHelper(_backColor).alpha == 0) { - dictionary!.setProperty( - PdfDictionaryProperties.bc, - PdfArray([0, 0, 0]), - ); - dictionary!.remove(PdfDictionaryProperties.bg); - } else { - dictionary!.setProperty( - PdfDictionaryProperties.bg, - PdfColorHelper.toArray(_backColor), - ); - } - } - } - - /// internal property - String? get normalCaption => _normalCaption; - set normalCaption(String? value) { - if (_normalCaption != value) { - _normalCaption = value; - dictionary!.setString(PdfDictionaryProperties.ca, _normalCaption); - } - } -} +import '../../interfaces/pdf_interface.dart'; +import '../graphics/pdf_color.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; + +/// The Syncfusion.Pdf.Interactive namespace contains classes used to create interactive elements. +class WidgetAppearance implements IPdfWrapper { + /// internal Constructor + WidgetAppearance() : super() { + dictionary!.setProperty( + PdfDictionaryProperties.bc, + PdfColorHelper.toArray(_borderColor), + ); + } + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + PdfColor _borderColor = PdfColor(0, 0, 0); + PdfColor _backColor = PdfColor.empty; + String? _normalCaption = ''; + + //Overrides + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + //Properties + /// Gets or sets the color of the border. + PdfColor get borderColor => _borderColor; + set borderColor(PdfColor value) { + if (_borderColor != value) { + _borderColor = value; + PdfColorHelper.getHelper(value).alpha == 0 + ? dictionary!.setProperty( + PdfDictionaryProperties.bc, + PdfArray([]), + ) + : dictionary!.setProperty( + PdfDictionaryProperties.bc, + PdfColorHelper.toArray(_borderColor), + ); + } + } + + /// Gets or sets the color of the background. + PdfColor get backColor => _backColor; + set backColor(PdfColor value) { + if (_backColor != value) { + _backColor = value; + if (PdfColorHelper.getHelper(_backColor).alpha == 0) { + dictionary!.setProperty( + PdfDictionaryProperties.bc, + PdfArray([0, 0, 0]), + ); + dictionary!.remove(PdfDictionaryProperties.bg); + } else { + dictionary!.setProperty( + PdfDictionaryProperties.bg, + PdfColorHelper.toArray(_backColor), + ); + } + } + } + + /// internal property + String? get normalCaption => _normalCaption; + set normalCaption(String? value) { + if (_normalCaption != value) { + _normalCaption = value; + dictionary!.setString(PdfDictionaryProperties.ca, _normalCaption); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/xfdf_parser.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/xfdf_parser.dart index b5201aaf1..90dba0191 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/xfdf_parser.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/annotations/xfdf_parser.dart @@ -1,1570 +1,1570 @@ -import 'dart:convert'; -import 'dart:ui'; - -import 'package:convert/convert.dart'; -import 'package:xml/xml.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../forms/pdf_xfdf_document.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/images/pdf_bitmap.dart'; -import '../graphics/pdf_transformation_matrix.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'json_parser.dart'; -import 'pdf_annotation.dart'; - -/// The class provides methods and properties to handle the loaded annotations from the existing PDF document for Xfdf export and import. -class XfdfParser { - //Consructor - /// Initializes a new instance of the [XfdfParser] class. - XfdfParser(List data, PdfDocument document) { - _document = document; - final String xmlString = utf8.decode(data); - _xmlDocument = XmlDocument.parse(xmlString); - if (_xmlDocument.rootElement.localName.toLowerCase() != 'xfdf') { - throw ArgumentError.value( - _xmlDocument.rootElement.localName, - 'xmlString', - 'Invalid XFDF data', - ); - } - } - - //Fields - late PdfDocument _document; - late XmlDocument _xmlDocument; - Map? _groupReferences; - List? _groupHolders; - - //Implementation. - /// internal method. - void parseAndImportAnnotationData() { - for (final XmlNode node - in _xmlDocument.rootElement.firstElementChild!.children) { - if (node is XmlElement) { - _parseAnnotationData(node); - } - } - } - - void _parseAnnotationData(XmlElement element) { - if (element.attributes.isNotEmpty) { - final String? pageIndexString = element.getAttribute('page'); - if (pageIndexString != null && !isNullOrEmpty(pageIndexString)) { - final int pageIndex = int.parse(pageIndexString); - if (pageIndex >= 0 && pageIndex < _document.pages.count) { - PdfPageHelper.getHelper(_document.pages[pageIndex]).importAnnotation = - true; - final PdfDictionary annotationDictionary = _getAnnotation( - element, - pageIndex, - ); - if (annotationDictionary.count > 0) { - final PdfReferenceHolder holder = PdfReferenceHolder( - annotationDictionary, - ); - if (annotationDictionary.containsKey('NM') || - annotationDictionary.containsKey(PdfDictionaryProperties.irt)) { - _addReferenceToGroup(holder, annotationDictionary); - } - final PdfDictionary? pageDictionary = - PdfPageHelper.getHelper(_document.pages[pageIndex]).dictionary; - if (pageDictionary != null) { - if (!pageDictionary.containsKey(PdfDictionaryProperties.annots)) { - pageDictionary[PdfDictionaryProperties.annots] = PdfArray(); - } - final IPdfPrimitive? annots = PdfCrossTable.dereference( - pageDictionary[PdfDictionaryProperties.annots], - ); - if (annots != null && annots is PdfArray) { - annots.elements.add(holder); - _handlePopUp(annots, holder, annotationDictionary); - annots.changed = true; - } - } - } - } - } - } - } - - void _handlePopUp( - PdfArray annots, - PdfReferenceHolder holder, - PdfDictionary annotDictionary, - ) { - if (annotDictionary.containsKey(PdfDictionaryProperties.popup)) { - final IPdfPrimitive? popup = PdfCrossTable.dereference( - annotDictionary[PdfDictionaryProperties.popup], - ); - if (popup != null && popup is PdfDictionary) { - popup.setProperty(PdfDictionaryProperties.parent, holder); - annots.add(popup); - } - } - } - - PdfDictionary _getAnnotation(XmlElement element, int pageIndex) { - final PdfDictionary annotationDictionary = PdfDictionary(); - annotationDictionary.setName( - PdfName(PdfDictionaryProperties.name), - PdfDictionaryProperties.annot, - ); - bool isValidType = true; - if (!isNullOrEmpty(element.localName)) { - switch (element.localName.toLowerCase()) { - case 'line': - annotationDictionary.setName( - PdfName(PdfDictionaryProperties.subtype), - PdfDictionaryProperties.line, - ); - final String? start = element.getAttribute('start'); - final String? end = element.getAttribute('end'); - if (start != null && end != null) { - final List linePoints = []; - _addLinePoints(linePoints, start); - _addLinePoints(linePoints, end); - if (linePoints.length == 4) { - annotationDictionary.setProperty( - PdfDictionaryProperties.l, - PdfArray(linePoints), - ); - } - linePoints.clear(); - } - _addLineEndStyle(element, annotationDictionary); - break; - case 'circle': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.circle, - ); - break; - case 'square': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.square, - ); - break; - case 'polyline': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'PolyLine', - ); - _addLineEndStyle(element, annotationDictionary); - break; - case 'polygon': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.polygon, - ); - _addLineEndStyle(element, annotationDictionary); - break; - case 'ink': - annotationDictionary.setName(PdfDictionaryProperties.subtype, 'Ink'); - break; - case 'popup': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.popup, - ); - break; - case 'text': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.text, - ); - break; - case 'freetext': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'FreeText', - ); - _addLineEndStyle(element, annotationDictionary); - break; - case 'stamp': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'Stamp', - ); - break; - case 'highlight': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.highlight, - ); - break; - case 'squiggly': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.squiggly, - ); - break; - case 'underline': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.underline, - ); - break; - case 'strikeout': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - PdfDictionaryProperties.strikeOut, - ); - break; - case 'fileattachment': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'FileAttachment', - ); - break; - case 'sound': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'Sound', - ); - break; - case 'caret': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'Caret', - ); - break; - case 'redact': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'Redact', - ); - break; - case 'watermark': - annotationDictionary.setName( - PdfDictionaryProperties.subtype, - 'Watermark', - ); - break; - default: - isValidType = false; - break; - } - if (isValidType) { - _addAnnotationData(annotationDictionary, element, pageIndex); - } - } - return annotationDictionary; - } - - void _addAnnotationData( - PdfDictionary annotDictionary, - XmlElement element, - int pageIndex, - ) { - _addBorderStyle(annotDictionary, element); - _applyAttributeValues(annotDictionary, element); - _parseInnerElements(annotDictionary, element, pageIndex); - _addMeasureDictionary(annotDictionary, element); - } - - void _addBorderStyle(PdfDictionary annotDictionary, XmlElement element) { - if (element.attributes.isNotEmpty) { - final PdfDictionary borderEffectDictionary = PdfDictionary(); - final PdfDictionary borderStyleDictionary = PdfDictionary(); - String? attribute = element.getAttribute('width'); - if (!isNullOrEmpty(attribute)) { - borderStyleDictionary.setNumber( - PdfDictionaryProperties.w, - double.parse(attribute!), - ); - } - bool isBasicStyle = true; - attribute = element.getAttribute('style'); - if (!isNullOrEmpty(attribute)) { - String style = ''; - switch (attribute) { - case 'dash': - style = PdfDictionaryProperties.d; - break; - case 'solid': - style = PdfDictionaryProperties.s; - break; - case 'bevelled': - style = 'B'; - break; - case 'inset': - style = PdfDictionaryProperties.i; - break; - case 'underline': - style = PdfDictionaryProperties.u; - break; - case 'cloudy': - style = PdfDictionaryProperties.c; - isBasicStyle = false; - break; - } - if (!isNullOrEmpty(style)) { - (isBasicStyle ? borderStyleDictionary : borderEffectDictionary) - .setName(PdfDictionaryProperties.s, style); - attribute = element.getAttribute('intensity'); - if (!isBasicStyle && !isNullOrEmpty(attribute)) { - borderEffectDictionary.setNumber( - PdfDictionaryProperties.i, - double.parse(attribute!), - ); - } else { - attribute = element.getAttribute('dashes'); - if (!isNullOrEmpty(attribute)) { - final List dashPoints = _obtainFloatPoints(attribute!); - if (dashPoints.isNotEmpty) { - borderStyleDictionary.setProperty( - PdfDictionaryProperties.d, - PdfArray(dashPoints), - ); - } - } - } - } - } - if (borderEffectDictionary.count > 0) { - annotDictionary.setProperty( - PdfDictionaryProperties.be, - PdfReferenceHolder(borderEffectDictionary), - ); - } else { - borderEffectDictionary.clear(); - borderEffectDictionary.isSaving = false; - } - if (borderStyleDictionary.count > 0) { - borderStyleDictionary.setProperty( - PdfDictionaryProperties.type, - PdfName(PdfDictionaryProperties.border), - ); - annotDictionary.setProperty( - PdfDictionaryProperties.bs, - PdfReferenceHolder(borderStyleDictionary), - ); - } else { - borderStyleDictionary.clear(); - borderStyleDictionary.isSaving = false; - } - } - } - - List _obtainFloatPoints(String value) { - final List result = []; - if (!isNullOrEmpty(value)) { - final List pointsArray = value.split(','); - for (final String pointString in pointsArray) { - final double? point = double.tryParse(pointString); - if (point != null) { - result.add(point); - } - } - } - return result; - } - - void _addLinePoints(List linePoints, String value) { - if (!isNullOrEmpty(value) && value.contains(',')) { - final List pointsArray = value.split(','); - for (final String pointString in pointsArray) { - final double? point = double.tryParse(pointString); - if (point != null) { - linePoints.add(point); - } - } - } - } - - void _applyAttributeValues( - PdfDictionary annotDictionary, - XmlElement element, - ) { - for (final XmlAttribute attribute in element.attributes) { - final String value = attribute.value; - final XmlName name = attribute.name; - switch (name.local.toLowerCase()) { - case 'page': - case 'start': - case 'end': - case 'width': - case 'head': - case 'tail': - case 'style': - case 'intensity': - case 'itex': - break; - case 'state': - _addString(annotDictionary, 'State', value); - break; - case 'statemodel': - _addString(annotDictionary, 'StateModel', value); - break; - case 'replytype': - if (value == 'group') { - annotDictionary.setName('RT', 'Group'); - } - break; - case 'inreplyto': - _addString(annotDictionary, PdfDictionaryProperties.irt, value); - break; - case 'rect': - final List points = _obtainFloatPoints(value); - if (points.isNotEmpty && points.length == 4) { - annotDictionary.setProperty( - PdfDictionaryProperties.rect, - PdfArray(points), - ); - } - break; - case 'color': - if (!isNullOrEmpty(value)) { - final PdfArray? colorArray = _getColorArray(value); - if (colorArray != null) { - annotDictionary.setProperty( - PdfDictionaryProperties.c, - colorArray, - ); - } - } - break; - case 'interior-color': - if (!isNullOrEmpty(value)) { - final PdfArray? colorArray = _getColorArray(value); - if (colorArray != null) { - annotDictionary.setProperty( - PdfDictionaryProperties.ic, - colorArray, - ); - } - } - break; - case 'date': - _addString(annotDictionary, PdfDictionaryProperties.m, value); - break; - case 'creationdate': - _addString( - annotDictionary, - PdfDictionaryProperties.creationDate, - value, - ); - break; - case 'name': - _addString(annotDictionary, 'NM', value); - break; - case 'icon': - if (!isNullOrEmpty(value)) { - annotDictionary.setName(PdfDictionaryProperties.name, value); - } - break; - case 'subject': - _addString( - annotDictionary, - PdfDictionaryProperties.subj, - _getFormattedString(value), - ); - break; - case 'title': - _addString( - annotDictionary, - PdfDictionaryProperties.t, - _getFormattedString(value), - ); - break; - case 'rotation': - _addInt(annotDictionary, PdfDictionaryProperties.rotate, value); - break; - case 'justification': - _addInt(annotDictionary, PdfDictionaryProperties.q, value); - break; - case 'fringe': - _addFloatPoints( - annotDictionary, - _obtainFloatPoints(value), - PdfDictionaryProperties.rd, - ); - break; - case 'it': - if (!isNullOrEmpty(value)) { - annotDictionary.setName(PdfDictionaryProperties.it, value); - } - break; - case 'leaderlength': - _addFloat(annotDictionary, PdfDictionaryProperties.ll, value); - break; - case 'leaderextend': - if (!isNullOrEmpty(value)) { - final double? leaderExtend = double.tryParse(value); - if (leaderExtend != null) { - annotDictionary.setNumber( - PdfDictionaryProperties.lle, - leaderExtend, - ); - } - } - break; - case 'caption': - if (!isNullOrEmpty(value)) { - annotDictionary.setBoolean( - PdfDictionaryProperties.cap, - value.toLowerCase() == 'yes', - ); - } - break; - case 'caption-style': - if (!isNullOrEmpty(value)) { - annotDictionary.setName(PdfDictionaryProperties.cp, value); - } - break; - case 'callout': - _addFloatPoints(annotDictionary, _obtainFloatPoints(value), 'CL'); - break; - case 'coords': - _addFloatPoints( - annotDictionary, - _obtainFloatPoints(value), - PdfDictionaryProperties.quadPoints, - ); - break; - case 'border': - _addFloatPoints( - annotDictionary, - _obtainFloatPoints(value), - PdfDictionaryProperties.border, - ); - break; - case 'opacity': - if (!isNullOrEmpty(value)) { - final double? opacity = double.tryParse(value); - if (opacity != null) { - annotDictionary.setNumber(PdfDictionaryProperties.ca, opacity); - } - } - break; - case 'flags': - if (!isNullOrEmpty(value)) { - final List annotationFlags = - []; - final List flags = value.split(','); - for (int i = 0; i < flags.length; i++) { - final PdfAnnotationFlags flagType = mapAnnotationFlags(flags[i]); - if (!annotationFlags.contains(flagType)) { - annotationFlags.add(flagType); - } - } - int flagValue = 0; - for (int i = 0; i < annotationFlags.length; i++) { - flagValue |= PdfAnnotationHelper.getAnnotationFlagsValue( - annotationFlags[i], - ); - } - if (flagValue > 0) { - annotDictionary.setNumber(PdfDictionaryProperties.f, flagValue); - } - } - break; - case 'open': - if (!isNullOrEmpty(value)) { - annotDictionary.setBoolean( - PdfDictionaryProperties.open, - value == 'true' || value == 'yes', - ); - } - break; - case 'calibrate': - _addString(annotDictionary, 'Calibrate', value); - break; - case 'customdata': - _addString(annotDictionary, 'CustomData', value); - break; - case 'overlaytext': - _addString(annotDictionary, 'OverlayText', value); - break; - case 'repeat': - annotDictionary.setBoolean( - 'Repeat', - value == 'true' || value == 'yes', - ); - break; - default: - break; - } - } - } - - void _parseInnerElements( - PdfDictionary annotDictionary, - XmlElement element, - int pageIndex, - ) { - if (element.attributes.isNotEmpty) { - for (final XmlNode childNode in element.children) { - if (childNode is XmlElement) { - final XmlName childName = childNode.name; - switch (childName.local.toLowerCase()) { - case 'popup': - if (childNode.attributes.isNotEmpty) { - final PdfDictionary popupDictionary = _getAnnotation( - childNode, - pageIndex, - ); - if (popupDictionary.count > 0) { - final PdfReferenceHolder holder = PdfReferenceHolder( - popupDictionary, - ); - annotDictionary.setProperty( - PdfDictionaryProperties.popup, - holder, - ); - if (popupDictionary.containsKey('NM')) { - _addReferenceToGroup(holder, popupDictionary); - } - } - } - break; - case 'contents': - String? contents = childNode.innerText; - if (!isNullOrEmpty(contents)) { - contents = contents.replaceAll('<', '<'); - contents = contents.replaceAll('>', '>'); - annotDictionary.setString( - PdfDictionaryProperties.contents, - contents, - ); - } - break; - case 'contents-richtext': - final XmlNode? richText = childNode.firstChild; - if (richText != null) { - final String richTextContents = richText.innerText; - final String contentText = childNode.innerText; - if (!isNullOrEmpty(richTextContents) && - !isNullOrEmpty(contentText) && - !annotDictionary.containsKey( - PdfDictionaryProperties.contents, - )) { - annotDictionary.setString( - 'RC', - '$richTextContents', - ); - annotDictionary.setString( - PdfDictionaryProperties.contents, - contentText, - ); - } else if (!isNullOrEmpty(richTextContents)) { - annotDictionary.setString( - 'RC', - '$richTextContents', - ); - } - } - break; - case 'defaultstyle': - _addString(annotDictionary, 'DS', childNode.innerText); - break; - case 'defaultappearance': - _addString( - annotDictionary, - PdfDictionaryProperties.da, - childNode.innerText, - ); - break; - case 'vertices': - if (!isNullOrEmpty(childNode.innerText)) { - final String verticesValue = childNode.innerText.replaceAll( - ';', - ',', - ); - if (verticesValue != '') { - final List verticesList = []; - _addLinePoints(verticesList, verticesValue); - if (verticesList.isNotEmpty && verticesList.length.isEven) { - annotDictionary.setProperty( - PdfDictionaryProperties.vertices, - PdfArray(verticesList), - ); - } - } - } - break; - case 'appearance': - if (!isNullOrEmpty(childNode.innerText)) { - final List appearanceArray = base64.decode( - childNode.innerText, - ); - if (appearanceArray.isNotEmpty) { - final XmlDocument appearanceDoc = XmlDocument.parse( - utf8.decode(appearanceArray), - ); - final List childNodes = appearanceDoc.children; - for (final XmlNode rootElement in childNodes) { - if (rootElement is XmlElement) { - if (rootElement.childElements.isNotEmpty) { - final XmlName rootName = rootElement.name; - if (rootName.local == XfdfProperties.dict) { - final String? rootAttribute = rootElement - .getAttribute(XfdfProperties.key); - if (rootAttribute != null && - !isNullOrEmpty(rootAttribute)) { - if (rootAttribute == 'AP') { - final PdfDictionary appearance = PdfDictionary(); - final List childs = rootElement.children; - for (final XmlNode child in childs) { - if (child is XmlElement) { - _getAppearance(appearance, child); - } - } - if (appearance.count > 0) { - annotDictionary.setProperty( - PdfDictionaryProperties.ap, - appearance, - ); - } - } - } - } - } - } - } - } - } - break; - case 'imagedata': - if (!isNullOrEmpty(childNode.innerText)) { - _addImageToAppearance(annotDictionary, childNode.innerText); - } - break; - case 'inklist': - if (childNode.children.isNotEmpty) { - for (final XmlNode child in childNode.children) { - if (child is XmlElement) { - final XmlName childNodeName = child.name; - if (childNodeName.local.toLowerCase() == 'gesture' && - !isNullOrEmpty(child.innerText)) { - final String pointsArrayValue = child.innerText - .replaceAll(';', ','); - if (pointsArrayValue != '') { - final PdfArray inkListCollection = PdfArray(); - final List pointsList = []; - _addLinePoints(pointsList, pointsArrayValue); - if (pointsList.isNotEmpty && pointsList.length.isEven) { - inkListCollection.add(PdfArray(pointsList)); - } - pointsList.clear(); - if (inkListCollection.count > 0) { - annotDictionary.setProperty( - 'InkList', - inkListCollection, - ); - } - } - } - } - } - } - break; - case 'data': - if (!isNullOrEmpty(childNode.innerText)) { - final List raw = List.from( - hex.decode(childNode.innerText), - ); - if (raw.isNotEmpty) { - if (annotDictionary.containsKey( - PdfDictionaryProperties.subtype, - )) { - final IPdfPrimitive? subtype = PdfCrossTable.dereference( - annotDictionary[PdfDictionaryProperties.subtype], - ); - if (subtype != null && subtype is PdfName) { - if (subtype.name == 'FileAttachment') { - final PdfDictionary fileDictionary = PdfDictionary(); - fileDictionary.setName( - PdfDictionaryProperties.type, - PdfDictionaryProperties.filespec, - ); - _addElementStrings( - fileDictionary, - element, - 'file', - PdfDictionaryProperties.f, - ); - _addElementStrings( - fileDictionary, - element, - 'file', - PdfDictionaryProperties.uf, - ); - final PdfStream fileStream = PdfStream(); - final PdfDictionary param = PdfDictionary(); - final String? sizeAttributes = element.getAttribute( - 'size', - ); - if (!isNullOrEmpty(sizeAttributes)) { - final int? size = int.tryParse(sizeAttributes!); - if (size != null) { - param.setNumber(PdfDictionaryProperties.size, size); - fileStream.setNumber('DL', size); - } - } - _addElementStrings( - param, - element, - 'modification', - PdfDictionaryProperties.modificationDate, - ); - _addElementStrings( - param, - element, - 'creation', - PdfDictionaryProperties.creationDate, - ); - fileStream.setProperty( - PdfDictionaryProperties.params, - param, - ); - _addElementStrings( - fileStream, - element, - 'mimetype', - PdfDictionaryProperties.subtype, - ); - fileStream.data = raw; - final PdfDictionary embeddedFile = PdfDictionary(); - embeddedFile.setProperty( - PdfDictionaryProperties.f, - PdfReferenceHolder(fileStream), - ); - fileDictionary.setProperty( - PdfDictionaryProperties.ef, - embeddedFile, - ); - annotDictionary.setProperty( - PdfDictionaryProperties.fs, - PdfReferenceHolder(fileDictionary), - ); - } else if (subtype.name == 'Sound') { - final PdfStream soundStream = PdfStream(); - soundStream.setName( - PdfDictionaryProperties.type, - 'Sound', - ); - _addNumber(soundStream, element, 'bits', 'B'); - _addNumber( - soundStream, - element, - 'rate', - PdfDictionaryProperties.r, - ); - _addNumber( - soundStream, - element, - 'channels', - PdfDictionaryProperties.c, - ); - String? attribute = element.getAttribute('encoding'); - if (!isNullOrEmpty(attribute)) { - soundStream.setName( - PdfDictionaryProperties.e, - attribute, - ); - } - soundStream.data = raw; - attribute = element.getAttribute('filter'); - if (!isNullOrEmpty(attribute)) { - soundStream.addFilter( - PdfDictionaryProperties.flateDecode, - ); - } - annotDictionary.setProperty( - 'Sound', - PdfReferenceHolder(soundStream), - ); - } - } - } - } - } - break; - } - } - } - } - } - - void _addElementStrings( - PdfDictionary dictionary, - XmlElement element, - String attributeName, - String key, - ) { - if (element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(attributeName); - if (!isNullOrEmpty(attribute)) { - _addString(dictionary, key, attribute); - } - } - } - - void _addNumber( - PdfDictionary dictionary, - XmlElement element, - String attributeName, - String key, - ) { - if (element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(attributeName); - if (!isNullOrEmpty(attribute)) { - _addInt(dictionary, key, attribute); - } - } - } - - void _addImageToAppearance(PdfDictionary annotDictionary, String value) { - final String convert = value - .replaceAll('data:image/png;base64,', '') - .replaceAll('data:image/jpg;base64,', '') - .replaceAll('data:image/bmp;base64,', ''); - final List appearanceArray = base64.decode(convert); - final PdfBitmap image = PdfBitmap(appearanceArray); - final IPdfPrimitive? array = PdfCrossTable.dereference( - annotDictionary[PdfDictionaryProperties.rect], - ); - if (array != null && array is PdfArray) { - const double x = 0; - const double y = 0; - final double width = (array[2]! as PdfNumber).value!.toDouble(); - final double height = (array[3]! as PdfNumber).value!.toDouble(); - final Rect rect = Rect.fromLTWH(x, y, width, height); - final PdfTemplate template = PdfTemplate(width, height); - _setMatrix( - PdfTemplateHelper.getHelper(template).content, - annotDictionary, - ); - template.graphics!.drawImage(image, rect); - final PdfReferenceHolder refHolder = PdfReferenceHolder(template); - final PdfDictionary appearanceDictionary = PdfDictionary(); - appearanceDictionary.setProperty(PdfDictionaryProperties.n, refHolder); - annotDictionary.setProperty( - PdfDictionaryProperties.ap, - appearanceDictionary, - ); - } - } - - void _setMatrix(PdfDictionary template, PdfDictionary annotDictionary) { - final IPdfPrimitive? bbox = PdfCrossTable.dereference( - template[PdfDictionaryProperties.bBox], - ); - if (bbox != null && bbox is PdfArray) { - if (annotDictionary.containsKey(PdfDictionaryProperties.rotate)) { - final IPdfPrimitive? rotate = PdfCrossTable.dereference( - annotDictionary[PdfDictionaryProperties.rotate], - ); - if (rotate is PdfNumber && rotate.value != 0) { - int rotateAngle = rotate.value!.toInt(); - if (rotateAngle == 0) { - rotateAngle = rotateAngle * 90; - } - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - matrix.rotate(rotateAngle.toDouble()); - final PdfArray mMatrix = PdfArray(matrix.matrix.elements); - template[PdfDictionaryProperties.matrix] = mMatrix; - } - } else { - final List elements = [ - 1, - 0, - 0, - 1, - -(bbox[0]! as PdfNumber).value!, - -(bbox[1]! as PdfNumber).value!, - ]; - template[PdfDictionaryProperties.matrix] = PdfArray(elements); - } - } - } - - PdfDictionary _getAppearance(PdfDictionary appearance, XmlElement element) { - final XmlName elementName = element.name; - switch (elementName.local) { - case XfdfProperties.stream: - final PdfStream stream = _getStream(element); - final PdfReferenceHolder holder = PdfReferenceHolder(stream); - _addKey(holder, appearance, element); - break; - case XfdfProperties.dict: - final PdfDictionary dictionary = _getDictionary(element); - final PdfReferenceHolder holder = PdfReferenceHolder(dictionary); - _addKey(holder, appearance, element); - break; - case XfdfProperties.array: - final PdfArray array = _getArray(element); - _addKey(array, appearance, element); - break; - case XfdfProperties.fixed: - final PdfNumber? floatNumber = _getFixed(element); - _addKey(floatNumber, appearance, element); - break; - case XfdfProperties.int: - final PdfNumber? intNumber = _getInt(element); - _addKey(intNumber, appearance, element); - break; - case XfdfProperties.string: - final PdfString? mstring = _getString(element); - _addKey(mstring, appearance, element); - break; - case XfdfProperties.name: - final PdfName? name = _getName(element); - _addKey(name, appearance, element); - break; - case XfdfProperties.bool: - final PdfBoolean? boolean = _getBoolean(element); - _addKey(boolean, appearance, element); - break; - case XfdfProperties.data: - final List? data = _getData(element); - if (data != null && data.isNotEmpty) { - if (appearance is PdfStream) { - appearance.data = data; - if (!appearance.containsKey(PdfDictionaryProperties.type) && - !appearance.containsKey(PdfDictionaryProperties.subtype)) { - appearance.decompress(); - } - bool isImage = false; - if (appearance.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? subtype = PdfCrossTable.dereference( - appearance[PdfDictionaryProperties.subtype], - ); - if (subtype != null && - subtype is PdfName && - subtype.name == PdfDictionaryProperties.image) { - isImage = true; - } - } - if (isImage) { - appearance.compress = false; - } else { - if (appearance.containsKey(PdfDictionaryProperties.length)) { - appearance.remove(PdfDictionaryProperties.length); - } - if (appearance.containsKey(PdfDictionaryProperties.filter)) { - appearance.remove(PdfDictionaryProperties.filter); - } - } - } - } - break; - } - - return appearance; - } - - void _addMeasureDictionary( - PdfDictionary annotDictionary, - XmlElement element, - ) { - XmlElement? measurement; - XmlElement? area; - XmlElement? distance; - XmlElement? xformat; - for (final XmlNode childNode in element.children) { - if (childNode is XmlElement) { - final XmlName childName = childNode.name; - if (childName.local.toLowerCase() == 'measure') { - measurement = childNode; - break; - } - } - } - final PdfDictionary measureDictionary = PdfDictionary(); - final PdfArray dArray = PdfArray(); - final PdfArray aArray = PdfArray(); - final PdfArray xArray = PdfArray(); - final PdfDictionary dDict = PdfDictionary(); - final PdfDictionary aDict = PdfDictionary(); - final PdfDictionary xDict = PdfDictionary(); - measureDictionary.items![PdfName(PdfDictionaryProperties.a)] = aArray; - measureDictionary.items![PdfName(PdfDictionaryProperties.d)] = dArray; - measureDictionary.items![PdfName(PdfDictionaryProperties.x)] = xArray; - if (measurement != null) { - measureDictionary.setName( - PdfDictionaryProperties.type, - PdfDictionaryProperties.measure, - ); - if (measurement.attributes.isNotEmpty) { - final String? attribute = measurement.getAttribute('rateValue'); - if (!isNullOrEmpty(attribute)) { - measureDictionary.setString(PdfDictionaryProperties.r, attribute); - } - } - for (final XmlNode childNode in measurement.children) { - if (childNode is XmlElement) { - final XmlName newElement = childNode.name; - if (newElement.local.toLowerCase() == 'area') { - area = childNode; - } - if (newElement.local.toLowerCase() == 'distance') { - distance = childNode; - } - if (newElement.local.toLowerCase() == 'xformat') { - xformat = childNode; - } - } - } - } - if (xformat != null) { - _addElements(xformat, xDict); - xArray.add(xDict); - } - if (area != null) { - _addElements(area, aDict); - aArray.add(aDict); - } - if (distance != null) { - _addElements(distance, dDict); - dArray.add(dDict); - } - if (measureDictionary.items!.isNotEmpty && - measureDictionary.containsKey(PdfDictionaryProperties.type)) { - annotDictionary.items![PdfName( - PdfDictionaryProperties.measure, - )] = PdfReferenceHolder(measureDictionary); - } - } - - void _addElements(XmlElement element, PdfDictionary dictionary) { - if (element.attributes.isNotEmpty) { - String? attribute = element.getAttribute('d'); - if (attribute != null) { - final double? d = double.tryParse(attribute); - if (d != null) { - dictionary.setProperty( - PdfName(PdfDictionaryProperties.d), - PdfNumber(d), - ); - } - } - attribute = element.getAttribute(PdfDictionaryProperties.c.toLowerCase()); - if (attribute != null) { - final double? c = double.tryParse(attribute); - if (c != null) { - dictionary.setProperty( - PdfName(PdfDictionaryProperties.c), - PdfNumber(c), - ); - } - } - attribute = element.getAttribute('rt'); - if (attribute != null) { - dictionary.items![PdfName('RT')] = PdfString(attribute); - } - attribute = element.getAttribute('rd'); - if (attribute != null) { - dictionary.items![PdfName(PdfDictionaryProperties.rd)] = PdfString( - attribute, - ); - } - attribute = element.getAttribute('ss'); - if (attribute != null) { - dictionary.items![PdfName('SS')] = PdfString(attribute); - } - attribute = element.getAttribute(PdfDictionaryProperties.u.toLowerCase()); - if (attribute != null) { - dictionary.items![PdfName(PdfDictionaryProperties.u)] = PdfString( - attribute, - ); - } - attribute = element.getAttribute(PdfDictionaryProperties.f.toLowerCase()); - if (attribute != null) { - dictionary.items![PdfName(PdfDictionaryProperties.f)] = PdfName( - attribute, - ); - } - attribute = element.getAttribute('fd'); - if (attribute != null) { - dictionary.items![PdfName('FD')] = PdfBoolean(attribute == 'yes'); - } - } - } - - PdfStream _getStream(XmlElement element) { - final PdfStream stream = PdfStream(); - if (element.children.isNotEmpty) { - for (final XmlNode child in element.children) { - if (child is XmlElement) { - _getAppearance(stream, child); - } - } - } - return stream; - } - - void _addKey( - IPdfPrimitive? primitive, - PdfDictionary dictionary, - XmlElement element, - ) { - if (primitive != null && element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(XfdfProperties.key); - if (!isNullOrEmpty(attribute)) { - dictionary.setProperty(attribute, primitive); - } - } - } - - PdfDictionary _getDictionary(XmlElement element) { - final PdfDictionary dictionary = PdfDictionary(); - if (element.children.isNotEmpty) { - for (final XmlNode child in element.children) { - if (child is XmlElement) { - _getAppearance(dictionary, child); - } - } - } - return dictionary; - } - - PdfArray _getArray(XmlElement element) { - final PdfArray array = PdfArray(); - if (element.children.isNotEmpty) { - for (final XmlNode child in element.children) { - if (child is XmlElement) { - _addArrayElements(array, child); - } - } - } - return array; - } - - PdfNumber? _getFixed(XmlElement element) { - if (element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(XfdfProperties.val); - if (!isNullOrEmpty(attribute)) { - final double? value = double.tryParse(attribute!); - if (value != null) { - return PdfNumber(value); - } - } - } - return null; - } - - PdfNumber? _getInt(XmlElement element) { - // int value; - if (element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(XfdfProperties.val); - if (!isNullOrEmpty(attribute)) { - final int? value = int.tryParse(attribute!); - if (value != null) { - return PdfNumber(value); - } - } - } - return null; - } - - void _addArrayElements(PdfArray array, XmlElement element) { - final XmlName elementName = element.name; - switch (elementName.local) { - case XfdfProperties.stream: - final PdfStream stream = _getStream(element); - _addArrayElement(array, PdfReferenceHolder(stream)); - break; - case XfdfProperties.dict: - final PdfDictionary dictionary = _getDictionary(element); - _addArrayElement(array, PdfReferenceHolder(dictionary)); - break; - case XfdfProperties.array: - final PdfArray pdfArray = _getArray(element); - _addArrayElement(array, pdfArray); - break; - case XfdfProperties.fixed: - final PdfNumber? floatValue = _getFixed(element); - _addArrayElement(array, floatValue); - break; - case XfdfProperties.int: - final PdfNumber? intValue = _getInt(element); - _addArrayElement(array, intValue); - break; - case XfdfProperties.name: - final PdfName? name = _getName(element); - _addArrayElement(array, name); - break; - case XfdfProperties.bool: - final PdfBoolean? boolean = _getBoolean(element); - _addArrayElement(array, boolean); - break; - case XfdfProperties.string: - final PdfString? mstring = _getString(element); - _addArrayElement(array, mstring); - break; - } - } - - void _addArrayElement(PdfArray array, IPdfPrimitive? primitive) { - if (primitive != null) { - array.add(primitive); - } - } - - PdfName? _getName(XmlElement element) { - if (element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(XfdfProperties.val); - if (!isNullOrEmpty(attribute)) { - return PdfName(attribute); - } - } - return null; - } - - PdfBoolean? _getBoolean(XmlElement element) { - if (element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(XfdfProperties.val); - if (!isNullOrEmpty(attribute)) { - return PdfBoolean(attribute!.toLowerCase() == 'true'); - } - } - return null; - } - - PdfString? _getString(XmlElement element) { - if (element.attributes.isNotEmpty) { - final String? attribute = element.getAttribute(XfdfProperties.val); - if (!isNullOrEmpty(attribute)) { - return PdfString(attribute!); - } else if (element.name.toXmlString().contains(XfdfProperties.string)) { - final List? data = _getData(element); - if (data != null && data.isNotEmpty) { - return PdfString.fromBytes(data); - } - } - } - return null; - } - - List? _getData(XmlElement element) { - if (!isNullOrEmpty(element.innerText) && element.attributes.isNotEmpty) { - final String? mode = element.getAttribute(XfdfProperties.mode); - final String? encoding = element.getAttribute('ENCODING'); - if (!isNullOrEmpty(mode) && !isNullOrEmpty(encoding)) { - if (mode == XfdfProperties.filtered && - encoding == XfdfProperties.ascii) { - return [...utf8.encode(element.innerText)]; - } else if (mode == XfdfProperties.raw && - encoding == XfdfProperties.hex) { - return _hexToBytes(element.innerText); - } - } else if (!isNullOrEmpty(encoding) && encoding == XfdfProperties.hex) { - return _hexToBytes(element.innerText); - } - } - return null; - } - - List _hexToBytes(String hexString) { - final List bytes = []; - for (int i = 0; i < hexString.length; i += 2) { - final String hex = hexString.substring(i, i + 2); - bytes.add(int.parse(hex, radix: 16)); - } - return bytes; - } - - void _addReferenceToGroup( - PdfReferenceHolder holder, - PdfDictionary dictionary, - ) { - IPdfPrimitive? name = PdfCrossTable.dereference(dictionary['NM']); - if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { - _groupReferences ??= {}; - _groupReferences![name.value!] = holder; - if (dictionary.containsKey(PdfDictionaryProperties.irt)) { - _groupHolders ??= []; - _groupHolders!.add(dictionary); - } - } else if (name == null) { - if (dictionary.containsKey(PdfDictionaryProperties.irt)) { - name = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.irt], - ); - } - if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { - if (_groupReferences != null && - _groupReferences!.containsKey(name.value)) { - final PdfReferenceHolder referenceHolder = - _groupReferences![name.value]!; - dictionary[PdfDictionaryProperties.irt] = referenceHolder; - } - } - } - } - - String? _getFormattedString(String? value) { - if (!isNullOrEmpty(value)) { - value = value!.replaceAll('<', '<'); - value = value.replaceAll('>', '>'); - } - return value; - } - - void _addString(PdfDictionary dictionary, String key, String? value) { - if (!isNullOrEmpty(value)) { - dictionary.setString(key, value); - } - } - - void _addInt(PdfDictionary dictionary, String key, String? value) { - if (!isNullOrEmpty(value)) { - final double? number = double.tryParse(value!); - if (number != null) { - dictionary.setNumber(key, number.toInt()); - } - } - } - - void _addFloatPoints(PdfDictionary dictionary, List points, String key) { - if (points.isNotEmpty) { - dictionary.setProperty(key, PdfArray(points)); - } - } - - void _addFloat(PdfDictionary dictionary, String key, String value) { - if (!isNullOrEmpty(value)) { - final int? number = int.tryParse(value); - if (number != null) { - dictionary.setNumber(key, number); - } - } - } - - PdfArray? _getColorArray(String value) { - final String hex = value.replaceAll('#', ''); - final int r = int.parse(hex.substring(0, 2), radix: 16); - final int g = int.parse(hex.substring(2, 4), radix: 16); - final int b = int.parse(hex.substring(4, hex.length), radix: 16); - if (r >= 0 && g >= 0 && b >= 0) { - final PdfArray colorArray = PdfArray(); - colorArray.add(PdfNumber(r / 255)); - colorArray.add(PdfNumber(g / 255)); - colorArray.add(PdfNumber(b / 255)); - return colorArray; - } - return null; - } - - ///Internal method - static PdfAnnotationFlags mapAnnotationFlags(String flag) { - PdfAnnotationFlags type; - switch (flag.toLowerCase()) { - case 'hidden': - type = PdfAnnotationFlags.hidden; - break; - case 'invisible': - type = PdfAnnotationFlags.invisible; - break; - case 'locked': - type = PdfAnnotationFlags.locked; - break; - case 'norotate': - type = PdfAnnotationFlags.noRotate; - break; - case 'noview': - type = PdfAnnotationFlags.noView; - break; - case 'nozoom': - type = PdfAnnotationFlags.noZoom; - break; - case 'print': - type = PdfAnnotationFlags.print; - break; - case 'readonly': - type = PdfAnnotationFlags.readOnly; - break; - case 'togglenoview': - type = PdfAnnotationFlags.toggleNoView; - break; - default: - type = PdfAnnotationFlags.defaultFlag; - break; - } - return type; - } - - void _addLineEndStyle(XmlElement element, PdfDictionary annotDictionary) { - if (element.attributes.isNotEmpty) { - String beginLineStyle = ''; - final String? headAttribute = element.getAttribute('head'); - if (!isNullOrEmpty(headAttribute)) { - beginLineStyle = getEnumName(mapLineEndingStyle(headAttribute!)); - } - String endLineStyle = ''; - final String? tailAttribute = element.getAttribute('tail'); - if (!isNullOrEmpty(tailAttribute)) { - endLineStyle = getEnumName(mapLineEndingStyle(tailAttribute!)); - } - if (!isNullOrEmpty(beginLineStyle)) { - if (!isNullOrEmpty(endLineStyle)) { - final PdfArray lineEndingStyles = PdfArray(); - lineEndingStyles.add(PdfName(beginLineStyle)); - lineEndingStyles.add(PdfName(endLineStyle)); - annotDictionary.setProperty( - PdfDictionaryProperties.le, - lineEndingStyles, - ); - } else { - annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); - } - } else if (!isNullOrEmpty(endLineStyle)) { - annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); - } - } - } - - /// Internal Field. - static PdfLineEndingStyle mapLineEndingStyle(String style) { - PdfLineEndingStyle lineStyle; - switch (style.toLowerCase()) { - case 'butt': - lineStyle = PdfLineEndingStyle.butt; - break; - case 'circle': - lineStyle = PdfLineEndingStyle.circle; - break; - case 'closedarrow': - lineStyle = PdfLineEndingStyle.closedArrow; - break; - case 'diamond': - lineStyle = PdfLineEndingStyle.diamond; - break; - case 'openarrow': - lineStyle = PdfLineEndingStyle.openArrow; - break; - case 'rclosedarrow': - lineStyle = PdfLineEndingStyle.rClosedArrow; - break; - case 'ropenarrow': - lineStyle = PdfLineEndingStyle.rOpenArrow; - break; - case 'slash': - lineStyle = PdfLineEndingStyle.slash; - break; - case 'square': - lineStyle = PdfLineEndingStyle.square; - break; - default: - lineStyle = PdfLineEndingStyle.none; - break; - } - return lineStyle; - } -} +import 'dart:convert'; +import 'dart:ui'; + +import 'package:convert/convert.dart'; +import 'package:xml/xml.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../forms/pdf_xfdf_document.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/images/pdf_bitmap.dart'; +import '../graphics/pdf_transformation_matrix.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'json_parser.dart'; +import 'pdf_annotation.dart'; + +/// The class provides methods and properties to handle the loaded annotations from the existing PDF document for Xfdf export and import. +class XfdfParser { + //Consructor + /// Initializes a new instance of the [XfdfParser] class. + XfdfParser(List data, PdfDocument document) { + _document = document; + final String xmlString = utf8.decode(data); + _xmlDocument = XmlDocument.parse(xmlString); + if (_xmlDocument.rootElement.localName.toLowerCase() != 'xfdf') { + throw ArgumentError.value( + _xmlDocument.rootElement.localName, + 'xmlString', + 'Invalid XFDF data', + ); + } + } + + //Fields + late PdfDocument _document; + late XmlDocument _xmlDocument; + Map? _groupReferences; + List? _groupHolders; + + //Implementation. + /// internal method. + void parseAndImportAnnotationData() { + for (final XmlNode node + in _xmlDocument.rootElement.firstElementChild!.children) { + if (node is XmlElement) { + _parseAnnotationData(node); + } + } + } + + void _parseAnnotationData(XmlElement element) { + if (element.attributes.isNotEmpty) { + final String? pageIndexString = element.getAttribute('page'); + if (pageIndexString != null && !isNullOrEmpty(pageIndexString)) { + final int pageIndex = int.parse(pageIndexString); + if (pageIndex >= 0 && pageIndex < _document.pages.count) { + PdfPageHelper.getHelper(_document.pages[pageIndex]).importAnnotation = + true; + final PdfDictionary annotationDictionary = _getAnnotation( + element, + pageIndex, + ); + if (annotationDictionary.count > 0) { + final PdfReferenceHolder holder = PdfReferenceHolder( + annotationDictionary, + ); + if (annotationDictionary.containsKey('NM') || + annotationDictionary.containsKey(PdfDictionaryProperties.irt)) { + _addReferenceToGroup(holder, annotationDictionary); + } + final PdfDictionary? pageDictionary = + PdfPageHelper.getHelper(_document.pages[pageIndex]).dictionary; + if (pageDictionary != null) { + if (!pageDictionary.containsKey(PdfDictionaryProperties.annots)) { + pageDictionary[PdfDictionaryProperties.annots] = PdfArray(); + } + final IPdfPrimitive? annots = PdfCrossTable.dereference( + pageDictionary[PdfDictionaryProperties.annots], + ); + if (annots != null && annots is PdfArray) { + annots.elements.add(holder); + _handlePopUp(annots, holder, annotationDictionary); + annots.changed = true; + } + } + } + } + } + } + } + + void _handlePopUp( + PdfArray annots, + PdfReferenceHolder holder, + PdfDictionary annotDictionary, + ) { + if (annotDictionary.containsKey(PdfDictionaryProperties.popup)) { + final IPdfPrimitive? popup = PdfCrossTable.dereference( + annotDictionary[PdfDictionaryProperties.popup], + ); + if (popup != null && popup is PdfDictionary) { + popup.setProperty(PdfDictionaryProperties.parent, holder); + annots.add(popup); + } + } + } + + PdfDictionary _getAnnotation(XmlElement element, int pageIndex) { + final PdfDictionary annotationDictionary = PdfDictionary(); + annotationDictionary.setName( + PdfName(PdfDictionaryProperties.name), + PdfDictionaryProperties.annot, + ); + bool isValidType = true; + if (!isNullOrEmpty(element.localName)) { + switch (element.localName.toLowerCase()) { + case 'line': + annotationDictionary.setName( + PdfName(PdfDictionaryProperties.subtype), + PdfDictionaryProperties.line, + ); + final String? start = element.getAttribute('start'); + final String? end = element.getAttribute('end'); + if (start != null && end != null) { + final List linePoints = []; + _addLinePoints(linePoints, start); + _addLinePoints(linePoints, end); + if (linePoints.length == 4) { + annotationDictionary.setProperty( + PdfDictionaryProperties.l, + PdfArray(linePoints), + ); + } + linePoints.clear(); + } + _addLineEndStyle(element, annotationDictionary); + break; + case 'circle': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.circle, + ); + break; + case 'square': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.square, + ); + break; + case 'polyline': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'PolyLine', + ); + _addLineEndStyle(element, annotationDictionary); + break; + case 'polygon': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.polygon, + ); + _addLineEndStyle(element, annotationDictionary); + break; + case 'ink': + annotationDictionary.setName(PdfDictionaryProperties.subtype, 'Ink'); + break; + case 'popup': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.popup, + ); + break; + case 'text': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.text, + ); + break; + case 'freetext': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'FreeText', + ); + _addLineEndStyle(element, annotationDictionary); + break; + case 'stamp': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'Stamp', + ); + break; + case 'highlight': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.highlight, + ); + break; + case 'squiggly': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.squiggly, + ); + break; + case 'underline': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.underline, + ); + break; + case 'strikeout': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + PdfDictionaryProperties.strikeOut, + ); + break; + case 'fileattachment': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'FileAttachment', + ); + break; + case 'sound': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'Sound', + ); + break; + case 'caret': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'Caret', + ); + break; + case 'redact': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'Redact', + ); + break; + case 'watermark': + annotationDictionary.setName( + PdfDictionaryProperties.subtype, + 'Watermark', + ); + break; + default: + isValidType = false; + break; + } + if (isValidType) { + _addAnnotationData(annotationDictionary, element, pageIndex); + } + } + return annotationDictionary; + } + + void _addAnnotationData( + PdfDictionary annotDictionary, + XmlElement element, + int pageIndex, + ) { + _addBorderStyle(annotDictionary, element); + _applyAttributeValues(annotDictionary, element); + _parseInnerElements(annotDictionary, element, pageIndex); + _addMeasureDictionary(annotDictionary, element); + } + + void _addBorderStyle(PdfDictionary annotDictionary, XmlElement element) { + if (element.attributes.isNotEmpty) { + final PdfDictionary borderEffectDictionary = PdfDictionary(); + final PdfDictionary borderStyleDictionary = PdfDictionary(); + String? attribute = element.getAttribute('width'); + if (!isNullOrEmpty(attribute)) { + borderStyleDictionary.setNumber( + PdfDictionaryProperties.w, + double.parse(attribute!), + ); + } + bool isBasicStyle = true; + attribute = element.getAttribute('style'); + if (!isNullOrEmpty(attribute)) { + String style = ''; + switch (attribute) { + case 'dash': + style = PdfDictionaryProperties.d; + break; + case 'solid': + style = PdfDictionaryProperties.s; + break; + case 'bevelled': + style = 'B'; + break; + case 'inset': + style = PdfDictionaryProperties.i; + break; + case 'underline': + style = PdfDictionaryProperties.u; + break; + case 'cloudy': + style = PdfDictionaryProperties.c; + isBasicStyle = false; + break; + } + if (!isNullOrEmpty(style)) { + (isBasicStyle ? borderStyleDictionary : borderEffectDictionary) + .setName(PdfDictionaryProperties.s, style); + attribute = element.getAttribute('intensity'); + if (!isBasicStyle && !isNullOrEmpty(attribute)) { + borderEffectDictionary.setNumber( + PdfDictionaryProperties.i, + double.parse(attribute!), + ); + } else { + attribute = element.getAttribute('dashes'); + if (!isNullOrEmpty(attribute)) { + final List dashPoints = _obtainFloatPoints(attribute!); + if (dashPoints.isNotEmpty) { + borderStyleDictionary.setProperty( + PdfDictionaryProperties.d, + PdfArray(dashPoints), + ); + } + } + } + } + } + if (borderEffectDictionary.count > 0) { + annotDictionary.setProperty( + PdfDictionaryProperties.be, + PdfReferenceHolder(borderEffectDictionary), + ); + } else { + borderEffectDictionary.clear(); + borderEffectDictionary.isSaving = false; + } + if (borderStyleDictionary.count > 0) { + borderStyleDictionary.setProperty( + PdfDictionaryProperties.type, + PdfName(PdfDictionaryProperties.border), + ); + annotDictionary.setProperty( + PdfDictionaryProperties.bs, + PdfReferenceHolder(borderStyleDictionary), + ); + } else { + borderStyleDictionary.clear(); + borderStyleDictionary.isSaving = false; + } + } + } + + List _obtainFloatPoints(String value) { + final List result = []; + if (!isNullOrEmpty(value)) { + final List pointsArray = value.split(','); + for (final String pointString in pointsArray) { + final double? point = double.tryParse(pointString); + if (point != null) { + result.add(point); + } + } + } + return result; + } + + void _addLinePoints(List linePoints, String value) { + if (!isNullOrEmpty(value) && value.contains(',')) { + final List pointsArray = value.split(','); + for (final String pointString in pointsArray) { + final double? point = double.tryParse(pointString); + if (point != null) { + linePoints.add(point); + } + } + } + } + + void _applyAttributeValues( + PdfDictionary annotDictionary, + XmlElement element, + ) { + for (final XmlAttribute attribute in element.attributes) { + final String value = attribute.value; + final XmlName name = attribute.name; + switch (name.local.toLowerCase()) { + case 'page': + case 'start': + case 'end': + case 'width': + case 'head': + case 'tail': + case 'style': + case 'intensity': + case 'itex': + break; + case 'state': + _addString(annotDictionary, 'State', value); + break; + case 'statemodel': + _addString(annotDictionary, 'StateModel', value); + break; + case 'replytype': + if (value == 'group') { + annotDictionary.setName('RT', 'Group'); + } + break; + case 'inreplyto': + _addString(annotDictionary, PdfDictionaryProperties.irt, value); + break; + case 'rect': + final List points = _obtainFloatPoints(value); + if (points.isNotEmpty && points.length == 4) { + annotDictionary.setProperty( + PdfDictionaryProperties.rect, + PdfArray(points), + ); + } + break; + case 'color': + if (!isNullOrEmpty(value)) { + final PdfArray? colorArray = _getColorArray(value); + if (colorArray != null) { + annotDictionary.setProperty( + PdfDictionaryProperties.c, + colorArray, + ); + } + } + break; + case 'interior-color': + if (!isNullOrEmpty(value)) { + final PdfArray? colorArray = _getColorArray(value); + if (colorArray != null) { + annotDictionary.setProperty( + PdfDictionaryProperties.ic, + colorArray, + ); + } + } + break; + case 'date': + _addString(annotDictionary, PdfDictionaryProperties.m, value); + break; + case 'creationdate': + _addString( + annotDictionary, + PdfDictionaryProperties.creationDate, + value, + ); + break; + case 'name': + _addString(annotDictionary, 'NM', value); + break; + case 'icon': + if (!isNullOrEmpty(value)) { + annotDictionary.setName(PdfDictionaryProperties.name, value); + } + break; + case 'subject': + _addString( + annotDictionary, + PdfDictionaryProperties.subj, + _getFormattedString(value), + ); + break; + case 'title': + _addString( + annotDictionary, + PdfDictionaryProperties.t, + _getFormattedString(value), + ); + break; + case 'rotation': + _addInt(annotDictionary, PdfDictionaryProperties.rotate, value); + break; + case 'justification': + _addInt(annotDictionary, PdfDictionaryProperties.q, value); + break; + case 'fringe': + _addFloatPoints( + annotDictionary, + _obtainFloatPoints(value), + PdfDictionaryProperties.rd, + ); + break; + case 'it': + if (!isNullOrEmpty(value)) { + annotDictionary.setName(PdfDictionaryProperties.it, value); + } + break; + case 'leaderlength': + _addFloat(annotDictionary, PdfDictionaryProperties.ll, value); + break; + case 'leaderextend': + if (!isNullOrEmpty(value)) { + final double? leaderExtend = double.tryParse(value); + if (leaderExtend != null) { + annotDictionary.setNumber( + PdfDictionaryProperties.lle, + leaderExtend, + ); + } + } + break; + case 'caption': + if (!isNullOrEmpty(value)) { + annotDictionary.setBoolean( + PdfDictionaryProperties.cap, + value.toLowerCase() == 'yes', + ); + } + break; + case 'caption-style': + if (!isNullOrEmpty(value)) { + annotDictionary.setName(PdfDictionaryProperties.cp, value); + } + break; + case 'callout': + _addFloatPoints(annotDictionary, _obtainFloatPoints(value), 'CL'); + break; + case 'coords': + _addFloatPoints( + annotDictionary, + _obtainFloatPoints(value), + PdfDictionaryProperties.quadPoints, + ); + break; + case 'border': + _addFloatPoints( + annotDictionary, + _obtainFloatPoints(value), + PdfDictionaryProperties.border, + ); + break; + case 'opacity': + if (!isNullOrEmpty(value)) { + final double? opacity = double.tryParse(value); + if (opacity != null) { + annotDictionary.setNumber(PdfDictionaryProperties.ca, opacity); + } + } + break; + case 'flags': + if (!isNullOrEmpty(value)) { + final List annotationFlags = + []; + final List flags = value.split(','); + for (int i = 0; i < flags.length; i++) { + final PdfAnnotationFlags flagType = mapAnnotationFlags(flags[i]); + if (!annotationFlags.contains(flagType)) { + annotationFlags.add(flagType); + } + } + int flagValue = 0; + for (int i = 0; i < annotationFlags.length; i++) { + flagValue |= PdfAnnotationHelper.getAnnotationFlagsValue( + annotationFlags[i], + ); + } + if (flagValue > 0) { + annotDictionary.setNumber(PdfDictionaryProperties.f, flagValue); + } + } + break; + case 'open': + if (!isNullOrEmpty(value)) { + annotDictionary.setBoolean( + PdfDictionaryProperties.open, + value == 'true' || value == 'yes', + ); + } + break; + case 'calibrate': + _addString(annotDictionary, 'Calibrate', value); + break; + case 'customdata': + _addString(annotDictionary, 'CustomData', value); + break; + case 'overlaytext': + _addString(annotDictionary, 'OverlayText', value); + break; + case 'repeat': + annotDictionary.setBoolean( + 'Repeat', + value == 'true' || value == 'yes', + ); + break; + default: + break; + } + } + } + + void _parseInnerElements( + PdfDictionary annotDictionary, + XmlElement element, + int pageIndex, + ) { + if (element.attributes.isNotEmpty) { + for (final XmlNode childNode in element.children) { + if (childNode is XmlElement) { + final XmlName childName = childNode.name; + switch (childName.local.toLowerCase()) { + case 'popup': + if (childNode.attributes.isNotEmpty) { + final PdfDictionary popupDictionary = _getAnnotation( + childNode, + pageIndex, + ); + if (popupDictionary.count > 0) { + final PdfReferenceHolder holder = PdfReferenceHolder( + popupDictionary, + ); + annotDictionary.setProperty( + PdfDictionaryProperties.popup, + holder, + ); + if (popupDictionary.containsKey('NM')) { + _addReferenceToGroup(holder, popupDictionary); + } + } + } + break; + case 'contents': + String? contents = childNode.innerText; + if (!isNullOrEmpty(contents)) { + contents = contents.replaceAll('<', '<'); + contents = contents.replaceAll('>', '>'); + annotDictionary.setString( + PdfDictionaryProperties.contents, + contents, + ); + } + break; + case 'contents-richtext': + final XmlNode? richText = childNode.firstChild; + if (richText != null) { + final String richTextContents = richText.innerText; + final String contentText = childNode.innerText; + if (!isNullOrEmpty(richTextContents) && + !isNullOrEmpty(contentText) && + !annotDictionary.containsKey( + PdfDictionaryProperties.contents, + )) { + annotDictionary.setString( + 'RC', + '$richTextContents', + ); + annotDictionary.setString( + PdfDictionaryProperties.contents, + contentText, + ); + } else if (!isNullOrEmpty(richTextContents)) { + annotDictionary.setString( + 'RC', + '$richTextContents', + ); + } + } + break; + case 'defaultstyle': + _addString(annotDictionary, 'DS', childNode.innerText); + break; + case 'defaultappearance': + _addString( + annotDictionary, + PdfDictionaryProperties.da, + childNode.innerText, + ); + break; + case 'vertices': + if (!isNullOrEmpty(childNode.innerText)) { + final String verticesValue = childNode.innerText.replaceAll( + ';', + ',', + ); + if (verticesValue != '') { + final List verticesList = []; + _addLinePoints(verticesList, verticesValue); + if (verticesList.isNotEmpty && verticesList.length.isEven) { + annotDictionary.setProperty( + PdfDictionaryProperties.vertices, + PdfArray(verticesList), + ); + } + } + } + break; + case 'appearance': + if (!isNullOrEmpty(childNode.innerText)) { + final List appearanceArray = base64.decode( + childNode.innerText, + ); + if (appearanceArray.isNotEmpty) { + final XmlDocument appearanceDoc = XmlDocument.parse( + utf8.decode(appearanceArray), + ); + final List childNodes = appearanceDoc.children; + for (final XmlNode rootElement in childNodes) { + if (rootElement is XmlElement) { + if (rootElement.childElements.isNotEmpty) { + final XmlName rootName = rootElement.name; + if (rootName.local == XfdfProperties.dict) { + final String? rootAttribute = rootElement + .getAttribute(XfdfProperties.key); + if (rootAttribute != null && + !isNullOrEmpty(rootAttribute)) { + if (rootAttribute == 'AP') { + final PdfDictionary appearance = PdfDictionary(); + final List childs = rootElement.children; + for (final XmlNode child in childs) { + if (child is XmlElement) { + _getAppearance(appearance, child); + } + } + if (appearance.count > 0) { + annotDictionary.setProperty( + PdfDictionaryProperties.ap, + appearance, + ); + } + } + } + } + } + } + } + } + } + break; + case 'imagedata': + if (!isNullOrEmpty(childNode.innerText)) { + _addImageToAppearance(annotDictionary, childNode.innerText); + } + break; + case 'inklist': + if (childNode.children.isNotEmpty) { + for (final XmlNode child in childNode.children) { + if (child is XmlElement) { + final XmlName childNodeName = child.name; + if (childNodeName.local.toLowerCase() == 'gesture' && + !isNullOrEmpty(child.innerText)) { + final String pointsArrayValue = child.innerText + .replaceAll(';', ','); + if (pointsArrayValue != '') { + final PdfArray inkListCollection = PdfArray(); + final List pointsList = []; + _addLinePoints(pointsList, pointsArrayValue); + if (pointsList.isNotEmpty && pointsList.length.isEven) { + inkListCollection.add(PdfArray(pointsList)); + } + pointsList.clear(); + if (inkListCollection.count > 0) { + annotDictionary.setProperty( + 'InkList', + inkListCollection, + ); + } + } + } + } + } + } + break; + case 'data': + if (!isNullOrEmpty(childNode.innerText)) { + final List raw = List.from( + hex.decode(childNode.innerText), + ); + if (raw.isNotEmpty) { + if (annotDictionary.containsKey( + PdfDictionaryProperties.subtype, + )) { + final IPdfPrimitive? subtype = PdfCrossTable.dereference( + annotDictionary[PdfDictionaryProperties.subtype], + ); + if (subtype != null && subtype is PdfName) { + if (subtype.name == 'FileAttachment') { + final PdfDictionary fileDictionary = PdfDictionary(); + fileDictionary.setName( + PdfDictionaryProperties.type, + PdfDictionaryProperties.filespec, + ); + _addElementStrings( + fileDictionary, + element, + 'file', + PdfDictionaryProperties.f, + ); + _addElementStrings( + fileDictionary, + element, + 'file', + PdfDictionaryProperties.uf, + ); + final PdfStream fileStream = PdfStream(); + final PdfDictionary param = PdfDictionary(); + final String? sizeAttributes = element.getAttribute( + 'size', + ); + if (!isNullOrEmpty(sizeAttributes)) { + final int? size = int.tryParse(sizeAttributes!); + if (size != null) { + param.setNumber(PdfDictionaryProperties.size, size); + fileStream.setNumber('DL', size); + } + } + _addElementStrings( + param, + element, + 'modification', + PdfDictionaryProperties.modificationDate, + ); + _addElementStrings( + param, + element, + 'creation', + PdfDictionaryProperties.creationDate, + ); + fileStream.setProperty( + PdfDictionaryProperties.params, + param, + ); + _addElementStrings( + fileStream, + element, + 'mimetype', + PdfDictionaryProperties.subtype, + ); + fileStream.data = raw; + final PdfDictionary embeddedFile = PdfDictionary(); + embeddedFile.setProperty( + PdfDictionaryProperties.f, + PdfReferenceHolder(fileStream), + ); + fileDictionary.setProperty( + PdfDictionaryProperties.ef, + embeddedFile, + ); + annotDictionary.setProperty( + PdfDictionaryProperties.fs, + PdfReferenceHolder(fileDictionary), + ); + } else if (subtype.name == 'Sound') { + final PdfStream soundStream = PdfStream(); + soundStream.setName( + PdfDictionaryProperties.type, + 'Sound', + ); + _addNumber(soundStream, element, 'bits', 'B'); + _addNumber( + soundStream, + element, + 'rate', + PdfDictionaryProperties.r, + ); + _addNumber( + soundStream, + element, + 'channels', + PdfDictionaryProperties.c, + ); + String? attribute = element.getAttribute('encoding'); + if (!isNullOrEmpty(attribute)) { + soundStream.setName( + PdfDictionaryProperties.e, + attribute, + ); + } + soundStream.data = raw; + attribute = element.getAttribute('filter'); + if (!isNullOrEmpty(attribute)) { + soundStream.addFilter( + PdfDictionaryProperties.flateDecode, + ); + } + annotDictionary.setProperty( + 'Sound', + PdfReferenceHolder(soundStream), + ); + } + } + } + } + } + break; + } + } + } + } + } + + void _addElementStrings( + PdfDictionary dictionary, + XmlElement element, + String attributeName, + String key, + ) { + if (element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(attributeName); + if (!isNullOrEmpty(attribute)) { + _addString(dictionary, key, attribute); + } + } + } + + void _addNumber( + PdfDictionary dictionary, + XmlElement element, + String attributeName, + String key, + ) { + if (element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(attributeName); + if (!isNullOrEmpty(attribute)) { + _addInt(dictionary, key, attribute); + } + } + } + + void _addImageToAppearance(PdfDictionary annotDictionary, String value) { + final String convert = value + .replaceAll('data:image/png;base64,', '') + .replaceAll('data:image/jpg;base64,', '') + .replaceAll('data:image/bmp;base64,', ''); + final List appearanceArray = base64.decode(convert); + final PdfBitmap image = PdfBitmap(appearanceArray); + final IPdfPrimitive? array = PdfCrossTable.dereference( + annotDictionary[PdfDictionaryProperties.rect], + ); + if (array != null && array is PdfArray) { + const double x = 0; + const double y = 0; + final double width = (array[2]! as PdfNumber).value!.toDouble(); + final double height = (array[3]! as PdfNumber).value!.toDouble(); + final Rect rect = Rect.fromLTWH(x, y, width, height); + final PdfTemplate template = PdfTemplate(width, height); + _setMatrix( + PdfTemplateHelper.getHelper(template).content, + annotDictionary, + ); + template.graphics!.drawImage(image, rect); + final PdfReferenceHolder refHolder = PdfReferenceHolder(template); + final PdfDictionary appearanceDictionary = PdfDictionary(); + appearanceDictionary.setProperty(PdfDictionaryProperties.n, refHolder); + annotDictionary.setProperty( + PdfDictionaryProperties.ap, + appearanceDictionary, + ); + } + } + + void _setMatrix(PdfDictionary template, PdfDictionary annotDictionary) { + final IPdfPrimitive? bbox = PdfCrossTable.dereference( + template[PdfDictionaryProperties.bBox], + ); + if (bbox != null && bbox is PdfArray) { + if (annotDictionary.containsKey(PdfDictionaryProperties.rotate)) { + final IPdfPrimitive? rotate = PdfCrossTable.dereference( + annotDictionary[PdfDictionaryProperties.rotate], + ); + if (rotate is PdfNumber && rotate.value != 0) { + int rotateAngle = rotate.value!.toInt(); + if (rotateAngle == 0) { + rotateAngle = rotateAngle * 90; + } + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + matrix.rotate(rotateAngle.toDouble()); + final PdfArray mMatrix = PdfArray(matrix.matrix.elements); + template[PdfDictionaryProperties.matrix] = mMatrix; + } + } else { + final List elements = [ + 1, + 0, + 0, + 1, + -(bbox[0]! as PdfNumber).value!, + -(bbox[1]! as PdfNumber).value!, + ]; + template[PdfDictionaryProperties.matrix] = PdfArray(elements); + } + } + } + + PdfDictionary _getAppearance(PdfDictionary appearance, XmlElement element) { + final XmlName elementName = element.name; + switch (elementName.local) { + case XfdfProperties.stream: + final PdfStream stream = _getStream(element); + final PdfReferenceHolder holder = PdfReferenceHolder(stream); + _addKey(holder, appearance, element); + break; + case XfdfProperties.dict: + final PdfDictionary dictionary = _getDictionary(element); + final PdfReferenceHolder holder = PdfReferenceHolder(dictionary); + _addKey(holder, appearance, element); + break; + case XfdfProperties.array: + final PdfArray array = _getArray(element); + _addKey(array, appearance, element); + break; + case XfdfProperties.fixed: + final PdfNumber? floatNumber = _getFixed(element); + _addKey(floatNumber, appearance, element); + break; + case XfdfProperties.int: + final PdfNumber? intNumber = _getInt(element); + _addKey(intNumber, appearance, element); + break; + case XfdfProperties.string: + final PdfString? mstring = _getString(element); + _addKey(mstring, appearance, element); + break; + case XfdfProperties.name: + final PdfName? name = _getName(element); + _addKey(name, appearance, element); + break; + case XfdfProperties.bool: + final PdfBoolean? boolean = _getBoolean(element); + _addKey(boolean, appearance, element); + break; + case XfdfProperties.data: + final List? data = _getData(element); + if (data != null && data.isNotEmpty) { + if (appearance is PdfStream) { + appearance.data = data; + if (!appearance.containsKey(PdfDictionaryProperties.type) && + !appearance.containsKey(PdfDictionaryProperties.subtype)) { + appearance.decompress(); + } + bool isImage = false; + if (appearance.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? subtype = PdfCrossTable.dereference( + appearance[PdfDictionaryProperties.subtype], + ); + if (subtype != null && + subtype is PdfName && + subtype.name == PdfDictionaryProperties.image) { + isImage = true; + } + } + if (isImage) { + appearance.compress = false; + } else { + if (appearance.containsKey(PdfDictionaryProperties.length)) { + appearance.remove(PdfDictionaryProperties.length); + } + if (appearance.containsKey(PdfDictionaryProperties.filter)) { + appearance.remove(PdfDictionaryProperties.filter); + } + } + } + } + break; + } + + return appearance; + } + + void _addMeasureDictionary( + PdfDictionary annotDictionary, + XmlElement element, + ) { + XmlElement? measurement; + XmlElement? area; + XmlElement? distance; + XmlElement? xformat; + for (final XmlNode childNode in element.children) { + if (childNode is XmlElement) { + final XmlName childName = childNode.name; + if (childName.local.toLowerCase() == 'measure') { + measurement = childNode; + break; + } + } + } + final PdfDictionary measureDictionary = PdfDictionary(); + final PdfArray dArray = PdfArray(); + final PdfArray aArray = PdfArray(); + final PdfArray xArray = PdfArray(); + final PdfDictionary dDict = PdfDictionary(); + final PdfDictionary aDict = PdfDictionary(); + final PdfDictionary xDict = PdfDictionary(); + measureDictionary.items![PdfName(PdfDictionaryProperties.a)] = aArray; + measureDictionary.items![PdfName(PdfDictionaryProperties.d)] = dArray; + measureDictionary.items![PdfName(PdfDictionaryProperties.x)] = xArray; + if (measurement != null) { + measureDictionary.setName( + PdfDictionaryProperties.type, + PdfDictionaryProperties.measure, + ); + if (measurement.attributes.isNotEmpty) { + final String? attribute = measurement.getAttribute('rateValue'); + if (!isNullOrEmpty(attribute)) { + measureDictionary.setString(PdfDictionaryProperties.r, attribute); + } + } + for (final XmlNode childNode in measurement.children) { + if (childNode is XmlElement) { + final XmlName newElement = childNode.name; + if (newElement.local.toLowerCase() == 'area') { + area = childNode; + } + if (newElement.local.toLowerCase() == 'distance') { + distance = childNode; + } + if (newElement.local.toLowerCase() == 'xformat') { + xformat = childNode; + } + } + } + } + if (xformat != null) { + _addElements(xformat, xDict); + xArray.add(xDict); + } + if (area != null) { + _addElements(area, aDict); + aArray.add(aDict); + } + if (distance != null) { + _addElements(distance, dDict); + dArray.add(dDict); + } + if (measureDictionary.items!.isNotEmpty && + measureDictionary.containsKey(PdfDictionaryProperties.type)) { + annotDictionary.items![PdfName( + PdfDictionaryProperties.measure, + )] = PdfReferenceHolder(measureDictionary); + } + } + + void _addElements(XmlElement element, PdfDictionary dictionary) { + if (element.attributes.isNotEmpty) { + String? attribute = element.getAttribute('d'); + if (attribute != null) { + final double? d = double.tryParse(attribute); + if (d != null) { + dictionary.setProperty( + PdfName(PdfDictionaryProperties.d), + PdfNumber(d), + ); + } + } + attribute = element.getAttribute(PdfDictionaryProperties.c.toLowerCase()); + if (attribute != null) { + final double? c = double.tryParse(attribute); + if (c != null) { + dictionary.setProperty( + PdfName(PdfDictionaryProperties.c), + PdfNumber(c), + ); + } + } + attribute = element.getAttribute('rt'); + if (attribute != null) { + dictionary.items![PdfName('RT')] = PdfString(attribute); + } + attribute = element.getAttribute('rd'); + if (attribute != null) { + dictionary.items![PdfName(PdfDictionaryProperties.rd)] = PdfString( + attribute, + ); + } + attribute = element.getAttribute('ss'); + if (attribute != null) { + dictionary.items![PdfName('SS')] = PdfString(attribute); + } + attribute = element.getAttribute(PdfDictionaryProperties.u.toLowerCase()); + if (attribute != null) { + dictionary.items![PdfName(PdfDictionaryProperties.u)] = PdfString( + attribute, + ); + } + attribute = element.getAttribute(PdfDictionaryProperties.f.toLowerCase()); + if (attribute != null) { + dictionary.items![PdfName(PdfDictionaryProperties.f)] = PdfName( + attribute, + ); + } + attribute = element.getAttribute('fd'); + if (attribute != null) { + dictionary.items![PdfName('FD')] = PdfBoolean(attribute == 'yes'); + } + } + } + + PdfStream _getStream(XmlElement element) { + final PdfStream stream = PdfStream(); + if (element.children.isNotEmpty) { + for (final XmlNode child in element.children) { + if (child is XmlElement) { + _getAppearance(stream, child); + } + } + } + return stream; + } + + void _addKey( + IPdfPrimitive? primitive, + PdfDictionary dictionary, + XmlElement element, + ) { + if (primitive != null && element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(XfdfProperties.key); + if (!isNullOrEmpty(attribute)) { + dictionary.setProperty(attribute, primitive); + } + } + } + + PdfDictionary _getDictionary(XmlElement element) { + final PdfDictionary dictionary = PdfDictionary(); + if (element.children.isNotEmpty) { + for (final XmlNode child in element.children) { + if (child is XmlElement) { + _getAppearance(dictionary, child); + } + } + } + return dictionary; + } + + PdfArray _getArray(XmlElement element) { + final PdfArray array = PdfArray(); + if (element.children.isNotEmpty) { + for (final XmlNode child in element.children) { + if (child is XmlElement) { + _addArrayElements(array, child); + } + } + } + return array; + } + + PdfNumber? _getFixed(XmlElement element) { + if (element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(XfdfProperties.val); + if (!isNullOrEmpty(attribute)) { + final double? value = double.tryParse(attribute!); + if (value != null) { + return PdfNumber(value); + } + } + } + return null; + } + + PdfNumber? _getInt(XmlElement element) { + // int value; + if (element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(XfdfProperties.val); + if (!isNullOrEmpty(attribute)) { + final int? value = int.tryParse(attribute!); + if (value != null) { + return PdfNumber(value); + } + } + } + return null; + } + + void _addArrayElements(PdfArray array, XmlElement element) { + final XmlName elementName = element.name; + switch (elementName.local) { + case XfdfProperties.stream: + final PdfStream stream = _getStream(element); + _addArrayElement(array, PdfReferenceHolder(stream)); + break; + case XfdfProperties.dict: + final PdfDictionary dictionary = _getDictionary(element); + _addArrayElement(array, PdfReferenceHolder(dictionary)); + break; + case XfdfProperties.array: + final PdfArray pdfArray = _getArray(element); + _addArrayElement(array, pdfArray); + break; + case XfdfProperties.fixed: + final PdfNumber? floatValue = _getFixed(element); + _addArrayElement(array, floatValue); + break; + case XfdfProperties.int: + final PdfNumber? intValue = _getInt(element); + _addArrayElement(array, intValue); + break; + case XfdfProperties.name: + final PdfName? name = _getName(element); + _addArrayElement(array, name); + break; + case XfdfProperties.bool: + final PdfBoolean? boolean = _getBoolean(element); + _addArrayElement(array, boolean); + break; + case XfdfProperties.string: + final PdfString? mstring = _getString(element); + _addArrayElement(array, mstring); + break; + } + } + + void _addArrayElement(PdfArray array, IPdfPrimitive? primitive) { + if (primitive != null) { + array.add(primitive); + } + } + + PdfName? _getName(XmlElement element) { + if (element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(XfdfProperties.val); + if (!isNullOrEmpty(attribute)) { + return PdfName(attribute); + } + } + return null; + } + + PdfBoolean? _getBoolean(XmlElement element) { + if (element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(XfdfProperties.val); + if (!isNullOrEmpty(attribute)) { + return PdfBoolean(attribute!.toLowerCase() == 'true'); + } + } + return null; + } + + PdfString? _getString(XmlElement element) { + if (element.attributes.isNotEmpty) { + final String? attribute = element.getAttribute(XfdfProperties.val); + if (!isNullOrEmpty(attribute)) { + return PdfString(attribute!); + } else if (element.name.toXmlString().contains(XfdfProperties.string)) { + final List? data = _getData(element); + if (data != null && data.isNotEmpty) { + return PdfString.fromBytes(data); + } + } + } + return null; + } + + List? _getData(XmlElement element) { + if (!isNullOrEmpty(element.innerText) && element.attributes.isNotEmpty) { + final String? mode = element.getAttribute(XfdfProperties.mode); + final String? encoding = element.getAttribute('ENCODING'); + if (!isNullOrEmpty(mode) && !isNullOrEmpty(encoding)) { + if (mode == XfdfProperties.filtered && + encoding == XfdfProperties.ascii) { + return [...utf8.encode(element.innerText)]; + } else if (mode == XfdfProperties.raw && + encoding == XfdfProperties.hex) { + return _hexToBytes(element.innerText); + } + } else if (!isNullOrEmpty(encoding) && encoding == XfdfProperties.hex) { + return _hexToBytes(element.innerText); + } + } + return null; + } + + List _hexToBytes(String hexString) { + final List bytes = []; + for (int i = 0; i < hexString.length; i += 2) { + final String hex = hexString.substring(i, i + 2); + bytes.add(int.parse(hex, radix: 16)); + } + return bytes; + } + + void _addReferenceToGroup( + PdfReferenceHolder holder, + PdfDictionary dictionary, + ) { + IPdfPrimitive? name = PdfCrossTable.dereference(dictionary['NM']); + if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { + _groupReferences ??= {}; + _groupReferences![name.value!] = holder; + if (dictionary.containsKey(PdfDictionaryProperties.irt)) { + _groupHolders ??= []; + _groupHolders!.add(dictionary); + } + } else if (name == null) { + if (dictionary.containsKey(PdfDictionaryProperties.irt)) { + name = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.irt], + ); + } + if (name != null && name is PdfString && !isNullOrEmpty(name.value)) { + if (_groupReferences != null && + _groupReferences!.containsKey(name.value)) { + final PdfReferenceHolder referenceHolder = + _groupReferences![name.value]!; + dictionary[PdfDictionaryProperties.irt] = referenceHolder; + } + } + } + } + + String? _getFormattedString(String? value) { + if (!isNullOrEmpty(value)) { + value = value!.replaceAll('<', '<'); + value = value.replaceAll('>', '>'); + } + return value; + } + + void _addString(PdfDictionary dictionary, String key, String? value) { + if (!isNullOrEmpty(value)) { + dictionary.setString(key, value); + } + } + + void _addInt(PdfDictionary dictionary, String key, String? value) { + if (!isNullOrEmpty(value)) { + final double? number = double.tryParse(value!); + if (number != null) { + dictionary.setNumber(key, number.toInt()); + } + } + } + + void _addFloatPoints(PdfDictionary dictionary, List points, String key) { + if (points.isNotEmpty) { + dictionary.setProperty(key, PdfArray(points)); + } + } + + void _addFloat(PdfDictionary dictionary, String key, String value) { + if (!isNullOrEmpty(value)) { + final int? number = int.tryParse(value); + if (number != null) { + dictionary.setNumber(key, number); + } + } + } + + PdfArray? _getColorArray(String value) { + final String hex = value.replaceAll('#', ''); + final int r = int.parse(hex.substring(0, 2), radix: 16); + final int g = int.parse(hex.substring(2, 4), radix: 16); + final int b = int.parse(hex.substring(4, hex.length), radix: 16); + if (r >= 0 && g >= 0 && b >= 0) { + final PdfArray colorArray = PdfArray(); + colorArray.add(PdfNumber(r / 255)); + colorArray.add(PdfNumber(g / 255)); + colorArray.add(PdfNumber(b / 255)); + return colorArray; + } + return null; + } + + ///Internal method + static PdfAnnotationFlags mapAnnotationFlags(String flag) { + PdfAnnotationFlags type; + switch (flag.toLowerCase()) { + case 'hidden': + type = PdfAnnotationFlags.hidden; + break; + case 'invisible': + type = PdfAnnotationFlags.invisible; + break; + case 'locked': + type = PdfAnnotationFlags.locked; + break; + case 'norotate': + type = PdfAnnotationFlags.noRotate; + break; + case 'noview': + type = PdfAnnotationFlags.noView; + break; + case 'nozoom': + type = PdfAnnotationFlags.noZoom; + break; + case 'print': + type = PdfAnnotationFlags.print; + break; + case 'readonly': + type = PdfAnnotationFlags.readOnly; + break; + case 'togglenoview': + type = PdfAnnotationFlags.toggleNoView; + break; + default: + type = PdfAnnotationFlags.defaultFlag; + break; + } + return type; + } + + void _addLineEndStyle(XmlElement element, PdfDictionary annotDictionary) { + if (element.attributes.isNotEmpty) { + String beginLineStyle = ''; + final String? headAttribute = element.getAttribute('head'); + if (!isNullOrEmpty(headAttribute)) { + beginLineStyle = getEnumName(mapLineEndingStyle(headAttribute!)); + } + String endLineStyle = ''; + final String? tailAttribute = element.getAttribute('tail'); + if (!isNullOrEmpty(tailAttribute)) { + endLineStyle = getEnumName(mapLineEndingStyle(tailAttribute!)); + } + if (!isNullOrEmpty(beginLineStyle)) { + if (!isNullOrEmpty(endLineStyle)) { + final PdfArray lineEndingStyles = PdfArray(); + lineEndingStyles.add(PdfName(beginLineStyle)); + lineEndingStyles.add(PdfName(endLineStyle)); + annotDictionary.setProperty( + PdfDictionaryProperties.le, + lineEndingStyles, + ); + } else { + annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); + } + } else if (!isNullOrEmpty(endLineStyle)) { + annotDictionary.setName(PdfDictionaryProperties.le, beginLineStyle); + } + } + } + + /// Internal Field. + static PdfLineEndingStyle mapLineEndingStyle(String style) { + PdfLineEndingStyle lineStyle; + switch (style.toLowerCase()) { + case 'butt': + lineStyle = PdfLineEndingStyle.butt; + break; + case 'circle': + lineStyle = PdfLineEndingStyle.circle; + break; + case 'closedarrow': + lineStyle = PdfLineEndingStyle.closedArrow; + break; + case 'diamond': + lineStyle = PdfLineEndingStyle.diamond; + break; + case 'openarrow': + lineStyle = PdfLineEndingStyle.openArrow; + break; + case 'rclosedarrow': + lineStyle = PdfLineEndingStyle.rClosedArrow; + break; + case 'ropenarrow': + lineStyle = PdfLineEndingStyle.rOpenArrow; + break; + case 'slash': + lineStyle = PdfLineEndingStyle.slash; + break; + case 'square': + lineStyle = PdfLineEndingStyle.square; + break; + default: + lineStyle = PdfLineEndingStyle.none; + break; + } + return lineStyle; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/color_space/pdf_icc_color_profile.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/color_space/pdf_icc_color_profile.dart index e4322d613..7488301e0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/color_space/pdf_icc_color_profile.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/color_space/pdf_icc_color_profile.dart @@ -1,44 +1,44 @@ -import 'dart:convert'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_stream.dart'; - -/// Class represents the ICC Colorspace. -//Used during creation of documents with PDF/A1B compliance. -class PdfICCColorProfile implements IPdfWrapper { - /// Initializes a new instance of the [PdfICCColorProfile] class. - PdfICCColorProfile() : super() { - stream.compress = true; - stream.setProperty( - PdfDictionaryProperties.filter, - PdfName(PdfDictionaryProperties.flateDecode), - ); - stream.setProperty(PdfDictionaryProperties.n, PdfNumber(3)); - stream.beginSave = _beginSaveStream; - } - - /// internal field - final PdfStream stream = PdfStream(); - - /// internal field - final String profileData = - 'AAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1TRlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVzYwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAAAlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAkbHVtaQAAA/gAAAAUbWVhcwAABAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAABDwAAAgMYlRSQwAABDwAAAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNrYXJkIENvbXBhbnkAAGRlc2MAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzUQABAAAAARbMWFlaIAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9kZXNjAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4AFF8uABDPFAAD7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521lYXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//'; - - //Implementation. - //Handles the BeginSave event of the Stream control. - void _beginSaveStream(Object sender, SavePdfPrimitiveArgs? args) { - stream.clearStream(); - stream.data = base64.decode(profileData).toList(); - } - - /// internal property - IPdfPrimitive? get element => stream; - - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } -} +import 'dart:convert'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_stream.dart'; + +/// Class represents the ICC Colorspace. +//Used during creation of documents with PDF/A1B compliance. +class PdfICCColorProfile implements IPdfWrapper { + /// Initializes a new instance of the [PdfICCColorProfile] class. + PdfICCColorProfile() : super() { + stream.compress = true; + stream.setProperty( + PdfDictionaryProperties.filter, + PdfName(PdfDictionaryProperties.flateDecode), + ); + stream.setProperty(PdfDictionaryProperties.n, PdfNumber(3)); + stream.beginSave = _beginSaveStream; + } + + /// internal field + final PdfStream stream = PdfStream(); + + /// internal field + final String profileData = + 'AAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1TRlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVzYwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAAAlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAkbHVtaQAAA/gAAAAUbWVhcwAABAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAABDwAAAgMYlRSQwAABDwAAAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNrYXJkIENvbXBhbnkAAGRlc2MAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzUQABAAAAARbMWFlaIAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9kZXNjAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4AFF8uABDPFAAD7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521lYXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf//'; + + //Implementation. + //Handles the BeginSave event of the Stream control. + void _beginSaveStream(Object sender, SavePdfPrimitiveArgs? args) { + stream.clearStream(); + stream.data = base64.decode(profileData).toList(); + } + + /// internal property + IPdfPrimitive? get element => stream; + + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_reader.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_reader.dart index 48c9f5b55..5fb69a098 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_reader.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_reader.dart @@ -1,783 +1,783 @@ -import 'dart:math'; - -import 'compressed_stream_writer.dart'; -import 'decompressor_huffman_tree.dart'; - -/// internal class -class CompressedStreamReader { - /// internal constructor - CompressedStreamReader(List data, [bool? noWrap]) { - _data = data; - _noWrap = noWrap ?? false; - _initialize(); - } - - //Fields - late List _data; - late bool _noWrap; - late int _offset; - late int _buffer; - late List _tempBuffer; - late int _maxUnsingedLimit; - late int _defHeaderMethodMask; - late int _windowSize; - late int _defHeaderInfoMask; - late int _maxValue; - late int _defHeaderFlagsFdict; - late bool _canReadNextBlock; - late bool _readingUncompressed; - late int _uncompressedDataLength; - late int _currentPosition; - int _dataLength = 0; - bool _canReadMoreData = true; - bool _checkSumRead = false; - int _checkSum = 1; - List? _blockBuffer; - DecompressorHuffmanTree? _currentLengthTree; - DecompressorHuffmanTree? _currentDistanceTree; - - /// internal field - static const List defHuffmanDyntreeRepeatBits = [2, 3, 7]; - - /// internal field - static const List defHuffmanDyntreeRepeatMinimums = [3, 3, 11]; - - /// internal field - static const List defHuffmanRepeatLengthBase = [ - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 13, - 15, - 17, - 19, - 23, - 27, - 31, - 35, - 43, - 51, - 59, - 67, - 83, - 99, - 115, - 131, - 163, - 195, - 227, - 258, - ]; - - /// internal field - static const List defHuffmanRepeatLengthExtension = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0, - ]; - - /// internal field - static const List defHuffmanRepeatDistanseBase = [ - 1, - 2, - 3, - 4, - 5, - 7, - 9, - 13, - 17, - 25, - 33, - 49, - 65, - 97, - 129, - 193, - 257, - 385, - 513, - 769, - 1025, - 1537, - 2049, - 3073, - 4097, - 6145, - 8193, - 12289, - 16385, - 24577, - ]; - - /// internal field - static const List defHuffmanRepeatDistanseExtension = [ - 0, - 0, - 0, - 0, - 1, - 1, - 2, - 2, - 3, - 3, - 4, - 4, - 5, - 5, - 6, - 6, - 7, - 7, - 8, - 8, - 9, - 9, - 10, - 10, - 11, - 11, - 12, - 12, - 13, - 13, - ]; - - /// internal field - static const int defHuffmanRepeatMax = 258; - - /// internal field - static const int defHuffmanEndBlock = 256; - - /// internal field - static const int defHuffmanLengthMinimumCode = 257; - - /// internal field - static const int defHuffmanLengthMaximumCode = 285; - - /// internal field - late int bufferedBits; - - //Implementation - void _initialize() { - _offset = 0; - bufferedBits = 0; - _buffer = 0; - _windowSize = 0; - _maxUnsingedLimit = 4294967295; - _tempBuffer = List.filled(4, 0, growable: true); - _canReadNextBlock = true; - _canReadMoreData = true; - _readingUncompressed = false; - _defHeaderMethodMask = 15 << 8; - _defHeaderInfoMask = 240 << 8; - _maxValue = 65535; - _defHeaderFlagsFdict = 32; - _currentPosition = 0; - _blockBuffer = List.filled(65535, 0, growable: true); - if (!_noWrap) { - _readZlibHeader(); - } - _decodeBlockHeader(); - } - - void _readZlibHeader() { - final int header = _readInt16(); - if (header == -1) { - throw ArgumentError.value( - header, - 'Header of the stream can not be read.', - ); - } - if (header % 31 != 0) { - throw ArgumentError.value(header, 'Header checksum illegal'); - } - if ((header & _defHeaderMethodMask) != (8 << 8)) { - throw ArgumentError.value(header, 'Unsupported compression method.'); - } - _windowSize = pow(2, ((header & _defHeaderInfoMask) >> 12) + 8) as int; - if (_windowSize > _maxValue) { - throw ArgumentError.value( - header, - 'Unsupported window size for deflate compression method.', - ); - } - if ((header & _defHeaderFlagsFdict) >> 5 == 1) { - throw ArgumentError.value( - header, - 'Custom dictionary is not supported at the moment.', - ); - } - } - - bool _decodeBlockHeader() { - if (!_canReadNextBlock) { - return false; - } - final int finalBlock = _readBits(1); - if (finalBlock == -1) { - return false; - } - final int blockType = _readBits(2); - if (blockType == -1) { - return false; - } - _canReadNextBlock = finalBlock == 0; - switch (blockType) { - case 0: - _readingUncompressed = true; - _skipToBoundary(); - final int length = _readInt16Inverted(); - final int lengthComplement = _readInt16Inverted(); - - if (length != (lengthComplement ^ 0xffff)) { - throw const FormatException('Wrong block length.'); - } - - if (length > _maxValue) { - throw ArgumentError.value( - length, - 'Uncompressed block length can not be more than 65535.', - ); - } - - _uncompressedDataLength = length; - _currentLengthTree = null; - _currentDistanceTree = null; - break; - case 1: - _readingUncompressed = false; - _uncompressedDataLength = -1; - _currentLengthTree = DecompressorHuffmanTree.lengthTree; - _currentDistanceTree = DecompressorHuffmanTree.distanceTree; - break; - case 2: - _readingUncompressed = false; - _uncompressedDataLength = -1; - final Map result = _decodeDynamicHeader( - _currentLengthTree, - _currentDistanceTree, - ); - _currentLengthTree = result['lengthTree'] as DecompressorHuffmanTree; - _currentDistanceTree = - result['distanceTree'] as DecompressorHuffmanTree; - break; - default: - throw ArgumentError.value(blockType, 'Wrong block type'); - } - return true; - } - - Map _decodeDynamicHeader( - DecompressorHuffmanTree? lengthTree, - DecompressorHuffmanTree? distanceTree, - ) { - List arrDecoderCodeLengths; - List arrResultingCodeLengths; - - int bLastSymbol = 0; - int iLengthsCount = _readBits(5); - int iDistancesCount = _readBits(5); - int iCodeLengthsCount = _readBits(4); - - if (iLengthsCount < 0 || iDistancesCount < 0 || iCodeLengthsCount < 0) { - throw ArgumentError.value(iLengthsCount, 'Wrong dynamic huffman codes.'); - } - - iLengthsCount += 257; - iDistancesCount += 1; - - final int iResultingCodeLengthsCount = iLengthsCount + iDistancesCount; - arrResultingCodeLengths = List.filled( - iResultingCodeLengthsCount, - 0, - growable: true, - ); - arrDecoderCodeLengths = List.filled(19, 0, growable: true); - iCodeLengthsCount += 4; - int iCurrentCode = 0; - - while (iCurrentCode < iCodeLengthsCount) { - final int len = _readBits(3); - - if (len < 0) { - throw ArgumentError.value(len, 'Wrong dynamic huffman codes.'); - } - - arrDecoderCodeLengths[CompressedStreamWriter - .defHuffmanDyntreeCodeLengthsOrder[iCurrentCode++]] = len.toUnsigned( - 8, - ); - } - final DecompressorHuffmanTree treeInternalDecoder = DecompressorHuffmanTree( - arrDecoderCodeLengths, - ); - - iCurrentCode = 0; - - int symbol = 0; - for (;;) { - bool bNeedBreak = false; - - while (((symbol = treeInternalDecoder.unpackSymbol(this)) & ~15) == 0) { - arrResultingCodeLengths[iCurrentCode++] = - bLastSymbol = symbol.toUnsigned(8); - - if (iCurrentCode == iResultingCodeLengthsCount) { - bNeedBreak = true; - break; - } - } - - if (bNeedBreak) { - break; - } - - if (symbol < 0) { - throw ArgumentError.value(symbol, 'Wrong dynamic huffman codes.'); - } - - if (symbol >= 17) { - bLastSymbol = 0; - } else if (iCurrentCode == 0) { - throw ArgumentError.value(iCurrentCode, 'Wrong dynamic huffman codes.'); - } - - final int iRepSymbol = symbol - 16; - final int bits = defHuffmanDyntreeRepeatBits[iRepSymbol]; - - int count = _readBits(bits); - - if (count < 0) { - throw ArgumentError.value(count, 'Wrong dynamic huffman codes.'); - } - - count += defHuffmanDyntreeRepeatMinimums[iRepSymbol]; - - if (iCurrentCode + count > iResultingCodeLengthsCount) { - throw ArgumentError.value(iCurrentCode, 'Wrong dynamic huffman codes.'); - } - - while (count-- > 0) { - arrResultingCodeLengths[iCurrentCode++] = bLastSymbol; - } - - if (iCurrentCode == iResultingCodeLengthsCount) { - break; - } - } - - final List tempLengthArray = List.filled( - iLengthsCount, - 0, - growable: true, - ); - List.copyRange( - tempLengthArray, - 0, - arrResultingCodeLengths, - 0, - iLengthsCount, - ); - lengthTree = DecompressorHuffmanTree(tempLengthArray); - - final List tempDistanceArray = List.filled( - iDistancesCount, - 0, - growable: true, - ); - List.copyRange( - tempDistanceArray, - 0, - arrResultingCodeLengths, - iLengthsCount, - iLengthsCount + iDistancesCount, - ); - distanceTree = DecompressorHuffmanTree(tempDistanceArray); - - return { - 'lengthTree': lengthTree, - 'distanceTree': distanceTree, - }; - } - - int _readInt16() { - int result = _readBits(8) << 8; - result |= _readBits(8); - return result; - } - - int _readBits(int count) { - final int result = peekBits(count); - if (result == -1) { - return -1; - } - bufferedBits -= count; - _buffer >>= count; - return result; - } - - /// internal method - int peekBits(int count) { - if (count < 0 || count > 32) { - throw ArgumentError.value(count, 'count'); - } - if (bufferedBits < count) { - _fillBuffer(); - } - if (bufferedBits < count) { - return -1; - } - final int bitmask = (~(_maxUnsingedLimit << count)).toUnsigned(32); - final int result = _buffer & bitmask; - return result; - } - - void _fillBuffer() { - final int length = - 4 - (bufferedBits >> 3) - (((bufferedBits & 7) != 0) ? 1 : 0); - if (length == 0) { - return; - } - final Map readResult = _readBytes(_tempBuffer, 0, length); - _tempBuffer = readResult['buffer'] as List; - final int bytesRead = readResult['count'] as int; - for (int i = 0; i < bytesRead; i++) { - _buffer |= _tempBuffer[i].toUnsigned(32) << bufferedBits; - bufferedBits += 8; - } - } - - int _readInt16Inverted() { - int result = _readBits(8); - result |= _readBits(8) << 8; - return result; - } - - int _readInt32() { - int result = (_readBits(8) << 24).toUnsigned(32); - result |= (_readBits(8) << 16).toUnsigned(32); - result |= (_readBits(8) << 8).toUnsigned(32); - result |= _readBits(8).toUnsigned(32); - return result; - } - - Map _readBytes(List buffer, int offset, int count) { - int readedCount = 0; - if (offset < buffer.length && (offset + count) <= buffer.length) { - for (int i = 0; i < count; i++) { - final Map readResult = _readByte(); - if (readResult['hasRead'] as bool) { - buffer[offset] = readResult['result'] as int; - offset++; - readedCount++; - } else { - break; - } - } - } - return {'count': readedCount, 'buffer': buffer}; - } - - Map _readByte() { - if (_offset < _data.length) { - final int result = _data[_offset]; - _offset = _offset + 1; - return {'hasRead': true, 'result': result}; - } else { - return {'hasRead': false, 'result': -1}; - } - } - - void _skipToBoundary() { - _buffer >>= bufferedBits & 7; - bufferedBits &= ~7; - } - - /// internal method - void skipBits(int count) { - if (count < 0) { - throw ArgumentError.value(count, 'Bits count can not be less than zero.'); - } - if (count == 0) { - return; - } - if (count >= bufferedBits) { - count -= bufferedBits; - bufferedBits = 0; - _buffer = 0; - // if something left, skip it. - if (count > 0) { - // Skip entire bytes. - _offset = _offset + count >> 3; - count &= 7; - // Skip bits. - if (count > 0) { - _fillBuffer(); - bufferedBits -= count; - _buffer >>= count; - } - } - } else { - bufferedBits -= count; - _buffer >>= count; - } - } - - /// internal method - Map read(List buffer, int offset, int length) { - if (offset < 0 || offset > buffer.length - 1) { - throw ArgumentError.value( - offset, - 'Offset does not belong to specified buffer.', - ); - } - if (length < 0 || length > buffer.length - offset) { - throw ArgumentError.value(length, 'Length is illegal.'); - } - final int initialLength = length; - while (length > 0) { - if (_currentPosition < _dataLength) { - final int inBlockPosition = _currentPosition % _maxValue; - int dataToCopy = min( - _maxValue - inBlockPosition, - _dataLength - _currentPosition, - ); - dataToCopy = min(dataToCopy, length); - - // Copy data. - List.copyRange( - buffer, - offset, - _blockBuffer!, - inBlockPosition, - inBlockPosition + dataToCopy, - ); - _currentPosition += dataToCopy; - offset += dataToCopy; - length -= dataToCopy; - } else { - if (!_canReadMoreData) { - break; - } - - final int oldDataLength = _dataLength; - - if (!_readingUncompressed) { - if (!_readHuffman()) { - break; - } - } else { - if (_uncompressedDataLength == 0) { - // If there is no more data in stream, just exit. - if (!(_canReadMoreData = _decodeBlockHeader())) { - break; - } - } else { - // Position of the data end in block buffer. - final int inBlockPosition = _dataLength % _maxValue; - final int dataToRead = min( - _uncompressedDataLength, - _maxValue - inBlockPosition, - ); - final int dataRead = _readPackedBytes( - _blockBuffer!, - inBlockPosition, - dataToRead, - ); - if (dataToRead != dataRead) { - throw ArgumentError.value( - dataToRead, - 'Not enough data in stream.', - ); - } - _uncompressedDataLength -= dataRead; - _dataLength += dataRead; - } - } - if (oldDataLength < _dataLength) { - final int start = oldDataLength % _maxValue; - final int end = _dataLength % _maxValue; - - if (start < end) { - _checksumUpdate(_blockBuffer, start, end - start); - } else { - _checksumUpdate(_blockBuffer, start, _maxValue - start); - - if (end > 0) { - _checksumUpdate(_blockBuffer, 0, end); - } - } - } - } - } - if (!_canReadMoreData && !_checkSumRead && !_noWrap) { - _skipToBoundary(); - if (_readInt32() != _checkSum) { - throw const FormatException('Checksum check failed.'); - } - _checkSumRead = true; - } - - return { - 'length': initialLength - length, - 'buffer': buffer, - }; - } - - void _checksumUpdate(List? buffer, int offset, int length) { - _checkSum = CompressedStreamWriter.checksumUpdate( - _checkSum, - buffer, - offset, - length, - ); - } - - int _readPackedBytes(List buffer, int offset, int length) { - if (offset < 0 || offset > buffer.length - 1) { - throw ArgumentError.value( - offset, - 'Offset cannot be less than zero or greater than buffer length - 1.', - ); - } - - if (length < 0) { - throw ArgumentError.value(length, 'Length can not be less than zero.'); - } - - if (length > buffer.length - offset) { - throw ArgumentError.value(length, 'Length is too large.'); - } - - if ((bufferedBits & 7) != 0) { - throw ArgumentError.value( - buffer, - 'Reading of unalligned data is not supported.', - ); - } - - if (length == 0) { - return 0; - } - - int result = 0; - - while (bufferedBits > 0 && length > 0) { - buffer[offset++] = _buffer.toUnsigned(8); - bufferedBits -= 8; - _buffer >>= 8; - length--; - result++; - } - - if (length > 0) { - final Map value = _readBytes(buffer, offset, length); - final int val = value['count'] as int; - result += val; - buffer = value['buffer'] as List; - } - return result; - } - - bool _readHuffman() { - int free = _maxValue - (_dataLength - _currentPosition); - bool dataRead = false; - int symbol = 0; - while (free >= defHuffmanRepeatMax) { - while (((symbol = _currentLengthTree!.unpackSymbol(this)) & ~0xff) == 0) { - _blockBuffer![_dataLength++ % _maxValue] = symbol.toUnsigned(8); - dataRead = true; - if (--free < defHuffmanRepeatMax) { - return true; - } - } - - if (symbol < defHuffmanLengthMinimumCode) { - if (symbol < defHuffmanEndBlock) { - throw ArgumentError.value(symbol, 'Illegal code.'); - } - _canReadMoreData = _decodeBlockHeader(); - return dataRead | _canReadMoreData; - } - - if (symbol > defHuffmanLengthMaximumCode) { - throw ArgumentError.value(symbol, 'Illegal repeat code length.'); - } - - int iRepeatLength = - defHuffmanRepeatLengthBase[symbol - defHuffmanLengthMinimumCode]; - - int iRepeatExtraBits = - defHuffmanRepeatLengthExtension[symbol - defHuffmanLengthMinimumCode]; - - if (iRepeatExtraBits > 0) { - final int extra = _readBits(iRepeatExtraBits); - if (extra < 0) { - throw ArgumentError.value(extra, 'Wrong data.'); - } - iRepeatLength += extra; - } - - // Unpack repeat distance. - symbol = _currentDistanceTree!.unpackSymbol(this); - - if (symbol < 0 || symbol > defHuffmanRepeatDistanseBase.length) { - throw ArgumentError.value(symbol, 'Wrong distance code.'); - } - int iRepeatDistance = defHuffmanRepeatDistanseBase[symbol]; - iRepeatExtraBits = defHuffmanRepeatDistanseExtension[symbol]; - if (iRepeatExtraBits > 0) { - final int extra = _readBits(iRepeatExtraBits); - if (extra < 0) { - throw ArgumentError.value(extra, 'Wrong data.'); - } - iRepeatDistance += extra; - } - // Copy data in slow repeat mode - for (int i = 0; i < iRepeatLength; i++) { - _blockBuffer![_dataLength % _maxValue] = - _blockBuffer![(_dataLength - iRepeatDistance) % _maxValue]; - _dataLength++; - free--; - } - - dataRead = true; - } - - return dataRead; - } -} +import 'dart:math'; + +import 'compressed_stream_writer.dart'; +import 'decompressor_huffman_tree.dart'; + +/// internal class +class CompressedStreamReader { + /// internal constructor + CompressedStreamReader(List data, [bool? noWrap]) { + _data = data; + _noWrap = noWrap ?? false; + _initialize(); + } + + //Fields + late List _data; + late bool _noWrap; + late int _offset; + late int _buffer; + late List _tempBuffer; + late int _maxUnsingedLimit; + late int _defHeaderMethodMask; + late int _windowSize; + late int _defHeaderInfoMask; + late int _maxValue; + late int _defHeaderFlagsFdict; + late bool _canReadNextBlock; + late bool _readingUncompressed; + late int _uncompressedDataLength; + late int _currentPosition; + int _dataLength = 0; + bool _canReadMoreData = true; + bool _checkSumRead = false; + int _checkSum = 1; + List? _blockBuffer; + DecompressorHuffmanTree? _currentLengthTree; + DecompressorHuffmanTree? _currentDistanceTree; + + /// internal field + static const List defHuffmanDyntreeRepeatBits = [2, 3, 7]; + + /// internal field + static const List defHuffmanDyntreeRepeatMinimums = [3, 3, 11]; + + /// internal field + static const List defHuffmanRepeatLengthBase = [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 258, + ]; + + /// internal field + static const List defHuffmanRepeatLengthExtension = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0, + ]; + + /// internal field + static const List defHuffmanRepeatDistanseBase = [ + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, + 16385, + 24577, + ]; + + /// internal field + static const List defHuffmanRepeatDistanseExtension = [ + 0, + 0, + 0, + 0, + 1, + 1, + 2, + 2, + 3, + 3, + 4, + 4, + 5, + 5, + 6, + 6, + 7, + 7, + 8, + 8, + 9, + 9, + 10, + 10, + 11, + 11, + 12, + 12, + 13, + 13, + ]; + + /// internal field + static const int defHuffmanRepeatMax = 258; + + /// internal field + static const int defHuffmanEndBlock = 256; + + /// internal field + static const int defHuffmanLengthMinimumCode = 257; + + /// internal field + static const int defHuffmanLengthMaximumCode = 285; + + /// internal field + late int bufferedBits; + + //Implementation + void _initialize() { + _offset = 0; + bufferedBits = 0; + _buffer = 0; + _windowSize = 0; + _maxUnsingedLimit = 4294967295; + _tempBuffer = List.filled(4, 0, growable: true); + _canReadNextBlock = true; + _canReadMoreData = true; + _readingUncompressed = false; + _defHeaderMethodMask = 15 << 8; + _defHeaderInfoMask = 240 << 8; + _maxValue = 65535; + _defHeaderFlagsFdict = 32; + _currentPosition = 0; + _blockBuffer = List.filled(65535, 0, growable: true); + if (!_noWrap) { + _readZlibHeader(); + } + _decodeBlockHeader(); + } + + void _readZlibHeader() { + final int header = _readInt16(); + if (header == -1) { + throw ArgumentError.value( + header, + 'Header of the stream can not be read.', + ); + } + if (header % 31 != 0) { + throw ArgumentError.value(header, 'Header checksum illegal'); + } + if ((header & _defHeaderMethodMask) != (8 << 8)) { + throw ArgumentError.value(header, 'Unsupported compression method.'); + } + _windowSize = pow(2, ((header & _defHeaderInfoMask) >> 12) + 8) as int; + if (_windowSize > _maxValue) { + throw ArgumentError.value( + header, + 'Unsupported window size for deflate compression method.', + ); + } + if ((header & _defHeaderFlagsFdict) >> 5 == 1) { + throw ArgumentError.value( + header, + 'Custom dictionary is not supported at the moment.', + ); + } + } + + bool _decodeBlockHeader() { + if (!_canReadNextBlock) { + return false; + } + final int finalBlock = _readBits(1); + if (finalBlock == -1) { + return false; + } + final int blockType = _readBits(2); + if (blockType == -1) { + return false; + } + _canReadNextBlock = finalBlock == 0; + switch (blockType) { + case 0: + _readingUncompressed = true; + _skipToBoundary(); + final int length = _readInt16Inverted(); + final int lengthComplement = _readInt16Inverted(); + + if (length != (lengthComplement ^ 0xffff)) { + throw const FormatException('Wrong block length.'); + } + + if (length > _maxValue) { + throw ArgumentError.value( + length, + 'Uncompressed block length can not be more than 65535.', + ); + } + + _uncompressedDataLength = length; + _currentLengthTree = null; + _currentDistanceTree = null; + break; + case 1: + _readingUncompressed = false; + _uncompressedDataLength = -1; + _currentLengthTree = DecompressorHuffmanTree.lengthTree; + _currentDistanceTree = DecompressorHuffmanTree.distanceTree; + break; + case 2: + _readingUncompressed = false; + _uncompressedDataLength = -1; + final Map result = _decodeDynamicHeader( + _currentLengthTree, + _currentDistanceTree, + ); + _currentLengthTree = result['lengthTree'] as DecompressorHuffmanTree; + _currentDistanceTree = + result['distanceTree'] as DecompressorHuffmanTree; + break; + default: + throw ArgumentError.value(blockType, 'Wrong block type'); + } + return true; + } + + Map _decodeDynamicHeader( + DecompressorHuffmanTree? lengthTree, + DecompressorHuffmanTree? distanceTree, + ) { + List arrDecoderCodeLengths; + List arrResultingCodeLengths; + + int bLastSymbol = 0; + int iLengthsCount = _readBits(5); + int iDistancesCount = _readBits(5); + int iCodeLengthsCount = _readBits(4); + + if (iLengthsCount < 0 || iDistancesCount < 0 || iCodeLengthsCount < 0) { + throw ArgumentError.value(iLengthsCount, 'Wrong dynamic huffman codes.'); + } + + iLengthsCount += 257; + iDistancesCount += 1; + + final int iResultingCodeLengthsCount = iLengthsCount + iDistancesCount; + arrResultingCodeLengths = List.filled( + iResultingCodeLengthsCount, + 0, + growable: true, + ); + arrDecoderCodeLengths = List.filled(19, 0, growable: true); + iCodeLengthsCount += 4; + int iCurrentCode = 0; + + while (iCurrentCode < iCodeLengthsCount) { + final int len = _readBits(3); + + if (len < 0) { + throw ArgumentError.value(len, 'Wrong dynamic huffman codes.'); + } + + arrDecoderCodeLengths[CompressedStreamWriter + .defHuffmanDyntreeCodeLengthsOrder[iCurrentCode++]] = len.toUnsigned( + 8, + ); + } + final DecompressorHuffmanTree treeInternalDecoder = DecompressorHuffmanTree( + arrDecoderCodeLengths, + ); + + iCurrentCode = 0; + + int symbol = 0; + for (;;) { + bool bNeedBreak = false; + + while (((symbol = treeInternalDecoder.unpackSymbol(this)) & ~15) == 0) { + arrResultingCodeLengths[iCurrentCode++] = + bLastSymbol = symbol.toUnsigned(8); + + if (iCurrentCode == iResultingCodeLengthsCount) { + bNeedBreak = true; + break; + } + } + + if (bNeedBreak) { + break; + } + + if (symbol < 0) { + throw ArgumentError.value(symbol, 'Wrong dynamic huffman codes.'); + } + + if (symbol >= 17) { + bLastSymbol = 0; + } else if (iCurrentCode == 0) { + throw ArgumentError.value(iCurrentCode, 'Wrong dynamic huffman codes.'); + } + + final int iRepSymbol = symbol - 16; + final int bits = defHuffmanDyntreeRepeatBits[iRepSymbol]; + + int count = _readBits(bits); + + if (count < 0) { + throw ArgumentError.value(count, 'Wrong dynamic huffman codes.'); + } + + count += defHuffmanDyntreeRepeatMinimums[iRepSymbol]; + + if (iCurrentCode + count > iResultingCodeLengthsCount) { + throw ArgumentError.value(iCurrentCode, 'Wrong dynamic huffman codes.'); + } + + while (count-- > 0) { + arrResultingCodeLengths[iCurrentCode++] = bLastSymbol; + } + + if (iCurrentCode == iResultingCodeLengthsCount) { + break; + } + } + + final List tempLengthArray = List.filled( + iLengthsCount, + 0, + growable: true, + ); + List.copyRange( + tempLengthArray, + 0, + arrResultingCodeLengths, + 0, + iLengthsCount, + ); + lengthTree = DecompressorHuffmanTree(tempLengthArray); + + final List tempDistanceArray = List.filled( + iDistancesCount, + 0, + growable: true, + ); + List.copyRange( + tempDistanceArray, + 0, + arrResultingCodeLengths, + iLengthsCount, + iLengthsCount + iDistancesCount, + ); + distanceTree = DecompressorHuffmanTree(tempDistanceArray); + + return { + 'lengthTree': lengthTree, + 'distanceTree': distanceTree, + }; + } + + int _readInt16() { + int result = _readBits(8) << 8; + result |= _readBits(8); + return result; + } + + int _readBits(int count) { + final int result = peekBits(count); + if (result == -1) { + return -1; + } + bufferedBits -= count; + _buffer >>= count; + return result; + } + + /// internal method + int peekBits(int count) { + if (count < 0 || count > 32) { + throw ArgumentError.value(count, 'count'); + } + if (bufferedBits < count) { + _fillBuffer(); + } + if (bufferedBits < count) { + return -1; + } + final int bitmask = (~(_maxUnsingedLimit << count)).toUnsigned(32); + final int result = _buffer & bitmask; + return result; + } + + void _fillBuffer() { + final int length = + 4 - (bufferedBits >> 3) - (((bufferedBits & 7) != 0) ? 1 : 0); + if (length == 0) { + return; + } + final Map readResult = _readBytes(_tempBuffer, 0, length); + _tempBuffer = readResult['buffer'] as List; + final int bytesRead = readResult['count'] as int; + for (int i = 0; i < bytesRead; i++) { + _buffer |= _tempBuffer[i].toUnsigned(32) << bufferedBits; + bufferedBits += 8; + } + } + + int _readInt16Inverted() { + int result = _readBits(8); + result |= _readBits(8) << 8; + return result; + } + + int _readInt32() { + int result = (_readBits(8) << 24).toUnsigned(32); + result |= (_readBits(8) << 16).toUnsigned(32); + result |= (_readBits(8) << 8).toUnsigned(32); + result |= _readBits(8).toUnsigned(32); + return result; + } + + Map _readBytes(List buffer, int offset, int count) { + int readedCount = 0; + if (offset < buffer.length && (offset + count) <= buffer.length) { + for (int i = 0; i < count; i++) { + final Map readResult = _readByte(); + if (readResult['hasRead'] as bool) { + buffer[offset] = readResult['result'] as int; + offset++; + readedCount++; + } else { + break; + } + } + } + return {'count': readedCount, 'buffer': buffer}; + } + + Map _readByte() { + if (_offset < _data.length) { + final int result = _data[_offset]; + _offset = _offset + 1; + return {'hasRead': true, 'result': result}; + } else { + return {'hasRead': false, 'result': -1}; + } + } + + void _skipToBoundary() { + _buffer >>= bufferedBits & 7; + bufferedBits &= ~7; + } + + /// internal method + void skipBits(int count) { + if (count < 0) { + throw ArgumentError.value(count, 'Bits count can not be less than zero.'); + } + if (count == 0) { + return; + } + if (count >= bufferedBits) { + count -= bufferedBits; + bufferedBits = 0; + _buffer = 0; + // if something left, skip it. + if (count > 0) { + // Skip entire bytes. + _offset = _offset + count >> 3; + count &= 7; + // Skip bits. + if (count > 0) { + _fillBuffer(); + bufferedBits -= count; + _buffer >>= count; + } + } + } else { + bufferedBits -= count; + _buffer >>= count; + } + } + + /// internal method + Map read(List buffer, int offset, int length) { + if (offset < 0 || offset > buffer.length - 1) { + throw ArgumentError.value( + offset, + 'Offset does not belong to specified buffer.', + ); + } + if (length < 0 || length > buffer.length - offset) { + throw ArgumentError.value(length, 'Length is illegal.'); + } + final int initialLength = length; + while (length > 0) { + if (_currentPosition < _dataLength) { + final int inBlockPosition = _currentPosition % _maxValue; + int dataToCopy = min( + _maxValue - inBlockPosition, + _dataLength - _currentPosition, + ); + dataToCopy = min(dataToCopy, length); + + // Copy data. + List.copyRange( + buffer, + offset, + _blockBuffer!, + inBlockPosition, + inBlockPosition + dataToCopy, + ); + _currentPosition += dataToCopy; + offset += dataToCopy; + length -= dataToCopy; + } else { + if (!_canReadMoreData) { + break; + } + + final int oldDataLength = _dataLength; + + if (!_readingUncompressed) { + if (!_readHuffman()) { + break; + } + } else { + if (_uncompressedDataLength == 0) { + // If there is no more data in stream, just exit. + if (!(_canReadMoreData = _decodeBlockHeader())) { + break; + } + } else { + // Position of the data end in block buffer. + final int inBlockPosition = _dataLength % _maxValue; + final int dataToRead = min( + _uncompressedDataLength, + _maxValue - inBlockPosition, + ); + final int dataRead = _readPackedBytes( + _blockBuffer!, + inBlockPosition, + dataToRead, + ); + if (dataToRead != dataRead) { + throw ArgumentError.value( + dataToRead, + 'Not enough data in stream.', + ); + } + _uncompressedDataLength -= dataRead; + _dataLength += dataRead; + } + } + if (oldDataLength < _dataLength) { + final int start = oldDataLength % _maxValue; + final int end = _dataLength % _maxValue; + + if (start < end) { + _checksumUpdate(_blockBuffer, start, end - start); + } else { + _checksumUpdate(_blockBuffer, start, _maxValue - start); + + if (end > 0) { + _checksumUpdate(_blockBuffer, 0, end); + } + } + } + } + } + if (!_canReadMoreData && !_checkSumRead && !_noWrap) { + _skipToBoundary(); + if (_readInt32() != _checkSum) { + throw const FormatException('Checksum check failed.'); + } + _checkSumRead = true; + } + + return { + 'length': initialLength - length, + 'buffer': buffer, + }; + } + + void _checksumUpdate(List? buffer, int offset, int length) { + _checkSum = CompressedStreamWriter.checksumUpdate( + _checkSum, + buffer, + offset, + length, + ); + } + + int _readPackedBytes(List buffer, int offset, int length) { + if (offset < 0 || offset > buffer.length - 1) { + throw ArgumentError.value( + offset, + 'Offset cannot be less than zero or greater than buffer length - 1.', + ); + } + + if (length < 0) { + throw ArgumentError.value(length, 'Length can not be less than zero.'); + } + + if (length > buffer.length - offset) { + throw ArgumentError.value(length, 'Length is too large.'); + } + + if ((bufferedBits & 7) != 0) { + throw ArgumentError.value( + buffer, + 'Reading of unalligned data is not supported.', + ); + } + + if (length == 0) { + return 0; + } + + int result = 0; + + while (bufferedBits > 0 && length > 0) { + buffer[offset++] = _buffer.toUnsigned(8); + bufferedBits -= 8; + _buffer >>= 8; + length--; + result++; + } + + if (length > 0) { + final Map value = _readBytes(buffer, offset, length); + final int val = value['count'] as int; + result += val; + buffer = value['buffer'] as List; + } + return result; + } + + bool _readHuffman() { + int free = _maxValue - (_dataLength - _currentPosition); + bool dataRead = false; + int symbol = 0; + while (free >= defHuffmanRepeatMax) { + while (((symbol = _currentLengthTree!.unpackSymbol(this)) & ~0xff) == 0) { + _blockBuffer![_dataLength++ % _maxValue] = symbol.toUnsigned(8); + dataRead = true; + if (--free < defHuffmanRepeatMax) { + return true; + } + } + + if (symbol < defHuffmanLengthMinimumCode) { + if (symbol < defHuffmanEndBlock) { + throw ArgumentError.value(symbol, 'Illegal code.'); + } + _canReadMoreData = _decodeBlockHeader(); + return dataRead | _canReadMoreData; + } + + if (symbol > defHuffmanLengthMaximumCode) { + throw ArgumentError.value(symbol, 'Illegal repeat code length.'); + } + + int iRepeatLength = + defHuffmanRepeatLengthBase[symbol - defHuffmanLengthMinimumCode]; + + int iRepeatExtraBits = + defHuffmanRepeatLengthExtension[symbol - defHuffmanLengthMinimumCode]; + + if (iRepeatExtraBits > 0) { + final int extra = _readBits(iRepeatExtraBits); + if (extra < 0) { + throw ArgumentError.value(extra, 'Wrong data.'); + } + iRepeatLength += extra; + } + + // Unpack repeat distance. + symbol = _currentDistanceTree!.unpackSymbol(this); + + if (symbol < 0 || symbol > defHuffmanRepeatDistanseBase.length) { + throw ArgumentError.value(symbol, 'Wrong distance code.'); + } + int iRepeatDistance = defHuffmanRepeatDistanseBase[symbol]; + iRepeatExtraBits = defHuffmanRepeatDistanseExtension[symbol]; + if (iRepeatExtraBits > 0) { + final int extra = _readBits(iRepeatExtraBits); + if (extra < 0) { + throw ArgumentError.value(extra, 'Wrong data.'); + } + iRepeatDistance += extra; + } + // Copy data in slow repeat mode + for (int i = 0; i < iRepeatLength; i++) { + _blockBuffer![_dataLength % _maxValue] = + _blockBuffer![(_dataLength - iRepeatDistance) % _maxValue]; + _dataLength++; + free--; + } + + dataRead = true; + } + + return dataRead; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_writer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_writer.dart index 0ea19e403..656eebda4 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_writer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressed_stream_writer.dart @@ -1,979 +1,979 @@ -import 'dart:math'; - -import '../pdf_document/enums.dart'; -import 'compressor_huffman_tree.dart'; - -/// internal class -class CompressedStreamWriter { - /// internal constructor - CompressedStreamWriter( - List outputStream, - bool bNoWrap, - PdfCompressionLevel? level, - bool bCloseStream, - ) { - _treeLiteral = CompressorHuffmanTree( - this, - defHuffmanLiteralAlphabetLength, - 257, - 15, - ); - _treeDistances = CompressorHuffmanTree( - this, - defHuffmanDistancesAlphabetLength, - 1, - 15, - ); - _treeCodeLengths = CompressorHuffmanTree( - this, - defHuffmanBitlenTreeLength, - 4, - 7, - ); - _arrDistancesBuffer = List.filled(defHuffmanBufferSize, 0); - _arrLiteralsBuffer = List.filled(defHuffmanBufferSize, 0); - _stream = outputStream; - _level = level; - _bNoWrap = bNoWrap; - _bCloseStream = bCloseStream; - _dataWindow = List.filled(2 * wsize, 0); - _hashHead = List.filled(hashSize, 0); - _hashPrevious = List.filled(wsize, 0); - _blockStart = _stringStart = 1; - _goodLength = goodLength[_getCompressionLevel(level)!]; - _niceLength = niceLength[_getCompressionLevel(level)!]; - _maximumChainLength = maxChain[_getCompressionLevel(level)!]; - _maximumLazySearch = maxLazy[_getCompressionLevel(level)!]; - if (!bNoWrap) { - _writeZLIBHeader(); - } - initializeStaticLiterals(); - } - - /// Start template of the zlib header. - static const int defZlibHeaderTemplate = (8 + (7 << 4)) << 8; - - /// Memory usage level. - static const int defaultMemLevel = 8; - - /// Size of the pending buffer. - static const int defPendingBufferSize = 1 << (defaultMemLevel + 8); - - /// Size of the buffer for the huffman encoding. - static const int defHuffmanBufferSize = 1 << (defaultMemLevel + 6); - - /// Length of the literal alphabet(literal+lengths). - static const int defHuffmanLiteralAlphabetLength = 286; - - /// Distances alphabet length. - static const int defHuffmanDistancesAlphabetLength = 30; - - /// Length of the code-lengths tree. - static const int defHuffmanBitlenTreeLength = 19; - - /// Code of the symbol, than means the end of the block. - static const int defHuffmanEndblockSymbol = 256; - - /// internal field - static const int tooFar = 4096; - - /// Maximum window size. - static const int wsize = 1 << 15; - - /// Internal compression engine constant - static const int wmask = wsize - 1; - - /// Internal compression engine constant - static const int hashBits = defaultMemLevel + 7; - - /// Internal compression engine constant - static const int hashSize = 1 << hashBits; - - /// Internal compression engine constant - static const int hashMask = hashSize - 1; - - /// Internal compression engine constant - static const int maxMatch = 258; - - /// Internal compression engine constant - static const int minMatch = 3; - - /// Internal compression engine constant - static const int hashShift = 5; - - /// Internal compression engine constant - static const int minLookahead = maxMatch + minMatch + 1; - - /// Internal compression engine constant - static const int maxDist = wsize - minLookahead; - - /// Internal compression engine constant - static const List goodLength = [0, 4, 4, 4, 4, 8, 8, 8, 32, 32]; - - /// internal field - static const int checkSumBitOffset = 16; - - /// internal field - static const int checksumBase = 65521; - - /// internal field - static const int checksumIterationCount = 3800; - - /// Internal compression engine constant - static const List niceLength = [ - 0, - 8, - 16, - 32, - 16, - 32, - 128, - 128, - 258, - 258, - ]; - - /// Internal compression engine constant - static const List maxChain = [ - 0, - 4, - 8, - 32, - 16, - 32, - 128, - 256, - 1024, - 4096, - ]; - - /// internal field - static const List defReverseBits = [ - 0, - 8, - 4, - 12, - 2, - 10, - 6, - 14, - 1, - 9, - 5, - 13, - 3, - 11, - 7, - 15, - ]; - - /// internal field - static const List defHuffmanDyntreeCodeLengthsOrder = [ - 16, - 17, - 18, - 0, - 8, - 7, - 9, - 6, - 10, - 5, - 11, - 4, - 12, - 3, - 13, - 2, - 14, - 1, - 15, - ]; - - /// internal field - static const List maxLazy = [0, 4, 5, 6, 4, 16, 16, 32, 128, 258]; - - final List _pendingBuffer = List.filled(defPendingBufferSize, 0); - int _pendingBufferLength = 0; - late List _arrDistancesBuffer; - late List _arrLiteralsBuffer; - late List _stream; - PdfCompressionLevel? _level; - bool _bNoWrap = false; - bool _bCloseStream = false; - List? _dataWindow; - late List _hashHead; - late List _hashPrevious; - int _blockStart = 0; - int _stringStart = 0; - int _lookAhead = 0; - int _maximumChainLength = 0; - int _niceLength = 0; - int _goodLength = 0; - List? _inputBuffer; - int _inputOffset = 0; - int _inputEnd = 0; - bool _bStreamClosed = false; - int _checksum = 1; - int _pendingBufferBitsInCache = 0; - int _pendingBufferBitsCache = 0; - int _currentHash = 0; - int _matchStart = 0; - int _matchLength = 0; - int _iBufferPosition = 0; - bool _matchPreviousAvailable = false; - late CompressorHuffmanTree _treeLiteral; - late CompressorHuffmanTree _treeDistances; - CompressorHuffmanTree? _treeCodeLengths; - int _iExtraBits = 0; - static List? _arrLiteralCodes; - static late List _arrLiteralLengths; - static late List _arrDistanceCodes; - static late List _arrDistanceLengths; - bool get _needsInput => _inputEnd == _inputOffset; - bool get _pendingBufferIsFlushed => _pendingBufferLength == 0; - bool get _huffmanIsFull => _iBufferPosition >= defHuffmanBufferSize; - int _maximumLazySearch = 0; - - int? _getCompressionLevel(PdfCompressionLevel? level) { - switch (level) { - case PdfCompressionLevel.none: - return 0; - case PdfCompressionLevel.bestSpeed: - return 1; - case PdfCompressionLevel.belowNormal: - return 3; - case PdfCompressionLevel.normal: - return 5; - case PdfCompressionLevel.aboveNormal: - return 7; - case PdfCompressionLevel.best: - return 9; - // ignore: no_default_cases - default: - return null; - } - } - - /// internal method - void initializeStaticLiterals() { - if (_arrLiteralCodes == null) { - _arrLiteralCodes = List.filled(defHuffmanLiteralAlphabetLength, 0); - _arrLiteralLengths = List.filled(defHuffmanLiteralAlphabetLength, 0); - int i = 0; - while (i < 144) { - _arrLiteralCodes![i] = bitReverse((0x030 + i) << 8); - _arrLiteralLengths[i++] = 8; - } - while (i < 256) { - _arrLiteralCodes![i] = bitReverse(((0x190 - 144) + i) << 7); - _arrLiteralLengths[i++] = 9; - } - while (i < 280) { - _arrLiteralCodes![i] = bitReverse(((0x000 - 256) + i) << 9); - _arrLiteralLengths[i++] = 7; - } - while (i < defHuffmanLiteralAlphabetLength) { - _arrLiteralCodes![i] = bitReverse(((0x0c0 - 280) + i) << 8); - _arrLiteralLengths[i++] = 8; - } - _arrDistanceCodes = List.filled( - defHuffmanDistancesAlphabetLength, - 0, - ); - _arrDistanceLengths = List.filled( - defHuffmanDistancesAlphabetLength, - 0, - ); - - for (i = 0; i < defHuffmanDistancesAlphabetLength; i++) { - _arrDistanceCodes[i] = bitReverse(i << 11); - _arrDistanceLengths[i] = 5; - } - } - } - - void _writeZLIBHeader() { - // Initialize header. - int iHeaderData = defZlibHeaderTemplate; - // Save compression level. - iHeaderData |= ((_getCompressionLevel(_level)! >> 2) & 3) << 6; - // Align header. - iHeaderData += 31 - (iHeaderData % 31); - // Write header to stream. - _pendingBufferWriteShortMSB(iHeaderData); - } - - void _pendingBufferWriteShortMSB(int s) { - _pendingBuffer[_pendingBufferLength++] = (s >> 8).toUnsigned(8); - _pendingBuffer[_pendingBufferLength++] = s.toUnsigned(8); - } - - /// internal method - void write(List data, int offset, int length, bool bCloseAfterWrite) { - final int end = offset + length; - if (0 > offset || offset > end || end > data.length) { - throw Exception('Offset or length is incorrect.'); - } - _inputBuffer = data; - _inputOffset = offset; - _inputEnd = end; - if (length == 0) { - return; - } - if (_bStreamClosed) { - throw Exception('Stream was closed.'); - } - _checksum = checksumUpdate(_checksum, _inputBuffer, offset, length); - - while (!_needsInput || !_pendingBufferIsFlushed) { - _pendingBufferFlush(); - if (!_compressData(bCloseAfterWrite) && bCloseAfterWrite) { - _pendingBufferFlush(); - _pendingBufferAlignToByte(); - - if (!_bNoWrap) { - _pendingBufferWriteShortMSB(_checksum >> 16); - _pendingBufferWriteShortMSB(_checksum & 0xffff); - } - _pendingBufferFlush(); - _bStreamClosed = true; - if (_bCloseStream) { - _stream.clear(); - } - } - } - } - - bool _compressData(bool finish) { - bool success; - do { - _fillWindow(); - - final bool canFlush = finish && _needsInput; - - switch (_level) { - case PdfCompressionLevel.bestSpeed: - case PdfCompressionLevel.belowNormal: - success = _compressFast(canFlush, finish); - break; - // ignore: no_default_cases - default: - success = _compressSlow(canFlush, finish); - break; - } - } while (_pendingBufferIsFlushed && success); - - return success; - } - - // Compress, using maximum compression level. - bool _compressSlow(bool flush, bool finish) { - if (_lookAhead < minLookahead && !flush) { - return false; - } - - while (_lookAhead >= minLookahead || flush) { - if (_lookAhead == 0) { - if (_matchPreviousAvailable) { - _huffmanTallyLit(_dataWindow![_stringStart - 1] & 0xff); - } - - _matchPreviousAvailable = false; - - _huffmanFlushBlock( - _dataWindow, - _blockStart, - _stringStart - _blockStart, - finish, - ); - - _blockStart = _stringStart; - - return false; - } - - if (_stringStart >= 2 * wsize - minLookahead) { - _slideWindow(); - } - - final int prevMatch = _matchStart; - int prevLen = _matchLength; - - if (_lookAhead >= minMatch) { - final int hashHead = _insertString(); - - if (hashHead != 0 && - _stringStart - hashHead <= maxDist && - _findLongestMatch(hashHead)) { - /// Discard match if too small and too far away. - if (_matchLength <= 5 && - (_matchLength == minMatch) && - _stringStart - _matchStart > tooFar) { - _matchLength = minMatch - 1; - } - } - } - - /// Previous match was better. - if (prevLen >= minMatch && _matchLength <= prevLen) { - _huffmanTallyDist(_stringStart - 1 - prevMatch, prevLen); - prevLen -= 2; - - do { - _stringStart++; - _lookAhead--; - - if (_lookAhead >= minMatch) { - _insertString(); - } - } while (--prevLen > 0); - - _stringStart++; - _lookAhead--; - _matchPreviousAvailable = false; - _matchLength = minMatch - 1; - } else { - if (_matchPreviousAvailable) { - _huffmanTallyLit(_dataWindow![_stringStart - 1] & 0xff); - } - - _matchPreviousAvailable = true; - _stringStart++; - _lookAhead--; - } - - if (_huffmanIsFull) { - int len = _stringStart - _blockStart; - if (_matchPreviousAvailable) { - len--; - } - - final bool lastBlock = - finish && _lookAhead == 0 && !_matchPreviousAvailable; - _huffmanFlushBlock(_dataWindow, _blockStart, len, lastBlock); - _blockStart += len; - - return !lastBlock; - } - } - - return true; - } - - // Compress with a maximum speed. - bool _compressFast(bool flush, bool finish) { - if (_lookAhead < minLookahead && !flush) { - return false; - } - - while (_lookAhead >= minLookahead || flush) { - if (_lookAhead == 0) { - _huffmanFlushBlock( - _dataWindow, - _blockStart, - _stringStart - _blockStart, - finish, - ); - _blockStart = _stringStart; - return false; - } - - if (_stringStart > 2 * wsize - minLookahead) { - _slideWindow(); - } - int hashHead; - if (_lookAhead >= minMatch && - (hashHead = _insertString()) != 0 && - _stringStart - hashHead <= maxDist && - _findLongestMatch(hashHead)) { - if (_huffmanTallyDist(_stringStart - _matchStart, _matchLength)) { - final bool lastBlock = finish && _lookAhead == 0; - _huffmanFlushBlock( - _dataWindow, - _blockStart, - _stringStart - _blockStart, - lastBlock, - ); - _blockStart = _stringStart; - } - _lookAhead -= _matchLength; - if (_matchLength <= _maximumLazySearch && _lookAhead >= minMatch) { - while (--_matchLength > 0) { - ++_stringStart; - _insertString(); - } - - ++_stringStart; - } else { - _stringStart += _matchLength; - - if (_lookAhead >= minMatch - 1) { - _updateHash(); - } - } - _matchLength = minMatch - 1; - - continue; - } else { - _huffmanTallyLit(_dataWindow![_stringStart] & 0xff); - ++_stringStart; - --_lookAhead; - } - if (_huffmanIsFull) { - final bool lastBlock = finish && _lookAhead == 0; - _huffmanFlushBlock( - _dataWindow, - _blockStart, - _stringStart - _blockStart, - lastBlock, - ); - _blockStart = _stringStart; - - return !lastBlock; - } - } - return true; - } - - bool _findLongestMatch(int curMatch) { - int chainLength = _maximumChainLength; - int scan = _stringStart; - int match; - int bestEnd = _stringStart + _matchLength; - int bestLen = max(_matchLength, minMatch - 1); - - final int limit = max(_stringStart - maxDist, 0); - - final int strend = _stringStart + maxMatch - 1; - int scanEnd1 = _dataWindow![bestEnd - 1]; - int scanEnd = _dataWindow![bestEnd]; - - /// Do not waste too much time if we already have a good match. - if (bestLen >= _goodLength) { - chainLength >>= 2; - } - - /// Do not look for matches beyond the end of the input. - /// This is necessary to make deflate deterministic. - - if (_niceLength > _lookAhead) { - _niceLength = _lookAhead; - } - - do { - if (_dataWindow![curMatch + bestLen] != scanEnd || - _dataWindow![curMatch + bestLen - 1] != scanEnd1 || - _dataWindow![curMatch] != _dataWindow![scan] || - _dataWindow![curMatch + 1] != _dataWindow![scan + 1]) { - continue; - } - - match = curMatch + 2; - scan += 2; - - /// We check for insufficient _lookAhead only every 8th comparison - /// and the 256th check will be made at _stringStart + 258. - - while (_dataWindow![++scan] == _dataWindow![++match] && - _dataWindow![++scan] == _dataWindow![++match] && - _dataWindow![++scan] == _dataWindow![++match] && - _dataWindow![++scan] == _dataWindow![++match] && - _dataWindow![++scan] == _dataWindow![++match] && - _dataWindow![++scan] == _dataWindow![++match] && - _dataWindow![++scan] == _dataWindow![++match] && - _dataWindow![++scan] == _dataWindow![++match] && - scan < strend) {} - - if (scan > bestEnd) { - _matchStart = curMatch; - bestEnd = scan; - bestLen = scan - _stringStart; - - if (bestLen >= _niceLength) { - break; - } - - scanEnd1 = _dataWindow![bestEnd - 1]; - scanEnd = _dataWindow![bestEnd]; - } - scan = _stringStart; - } while ((curMatch = _hashPrevious[curMatch & wmask] & 0xffff) > limit && - --chainLength != 0); - - _matchLength = min(bestLen, _lookAhead); - - return _matchLength >= minMatch; - } - - bool _huffmanTallyDist(int dist, int len) { - _arrDistancesBuffer[_iBufferPosition] = dist.toSigned(16); - _arrLiteralsBuffer[_iBufferPosition++] = (len - 3).toUnsigned(8); - - final int lc = _huffmanLengthCode(len - 3); - _treeLiteral.codeFrequences[lc]++; - if (lc >= 265 && lc < 285) { - _iExtraBits += (lc - 261) ~/ 4; - } - - final int dc = _huffmanDistanceCode(dist - 1); - _treeDistances.codeFrequences[dc]++; - if (dc >= 4) { - _iExtraBits += dc ~/ 2 - 1; - } - return _huffmanIsFull; - } - - void _huffmanFlushBlock( - List? stored, - int storedOffset, - int storedLength, - bool lastBlock, - ) { - _treeLiteral.codeFrequences[defHuffmanEndblockSymbol]++; - - // Build trees. - _treeLiteral.buildTree(); - _treeDistances.buildTree(); - - // Calculate bitlen frequency. - _treeLiteral.calcBLFreq(_treeCodeLengths); - _treeDistances.calcBLFreq(_treeCodeLengths); - - // Build bitlen tree. - _treeCodeLengths!.buildTree(); - - int blTreeCodes = 4; - for (int i = 18; i > blTreeCodes; i--) { - if (_treeCodeLengths!.codeLengths![defHuffmanDyntreeCodeLengthsOrder[i]] > - 0) { - blTreeCodes = i + 1; - } - } - int optLen = - 14 + - blTreeCodes * 3 + - _treeCodeLengths!.getEncodedLength() + - _treeLiteral.getEncodedLength() + - _treeDistances.getEncodedLength() + - _iExtraBits; - - int staticLen = _iExtraBits; - for (int i = 0; i < defHuffmanLiteralAlphabetLength; i++) { - staticLen += _treeLiteral.codeFrequences[i] * _arrLiteralLengths[i]; - } - for (int i = 0; i < defHuffmanDistancesAlphabetLength; i++) { - staticLen += _treeDistances.codeFrequences[i] * _arrDistanceLengths[i]; - } - if (optLen >= staticLen) { - // Force static trees. - optLen = staticLen; - } - - if (storedOffset >= 0 && storedLength + 4 < optLen >> 3) { - _huffmanFlushStoredBlock(stored!, storedOffset, storedLength, lastBlock); - } else if (optLen == staticLen) { - // Encode with static tree. - pendingBufferWriteBits((1 << 1) + (lastBlock ? 1 : 0), 3); - _treeLiteral.setStaticCodes(_arrLiteralCodes!, _arrLiteralLengths); - _treeDistances.setStaticCodes(_arrDistanceCodes, _arrDistanceLengths); - _huffmanCompressBlock(); - _huffmanReset(); - } else { - // Encode with dynamic tree. - pendingBufferWriteBits((2 << 1) + (lastBlock ? 1 : 0), 3); - _huffmanSendAllTrees(blTreeCodes); - _huffmanCompressBlock(); - _huffmanReset(); - } - } - - void _huffmanSendAllTrees(int blTreeCodes) { - _treeCodeLengths!.buildCodes(); - _treeLiteral.buildCodes(); - _treeDistances.buildCodes(); - pendingBufferWriteBits(_treeLiteral.codeCount - 257, 5); - pendingBufferWriteBits(_treeDistances.codeCount - 1, 5); - pendingBufferWriteBits(blTreeCodes - 4, 4); - - for (int rank = 0; rank < blTreeCodes; rank++) { - pendingBufferWriteBits( - _treeCodeLengths!.codeLengths![defHuffmanDyntreeCodeLengthsOrder[rank]], - 3, - ); - } - - _treeLiteral.writeTree(_treeCodeLengths); - _treeDistances.writeTree(_treeCodeLengths); - } - - int _insertString() { - int match; - final int hash = - ((_currentHash << hashShift) ^ - _dataWindow![_stringStart + (minMatch - 1)]) & - hashMask; - - _hashPrevious[_stringStart & wmask] = match = _hashHead[hash]; - _hashHead[hash] = _stringStart.toSigned(16); - _currentHash = hash; - return match & 0xffff; - } - - void _huffmanCompressBlock() { - for (int i = 0; i < _iBufferPosition; i++) { - final int litlen = _arrLiteralsBuffer[i] & 255; - int dist = _arrDistancesBuffer[i]; - - if (dist-- != 0) { - final int lc = _huffmanLengthCode(litlen); - _treeLiteral.writeCodeToStream(lc); - - int bits = (lc - 261) ~/ 4; - if (bits > 0 && bits <= 5) { - pendingBufferWriteBits(litlen & ((1 << bits) - 1), bits); - } - - final int dc = _huffmanDistanceCode(dist); - _treeDistances.writeCodeToStream(dc); - - bits = dc ~/ 2 - 1; - if (bits > 0) { - pendingBufferWriteBits(dist & ((1 << bits) - 1), bits); - } - } else { - _treeLiteral.writeCodeToStream(litlen); - } - } - - _treeLiteral.writeCodeToStream(defHuffmanEndblockSymbol); - } - - int _huffmanDistanceCode(int distance) { - int code = 0; - - while (distance >= 4) { - code += 2; - distance >>= 1; - } - return code + distance; - } - - int _huffmanLengthCode(int len) { - if (len == 255) { - return 285; - } - - int code = 257; - - while (len >= 8) { - code += 4; - len >>= 1; - } - - return code + len; - } - - void _huffmanFlushStoredBlock( - List stored, - int storedOffset, - int storedLength, - bool lastBlock, - ) { - pendingBufferWriteBits((0 << 1) + (lastBlock ? 1 : 0), 3); - _pendingBufferAlignToByte(); - _pendingBufferWriteShort(storedLength); - _pendingBufferWriteShort(~storedLength); - _pendingBufferWriteByteBlock(stored, storedOffset, storedLength); - _huffmanReset(); - } - - void _huffmanReset() { - _iBufferPosition = 0; - _iExtraBits = 0; - _treeLiteral.reset(); - _treeDistances.reset(); - _treeCodeLengths!.reset(); - } - - void _pendingBufferWriteShort(int s) { - _pendingBuffer[_pendingBufferLength++] = s.toUnsigned(8); - _pendingBuffer[_pendingBufferLength++] = (s >> 8).toUnsigned(8); - } - - void _pendingBufferWriteByteBlock(List data, int offset, int length) { - List.copyRange( - _pendingBuffer, - _pendingBufferLength, - data, - offset, - offset + length, - ); - _pendingBufferLength += length; - } - - void _pendingBufferAlignToByte() { - if (_pendingBufferBitsInCache > 0) { - _pendingBuffer[_pendingBufferLength++] = _pendingBufferBitsCache - .toUnsigned(8); - - if (_pendingBufferBitsInCache > 8) { - _pendingBuffer[_pendingBufferLength++] = (_pendingBufferBitsCache >> 8) - .toUnsigned(8); - } - } - - _pendingBufferBitsCache = 0; - _pendingBufferBitsInCache = 0; - } - - /// internal method - void pendingBufferWriteBits(int b, int count) { - _pendingBufferBitsCache |= (b << _pendingBufferBitsInCache).toUnsigned(32); - _pendingBufferBitsInCache += count; - - _pendingBufferFlushBits(); - } - - bool _huffmanTallyLit(int literal) { - _arrDistancesBuffer[_iBufferPosition] = 0; - _arrLiteralsBuffer[_iBufferPosition++] = literal.toUnsigned(8); - _treeLiteral.codeFrequences[literal]++; - return _huffmanIsFull; - } - - void _fillWindow() { - if (_stringStart >= wsize + maxDist) { - _slideWindow(); - } - - while (_lookAhead < minLookahead && _inputOffset < _inputEnd) { - int more = 2 * wsize - _lookAhead - _stringStart; - if (more > _inputEnd - _inputOffset) { - more = _inputEnd - _inputOffset; - } - List.copyRange( - _dataWindow!, - _stringStart + _lookAhead, - _inputBuffer!, - _inputOffset, - _inputOffset + more, - ); - - _inputOffset += more; - _lookAhead += more; - } - - if (_lookAhead >= minMatch) { - _updateHash(); - } - } - - void _slideWindow() { - List.copyRange(_dataWindow!, 0, _dataWindow!, wsize, wsize + wsize); - _matchStart -= wsize; - _stringStart -= wsize; - _blockStart -= wsize; - - for (int i = 0; i < hashSize; ++i) { - final int m = _hashHead[i] & 0xffff; - _hashHead[i] = ((m >= wsize) ? (m - wsize) : 0).toSigned(16); - } - - for (int i = 0; i < wsize; i++) { - final int m = _hashPrevious[i] & 0xffff; - _hashPrevious[i] = ((m >= wsize) ? (m - wsize) : 0).toSigned(16); - } - } - - void _updateHash() { - _currentHash = - (_dataWindow![_stringStart] << hashShift) ^ - _dataWindow![_stringStart + 1]; - } - - void _pendingBufferFlush() { - _pendingBufferFlushBits(); - if (_pendingBufferLength > 0) { - final List array = List.filled(_pendingBufferLength, 0); - array.setAll(0, _pendingBuffer.sublist(0, _pendingBufferLength)); - _stream.addAll(array); - } - _pendingBufferLength = 0; - } - - /// Flushes fully recorded bytes to buffer array. - int _pendingBufferFlushBits() { - int result = 0; - while (_pendingBufferBitsInCache >= 8 && - _pendingBufferLength < defPendingBufferSize) { - _pendingBuffer[_pendingBufferLength++] = _pendingBufferBitsCache - .toUnsigned(8); - _pendingBufferBitsCache >>= 8; - _pendingBufferBitsInCache -= 8; - result++; - } - return result; - } - - /// internal method - // ignore: unused_element - void close() { - if (_bStreamClosed) { - return; - } - do { - _pendingBufferFlush(); - if (!_compressData(true)) { - _pendingBufferFlush(); - _pendingBufferAlignToByte(); - - if (!_bNoWrap) { - _pendingBufferWriteShortMSB(_checksum >> 16); - _pendingBufferWriteShortMSB(_checksum & 0xffff); - } - - _pendingBufferFlush(); - } - } while (!_needsInput || !_pendingBufferIsFlushed); - - _bStreamClosed = true; - - if (_bCloseStream) { - _stream.clear(); - } - } - - /// internal field - static int bitReverse(int value) { - return (defReverseBits[(value & 15)] << 12 | - defReverseBits[((value >> 4) & 15)] << 8 | - defReverseBits[((value >> 8) & 15)] << 4 | - defReverseBits[(value >> 12)]) - .toSigned(16); - } - - /// internal method - static int checksumUpdate( - int checksum, - List? buffer, - int offset, - int length, - ) { - int checksumUint = checksum.toUnsigned(32); - int s1 = checksumUint & 65535; - int s2 = checksumUint >> checkSumBitOffset; - while (length > 0) { - int steps = min(length, checksumIterationCount); - length -= steps; - while (--steps >= 0) { - s1 = s1 + (buffer![offset++] & 255).toUnsigned(32); - s2 += s1; - } - s1 %= checksumBase; - s2 %= checksumBase; - } - checksumUint = (s2 << checkSumBitOffset) | s1; - return checksumUint; - } -} +import 'dart:math'; + +import '../pdf_document/enums.dart'; +import 'compressor_huffman_tree.dart'; + +/// internal class +class CompressedStreamWriter { + /// internal constructor + CompressedStreamWriter( + List outputStream, + bool bNoWrap, + PdfCompressionLevel? level, + bool bCloseStream, + ) { + _treeLiteral = CompressorHuffmanTree( + this, + defHuffmanLiteralAlphabetLength, + 257, + 15, + ); + _treeDistances = CompressorHuffmanTree( + this, + defHuffmanDistancesAlphabetLength, + 1, + 15, + ); + _treeCodeLengths = CompressorHuffmanTree( + this, + defHuffmanBitlenTreeLength, + 4, + 7, + ); + _arrDistancesBuffer = List.filled(defHuffmanBufferSize, 0); + _arrLiteralsBuffer = List.filled(defHuffmanBufferSize, 0); + _stream = outputStream; + _level = level; + _bNoWrap = bNoWrap; + _bCloseStream = bCloseStream; + _dataWindow = List.filled(2 * wsize, 0); + _hashHead = List.filled(hashSize, 0); + _hashPrevious = List.filled(wsize, 0); + _blockStart = _stringStart = 1; + _goodLength = goodLength[_getCompressionLevel(level)!]; + _niceLength = niceLength[_getCompressionLevel(level)!]; + _maximumChainLength = maxChain[_getCompressionLevel(level)!]; + _maximumLazySearch = maxLazy[_getCompressionLevel(level)!]; + if (!bNoWrap) { + _writeZLIBHeader(); + } + initializeStaticLiterals(); + } + + /// Start template of the zlib header. + static const int defZlibHeaderTemplate = (8 + (7 << 4)) << 8; + + /// Memory usage level. + static const int defaultMemLevel = 8; + + /// Size of the pending buffer. + static const int defPendingBufferSize = 1 << (defaultMemLevel + 8); + + /// Size of the buffer for the huffman encoding. + static const int defHuffmanBufferSize = 1 << (defaultMemLevel + 6); + + /// Length of the literal alphabet(literal+lengths). + static const int defHuffmanLiteralAlphabetLength = 286; + + /// Distances alphabet length. + static const int defHuffmanDistancesAlphabetLength = 30; + + /// Length of the code-lengths tree. + static const int defHuffmanBitlenTreeLength = 19; + + /// Code of the symbol, than means the end of the block. + static const int defHuffmanEndblockSymbol = 256; + + /// internal field + static const int tooFar = 4096; + + /// Maximum window size. + static const int wsize = 1 << 15; + + /// Internal compression engine constant + static const int wmask = wsize - 1; + + /// Internal compression engine constant + static const int hashBits = defaultMemLevel + 7; + + /// Internal compression engine constant + static const int hashSize = 1 << hashBits; + + /// Internal compression engine constant + static const int hashMask = hashSize - 1; + + /// Internal compression engine constant + static const int maxMatch = 258; + + /// Internal compression engine constant + static const int minMatch = 3; + + /// Internal compression engine constant + static const int hashShift = 5; + + /// Internal compression engine constant + static const int minLookahead = maxMatch + minMatch + 1; + + /// Internal compression engine constant + static const int maxDist = wsize - minLookahead; + + /// Internal compression engine constant + static const List goodLength = [0, 4, 4, 4, 4, 8, 8, 8, 32, 32]; + + /// internal field + static const int checkSumBitOffset = 16; + + /// internal field + static const int checksumBase = 65521; + + /// internal field + static const int checksumIterationCount = 3800; + + /// Internal compression engine constant + static const List niceLength = [ + 0, + 8, + 16, + 32, + 16, + 32, + 128, + 128, + 258, + 258, + ]; + + /// Internal compression engine constant + static const List maxChain = [ + 0, + 4, + 8, + 32, + 16, + 32, + 128, + 256, + 1024, + 4096, + ]; + + /// internal field + static const List defReverseBits = [ + 0, + 8, + 4, + 12, + 2, + 10, + 6, + 14, + 1, + 9, + 5, + 13, + 3, + 11, + 7, + 15, + ]; + + /// internal field + static const List defHuffmanDyntreeCodeLengthsOrder = [ + 16, + 17, + 18, + 0, + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + ]; + + /// internal field + static const List maxLazy = [0, 4, 5, 6, 4, 16, 16, 32, 128, 258]; + + final List _pendingBuffer = List.filled(defPendingBufferSize, 0); + int _pendingBufferLength = 0; + late List _arrDistancesBuffer; + late List _arrLiteralsBuffer; + late List _stream; + PdfCompressionLevel? _level; + bool _bNoWrap = false; + bool _bCloseStream = false; + List? _dataWindow; + late List _hashHead; + late List _hashPrevious; + int _blockStart = 0; + int _stringStart = 0; + int _lookAhead = 0; + int _maximumChainLength = 0; + int _niceLength = 0; + int _goodLength = 0; + List? _inputBuffer; + int _inputOffset = 0; + int _inputEnd = 0; + bool _bStreamClosed = false; + int _checksum = 1; + int _pendingBufferBitsInCache = 0; + int _pendingBufferBitsCache = 0; + int _currentHash = 0; + int _matchStart = 0; + int _matchLength = 0; + int _iBufferPosition = 0; + bool _matchPreviousAvailable = false; + late CompressorHuffmanTree _treeLiteral; + late CompressorHuffmanTree _treeDistances; + CompressorHuffmanTree? _treeCodeLengths; + int _iExtraBits = 0; + static List? _arrLiteralCodes; + static late List _arrLiteralLengths; + static late List _arrDistanceCodes; + static late List _arrDistanceLengths; + bool get _needsInput => _inputEnd == _inputOffset; + bool get _pendingBufferIsFlushed => _pendingBufferLength == 0; + bool get _huffmanIsFull => _iBufferPosition >= defHuffmanBufferSize; + int _maximumLazySearch = 0; + + int? _getCompressionLevel(PdfCompressionLevel? level) { + switch (level) { + case PdfCompressionLevel.none: + return 0; + case PdfCompressionLevel.bestSpeed: + return 1; + case PdfCompressionLevel.belowNormal: + return 3; + case PdfCompressionLevel.normal: + return 5; + case PdfCompressionLevel.aboveNormal: + return 7; + case PdfCompressionLevel.best: + return 9; + // ignore: no_default_cases + default: + return null; + } + } + + /// internal method + void initializeStaticLiterals() { + if (_arrLiteralCodes == null) { + _arrLiteralCodes = List.filled(defHuffmanLiteralAlphabetLength, 0); + _arrLiteralLengths = List.filled(defHuffmanLiteralAlphabetLength, 0); + int i = 0; + while (i < 144) { + _arrLiteralCodes![i] = bitReverse((0x030 + i) << 8); + _arrLiteralLengths[i++] = 8; + } + while (i < 256) { + _arrLiteralCodes![i] = bitReverse(((0x190 - 144) + i) << 7); + _arrLiteralLengths[i++] = 9; + } + while (i < 280) { + _arrLiteralCodes![i] = bitReverse(((0x000 - 256) + i) << 9); + _arrLiteralLengths[i++] = 7; + } + while (i < defHuffmanLiteralAlphabetLength) { + _arrLiteralCodes![i] = bitReverse(((0x0c0 - 280) + i) << 8); + _arrLiteralLengths[i++] = 8; + } + _arrDistanceCodes = List.filled( + defHuffmanDistancesAlphabetLength, + 0, + ); + _arrDistanceLengths = List.filled( + defHuffmanDistancesAlphabetLength, + 0, + ); + + for (i = 0; i < defHuffmanDistancesAlphabetLength; i++) { + _arrDistanceCodes[i] = bitReverse(i << 11); + _arrDistanceLengths[i] = 5; + } + } + } + + void _writeZLIBHeader() { + // Initialize header. + int iHeaderData = defZlibHeaderTemplate; + // Save compression level. + iHeaderData |= ((_getCompressionLevel(_level)! >> 2) & 3) << 6; + // Align header. + iHeaderData += 31 - (iHeaderData % 31); + // Write header to stream. + _pendingBufferWriteShortMSB(iHeaderData); + } + + void _pendingBufferWriteShortMSB(int s) { + _pendingBuffer[_pendingBufferLength++] = (s >> 8).toUnsigned(8); + _pendingBuffer[_pendingBufferLength++] = s.toUnsigned(8); + } + + /// internal method + void write(List data, int offset, int length, bool bCloseAfterWrite) { + final int end = offset + length; + if (0 > offset || offset > end || end > data.length) { + throw Exception('Offset or length is incorrect.'); + } + _inputBuffer = data; + _inputOffset = offset; + _inputEnd = end; + if (length == 0) { + return; + } + if (_bStreamClosed) { + throw Exception('Stream was closed.'); + } + _checksum = checksumUpdate(_checksum, _inputBuffer, offset, length); + + while (!_needsInput || !_pendingBufferIsFlushed) { + _pendingBufferFlush(); + if (!_compressData(bCloseAfterWrite) && bCloseAfterWrite) { + _pendingBufferFlush(); + _pendingBufferAlignToByte(); + + if (!_bNoWrap) { + _pendingBufferWriteShortMSB(_checksum >> 16); + _pendingBufferWriteShortMSB(_checksum & 0xffff); + } + _pendingBufferFlush(); + _bStreamClosed = true; + if (_bCloseStream) { + _stream.clear(); + } + } + } + } + + bool _compressData(bool finish) { + bool success; + do { + _fillWindow(); + + final bool canFlush = finish && _needsInput; + + switch (_level) { + case PdfCompressionLevel.bestSpeed: + case PdfCompressionLevel.belowNormal: + success = _compressFast(canFlush, finish); + break; + // ignore: no_default_cases + default: + success = _compressSlow(canFlush, finish); + break; + } + } while (_pendingBufferIsFlushed && success); + + return success; + } + + // Compress, using maximum compression level. + bool _compressSlow(bool flush, bool finish) { + if (_lookAhead < minLookahead && !flush) { + return false; + } + + while (_lookAhead >= minLookahead || flush) { + if (_lookAhead == 0) { + if (_matchPreviousAvailable) { + _huffmanTallyLit(_dataWindow![_stringStart - 1] & 0xff); + } + + _matchPreviousAvailable = false; + + _huffmanFlushBlock( + _dataWindow, + _blockStart, + _stringStart - _blockStart, + finish, + ); + + _blockStart = _stringStart; + + return false; + } + + if (_stringStart >= 2 * wsize - minLookahead) { + _slideWindow(); + } + + final int prevMatch = _matchStart; + int prevLen = _matchLength; + + if (_lookAhead >= minMatch) { + final int hashHead = _insertString(); + + if (hashHead != 0 && + _stringStart - hashHead <= maxDist && + _findLongestMatch(hashHead)) { + /// Discard match if too small and too far away. + if (_matchLength <= 5 && + (_matchLength == minMatch) && + _stringStart - _matchStart > tooFar) { + _matchLength = minMatch - 1; + } + } + } + + /// Previous match was better. + if (prevLen >= minMatch && _matchLength <= prevLen) { + _huffmanTallyDist(_stringStart - 1 - prevMatch, prevLen); + prevLen -= 2; + + do { + _stringStart++; + _lookAhead--; + + if (_lookAhead >= minMatch) { + _insertString(); + } + } while (--prevLen > 0); + + _stringStart++; + _lookAhead--; + _matchPreviousAvailable = false; + _matchLength = minMatch - 1; + } else { + if (_matchPreviousAvailable) { + _huffmanTallyLit(_dataWindow![_stringStart - 1] & 0xff); + } + + _matchPreviousAvailable = true; + _stringStart++; + _lookAhead--; + } + + if (_huffmanIsFull) { + int len = _stringStart - _blockStart; + if (_matchPreviousAvailable) { + len--; + } + + final bool lastBlock = + finish && _lookAhead == 0 && !_matchPreviousAvailable; + _huffmanFlushBlock(_dataWindow, _blockStart, len, lastBlock); + _blockStart += len; + + return !lastBlock; + } + } + + return true; + } + + // Compress with a maximum speed. + bool _compressFast(bool flush, bool finish) { + if (_lookAhead < minLookahead && !flush) { + return false; + } + + while (_lookAhead >= minLookahead || flush) { + if (_lookAhead == 0) { + _huffmanFlushBlock( + _dataWindow, + _blockStart, + _stringStart - _blockStart, + finish, + ); + _blockStart = _stringStart; + return false; + } + + if (_stringStart > 2 * wsize - minLookahead) { + _slideWindow(); + } + int hashHead; + if (_lookAhead >= minMatch && + (hashHead = _insertString()) != 0 && + _stringStart - hashHead <= maxDist && + _findLongestMatch(hashHead)) { + if (_huffmanTallyDist(_stringStart - _matchStart, _matchLength)) { + final bool lastBlock = finish && _lookAhead == 0; + _huffmanFlushBlock( + _dataWindow, + _blockStart, + _stringStart - _blockStart, + lastBlock, + ); + _blockStart = _stringStart; + } + _lookAhead -= _matchLength; + if (_matchLength <= _maximumLazySearch && _lookAhead >= minMatch) { + while (--_matchLength > 0) { + ++_stringStart; + _insertString(); + } + + ++_stringStart; + } else { + _stringStart += _matchLength; + + if (_lookAhead >= minMatch - 1) { + _updateHash(); + } + } + _matchLength = minMatch - 1; + + continue; + } else { + _huffmanTallyLit(_dataWindow![_stringStart] & 0xff); + ++_stringStart; + --_lookAhead; + } + if (_huffmanIsFull) { + final bool lastBlock = finish && _lookAhead == 0; + _huffmanFlushBlock( + _dataWindow, + _blockStart, + _stringStart - _blockStart, + lastBlock, + ); + _blockStart = _stringStart; + + return !lastBlock; + } + } + return true; + } + + bool _findLongestMatch(int curMatch) { + int chainLength = _maximumChainLength; + int scan = _stringStart; + int match; + int bestEnd = _stringStart + _matchLength; + int bestLen = max(_matchLength, minMatch - 1); + + final int limit = max(_stringStart - maxDist, 0); + + final int strend = _stringStart + maxMatch - 1; + int scanEnd1 = _dataWindow![bestEnd - 1]; + int scanEnd = _dataWindow![bestEnd]; + + /// Do not waste too much time if we already have a good match. + if (bestLen >= _goodLength) { + chainLength >>= 2; + } + + /// Do not look for matches beyond the end of the input. + /// This is necessary to make deflate deterministic. + + if (_niceLength > _lookAhead) { + _niceLength = _lookAhead; + } + + do { + if (_dataWindow![curMatch + bestLen] != scanEnd || + _dataWindow![curMatch + bestLen - 1] != scanEnd1 || + _dataWindow![curMatch] != _dataWindow![scan] || + _dataWindow![curMatch + 1] != _dataWindow![scan + 1]) { + continue; + } + + match = curMatch + 2; + scan += 2; + + /// We check for insufficient _lookAhead only every 8th comparison + /// and the 256th check will be made at _stringStart + 258. + + while (_dataWindow![++scan] == _dataWindow![++match] && + _dataWindow![++scan] == _dataWindow![++match] && + _dataWindow![++scan] == _dataWindow![++match] && + _dataWindow![++scan] == _dataWindow![++match] && + _dataWindow![++scan] == _dataWindow![++match] && + _dataWindow![++scan] == _dataWindow![++match] && + _dataWindow![++scan] == _dataWindow![++match] && + _dataWindow![++scan] == _dataWindow![++match] && + scan < strend) {} + + if (scan > bestEnd) { + _matchStart = curMatch; + bestEnd = scan; + bestLen = scan - _stringStart; + + if (bestLen >= _niceLength) { + break; + } + + scanEnd1 = _dataWindow![bestEnd - 1]; + scanEnd = _dataWindow![bestEnd]; + } + scan = _stringStart; + } while ((curMatch = _hashPrevious[curMatch & wmask] & 0xffff) > limit && + --chainLength != 0); + + _matchLength = min(bestLen, _lookAhead); + + return _matchLength >= minMatch; + } + + bool _huffmanTallyDist(int dist, int len) { + _arrDistancesBuffer[_iBufferPosition] = dist.toSigned(16); + _arrLiteralsBuffer[_iBufferPosition++] = (len - 3).toUnsigned(8); + + final int lc = _huffmanLengthCode(len - 3); + _treeLiteral.codeFrequences[lc]++; + if (lc >= 265 && lc < 285) { + _iExtraBits += (lc - 261) ~/ 4; + } + + final int dc = _huffmanDistanceCode(dist - 1); + _treeDistances.codeFrequences[dc]++; + if (dc >= 4) { + _iExtraBits += dc ~/ 2 - 1; + } + return _huffmanIsFull; + } + + void _huffmanFlushBlock( + List? stored, + int storedOffset, + int storedLength, + bool lastBlock, + ) { + _treeLiteral.codeFrequences[defHuffmanEndblockSymbol]++; + + // Build trees. + _treeLiteral.buildTree(); + _treeDistances.buildTree(); + + // Calculate bitlen frequency. + _treeLiteral.calcBLFreq(_treeCodeLengths); + _treeDistances.calcBLFreq(_treeCodeLengths); + + // Build bitlen tree. + _treeCodeLengths!.buildTree(); + + int blTreeCodes = 4; + for (int i = 18; i > blTreeCodes; i--) { + if (_treeCodeLengths!.codeLengths![defHuffmanDyntreeCodeLengthsOrder[i]] > + 0) { + blTreeCodes = i + 1; + } + } + int optLen = + 14 + + blTreeCodes * 3 + + _treeCodeLengths!.getEncodedLength() + + _treeLiteral.getEncodedLength() + + _treeDistances.getEncodedLength() + + _iExtraBits; + + int staticLen = _iExtraBits; + for (int i = 0; i < defHuffmanLiteralAlphabetLength; i++) { + staticLen += _treeLiteral.codeFrequences[i] * _arrLiteralLengths[i]; + } + for (int i = 0; i < defHuffmanDistancesAlphabetLength; i++) { + staticLen += _treeDistances.codeFrequences[i] * _arrDistanceLengths[i]; + } + if (optLen >= staticLen) { + // Force static trees. + optLen = staticLen; + } + + if (storedOffset >= 0 && storedLength + 4 < optLen >> 3) { + _huffmanFlushStoredBlock(stored!, storedOffset, storedLength, lastBlock); + } else if (optLen == staticLen) { + // Encode with static tree. + pendingBufferWriteBits((1 << 1) + (lastBlock ? 1 : 0), 3); + _treeLiteral.setStaticCodes(_arrLiteralCodes!, _arrLiteralLengths); + _treeDistances.setStaticCodes(_arrDistanceCodes, _arrDistanceLengths); + _huffmanCompressBlock(); + _huffmanReset(); + } else { + // Encode with dynamic tree. + pendingBufferWriteBits((2 << 1) + (lastBlock ? 1 : 0), 3); + _huffmanSendAllTrees(blTreeCodes); + _huffmanCompressBlock(); + _huffmanReset(); + } + } + + void _huffmanSendAllTrees(int blTreeCodes) { + _treeCodeLengths!.buildCodes(); + _treeLiteral.buildCodes(); + _treeDistances.buildCodes(); + pendingBufferWriteBits(_treeLiteral.codeCount - 257, 5); + pendingBufferWriteBits(_treeDistances.codeCount - 1, 5); + pendingBufferWriteBits(blTreeCodes - 4, 4); + + for (int rank = 0; rank < blTreeCodes; rank++) { + pendingBufferWriteBits( + _treeCodeLengths!.codeLengths![defHuffmanDyntreeCodeLengthsOrder[rank]], + 3, + ); + } + + _treeLiteral.writeTree(_treeCodeLengths); + _treeDistances.writeTree(_treeCodeLengths); + } + + int _insertString() { + int match; + final int hash = + ((_currentHash << hashShift) ^ + _dataWindow![_stringStart + (minMatch - 1)]) & + hashMask; + + _hashPrevious[_stringStart & wmask] = match = _hashHead[hash]; + _hashHead[hash] = _stringStart.toSigned(16); + _currentHash = hash; + return match & 0xffff; + } + + void _huffmanCompressBlock() { + for (int i = 0; i < _iBufferPosition; i++) { + final int litlen = _arrLiteralsBuffer[i] & 255; + int dist = _arrDistancesBuffer[i]; + + if (dist-- != 0) { + final int lc = _huffmanLengthCode(litlen); + _treeLiteral.writeCodeToStream(lc); + + int bits = (lc - 261) ~/ 4; + if (bits > 0 && bits <= 5) { + pendingBufferWriteBits(litlen & ((1 << bits) - 1), bits); + } + + final int dc = _huffmanDistanceCode(dist); + _treeDistances.writeCodeToStream(dc); + + bits = dc ~/ 2 - 1; + if (bits > 0) { + pendingBufferWriteBits(dist & ((1 << bits) - 1), bits); + } + } else { + _treeLiteral.writeCodeToStream(litlen); + } + } + + _treeLiteral.writeCodeToStream(defHuffmanEndblockSymbol); + } + + int _huffmanDistanceCode(int distance) { + int code = 0; + + while (distance >= 4) { + code += 2; + distance >>= 1; + } + return code + distance; + } + + int _huffmanLengthCode(int len) { + if (len == 255) { + return 285; + } + + int code = 257; + + while (len >= 8) { + code += 4; + len >>= 1; + } + + return code + len; + } + + void _huffmanFlushStoredBlock( + List stored, + int storedOffset, + int storedLength, + bool lastBlock, + ) { + pendingBufferWriteBits((0 << 1) + (lastBlock ? 1 : 0), 3); + _pendingBufferAlignToByte(); + _pendingBufferWriteShort(storedLength); + _pendingBufferWriteShort(~storedLength); + _pendingBufferWriteByteBlock(stored, storedOffset, storedLength); + _huffmanReset(); + } + + void _huffmanReset() { + _iBufferPosition = 0; + _iExtraBits = 0; + _treeLiteral.reset(); + _treeDistances.reset(); + _treeCodeLengths!.reset(); + } + + void _pendingBufferWriteShort(int s) { + _pendingBuffer[_pendingBufferLength++] = s.toUnsigned(8); + _pendingBuffer[_pendingBufferLength++] = (s >> 8).toUnsigned(8); + } + + void _pendingBufferWriteByteBlock(List data, int offset, int length) { + List.copyRange( + _pendingBuffer, + _pendingBufferLength, + data, + offset, + offset + length, + ); + _pendingBufferLength += length; + } + + void _pendingBufferAlignToByte() { + if (_pendingBufferBitsInCache > 0) { + _pendingBuffer[_pendingBufferLength++] = _pendingBufferBitsCache + .toUnsigned(8); + + if (_pendingBufferBitsInCache > 8) { + _pendingBuffer[_pendingBufferLength++] = (_pendingBufferBitsCache >> 8) + .toUnsigned(8); + } + } + + _pendingBufferBitsCache = 0; + _pendingBufferBitsInCache = 0; + } + + /// internal method + void pendingBufferWriteBits(int b, int count) { + _pendingBufferBitsCache |= (b << _pendingBufferBitsInCache).toUnsigned(32); + _pendingBufferBitsInCache += count; + + _pendingBufferFlushBits(); + } + + bool _huffmanTallyLit(int literal) { + _arrDistancesBuffer[_iBufferPosition] = 0; + _arrLiteralsBuffer[_iBufferPosition++] = literal.toUnsigned(8); + _treeLiteral.codeFrequences[literal]++; + return _huffmanIsFull; + } + + void _fillWindow() { + if (_stringStart >= wsize + maxDist) { + _slideWindow(); + } + + while (_lookAhead < minLookahead && _inputOffset < _inputEnd) { + int more = 2 * wsize - _lookAhead - _stringStart; + if (more > _inputEnd - _inputOffset) { + more = _inputEnd - _inputOffset; + } + List.copyRange( + _dataWindow!, + _stringStart + _lookAhead, + _inputBuffer!, + _inputOffset, + _inputOffset + more, + ); + + _inputOffset += more; + _lookAhead += more; + } + + if (_lookAhead >= minMatch) { + _updateHash(); + } + } + + void _slideWindow() { + List.copyRange(_dataWindow!, 0, _dataWindow!, wsize, wsize + wsize); + _matchStart -= wsize; + _stringStart -= wsize; + _blockStart -= wsize; + + for (int i = 0; i < hashSize; ++i) { + final int m = _hashHead[i] & 0xffff; + _hashHead[i] = ((m >= wsize) ? (m - wsize) : 0).toSigned(16); + } + + for (int i = 0; i < wsize; i++) { + final int m = _hashPrevious[i] & 0xffff; + _hashPrevious[i] = ((m >= wsize) ? (m - wsize) : 0).toSigned(16); + } + } + + void _updateHash() { + _currentHash = + (_dataWindow![_stringStart] << hashShift) ^ + _dataWindow![_stringStart + 1]; + } + + void _pendingBufferFlush() { + _pendingBufferFlushBits(); + if (_pendingBufferLength > 0) { + final List array = List.filled(_pendingBufferLength, 0); + array.setAll(0, _pendingBuffer.sublist(0, _pendingBufferLength)); + _stream.addAll(array); + } + _pendingBufferLength = 0; + } + + /// Flushes fully recorded bytes to buffer array. + int _pendingBufferFlushBits() { + int result = 0; + while (_pendingBufferBitsInCache >= 8 && + _pendingBufferLength < defPendingBufferSize) { + _pendingBuffer[_pendingBufferLength++] = _pendingBufferBitsCache + .toUnsigned(8); + _pendingBufferBitsCache >>= 8; + _pendingBufferBitsInCache -= 8; + result++; + } + return result; + } + + /// internal method + // ignore: unused_element + void close() { + if (_bStreamClosed) { + return; + } + do { + _pendingBufferFlush(); + if (!_compressData(true)) { + _pendingBufferFlush(); + _pendingBufferAlignToByte(); + + if (!_bNoWrap) { + _pendingBufferWriteShortMSB(_checksum >> 16); + _pendingBufferWriteShortMSB(_checksum & 0xffff); + } + + _pendingBufferFlush(); + } + } while (!_needsInput || !_pendingBufferIsFlushed); + + _bStreamClosed = true; + + if (_bCloseStream) { + _stream.clear(); + } + } + + /// internal field + static int bitReverse(int value) { + return (defReverseBits[(value & 15)] << 12 | + defReverseBits[((value >> 4) & 15)] << 8 | + defReverseBits[((value >> 8) & 15)] << 4 | + defReverseBits[(value >> 12)]) + .toSigned(16); + } + + /// internal method + static int checksumUpdate( + int checksum, + List? buffer, + int offset, + int length, + ) { + int checksumUint = checksum.toUnsigned(32); + int s1 = checksumUint & 65535; + int s2 = checksumUint >> checkSumBitOffset; + while (length > 0) { + int steps = min(length, checksumIterationCount); + length -= steps; + while (--steps >= 0) { + s1 = s1 + (buffer![offset++] & 255).toUnsigned(32); + s2 += s1; + } + s1 %= checksumBase; + s2 %= checksumBase; + } + checksumUint = (s2 << checkSumBitOffset) | s1; + return checksumUint; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressor_huffman_tree.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressor_huffman_tree.dart index 00ef61169..0ffe9a9b8 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressor_huffman_tree.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/compressor_huffman_tree.dart @@ -1,386 +1,386 @@ -import 'dart:math'; - -import 'compressed_stream_writer.dart'; - -/// Represents the Huffman Tree. -class CompressorHuffmanTree { - /// Create a new Huffman tree. - CompressorHuffmanTree( - CompressedStreamWriter writer, - int iElementsCount, - int iMinimumCodes, - int iMaximumLength, - ) { - _writer = writer; - _codeMinimumCount = iMinimumCodes; - _maximumLength = iMaximumLength; - codeFrequences = List.filled(iElementsCount, 0); - _lengthCounts = List.filled(iMaximumLength, 0); - } - - /// internal field - static const List defReverseBits = [ - 0, - 8, - 4, - 12, - 2, - 10, - 6, - 14, - 1, - 9, - 5, - 13, - 3, - 11, - 7, - 15, - ]; - List? _codes; - late List _lengthCounts; - late int _codeMinimumCount; - int? _maximumLength; - late CompressedStreamWriter _writer; - - /// internal field - late List codeFrequences; - - /// internal field - late int codeCount; - - /// internal field - List? codeLengths; - - /// internal method - void buildTree() { - final int iCodesCount = codeFrequences.length; - final List arrTree = List.filled(iCodesCount, 0); - int iTreeLength = 0; - int iMaxCode = 0; - - for (int n = 0; n < iCodesCount; n++) { - final int freq = codeFrequences[n]; - - if (freq != 0) { - int pos = iTreeLength++; - int ppos; - - while (pos > 0 && - codeFrequences[arrTree[ppos = (pos - 1) ~/ 2]] > freq) { - arrTree[pos] = arrTree[ppos]; - pos = ppos; - } - - arrTree[pos] = n; - - iMaxCode = n; - } - } - - while (iTreeLength < 2) { - arrTree[iTreeLength++] = (iMaxCode < 2) ? ++iMaxCode : 0; - } - - codeCount = max(iMaxCode + 1, _codeMinimumCount); - - final int iLeafsCount = iTreeLength; - int iNodesCount = iLeafsCount; - final List childs = List.filled(4 * iTreeLength - 2, 0); - final List values = List.filled(2 * iTreeLength - 1, 0); - - for (int i = 0; i < iTreeLength; i++) { - final int node = arrTree[i]; - final int iIndex = 2 * i; - childs[iIndex] = node; - childs[iIndex + 1] = -1; - values[i] = codeFrequences[node] << 8; - arrTree[i] = i; - } - - do { - final int first = arrTree[0]; - int last = arrTree[--iTreeLength]; - int lastVal = values[last]; - - int ppos = 0; - int path = 1; - - while (path < iTreeLength) { - if (path + 1 < iTreeLength && - values[arrTree[path]] > values[arrTree[path + 1]]) { - path++; - } - - arrTree[ppos] = arrTree[path]; - ppos = path; - path = ppos * 2 + 1; - } - - while ((path = ppos) > 0 && - values[arrTree[ppos = (path - 1) ~/ 2]] > lastVal) { - arrTree[path] = arrTree[ppos]; - } - - arrTree[path] = last; - - final int second = arrTree[0]; - - last = iNodesCount++; - childs[2 * last] = first; - childs[2 * last + 1] = second; - final int mindepth = min(values[first] & 0xff, values[second] & 0xff); - values[last] = lastVal = values[first] + values[second] - mindepth + 1; - - ppos = 0; - path = 1; - - while (path < iTreeLength) { - if (path + 1 < iTreeLength && - values[arrTree[path]] > values[arrTree[path + 1]]) { - path++; - } - - arrTree[ppos] = arrTree[path]; - ppos = path; - path = ppos * 2 + 1; - } - - while ((path = ppos) > 0 && - values[arrTree[ppos = (path - 1) ~/ 2]] > lastVal) { - arrTree[path] = arrTree[ppos]; - } - - arrTree[path] = last; - } while (iTreeLength > 1); - - if (arrTree[0] != childs.length / 2 - 1) { - throw Exception('Heap invariant violated'); - } - - _buildLength(childs); - } - - void _buildLength(List childs) { - codeLengths = List.filled(codeFrequences.length, 0); - final int numNodes = childs.length ~/ 2; - final int numLeafs = (numNodes + 1) ~/ 2; - int overflow = 0; - - for (int i = 0; i < _maximumLength!; i++) { - _lengthCounts[i] = 0; - } - - // Calculating optimal code lengths - final List lengths = List.filled(numNodes, 0); - lengths[numNodes - 1] = 0; - - for (int i = numNodes - 1; i >= 0; i--) { - final int iChildIndex = 2 * i + 1; - - if (childs[iChildIndex] != -1) { - int bitLength = lengths[i] + 1; - - if (bitLength > _maximumLength!) { - bitLength = _maximumLength!; - overflow++; - } - - lengths[childs[iChildIndex - 1]] = - lengths[childs[iChildIndex]] = bitLength; - } else { - final int bitLength = lengths[i]; - _lengthCounts[bitLength - 1]++; - codeLengths![childs[iChildIndex - 1]] = lengths[i].toUnsigned(8); - } - } - - if (overflow == 0) { - return; - } - - int iIncreasableLength = _maximumLength! - 1; - - do { - // Find the first bit codeLengths which could increase. - while (_lengthCounts[--iIncreasableLength] == 0) {} - - do { - _lengthCounts[iIncreasableLength]--; - _lengthCounts[++iIncreasableLength]++; - overflow -= 1 << (_maximumLength! - 1 - iIncreasableLength); - } while (overflow > 0 && iIncreasableLength < _maximumLength! - 1); - } while (overflow > 0); - - _lengthCounts[_maximumLength! - 1] += overflow; - _lengthCounts[_maximumLength! - 2] -= overflow; - - // Recreate tree. - int nodePtr = 2 * numLeafs; - - for (int? bits = _maximumLength; bits != 0; bits--) { - int n = _lengthCounts[bits! - 1]; - - while (n > 0) { - final int childPtr = 2 * childs[nodePtr++]; - - if (childs[childPtr + 1] == -1) { - codeLengths![childs[childPtr]] = bits.toUnsigned(8); - n--; - } - } - } - } - - /// internal method - void calcBLFreq(CompressorHuffmanTree? blTree) { - int maxCount; - int minCount; - int count; - int curlen = -1; - int i = 0; - while (i < codeCount) { - count = 1; - final int nextlen = codeLengths![i]; - if (nextlen == 0) { - maxCount = 138; - minCount = 3; - } else { - maxCount = 6; - minCount = 3; - if (curlen != nextlen) { - blTree!.codeFrequences[nextlen]++; - count = 0; - } - } - curlen = nextlen; - i++; - while (i < codeCount && curlen == codeLengths![i]) { - i++; - if (++count >= maxCount) { - break; - } - } - if (count < minCount) { - blTree!.codeFrequences[curlen] += count.toSigned(16); - } else if (curlen != 0) { - blTree!.codeFrequences[16]++; - } else if (count <= 10) { - blTree!.codeFrequences[17]++; - } else { - blTree!.codeFrequences[18]++; - } - } - } - - /// internal method - int getEncodedLength() { - int len = 0; - for (int i = 0; i < codeFrequences.length; i++) { - len += codeFrequences[i] * codeLengths![i]; - } - return len; - } - - /// internal method - void writeCodeToStream(int code) { - _writer.pendingBufferWriteBits(_codes![code] & 0xffff, codeLengths![code]); - } - - /// internal method - void setStaticCodes(List codes, List lengths) { - _codes = List.from(codes); - codeLengths = List.from(lengths); - } - - /// internal method - void writeTree(CompressorHuffmanTree? blTree) { - int iMaxRepeatCount; - int iMinRepeatCount; - int iCurrentRepeatCount; - int iCurrentCodeLength = -1; - - int i = 0; - while (i < codeCount) { - iCurrentRepeatCount = 1; - final int nextlen = codeLengths![i]; - - if (nextlen == 0) { - iMaxRepeatCount = 138; - iMinRepeatCount = 3; - } else { - iMaxRepeatCount = 6; - iMinRepeatCount = 3; - - if (iCurrentCodeLength != nextlen) { - blTree!.writeCodeToStream(nextlen); - iCurrentRepeatCount = 0; - } - } - - iCurrentCodeLength = nextlen; - i++; - - while (i < codeCount && iCurrentCodeLength == codeLengths![i]) { - i++; - - if (++iCurrentRepeatCount >= iMaxRepeatCount) { - break; - } - } - - if (iCurrentRepeatCount < iMinRepeatCount) { - while (iCurrentRepeatCount-- > 0) { - blTree!.writeCodeToStream(iCurrentCodeLength); - } - } else if (iCurrentCodeLength != 0) { - blTree!.writeCodeToStream(16); - _writer.pendingBufferWriteBits(iCurrentRepeatCount - 3, 2); - } else if (iCurrentRepeatCount <= 10) { - blTree!.writeCodeToStream(17); - _writer.pendingBufferWriteBits(iCurrentRepeatCount - 3, 3); - } else { - blTree!.writeCodeToStream(18); - _writer.pendingBufferWriteBits(iCurrentRepeatCount - 11, 7); - } - } - } - - /// internal method - void buildCodes() { - final List nextCode = List.filled(_maximumLength!, 0); - _codes = List.filled(codeCount, 0); - int code = 0; - - for (int bitsCount = 0; bitsCount < _maximumLength!; bitsCount++) { - nextCode[bitsCount] = code; - code += _lengthCounts[bitsCount] << (15 - bitsCount); - } - - for (int i = 0; i < codeCount; i++) { - final int bits = codeLengths![i]; - - if (bits > 0) { - _codes![i] = _bitReverse(nextCode[bits - 1]); - nextCode[bits - 1] += 1 << (16 - bits); - } - } - } - - int _bitReverse(int value) { - return (defReverseBits[value & 15] << 12 | - defReverseBits[(value >> 4) & 15] << 8 | - defReverseBits[(value >> 8) & 15] << 4 | - defReverseBits[value >> 12]) - .toSigned(16); - } - - /// internal method - void reset() { - for (int i = 0; i < codeFrequences.length; i++) { - codeFrequences[i] = 0; - } - _codes = null; - codeLengths = null; - } -} +import 'dart:math'; + +import 'compressed_stream_writer.dart'; + +/// Represents the Huffman Tree. +class CompressorHuffmanTree { + /// Create a new Huffman tree. + CompressorHuffmanTree( + CompressedStreamWriter writer, + int iElementsCount, + int iMinimumCodes, + int iMaximumLength, + ) { + _writer = writer; + _codeMinimumCount = iMinimumCodes; + _maximumLength = iMaximumLength; + codeFrequences = List.filled(iElementsCount, 0); + _lengthCounts = List.filled(iMaximumLength, 0); + } + + /// internal field + static const List defReverseBits = [ + 0, + 8, + 4, + 12, + 2, + 10, + 6, + 14, + 1, + 9, + 5, + 13, + 3, + 11, + 7, + 15, + ]; + List? _codes; + late List _lengthCounts; + late int _codeMinimumCount; + int? _maximumLength; + late CompressedStreamWriter _writer; + + /// internal field + late List codeFrequences; + + /// internal field + late int codeCount; + + /// internal field + List? codeLengths; + + /// internal method + void buildTree() { + final int iCodesCount = codeFrequences.length; + final List arrTree = List.filled(iCodesCount, 0); + int iTreeLength = 0; + int iMaxCode = 0; + + for (int n = 0; n < iCodesCount; n++) { + final int freq = codeFrequences[n]; + + if (freq != 0) { + int pos = iTreeLength++; + int ppos; + + while (pos > 0 && + codeFrequences[arrTree[ppos = (pos - 1) ~/ 2]] > freq) { + arrTree[pos] = arrTree[ppos]; + pos = ppos; + } + + arrTree[pos] = n; + + iMaxCode = n; + } + } + + while (iTreeLength < 2) { + arrTree[iTreeLength++] = (iMaxCode < 2) ? ++iMaxCode : 0; + } + + codeCount = max(iMaxCode + 1, _codeMinimumCount); + + final int iLeafsCount = iTreeLength; + int iNodesCount = iLeafsCount; + final List childs = List.filled(4 * iTreeLength - 2, 0); + final List values = List.filled(2 * iTreeLength - 1, 0); + + for (int i = 0; i < iTreeLength; i++) { + final int node = arrTree[i]; + final int iIndex = 2 * i; + childs[iIndex] = node; + childs[iIndex + 1] = -1; + values[i] = codeFrequences[node] << 8; + arrTree[i] = i; + } + + do { + final int first = arrTree[0]; + int last = arrTree[--iTreeLength]; + int lastVal = values[last]; + + int ppos = 0; + int path = 1; + + while (path < iTreeLength) { + if (path + 1 < iTreeLength && + values[arrTree[path]] > values[arrTree[path + 1]]) { + path++; + } + + arrTree[ppos] = arrTree[path]; + ppos = path; + path = ppos * 2 + 1; + } + + while ((path = ppos) > 0 && + values[arrTree[ppos = (path - 1) ~/ 2]] > lastVal) { + arrTree[path] = arrTree[ppos]; + } + + arrTree[path] = last; + + final int second = arrTree[0]; + + last = iNodesCount++; + childs[2 * last] = first; + childs[2 * last + 1] = second; + final int mindepth = min(values[first] & 0xff, values[second] & 0xff); + values[last] = lastVal = values[first] + values[second] - mindepth + 1; + + ppos = 0; + path = 1; + + while (path < iTreeLength) { + if (path + 1 < iTreeLength && + values[arrTree[path]] > values[arrTree[path + 1]]) { + path++; + } + + arrTree[ppos] = arrTree[path]; + ppos = path; + path = ppos * 2 + 1; + } + + while ((path = ppos) > 0 && + values[arrTree[ppos = (path - 1) ~/ 2]] > lastVal) { + arrTree[path] = arrTree[ppos]; + } + + arrTree[path] = last; + } while (iTreeLength > 1); + + if (arrTree[0] != childs.length / 2 - 1) { + throw Exception('Heap invariant violated'); + } + + _buildLength(childs); + } + + void _buildLength(List childs) { + codeLengths = List.filled(codeFrequences.length, 0); + final int numNodes = childs.length ~/ 2; + final int numLeafs = (numNodes + 1) ~/ 2; + int overflow = 0; + + for (int i = 0; i < _maximumLength!; i++) { + _lengthCounts[i] = 0; + } + + // Calculating optimal code lengths + final List lengths = List.filled(numNodes, 0); + lengths[numNodes - 1] = 0; + + for (int i = numNodes - 1; i >= 0; i--) { + final int iChildIndex = 2 * i + 1; + + if (childs[iChildIndex] != -1) { + int bitLength = lengths[i] + 1; + + if (bitLength > _maximumLength!) { + bitLength = _maximumLength!; + overflow++; + } + + lengths[childs[iChildIndex - 1]] = + lengths[childs[iChildIndex]] = bitLength; + } else { + final int bitLength = lengths[i]; + _lengthCounts[bitLength - 1]++; + codeLengths![childs[iChildIndex - 1]] = lengths[i].toUnsigned(8); + } + } + + if (overflow == 0) { + return; + } + + int iIncreasableLength = _maximumLength! - 1; + + do { + // Find the first bit codeLengths which could increase. + while (_lengthCounts[--iIncreasableLength] == 0) {} + + do { + _lengthCounts[iIncreasableLength]--; + _lengthCounts[++iIncreasableLength]++; + overflow -= 1 << (_maximumLength! - 1 - iIncreasableLength); + } while (overflow > 0 && iIncreasableLength < _maximumLength! - 1); + } while (overflow > 0); + + _lengthCounts[_maximumLength! - 1] += overflow; + _lengthCounts[_maximumLength! - 2] -= overflow; + + // Recreate tree. + int nodePtr = 2 * numLeafs; + + for (int? bits = _maximumLength; bits != 0; bits--) { + int n = _lengthCounts[bits! - 1]; + + while (n > 0) { + final int childPtr = 2 * childs[nodePtr++]; + + if (childs[childPtr + 1] == -1) { + codeLengths![childs[childPtr]] = bits.toUnsigned(8); + n--; + } + } + } + } + + /// internal method + void calcBLFreq(CompressorHuffmanTree? blTree) { + int maxCount; + int minCount; + int count; + int curlen = -1; + int i = 0; + while (i < codeCount) { + count = 1; + final int nextlen = codeLengths![i]; + if (nextlen == 0) { + maxCount = 138; + minCount = 3; + } else { + maxCount = 6; + minCount = 3; + if (curlen != nextlen) { + blTree!.codeFrequences[nextlen]++; + count = 0; + } + } + curlen = nextlen; + i++; + while (i < codeCount && curlen == codeLengths![i]) { + i++; + if (++count >= maxCount) { + break; + } + } + if (count < minCount) { + blTree!.codeFrequences[curlen] += count.toSigned(16); + } else if (curlen != 0) { + blTree!.codeFrequences[16]++; + } else if (count <= 10) { + blTree!.codeFrequences[17]++; + } else { + blTree!.codeFrequences[18]++; + } + } + } + + /// internal method + int getEncodedLength() { + int len = 0; + for (int i = 0; i < codeFrequences.length; i++) { + len += codeFrequences[i] * codeLengths![i]; + } + return len; + } + + /// internal method + void writeCodeToStream(int code) { + _writer.pendingBufferWriteBits(_codes![code] & 0xffff, codeLengths![code]); + } + + /// internal method + void setStaticCodes(List codes, List lengths) { + _codes = List.from(codes); + codeLengths = List.from(lengths); + } + + /// internal method + void writeTree(CompressorHuffmanTree? blTree) { + int iMaxRepeatCount; + int iMinRepeatCount; + int iCurrentRepeatCount; + int iCurrentCodeLength = -1; + + int i = 0; + while (i < codeCount) { + iCurrentRepeatCount = 1; + final int nextlen = codeLengths![i]; + + if (nextlen == 0) { + iMaxRepeatCount = 138; + iMinRepeatCount = 3; + } else { + iMaxRepeatCount = 6; + iMinRepeatCount = 3; + + if (iCurrentCodeLength != nextlen) { + blTree!.writeCodeToStream(nextlen); + iCurrentRepeatCount = 0; + } + } + + iCurrentCodeLength = nextlen; + i++; + + while (i < codeCount && iCurrentCodeLength == codeLengths![i]) { + i++; + + if (++iCurrentRepeatCount >= iMaxRepeatCount) { + break; + } + } + + if (iCurrentRepeatCount < iMinRepeatCount) { + while (iCurrentRepeatCount-- > 0) { + blTree!.writeCodeToStream(iCurrentCodeLength); + } + } else if (iCurrentCodeLength != 0) { + blTree!.writeCodeToStream(16); + _writer.pendingBufferWriteBits(iCurrentRepeatCount - 3, 2); + } else if (iCurrentRepeatCount <= 10) { + blTree!.writeCodeToStream(17); + _writer.pendingBufferWriteBits(iCurrentRepeatCount - 3, 3); + } else { + blTree!.writeCodeToStream(18); + _writer.pendingBufferWriteBits(iCurrentRepeatCount - 11, 7); + } + } + } + + /// internal method + void buildCodes() { + final List nextCode = List.filled(_maximumLength!, 0); + _codes = List.filled(codeCount, 0); + int code = 0; + + for (int bitsCount = 0; bitsCount < _maximumLength!; bitsCount++) { + nextCode[bitsCount] = code; + code += _lengthCounts[bitsCount] << (15 - bitsCount); + } + + for (int i = 0; i < codeCount; i++) { + final int bits = codeLengths![i]; + + if (bits > 0) { + _codes![i] = _bitReverse(nextCode[bits - 1]); + nextCode[bits - 1] += 1 << (16 - bits); + } + } + } + + int _bitReverse(int value) { + return (defReverseBits[value & 15] << 12 | + defReverseBits[(value >> 4) & 15] << 8 | + defReverseBits[(value >> 8) & 15] << 4 | + defReverseBits[value >> 12]) + .toSigned(16); + } + + /// internal method + void reset() { + for (int i = 0; i < codeFrequences.length; i++) { + codeFrequences[i] = 0; + } + _codes = null; + codeLengths = null; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/decompressor_huffman_tree.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/decompressor_huffman_tree.dart index 66762afea..bd5fa7151 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/decompressor_huffman_tree.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/decompressor_huffman_tree.dart @@ -1,204 +1,204 @@ -import 'compressed_stream_reader.dart'; -import 'compressed_stream_writer.dart'; - -/// internal class -class DecompressorHuffmanTree { - /// internal constructor - DecompressorHuffmanTree(List lengths) { - _buildTree(lengths); - } - - //Fields - static const int _maxBitLength = 15; - late List _tree; - static DecompressorHuffmanTree? _lengthTree; - static DecompressorHuffmanTree? _distanceTree; - - //Properties - /// internal property - static DecompressorHuffmanTree? get lengthTree { - if (_lengthTree == null) { - _initialize(); - } - return _lengthTree; - } - - /// internal property - static DecompressorHuffmanTree? get distanceTree { - if (_distanceTree == null) { - _initialize(); - } - return _distanceTree; - } - - //Implementation - static void _initialize() { - try { - List lengths; - int index; - // Generate huffman tree for lengths. - lengths = List.filled(288, 0, growable: true); - index = 0; - while (index < 144) { - lengths[index++] = 8; - } - while (index < 256) { - lengths[index++] = 9; - } - while (index < 280) { - lengths[index++] = 7; - } - while (index < 288) { - lengths[index++] = 8; - } - _lengthTree = DecompressorHuffmanTree(lengths); - lengths = List.filled(32, 0, growable: true); - index = 0; - while (index < 32) { - lengths[index++] = 5; - } - _distanceTree = DecompressorHuffmanTree(lengths); - } catch (e) { - throw ArgumentError.value( - e, - 'DecompressorHuffmanTree: fixed trees generation failed', - ); - } - } - - void _buildTree(List lengths) { - final List blCount = List.filled( - _maxBitLength + 1, - 0, - growable: true, - ); - final List nextCode = List.filled( - _maxBitLength + 1, - 0, - growable: true, - ); - int? treeSize; - int? code = 0; - final Map result = _prepareData( - blCount, - nextCode, - lengths, - treeSize, - ); - treeSize = result['treeSize'] as int?; - code = result['code'] as int; - _tree = _treeFromData(blCount, nextCode, lengths, code, treeSize!); - } - - Map _prepareData( - List blCount, - List nextCode, - List lengths, - int? treeSize, - ) { - int code = 0; - treeSize = 512; - for (int i = 0; i < lengths.length; i++) { - final int length = lengths[i]; - if (length > 0) { - blCount[length]++; - } - } - for (int bits = 1; bits <= _maxBitLength; bits++) { - nextCode[bits] = code; - code += blCount[bits] << (16 - bits); - - if (bits >= 10) { - final int start = nextCode[bits] & 0x1ff80; - final int end = code & 0x1ff80; - treeSize = treeSize! + ((end - start) >> (16 - bits)); - } - } - return {'treeSize': treeSize, 'code': code}; - } - - List _treeFromData( - List blCount, - List nextCode, - List lengths, - int? code, - int treeSize, - ) { - final List tree = List.filled(treeSize, 0, growable: true); - int pointer = 512; - const int increment = 1 << 7; - for (int bits = _maxBitLength; bits >= 10; bits--) { - final int end = code! & 0x1ff80; - code -= blCount[bits] << (16 - bits); - final int start = code & 0x1ff80; - for (int i = start; i < end; i += increment) { - tree[CompressedStreamWriter.bitReverse(i)] = ((-pointer << 4) | bits) - .toSigned(16); - pointer += 1 << (bits - 9); - } - } - - for (int i = 0; i < lengths.length; i++) { - final int bits = lengths[i]; - if (bits == 0) { - continue; - } - code = nextCode[bits]; - int revcode = CompressedStreamWriter.bitReverse(code); - if (bits <= 9) { - do { - tree[revcode] = ((i << 4) | bits).toSigned(16); - revcode += 1 << bits; - } while (revcode < 512); - } else { - int subTree = tree[revcode & 511]; - final int treeLen = 1 << (subTree & 15); - subTree = -(subTree >> 4); - do { - tree[subTree | (revcode >> 9)] = ((i << 4) | bits).toSigned(16); - revcode += 1 << bits; - } while (revcode < treeLen); - } - nextCode[bits] = code + (1 << (16 - bits)); - } - return tree; - } - - /// internal method - int unpackSymbol(CompressedStreamReader input) { - int lookahead, symbol; - if ((lookahead = input.peekBits(9)) >= 0) { - if ((symbol = _tree[lookahead]) >= 0) { - input.skipBits(symbol & 15); - return symbol >> 4; - } - final int subtree = -(symbol >> 4); - final int bitlen = symbol & 15; - if ((lookahead = input.peekBits(bitlen)) >= 0) { - symbol = _tree[subtree | (lookahead >> 9)]; - input.skipBits(symbol & 15); - return symbol >> 4; - } else { - final int bits = input.bufferedBits; - lookahead = input.peekBits(bits); - symbol = _tree[subtree | (lookahead >> 9)]; - if ((symbol & 15) <= bits) { - input.skipBits(symbol & 15); - return symbol >> 4; - } else { - return -1; - } - } - } else { - final int bits = input.bufferedBits; - lookahead = input.peekBits(bits); - symbol = _tree[lookahead]; - if (symbol >= 0 && (symbol & 15) <= bits) { - input.skipBits(symbol & 15); - return symbol >> 4; - } else { - return -1; - } - } - } -} +import 'compressed_stream_reader.dart'; +import 'compressed_stream_writer.dart'; + +/// internal class +class DecompressorHuffmanTree { + /// internal constructor + DecompressorHuffmanTree(List lengths) { + _buildTree(lengths); + } + + //Fields + static const int _maxBitLength = 15; + late List _tree; + static DecompressorHuffmanTree? _lengthTree; + static DecompressorHuffmanTree? _distanceTree; + + //Properties + /// internal property + static DecompressorHuffmanTree? get lengthTree { + if (_lengthTree == null) { + _initialize(); + } + return _lengthTree; + } + + /// internal property + static DecompressorHuffmanTree? get distanceTree { + if (_distanceTree == null) { + _initialize(); + } + return _distanceTree; + } + + //Implementation + static void _initialize() { + try { + List lengths; + int index; + // Generate huffman tree for lengths. + lengths = List.filled(288, 0, growable: true); + index = 0; + while (index < 144) { + lengths[index++] = 8; + } + while (index < 256) { + lengths[index++] = 9; + } + while (index < 280) { + lengths[index++] = 7; + } + while (index < 288) { + lengths[index++] = 8; + } + _lengthTree = DecompressorHuffmanTree(lengths); + lengths = List.filled(32, 0, growable: true); + index = 0; + while (index < 32) { + lengths[index++] = 5; + } + _distanceTree = DecompressorHuffmanTree(lengths); + } catch (e) { + throw ArgumentError.value( + e, + 'DecompressorHuffmanTree: fixed trees generation failed', + ); + } + } + + void _buildTree(List lengths) { + final List blCount = List.filled( + _maxBitLength + 1, + 0, + growable: true, + ); + final List nextCode = List.filled( + _maxBitLength + 1, + 0, + growable: true, + ); + int? treeSize; + int? code = 0; + final Map result = _prepareData( + blCount, + nextCode, + lengths, + treeSize, + ); + treeSize = result['treeSize'] as int?; + code = result['code'] as int; + _tree = _treeFromData(blCount, nextCode, lengths, code, treeSize!); + } + + Map _prepareData( + List blCount, + List nextCode, + List lengths, + int? treeSize, + ) { + int code = 0; + treeSize = 512; + for (int i = 0; i < lengths.length; i++) { + final int length = lengths[i]; + if (length > 0) { + blCount[length]++; + } + } + for (int bits = 1; bits <= _maxBitLength; bits++) { + nextCode[bits] = code; + code += blCount[bits] << (16 - bits); + + if (bits >= 10) { + final int start = nextCode[bits] & 0x1ff80; + final int end = code & 0x1ff80; + treeSize = treeSize! + ((end - start) >> (16 - bits)); + } + } + return {'treeSize': treeSize, 'code': code}; + } + + List _treeFromData( + List blCount, + List nextCode, + List lengths, + int? code, + int treeSize, + ) { + final List tree = List.filled(treeSize, 0, growable: true); + int pointer = 512; + const int increment = 1 << 7; + for (int bits = _maxBitLength; bits >= 10; bits--) { + final int end = code! & 0x1ff80; + code -= blCount[bits] << (16 - bits); + final int start = code & 0x1ff80; + for (int i = start; i < end; i += increment) { + tree[CompressedStreamWriter.bitReverse(i)] = ((-pointer << 4) | bits) + .toSigned(16); + pointer += 1 << (bits - 9); + } + } + + for (int i = 0; i < lengths.length; i++) { + final int bits = lengths[i]; + if (bits == 0) { + continue; + } + code = nextCode[bits]; + int revcode = CompressedStreamWriter.bitReverse(code); + if (bits <= 9) { + do { + tree[revcode] = ((i << 4) | bits).toSigned(16); + revcode += 1 << bits; + } while (revcode < 512); + } else { + int subTree = tree[revcode & 511]; + final int treeLen = 1 << (subTree & 15); + subTree = -(subTree >> 4); + do { + tree[subTree | (revcode >> 9)] = ((i << 4) | bits).toSigned(16); + revcode += 1 << bits; + } while (revcode < treeLen); + } + nextCode[bits] = code + (1 << (16 - bits)); + } + return tree; + } + + /// internal method + int unpackSymbol(CompressedStreamReader input) { + int lookahead, symbol; + if ((lookahead = input.peekBits(9)) >= 0) { + if ((symbol = _tree[lookahead]) >= 0) { + input.skipBits(symbol & 15); + return symbol >> 4; + } + final int subtree = -(symbol >> 4); + final int bitlen = symbol & 15; + if ((lookahead = input.peekBits(bitlen)) >= 0) { + symbol = _tree[subtree | (lookahead >> 9)]; + input.skipBits(symbol & 15); + return symbol >> 4; + } else { + final int bits = input.bufferedBits; + lookahead = input.peekBits(bits); + symbol = _tree[subtree | (lookahead >> 9)]; + if ((symbol & 15) <= bits) { + input.skipBits(symbol & 15); + return symbol >> 4; + } else { + return -1; + } + } + } else { + final int bits = input.bufferedBits; + lookahead = input.peekBits(bits); + symbol = _tree[lookahead]; + if (symbol >= 0 && (symbol & 15) <= bits) { + input.skipBits(symbol & 15); + return symbol >> 4; + } else { + return -1; + } + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/decompressed_output.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/decompressed_output.dart index d7b4a9070..6f1c662d3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/decompressed_output.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/decompressed_output.dart @@ -1,122 +1,122 @@ -import 'dart:math'; - -import 'in_buffer.dart'; - -/// internal class -class DecompressedOutput { - /// internal constructor - DecompressedOutput() { - _dOutput = List.filled(_dOutSize, 0); - _end = 0; - _usedBytes = 0; - } - - //Fields - static const int _dOutSize = 32768; - static const int _dOutMask = 32767; - List? _dOutput; - int _end = 0; - int _usedBytes = 0; - - //Properties - /// internal property - int get unusedBytes => _dOutSize - _usedBytes; - - /// internal property - int? get usedBytes => _usedBytes; - - //Implementation - /// internal method - void write(int b) { - _dOutput![_end++] = b; - _end &= _dOutMask; - ++_usedBytes; - } - - /// internal method - void writeLD(int length, int distance) { - _usedBytes += length; - int copyStart = (_end - distance) & _dOutMask; - final int border = _dOutSize - length; - if (copyStart <= border && _end < border) { - if (length <= distance) { - List.copyRange( - _dOutput!, - _end, - _dOutput!, - copyStart, - copyStart + length, - ); - _end += length; - } else { - while (length-- > 0) { - _dOutput![_end++] = _dOutput![copyStart++]; - } - } - } else { - while (length-- > 0) { - _dOutput![_end++] = _dOutput![copyStart++]; - _end &= _dOutMask; - copyStart &= _dOutMask; - } - } - } - - /// internal method - int copyFrom(InBuffer input, int length) { - length = min(min(length, _dOutSize - _usedBytes), input.bytes); - int copied; - final int tailLen = _dOutSize - _end; - if (length > tailLen) { - copied = input.copyTo(_dOutput, _end, tailLen); - if (copied == tailLen) { - copied += input.copyTo(_dOutput, 0, length - tailLen); - } - } else { - copied = input.copyTo(_dOutput, _end, length); - } - _end = (_end + copied) & _dOutMask; - _usedBytes += copied; - return copied; - } - - /// internal method - Map copyTo(List output, int offset, int length) { - int? end; - if (length > _usedBytes) { - end = _end; - length = _usedBytes; - } else { - end = (_end - _usedBytes + length) & _dOutMask; - } - final int copied = length; - final int tailLen = length - end; - int sourceStart = _dOutSize - tailLen; - if (tailLen > 0) { - for ( - int i = 0; - i < tailLen && - i + sourceStart < _dOutput!.length && - i + offset < output.length; - i++ - ) { - output[offset + i] = _dOutput![sourceStart + i]; - } - final int sourceStartIndex = _dOutSize - tailLen; - List.copyRange( - output, - offset, - _dOutput!, - sourceStartIndex, - sourceStartIndex + tailLen, - ); - offset += tailLen; - length = end; - } - sourceStart = end - length; - final int sourceStartIndex = end - length; - List.copyRange(output, offset, _dOutput!, sourceStartIndex, end); - _usedBytes -= copied; - return {'count': copied, 'data': output}; - } -} +import 'dart:math'; + +import 'in_buffer.dart'; + +/// internal class +class DecompressedOutput { + /// internal constructor + DecompressedOutput() { + _dOutput = List.filled(_dOutSize, 0); + _end = 0; + _usedBytes = 0; + } + + //Fields + static const int _dOutSize = 32768; + static const int _dOutMask = 32767; + List? _dOutput; + int _end = 0; + int _usedBytes = 0; + + //Properties + /// internal property + int get unusedBytes => _dOutSize - _usedBytes; + + /// internal property + int? get usedBytes => _usedBytes; + + //Implementation + /// internal method + void write(int b) { + _dOutput![_end++] = b; + _end &= _dOutMask; + ++_usedBytes; + } + + /// internal method + void writeLD(int length, int distance) { + _usedBytes += length; + int copyStart = (_end - distance) & _dOutMask; + final int border = _dOutSize - length; + if (copyStart <= border && _end < border) { + if (length <= distance) { + List.copyRange( + _dOutput!, + _end, + _dOutput!, + copyStart, + copyStart + length, + ); + _end += length; + } else { + while (length-- > 0) { + _dOutput![_end++] = _dOutput![copyStart++]; + } + } + } else { + while (length-- > 0) { + _dOutput![_end++] = _dOutput![copyStart++]; + _end &= _dOutMask; + copyStart &= _dOutMask; + } + } + } + + /// internal method + int copyFrom(InBuffer input, int length) { + length = min(min(length, _dOutSize - _usedBytes), input.bytes); + int copied; + final int tailLen = _dOutSize - _end; + if (length > tailLen) { + copied = input.copyTo(_dOutput, _end, tailLen); + if (copied == tailLen) { + copied += input.copyTo(_dOutput, 0, length - tailLen); + } + } else { + copied = input.copyTo(_dOutput, _end, length); + } + _end = (_end + copied) & _dOutMask; + _usedBytes += copied; + return copied; + } + + /// internal method + Map copyTo(List output, int offset, int length) { + int? end; + if (length > _usedBytes) { + end = _end; + length = _usedBytes; + } else { + end = (_end - _usedBytes + length) & _dOutMask; + } + final int copied = length; + final int tailLen = length - end; + int sourceStart = _dOutSize - tailLen; + if (tailLen > 0) { + for ( + int i = 0; + i < tailLen && + i + sourceStart < _dOutput!.length && + i + offset < output.length; + i++ + ) { + output[offset + i] = _dOutput![sourceStart + i]; + } + final int sourceStartIndex = _dOutSize - tailLen; + List.copyRange( + output, + offset, + _dOutput!, + sourceStartIndex, + sourceStartIndex + tailLen, + ); + offset += tailLen; + length = end; + } + sourceStart = end - length; + final int sourceStartIndex = end - length; + List.copyRange(output, offset, _dOutput!, sourceStartIndex, end); + _usedBytes -= copied; + return {'count': copied, 'data': output}; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/deflate_stream.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/deflate_stream.dart index 55f58bf4a..44242c15c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/deflate_stream.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/deflate_stream.dart @@ -1,67 +1,67 @@ -import 'in_flatter.dart'; - -/// internal class -class DeflateStream { - /// internal constructor - DeflateStream(List data, int offset, bool leaveOpen) { - _offset = offset; - _data = data; - _leaveOpen = leaveOpen; - _inflater = Inflater(); - _buffer = List.filled(8192, 0); - } - - //Fields - late List _data; - // ignore: unused_field - late bool? _leaveOpen; - late int _offset; - List? _buffer; - late Inflater _inflater; - - /// internal method - Map read(List? array, int offset, int count) { - int? length; - int cOffset = offset; - int rCount = count; - while (true) { - final Map inflateResult = _inflater.inflate( - array!, - cOffset, - rCount, - ); - length = inflateResult['count'] as int?; - array = inflateResult['data'] as List; - cOffset += length!; - rCount -= length; - if (rCount == 0) { - break; - } - if (_inflater.finished) { - break; - } - final Map result = _readBytes(); - final int? bytes = result['count'] as int?; - _buffer = result['buffer'] as List; - if (bytes == 0) { - break; - } - _inflater.setInput(_buffer, 0, bytes!); - } - return {'count': count - rCount, 'data': array}; - } - - Map _readBytes() { - if (_offset >= _data.length) { - return {'buffer': [], 'count': 0}; - } else { - int count = 0; - for (int i = 0; i < _buffer!.length && i + _offset < _data.length; i++) { - _buffer![i] = _data[_offset + i]; - count++; - } - _offset += count; - return {'buffer': _buffer, 'count': count}; - } - } -} +import 'in_flatter.dart'; + +/// internal class +class DeflateStream { + /// internal constructor + DeflateStream(List data, int offset, bool leaveOpen) { + _offset = offset; + _data = data; + _leaveOpen = leaveOpen; + _inflater = Inflater(); + _buffer = List.filled(8192, 0); + } + + //Fields + late List _data; + // ignore: unused_field + late bool? _leaveOpen; + late int _offset; + List? _buffer; + late Inflater _inflater; + + /// internal method + Map read(List? array, int offset, int count) { + int? length; + int cOffset = offset; + int rCount = count; + while (true) { + final Map inflateResult = _inflater.inflate( + array!, + cOffset, + rCount, + ); + length = inflateResult['count'] as int?; + array = inflateResult['data'] as List; + cOffset += length!; + rCount -= length; + if (rCount == 0) { + break; + } + if (_inflater.finished) { + break; + } + final Map result = _readBytes(); + final int? bytes = result['count'] as int?; + _buffer = result['buffer'] as List; + if (bytes == 0) { + break; + } + _inflater.setInput(_buffer, 0, bytes!); + } + return {'count': count - rCount, 'data': array}; + } + + Map _readBytes() { + if (_offset >= _data.length) { + return {'buffer': [], 'count': 0}; + } else { + int count = 0; + for (int i = 0; i < _buffer!.length && i + _offset < _data.length; i++) { + _buffer![i] = _data[_offset + i]; + count++; + } + _offset += count; + return {'buffer': _buffer, 'count': count}; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/huffman_tree.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/huffman_tree.dart index 1e31f91e7..172359cff 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/huffman_tree.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/huffman_tree.dart @@ -1,175 +1,175 @@ -import 'in_buffer.dart'; - -/// internal class -class HuffmanTree { - /// internal constructor - HuffmanTree({List? code, bool? isLtree}) { - if (code == null && isLtree != null) { - _clArray = isLtree ? _getLTree() : _getDTree(); - } else if (code != null) { - _clArray = code; - } else { - ArgumentError.value(code, 'code', 'The value of the code cannot be null'); - } - if (_clArray.length == maxLTree) { - _tBits = 9; - } else { - _tBits = 7; - } - _tMask = (1 << _tBits) - 1; - _createTable(); - } - - // Constants - /// internal field - static const int maxLTree = 288; - - /// internal field - static const int maxDTree = 32; - - /// internal field - static const int nCLength = 19; - - // Fields - late int _tBits; - late List _table; - late List? _left; - late List? _right; - late List _clArray; - late int _tMask; - - //Implementation - List _getLTree() { - final List lTree = List.filled(maxLTree, 0); - for (int i = 0; i <= 143; i++) { - lTree[i] = 8.toUnsigned(8); - } - for (int i = 144; i <= 255; i++) { - lTree[i] = 9.toUnsigned(8); - } - for (int i = 256; i <= 279; i++) { - lTree[i] = 7.toUnsigned(8); - } - for (int i = 280; i <= 287; i++) { - lTree[i] = 8.toUnsigned(8); - } - return lTree; - } - - List _getDTree() { - return List.filled(maxDTree, 5); - } - - List _calculateHashCode() { - final List bit = List.filled(17, 0); - for (int i = 0; i < _clArray.length; i++) { - bit[_clArray[i]]++; - } - bit[0] = 0; - final List next = List.filled(17, 0); - int temp = 0; - for (int bits = 1; bits <= 16; bits++) { - temp = (temp + bit[bits - 1]) << 1; - next[bits] = temp; - } - final List code = List.filled(maxLTree, 0); - for (int i = 0; i < _clArray.length; i++) { - final int len = _clArray[i]; - if (len > 0) { - code[i] = _bitReverse(next[len], len); - next[len]++; - } - } - return code; - } - - int _bitReverse(int code, int length) { - int newcode = 0; - do { - newcode |= code & 1; - newcode <<= 1; - code >>= 1; - } while (--length > 0); - return newcode >> 1; - } - - void _createTable() { - final List codeArray = _calculateHashCode(); - _table = List.filled(1 << _tBits, 0); - _left = List.filled(2 * _clArray.length, 0); - _right = List.filled(2 * _clArray.length, 0); - int avail = _clArray.length.toSigned(16); - for (int ch = 0; ch < _clArray.length; ch++) { - final int len = _clArray[ch]; - if (len > 0) { - int start = codeArray[ch]; - if (len <= _tBits) { - final int i = 1 << len; - if (start >= i) { - throw ArgumentError.value('Invalid Data.'); - } - final int l = 1 << (_tBits - len); - for (int j = 0; j < l; j++) { - _table[start] = ch.toSigned(16); - start += i; - } - } else { - int ofBits = len - _tBits; - int bitMask = 1 << _tBits; - int index = start & ((1 << _tBits) - 1); - List array = _table; - do { - int value = array[index].toSigned(16); - if (value == 0) { - array[index] = (-avail).toSigned(16); - value = (-avail).toSigned(16); - avail++; - } - if (value > 0) { - throw ArgumentError.value('Invalid Data.'); - } - if ((start & bitMask) == 0) { - array = _left!; - } else { - array = _right!; - } - index = -value; - bitMask <<= 1; - ofBits--; - } while (ofBits != 0); - array[index] = ch.toSigned(16); - } - } - } - } - - /// internal method - int getNextSymbol(InBuffer input) { - final int? bitBuffer = input.load16Bits(); - if (input.bits == 0) { - return -1; - } - int symbol = _table[bitBuffer! & _tMask]; - if (symbol < 0) { - int mask = (1 << _tBits).toUnsigned(32); - do { - symbol = -symbol; - if ((bitBuffer & mask) == 0) { - symbol = _left![symbol]; - } else { - symbol = _right![symbol]; - } - mask <<= 1; - } while (symbol < 0); - } - final int codeLength = _clArray[symbol]; - if (codeLength <= 0) { - throw ArgumentError.value('Invalid Data.'); - } - if (codeLength > input.bits) { - return -1; - } - input.skipBits(codeLength); - return symbol; - } -} +import 'in_buffer.dart'; + +/// internal class +class HuffmanTree { + /// internal constructor + HuffmanTree({List? code, bool? isLtree}) { + if (code == null && isLtree != null) { + _clArray = isLtree ? _getLTree() : _getDTree(); + } else if (code != null) { + _clArray = code; + } else { + ArgumentError.value(code, 'code', 'The value of the code cannot be null'); + } + if (_clArray.length == maxLTree) { + _tBits = 9; + } else { + _tBits = 7; + } + _tMask = (1 << _tBits) - 1; + _createTable(); + } + + // Constants + /// internal field + static const int maxLTree = 288; + + /// internal field + static const int maxDTree = 32; + + /// internal field + static const int nCLength = 19; + + // Fields + late int _tBits; + late List _table; + late List? _left; + late List? _right; + late List _clArray; + late int _tMask; + + //Implementation + List _getLTree() { + final List lTree = List.filled(maxLTree, 0); + for (int i = 0; i <= 143; i++) { + lTree[i] = 8.toUnsigned(8); + } + for (int i = 144; i <= 255; i++) { + lTree[i] = 9.toUnsigned(8); + } + for (int i = 256; i <= 279; i++) { + lTree[i] = 7.toUnsigned(8); + } + for (int i = 280; i <= 287; i++) { + lTree[i] = 8.toUnsigned(8); + } + return lTree; + } + + List _getDTree() { + return List.filled(maxDTree, 5); + } + + List _calculateHashCode() { + final List bit = List.filled(17, 0); + for (int i = 0; i < _clArray.length; i++) { + bit[_clArray[i]]++; + } + bit[0] = 0; + final List next = List.filled(17, 0); + int temp = 0; + for (int bits = 1; bits <= 16; bits++) { + temp = (temp + bit[bits - 1]) << 1; + next[bits] = temp; + } + final List code = List.filled(maxLTree, 0); + for (int i = 0; i < _clArray.length; i++) { + final int len = _clArray[i]; + if (len > 0) { + code[i] = _bitReverse(next[len], len); + next[len]++; + } + } + return code; + } + + int _bitReverse(int code, int length) { + int newcode = 0; + do { + newcode |= code & 1; + newcode <<= 1; + code >>= 1; + } while (--length > 0); + return newcode >> 1; + } + + void _createTable() { + final List codeArray = _calculateHashCode(); + _table = List.filled(1 << _tBits, 0); + _left = List.filled(2 * _clArray.length, 0); + _right = List.filled(2 * _clArray.length, 0); + int avail = _clArray.length.toSigned(16); + for (int ch = 0; ch < _clArray.length; ch++) { + final int len = _clArray[ch]; + if (len > 0) { + int start = codeArray[ch]; + if (len <= _tBits) { + final int i = 1 << len; + if (start >= i) { + throw ArgumentError.value('Invalid Data.'); + } + final int l = 1 << (_tBits - len); + for (int j = 0; j < l; j++) { + _table[start] = ch.toSigned(16); + start += i; + } + } else { + int ofBits = len - _tBits; + int bitMask = 1 << _tBits; + int index = start & ((1 << _tBits) - 1); + List array = _table; + do { + int value = array[index].toSigned(16); + if (value == 0) { + array[index] = (-avail).toSigned(16); + value = (-avail).toSigned(16); + avail++; + } + if (value > 0) { + throw ArgumentError.value('Invalid Data.'); + } + if ((start & bitMask) == 0) { + array = _left!; + } else { + array = _right!; + } + index = -value; + bitMask <<= 1; + ofBits--; + } while (ofBits != 0); + array[index] = ch.toSigned(16); + } + } + } + } + + /// internal method + int getNextSymbol(InBuffer input) { + final int? bitBuffer = input.load16Bits(); + if (input.bits == 0) { + return -1; + } + int symbol = _table[bitBuffer! & _tMask]; + if (symbol < 0) { + int mask = (1 << _tBits).toUnsigned(32); + do { + symbol = -symbol; + if ((bitBuffer & mask) == 0) { + symbol = _left![symbol]; + } else { + symbol = _right![symbol]; + } + mask <<= 1; + } while (symbol < 0); + } + final int codeLength = _clArray[symbol]; + if (codeLength <= 0) { + throw ArgumentError.value('Invalid Data.'); + } + if (codeLength > input.bits) { + return -1; + } + input.skipBits(codeLength); + return symbol; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_buffer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_buffer.dart index 1556447df..13ffcd4e9 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_buffer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_buffer.dart @@ -1,130 +1,130 @@ -/// internal class -class InBuffer { - /// internal constructor - InBuffer() { - _bBuffer = 0; - _bInBuffer = 0; - _begin = 0; - _end = 0; - } - - //Fields - List? _buffer; - late int _begin; - late int _end; - late int _bBuffer; - late int _bInBuffer; - - //Properties - /// internal property - int get bytes => (_end - _begin) + (_bInBuffer ~/ 8); - - /// internal property - int get bits => _bInBuffer; - - //Implementation - /// internal method - bool availableBits(int count) { - if (_bInBuffer < count) { - if (_needsInput()) { - return false; - } - _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; - _bInBuffer += 8; - if (_bInBuffer < count) { - if (_needsInput()) { - return false; - } - _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; - _bInBuffer += 8; - } - } - return true; - } - - /// internal method - int? load16Bits() { - if (_bInBuffer < 8) { - if (_begin < _end) { - _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; - _bInBuffer += 8; - } - if (_begin < _end) { - _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; - _bInBuffer += 8; - } - } else if (_bInBuffer < 16) { - if (_begin < _end) { - _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; - _bInBuffer += 8; - } - } - return _bBuffer; - } - - int _getBitMask(int count) { - return (1.toUnsigned(32) << count) - 1; - } - - /// internal method - int getBits(int count) { - if (!availableBits(count)) { - return -1; - } - final int result = _bBuffer & _getBitMask(count); - _bBuffer >>= count; - _bInBuffer -= count; - return result; - } - - /// internal method - int copyTo(List? output, int offset, int length) { - int bitBuffer = 0; - while (_bInBuffer > 0 && length > 0) { - output![offset++] = _bBuffer.toUnsigned(8); - _bBuffer >>= 8; - _bInBuffer -= 8; - length--; - bitBuffer++; - } - if (length == 0) { - return bitBuffer; - } - final int avail = _end - _begin; - if (length > avail) { - length = avail; - } - for ( - int i = 0; - i < length && i + _begin < _buffer!.length && i + offset < output!.length; - i++ - ) { - output[offset + i] = _buffer![_begin + i]; - } - _begin += length; - return bitBuffer + length; - } - - bool _needsInput() { - return _begin == _end; - } - - /// internal method - void setInput(List? buffer, int offset, int length) { - _buffer = buffer; - _begin = offset; - _end = offset + length; - } - - /// internal method - void skipBits(int n) { - _bBuffer >>= n; - _bInBuffer -= n; - } - - /// internal method - void skipByteBoundary() { - _bBuffer >>= _bInBuffer % 8; - _bInBuffer = _bInBuffer - (_bInBuffer % 8); - } -} +/// internal class +class InBuffer { + /// internal constructor + InBuffer() { + _bBuffer = 0; + _bInBuffer = 0; + _begin = 0; + _end = 0; + } + + //Fields + List? _buffer; + late int _begin; + late int _end; + late int _bBuffer; + late int _bInBuffer; + + //Properties + /// internal property + int get bytes => (_end - _begin) + (_bInBuffer ~/ 8); + + /// internal property + int get bits => _bInBuffer; + + //Implementation + /// internal method + bool availableBits(int count) { + if (_bInBuffer < count) { + if (_needsInput()) { + return false; + } + _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; + _bInBuffer += 8; + if (_bInBuffer < count) { + if (_needsInput()) { + return false; + } + _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; + _bInBuffer += 8; + } + } + return true; + } + + /// internal method + int? load16Bits() { + if (_bInBuffer < 8) { + if (_begin < _end) { + _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; + _bInBuffer += 8; + } + if (_begin < _end) { + _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; + _bInBuffer += 8; + } + } else if (_bInBuffer < 16) { + if (_begin < _end) { + _bBuffer |= _buffer![_begin++].toUnsigned(32) << _bInBuffer; + _bInBuffer += 8; + } + } + return _bBuffer; + } + + int _getBitMask(int count) { + return (1.toUnsigned(32) << count) - 1; + } + + /// internal method + int getBits(int count) { + if (!availableBits(count)) { + return -1; + } + final int result = _bBuffer & _getBitMask(count); + _bBuffer >>= count; + _bInBuffer -= count; + return result; + } + + /// internal method + int copyTo(List? output, int offset, int length) { + int bitBuffer = 0; + while (_bInBuffer > 0 && length > 0) { + output![offset++] = _bBuffer.toUnsigned(8); + _bBuffer >>= 8; + _bInBuffer -= 8; + length--; + bitBuffer++; + } + if (length == 0) { + return bitBuffer; + } + final int avail = _end - _begin; + if (length > avail) { + length = avail; + } + for ( + int i = 0; + i < length && i + _begin < _buffer!.length && i + offset < output!.length; + i++ + ) { + output[offset + i] = _buffer![_begin + i]; + } + _begin += length; + return bitBuffer + length; + } + + bool _needsInput() { + return _begin == _end; + } + + /// internal method + void setInput(List? buffer, int offset, int length) { + _buffer = buffer; + _begin = offset; + _end = offset + length; + } + + /// internal method + void skipBits(int n) { + _bBuffer >>= n; + _bInBuffer -= n; + } + + /// internal method + void skipByteBoundary() { + _bBuffer >>= _bInBuffer % 8; + _bInBuffer = _bInBuffer - (_bInBuffer % 8); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_flatter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_flatter.dart index db8549628..a4fa97b66 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_flatter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/deflate/in_flatter.dart @@ -1,808 +1,808 @@ -import '../enums.dart'; -import 'decompressed_output.dart'; -import 'huffman_tree.dart'; -import 'in_buffer.dart'; - -/// internal class -class Inflater { - /// internal constructor - Inflater() { - _bfinal = 0; - _bLength = 0; - _blBuffer = List.filled(4, 0); - _blockType = BlockType.unCompressedType; - _caSize = 0; - _clCodeCount = 0; - _extraBits = 0; - _lengthCode = 0; - _length = 0; - _llCodeCount = 0; - _output = DecompressedOutput(); - _input = InBuffer(); - _loopCounter = 0; - _codeList = List.filled( - HuffmanTree.maxLTree + HuffmanTree.maxDTree, - 0, - growable: true, - ); - _cltcl = List.filled(HuffmanTree.nCLength, 0, growable: true); - _inflaterstate = InflaterState.readingBFinal; - } - - //Fields - late DecompressedOutput _output; - late InBuffer _input; - late HuffmanTree _llTree; - late HuffmanTree _distanceTree; - late InflaterState _inflaterstate; - late int _bfinal; - late BlockType _blockType; - late List _blBuffer; - late int _bLength; - late int _length; - late int _distanceCode; - late int _extraBits; - late int _loopCounter; - late int _llCodeCount; - late int _dCodeCount; - late int _clCodeCount; - late int _caSize; - late int _lengthCode; - late List _codeList; - late List _cltcl; - late HuffmanTree _clTree; - - //Implementation - - /// internal method - void setInput(List? inputBytes, int offset, int length) { - _input.setInput(inputBytes, offset, length); - } - - /// internal property - bool get finished => - _inflaterstate == InflaterState.done || - _inflaterstate == InflaterState.vFooter; - - /// internal method - Map inflate(List bytes, int offset, int length) { - int i = 0; - do { - final Map result = _output.copyTo(bytes, offset, length); - final int copied = result['count'] as int; - bytes = result['data'] as List; - if (copied > 0) { - offset += copied; - i += copied; - length -= copied; - } - if (length == 0) { - break; - } - } while (!finished && _decode()!); - return {'count': i, 'data': bytes}; - } - - bool? _decode() { - bool? eob = false; - bool? result = false; - if (finished) { - return true; - } - if (_inflaterstate == InflaterState.readingBFinal) { - if (!_input.availableBits(1)) { - return false; - } - _bfinal = _input.getBits(1); - _inflaterstate = InflaterState.readingBType; - } - if (_inflaterstate == InflaterState.readingBType) { - if (!_input.availableBits(2)) { - _inflaterstate = InflaterState.readingBType; - return false; - } - _blockType = _getBlockType(_input.getBits(2)); - if (_blockType == BlockType.dynamicType) { - _inflaterstate = InflaterState.readingNLCodes; - } else if (_blockType == BlockType.staticType) { - _llTree = HuffmanTree(isLtree: true); - _distanceTree = HuffmanTree(isLtree: false); - _inflaterstate = InflaterState.decodeTop; - } else if (_blockType == BlockType.unCompressedType) { - _inflaterstate = InflaterState.unCompressedAligning; - } - } - if (_blockType == BlockType.dynamicType) { - if (_getInflaterStateValue(_inflaterstate) < - _getInflaterStateValue(InflaterState.decodeTop)) { - result = _decodeDynamicBlockHeader(); - } else { - final Map returnedValue = _decodeBlock(eob); - result = returnedValue['result'] as bool?; - eob = returnedValue['eob'] as bool?; - _output = returnedValue['output'] as DecompressedOutput; - } - } else if (_blockType == BlockType.staticType) { - final Map returnedValue = _decodeBlock(eob); - result = returnedValue['result'] as bool?; - eob = returnedValue['eob'] as bool?; - _output = returnedValue['output'] as DecompressedOutput; - } else if (_blockType == BlockType.unCompressedType) { - final Map returnedValue = _decodeUncompressedBlock(eob); - result = returnedValue['result'] as bool?; - eob = returnedValue['eob'] as bool?; - _output = returnedValue['output'] as DecompressedOutput; - } - if (eob! && (_bfinal != 0)) { - _inflaterstate = InflaterState.done; - } - return result; - } - - Map _decodeUncompressedBlock(bool? endblock) { - endblock = false; - while (true) { - switch (_inflaterstate) { - case InflaterState.unCompressedAligning: - _input.skipByteBoundary(); - _inflaterstate = InflaterState.unCompressedByte1; - if (!_unCompressedByte()) { - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - } - break; - case InflaterState.unCompressedByte1: - case InflaterState.unCompressedByte2: - case InflaterState.unCompressedByte3: - case InflaterState.unCompressedByte4: - if (!_unCompressedByte()) { - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - } - break; - case InflaterState.decodeUnCompressedBytes: - final int bytesCopied = _output.copyFrom(_input, _bLength); - _bLength -= bytesCopied; - if (_bLength == 0) { - _inflaterstate = InflaterState.readingBFinal; - endblock = true; - return { - 'result': true, - 'eob': endblock, - 'output': _output, - }; - } - if (_output.unusedBytes == 0) { - return { - 'result': true, - 'eob': endblock, - 'output': _output, - }; - } - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - // ignore: no_default_cases - default: - break; - } - } - } - - bool _unCompressedByte() { - final int bits = _input.getBits(8); - if (bits < 0) { - return false; - } - _blBuffer[_getInflaterStateValue(_inflaterstate) - - _getInflaterStateValue(InflaterState.unCompressedByte1)] = bits - .toUnsigned(8); - if (_inflaterstate == InflaterState.unCompressedByte4) { - _bLength = _blBuffer[0] + (_blBuffer[1]) * 256; - if (_bLength.toUnsigned(16) != - (~(_blBuffer[2] + (_blBuffer[3]) * 256)).toUnsigned(16)) { - throw ArgumentError.value('Ivalid block length.'); - } - } - _inflaterstate = _getInflaterState( - _getInflaterStateValue(_inflaterstate) + 1, - ); - return true; - } - - Map _decodeBlock(bool? endblock) { - endblock = false; - int fb = _output.unusedBytes; - while (fb > 258) { - int symbol; - switch (_inflaterstate) { - case InflaterState.decodeTop: - symbol = _llTree.getNextSymbol(_input); - if (symbol < 0) { - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - } - if (symbol < 256) { - _output.write(symbol.toUnsigned(8)); - --fb; - } else if (symbol == 256) { - endblock = true; - _inflaterstate = InflaterState.readingBFinal; - return { - 'result': true, - 'eob': endblock, - 'output': _output, - }; - } else { - symbol -= 257; - if (symbol < 8) { - symbol += 3; - _extraBits = 0; - } else if (symbol == 28) { - symbol = 258; - _extraBits = 0; - } else { - if (symbol < 0 || symbol >= _extraLengthBits.length) { - throw ArgumentError.value('Invalid data.'); - } - _extraBits = _extraLengthBits[symbol]; - } - _length = symbol; - final Map inLengthResult = _inLength(fb); - fb = inLengthResult['fb'] as int; - if (!(inLengthResult['value'] as bool)) { - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - } - } - break; - case InflaterState.iLength: - final Map inLengthResult = _inLength(fb); - fb = inLengthResult['fb'] as int; - if (!(inLengthResult['value'] as bool)) { - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - } - break; - case InflaterState.fLength: - final Map fLengthResult = _fLength(fb); - fb = fLengthResult['fb'] as int; - if (!(fLengthResult['value'] as bool)) { - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - } - break; - case InflaterState.dCode: - final Map dCodeResult = _dcode(fb); - fb = dCodeResult['fb'] as int; - if (!(dCodeResult['value'] as bool)) { - return { - 'result': false, - 'eob': endblock, - 'output': _output, - }; - } - break; - // ignore: no_default_cases - default: - break; - } - } - return { - 'result': true, - 'eob': endblock, - 'output': _output, - }; - } - - Map _inLength(int fb) { - if (_extraBits > 0) { - _inflaterstate = InflaterState.iLength; - final int bits = _input.getBits(_extraBits); - if (bits < 0) { - return {'value': false, 'fb': fb}; - } - if (_length < 0 || _length >= _lengthBase.length) { - throw ArgumentError.value('Invalid data.'); - } - _length = _lengthBase[_length] + bits; - } - _inflaterstate = InflaterState.fLength; - final Map fLengthResult = _fLength(fb); - fb = fLengthResult['fb'] as int; - if (!(fLengthResult['value'] as bool)) { - return {'value': false, 'fb': fb}; - } - return {'value': true, 'fb': fb}; - } - - Map _fLength(int fb) { - if (_blockType == BlockType.dynamicType) { - _distanceCode = _distanceTree.getNextSymbol(_input); - } else { - _distanceCode = _input.getBits(5); - if (_distanceCode >= 0) { - _distanceCode = _staticDistanceTreeTable[_distanceCode]; - } - } - if (_distanceCode < 0) { - return {'value': false, 'fb': fb}; - } - _inflaterstate = InflaterState.dCode; - final Map dCodeResult = _dcode(fb); - fb = dCodeResult['fb'] as int; - if (!(dCodeResult['value'] as bool)) { - return {'value': false, 'fb': fb}; - } - return {'value': true, 'fb': fb}; - } - - Map _dcode(int fb) { - int offset; - if (_distanceCode > 3) { - _extraBits = (_distanceCode - 2) >> 1; - final int bits = _input.getBits(_extraBits); - if (bits < 0) { - return {'value': false, 'fb': fb}; - } - offset = _distanceBasePosition[_distanceCode] + bits; - } else { - offset = _distanceCode + 1; - } - _output.writeLD(_length, offset); - fb -= _length; - _inflaterstate = InflaterState.decodeTop; - return {'value': true, 'fb': fb}; - } - - bool _decodeDynamicBlockHeader() { - switch (_inflaterstate) { - case InflaterState.readingNLCodes: - _llCodeCount = _input.getBits(5); - if (_llCodeCount < 0) { - return false; - } - _llCodeCount += 257; - _inflaterstate = InflaterState.readingNDCodes; - if (!_readingNDCodes()) { - return false; - } - break; - case InflaterState.readingNDCodes: - if (!_readingNDCodes()) { - return false; - } - break; - case InflaterState.readingNCLCodes: - if (!_readingNCLCodes()) { - return false; - } - break; - case InflaterState.readingCLCodes: - if (!_readingCLCodes()) { - return false; - } - break; - case InflaterState.readingTCBefore: - case InflaterState.readingTCAfter: - if (!_readingTCBefore()) { - return false; - } - break; - // ignore: no_default_cases - default: - break; - } - - final List literalTreeCodeLength = List.filled( - HuffmanTree.maxLTree, - 0, - ); - List.copyRange(literalTreeCodeLength, 0, _codeList, 0, _llCodeCount); - final List distanceTreeCodeLength = List.filled( - HuffmanTree.maxDTree, - 0, - ); - List.copyRange( - distanceTreeCodeLength, - 0, - _codeList, - _llCodeCount, - _llCodeCount + _dCodeCount, - ); - _llTree = HuffmanTree(code: literalTreeCodeLength); - _distanceTree = HuffmanTree(code: distanceTreeCodeLength); - _inflaterstate = InflaterState.decodeTop; - return true; - } - - bool _readingNDCodes() { - _dCodeCount = _input.getBits(5); - if (_dCodeCount < 0) { - return false; - } - _dCodeCount += 1; - _inflaterstate = InflaterState.readingNCLCodes; - if (!_readingNCLCodes()) { - return false; - } - return true; - } - - bool _readingNCLCodes() { - _clCodeCount = _input.getBits(4); - if (_clCodeCount < 0) { - return false; - } - _clCodeCount += 4; - _loopCounter = 0; - _inflaterstate = InflaterState.readingCLCodes; - if (!_readingCLCodes()) { - return false; - } - return true; - } - - bool _readingCLCodes() { - while (_loopCounter < _clCodeCount) { - final int bits = _input.getBits(3); - if (bits < 0) { - return false; - } - _cltcl[_codeOrder[_loopCounter]] = bits.toUnsigned(8); - ++_loopCounter; - } - - for (int i = _clCodeCount; i < _codeOrder.length; i++) { - _cltcl[_codeOrder[i]] = 0; - } - _clTree = HuffmanTree(code: _cltcl); - _caSize = _llCodeCount + _dCodeCount; - _loopCounter = 0; - _inflaterstate = InflaterState.readingTCBefore; - if (!_readingTCBefore()) { - return false; - } - return true; - } - - bool _readingTCBefore() { - while (_loopCounter < _caSize) { - if (_inflaterstate == InflaterState.readingTCBefore) { - if ((_lengthCode = _clTree.getNextSymbol(_input)) < 0) { - return false; - } - } - if (_lengthCode <= 15) { - _codeList[_loopCounter++] = _lengthCode.toUnsigned(8); - } else { - if (!_input.availableBits(7)) { - _inflaterstate = InflaterState.readingTCAfter; - return false; - } - int repeatCount; - if (_lengthCode == 16) { - if (_loopCounter == 0) { - throw ArgumentError.value('Invalid data.'); - } - final int previousCode = _codeList[_loopCounter - 1].toUnsigned(8); - repeatCount = _input.getBits(2) + 3; - if (_loopCounter + repeatCount > _caSize) { - throw ArgumentError.value('Invalid data.'); - } - for (int j = 0; j < repeatCount; j++) { - _codeList[_loopCounter++] = previousCode; - } - } else if (_lengthCode == 17) { - repeatCount = _input.getBits(3) + 3; - if (_loopCounter + repeatCount > _caSize) { - throw ArgumentError.value('Invalid data.'); - } - for (int j = 0; j < repeatCount; j++) { - _codeList[_loopCounter++] = 0; - } - } else { - repeatCount = _input.getBits(7) + 11; - if (_loopCounter + repeatCount > _caSize) { - throw ArgumentError.value('Invalid data.'); - } - for (int j = 0; j < repeatCount; j++) { - _codeList[_loopCounter++] = 0; - } - } - } - _inflaterstate = InflaterState.readingTCBefore; - } - return true; - } - - BlockType _getBlockType(int type) { - if (type == BlockType.unCompressedType.index) { - return BlockType.unCompressedType; - } else if (type == BlockType.staticType.index) { - return BlockType.staticType; - } else { - return BlockType.dynamicType; - } - } - - InflaterState _getInflaterState(int value) { - switch (value) { - case 0: - return InflaterState.readingHeader; - case 2: - return InflaterState.readingBFinal; - case 3: - return InflaterState.readingBType; - case 4: - return InflaterState.readingNLCodes; - case 5: - return InflaterState.readingNDCodes; - case 6: - return InflaterState.readingNCLCodes; - case 7: - return InflaterState.readingCLCodes; - case 8: - return InflaterState.readingTCBefore; - case 9: - return InflaterState.readingTCAfter; - case 10: - return InflaterState.decodeTop; - case 11: - return InflaterState.iLength; - case 12: - return InflaterState.fLength; - case 13: - return InflaterState.dCode; - case 15: - return InflaterState.unCompressedAligning; - case 16: - return InflaterState.unCompressedByte1; - case 17: - return InflaterState.unCompressedByte2; - case 18: - return InflaterState.unCompressedByte3; - case 19: - return InflaterState.unCompressedByte4; - case 20: - return InflaterState.decodeUnCompressedBytes; - case 21: - return InflaterState.srFooter; - case 22: - return InflaterState.rFooter; - case 23: - return InflaterState.vFooter; - case 24: - return InflaterState.done; - default: - return InflaterState.readingHeader; - } - } - - int _getInflaterStateValue(InflaterState? state) { - switch (state) { - case InflaterState.readingHeader: - return 0; - case InflaterState.readingBFinal: - return 2; - case InflaterState.readingBType: - return 3; - case InflaterState.readingNLCodes: - return 4; - case InflaterState.readingNDCodes: - return 5; - case InflaterState.readingNCLCodes: - return 6; - case InflaterState.readingCLCodes: - return 7; - case InflaterState.readingTCBefore: - return 8; - case InflaterState.readingTCAfter: - return 9; - case InflaterState.decodeTop: - return 10; - case InflaterState.iLength: - return 11; - case InflaterState.fLength: - return 12; - case InflaterState.dCode: - return 13; - case InflaterState.unCompressedAligning: - return 15; - case InflaterState.unCompressedByte1: - return 16; - case InflaterState.unCompressedByte2: - return 17; - case InflaterState.unCompressedByte3: - return 18; - case InflaterState.unCompressedByte4: - return 19; - case InflaterState.decodeUnCompressedBytes: - return 20; - case InflaterState.srFooter: - return 21; - case InflaterState.rFooter: - return 22; - case InflaterState.vFooter: - return 23; - case InflaterState.done: - return 24; - // ignore: no_default_cases - default: - return 0; - } - } - - //Static members - static const List _lengthBase = [ - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 13, - 15, - 17, - 19, - 23, - 27, - 31, - 35, - 43, - 51, - 59, - 67, - 83, - 99, - 115, - 131, - 163, - 195, - 227, - 258, - ]; - static const List _distanceBasePosition = [ - 1, - 2, - 3, - 4, - 5, - 7, - 9, - 13, - 17, - 25, - 33, - 49, - 65, - 97, - 129, - 193, - 257, - 385, - 513, - 769, - 1025, - 1537, - 2049, - 3073, - 4097, - 6145, - 8193, - 12289, - 16385, - 24577, - 0, - 0, - ]; - static const List _codeOrder = [ - 16, - 17, - 18, - 0, - 8, - 7, - 9, - 6, - 10, - 5, - 11, - 4, - 12, - 3, - 13, - 2, - 14, - 1, - 15, - ]; - static const List _staticDistanceTreeTable = [ - 0x00, - 0x10, - 0x08, - 0x18, - 0x04, - 0x14, - 0x0c, - 0x1c, - 0x02, - 0x12, - 0x0a, - 0x1a, - 0x06, - 0x16, - 0x0e, - 0x1e, - 0x01, - 0x11, - 0x09, - 0x19, - 0x05, - 0x15, - 0x0d, - 0x1d, - 0x03, - 0x13, - 0x0b, - 0x1b, - 0x07, - 0x17, - 0x0f, - 0x1f, - ]; - static const List _extraLengthBits = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 5, - 5, - 5, - 5, - 0, - ]; -} +import '../enums.dart'; +import 'decompressed_output.dart'; +import 'huffman_tree.dart'; +import 'in_buffer.dart'; + +/// internal class +class Inflater { + /// internal constructor + Inflater() { + _bfinal = 0; + _bLength = 0; + _blBuffer = List.filled(4, 0); + _blockType = BlockType.unCompressedType; + _caSize = 0; + _clCodeCount = 0; + _extraBits = 0; + _lengthCode = 0; + _length = 0; + _llCodeCount = 0; + _output = DecompressedOutput(); + _input = InBuffer(); + _loopCounter = 0; + _codeList = List.filled( + HuffmanTree.maxLTree + HuffmanTree.maxDTree, + 0, + growable: true, + ); + _cltcl = List.filled(HuffmanTree.nCLength, 0, growable: true); + _inflaterstate = InflaterState.readingBFinal; + } + + //Fields + late DecompressedOutput _output; + late InBuffer _input; + late HuffmanTree _llTree; + late HuffmanTree _distanceTree; + late InflaterState _inflaterstate; + late int _bfinal; + late BlockType _blockType; + late List _blBuffer; + late int _bLength; + late int _length; + late int _distanceCode; + late int _extraBits; + late int _loopCounter; + late int _llCodeCount; + late int _dCodeCount; + late int _clCodeCount; + late int _caSize; + late int _lengthCode; + late List _codeList; + late List _cltcl; + late HuffmanTree _clTree; + + //Implementation + + /// internal method + void setInput(List? inputBytes, int offset, int length) { + _input.setInput(inputBytes, offset, length); + } + + /// internal property + bool get finished => + _inflaterstate == InflaterState.done || + _inflaterstate == InflaterState.vFooter; + + /// internal method + Map inflate(List bytes, int offset, int length) { + int i = 0; + do { + final Map result = _output.copyTo(bytes, offset, length); + final int copied = result['count'] as int; + bytes = result['data'] as List; + if (copied > 0) { + offset += copied; + i += copied; + length -= copied; + } + if (length == 0) { + break; + } + } while (!finished && _decode()!); + return {'count': i, 'data': bytes}; + } + + bool? _decode() { + bool? eob = false; + bool? result = false; + if (finished) { + return true; + } + if (_inflaterstate == InflaterState.readingBFinal) { + if (!_input.availableBits(1)) { + return false; + } + _bfinal = _input.getBits(1); + _inflaterstate = InflaterState.readingBType; + } + if (_inflaterstate == InflaterState.readingBType) { + if (!_input.availableBits(2)) { + _inflaterstate = InflaterState.readingBType; + return false; + } + _blockType = _getBlockType(_input.getBits(2)); + if (_blockType == BlockType.dynamicType) { + _inflaterstate = InflaterState.readingNLCodes; + } else if (_blockType == BlockType.staticType) { + _llTree = HuffmanTree(isLtree: true); + _distanceTree = HuffmanTree(isLtree: false); + _inflaterstate = InflaterState.decodeTop; + } else if (_blockType == BlockType.unCompressedType) { + _inflaterstate = InflaterState.unCompressedAligning; + } + } + if (_blockType == BlockType.dynamicType) { + if (_getInflaterStateValue(_inflaterstate) < + _getInflaterStateValue(InflaterState.decodeTop)) { + result = _decodeDynamicBlockHeader(); + } else { + final Map returnedValue = _decodeBlock(eob); + result = returnedValue['result'] as bool?; + eob = returnedValue['eob'] as bool?; + _output = returnedValue['output'] as DecompressedOutput; + } + } else if (_blockType == BlockType.staticType) { + final Map returnedValue = _decodeBlock(eob); + result = returnedValue['result'] as bool?; + eob = returnedValue['eob'] as bool?; + _output = returnedValue['output'] as DecompressedOutput; + } else if (_blockType == BlockType.unCompressedType) { + final Map returnedValue = _decodeUncompressedBlock(eob); + result = returnedValue['result'] as bool?; + eob = returnedValue['eob'] as bool?; + _output = returnedValue['output'] as DecompressedOutput; + } + if (eob! && (_bfinal != 0)) { + _inflaterstate = InflaterState.done; + } + return result; + } + + Map _decodeUncompressedBlock(bool? endblock) { + endblock = false; + while (true) { + switch (_inflaterstate) { + case InflaterState.unCompressedAligning: + _input.skipByteBoundary(); + _inflaterstate = InflaterState.unCompressedByte1; + if (!_unCompressedByte()) { + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + } + break; + case InflaterState.unCompressedByte1: + case InflaterState.unCompressedByte2: + case InflaterState.unCompressedByte3: + case InflaterState.unCompressedByte4: + if (!_unCompressedByte()) { + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + } + break; + case InflaterState.decodeUnCompressedBytes: + final int bytesCopied = _output.copyFrom(_input, _bLength); + _bLength -= bytesCopied; + if (_bLength == 0) { + _inflaterstate = InflaterState.readingBFinal; + endblock = true; + return { + 'result': true, + 'eob': endblock, + 'output': _output, + }; + } + if (_output.unusedBytes == 0) { + return { + 'result': true, + 'eob': endblock, + 'output': _output, + }; + } + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + // ignore: no_default_cases + default: + break; + } + } + } + + bool _unCompressedByte() { + final int bits = _input.getBits(8); + if (bits < 0) { + return false; + } + _blBuffer[_getInflaterStateValue(_inflaterstate) - + _getInflaterStateValue(InflaterState.unCompressedByte1)] = bits + .toUnsigned(8); + if (_inflaterstate == InflaterState.unCompressedByte4) { + _bLength = _blBuffer[0] + (_blBuffer[1]) * 256; + if (_bLength.toUnsigned(16) != + (~(_blBuffer[2] + (_blBuffer[3]) * 256)).toUnsigned(16)) { + throw ArgumentError.value('Ivalid block length.'); + } + } + _inflaterstate = _getInflaterState( + _getInflaterStateValue(_inflaterstate) + 1, + ); + return true; + } + + Map _decodeBlock(bool? endblock) { + endblock = false; + int fb = _output.unusedBytes; + while (fb > 258) { + int symbol; + switch (_inflaterstate) { + case InflaterState.decodeTop: + symbol = _llTree.getNextSymbol(_input); + if (symbol < 0) { + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + } + if (symbol < 256) { + _output.write(symbol.toUnsigned(8)); + --fb; + } else if (symbol == 256) { + endblock = true; + _inflaterstate = InflaterState.readingBFinal; + return { + 'result': true, + 'eob': endblock, + 'output': _output, + }; + } else { + symbol -= 257; + if (symbol < 8) { + symbol += 3; + _extraBits = 0; + } else if (symbol == 28) { + symbol = 258; + _extraBits = 0; + } else { + if (symbol < 0 || symbol >= _extraLengthBits.length) { + throw ArgumentError.value('Invalid data.'); + } + _extraBits = _extraLengthBits[symbol]; + } + _length = symbol; + final Map inLengthResult = _inLength(fb); + fb = inLengthResult['fb'] as int; + if (!(inLengthResult['value'] as bool)) { + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + } + } + break; + case InflaterState.iLength: + final Map inLengthResult = _inLength(fb); + fb = inLengthResult['fb'] as int; + if (!(inLengthResult['value'] as bool)) { + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + } + break; + case InflaterState.fLength: + final Map fLengthResult = _fLength(fb); + fb = fLengthResult['fb'] as int; + if (!(fLengthResult['value'] as bool)) { + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + } + break; + case InflaterState.dCode: + final Map dCodeResult = _dcode(fb); + fb = dCodeResult['fb'] as int; + if (!(dCodeResult['value'] as bool)) { + return { + 'result': false, + 'eob': endblock, + 'output': _output, + }; + } + break; + // ignore: no_default_cases + default: + break; + } + } + return { + 'result': true, + 'eob': endblock, + 'output': _output, + }; + } + + Map _inLength(int fb) { + if (_extraBits > 0) { + _inflaterstate = InflaterState.iLength; + final int bits = _input.getBits(_extraBits); + if (bits < 0) { + return {'value': false, 'fb': fb}; + } + if (_length < 0 || _length >= _lengthBase.length) { + throw ArgumentError.value('Invalid data.'); + } + _length = _lengthBase[_length] + bits; + } + _inflaterstate = InflaterState.fLength; + final Map fLengthResult = _fLength(fb); + fb = fLengthResult['fb'] as int; + if (!(fLengthResult['value'] as bool)) { + return {'value': false, 'fb': fb}; + } + return {'value': true, 'fb': fb}; + } + + Map _fLength(int fb) { + if (_blockType == BlockType.dynamicType) { + _distanceCode = _distanceTree.getNextSymbol(_input); + } else { + _distanceCode = _input.getBits(5); + if (_distanceCode >= 0) { + _distanceCode = _staticDistanceTreeTable[_distanceCode]; + } + } + if (_distanceCode < 0) { + return {'value': false, 'fb': fb}; + } + _inflaterstate = InflaterState.dCode; + final Map dCodeResult = _dcode(fb); + fb = dCodeResult['fb'] as int; + if (!(dCodeResult['value'] as bool)) { + return {'value': false, 'fb': fb}; + } + return {'value': true, 'fb': fb}; + } + + Map _dcode(int fb) { + int offset; + if (_distanceCode > 3) { + _extraBits = (_distanceCode - 2) >> 1; + final int bits = _input.getBits(_extraBits); + if (bits < 0) { + return {'value': false, 'fb': fb}; + } + offset = _distanceBasePosition[_distanceCode] + bits; + } else { + offset = _distanceCode + 1; + } + _output.writeLD(_length, offset); + fb -= _length; + _inflaterstate = InflaterState.decodeTop; + return {'value': true, 'fb': fb}; + } + + bool _decodeDynamicBlockHeader() { + switch (_inflaterstate) { + case InflaterState.readingNLCodes: + _llCodeCount = _input.getBits(5); + if (_llCodeCount < 0) { + return false; + } + _llCodeCount += 257; + _inflaterstate = InflaterState.readingNDCodes; + if (!_readingNDCodes()) { + return false; + } + break; + case InflaterState.readingNDCodes: + if (!_readingNDCodes()) { + return false; + } + break; + case InflaterState.readingNCLCodes: + if (!_readingNCLCodes()) { + return false; + } + break; + case InflaterState.readingCLCodes: + if (!_readingCLCodes()) { + return false; + } + break; + case InflaterState.readingTCBefore: + case InflaterState.readingTCAfter: + if (!_readingTCBefore()) { + return false; + } + break; + // ignore: no_default_cases + default: + break; + } + + final List literalTreeCodeLength = List.filled( + HuffmanTree.maxLTree, + 0, + ); + List.copyRange(literalTreeCodeLength, 0, _codeList, 0, _llCodeCount); + final List distanceTreeCodeLength = List.filled( + HuffmanTree.maxDTree, + 0, + ); + List.copyRange( + distanceTreeCodeLength, + 0, + _codeList, + _llCodeCount, + _llCodeCount + _dCodeCount, + ); + _llTree = HuffmanTree(code: literalTreeCodeLength); + _distanceTree = HuffmanTree(code: distanceTreeCodeLength); + _inflaterstate = InflaterState.decodeTop; + return true; + } + + bool _readingNDCodes() { + _dCodeCount = _input.getBits(5); + if (_dCodeCount < 0) { + return false; + } + _dCodeCount += 1; + _inflaterstate = InflaterState.readingNCLCodes; + if (!_readingNCLCodes()) { + return false; + } + return true; + } + + bool _readingNCLCodes() { + _clCodeCount = _input.getBits(4); + if (_clCodeCount < 0) { + return false; + } + _clCodeCount += 4; + _loopCounter = 0; + _inflaterstate = InflaterState.readingCLCodes; + if (!_readingCLCodes()) { + return false; + } + return true; + } + + bool _readingCLCodes() { + while (_loopCounter < _clCodeCount) { + final int bits = _input.getBits(3); + if (bits < 0) { + return false; + } + _cltcl[_codeOrder[_loopCounter]] = bits.toUnsigned(8); + ++_loopCounter; + } + + for (int i = _clCodeCount; i < _codeOrder.length; i++) { + _cltcl[_codeOrder[i]] = 0; + } + _clTree = HuffmanTree(code: _cltcl); + _caSize = _llCodeCount + _dCodeCount; + _loopCounter = 0; + _inflaterstate = InflaterState.readingTCBefore; + if (!_readingTCBefore()) { + return false; + } + return true; + } + + bool _readingTCBefore() { + while (_loopCounter < _caSize) { + if (_inflaterstate == InflaterState.readingTCBefore) { + if ((_lengthCode = _clTree.getNextSymbol(_input)) < 0) { + return false; + } + } + if (_lengthCode <= 15) { + _codeList[_loopCounter++] = _lengthCode.toUnsigned(8); + } else { + if (!_input.availableBits(7)) { + _inflaterstate = InflaterState.readingTCAfter; + return false; + } + int repeatCount; + if (_lengthCode == 16) { + if (_loopCounter == 0) { + throw ArgumentError.value('Invalid data.'); + } + final int previousCode = _codeList[_loopCounter - 1].toUnsigned(8); + repeatCount = _input.getBits(2) + 3; + if (_loopCounter + repeatCount > _caSize) { + throw ArgumentError.value('Invalid data.'); + } + for (int j = 0; j < repeatCount; j++) { + _codeList[_loopCounter++] = previousCode; + } + } else if (_lengthCode == 17) { + repeatCount = _input.getBits(3) + 3; + if (_loopCounter + repeatCount > _caSize) { + throw ArgumentError.value('Invalid data.'); + } + for (int j = 0; j < repeatCount; j++) { + _codeList[_loopCounter++] = 0; + } + } else { + repeatCount = _input.getBits(7) + 11; + if (_loopCounter + repeatCount > _caSize) { + throw ArgumentError.value('Invalid data.'); + } + for (int j = 0; j < repeatCount; j++) { + _codeList[_loopCounter++] = 0; + } + } + } + _inflaterstate = InflaterState.readingTCBefore; + } + return true; + } + + BlockType _getBlockType(int type) { + if (type == BlockType.unCompressedType.index) { + return BlockType.unCompressedType; + } else if (type == BlockType.staticType.index) { + return BlockType.staticType; + } else { + return BlockType.dynamicType; + } + } + + InflaterState _getInflaterState(int value) { + switch (value) { + case 0: + return InflaterState.readingHeader; + case 2: + return InflaterState.readingBFinal; + case 3: + return InflaterState.readingBType; + case 4: + return InflaterState.readingNLCodes; + case 5: + return InflaterState.readingNDCodes; + case 6: + return InflaterState.readingNCLCodes; + case 7: + return InflaterState.readingCLCodes; + case 8: + return InflaterState.readingTCBefore; + case 9: + return InflaterState.readingTCAfter; + case 10: + return InflaterState.decodeTop; + case 11: + return InflaterState.iLength; + case 12: + return InflaterState.fLength; + case 13: + return InflaterState.dCode; + case 15: + return InflaterState.unCompressedAligning; + case 16: + return InflaterState.unCompressedByte1; + case 17: + return InflaterState.unCompressedByte2; + case 18: + return InflaterState.unCompressedByte3; + case 19: + return InflaterState.unCompressedByte4; + case 20: + return InflaterState.decodeUnCompressedBytes; + case 21: + return InflaterState.srFooter; + case 22: + return InflaterState.rFooter; + case 23: + return InflaterState.vFooter; + case 24: + return InflaterState.done; + default: + return InflaterState.readingHeader; + } + } + + int _getInflaterStateValue(InflaterState? state) { + switch (state) { + case InflaterState.readingHeader: + return 0; + case InflaterState.readingBFinal: + return 2; + case InflaterState.readingBType: + return 3; + case InflaterState.readingNLCodes: + return 4; + case InflaterState.readingNDCodes: + return 5; + case InflaterState.readingNCLCodes: + return 6; + case InflaterState.readingCLCodes: + return 7; + case InflaterState.readingTCBefore: + return 8; + case InflaterState.readingTCAfter: + return 9; + case InflaterState.decodeTop: + return 10; + case InflaterState.iLength: + return 11; + case InflaterState.fLength: + return 12; + case InflaterState.dCode: + return 13; + case InflaterState.unCompressedAligning: + return 15; + case InflaterState.unCompressedByte1: + return 16; + case InflaterState.unCompressedByte2: + return 17; + case InflaterState.unCompressedByte3: + return 18; + case InflaterState.unCompressedByte4: + return 19; + case InflaterState.decodeUnCompressedBytes: + return 20; + case InflaterState.srFooter: + return 21; + case InflaterState.rFooter: + return 22; + case InflaterState.vFooter: + return 23; + case InflaterState.done: + return 24; + // ignore: no_default_cases + default: + return 0; + } + } + + //Static members + static const List _lengthBase = [ + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 13, + 15, + 17, + 19, + 23, + 27, + 31, + 35, + 43, + 51, + 59, + 67, + 83, + 99, + 115, + 131, + 163, + 195, + 227, + 258, + ]; + static const List _distanceBasePosition = [ + 1, + 2, + 3, + 4, + 5, + 7, + 9, + 13, + 17, + 25, + 33, + 49, + 65, + 97, + 129, + 193, + 257, + 385, + 513, + 769, + 1025, + 1537, + 2049, + 3073, + 4097, + 6145, + 8193, + 12289, + 16385, + 24577, + 0, + 0, + ]; + static const List _codeOrder = [ + 16, + 17, + 18, + 0, + 8, + 7, + 9, + 6, + 10, + 5, + 11, + 4, + 12, + 3, + 13, + 2, + 14, + 1, + 15, + ]; + static const List _staticDistanceTreeTable = [ + 0x00, + 0x10, + 0x08, + 0x18, + 0x04, + 0x14, + 0x0c, + 0x1c, + 0x02, + 0x12, + 0x0a, + 0x1a, + 0x06, + 0x16, + 0x0e, + 0x1e, + 0x01, + 0x11, + 0x09, + 0x19, + 0x05, + 0x15, + 0x0d, + 0x1d, + 0x03, + 0x13, + 0x0b, + 0x1b, + 0x07, + 0x17, + 0x0f, + 0x1f, + ]; + static const List _extraLengthBits = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 5, + 5, + 5, + 5, + 0, + ]; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/enums.dart index 5ffc60e11..bf64c7e4e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/enums.dart @@ -1,83 +1,83 @@ -/// internal enumerator -enum InflaterState { - /// internal enumerator - readingHeader, - - /// internal enumerator - readingBFinal, - - /// internal enumerator - readingBType, - - /// internal enumerator - readingNLCodes, - - /// internal enumerator - readingNDCodes, - - /// internal enumerator - readingNCLCodes, - - /// internal enumerator - readingCLCodes, - - /// internal enumerator - readingTCBefore, - - /// internal enumerator - readingTCAfter, - - /// internal enumerator - decodeTop, - - /// internal enumerator - iLength, - - /// internal enumerator - fLength, - - /// internal enumerator - dCode, - - /// internal enumerator - unCompressedAligning, - - /// internal enumerator - unCompressedByte1, - - /// internal enumerator - unCompressedByte2, - - /// internal enumerator - unCompressedByte3, - - /// internal enumerator - unCompressedByte4, - - /// internal enumerator - decodeUnCompressedBytes, - - /// internal enumerator - srFooter, - - /// internal enumerator - rFooter, - - /// internal enumerator - vFooter, - - /// internal enumerator - done, -} - -/// internal enumerator -enum BlockType { - /// internal enumerator - unCompressedType, - - /// internal enumerator - staticType, - - /// internal enumerator - dynamicType, -} +/// internal enumerator +enum InflaterState { + /// internal enumerator + readingHeader, + + /// internal enumerator + readingBFinal, + + /// internal enumerator + readingBType, + + /// internal enumerator + readingNLCodes, + + /// internal enumerator + readingNDCodes, + + /// internal enumerator + readingNCLCodes, + + /// internal enumerator + readingCLCodes, + + /// internal enumerator + readingTCBefore, + + /// internal enumerator + readingTCAfter, + + /// internal enumerator + decodeTop, + + /// internal enumerator + iLength, + + /// internal enumerator + fLength, + + /// internal enumerator + dCode, + + /// internal enumerator + unCompressedAligning, + + /// internal enumerator + unCompressedByte1, + + /// internal enumerator + unCompressedByte2, + + /// internal enumerator + unCompressedByte3, + + /// internal enumerator + unCompressedByte4, + + /// internal enumerator + decodeUnCompressedBytes, + + /// internal enumerator + srFooter, + + /// internal enumerator + rFooter, + + /// internal enumerator + vFooter, + + /// internal enumerator + done, +} + +/// internal enumerator +enum BlockType { + /// internal enumerator + unCompressedType, + + /// internal enumerator + staticType, + + /// internal enumerator + dynamicType, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_png_filter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_png_filter.dart index e1a5ebe4b..c48999641 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_png_filter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_png_filter.dart @@ -1,282 +1,282 @@ -/// internal class -class PdfPngFilter { - /// internal constructor - PdfPngFilter() { - _decompressFilter = _decompressData; - bytesPerPixel = 1; - } - - //Fields - _RowFilter? _decompressFilter; - - /// internal field - late int bytesPerPixel; - - //Implementation - /// internal method - List decompress(List data, int bytesPerRow) { - if (bytesPerRow <= 0) { - throw ArgumentError.value( - bytesPerRow, - 'There cannot be less or equal to zero bytes in a line.', - ); - } - return _modify(data, bytesPerRow + 1, _decompressFilter, false); - } - - List _modify(List data, int bpr, _RowFilter? filter, bool pack) { - int index = 0; - final int length = data.length; - final int items = length ~/ bpr; - final int outBPR = bpr - (pack ? -1 : 1); - final int outLength = pack ? items * outBPR : items * outBPR; - - List result = List.filled(outLength, 0, growable: true); - int currentRow = 0; - - while (index + bpr <= length) { - result = filter!(data, index, bpr, result, currentRow, outBPR); - currentRow += outBPR; - index += bpr; - } - return result; - } - - List _decompressData( - List data, - int inIndex, - int inBPR, - List result, - int resIndex, - int resBPR, - ) { - final _Type type = _getType(data[inIndex]); - switch (type) { - case _Type.none: - result = _decompressNone( - data, - inIndex + 1, - inBPR, - result, - resIndex, - resBPR, - ); - break; - case _Type.sub: - result = _deompressSub( - data, - inIndex + 1, - inBPR, - result, - resIndex, - resBPR, - ); - break; - case _Type.up: - result = _decompressUp( - data, - inIndex + 1, - inBPR, - result, - resIndex, - resBPR, - ); - break; - case _Type.average: - result = _decompressAverage( - data, - inIndex + 1, - inBPR, - result, - resIndex, - resBPR, - ); - break; - case _Type.paeth: - result = _decompressPaeth( - data, - inIndex + 1, - inBPR, - result, - resIndex, - resBPR, - ); - break; - } - return result; - } - - List _decompressNone( - List data, - int inIndex, - int inBPR, - List result, - int resIndex, - int resBPR, - ) { - for (int i = 1; i < inBPR; ++i) { - result[resIndex] = data[inIndex]; - ++resIndex; - ++inIndex; - } - return result; - } - - List _deompressSub( - List data, - int inIndex, - int inBPR, - List result, - int resIndex, - int resBPR, - ) { - for (int i = 0; i < resBPR; ++i) { - result[resIndex] = (data[inIndex] + ((i > 0) ? result[resIndex - 1] : 0)) - .toUnsigned(8); - ++resIndex; - ++inIndex; - } - return result; - } - - List _decompressUp( - List data, - int inIndex, - int inBPR, - List result, - int resIndex, - int resBPR, - ) { - int prevIndex = resIndex - resBPR; - for (int i = 0; i < resBPR; ++i) { - result[resIndex] = (data[inIndex] + - ((prevIndex < 0) ? 0 : result[prevIndex])) - .toUnsigned(8); - ++resIndex; - ++inIndex; - ++prevIndex; - } - return result; - } - - List _decompressAverage( - List data, - int inIndex, - int inBPR, - List result, - int resIndex, - int resBPR, - ) { - int prevIndex = resIndex - resBPR; - final List previous = List.filled(resBPR, 0, growable: true); - for (int i = 0; i < resBPR; i++) { - result[resIndex + i] = data[inIndex + i]; - } - for (int i = 0; i < 1; i++) { - if (prevIndex < 0) { - result[resIndex] = (data[inIndex] + previous[resIndex]).toUnsigned(8); - } else { - result[resIndex] = (data[inIndex] + (result[prevIndex] / 2)) - .toInt() - .toUnsigned(8); - } - ++prevIndex; - ++resIndex; - } - for (int i = bytesPerPixel; i < resBPR; i++) { - if (prevIndex < 0) { - result[resIndex] = (result[resIndex] + - (((result[resIndex - bytesPerPixel] & 0xff) + - (previous[resIndex] & 0xff)) ~/ - 2)) - .toUnsigned(8); - } else { - result[resIndex] = (result[resIndex] + - (((result[resIndex - bytesPerPixel] & 0xff) + - (result[prevIndex] & 0xff)) ~/ - 2)) - .toUnsigned(8); - } - ++resIndex; - ++inIndex; - ++prevIndex; - } - return result; - } - - List _decompressPaeth( - List data, - int inIndex, - int inBPR, - List result, - int resIndex, - int resBPR, - ) { - int prevIndex = resIndex - resBPR; - for (int i = 0; i < resBPR; i++) { - result[resIndex + i] = data[inIndex + i]; - } - for (int i = 0; i < bytesPerPixel; i++) { - result[resIndex] = (result[resIndex] + result[prevIndex]).toUnsigned(8); - resIndex++; - prevIndex++; - } - for (int i = bytesPerPixel; i < resBPR; ++i) { - final int a = result[resIndex - bytesPerPixel] & 0xff; - final int b = result[prevIndex] & 0xff; - final int c = result[prevIndex - bytesPerPixel] & 0xff; - result[resIndex] = (result[resIndex] + _paethPredictor(a, b, c)) - .toUnsigned(8); - ++resIndex; - ++inIndex; - ++prevIndex; - } - return result; - } - - int _paethPredictor(int a, int b, int c) { - final int p = a + b - c; - final int pa = (p - a).abs(); - final int pb = (p - b).abs(); - final int pc = (p - c).abs(); - if (pa <= pb && pa <= pc) { - return a.toUnsigned(8); - } else if (pb <= pc) { - return b.toUnsigned(8); - } else { - return c.toUnsigned(8); - } - } - - _Type _getType(int? type) { - _Type result; - if (type == 0) { - result = _Type.none; - } else if (type == 1) { - result = _Type.sub; - } else if (type == 2) { - result = _Type.up; - } else if (type == 3) { - result = _Type.average; - } else if (type == 4) { - result = _Type.paeth; - } else { - throw ArgumentError.value(type, 'Invalid type'); - } - return result; - } -} - -//Delegates -typedef _RowFilter = - List Function( - List data, - int inIndex, - int inBPR, - List result, - int resIndex, - int resBPR, - ); - -//Enum -enum _Type { none, sub, up, average, paeth } +/// internal class +class PdfPngFilter { + /// internal constructor + PdfPngFilter() { + _decompressFilter = _decompressData; + bytesPerPixel = 1; + } + + //Fields + _RowFilter? _decompressFilter; + + /// internal field + late int bytesPerPixel; + + //Implementation + /// internal method + List decompress(List data, int bytesPerRow) { + if (bytesPerRow <= 0) { + throw ArgumentError.value( + bytesPerRow, + 'There cannot be less or equal to zero bytes in a line.', + ); + } + return _modify(data, bytesPerRow + 1, _decompressFilter, false); + } + + List _modify(List data, int bpr, _RowFilter? filter, bool pack) { + int index = 0; + final int length = data.length; + final int items = length ~/ bpr; + final int outBPR = bpr - (pack ? -1 : 1); + final int outLength = pack ? items * outBPR : items * outBPR; + + List result = List.filled(outLength, 0, growable: true); + int currentRow = 0; + + while (index + bpr <= length) { + result = filter!(data, index, bpr, result, currentRow, outBPR); + currentRow += outBPR; + index += bpr; + } + return result; + } + + List _decompressData( + List data, + int inIndex, + int inBPR, + List result, + int resIndex, + int resBPR, + ) { + final _Type type = _getType(data[inIndex]); + switch (type) { + case _Type.none: + result = _decompressNone( + data, + inIndex + 1, + inBPR, + result, + resIndex, + resBPR, + ); + break; + case _Type.sub: + result = _deompressSub( + data, + inIndex + 1, + inBPR, + result, + resIndex, + resBPR, + ); + break; + case _Type.up: + result = _decompressUp( + data, + inIndex + 1, + inBPR, + result, + resIndex, + resBPR, + ); + break; + case _Type.average: + result = _decompressAverage( + data, + inIndex + 1, + inBPR, + result, + resIndex, + resBPR, + ); + break; + case _Type.paeth: + result = _decompressPaeth( + data, + inIndex + 1, + inBPR, + result, + resIndex, + resBPR, + ); + break; + } + return result; + } + + List _decompressNone( + List data, + int inIndex, + int inBPR, + List result, + int resIndex, + int resBPR, + ) { + for (int i = 1; i < inBPR; ++i) { + result[resIndex] = data[inIndex]; + ++resIndex; + ++inIndex; + } + return result; + } + + List _deompressSub( + List data, + int inIndex, + int inBPR, + List result, + int resIndex, + int resBPR, + ) { + for (int i = 0; i < resBPR; ++i) { + result[resIndex] = (data[inIndex] + ((i > 0) ? result[resIndex - 1] : 0)) + .toUnsigned(8); + ++resIndex; + ++inIndex; + } + return result; + } + + List _decompressUp( + List data, + int inIndex, + int inBPR, + List result, + int resIndex, + int resBPR, + ) { + int prevIndex = resIndex - resBPR; + for (int i = 0; i < resBPR; ++i) { + result[resIndex] = (data[inIndex] + + ((prevIndex < 0) ? 0 : result[prevIndex])) + .toUnsigned(8); + ++resIndex; + ++inIndex; + ++prevIndex; + } + return result; + } + + List _decompressAverage( + List data, + int inIndex, + int inBPR, + List result, + int resIndex, + int resBPR, + ) { + int prevIndex = resIndex - resBPR; + final List previous = List.filled(resBPR, 0, growable: true); + for (int i = 0; i < resBPR; i++) { + result[resIndex + i] = data[inIndex + i]; + } + for (int i = 0; i < 1; i++) { + if (prevIndex < 0) { + result[resIndex] = (data[inIndex] + previous[resIndex]).toUnsigned(8); + } else { + result[resIndex] = (data[inIndex] + (result[prevIndex] / 2)) + .toInt() + .toUnsigned(8); + } + ++prevIndex; + ++resIndex; + } + for (int i = bytesPerPixel; i < resBPR; i++) { + if (prevIndex < 0) { + result[resIndex] = (result[resIndex] + + (((result[resIndex - bytesPerPixel] & 0xff) + + (previous[resIndex] & 0xff)) ~/ + 2)) + .toUnsigned(8); + } else { + result[resIndex] = (result[resIndex] + + (((result[resIndex - bytesPerPixel] & 0xff) + + (result[prevIndex] & 0xff)) ~/ + 2)) + .toUnsigned(8); + } + ++resIndex; + ++inIndex; + ++prevIndex; + } + return result; + } + + List _decompressPaeth( + List data, + int inIndex, + int inBPR, + List result, + int resIndex, + int resBPR, + ) { + int prevIndex = resIndex - resBPR; + for (int i = 0; i < resBPR; i++) { + result[resIndex + i] = data[inIndex + i]; + } + for (int i = 0; i < bytesPerPixel; i++) { + result[resIndex] = (result[resIndex] + result[prevIndex]).toUnsigned(8); + resIndex++; + prevIndex++; + } + for (int i = bytesPerPixel; i < resBPR; ++i) { + final int a = result[resIndex - bytesPerPixel] & 0xff; + final int b = result[prevIndex] & 0xff; + final int c = result[prevIndex - bytesPerPixel] & 0xff; + result[resIndex] = (result[resIndex] + _paethPredictor(a, b, c)) + .toUnsigned(8); + ++resIndex; + ++inIndex; + ++prevIndex; + } + return result; + } + + int _paethPredictor(int a, int b, int c) { + final int p = a + b - c; + final int pa = (p - a).abs(); + final int pb = (p - b).abs(); + final int pc = (p - c).abs(); + if (pa <= pb && pa <= pc) { + return a.toUnsigned(8); + } else if (pb <= pc) { + return b.toUnsigned(8); + } else { + return c.toUnsigned(8); + } + } + + _Type _getType(int? type) { + _Type result; + if (type == 0) { + result = _Type.none; + } else if (type == 1) { + result = _Type.sub; + } else if (type == 2) { + result = _Type.up; + } else if (type == 3) { + result = _Type.average; + } else if (type == 4) { + result = _Type.paeth; + } else { + throw ArgumentError.value(type, 'Invalid type'); + } + return result; + } +} + +//Delegates +typedef _RowFilter = + List Function( + List data, + int inIndex, + int inBPR, + List result, + int resIndex, + int resBPR, + ); + +//Enum +enum _Type { none, sub, up, average, paeth } diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_zlib_compressor.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_zlib_compressor.dart index ab2dc822c..eedf0b7fd 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_zlib_compressor.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/compression/pdf_zlib_compressor.dart @@ -1,146 +1,146 @@ -import '../pdf_document/enums.dart'; -import 'compressed_stream_reader.dart'; -import 'deflate/deflate_stream.dart'; - -/// internal class -class PdfZlibCompressor { - /// internal constructor - PdfZlibCompressor() { - level = PdfCompressionLevel.normal; - } - - /// internal field - PdfCompressionLevel? level; - - /// internal field - int defaultBufferSize = 32; - - /// internal method - List decompress(List data) { - List outputStream = []; - List buffer = List.filled(defaultBufferSize, 0, growable: true); - final CompressedStreamReader reader = CompressedStreamReader(data); - int? len = 0; - try { - Map returnValue = reader.read(buffer, 0, buffer.length); - len = returnValue['length'] as int?; - buffer = returnValue['buffer'] as List; - while (len! > 0) { - for (int i = 0; i < len; i++) { - outputStream.add(buffer[i]); - } - returnValue = reader.read(buffer, 0, buffer.length); - len = returnValue['length'] as int?; - buffer = returnValue['buffer'] as List; - } - } on FormatException catch (e1) { - if (e1.message.contains('Checksum check failed.')) { - final DeflateStream deflateStream = DeflateStream(data, 2, true); - buffer = List.filled(4096, 0, growable: true); - int? numRead = 0; - outputStream = []; - do { - final Map result = deflateStream.read( - buffer, - 0, - buffer.length, - ); - numRead = result['count'] as int?; - buffer = result['data'] as List; - for (int i = 0; i < numRead!; i++) { - outputStream.add(buffer[i]); - } - } while (numRead > 0); - } - } catch (e2) { - //This catch not throws any exception - } - return outputStream; - } -} - -/// internal class -class PdfAscii85Compressor { - /// internal constructor - PdfAscii85Compressor() { - _codeTable = [85 * 85 * 85 * 85, 85 * 85 * 85, 85 * 85, 85, 1]; - _decodedBlock = List.filled(4, 0, growable: true); - _encodedBlock = List.filled(5, 0, growable: true); - _tuple = 0; - _asciiOffset = 33; - } - - //Fields - late List _codeTable; - late List _decodedBlock; - late List _encodedBlock; - late int _tuple; - late int _asciiOffset; - - /// internal method - List decompress(List data) { - final List outputData = []; - int count = 0; - bool processChar = false; - for (final int byte in data) { - final String c = String.fromCharCode(byte); - switch (c) { - case 'z': - if (count != 0) { - throw ArgumentError.value( - c, - 'c', - 'The character "z" is invalid inside an ASCII85 block.', - ); - } - _decodedBlock = List.filled(4, 0, growable: true); - for (int i = 0; i < _decodedBlock.length; i++) { - outputData.add(_decodedBlock[i]); - } - processChar = false; - break; - case '\n': - case '\r': - case '\t': - case '\f': - case '\b': - processChar = false; - break; - default: - if (c == String.fromCharCode(0)) { - processChar = false; - break; - } - processChar = true; - break; - } - if (processChar) { - _tuple += (byte - _asciiOffset).toUnsigned(16) * _codeTable[count]; - count++; - if (count == _encodedBlock.length) { - _decodeBlock(_decodedBlock.length); - for (int i = 0; i < _decodedBlock.length; i++) { - outputData.add(_decodedBlock[i]); - } - _tuple = 0; - count = 0; - } - } - } - if (count != 0) { - count--; - _tuple += _codeTable[count]; - _decodeBlock(count); - for (int i = 0; i < count; i++) { - outputData.add(_decodedBlock[i]); - } - } - return outputData; - } - - void _decodeBlock(int count) { - for (int i = 0; i < count; i++) { - _decodedBlock[i] = (_tuple >> 24 - (i * 8)).toUnsigned(8); - } - } -} +import '../pdf_document/enums.dart'; +import 'compressed_stream_reader.dart'; +import 'deflate/deflate_stream.dart'; + +/// internal class +class PdfZlibCompressor { + /// internal constructor + PdfZlibCompressor() { + level = PdfCompressionLevel.normal; + } + + /// internal field + PdfCompressionLevel? level; + + /// internal field + int defaultBufferSize = 32; + + /// internal method + List decompress(List data) { + List outputStream = []; + List buffer = List.filled(defaultBufferSize, 0, growable: true); + final CompressedStreamReader reader = CompressedStreamReader(data); + int? len = 0; + try { + Map returnValue = reader.read(buffer, 0, buffer.length); + len = returnValue['length'] as int?; + buffer = returnValue['buffer'] as List; + while (len! > 0) { + for (int i = 0; i < len; i++) { + outputStream.add(buffer[i]); + } + returnValue = reader.read(buffer, 0, buffer.length); + len = returnValue['length'] as int?; + buffer = returnValue['buffer'] as List; + } + } on FormatException catch (e1) { + if (e1.message.contains('Checksum check failed.')) { + final DeflateStream deflateStream = DeflateStream(data, 2, true); + buffer = List.filled(4096, 0, growable: true); + int? numRead = 0; + outputStream = []; + do { + final Map result = deflateStream.read( + buffer, + 0, + buffer.length, + ); + numRead = result['count'] as int?; + buffer = result['data'] as List; + for (int i = 0; i < numRead!; i++) { + outputStream.add(buffer[i]); + } + } while (numRead > 0); + } + } catch (e2) { + //This catch not throws any exception + } + return outputStream; + } +} + +/// internal class +class PdfAscii85Compressor { + /// internal constructor + PdfAscii85Compressor() { + _codeTable = [85 * 85 * 85 * 85, 85 * 85 * 85, 85 * 85, 85, 1]; + _decodedBlock = List.filled(4, 0, growable: true); + _encodedBlock = List.filled(5, 0, growable: true); + _tuple = 0; + _asciiOffset = 33; + } + + //Fields + late List _codeTable; + late List _decodedBlock; + late List _encodedBlock; + late int _tuple; + late int _asciiOffset; + + /// internal method + List decompress(List data) { + final List outputData = []; + int count = 0; + bool processChar = false; + for (final int byte in data) { + final String c = String.fromCharCode(byte); + switch (c) { + case 'z': + if (count != 0) { + throw ArgumentError.value( + c, + 'c', + 'The character "z" is invalid inside an ASCII85 block.', + ); + } + _decodedBlock = List.filled(4, 0, growable: true); + for (int i = 0; i < _decodedBlock.length; i++) { + outputData.add(_decodedBlock[i]); + } + processChar = false; + break; + case '\n': + case '\r': + case '\t': + case '\f': + case '\b': + processChar = false; + break; + default: + if (c == String.fromCharCode(0)) { + processChar = false; + break; + } + processChar = true; + break; + } + if (processChar) { + _tuple += (byte - _asciiOffset).toUnsigned(16) * _codeTable[count]; + count++; + if (count == _encodedBlock.length) { + _decodeBlock(_decodedBlock.length); + for (int i = 0; i < _decodedBlock.length; i++) { + outputData.add(_decodedBlock[i]); + } + _tuple = 0; + count = 0; + } + } + } + if (count != 0) { + count--; + _tuple += _codeTable[count]; + _decodeBlock(count); + for (int i = 0; i < count; i++) { + outputData.add(_decodedBlock[i]); + } + } + return outputData; + } + + void _decodeBlock(int count) { + for (int i = 0; i < count; i++) { + _decodedBlock[i] = (_tuple >> 24 - (i * 8)).toUnsigned(8); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/color.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/color.dart index 8e8872b8e..4658db308 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/color.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/color.dart @@ -1,1091 +1,1091 @@ -/// internal class -class ColorHelper { - /// internal constructor - ColorHelper(this._knownColor); - - /// internal field - static const int argbAlphaShift = 24; - - /// internal field - static const int argbRedShift = 16; - - /// internal field - static const int argbGreebShift = 8; - - /// internal field - static const int argbBlueShift = 0; - - int? _value; - final KnownColor _knownColor; - - /// internal property - int get r { - return ((value! >> argbRedShift) & 0xFF).toUnsigned(8); - } - - /// internal property - int get g { - return ((value! >> argbGreebShift) & 0xFF).toUnsigned(8); - } - - /// internal property - int get b { - return ((value! >> argbBlueShift) & 0xFF).toUnsigned(8); - } - - /// internal property - int get a { - return ((value! >> argbAlphaShift) & 0xFF).toUnsigned(8); - } - - /// internal property - int? get value { - _value ??= KnownColorTable().knowColorToArgb(_knownColor); - return _value; - } -} - -/// internal class -class KnownColorTable { - /// internal constructor - KnownColorTable() { - initColorTable(); - } - - /// internal field - static Map colorTable = {}; - - /// internal method - void initColorTable() { - colorTable[0x1b] = 0xffffff; - colorTable[0x1c] = -984833; - colorTable[0x1d] = -332841; - colorTable[30] = -16711681; - colorTable[0x1f] = -8388652; - colorTable[0x18] = -1; - colorTable[0x20] = -983041; - colorTable[0x21] = -657956; - colorTable[0x22] = -6972; - colorTable[0x23] = -16777216; - colorTable[0x24] = -5171; - colorTable[0x25] = -16776961; - colorTable[0x26] = -7722014; - colorTable[0x27] = -5952982; - colorTable[40] = -2180985; - colorTable[0x29] = -10510688; - colorTable[0x2a] = -8388864; - colorTable[0x2b] = -2987746; - colorTable[0x2c] = -32944; - colorTable[0x2d] = -10185235; - colorTable[0x2e] = -1828; - colorTable[0x2f] = -2354116; - colorTable[0x30] = -16711681; - colorTable[0x31] = -16777077; - colorTable[50] = -16741493; - colorTable[0x33] = -4684277; - colorTable[0x34] = -5658199; - colorTable[0x35] = -16751616; - colorTable[0x36] = -4343957; - colorTable[0x37] = -7667573; - colorTable[0x38] = -11179217; - colorTable[0x39] = -29696; - colorTable[0x3a] = -6737204; - colorTable[0x3b] = -7667712; - colorTable[60] = -1468806; - colorTable[0x3d] = -7357301; - colorTable[0x3e] = -12042869; - colorTable[0x3f] = -13676721; - colorTable[0x40] = -16724271; - colorTable[0x41] = -7077677; - colorTable[0x42] = -60269; - colorTable[0x43] = -16728065; - colorTable[0x44] = -9868951; - colorTable[0x45] = -14774017; - colorTable[70] = -5103070; - colorTable[0x47] = -1296; - colorTable[0x48] = -14513374; - colorTable[0x49] = -65281; - colorTable[0x4a] = -2302756; - colorTable[0x4b] = -460545; - colorTable[0x4c] = -10496; - colorTable[0x4d] = -2448096; - colorTable[0x4e] = -8355712; - colorTable[0x4f] = -16744448; - colorTable[80] = -5374161; - colorTable[0x51] = -983056; - colorTable[0x52] = -38476; - colorTable[0x53] = -3318692; - colorTable[0x54] = -11861886; - colorTable[0x55] = -16; - colorTable[0x56] = -989556; - colorTable[0x57] = -1644806; - colorTable[0x58] = -3851; - colorTable[0x59] = -8586240; - colorTable[90] = -1331; - colorTable[0x5b] = -5383962; - colorTable[0x5c] = -1015680; - colorTable[0x5d] = -2031617; - colorTable[0x5e] = -329006; - colorTable[0x5f] = -2894893; - colorTable[0x60] = -7278960; - colorTable[0x61] = -18751; - colorTable[0x62] = -24454; - colorTable[0x63] = -14634326; - colorTable[100] = -7876870; - colorTable[0x65] = -8943463; - colorTable[0x66] = -5192482; - colorTable[0x67] = -32; - colorTable[0x68] = -16711936; - colorTable[0x69] = -13447886; - colorTable[0x6a] = -331546; - colorTable[0x6b] = -65281; - colorTable[0x6c] = -8388608; - colorTable[0x6d] = -10039894; - colorTable[110] = -16777011; - colorTable[0x6f] = -4565549; - colorTable[0x70] = -7114533; - colorTable[0x71] = -12799119; - colorTable[0x72] = -8689426; - colorTable[0x73] = -16713062; - colorTable[0x74] = -12004916; - colorTable[0x75] = -3730043; - colorTable[0x76] = -15132304; - colorTable[0x77] = -655366; - colorTable[120] = -6943; - colorTable[0x79] = -6987; - colorTable[0x7a] = -8531; - colorTable[0x7b] = -16777088; - colorTable[0x7c] = -133658; - colorTable[0x7d] = -8355840; - colorTable[0x7e] = -9728477; - colorTable[0x7f] = -23296; - colorTable[0x80] = -47872; - colorTable[0x81] = -2461482; - colorTable[130] = -1120086; - colorTable[0x83] = -6751336; - colorTable[0x84] = -5247250; - colorTable[0x85] = -2396013; - colorTable[0x86] = -4139; - colorTable[0x87] = -9543; - colorTable[0x88] = -3308225; - colorTable[0x89] = -16181; - colorTable[0x8a] = -2252579; - colorTable[0x8b] = -5185306; - colorTable[140] = -8388480; - colorTable[0x8d] = -65536; - colorTable[0x8e] = -4419697; - colorTable[0x8f] = -12490271; - colorTable[0x90] = -7650029; - colorTable[0x91] = -360334; - colorTable[0x92] = -744352; - colorTable[0x93] = -13726889; - colorTable[0x94] = -2578; - colorTable[0x95] = -6270419; - colorTable[150] = -4144960; - colorTable[0x97] = -7876885; - colorTable[0x98] = -9807155; - colorTable[0x99] = -9404272; - colorTable[0x9a] = -1286; - colorTable[0x9b] = -16711809; - colorTable[0x9c] = -12156236; - colorTable[0x9d] = -2968436; - colorTable[0x9e] = -16744320; - colorTable[0x9f] = -2572328; - colorTable[160] = -40121; - colorTable[0xa1] = -12525360; - colorTable[0xa2] = -1146130; - colorTable[0xa3] = -663885; - colorTable[0xa4] = -1; - colorTable[0xa5] = -657931; - colorTable[0xa6] = -256; - colorTable[0xa7] = -6632142; - } - - /// internal method - int? knowColorToArgb(KnownColor color) { - if (getKnownColor(color) <= getKnownColor(KnownColor.menuHighlight)) { - return colorTable[getKnownColor(color)]; - } - return 0; - } - - /// internal method - int getKnownColor(KnownColor color) { - switch (color) { - case KnownColor.activeBorder: - return 1; - case KnownColor.activeCaption: - return 2; - case KnownColor.activeCaptionText: - return 3; - case KnownColor.aliceBlue: - return 0x1c; - case KnownColor.antiqueWhite: - return 0x1d; - case KnownColor.appWorkspace: - return 4; - case KnownColor.aqua: - return 30; - case KnownColor.aquamarine: - return 0x1f; - case KnownColor.azure: - return 0x20; - case KnownColor.beige: - return 0x21; - case KnownColor.bisque: - return 0x22; - case KnownColor.black: - return 0x23; - case KnownColor.blanchedAlmond: - return 0x24; - case KnownColor.blue: - return 0x25; - case KnownColor.blueViolet: - return 0x26; - case KnownColor.brown: - return 0x27; - case KnownColor.burlyWood: - return 40; - case KnownColor.buttonFace: - return 0xa8; - case KnownColor.buttonHighlight: - return 0xa9; - case KnownColor.buttonShadow: - return 170; - case KnownColor.cadetBlue: - return 0x29; - case KnownColor.chartreuse: - return 0x2a; - case KnownColor.chocolate: - return 0x2b; - case KnownColor.control: - return 5; - case KnownColor.controlDark: - return 6; - case KnownColor.controlDarkDark: - return 7; - case KnownColor.controlLight: - return 8; - case KnownColor.controlLightLight: - return 9; - case KnownColor.controlText: - return 10; - case KnownColor.coral: - return 0x2c; - case KnownColor.cornflowerBlue: - return 0x2d; - case KnownColor.cornsilk: - return 0x2e; - case KnownColor.crimson: - return 0x2f; - case KnownColor.cyan: - return 0x30; - case KnownColor.darkBlue: - return 0x31; - case KnownColor.darkCyan: - return 50; - case KnownColor.darkGoldenrod: - return 0x33; - case KnownColor.darkGray: - return 0x34; - case KnownColor.darkGreen: - return 0x35; - case KnownColor.darkKhaki: - return 0x36; - case KnownColor.darkMagenta: - return 0x37; - case KnownColor.darkOliveGreen: - return 0x38; - case KnownColor.darkOrange: - return 0x39; - case KnownColor.darkOrchid: - return 0x3a; - case KnownColor.darkRed: - return 0x3b; - case KnownColor.darkSalmon: - return 60; - case KnownColor.darkSeaGreen: - return 0x3d; - case KnownColor.darkSlateBlue: - return 0x3e; - case KnownColor.darkSlateGray: - return 0x3f; - case KnownColor.darkTurquoise: - return 0x40; - case KnownColor.darkViolet: - return 0x41; - case KnownColor.deepPink: - return 0x42; - case KnownColor.deepSkyBlue: - return 0x43; - case KnownColor.desktop: - return 11; - case KnownColor.dimGray: - return 0x44; - case KnownColor.dodgerBlue: - return 0x45; - case KnownColor.firebrick: - return 70; - case KnownColor.floralWhite: - return 0x47; - case KnownColor.forestGreen: - return 0x48; - case KnownColor.fuchsia: - return 0x49; - case KnownColor.gainsboro: - return 0x4a; - case KnownColor.ghostWhite: - return 0x4b; - case KnownColor.gold: - return 0x4c; - case KnownColor.goldenrod: - return 0x4d; - case KnownColor.gradientActiveCaption: - return 0xab; - case KnownColor.gradientInactiveCaption: - return 0xac; - case KnownColor.gray: - return 0x4e; - case KnownColor.grayText: - return 12; - case KnownColor.green: - return 0x4f; - case KnownColor.greenYellow: - return 80; - case KnownColor.highlight: - return 13; - case KnownColor.highlightText: - return 14; - case KnownColor.honeydew: - return 0x51; - case KnownColor.hotPink: - return 0x52; - case KnownColor.hotTrack: - return 15; - case KnownColor.inactiveBorder: - return 0x10; - case KnownColor.inactiveCaption: - return 0x11; - case KnownColor.inactiveCaptionText: - return 0x12; - case KnownColor.indianRed: - return 0x53; - case KnownColor.indigo: - return 0x54; - case KnownColor.info: - return 0x13; - case KnownColor.infoText: - return 20; - case KnownColor.ivory: - return 0x55; - case KnownColor.khaki: - return 0x56; - case KnownColor.lavender: - return 0x57; - case KnownColor.lavenderBlush: - return 0x58; - case KnownColor.lawnGreen: - return 0x59; - case KnownColor.lemonChiffon: - return 90; - case KnownColor.lightBlue: - return 0x5b; - case KnownColor.lightCoral: - return 0x5c; - case KnownColor.lightCyan: - return 0x5d; - case KnownColor.lightGoldenrodYellow: - return 0x5e; - case KnownColor.lightGray: - return 0x5f; - case KnownColor.lightGreen: - return 0x60; - case KnownColor.lightPink: - return 0x61; - case KnownColor.lightSalmon: - return 0x62; - case KnownColor.lightSeaGreen: - return 0x63; - case KnownColor.lightSkyBlue: - return 100; - case KnownColor.lightSlateGray: - return 0x65; - case KnownColor.lightSteelBlue: - return 0x66; - case KnownColor.lightYellow: - return 0x67; - case KnownColor.lime: - return 0x68; - case KnownColor.limeGreen: - return 0x69; - case KnownColor.linen: - return 0x6a; - case KnownColor.magenta: - return 0x6b; - case KnownColor.maroon: - return 0x6c; - case KnownColor.mediumAquamarine: - return 0x6d; - case KnownColor.mediumBlue: - return 110; - case KnownColor.mediumOrchid: - return 0x6f; - case KnownColor.mediumPurple: - return 0x70; - case KnownColor.mediumSeaGreen: - return 0x71; - case KnownColor.mediumSlateBlue: - return 0x72; - case KnownColor.mediumSpringGreen: - return 0x73; - case KnownColor.mediumTurquoise: - return 0x74; - case KnownColor.mediumVioletRed: - return 0x75; - case KnownColor.menu: - return 0x15; - case KnownColor.menuBar: - return 0xad; - case KnownColor.menuHighlight: - return 0xae; - case KnownColor.menuText: - return 0x16; - case KnownColor.midnightBlue: - return 0x76; - case KnownColor.mintCream: - return 0x77; - case KnownColor.mistyRose: - return 120; - case KnownColor.moccasin: - return 0x79; - case KnownColor.navajoWhite: - return 0x7a; - case KnownColor.navy: - return 0x7b; - case KnownColor.oldLace: - return 0x7c; - case KnownColor.olive: - return 0x7d; - case KnownColor.oliveDrab: - return 0x7e; - case KnownColor.orange: - return 0x7f; - case KnownColor.orangeRed: - return 0x80; - case KnownColor.orchid: - return 0x81; - case KnownColor.paleGoldenrod: - return 130; - case KnownColor.paleGreen: - return 0x83; - case KnownColor.paleTurquoise: - return 0x84; - case KnownColor.paleVioletRed: - return 0x85; - case KnownColor.papayaWhip: - return 0x86; - case KnownColor.peachPuff: - return 0x87; - case KnownColor.peru: - return 0x88; - case KnownColor.pink: - return 0x89; - case KnownColor.plum: - return 0x8a; - case KnownColor.powderBlue: - return 0x8b; - case KnownColor.purple: - return 140; - case KnownColor.red: - return 0x8d; - case KnownColor.rosyBrown: - return 0x8e; - case KnownColor.royalBlue: - return 0x8f; - case KnownColor.saddleBrown: - return 0x90; - case KnownColor.salmon: - return 0x91; - case KnownColor.sandyBrown: - return 0x92; - case KnownColor.scrollBar: - return 0x17; - case KnownColor.seaGreen: - return 0x93; - case KnownColor.seaShell: - return 0x94; - case KnownColor.sienna: - return 0x95; - case KnownColor.silver: - return 150; - case KnownColor.skyBlue: - return 0x97; - case KnownColor.slateBlue: - return 0x98; - case KnownColor.slateGray: - return 0x99; - case KnownColor.snow: - return 0x9a; - case KnownColor.springGreen: - return 0x9b; - case KnownColor.steelBlue: - return 0x9c; - case KnownColor.tan: - return 0x9d; - case KnownColor.teal: - return 0x9e; - case KnownColor.thistle: - return 0x9f; - case KnownColor.tomato: - return 160; - case KnownColor.transparent: - return 0x1b; - case KnownColor.turquoise: - return 0xa1; - case KnownColor.violet: - return 0xa2; - case KnownColor.wheat: - return 0xa3; - case KnownColor.white: - return 0xa4; - case KnownColor.whiteSmoke: - return 0xa5; - case KnownColor.window: - return 0x18; - case KnownColor.windowFrame: - return 0x19; - case KnownColor.windowText: - return 0x1a; - case KnownColor.yellow: - return 0xa6; - case KnownColor.yellowGreen: - return 0xa7; - } - } -} - -/// internal enumerator -enum KnownColor { - /// internal enumerator - activeBorder, - - /// internal enumerator - activeCaption, - - /// internal enumerator - activeCaptionText, - - /// internal enumerator - aliceBlue, - - /// internal enumerator - antiqueWhite, - - /// internal enumerator - appWorkspace, - - /// internal enumerator - aqua, - - /// internal enumerator - aquamarine, - - /// internal enumerator - azure, - - /// internal enumerator - beige, - - /// internal enumerator - bisque, - - /// internal enumerator - black, - - /// internal enumerator - blanchedAlmond, - - /// internal enumerator - blue, - - /// internal enumerator - blueViolet, - - /// internal enumerator - brown, - - /// internal enumerator - burlyWood, - - /// internal enumerator - buttonFace, - - /// internal enumerator - buttonHighlight, - - /// internal enumerator - buttonShadow, - - /// internal enumerator - cadetBlue, - - /// internal enumerator - chartreuse, - - /// internal enumerator - chocolate, - - /// internal enumerator - control, - - /// internal enumerator - controlDark, - - /// internal enumerator - controlDarkDark, - - /// internal enumerator - controlLight, - - /// internal enumerator - controlLightLight, - - /// internal enumerator - controlText, - - /// internal enumerator - coral, - - /// internal enumerator - cornflowerBlue, - - /// internal enumerator - cornsilk, - - /// internal enumerator - crimson, - - /// internal enumerator - cyan, - - /// internal enumerator - darkBlue, - - /// internal enumerator - darkCyan, - - /// internal enumerator - darkGoldenrod, - - /// internal enumerator - darkGray, - - /// internal enumerator - darkGreen, - - /// internal enumerator - darkKhaki, - - /// internal enumerator - darkMagenta, - - /// internal enumerator - darkOliveGreen, - - /// internal enumerator - darkOrange, - - /// internal enumerator - darkOrchid, - - /// internal enumerator - darkRed, - - /// internal enumerator - darkSalmon, - - /// internal enumerator - /// internal enumerator - darkSeaGreen, - - /// internal enumerator - darkSlateBlue, - - /// internal enumerator - darkSlateGray, - - /// internal enumerator - darkTurquoise, - - /// internal enumerator - darkViolet, - - /// internal enumerator - deepPink, - - /// internal enumerator - deepSkyBlue, - - /// internal enumerator - desktop, - - /// internal enumerator - dimGray, - - /// internal enumerator - dodgerBlue, - - /// internal enumerator - firebrick, - - /// internal enumerator - floralWhite, - - /// internal enumerator - forestGreen, - - /// internal enumerator - fuchsia, - - /// internal enumerator - gainsboro, - - /// internal enumerator - ghostWhite, - - /// internal enumerator - gold, - - /// internal enumerator - goldenrod, - - /// internal enumerator - gradientActiveCaption, - - /// internal enumerator - gradientInactiveCaption, - - /// internal enumerator - gray, - - /// internal enumerator - grayText, - - /// internal enumerator - green, - - /// internal enumerator - greenYellow, - - /// internal enumerator - highlight, - - /// internal enumerator - highlightText, - - /// internal enumerator - honeydew, - - /// internal enumerator - hotPink, - - /// internal enumerator - hotTrack, - - /// internal enumerator - inactiveBorder, - - /// internal enumerator - inactiveCaption, - - /// internal enumerator - inactiveCaptionText, - - /// internal enumerator - indianRed, - - /// internal enumerator - indigo, - - /// internal enumerator - info, - - /// internal enumerator - infoText, - - /// internal enumerator - ivory, - - /// internal enumerator - khaki, - - /// internal enumerator - lavender, - - /// internal enumerator - lavenderBlush, - - /// internal enumerator - lawnGreen, - - /// internal enumerator - lemonChiffon, - - /// internal enumerator - lightBlue, - - /// internal enumerator - lightCoral, - - /// internal enumerator - lightCyan, - - /// internal enumerator - lightGoldenrodYellow, - - /// internal enumerator - lightGray, - - /// internal enumerator - lightGreen, - - /// internal enumerator - lightPink, - - /// internal enumerator - lightSalmon, - - /// internal enumerator - lightSeaGreen, - - /// internal enumerator - lightSkyBlue, - - /// internal enumerator - lightSlateGray, - - /// internal enumerator - lightSteelBlue, - - /// internal enumerator - lightYellow, - - /// internal enumerator - lime, - - /// internal enumerator - limeGreen, - - /// internal enumerator - linen, - - /// internal enumerator - magenta, - - /// internal enumerator - maroon, - - /// internal enumerator - mediumAquamarine, - - /// internal enumerator - mediumBlue, - - /// internal enumerator - mediumOrchid, - - /// internal enumerator - mediumPurple, - - /// internal enumerator - mediumSeaGreen, - - /// internal enumerator - mediumSlateBlue, - - /// internal enumerator - mediumSpringGreen, - - /// internal enumerator - mediumTurquoise, - - /// internal enumerator - mediumVioletRed, - - /// internal enumerator - menu, - - /// internal enumerator - menuBar, - - /// internal enumerator - menuHighlight, - - /// internal enumerator - menuText, - - /// internal enumerator - midnightBlue, - - /// internal enumerator - mintCream, - - /// internal enumerator - mistyRose, - - /// internal enumerator - moccasin, - - /// internal enumerator - navajoWhite, - - /// internal enumerator - navy, - - /// internal enumerator - oldLace, - - /// internal enumerator - olive, - - /// internal enumerator - oliveDrab, - - /// internal enumerator - orange, - - /// internal enumerator - orangeRed, - - /// internal enumerator - orchid, - - /// internal enumerator - paleGoldenrod, - - /// internal enumerator - paleGreen, - - /// internal enumerator - paleTurquoise, - - /// internal enumerator - paleVioletRed, - - /// internal enumerator - papayaWhip, - - /// internal enumerator - peachPuff, - - /// internal enumerator - peru, - - /// internal enumerator - pink, - - /// internal enumerator - plum, - - /// internal enumerator - powderBlue, - - /// internal enumerator - purple, - - /// internal enumerator - red, - - /// internal enumerator - rosyBrown, - - /// internal enumerator - royalBlue, - - /// internal enumerator - saddleBrown, - - /// internal enumerator - salmon, - - /// internal enumerator - sandyBrown, - - /// internal enumerator - scrollBar, - - /// internal enumerator - seaGreen, - - /// internal enumerator - seaShell, - - /// internal enumerator - sienna, - - /// internal enumerator - silver, - - /// internal enumerator - skyBlue, - - /// internal enumerator - slateBlue, - - /// internal enumerator - slateGray, - - /// internal enumerator - snow, - - /// internal enumerator - springGreen, - - /// internal enumerator - steelBlue, - - /// internal enumerator - tan, - - /// internal enumerator - teal, - - /// internal enumerator - thistle, - - /// internal enumerator - tomato, - - /// internal enumerator - transparent, - - /// internal enumerator - turquoise, - - /// internal enumerator - violet, - - /// internal enumerator - wheat, - - /// internal enumerator - white, - - /// internal enumerator - whiteSmoke, - - /// internal enumerator - window, - - /// internal enumerator - windowFrame, - - /// internal enumerator - windowText, - - /// internal enumerator - yellow, - - /// internal enumerator - yellowGreen, -} +/// internal class +class ColorHelper { + /// internal constructor + ColorHelper(this._knownColor); + + /// internal field + static const int argbAlphaShift = 24; + + /// internal field + static const int argbRedShift = 16; + + /// internal field + static const int argbGreebShift = 8; + + /// internal field + static const int argbBlueShift = 0; + + int? _value; + final KnownColor _knownColor; + + /// internal property + int get r { + return ((value! >> argbRedShift) & 0xFF).toUnsigned(8); + } + + /// internal property + int get g { + return ((value! >> argbGreebShift) & 0xFF).toUnsigned(8); + } + + /// internal property + int get b { + return ((value! >> argbBlueShift) & 0xFF).toUnsigned(8); + } + + /// internal property + int get a { + return ((value! >> argbAlphaShift) & 0xFF).toUnsigned(8); + } + + /// internal property + int? get value { + _value ??= KnownColorTable().knowColorToArgb(_knownColor); + return _value; + } +} + +/// internal class +class KnownColorTable { + /// internal constructor + KnownColorTable() { + initColorTable(); + } + + /// internal field + static Map colorTable = {}; + + /// internal method + void initColorTable() { + colorTable[0x1b] = 0xffffff; + colorTable[0x1c] = -984833; + colorTable[0x1d] = -332841; + colorTable[30] = -16711681; + colorTable[0x1f] = -8388652; + colorTable[0x18] = -1; + colorTable[0x20] = -983041; + colorTable[0x21] = -657956; + colorTable[0x22] = -6972; + colorTable[0x23] = -16777216; + colorTable[0x24] = -5171; + colorTable[0x25] = -16776961; + colorTable[0x26] = -7722014; + colorTable[0x27] = -5952982; + colorTable[40] = -2180985; + colorTable[0x29] = -10510688; + colorTable[0x2a] = -8388864; + colorTable[0x2b] = -2987746; + colorTable[0x2c] = -32944; + colorTable[0x2d] = -10185235; + colorTable[0x2e] = -1828; + colorTable[0x2f] = -2354116; + colorTable[0x30] = -16711681; + colorTable[0x31] = -16777077; + colorTable[50] = -16741493; + colorTable[0x33] = -4684277; + colorTable[0x34] = -5658199; + colorTable[0x35] = -16751616; + colorTable[0x36] = -4343957; + colorTable[0x37] = -7667573; + colorTable[0x38] = -11179217; + colorTable[0x39] = -29696; + colorTable[0x3a] = -6737204; + colorTable[0x3b] = -7667712; + colorTable[60] = -1468806; + colorTable[0x3d] = -7357301; + colorTable[0x3e] = -12042869; + colorTable[0x3f] = -13676721; + colorTable[0x40] = -16724271; + colorTable[0x41] = -7077677; + colorTable[0x42] = -60269; + colorTable[0x43] = -16728065; + colorTable[0x44] = -9868951; + colorTable[0x45] = -14774017; + colorTable[70] = -5103070; + colorTable[0x47] = -1296; + colorTable[0x48] = -14513374; + colorTable[0x49] = -65281; + colorTable[0x4a] = -2302756; + colorTable[0x4b] = -460545; + colorTable[0x4c] = -10496; + colorTable[0x4d] = -2448096; + colorTable[0x4e] = -8355712; + colorTable[0x4f] = -16744448; + colorTable[80] = -5374161; + colorTable[0x51] = -983056; + colorTable[0x52] = -38476; + colorTable[0x53] = -3318692; + colorTable[0x54] = -11861886; + colorTable[0x55] = -16; + colorTable[0x56] = -989556; + colorTable[0x57] = -1644806; + colorTable[0x58] = -3851; + colorTable[0x59] = -8586240; + colorTable[90] = -1331; + colorTable[0x5b] = -5383962; + colorTable[0x5c] = -1015680; + colorTable[0x5d] = -2031617; + colorTable[0x5e] = -329006; + colorTable[0x5f] = -2894893; + colorTable[0x60] = -7278960; + colorTable[0x61] = -18751; + colorTable[0x62] = -24454; + colorTable[0x63] = -14634326; + colorTable[100] = -7876870; + colorTable[0x65] = -8943463; + colorTable[0x66] = -5192482; + colorTable[0x67] = -32; + colorTable[0x68] = -16711936; + colorTable[0x69] = -13447886; + colorTable[0x6a] = -331546; + colorTable[0x6b] = -65281; + colorTable[0x6c] = -8388608; + colorTable[0x6d] = -10039894; + colorTable[110] = -16777011; + colorTable[0x6f] = -4565549; + colorTable[0x70] = -7114533; + colorTable[0x71] = -12799119; + colorTable[0x72] = -8689426; + colorTable[0x73] = -16713062; + colorTable[0x74] = -12004916; + colorTable[0x75] = -3730043; + colorTable[0x76] = -15132304; + colorTable[0x77] = -655366; + colorTable[120] = -6943; + colorTable[0x79] = -6987; + colorTable[0x7a] = -8531; + colorTable[0x7b] = -16777088; + colorTable[0x7c] = -133658; + colorTable[0x7d] = -8355840; + colorTable[0x7e] = -9728477; + colorTable[0x7f] = -23296; + colorTable[0x80] = -47872; + colorTable[0x81] = -2461482; + colorTable[130] = -1120086; + colorTable[0x83] = -6751336; + colorTable[0x84] = -5247250; + colorTable[0x85] = -2396013; + colorTable[0x86] = -4139; + colorTable[0x87] = -9543; + colorTable[0x88] = -3308225; + colorTable[0x89] = -16181; + colorTable[0x8a] = -2252579; + colorTable[0x8b] = -5185306; + colorTable[140] = -8388480; + colorTable[0x8d] = -65536; + colorTable[0x8e] = -4419697; + colorTable[0x8f] = -12490271; + colorTable[0x90] = -7650029; + colorTable[0x91] = -360334; + colorTable[0x92] = -744352; + colorTable[0x93] = -13726889; + colorTable[0x94] = -2578; + colorTable[0x95] = -6270419; + colorTable[150] = -4144960; + colorTable[0x97] = -7876885; + colorTable[0x98] = -9807155; + colorTable[0x99] = -9404272; + colorTable[0x9a] = -1286; + colorTable[0x9b] = -16711809; + colorTable[0x9c] = -12156236; + colorTable[0x9d] = -2968436; + colorTable[0x9e] = -16744320; + colorTable[0x9f] = -2572328; + colorTable[160] = -40121; + colorTable[0xa1] = -12525360; + colorTable[0xa2] = -1146130; + colorTable[0xa3] = -663885; + colorTable[0xa4] = -1; + colorTable[0xa5] = -657931; + colorTable[0xa6] = -256; + colorTable[0xa7] = -6632142; + } + + /// internal method + int? knowColorToArgb(KnownColor color) { + if (getKnownColor(color) <= getKnownColor(KnownColor.menuHighlight)) { + return colorTable[getKnownColor(color)]; + } + return 0; + } + + /// internal method + int getKnownColor(KnownColor color) { + switch (color) { + case KnownColor.activeBorder: + return 1; + case KnownColor.activeCaption: + return 2; + case KnownColor.activeCaptionText: + return 3; + case KnownColor.aliceBlue: + return 0x1c; + case KnownColor.antiqueWhite: + return 0x1d; + case KnownColor.appWorkspace: + return 4; + case KnownColor.aqua: + return 30; + case KnownColor.aquamarine: + return 0x1f; + case KnownColor.azure: + return 0x20; + case KnownColor.beige: + return 0x21; + case KnownColor.bisque: + return 0x22; + case KnownColor.black: + return 0x23; + case KnownColor.blanchedAlmond: + return 0x24; + case KnownColor.blue: + return 0x25; + case KnownColor.blueViolet: + return 0x26; + case KnownColor.brown: + return 0x27; + case KnownColor.burlyWood: + return 40; + case KnownColor.buttonFace: + return 0xa8; + case KnownColor.buttonHighlight: + return 0xa9; + case KnownColor.buttonShadow: + return 170; + case KnownColor.cadetBlue: + return 0x29; + case KnownColor.chartreuse: + return 0x2a; + case KnownColor.chocolate: + return 0x2b; + case KnownColor.control: + return 5; + case KnownColor.controlDark: + return 6; + case KnownColor.controlDarkDark: + return 7; + case KnownColor.controlLight: + return 8; + case KnownColor.controlLightLight: + return 9; + case KnownColor.controlText: + return 10; + case KnownColor.coral: + return 0x2c; + case KnownColor.cornflowerBlue: + return 0x2d; + case KnownColor.cornsilk: + return 0x2e; + case KnownColor.crimson: + return 0x2f; + case KnownColor.cyan: + return 0x30; + case KnownColor.darkBlue: + return 0x31; + case KnownColor.darkCyan: + return 50; + case KnownColor.darkGoldenrod: + return 0x33; + case KnownColor.darkGray: + return 0x34; + case KnownColor.darkGreen: + return 0x35; + case KnownColor.darkKhaki: + return 0x36; + case KnownColor.darkMagenta: + return 0x37; + case KnownColor.darkOliveGreen: + return 0x38; + case KnownColor.darkOrange: + return 0x39; + case KnownColor.darkOrchid: + return 0x3a; + case KnownColor.darkRed: + return 0x3b; + case KnownColor.darkSalmon: + return 60; + case KnownColor.darkSeaGreen: + return 0x3d; + case KnownColor.darkSlateBlue: + return 0x3e; + case KnownColor.darkSlateGray: + return 0x3f; + case KnownColor.darkTurquoise: + return 0x40; + case KnownColor.darkViolet: + return 0x41; + case KnownColor.deepPink: + return 0x42; + case KnownColor.deepSkyBlue: + return 0x43; + case KnownColor.desktop: + return 11; + case KnownColor.dimGray: + return 0x44; + case KnownColor.dodgerBlue: + return 0x45; + case KnownColor.firebrick: + return 70; + case KnownColor.floralWhite: + return 0x47; + case KnownColor.forestGreen: + return 0x48; + case KnownColor.fuchsia: + return 0x49; + case KnownColor.gainsboro: + return 0x4a; + case KnownColor.ghostWhite: + return 0x4b; + case KnownColor.gold: + return 0x4c; + case KnownColor.goldenrod: + return 0x4d; + case KnownColor.gradientActiveCaption: + return 0xab; + case KnownColor.gradientInactiveCaption: + return 0xac; + case KnownColor.gray: + return 0x4e; + case KnownColor.grayText: + return 12; + case KnownColor.green: + return 0x4f; + case KnownColor.greenYellow: + return 80; + case KnownColor.highlight: + return 13; + case KnownColor.highlightText: + return 14; + case KnownColor.honeydew: + return 0x51; + case KnownColor.hotPink: + return 0x52; + case KnownColor.hotTrack: + return 15; + case KnownColor.inactiveBorder: + return 0x10; + case KnownColor.inactiveCaption: + return 0x11; + case KnownColor.inactiveCaptionText: + return 0x12; + case KnownColor.indianRed: + return 0x53; + case KnownColor.indigo: + return 0x54; + case KnownColor.info: + return 0x13; + case KnownColor.infoText: + return 20; + case KnownColor.ivory: + return 0x55; + case KnownColor.khaki: + return 0x56; + case KnownColor.lavender: + return 0x57; + case KnownColor.lavenderBlush: + return 0x58; + case KnownColor.lawnGreen: + return 0x59; + case KnownColor.lemonChiffon: + return 90; + case KnownColor.lightBlue: + return 0x5b; + case KnownColor.lightCoral: + return 0x5c; + case KnownColor.lightCyan: + return 0x5d; + case KnownColor.lightGoldenrodYellow: + return 0x5e; + case KnownColor.lightGray: + return 0x5f; + case KnownColor.lightGreen: + return 0x60; + case KnownColor.lightPink: + return 0x61; + case KnownColor.lightSalmon: + return 0x62; + case KnownColor.lightSeaGreen: + return 0x63; + case KnownColor.lightSkyBlue: + return 100; + case KnownColor.lightSlateGray: + return 0x65; + case KnownColor.lightSteelBlue: + return 0x66; + case KnownColor.lightYellow: + return 0x67; + case KnownColor.lime: + return 0x68; + case KnownColor.limeGreen: + return 0x69; + case KnownColor.linen: + return 0x6a; + case KnownColor.magenta: + return 0x6b; + case KnownColor.maroon: + return 0x6c; + case KnownColor.mediumAquamarine: + return 0x6d; + case KnownColor.mediumBlue: + return 110; + case KnownColor.mediumOrchid: + return 0x6f; + case KnownColor.mediumPurple: + return 0x70; + case KnownColor.mediumSeaGreen: + return 0x71; + case KnownColor.mediumSlateBlue: + return 0x72; + case KnownColor.mediumSpringGreen: + return 0x73; + case KnownColor.mediumTurquoise: + return 0x74; + case KnownColor.mediumVioletRed: + return 0x75; + case KnownColor.menu: + return 0x15; + case KnownColor.menuBar: + return 0xad; + case KnownColor.menuHighlight: + return 0xae; + case KnownColor.menuText: + return 0x16; + case KnownColor.midnightBlue: + return 0x76; + case KnownColor.mintCream: + return 0x77; + case KnownColor.mistyRose: + return 120; + case KnownColor.moccasin: + return 0x79; + case KnownColor.navajoWhite: + return 0x7a; + case KnownColor.navy: + return 0x7b; + case KnownColor.oldLace: + return 0x7c; + case KnownColor.olive: + return 0x7d; + case KnownColor.oliveDrab: + return 0x7e; + case KnownColor.orange: + return 0x7f; + case KnownColor.orangeRed: + return 0x80; + case KnownColor.orchid: + return 0x81; + case KnownColor.paleGoldenrod: + return 130; + case KnownColor.paleGreen: + return 0x83; + case KnownColor.paleTurquoise: + return 0x84; + case KnownColor.paleVioletRed: + return 0x85; + case KnownColor.papayaWhip: + return 0x86; + case KnownColor.peachPuff: + return 0x87; + case KnownColor.peru: + return 0x88; + case KnownColor.pink: + return 0x89; + case KnownColor.plum: + return 0x8a; + case KnownColor.powderBlue: + return 0x8b; + case KnownColor.purple: + return 140; + case KnownColor.red: + return 0x8d; + case KnownColor.rosyBrown: + return 0x8e; + case KnownColor.royalBlue: + return 0x8f; + case KnownColor.saddleBrown: + return 0x90; + case KnownColor.salmon: + return 0x91; + case KnownColor.sandyBrown: + return 0x92; + case KnownColor.scrollBar: + return 0x17; + case KnownColor.seaGreen: + return 0x93; + case KnownColor.seaShell: + return 0x94; + case KnownColor.sienna: + return 0x95; + case KnownColor.silver: + return 150; + case KnownColor.skyBlue: + return 0x97; + case KnownColor.slateBlue: + return 0x98; + case KnownColor.slateGray: + return 0x99; + case KnownColor.snow: + return 0x9a; + case KnownColor.springGreen: + return 0x9b; + case KnownColor.steelBlue: + return 0x9c; + case KnownColor.tan: + return 0x9d; + case KnownColor.teal: + return 0x9e; + case KnownColor.thistle: + return 0x9f; + case KnownColor.tomato: + return 160; + case KnownColor.transparent: + return 0x1b; + case KnownColor.turquoise: + return 0xa1; + case KnownColor.violet: + return 0xa2; + case KnownColor.wheat: + return 0xa3; + case KnownColor.white: + return 0xa4; + case KnownColor.whiteSmoke: + return 0xa5; + case KnownColor.window: + return 0x18; + case KnownColor.windowFrame: + return 0x19; + case KnownColor.windowText: + return 0x1a; + case KnownColor.yellow: + return 0xa6; + case KnownColor.yellowGreen: + return 0xa7; + } + } +} + +/// internal enumerator +enum KnownColor { + /// internal enumerator + activeBorder, + + /// internal enumerator + activeCaption, + + /// internal enumerator + activeCaptionText, + + /// internal enumerator + aliceBlue, + + /// internal enumerator + antiqueWhite, + + /// internal enumerator + appWorkspace, + + /// internal enumerator + aqua, + + /// internal enumerator + aquamarine, + + /// internal enumerator + azure, + + /// internal enumerator + beige, + + /// internal enumerator + bisque, + + /// internal enumerator + black, + + /// internal enumerator + blanchedAlmond, + + /// internal enumerator + blue, + + /// internal enumerator + blueViolet, + + /// internal enumerator + brown, + + /// internal enumerator + burlyWood, + + /// internal enumerator + buttonFace, + + /// internal enumerator + buttonHighlight, + + /// internal enumerator + buttonShadow, + + /// internal enumerator + cadetBlue, + + /// internal enumerator + chartreuse, + + /// internal enumerator + chocolate, + + /// internal enumerator + control, + + /// internal enumerator + controlDark, + + /// internal enumerator + controlDarkDark, + + /// internal enumerator + controlLight, + + /// internal enumerator + controlLightLight, + + /// internal enumerator + controlText, + + /// internal enumerator + coral, + + /// internal enumerator + cornflowerBlue, + + /// internal enumerator + cornsilk, + + /// internal enumerator + crimson, + + /// internal enumerator + cyan, + + /// internal enumerator + darkBlue, + + /// internal enumerator + darkCyan, + + /// internal enumerator + darkGoldenrod, + + /// internal enumerator + darkGray, + + /// internal enumerator + darkGreen, + + /// internal enumerator + darkKhaki, + + /// internal enumerator + darkMagenta, + + /// internal enumerator + darkOliveGreen, + + /// internal enumerator + darkOrange, + + /// internal enumerator + darkOrchid, + + /// internal enumerator + darkRed, + + /// internal enumerator + darkSalmon, + + /// internal enumerator + /// internal enumerator + darkSeaGreen, + + /// internal enumerator + darkSlateBlue, + + /// internal enumerator + darkSlateGray, + + /// internal enumerator + darkTurquoise, + + /// internal enumerator + darkViolet, + + /// internal enumerator + deepPink, + + /// internal enumerator + deepSkyBlue, + + /// internal enumerator + desktop, + + /// internal enumerator + dimGray, + + /// internal enumerator + dodgerBlue, + + /// internal enumerator + firebrick, + + /// internal enumerator + floralWhite, + + /// internal enumerator + forestGreen, + + /// internal enumerator + fuchsia, + + /// internal enumerator + gainsboro, + + /// internal enumerator + ghostWhite, + + /// internal enumerator + gold, + + /// internal enumerator + goldenrod, + + /// internal enumerator + gradientActiveCaption, + + /// internal enumerator + gradientInactiveCaption, + + /// internal enumerator + gray, + + /// internal enumerator + grayText, + + /// internal enumerator + green, + + /// internal enumerator + greenYellow, + + /// internal enumerator + highlight, + + /// internal enumerator + highlightText, + + /// internal enumerator + honeydew, + + /// internal enumerator + hotPink, + + /// internal enumerator + hotTrack, + + /// internal enumerator + inactiveBorder, + + /// internal enumerator + inactiveCaption, + + /// internal enumerator + inactiveCaptionText, + + /// internal enumerator + indianRed, + + /// internal enumerator + indigo, + + /// internal enumerator + info, + + /// internal enumerator + infoText, + + /// internal enumerator + ivory, + + /// internal enumerator + khaki, + + /// internal enumerator + lavender, + + /// internal enumerator + lavenderBlush, + + /// internal enumerator + lawnGreen, + + /// internal enumerator + lemonChiffon, + + /// internal enumerator + lightBlue, + + /// internal enumerator + lightCoral, + + /// internal enumerator + lightCyan, + + /// internal enumerator + lightGoldenrodYellow, + + /// internal enumerator + lightGray, + + /// internal enumerator + lightGreen, + + /// internal enumerator + lightPink, + + /// internal enumerator + lightSalmon, + + /// internal enumerator + lightSeaGreen, + + /// internal enumerator + lightSkyBlue, + + /// internal enumerator + lightSlateGray, + + /// internal enumerator + lightSteelBlue, + + /// internal enumerator + lightYellow, + + /// internal enumerator + lime, + + /// internal enumerator + limeGreen, + + /// internal enumerator + linen, + + /// internal enumerator + magenta, + + /// internal enumerator + maroon, + + /// internal enumerator + mediumAquamarine, + + /// internal enumerator + mediumBlue, + + /// internal enumerator + mediumOrchid, + + /// internal enumerator + mediumPurple, + + /// internal enumerator + mediumSeaGreen, + + /// internal enumerator + mediumSlateBlue, + + /// internal enumerator + mediumSpringGreen, + + /// internal enumerator + mediumTurquoise, + + /// internal enumerator + mediumVioletRed, + + /// internal enumerator + menu, + + /// internal enumerator + menuBar, + + /// internal enumerator + menuHighlight, + + /// internal enumerator + menuText, + + /// internal enumerator + midnightBlue, + + /// internal enumerator + mintCream, + + /// internal enumerator + mistyRose, + + /// internal enumerator + moccasin, + + /// internal enumerator + navajoWhite, + + /// internal enumerator + navy, + + /// internal enumerator + oldLace, + + /// internal enumerator + olive, + + /// internal enumerator + oliveDrab, + + /// internal enumerator + orange, + + /// internal enumerator + orangeRed, + + /// internal enumerator + orchid, + + /// internal enumerator + paleGoldenrod, + + /// internal enumerator + paleGreen, + + /// internal enumerator + paleTurquoise, + + /// internal enumerator + paleVioletRed, + + /// internal enumerator + papayaWhip, + + /// internal enumerator + peachPuff, + + /// internal enumerator + peru, + + /// internal enumerator + pink, + + /// internal enumerator + plum, + + /// internal enumerator + powderBlue, + + /// internal enumerator + purple, + + /// internal enumerator + red, + + /// internal enumerator + rosyBrown, + + /// internal enumerator + royalBlue, + + /// internal enumerator + saddleBrown, + + /// internal enumerator + salmon, + + /// internal enumerator + sandyBrown, + + /// internal enumerator + scrollBar, + + /// internal enumerator + seaGreen, + + /// internal enumerator + seaShell, + + /// internal enumerator + sienna, + + /// internal enumerator + silver, + + /// internal enumerator + skyBlue, + + /// internal enumerator + slateBlue, + + /// internal enumerator + slateGray, + + /// internal enumerator + snow, + + /// internal enumerator + springGreen, + + /// internal enumerator + steelBlue, + + /// internal enumerator + tan, + + /// internal enumerator + teal, + + /// internal enumerator + thistle, + + /// internal enumerator + tomato, + + /// internal enumerator + transparent, + + /// internal enumerator + turquoise, + + /// internal enumerator + violet, + + /// internal enumerator + wheat, + + /// internal enumerator + white, + + /// internal enumerator + whiteSmoke, + + /// internal enumerator + window, + + /// internal enumerator + windowFrame, + + /// internal enumerator + windowText, + + /// internal enumerator + yellow, + + /// internal enumerator + yellowGreen, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/drawing.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/drawing.dart index 8ff239fa7..ac38222df 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/drawing.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/drawing/drawing.dart @@ -1,150 +1,150 @@ -import 'dart:ui'; - -/// Represents the size values. -class PdfSize { - /// Initializes the [PdfSize] class. - PdfSize(this.width, this.height); - - /// internal constructor - PdfSize.fromSize(Size size) { - width = size.width; - height = size.height; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is PdfSize && width == other.width && height == other.height; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => width.hashCode; - - /// Gets or sets the width value. - late double width; - - /// Gets or sets the height value. - late double height; - - /// Gets the empty size. - static PdfSize get empty => PdfSize(0, 0); - - /// internal property - Size get size => Size(width, height); -} - -/// Represents the point values. -class PdfPoint { - /// Initializes the [PdfPoint] class. - PdfPoint(this.x, this.y); - - /// internal constructor - PdfPoint.fromOffset(Offset location) { - x = location.dx; - y = location.dy; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is PdfPoint && x == other.x && y == other.y; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => x.hashCode; - - /// Gets or sets the x value. - late double x; - - /// Gets or sets the y value. - late double y; - - /// Gets the empty [PdfPoint]. - static PdfPoint get empty => PdfPoint(0, 0); - - /// internal property - Offset get offset => Offset(x, y); -} - -/// Represents the rectangle values. -class PdfRectangle { - /// Intialize the [PdfRectangle] class. - PdfRectangle(this.x, this.y, this.width, this.height); - - /// internal constructor - PdfRectangle.fromRect(Rect rect) { - x = rect.left; - y = rect.top; - width = rect.width; - height = rect.height; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is PdfRectangle && - x == other.x && - y == other.y && - height == other.height && - width == other.width; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => x.hashCode; - - /// Gets or sets the [x] value. - late double x; - - /// Gets or sets the [y] value. - late double y; - - /// Gets or sets the [width] value. - late double width; - - /// Gets or sets the [height] value. - late double height; - - /// Gets the [location]. - PdfPoint get location => PdfPoint(x, y); - - /// Sets the [location]. - set location(PdfPoint value) { - x = value.x; - y = value.y; - } - - /// Gets the [size]. - PdfSize get size => PdfSize(width, height); - - /// Sets the [size]. - set size(PdfSize value) { - width = value.width; - height = value.height; - } - - /// Gets the left. - double get left => x; - - /// Gets the top. - double get top => y; - - /// Gets the right. - double get right => x + width; - - /// Gets the bottom. - double get bottom => y + height; - - /// Gets the empty [PdfRectangle]. - static PdfRectangle get empty => PdfRectangle(0, 0, 0, 0); - - /// internal property - Rect get rect => Rect.fromLTWH(x, y, width, height); - - ///Clones the instance of a rectangle. - PdfRectangle clone() { - return PdfRectangle(x, y, width, height); - } -} +import 'dart:ui'; + +/// Represents the size values. +class PdfSize { + /// Initializes the [PdfSize] class. + PdfSize(this.width, this.height); + + /// internal constructor + PdfSize.fromSize(Size size) { + width = size.width; + height = size.height; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is PdfSize && width == other.width && height == other.height; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => width.hashCode; + + /// Gets or sets the width value. + late double width; + + /// Gets or sets the height value. + late double height; + + /// Gets the empty size. + static PdfSize get empty => PdfSize(0, 0); + + /// internal property + Size get size => Size(width, height); +} + +/// Represents the point values. +class PdfPoint { + /// Initializes the [PdfPoint] class. + PdfPoint(this.x, this.y); + + /// internal constructor + PdfPoint.fromOffset(Offset location) { + x = location.dx; + y = location.dy; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is PdfPoint && x == other.x && y == other.y; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => x.hashCode; + + /// Gets or sets the x value. + late double x; + + /// Gets or sets the y value. + late double y; + + /// Gets the empty [PdfPoint]. + static PdfPoint get empty => PdfPoint(0, 0); + + /// internal property + Offset get offset => Offset(x, y); +} + +/// Represents the rectangle values. +class PdfRectangle { + /// Intialize the [PdfRectangle] class. + PdfRectangle(this.x, this.y, this.width, this.height); + + /// internal constructor + PdfRectangle.fromRect(Rect rect) { + x = rect.left; + y = rect.top; + width = rect.width; + height = rect.height; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is PdfRectangle && + x == other.x && + y == other.y && + height == other.height && + width == other.width; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => x.hashCode; + + /// Gets or sets the [x] value. + late double x; + + /// Gets or sets the [y] value. + late double y; + + /// Gets or sets the [width] value. + late double width; + + /// Gets or sets the [height] value. + late double height; + + /// Gets the [location]. + PdfPoint get location => PdfPoint(x, y); + + /// Sets the [location]. + set location(PdfPoint value) { + x = value.x; + y = value.y; + } + + /// Gets the [size]. + PdfSize get size => PdfSize(width, height); + + /// Sets the [size]. + set size(PdfSize value) { + width = value.width; + height = value.height; + } + + /// Gets the left. + double get left => x; + + /// Gets the top. + double get top => y; + + /// Gets the right. + double get right => x + width; + + /// Gets the bottom. + double get bottom => y + height; + + /// Gets the empty [PdfRectangle]. + static PdfRectangle get empty => PdfRectangle(0, 0, 0, 0); + + /// internal property + Rect get rect => Rect.fromLTWH(x, y, width, height); + + ///Clones the instance of a rectangle. + PdfRectangle clone() { + return PdfRectangle(x, y, width, height); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/enums.dart index ca9af76f0..bd23abcb3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/enums.dart @@ -1,11 +1,11 @@ -/// Defines the constants that specify the option for text search. -enum TextSearchOption { - /// Searches whole words only but not case sensitive. - wholeWords, - - /// Searches words with case sensitive. - caseSensitive, - - /// Searches words with both the case sensitive and whole word. - both, -} +/// Defines the constants that specify the option for text search. +enum TextSearchOption { + /// Searches whole words only but not case sensitive. + wholeWords, + + /// Searches words with case sensitive. + caseSensitive, + + /// Searches words with both the case sensitive and whole word. + both, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_file2.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_file2.dart index 2bfdd0086..e6b08bcb1 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_file2.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_file2.dart @@ -1,4267 +1,4267 @@ -// ignore_for_file: text_direction_code_point_in_literal -/// internal constructor -class AdobeGlyphList { - // Constructor - /// internal class - AdobeGlyphList() { - initialize(); - } - - // Fields - /// internal field - Map? map; - - // Implementations - /// internal method - void initialize() { - map = {}; - map!['A'] = 'A'; - map!['AE'] = 'Æ'; - map!['AEacute'] = 'Ǽ'; - map!['AEmacron'] = 'Ǣ'; - map!['AEsmall'] = ''; - map!['Aacute'] = 'Á'; - map!['Aacutesmall'] = ''; - map!['Abreve'] = 'Ă'; - map!['Abreveacute'] = 'Ắ'; - map!['Abrevecyrillic'] = 'Ӑ'; - map!['Abrevedotbelow'] = 'Ặ'; - map!['Abrevegrave'] = 'Ằ'; - map!['Abrevehookabove'] = 'Ẳ'; - map!['Abrevetilde'] = 'Ẵ'; - map!['Acaron'] = 'Ǎ'; - map!['Acircle'] = 'Ⓐ'; - map!['Acircumflex'] = 'Â'; - map!['Acircumflexacute'] = 'Ấ'; - map!['Acircumflexdotbelow'] = 'Ậ'; - map!['Acircumflexgrave'] = 'Ầ'; - map!['Acircumflexhookabove'] = 'Ẩ'; - map!['Acircumflexsmall'] = ''; - map!['Acircumflextilde'] = 'Ẫ'; - map!['Acute'] = ''; - map!['Acutesmall'] = ''; - map!['Acyrillic'] = 'А'; - map!['Adblgrave'] = 'Ȁ'; - map!['Adieresis'] = 'Ä'; - map!['Adieresiscyrillic'] = 'Ӓ'; - map!['Adieresismacron'] = 'Ǟ'; - map!['Adieresissmall'] = ''; - map!['Adotbelow'] = 'Ạ'; - map!['Adotmacron'] = 'Ǡ'; - map!['Agrave'] = 'À'; - map!['Agravesmall'] = ''; - map!['Ahookabove'] = 'Ả'; - map!['Aiecyrillic'] = 'Ӕ'; - map!['Ainvertedbreve'] = 'Ȃ'; - map!['Alpha'] = 'Α'; - map!['Alphatonos'] = 'Ά'; - map!['Amacron'] = 'Ā'; - map!['Amonospace'] = 'A'; - map!['Aogonek'] = 'Ą'; - map!['Aring'] = 'Å'; - map!['Aringacute'] = 'Ǻ'; - map!['Aringbelow'] = 'Ḁ'; - map!['Aringsmall'] = ''; - map!['Asmall'] = ''; - map!['Atilde'] = 'Ã'; - map!['Atildesmall'] = ''; - map!['Aybarmenian'] = 'Ա'; - map!['B'] = 'B'; - map!['Bcircle'] = 'Ⓑ'; - map!['Bdotaccent'] = 'Ḃ'; - map!['Bdotbelow'] = 'Ḅ'; - map!['Becyrillic'] = 'Б'; - map!['Benarmenian'] = 'Բ'; - map!['Beta'] = 'Β'; - map!['Bhook'] = 'Ɓ'; - map!['Blinebelow'] = 'Ḇ'; - map!['Bmonospace'] = 'B'; - map!['Brevesmall'] = ''; - map!['Bsmall'] = ''; - map!['Btopbar'] = 'Ƃ'; - map!['C'] = 'C'; - map!['Caarmenian'] = 'Ծ'; - map!['Cacute'] = 'Ć'; - map!['Caron'] = ''; - map!['Caronsmall'] = ''; - map!['Ccaron'] = 'Č'; - map!['Ccedilla'] = 'Ç'; - map!['Ccedillaacute'] = 'Ḉ'; - map!['Ccedillasmall'] = ''; - map!['Ccircle'] = 'Ⓒ'; - map!['Ccircumflex'] = 'Ĉ'; - map!['Cdot'] = 'Ċ'; - map!['Cdotaccent'] = 'Ċ'; - map!['Cedillasmall'] = ''; - map!['Chaarmenian'] = 'Չ'; - map!['Cheabkhasiancyrillic'] = 'Ҽ'; - map!['Checyrillic'] = 'Ч'; - map!['Chedescenderabkhasiancyrillic'] = 'Ҿ'; - map!['Chedescendercyrillic'] = 'Ҷ'; - map!['Chedieresiscyrillic'] = 'Ӵ'; - map!['Cheharmenian'] = 'Ճ'; - map!['Chekhakassiancyrillic'] = 'Ӌ'; - map!['Cheverticalstrokecyrillic'] = 'Ҹ'; - map!['Chi'] = 'Χ'; - map!['Chook'] = 'Ƈ'; - map!['Circumflexsmall'] = ''; - map!['Cmonospace'] = 'C'; - map!['Coarmenian'] = 'Ց'; - map!['Csmall'] = ''; - map!['D'] = 'D'; - map!['DZ'] = 'DZ'; - map!['DZcaron'] = 'DŽ'; - map!['Daarmenian'] = 'Դ'; - map!['Dafrican'] = 'Ɖ'; - map!['Dcaron'] = 'Ď'; - map!['Dcedilla'] = 'Ḑ'; - map!['Dcircle'] = 'Ⓓ'; - map!['Dcircumflexbelow'] = 'Ḓ'; - map!['Dcroat'] = 'Đ'; - map!['Ddotaccent'] = 'Ḋ'; - map!['Ddotbelow'] = 'Ḍ'; - map!['Decyrillic'] = 'Д'; - map!['Deicoptic'] = 'Ϯ'; - map!['Delta'] = '∆'; - map!['Deltagreek'] = 'Δ'; - map!['Dhook'] = 'Ɗ'; - map!['Dieresis'] = ''; - map!['DieresisAcute'] = ''; - map!['DieresisGrave'] = ''; - map!['Dieresissmall'] = ''; - map!['Digammagreek'] = 'Ϝ'; - map!['Djecyrillic'] = 'Ђ'; - map!['Dlinebelow'] = 'Ḏ'; - map!['Dmonospace'] = 'D'; - map!['Dotaccentsmall'] = ''; - map!['Dslash'] = 'Đ'; - map!['Dsmall'] = ''; - map!['Dtopbar'] = 'Ƌ'; - map!['Dz'] = 'Dz'; - map!['Dzcaron'] = 'Dž'; - map!['Dzeabkhasiancyrillic'] = 'Ӡ'; - map!['Dzecyrillic'] = 'Ѕ'; - map!['Dzhecyrillic'] = 'Џ'; - map!['E'] = 'E'; - map!['Eacute'] = 'É'; - map!['Eacutesmall'] = ''; - map!['Ebreve'] = 'Ĕ'; - map!['Ecaron'] = 'Ě'; - map!['Ecedillabreve'] = 'Ḝ'; - map!['Echarmenian'] = 'Ե'; - map!['Ecircle'] = 'Ⓔ'; - map!['Ecircumflex'] = 'Ê'; - map!['Ecircumflexacute'] = 'Ế'; - map!['Ecircumflexbelow'] = 'Ḙ'; - map!['Ecircumflexdotbelow'] = 'Ệ'; - map!['Ecircumflexgrave'] = 'Ề'; - map!['Ecircumflexhookabove'] = 'Ể'; - map!['Ecircumflexsmall'] = ''; - map!['Ecircumflextilde'] = 'Ễ'; - map!['Ecyrillic'] = 'Є'; - map!['Edblgrave'] = 'Ȅ'; - map!['Edieresis'] = 'Ë'; - map!['Edieresissmall'] = ''; - map!['Edot'] = 'Ė'; - map!['Edotaccent'] = 'Ė'; - map!['Edotbelow'] = 'Ẹ'; - map!['Efcyrillic'] = 'Ф'; - map!['Egrave'] = 'È'; - map!['Egravesmall'] = ''; - map!['Eharmenian'] = 'Է'; - map!['Ehookabove'] = 'Ẻ'; - map!['Eightroman'] = 'Ⅷ'; - map!['Einvertedbreve'] = 'Ȇ'; - map!['Eiotifiedcyrillic'] = 'Ѥ'; - map!['Elcyrillic'] = 'Л'; - map!['Elevenroman'] = 'Ⅺ'; - map!['Emacron'] = 'Ē'; - map!['Emacronacute'] = 'Ḗ'; - map!['Emacrongrave'] = 'Ḕ'; - map!['Emcyrillic'] = 'М'; - map!['Emonospace'] = 'E'; - map!['Encyrillic'] = 'Н'; - map!['Endescendercyrillic'] = 'Ң'; - map!['Eng'] = 'Ŋ'; - map!['Enghecyrillic'] = 'Ҥ'; - map!['Enhookcyrillic'] = 'Ӈ'; - map!['Eogonek'] = 'Ę'; - map!['Eopen'] = 'Ɛ'; - map!['Epsilon'] = 'Ε'; - map!['Epsilontonos'] = 'Έ'; - map!['Ercyrillic'] = 'Р'; - map!['Ereversed'] = 'Ǝ'; - map!['Ereversedcyrillic'] = 'Э'; - map!['Escyrillic'] = 'С'; - map!['Esdescendercyrillic'] = 'Ҫ'; - map!['Esh'] = 'Ʃ'; - map!['Esmall'] = ''; - map!['Eta'] = 'Η'; - map!['Etarmenian'] = 'Ը'; - map!['Etatonos'] = 'Ή'; - map!['Eth'] = 'Ð'; - map!['Ethsmall'] = ''; - map!['Etilde'] = 'Ẽ'; - map!['Etildebelow'] = 'Ḛ'; - map!['Euro'] = '€'; - map!['Ezh'] = 'Ʒ'; - map!['Ezhcaron'] = 'Ǯ'; - map!['Ezhreversed'] = 'Ƹ'; - map!['F'] = 'F'; - map!['Fcircle'] = 'Ⓕ'; - map!['Fdotaccent'] = 'Ḟ'; - map!['Feharmenian'] = 'Ֆ'; - map!['Feicoptic'] = 'Ϥ'; - map!['Fhook'] = 'Ƒ'; - map!['Fitacyrillic'] = 'Ѳ'; - map!['Fiveroman'] = 'Ⅴ'; - map!['Fmonospace'] = 'F'; - map!['Fourroman'] = 'Ⅳ'; - map!['Fsmall'] = ''; - map!['G'] = 'G'; - map!['GBsquare'] = '㎇'; - map!['Gacute'] = 'Ǵ'; - map!['Gamma'] = 'Γ'; - map!['Gammaafrican'] = 'Ɣ'; - map!['Gangiacoptic'] = 'Ϫ'; - map!['Gbreve'] = 'Ğ'; - map!['Gcaron'] = 'Ǧ'; - map!['Gcedilla'] = 'Ģ'; - map!['Gcircle'] = 'Ⓖ'; - map!['Gcircumflex'] = 'Ĝ'; - map!['Gcommaaccent'] = 'Ģ'; - map!['Gdot'] = 'Ġ'; - map!['Gdotaccent'] = 'Ġ'; - map!['Gecyrillic'] = 'Г'; - map!['Ghadarmenian'] = 'Ղ'; - map!['Ghemiddlehookcyrillic'] = 'Ҕ'; - map!['Ghestrokecyrillic'] = 'Ғ'; - map!['Gheupturncyrillic'] = 'Ґ'; - map!['Ghook'] = 'Ɠ'; - map!['Gimarmenian'] = 'Գ'; - map!['Gjecyrillic'] = 'Ѓ'; - map!['Gmacron'] = 'Ḡ'; - map!['Gmonospace'] = 'G'; - map!['Grave'] = ''; - map!['Gravesmall'] = ''; - map!['Gsmall'] = ''; - map!['Gsmallhook'] = 'ʛ'; - map!['Gstroke'] = 'Ǥ'; - map!['H'] = 'H'; - map!['H18533'] = '●'; - map!['H18543'] = '▪'; - map!['H18551'] = '▫'; - map!['H22073'] = '□'; - map!['HPsquare'] = '㏋'; - map!['Haabkhasiancyrillic'] = 'Ҩ'; - map!['Hadescendercyrillic'] = 'Ҳ'; - map!['Hardsigncyrillic'] = 'Ъ'; - map!['Hbar'] = 'Ħ'; - map!['Hbrevebelow'] = 'Ḫ'; - map!['Hcedilla'] = 'Ḩ'; - map!['Hcircle'] = 'Ⓗ'; - map!['Hcircumflex'] = 'Ĥ'; - map!['Hdieresis'] = 'Ḧ'; - map!['Hdotaccent'] = 'Ḣ'; - map!['Hdotbelow'] = 'Ḥ'; - map!['Hmonospace'] = 'H'; - map!['Hoarmenian'] = 'Հ'; - map!['Horicoptic'] = 'Ϩ'; - map!['Hsmall'] = ''; - map!['Hungarumlaut'] = ''; - map!['Hungarumlautsmall'] = ''; - map!['Hzsquare'] = '㎐'; - map!['I'] = 'I'; - map!['IAcyrillic'] = 'Я'; - map!['IJ'] = 'IJ'; - map!['IUcyrillic'] = 'Ю'; - map!['Iacute'] = 'Í'; - map!['Iacutesmall'] = ''; - map!['Ibreve'] = 'Ĭ'; - map!['Icaron'] = 'Ǐ'; - map!['Icircle'] = 'Ⓘ'; - map!['Icircumflex'] = 'Î'; - map!['Icircumflexsmall'] = ''; - map!['Icyrillic'] = 'І'; - map!['Idblgrave'] = 'Ȉ'; - map!['Idieresis'] = 'Ï'; - map!['Idieresisacute'] = 'Ḯ'; - map!['Idieresiscyrillic'] = 'Ӥ'; - map!['Idieresissmall'] = ''; - map!['Idot'] = 'İ'; - map!['Idotaccent'] = 'İ'; - map!['Idotbelow'] = 'Ị'; - map!['Iebrevecyrillic'] = 'Ӗ'; - map!['Iecyrillic'] = 'Е'; - map!['Ifraktur'] = 'ℑ'; - map!['Igrave'] = 'Ì'; - map!['Igravesmall'] = ''; - map!['Ihookabove'] = 'Ỉ'; - map!['Iicyrillic'] = 'И'; - map!['Iinvertedbreve'] = 'Ȋ'; - map!['Iishortcyrillic'] = 'Й'; - map!['Imacron'] = 'Ī'; - map!['Imacroncyrillic'] = 'Ӣ'; - map!['Imonospace'] = 'I'; - map!['Iniarmenian'] = 'Ի'; - map!['Iocyrillic'] = 'Ё'; - map!['Iogonek'] = 'Į'; - map!['Iota'] = 'Ι'; - map!['Iotaafrican'] = 'Ɩ'; - map!['Iotadieresis'] = 'Ϊ'; - map!['Iotatonos'] = 'Ί'; - map!['Ismall'] = ''; - map!['Istroke'] = 'Ɨ'; - map!['Itilde'] = 'Ĩ'; - map!['Itildebelow'] = 'Ḭ'; - map!['Izhitsacyrillic'] = 'Ѵ'; - map!['Izhitsadblgravecyrillic'] = 'Ѷ'; - map!['J'] = 'J'; - map!['Jaarmenian'] = 'Ձ'; - map!['Jcircle'] = 'Ⓙ'; - map!['Jcircumflex'] = 'Ĵ'; - map!['Jecyrillic'] = 'Ј'; - map!['Jheharmenian'] = 'Ջ'; - map!['Jmonospace'] = 'J'; - map!['Jsmall'] = ''; - map!['K'] = 'K'; - map!['KBsquare'] = '㎅'; - map!['KKsquare'] = '㏍'; - map!['Kabashkircyrillic'] = 'Ҡ'; - map!['Kacute'] = 'Ḱ'; - map!['Kacyrillic'] = 'К'; - map!['Kadescendercyrillic'] = 'Қ'; - map!['Kahookcyrillic'] = 'Ӄ'; - map!['Kappa'] = 'Κ'; - map!['Kastrokecyrillic'] = 'Ҟ'; - map!['Kaverticalstrokecyrillic'] = 'Ҝ'; - map!['Kcaron'] = 'Ǩ'; - map!['Kcedilla'] = 'Ķ'; - map!['Kcircle'] = 'Ⓚ'; - map!['Kcommaaccent'] = 'Ķ'; - map!['Kdotbelow'] = 'Ḳ'; - map!['Keharmenian'] = 'Ք'; - map!['Kenarmenian'] = 'Կ'; - map!['Khacyrillic'] = 'Х'; - map!['Kheicoptic'] = 'Ϧ'; - map!['Khook'] = 'Ƙ'; - map!['Kjecyrillic'] = 'Ќ'; - map!['Klinebelow'] = 'Ḵ'; - map!['Kmonospace'] = 'K'; - map!['Koppacyrillic'] = 'Ҁ'; - map!['Koppagreek'] = 'Ϟ'; - map!['Ksicyrillic'] = 'Ѯ'; - map!['Ksmall'] = ''; - map!['L'] = 'L'; - map!['LJ'] = 'LJ'; - map!['LL'] = ''; - map!['Lacute'] = 'Ĺ'; - map!['Lambda'] = 'Λ'; - map!['Lcaron'] = 'Ľ'; - map!['Lcedilla'] = 'Ļ'; - map!['Lcircle'] = 'Ⓛ'; - map!['Lcircumflexbelow'] = 'Ḽ'; - map!['Lcommaaccent'] = 'Ļ'; - map!['Ldot'] = 'Ŀ'; - map!['Ldotaccent'] = 'Ŀ'; - map!['Ldotbelow'] = 'Ḷ'; - map!['Ldotbelowmacron'] = 'Ḹ'; - map!['Liwnarmenian'] = 'Լ'; - map!['Lj'] = 'Lj'; - map!['Ljecyrillic'] = 'Љ'; - map!['Llinebelow'] = 'Ḻ'; - map!['Lmonospace'] = 'L'; - map!['Lslash'] = 'Ł'; - map!['Lslashsmall'] = ''; - map!['Lsmall'] = ''; - map!['M'] = 'M'; - map!['MBsquare'] = '㎆'; - map!['Macron'] = ''; - map!['Macronsmall'] = ''; - map!['Macute'] = 'Ḿ'; - map!['Mcircle'] = 'Ⓜ'; - map!['Mdotaccent'] = 'Ṁ'; - map!['Mdotbelow'] = 'Ṃ'; - map!['Menarmenian'] = 'Մ'; - map!['Mmonospace'] = 'M'; - map!['Msmall'] = ''; - map!['Mturned'] = 'Ɯ'; - map!['Mu'] = 'Μ'; - map!['N'] = 'N'; - map!['NJ'] = 'NJ'; - map!['Nacute'] = 'Ń'; - map!['Ncaron'] = 'Ň'; - map!['Ncedilla'] = 'Ņ'; - map!['Ncircle'] = 'Ⓝ'; - map!['Ncircumflexbelow'] = 'Ṋ'; - map!['Ncommaaccent'] = 'Ņ'; - map!['Ndotaccent'] = 'Ṅ'; - map!['Ndotbelow'] = 'Ṇ'; - map!['Nhookleft'] = 'Ɲ'; - map!['Nineroman'] = 'Ⅸ'; - map!['Nj'] = 'Nj'; - map!['Njecyrillic'] = 'Њ'; - map!['Nlinebelow'] = 'Ṉ'; - map!['Nmonospace'] = 'N'; - map!['Nowarmenian'] = 'Ն'; - map!['Nsmall'] = ''; - map!['Ntilde'] = 'Ñ'; - map!['Ntildesmall'] = ''; - map!['Nu'] = 'Ν'; - map!['O'] = 'O'; - map!['OE'] = 'Œ'; - map!['OEsmall'] = ''; - map!['Oacute'] = 'Ó'; - map!['Oacutesmall'] = ''; - map!['Obarredcyrillic'] = 'Ө'; - map!['Obarreddieresiscyrillic'] = 'Ӫ'; - map!['Obreve'] = 'Ŏ'; - map!['Ocaron'] = 'Ǒ'; - map!['Ocenteredtilde'] = 'Ɵ'; - map!['Ocircle'] = 'Ⓞ'; - map!['Ocircumflex'] = 'Ô'; - map!['Ocircumflexacute'] = 'Ố'; - map!['Ocircumflexdotbelow'] = 'Ộ'; - map!['Ocircumflexgrave'] = 'Ồ'; - map!['Ocircumflexhookabove'] = 'Ổ'; - map!['Ocircumflexsmall'] = ''; - map!['Ocircumflextilde'] = 'Ỗ'; - map!['Ocyrillic'] = 'О'; - map!['Odblacute'] = 'Ő'; - map!['Odblgrave'] = 'Ȍ'; - map!['Odieresis'] = 'Ö'; - map!['Odieresiscyrillic'] = 'Ӧ'; - map!['Odieresissmall'] = ''; - map!['Odotbelow'] = 'Ọ'; - map!['Ogoneksmall'] = ''; - map!['Ograve'] = 'Ò'; - map!['Ogravesmall'] = ''; - map!['Oharmenian'] = 'Օ'; - map!['Ohm'] = 'Ω'; - map!['Ohookabove'] = 'Ỏ'; - map!['Ohorn'] = 'Ơ'; - map!['Ohornacute'] = 'Ớ'; - map!['Ohorndotbelow'] = 'Ợ'; - map!['Ohorngrave'] = 'Ờ'; - map!['Ohornhookabove'] = 'Ở'; - map!['Ohorntilde'] = 'Ỡ'; - map!['Ohungarumlaut'] = 'Ő'; - map!['Oi'] = 'Ƣ'; - map!['Oinvertedbreve'] = 'Ȏ'; - map!['Omacron'] = 'Ō'; - map!['Omacronacute'] = 'Ṓ'; - map!['Omacrongrave'] = 'Ṑ'; - map!['Omega'] = 'Ω'; - map!['Omegacyrillic'] = 'Ѡ'; - map!['Omegagreek'] = 'Ω'; - map!['Omegaroundcyrillic'] = 'Ѻ'; - map!['Omegatitlocyrillic'] = 'Ѽ'; - map!['Omegatonos'] = 'Ώ'; - map!['Omicron'] = 'Ο'; - map!['Omicrontonos'] = 'Ό'; - map!['Omonospace'] = 'O'; - map!['Oneroman'] = 'Ⅰ'; - map!['Oogonek'] = 'Ǫ'; - map!['Oogonekmacron'] = 'Ǭ'; - map!['Oopen'] = 'Ɔ'; - map!['Oslash'] = 'Ø'; - map!['Oslashacute'] = 'Ǿ'; - map!['Oslashsmall'] = ''; - map!['Osmall'] = ''; - map!['Ostrokeacute'] = 'Ǿ'; - map!['Otcyrillic'] = 'Ѿ'; - map!['Otilde'] = 'Õ'; - map!['Otildeacute'] = 'Ṍ'; - map!['Otildedieresis'] = 'Ṏ'; - map!['Otildesmall'] = ''; - map!['P'] = 'P'; - map!['Pacute'] = 'Ṕ'; - map!['Pcircle'] = 'Ⓟ'; - map!['Pdotaccent'] = 'Ṗ'; - map!['Pecyrillic'] = 'П'; - map!['Peharmenian'] = 'Պ'; - map!['Pemiddlehookcyrillic'] = 'Ҧ'; - map!['Phi'] = 'Φ'; - map!['Phook'] = 'Ƥ'; - map!['Pi'] = 'Π'; - map!['Piwrarmenian'] = 'Փ'; - map!['Pmonospace'] = 'P'; - map!['Psi'] = 'Ψ'; - map!['Psicyrillic'] = 'Ѱ'; - map!['Psmall'] = ''; - map!['Q'] = 'Q'; - map!['Qcircle'] = 'Ⓠ'; - map!['Qmonospace'] = 'Q'; - map!['Qsmall'] = ''; - map!['R'] = 'R'; - map!['Raarmenian'] = 'Ռ'; - map!['Racute'] = 'Ŕ'; - map!['Rcaron'] = 'Ř'; - map!['Rcedilla'] = 'Ŗ'; - map!['Rcircle'] = 'Ⓡ'; - map!['Rcommaaccent'] = 'Ŗ'; - map!['Rdblgrave'] = 'Ȑ'; - map!['Rdotaccent'] = 'Ṙ'; - map!['Rdotbelow'] = 'Ṛ'; - map!['Rdotbelowmacron'] = 'Ṝ'; - map!['Reharmenian'] = 'Ր'; - map!['Rfraktur'] = 'ℜ'; - map!['Rho'] = 'Ρ'; - map!['Ringsmall'] = ''; - map!['Rinvertedbreve'] = 'Ȓ'; - map!['Rlinebelow'] = 'Ṟ'; - map!['Rmonospace'] = 'R'; - map!['Rsmall'] = ''; - map!['Rsmallinverted'] = 'ʁ'; - map!['Rsmallinvertedsuperior'] = 'ʶ'; - map!['S'] = 'S'; - map!['SF010000'] = '┌'; - map!['SF020000'] = '└'; - map!['SF030000'] = '┐'; - map!['SF040000'] = '┘'; - map!['SF050000'] = '┼'; - map!['SF060000'] = '┬'; - map!['SF070000'] = '┴'; - map!['SF080000'] = '├'; - map!['SF090000'] = '┤'; - map!['SF100000'] = '─'; - map!['SF110000'] = '│'; - map!['SF190000'] = '╡'; - map!['SF200000'] = '╢'; - map!['SF210000'] = '╖'; - map!['SF220000'] = '╕'; - map!['SF230000'] = '╣'; - map!['SF240000'] = '║'; - map!['SF250000'] = '╗'; - map!['SF260000'] = '╝'; - map!['SF270000'] = '╜'; - map!['SF280000'] = '╛'; - map!['SF360000'] = '╞'; - map!['SF370000'] = '╟'; - map!['SF380000'] = '╚'; - map!['SF390000'] = '╔'; - map!['SF400000'] = '╩'; - map!['SF410000'] = '╦'; - map!['SF420000'] = '╠'; - map!['SF430000'] = '═'; - map!['SF440000'] = '╬'; - map!['SF450000'] = '╧'; - map!['SF460000'] = '╨'; - map!['SF470000'] = '╤'; - map!['SF480000'] = '╥'; - map!['SF490000'] = '╙'; - map!['SF500000'] = '╘'; - map!['SF510000'] = '╒'; - map!['SF520000'] = '╓'; - map!['SF530000'] = '╫'; - map!['SF540000'] = '╪'; - map!['Sacute'] = 'Ś'; - map!['Sacutedotaccent'] = 'Ṥ'; - map!['Sampigreek'] = 'Ϡ'; - map!['Scaron'] = 'Š'; - map!['Scarondotaccent'] = 'Ṧ'; - map!['Scaronsmall'] = ''; - map!['Scedilla'] = 'Ş'; - map!['Schwa'] = 'Ə'; - map!['Schwacyrillic'] = 'Ә'; - map!['Schwadieresiscyrillic'] = 'Ӛ'; - map!['Scircle'] = 'Ⓢ'; - map!['Scircumflex'] = 'Ŝ'; - map!['Scommaaccent'] = 'Ș'; - map!['Sdotaccent'] = 'Ṡ'; - map!['Sdotbelow'] = 'Ṣ'; - map!['Sdotbelowdotaccent'] = 'Ṩ'; - map!['Seharmenian'] = 'Ս'; - map!['Sevenroman'] = 'Ⅶ'; - map!['Shaarmenian'] = 'Շ'; - map!['Shacyrillic'] = 'Ш'; - map!['Shchacyrillic'] = 'Щ'; - map!['Sheicoptic'] = 'Ϣ'; - map!['Shhacyrillic'] = 'Һ'; - map!['Shimacoptic'] = 'Ϭ'; - map!['Sigma'] = 'Σ'; - map!['Sixroman'] = 'Ⅵ'; - map!['Smonospace'] = 'S'; - map!['Softsigncyrillic'] = 'Ь'; - map!['Ssmall'] = ''; - map!['Stigmagreek'] = 'Ϛ'; - map!['T'] = 'T'; - map!['Tau'] = 'Τ'; - map!['Tbar'] = 'Ŧ'; - map!['Tcaron'] = 'Ť'; - map!['Tcedilla'] = 'Ţ'; - map!['Tcircle'] = 'Ⓣ'; - map!['Tcircumflexbelow'] = 'Ṱ'; - map!['Tcommaaccent'] = 'Ţ'; - map!['Tdotaccent'] = 'Ṫ'; - map!['Tdotbelow'] = 'Ṭ'; - map!['Tecyrillic'] = 'Т'; - map!['Tedescendercyrillic'] = 'Ҭ'; - map!['Tenroman'] = 'Ⅹ'; - map!['Tetsecyrillic'] = 'Ҵ'; - map!['Theta'] = 'Θ'; - map!['Thook'] = 'Ƭ'; - map!['Thorn'] = 'Þ'; - map!['Thornsmall'] = ''; - map!['Threeroman'] = 'Ⅲ'; - map!['Tildesmall'] = ''; - map!['Tiwnarmenian'] = 'Տ'; - map!['Tlinebelow'] = 'Ṯ'; - map!['Tmonospace'] = 'T'; - map!['Toarmenian'] = 'Թ'; - map!['Tonefive'] = 'Ƽ'; - map!['Tonesix'] = 'Ƅ'; - map!['Tonetwo'] = 'Ƨ'; - map!['Tretroflexhook'] = 'Ʈ'; - map!['Tsecyrillic'] = 'Ц'; - map!['Tshecyrillic'] = 'Ћ'; - map!['Tsmall'] = ''; - map!['Twelveroman'] = 'Ⅻ'; - map!['Tworoman'] = 'Ⅱ'; - map!['U'] = 'U'; - map!['Uacute'] = 'Ú'; - map!['Uacutesmall'] = ''; - map!['Ubreve'] = 'Ŭ'; - map!['Ucaron'] = 'Ǔ'; - map!['Ucircle'] = 'Ⓤ'; - map!['Ucircumflex'] = 'Û'; - map!['Ucircumflexbelow'] = 'Ṷ'; - map!['Ucircumflexsmall'] = ''; - map!['Ucyrillic'] = 'У'; - map!['Udblacute'] = 'Ű'; - map!['Udblgrave'] = 'Ȕ'; - map!['Udieresis'] = 'Ü'; - map!['Udieresisacute'] = 'Ǘ'; - map!['Udieresisbelow'] = 'Ṳ'; - map!['Udieresiscaron'] = 'Ǚ'; - map!['Udieresiscyrillic'] = 'Ӱ'; - map!['Udieresisgrave'] = 'Ǜ'; - map!['Udieresismacron'] = 'Ǖ'; - map!['Udieresissmall'] = ''; - map!['Udotbelow'] = 'Ụ'; - map!['Ugrave'] = 'Ù'; - map!['Ugravesmall'] = ''; - map!['Uhookabove'] = 'Ủ'; - map!['Uhorn'] = 'Ư'; - map!['Uhornacute'] = 'Ứ'; - map!['Uhorndotbelow'] = 'Ự'; - map!['Uhorngrave'] = 'Ừ'; - map!['Uhornhookabove'] = 'Ử'; - map!['Uhorntilde'] = 'Ữ'; - map!['Uhungarumlaut'] = 'Ű'; - map!['Uhungarumlautcyrillic'] = 'Ӳ'; - map!['Uinvertedbreve'] = 'Ȗ'; - map!['Ukcyrillic'] = 'Ѹ'; - map!['Umacron'] = 'Ū'; - map!['Umacroncyrillic'] = 'Ӯ'; - map!['Umacrondieresis'] = 'Ṻ'; - map!['Umonospace'] = 'U'; - map!['Uogonek'] = 'Ų'; - map!['Upsilon'] = 'Υ'; - map!['Upsilon1'] = 'ϒ'; - map!['Upsilonacutehooksymbolgreek'] = 'ϓ'; - map!['Upsilonafrican'] = 'Ʊ'; - map!['Upsilondieresis'] = 'Ϋ'; - map!['Upsilondieresishooksymbolgreek'] = 'ϔ'; - map!['Upsilonhooksymbol'] = 'ϒ'; - map!['Upsilontonos'] = 'Ύ'; - map!['Uring'] = 'Ů'; - map!['Ushortcyrillic'] = 'Ў'; - map!['Usmall'] = ''; - map!['Ustraightcyrillic'] = 'Ү'; - map!['Ustraightstrokecyrillic'] = 'Ұ'; - map!['Utilde'] = 'Ũ'; - map!['Utildeacute'] = 'Ṹ'; - map!['Utildebelow'] = 'Ṵ'; - map!['V'] = 'V'; - map!['Vcircle'] = 'Ⓥ'; - map!['Vdotbelow'] = 'Ṿ'; - map!['Vecyrillic'] = 'В'; - map!['Vewarmenian'] = 'Վ'; - map!['Vhook'] = 'Ʋ'; - map!['Vmonospace'] = 'V'; - map!['Voarmenian'] = 'Ո'; - map!['Vsmall'] = ''; - map!['Vtilde'] = 'Ṽ'; - map!['W'] = 'W'; - map!['Wacute'] = 'Ẃ'; - map!['Wcircle'] = 'Ⓦ'; - map!['Wcircumflex'] = 'Ŵ'; - map!['Wdieresis'] = 'Ẅ'; - map!['Wdotaccent'] = 'Ẇ'; - map!['Wdotbelow'] = 'Ẉ'; - map!['Wgrave'] = 'Ẁ'; - map!['Wmonospace'] = 'W'; - map!['Wsmall'] = ''; - map!['X'] = 'X'; - map!['Xcircle'] = 'Ⓧ'; - map!['Xdieresis'] = 'Ẍ'; - map!['Xdotaccent'] = 'Ẋ'; - map!['Xeharmenian'] = 'Խ'; - map!['Xi'] = 'Ξ'; - map!['Xmonospace'] = 'X'; - map!['Xsmall'] = ''; - map!['Y'] = 'Y'; - map!['Yacute'] = 'Ý'; - map!['Yacutesmall'] = ''; - map!['Yatcyrillic'] = 'Ѣ'; - map!['Ycircle'] = 'Ⓨ'; - map!['Ycircumflex'] = 'Ŷ'; - map!['Ydieresis'] = 'Ÿ'; - map!['Ydieresissmall'] = ''; - map!['Ydotaccent'] = 'Ẏ'; - map!['Ydotbelow'] = 'Ỵ'; - map!['Yericyrillic'] = 'Ы'; - map!['Yerudieresiscyrillic'] = 'Ӹ'; - map!['Ygrave'] = 'Ỳ'; - map!['Yhook'] = 'Ƴ'; - map!['Yhookabove'] = 'Ỷ'; - map!['Yiarmenian'] = 'Յ'; - map!['Yicyrillic'] = 'Ї'; - map!['Yiwnarmenian'] = 'Ւ'; - map!['Ymonospace'] = 'Y'; - map!['Ysmall'] = ''; - map!['Ytilde'] = 'Ỹ'; - map!['Yusbigcyrillic'] = 'Ѫ'; - map!['Yusbigiotifiedcyrillic'] = 'Ѭ'; - map!['Yuslittlecyrillic'] = 'Ѧ'; - map!['Yuslittleiotifiedcyrillic'] = 'Ѩ'; - map!['Z'] = 'Z'; - map!['Zaarmenian'] = 'Զ'; - map!['Zacute'] = 'Ź'; - map!['Zcaron'] = 'Ž'; - map!['Zcaronsmall'] = ''; - map!['Zcircle'] = 'Ⓩ'; - map!['Zcircumflex'] = 'Ẑ'; - map!['Zdot'] = 'Ż'; - map!['Zdotaccent'] = 'Ż'; - map!['Zdotbelow'] = 'Ẓ'; - map!['Zecyrillic'] = 'З'; - map!['Zedescendercyrillic'] = 'Ҙ'; - map!['Zedieresiscyrillic'] = 'Ӟ'; - map!['Zeta'] = 'Ζ'; - map!['Zhearmenian'] = 'Ժ'; - map!['Zhebrevecyrillic'] = 'Ӂ'; - map!['Zhecyrillic'] = 'Ж'; - map!['Zhedescendercyrillic'] = 'Җ'; - map!['Zhedieresiscyrillic'] = 'Ӝ'; - map!['Zlinebelow'] = 'Ẕ'; - map!['Zmonospace'] = 'Z'; - map!['Zsmall'] = ''; - map!['Zstroke'] = 'Ƶ'; - map!['a'] = 'a'; - map!['aabengali'] = 'আ'; - map!['aacute'] = 'á'; - map!['aadeva'] = 'आ'; - map!['aagujarati'] = 'આ'; - map!['aagurmukhi'] = 'ਆ'; - map!['aamatragurmukhi'] = 'ਾ'; - map!['aarusquare'] = '㌃'; - map!['aavowelsignbengali'] = 'া'; - map!['aavowelsigndeva'] = 'ा'; - map!['aavowelsigngujarati'] = 'ા'; - map!['abbreviationmarkarmenian'] = '՟'; - map!['abbreviationsigndeva'] = '॰'; - map!['abengali'] = 'অ'; - map!['abopomofo'] = 'ㄚ'; - map!['abreve'] = 'ă'; - map!['abreveacute'] = 'ắ'; - map!['abrevecyrillic'] = 'ӑ'; - map!['abrevedotbelow'] = 'ặ'; - map!['abrevegrave'] = 'ằ'; - map!['abrevehookabove'] = 'ẳ'; - map!['abrevetilde'] = 'ẵ'; - map!['acaron'] = 'ǎ'; - map!['acircle'] = 'ⓐ'; - map!['acircumflex'] = 'â'; - map!['acircumflexacute'] = 'ấ'; - map!['acircumflexdotbelow'] = 'ậ'; - map!['acircumflexgrave'] = 'ầ'; - map!['acircumflexhookabove'] = 'ẩ'; - map!['acircumflextilde'] = 'ẫ'; - map!['acute'] = '´'; - map!['acutebelowcmb'] = '̗'; - map!['acutecmb'] = '́'; - map!['acutecomb'] = '́'; - map!['acutedeva'] = '॔'; - map!['acutelowmod'] = 'ˏ'; - map!['acutetonecmb'] = '́'; - map!['acyrillic'] = 'а'; - map!['adblgrave'] = 'ȁ'; - map!['addakgurmukhi'] = 'ੱ'; - map!['adeva'] = 'अ'; - map!['adieresis'] = 'ä'; - map!['adieresiscyrillic'] = 'ӓ'; - map!['adieresismacron'] = 'ǟ'; - map!['adotbelow'] = 'ạ'; - map!['adotmacron'] = 'ǡ'; - map!['ae'] = 'æ'; - map!['aeacute'] = 'ǽ'; - map!['aekorean'] = 'ㅐ'; - map!['aemacron'] = 'ǣ'; - map!['afii00208'] = '―'; - map!['afii08941'] = '₤'; - map!['afii10017'] = 'А'; - map!['afii10018'] = 'Б'; - map!['afii10019'] = 'В'; - map!['afii10020'] = 'Г'; - map!['afii10021'] = 'Д'; - map!['afii10022'] = 'Е'; - map!['afii10023'] = 'Ё'; - map!['afii10024'] = 'Ж'; - map!['afii10025'] = 'З'; - map!['afii10026'] = 'И'; - map!['afii10027'] = 'Й'; - map!['afii10028'] = 'К'; - map!['afii10029'] = 'Л'; - map!['afii10030'] = 'М'; - map!['afii10031'] = 'Н'; - map!['afii10032'] = 'О'; - map!['afii10033'] = 'П'; - map!['afii10034'] = 'Р'; - map!['afii10035'] = 'С'; - map!['afii10036'] = 'Т'; - map!['afii10037'] = 'У'; - map!['afii10038'] = 'Ф'; - map!['afii10039'] = 'Х'; - map!['afii10040'] = 'Ц'; - map!['afii10041'] = 'Ч'; - map!['afii10042'] = 'Ш'; - map!['afii10043'] = 'Щ'; - map!['afii10044'] = 'Ъ'; - map!['afii10045'] = 'Ы'; - map!['afii10046'] = 'Ь'; - map!['afii10047'] = 'Э'; - map!['afii10048'] = 'Ю'; - map!['afii10049'] = 'Я'; - map!['afii10050'] = 'Ґ'; - map!['afii10051'] = 'Ђ'; - map!['afii10052'] = 'Ѓ'; - map!['afii10053'] = 'Є'; - map!['afii10054'] = 'Ѕ'; - map!['afii10055'] = 'І'; - map!['afii10056'] = 'Ї'; - map!['afii10057'] = 'Ј'; - map!['afii10058'] = 'Љ'; - map!['afii10059'] = 'Њ'; - map!['afii10060'] = 'Ћ'; - map!['afii10061'] = 'Ќ'; - map!['afii10062'] = 'Ў'; - map!['afii10063'] = ''; - map!['afii10064'] = ''; - map!['afii10065'] = 'а'; - map!['afii10066'] = 'б'; - map!['afii10067'] = 'в'; - map!['afii10068'] = 'г'; - map!['afii10069'] = 'д'; - map!['afii10070'] = 'е'; - map!['afii10071'] = 'ё'; - map!['afii10072'] = 'ж'; - map!['afii10073'] = 'з'; - map!['afii10074'] = 'и'; - map!['afii10075'] = 'й'; - map!['afii10076'] = 'к'; - map!['afii10077'] = 'л'; - map!['afii10078'] = 'м'; - map!['afii10079'] = 'н'; - map!['afii10080'] = 'о'; - map!['afii10081'] = 'п'; - map!['afii10082'] = 'р'; - map!['afii10083'] = 'с'; - map!['afii10084'] = 'т'; - map!['afii10085'] = 'у'; - map!['afii10086'] = 'ф'; - map!['afii10087'] = 'х'; - map!['afii10088'] = 'ц'; - map!['afii10089'] = 'ч'; - map!['afii10090'] = 'ш'; - map!['afii10091'] = 'щ'; - map!['afii10092'] = 'ъ'; - map!['afii10093'] = 'ы'; - map!['afii10094'] = 'ь'; - map!['afii10095'] = 'э'; - map!['afii10096'] = 'ю'; - map!['afii10097'] = 'я'; - map!['afii10098'] = 'ґ'; - map!['afii10099'] = 'ђ'; - map!['afii10100'] = 'ѓ'; - map!['afii10101'] = 'є'; - map!['afii10102'] = 'ѕ'; - map!['afii10103'] = 'і'; - map!['afii10104'] = 'ї'; - map!['afii10105'] = 'ј'; - map!['afii10106'] = 'љ'; - map!['afii10107'] = 'њ'; - map!['afii10108'] = 'ћ'; - map!['afii10109'] = 'ќ'; - map!['afii10110'] = 'ў'; - map!['afii10145'] = 'Џ'; - map!['afii10146'] = 'Ѣ'; - map!['afii10147'] = 'Ѳ'; - map!['afii10148'] = 'Ѵ'; - map!['afii10192'] = ''; - map!['afii10193'] = 'џ'; - map!['afii10194'] = 'ѣ'; - map!['afii10195'] = 'ѳ'; - map!['afii10196'] = 'ѵ'; - map!['afii10831'] = ''; - map!['afii10832'] = ''; - map!['afii10846'] = 'ә'; - map!['afii299'] = '‎'; - map!['afii300'] = '‏'; - map!['afii301'] = '‍'; - map!['afii57381'] = '٪'; - map!['afii57388'] = '،'; - map!['afii57392'] = '٠'; - map!['afii57393'] = '١'; - map!['afii57394'] = '٢'; - map!['afii57395'] = '٣'; - map!['afii57396'] = '٤'; - map!['afii57397'] = '٥'; - map!['afii57398'] = '٦'; - map!['afii57399'] = '٧'; - map!['afii57400'] = '٨'; - map!['afii57401'] = '٩'; - map!['afii57403'] = '؛'; - map!['afii57407'] = '؟'; - map!['afii57409'] = 'ء'; - map!['afii57410'] = 'آ'; - map!['afii57411'] = 'أ'; - map!['afii57412'] = 'ؤ'; - map!['afii57413'] = 'إ'; - map!['afii57414'] = 'ئ'; - map!['afii57415'] = 'ا'; - map!['afii57416'] = 'ب'; - map!['afii57417'] = 'ة'; - map!['afii57418'] = 'ت'; - map!['afii57419'] = 'ث'; - map!['afii57420'] = 'ج'; - map!['afii57421'] = 'ح'; - map!['afii57422'] = 'خ'; - map!['afii57423'] = 'د'; - map!['afii57424'] = 'ذ'; - map!['afii57425'] = 'ر'; - map!['afii57426'] = 'ز'; - map!['afii57427'] = 'س'; - map!['afii57428'] = 'ش'; - map!['afii57429'] = 'ص'; - map!['afii57430'] = 'ض'; - map!['afii57431'] = 'ط'; - map!['afii57432'] = 'ظ'; - map!['afii57433'] = 'ع'; - map!['afii57434'] = 'غ'; - map!['afii57440'] = 'ـ'; - map!['afii57441'] = 'ف'; - map!['afii57442'] = 'ق'; - map!['afii57443'] = 'ك'; - map!['afii57444'] = 'ل'; - map!['afii57445'] = 'م'; - map!['afii57446'] = 'ن'; - map!['afii57448'] = 'و'; - map!['afii57449'] = 'ى'; - map!['afii57450'] = 'ي'; - map!['afii57451'] = 'ً'; - map!['afii57452'] = 'ٌ'; - map!['afii57453'] = 'ٍ'; - map!['afii57454'] = 'َ'; - map!['afii57455'] = 'ُ'; - map!['afii57456'] = 'ِ'; - map!['afii57457'] = 'ّ'; - map!['afii57458'] = 'ْ'; - map!['afii57470'] = 'ه'; - map!['afii57505'] = 'ڤ'; - map!['afii57506'] = 'پ'; - map!['afii57507'] = 'چ'; - map!['afii57508'] = 'ژ'; - map!['afii57509'] = 'گ'; - map!['afii57511'] = 'ٹ'; - map!['afii57512'] = 'ڈ'; - map!['afii57513'] = 'ڑ'; - map!['afii57514'] = 'ں'; - map!['afii57519'] = 'ے'; - map!['afii57534'] = 'ە'; - map!['afii57636'] = '₪'; - map!['afii57645'] = '־'; - map!['afii57658'] = '׃'; - map!['afii57664'] = 'א'; - map!['afii57665'] = 'ב'; - map!['afii57666'] = 'ג'; - map!['afii57667'] = 'ד'; - map!['afii57668'] = 'ה'; - map!['afii57669'] = 'ו'; - map!['afii57670'] = 'ז'; - map!['afii57671'] = 'ח'; - map!['afii57672'] = 'ט'; - map!['afii57673'] = 'י'; - map!['afii57674'] = 'ך'; - map!['afii57675'] = 'כ'; - map!['afii57676'] = 'ל'; - map!['afii57677'] = 'ם'; - map!['afii57678'] = 'מ'; - map!['afii57679'] = 'ן'; - map!['afii57680'] = 'נ'; - map!['afii57681'] = 'ס'; - map!['afii57682'] = 'ע'; - map!['afii57683'] = 'ף'; - map!['afii57684'] = 'פ'; - map!['afii57685'] = 'ץ'; - map!['afii57686'] = 'צ'; - map!['afii57687'] = 'ק'; - map!['afii57688'] = 'ר'; - map!['afii57689'] = 'ש'; - map!['afii57690'] = 'ת'; - map!['afii57694'] = 'שׁ'; - map!['afii57695'] = 'שׂ'; - map!['afii57700'] = 'וֹ'; - map!['afii57705'] = 'ײַ'; - map!['afii57716'] = 'װ'; - map!['afii57717'] = 'ױ'; - map!['afii57718'] = 'ײ'; - map!['afii57723'] = 'וּ'; - map!['afii57793'] = 'ִ'; - map!['afii57794'] = 'ֵ'; - map!['afii57795'] = 'ֶ'; - map!['afii57796'] = 'ֻ'; - map!['afii57797'] = 'ָ'; - map!['afii57798'] = 'ַ'; - map!['afii57799'] = 'ְ'; - map!['afii57800'] = 'ֲ'; - map!['afii57801'] = 'ֱ'; - map!['afii57802'] = 'ֳ'; - map!['afii57803'] = 'ׂ'; - map!['afii57804'] = 'ׁ'; - map!['afii57806'] = 'ֹ'; - map!['afii57807'] = 'ּ'; - map!['afii57839'] = 'ֽ'; - map!['afii57841'] = 'ֿ'; - map!['afii57842'] = '׀'; - map!['afii57929'] = 'ʼ'; - map!['afii61248'] = '℅'; - map!['afii61289'] = 'ℓ'; - map!['afii61352'] = '№'; - map!['afii61573'] = '‬'; - map!['afii61574'] = '‭'; - map!['afii61575'] = '‮'; - map!['afii61664'] = '‌'; - map!['afii63167'] = '٭'; - map!['afii64937'] = 'ʽ'; - map!['agrave'] = 'à'; - map!['agujarati'] = 'અ'; - map!['agurmukhi'] = 'ਅ'; - map!['ahiragana'] = 'あ'; - map!['ahookabove'] = 'ả'; - map!['aibengali'] = 'ঐ'; - map!['aibopomofo'] = 'ㄞ'; - map!['aideva'] = 'ऐ'; - map!['aiecyrillic'] = 'ӕ'; - map!['aigujarati'] = 'ઐ'; - map!['aigurmukhi'] = 'ਐ'; - map!['aimatragurmukhi'] = 'ੈ'; - map!['ainarabic'] = 'ع'; - map!['ainfinalarabic'] = 'ﻊ'; - map!['aininitialarabic'] = 'ﻋ'; - map!['ainmedialarabic'] = 'ﻌ'; - map!['ainvertedbreve'] = 'ȃ'; - map!['aivowelsignbengali'] = 'ৈ'; - map!['aivowelsigndeva'] = 'ै'; - map!['aivowelsigngujarati'] = 'ૈ'; - map!['akatakana'] = 'ア'; - map!['akatakanahalfwidth'] = 'ア'; - map!['akorean'] = 'ㅏ'; - map!['alef'] = 'א'; - map!['alefarabic'] = 'ا'; - map!['alefdageshhebrew'] = 'אּ'; - map!['aleffinalarabic'] = 'ﺎ'; - map!['alefhamzaabovearabic'] = 'أ'; - map!['alefhamzaabovefinalarabic'] = 'ﺄ'; - map!['alefhamzabelowarabic'] = 'إ'; - map!['alefhamzabelowfinalarabic'] = 'ﺈ'; - map!['alefhebrew'] = 'א'; - map!['aleflamedhebrew'] = 'ﭏ'; - map!['alefmaddaabovearabic'] = 'آ'; - map!['alefmaddaabovefinalarabic'] = 'ﺂ'; - map!['alefmaksuraarabic'] = 'ى'; - map!['alefmaksurafinalarabic'] = 'ﻰ'; - map!['alefmaksurainitialarabic'] = 'ﻳ'; - map!['alefmaksuramedialarabic'] = 'ﻴ'; - map!['alefpatahhebrew'] = 'אַ'; - map!['alefqamatshebrew'] = 'אָ'; - map!['aleph'] = 'ℵ'; - map!['allequal'] = '≌'; - map!['alpha'] = 'α'; - map!['alphatonos'] = 'ά'; - map!['amacron'] = 'ā'; - map!['amonospace'] = 'a'; - map!['ampersand'] = '&'; - map!['ampersandmonospace'] = '&'; - map!['ampersandsmall'] = ''; - map!['amsquare'] = '㏂'; - map!['anbopomofo'] = 'ㄢ'; - map!['angbopomofo'] = 'ㄤ'; - map!['angkhankhuthai'] = '๚'; - map!['angle'] = '∠'; - map!['angbracketleft'] = '〈'; - map!['anglebracketleft'] = '〈'; - map!['anglebracketleftvertical'] = '︿'; - map!['angbracketright'] = '〉'; - map!['anglebracketright'] = '〉'; - map!['anglebracketrightvertical'] = '﹀'; - map!['angleleft'] = '〈'; - map!['angleright'] = '〉'; - map!['angstrom'] = 'Å'; - map!['anoteleia'] = '·'; - map!['anudattadeva'] = '॒'; - map!['anusvarabengali'] = 'ং'; - map!['anusvaradeva'] = 'ं'; - map!['anusvaragujarati'] = 'ં'; - map!['aogonek'] = 'ą'; - map!['apaatosquare'] = '㌀'; - map!['aparen'] = '⒜'; - map!['apostrophearmenian'] = '՚'; - map!['apostrophemod'] = 'ʼ'; - map!['apple'] = ''; - map!['approaches'] = '≐'; - map!['approxequal'] = '≈'; - map!['approxequalorimage'] = '≒'; - map!['approximatelyequal'] = '≅'; - map!['araeaekorean'] = 'ㆎ'; - map!['araeakorean'] = 'ㆍ'; - map!['arc'] = '⌒'; - map!['arighthalfring'] = 'ẚ'; - map!['aring'] = 'å'; - map!['aringacute'] = 'ǻ'; - map!['aringbelow'] = 'ḁ'; - map!['arrowboth'] = '↔'; - map!['arrowdashdown'] = '⇣'; - map!['arrowdashleft'] = '⇠'; - map!['arrowdashright'] = '⇢'; - map!['arrowdashup'] = '⇡'; - map!['arrowdblboth'] = '⇔'; - map!['arrowdbldown'] = '⇓'; - map!['arrowdblleft'] = '⇐'; - map!['arrowdblright'] = '⇒'; - map!['arrowdblup'] = '⇑'; - map!['arrowdown'] = '↓'; - map!['arrowdownleft'] = '↙'; - map!['arrowdownright'] = '↘'; - map!['arrowdownwhite'] = '⇩'; - map!['arrowheaddownmod'] = '˅'; - map!['arrowheadleftmod'] = '˂'; - map!['arrowheadrightmod'] = '˃'; - map!['arrowheadupmod'] = '˄'; - map!['arrowhorizex'] = ''; - map!['arrowleft'] = '←'; - map!['arrowleftdbl'] = '⇐'; - map!['arrowleftdblstroke'] = '⇍'; - map!['arrowleftoverright'] = '⇆'; - map!['arrowleftwhite'] = '⇦'; - map!['arrowright'] = '→'; - map!['arrowrightdblstroke'] = '⇏'; - map!['arrowrightheavy'] = '➞'; - map!['arrowrightoverleft'] = '⇄'; - map!['arrowrightwhite'] = '⇨'; - map!['arrowtableft'] = '⇤'; - map!['arrowtabright'] = '⇥'; - map!['arrowup'] = '↑'; - map!['arrowupdn'] = '↕'; - map!['arrowupdnbse'] = '↨'; - map!['arrowupdownbase'] = '↨'; - map!['arrowupleft'] = '↖'; - map!['arrowupleftofdown'] = '⇅'; - map!['arrowupright'] = '↗'; - map!['arrowupwhite'] = '⇧'; - map!['arrowvertex'] = ''; - map!['asciicircum'] = '^'; - map!['asciicircummonospace'] = '^'; - map!['asciitilde'] = '~'; - map!['asciitildemonospace'] = '~'; - map!['ascript'] = 'ɑ'; - map!['ascriptturned'] = 'ɒ'; - map!['asmallhiragana'] = 'ぁ'; - map!['asmallkatakana'] = 'ァ'; - map!['asmallkatakanahalfwidth'] = 'ァ'; - map!['asterisk'] = '*'; - map!['asteriskaltonearabic'] = '٭'; - map!['asteriskarabic'] = '٭'; - map!['asteriskmath'] = '∗'; - map!['asteriskmonospace'] = '*'; - map!['asterisksmall'] = '﹡'; - map!['asterism'] = '⁂'; - map!['asuperior'] = ''; - map!['asymptoticallyequal'] = '≃'; - map!['at'] = '@'; - map!['atilde'] = 'ã'; - map!['atmonospace'] = '@'; - map!['atsmall'] = '﹫'; - map!['aturned'] = 'ɐ'; - map!['aubengali'] = 'ঔ'; - map!['aubopomofo'] = 'ㄠ'; - map!['audeva'] = 'औ'; - map!['augujarati'] = 'ઔ'; - map!['augurmukhi'] = 'ਔ'; - map!['aulengthmarkbengali'] = 'ৗ'; - map!['aumatragurmukhi'] = 'ੌ'; - map!['auvowelsignbengali'] = 'ৌ'; - map!['auvowelsigndeva'] = 'ौ'; - map!['auvowelsigngujarati'] = 'ૌ'; - map!['avagrahadeva'] = 'ऽ'; - map!['aybarmenian'] = 'ա'; - map!['ayin'] = 'ע'; - map!['ayinaltonehebrew'] = 'ﬠ'; - map!['ayinhebrew'] = 'ע'; - map!['b'] = 'b'; - map!['babengali'] = 'ব'; - map!['backslash'] = r'\'; - map!['backslashmonospace'] = '\'; - map!['badeva'] = 'ब'; - map!['bagujarati'] = 'બ'; - map!['bagurmukhi'] = 'ਬ'; - map!['bahiragana'] = 'ば'; - map!['bahtthai'] = '฿'; - map!['bakatakana'] = 'バ'; - map!['bar'] = '|'; - map!['barmonospace'] = '|'; - map!['bbopomofo'] = 'ㄅ'; - map!['bcircle'] = 'ⓑ'; - map!['bdotaccent'] = 'ḃ'; - map!['bdotbelow'] = 'ḅ'; - map!['beamedsixteenthnotes'] = '♬'; - map!['because'] = '∵'; - map!['becyrillic'] = 'б'; - map!['beharabic'] = 'ب'; - map!['behfinalarabic'] = 'ﺐ'; - map!['behinitialarabic'] = 'ﺑ'; - map!['behiragana'] = 'べ'; - map!['behmedialarabic'] = 'ﺒ'; - map!['behmeeminitialarabic'] = 'ﲟ'; - map!['behmeemisolatedarabic'] = 'ﰈ'; - map!['behnoonfinalarabic'] = 'ﱭ'; - map!['bekatakana'] = 'ベ'; - map!['benarmenian'] = 'բ'; - map!['bet'] = 'ב'; - map!['beta'] = 'β'; - map!['betasymbolgreek'] = 'ϐ'; - map!['betdagesh'] = 'בּ'; - map!['betdageshhebrew'] = 'בּ'; - map!['bethebrew'] = 'ב'; - map!['betrafehebrew'] = 'בֿ'; - map!['bhabengali'] = 'ভ'; - map!['bhadeva'] = 'भ'; - map!['bhagujarati'] = 'ભ'; - map!['bhagurmukhi'] = 'ਭ'; - map!['bhook'] = 'ɓ'; - map!['bihiragana'] = 'び'; - map!['bikatakana'] = 'ビ'; - map!['bilabialclick'] = 'ʘ'; - map!['bindigurmukhi'] = 'ਂ'; - map!['birusquare'] = '㌱'; - map!['blackcircle'] = '●'; - map!['blackdiamond'] = '◆'; - map!['blackdownpointingtriangle'] = '▼'; - map!['blackleftpointingpointer'] = '◄'; - map!['blackleftpointingtriangle'] = '◀'; - map!['blacklenticularbracketleft'] = '【'; - map!['blacklenticularbracketleftvertical'] = '︻'; - map!['blacklenticularbracketright'] = '】'; - map!['blacklenticularbracketrightvertical'] = '︼'; - map!['blacklowerlefttriangle'] = '◣'; - map!['blacklowerrighttriangle'] = '◢'; - map!['blackrectangle'] = '▬'; - map!['blackrightpointingpointer'] = '►'; - map!['blackrightpointingtriangle'] = '▶'; - map!['blacksmallsquare'] = '▪'; - map!['blacksmilingface'] = '☻'; - map!['blacksquare'] = '■'; - map!['blackstar'] = '★'; - map!['blackupperlefttriangle'] = '◤'; - map!['blackupperrighttriangle'] = '◥'; - map!['blackuppointingsmalltriangle'] = '▴'; - map!['blackuppointingtriangle'] = '▲'; - map!['blank'] = '␣'; - map!['blinebelow'] = 'ḇ'; - map!['block'] = '█'; - map!['bmonospace'] = 'b'; - map!['bobaimaithai'] = 'บ'; - map!['bohiragana'] = 'ぼ'; - map!['bokatakana'] = 'ボ'; - map!['bparen'] = '⒝'; - map!['bqsquare'] = '㏃'; - map!['braceex'] = ''; - map!['braceleft'] = '{'; - map!['braceleftbt'] = ''; - map!['braceleftmid'] = ''; - map!['braceleftmonospace'] = '{'; - map!['braceleftsmall'] = '﹛'; - map!['bracelefttp'] = ''; - map!['braceleftvertical'] = '︷'; - map!['braceright'] = '}'; - map!['bracerightbt'] = ''; - map!['bracerightmid'] = ''; - map!['bracerightmonospace'] = '}'; - map!['bracerightsmall'] = '﹜'; - map!['bracerighttp'] = ''; - map!['bracerightvertical'] = '︸'; - map!['bracketleft'] = '['; - map!['bracketleftbt'] = ''; - map!['bracketleftex'] = ''; - map!['bracketleftmonospace'] = '['; - map!['bracketlefttp'] = ''; - map!['bracketright'] = ']'; - map!['bracketrightbt'] = ''; - map!['bracketrightex'] = ''; - map!['bracketrightmonospace'] = ']'; - map!['bracketrighttp'] = ''; - map!['breve'] = '˘'; - map!['brevebelowcmb'] = '̮'; - map!['brevecmb'] = '̆'; - map!['breveinvertedbelowcmb'] = '̯'; - map!['breveinvertedcmb'] = '̑'; - map!['breveinverteddoublecmb'] = '͡'; - map!['bridgebelowcmb'] = '̪'; - map!['bridgeinvertedbelowcmb'] = '̺'; - map!['brokenbar'] = '¦'; - map!['bstroke'] = 'ƀ'; - map!['bsuperior'] = ''; - map!['btopbar'] = 'ƃ'; - map!['buhiragana'] = 'ぶ'; - map!['bukatakana'] = 'ブ'; - map!['bullet'] = '•'; - map!['bulletinverse'] = '◘'; - map!['bulletoperator'] = '∙'; - map!['bullseye'] = '◎'; - map!['c'] = 'c'; - map!['caarmenian'] = 'ծ'; - map!['cabengali'] = 'চ'; - map!['cacute'] = 'ć'; - map!['cadeva'] = 'च'; - map!['cagujarati'] = 'ચ'; - map!['cagurmukhi'] = 'ਚ'; - map!['calsquare'] = '㎈'; - map!['candrabindubengali'] = 'ঁ'; - map!['candrabinducmb'] = '̐'; - map!['candrabindudeva'] = 'ँ'; - map!['candrabindugujarati'] = 'ઁ'; - map!['capslock'] = '⇪'; - map!['careof'] = '℅'; - map!['caron'] = 'ˇ'; - map!['caronbelowcmb'] = '̬'; - map!['caroncmb'] = '̌'; - map!['carriagereturn'] = '↵'; - map!['cbopomofo'] = 'ㄘ'; - map!['ccaron'] = 'č'; - map!['ccedilla'] = 'ç'; - map!['ccedillaacute'] = 'ḉ'; - map!['ccircle'] = 'ⓒ'; - map!['ccircumflex'] = 'ĉ'; - map!['ccurl'] = 'ɕ'; - map!['cdot'] = 'ċ'; - map!['cdotaccent'] = 'ċ'; - map!['cdsquare'] = '㏅'; - map!['cedilla'] = '¸'; - map!['cedillacmb'] = '̧'; - map!['cent'] = '¢'; - map!['centigrade'] = '℃'; - map!['centinferior'] = ''; - map!['centmonospace'] = '¢'; - map!['centoldstyle'] = ''; - map!['centsuperior'] = ''; - map!['chaarmenian'] = 'չ'; - map!['chabengali'] = 'ছ'; - map!['chadeva'] = 'छ'; - map!['chagujarati'] = 'છ'; - map!['chagurmukhi'] = 'ਛ'; - map!['chbopomofo'] = 'ㄔ'; - map!['cheabkhasiancyrillic'] = 'ҽ'; - map!['checkmark'] = '✓'; - map!['checyrillic'] = 'ч'; - map!['chedescenderabkhasiancyrillic'] = 'ҿ'; - map!['chedescendercyrillic'] = 'ҷ'; - map!['chedieresiscyrillic'] = 'ӵ'; - map!['cheharmenian'] = 'ճ'; - map!['chekhakassiancyrillic'] = 'ӌ'; - map!['cheverticalstrokecyrillic'] = 'ҹ'; - map!['chi'] = 'χ'; - map!['chieuchacirclekorean'] = '㉷'; - map!['chieuchaparenkorean'] = '㈗'; - map!['chieuchcirclekorean'] = '㉩'; - map!['chieuchkorean'] = 'ㅊ'; - map!['chieuchparenkorean'] = '㈉'; - map!['chochangthai'] = 'ช'; - map!['chochanthai'] = 'จ'; - map!['chochingthai'] = 'ฉ'; - map!['chochoethai'] = 'ฌ'; - map!['chook'] = 'ƈ'; - map!['cieucacirclekorean'] = '㉶'; - map!['cieucaparenkorean'] = '㈖'; - map!['cieuccirclekorean'] = '㉨'; - map!['cieuckorean'] = 'ㅈ'; - map!['cieucparenkorean'] = '㈈'; - map!['cieucuparenkorean'] = '㈜'; - map!['circle'] = '○'; - map!['circlemultiply'] = '⊗'; - map!['circleot'] = '⊙'; - map!['circleplus'] = '⊕'; - map!['circlepostalmark'] = '〶'; - map!['circlewithlefthalfblack'] = '◐'; - map!['circlewithrighthalfblack'] = '◑'; - map!['circumflex'] = 'ˆ'; - map!['circumflexbelowcmb'] = '̭'; - map!['circumflexcmb'] = '̂'; - map!['clear'] = '⌧'; - map!['clickalveolar'] = 'ǂ'; - map!['clickdental'] = 'ǀ'; - map!['clicklateral'] = 'ǁ'; - map!['clickretroflex'] = 'ǃ'; - map!['club'] = '♣'; - map!['clubsuitblack'] = '♣'; - map!['clubsuitwhite'] = '♧'; - map!['cmcubedsquare'] = '㎤'; - map!['cmonospace'] = 'c'; - map!['cmsquaredsquare'] = '㎠'; - map!['coarmenian'] = 'ց'; - map!['colon'] = ':'; - map!['colonmonetary'] = '₡'; - map!['colonmonospace'] = ':'; - map!['colonsign'] = '₡'; - map!['colonsmall'] = '﹕'; - map!['colontriangularhalfmod'] = 'ˑ'; - map!['colontriangularmod'] = 'ː'; - map!['comma'] = ','; - map!['commaabovecmb'] = '̓'; - map!['commaaboverightcmb'] = '̕'; - map!['commaaccent'] = ''; - map!['commaarabic'] = '،'; - map!['commaarmenian'] = '՝'; - map!['commainferior'] = ''; - map!['commamonospace'] = ','; - map!['commareversedabovecmb'] = '̔'; - map!['commareversedmod'] = 'ʽ'; - map!['commasmall'] = '﹐'; - map!['commasuperior'] = ''; - map!['commaturnedabovecmb'] = '̒'; - map!['commaturnedmod'] = 'ʻ'; - map!['compass'] = '☼'; - map!['congruent'] = '≅'; - map!['contourintegral'] = '∮'; - map!['control'] = '⌃'; - map!['controlACK'] = '\u0006'; - map!['controlBEL'] = r'a'; - map!['controlBS'] = '\b'; - map!['controlCAN'] = '\u0018'; - map!['controlCR'] = '\r'; - map!['controlDC1'] = '\u0011'; - map!['controlDC2'] = '\u0012'; - map!['controlDC3'] = '\u0013'; - map!['controlDC4'] = '\u0014'; - map!['controlDEL'] = '\u007f'; - map!['controlDLE'] = '\u0010'; - map!['controlEM'] = '\u0019'; - map!['controlENQ'] = '\u0005'; - map!['controlEOT'] = '\u0004'; - map!['controlESC'] = '\u001b'; - map!['controlETB'] = '\u0017'; - map!['controlETX'] = '\u0003'; - map!['controlFF'] = '\f'; - map!['controlFS'] = '\u001c'; - map!['controlGS'] = '\u001d'; - map!['controlHT'] = '\t'; - map!['controlLF'] = '\n'; - map!['controlNAK'] = '\u0015'; - map!['controlRS'] = '\u001e'; - map!['controlSI'] = '\u000f'; - map!['controlSO'] = '\u000e'; - map!['controlSOT'] = '\u0002'; - map!['controlSTX'] = '\u0001'; - map!['controlSUB'] = '\u001a'; - map!['controlSYN'] = '\u0016'; - map!['controlUS'] = '\u001f'; - map!['controlVT'] = '\v'; - map!['copyright'] = '©'; - map!['copyrightsans'] = ''; - map!['copyrightserif'] = ''; - map!['cornerbracketleft'] = '「'; - map!['cornerbracketlefthalfwidth'] = '「'; - map!['cornerbracketleftvertical'] = '﹁'; - map!['cornerbracketright'] = '」'; - map!['cornerbracketrighthalfwidth'] = '」'; - map!['cornerbracketrightvertical'] = '﹂'; - map!['corporationsquare'] = '㍿'; - map!['cosquare'] = '㏇'; - map!['coverkgsquare'] = '㏆'; - map!['cparen'] = '⒞'; - map!['cruzeiro'] = '₢'; - map!['cstretched'] = 'ʗ'; - map!['curlyand'] = '⋏'; - map!['curlyor'] = '⋎'; - map!['currency'] = '¤'; - map!['cyrBreve'] = ''; - map!['cyrFlex'] = ''; - map!['cyrbreve'] = ''; - map!['cyrflex'] = ''; - map!['d'] = 'd'; - map!['daarmenian'] = 'դ'; - map!['dabengali'] = 'দ'; - map!['dadarabic'] = 'ض'; - map!['dadeva'] = 'द'; - map!['dadfinalarabic'] = 'ﺾ'; - map!['dadinitialarabic'] = 'ﺿ'; - map!['dadmedialarabic'] = 'ﻀ'; - map!['dagesh'] = 'ּ'; - map!['dageshhebrew'] = 'ּ'; - map!['dagger'] = '†'; - map!['daggerdbl'] = '‡'; - map!['dagujarati'] = 'દ'; - map!['dagurmukhi'] = 'ਦ'; - map!['dahiragana'] = 'だ'; - map!['dakatakana'] = 'ダ'; - map!['dalarabic'] = 'د'; - map!['dalet'] = 'ד'; - map!['daletdagesh'] = 'דּ'; - map!['daletdageshhebrew'] = 'דּ'; - map!['dalethebrew'] = 'ד'; - map!['dalfinalarabic'] = 'ﺪ'; - map!['dammaarabic'] = 'ُ'; - map!['dammalowarabic'] = 'ُ'; - map!['dammatanaltonearabic'] = 'ٌ'; - map!['dammatanarabic'] = 'ٌ'; - map!['danda'] = '।'; - map!['dargahebrew'] = '֧'; - map!['dargalefthebrew'] = '֧'; - map!['dasiapneumatacyrilliccmb'] = '҅'; - map!['dblGrave'] = ''; - map!['dblanglebracketleft'] = '《'; - map!['dblanglebracketleftvertical'] = '︽'; - map!['dblanglebracketright'] = '》'; - map!['dblanglebracketrightvertical'] = '︾'; - map!['dblarchinvertedbelowcmb'] = '̫'; - map!['dblarrowleft'] = '⇔'; - map!['dblarrowright'] = '⇒'; - map!['dbldanda'] = '॥'; - map!['dblgrave'] = ''; - map!['dblgravecmb'] = '̏'; - map!['dblintegral'] = '∬'; - map!['dbllowline'] = '‗'; - map!['dbllowlinecmb'] = '̳'; - map!['dbloverlinecmb'] = '̿'; - map!['dblprimemod'] = 'ʺ'; - map!['dblverticalbar'] = '‖'; - map!['dblverticallineabovecmb'] = '̎'; - map!['dbopomofo'] = 'ㄉ'; - map!['dbsquare'] = '㏈'; - map!['dcaron'] = 'ď'; - map!['dcedilla'] = 'ḑ'; - map!['dcircle'] = 'ⓓ'; - map!['dcircumflexbelow'] = 'ḓ'; - map!['dcroat'] = 'đ'; - map!['ddabengali'] = 'ড'; - map!['ddadeva'] = 'ड'; - map!['ddagujarati'] = 'ડ'; - map!['ddagurmukhi'] = 'ਡ'; - map!['ddalarabic'] = 'ڈ'; - map!['ddalfinalarabic'] = 'ﮉ'; - map!['dddhadeva'] = 'ड़'; - map!['ddhabengali'] = 'ঢ'; - map!['ddhadeva'] = 'ढ'; - map!['ddhagujarati'] = 'ઢ'; - map!['ddhagurmukhi'] = 'ਢ'; - map!['ddotaccent'] = 'ḋ'; - map!['ddotbelow'] = 'ḍ'; - map!['decimalseparatorarabic'] = '٫'; - map!['decimalseparatorpersian'] = '٫'; - map!['decyrillic'] = 'д'; - map!['degree'] = '°'; - map!['dehihebrew'] = '֭'; - map!['dehiragana'] = 'で'; - map!['deicoptic'] = 'ϯ'; - map!['dekatakana'] = 'デ'; - map!['deleteleft'] = '⌫'; - map!['deleteright'] = '⌦'; - map!['delta'] = 'δ'; - map!['deltaturned'] = 'ƍ'; - map!['denominatorminusonenumeratorbengali'] = '৸'; - map!['dezh'] = 'ʤ'; - map!['dhabengali'] = 'ধ'; - map!['dhadeva'] = 'ध'; - map!['dhagujarati'] = 'ધ'; - map!['dhagurmukhi'] = 'ਧ'; - map!['dhook'] = 'ɗ'; - map!['dialytikatonos'] = '΅'; - map!['dialytikatonoscmb'] = '̈́'; - map!['diamond'] = '♦'; - map!['diamondsuitwhite'] = '♢'; - map!['dieresis'] = '¨'; - map!['dieresisacute'] = ''; - map!['dieresisbelowcmb'] = '̤'; - map!['dieresiscmb'] = '̈'; - map!['dieresisgrave'] = ''; - map!['dieresistonos'] = '΅'; - map!['dihiragana'] = 'ぢ'; - map!['dikatakana'] = 'ヂ'; - map!['dittomark'] = '〃'; - map!['divide'] = '÷'; - map!['divides'] = '∣'; - map!['divisionslash'] = '∕'; - map!['djecyrillic'] = 'ђ'; - map!['dkshade'] = '▓'; - map!['dlinebelow'] = 'ḏ'; - map!['dlsquare'] = '㎗'; - map!['dmacron'] = 'đ'; - map!['dmonospace'] = 'd'; - map!['dnblock'] = '▄'; - map!['dochadathai'] = 'ฎ'; - map!['dodekthai'] = 'ด'; - map!['dohiragana'] = 'ど'; - map!['dokatakana'] = 'ド'; - map!['dollar'] = r'$'; - map!['dollarinferior'] = ''; - map!['dollarmonospace'] = '$'; - map!['dollaroldstyle'] = ''; - map!['dollarsmall'] = '﹩'; - map!['dollarsuperior'] = ''; - map!['dong'] = '₫'; - map!['dorusquare'] = '㌦'; - map!['dotaccent'] = '˙'; - map!['dotaccentcmb'] = '̇'; - map!['dotbelowcmb'] = '̣'; - map!['dotbelowcomb'] = '̣'; - map!['dotkatakana'] = '・'; - map!['dotlessi'] = 'ı'; - map!['dotlessj'] = ''; - map!['dotlessjstrokehook'] = 'ʄ'; - map!['dotmath'] = '⋅'; - map!['dottedcircle'] = '◌'; - map!['doubleyodpatah'] = 'ײַ'; - map!['doubleyodpatahhebrew'] = 'ײַ'; - map!['downtackbelowcmb'] = '̞'; - map!['downtackmod'] = '˕'; - map!['dparen'] = '⒟'; - map!['dsuperior'] = ''; - map!['dtail'] = 'ɖ'; - map!['dtopbar'] = 'ƌ'; - map!['duhiragana'] = 'づ'; - map!['dukatakana'] = 'ヅ'; - map!['dz'] = 'dz'; - map!['dzaltone'] = 'ʣ'; - map!['dzcaron'] = 'dž'; - map!['dzcurl'] = 'ʥ'; - map!['dzeabkhasiancyrillic'] = 'ӡ'; - map!['dzecyrillic'] = 'ѕ'; - map!['dzhecyrillic'] = 'џ'; - map!['e'] = 'e'; - map!['eacute'] = 'é'; - map!['earth'] = '♁'; - map!['ebengali'] = 'এ'; - map!['ebopomofo'] = 'ㄜ'; - map!['ebreve'] = 'ĕ'; - map!['ecandradeva'] = 'ऍ'; - map!['ecandragujarati'] = 'ઍ'; - map!['ecandravowelsigndeva'] = 'ॅ'; - map!['ecandravowelsigngujarati'] = 'ૅ'; - map!['ecaron'] = 'ě'; - map!['ecedillabreve'] = 'ḝ'; - map!['echarmenian'] = 'ե'; - map!['echyiwnarmenian'] = 'և'; - map!['ecircle'] = 'ⓔ'; - map!['ecircumflex'] = 'ê'; - map!['ecircumflexacute'] = 'ế'; - map!['ecircumflexbelow'] = 'ḙ'; - map!['ecircumflexdotbelow'] = 'ệ'; - map!['ecircumflexgrave'] = 'ề'; - map!['ecircumflexhookabove'] = 'ể'; - map!['ecircumflextilde'] = 'ễ'; - map!['ecyrillic'] = 'є'; - map!['edblgrave'] = 'ȅ'; - map!['edeva'] = 'ए'; - map!['edieresis'] = 'ë'; - map!['edot'] = 'ė'; - map!['edotaccent'] = 'ė'; - map!['edotbelow'] = 'ẹ'; - map!['eegurmukhi'] = 'ਏ'; - map!['eematragurmukhi'] = 'ੇ'; - map!['efcyrillic'] = 'ф'; - map!['egrave'] = 'è'; - map!['egujarati'] = 'એ'; - map!['eharmenian'] = 'է'; - map!['ehbopomofo'] = 'ㄝ'; - map!['ehiragana'] = 'え'; - map!['ehookabove'] = 'ẻ'; - map!['eibopomofo'] = 'ㄟ'; - map!['eight'] = '8'; - map!['eightarabic'] = '٨'; - map!['eightbengali'] = '৮'; - map!['eightcircle'] = '⑧'; - map!['eightcircleinversesansserif'] = '➑'; - map!['eightdeva'] = '८'; - map!['eighteencircle'] = '⑱'; - map!['eighteenparen'] = '⒅'; - map!['eighteenperiod'] = '⒙'; - map!['eightgujarati'] = '૮'; - map!['eightgurmukhi'] = '੮'; - map!['eighthackarabic'] = '٨'; - map!['eighthangzhou'] = '〨'; - map!['eighthnotebeamed'] = '♫'; - map!['eightideographicparen'] = '㈧'; - map!['eightinferior'] = '₈'; - map!['eightmonospace'] = '8'; - map!['eightoldstyle'] = ''; - map!['eightparen'] = '⑻'; - map!['eightperiod'] = '⒏'; - map!['eightpersian'] = '۸'; - map!['eightroman'] = 'ⅷ'; - map!['eightsuperior'] = '⁸'; - map!['eightthai'] = '๘'; - map!['einvertedbreve'] = 'ȇ'; - map!['eiotifiedcyrillic'] = 'ѥ'; - map!['ekatakana'] = 'エ'; - map!['ekatakanahalfwidth'] = 'エ'; - map!['ekonkargurmukhi'] = 'ੴ'; - map!['ekorean'] = 'ㅔ'; - map!['elcyrillic'] = 'л'; - map!['element'] = '∈'; - map!['elevencircle'] = '⑪'; - map!['elevenparen'] = '⑾'; - map!['elevenperiod'] = '⒒'; - map!['elevenroman'] = 'ⅺ'; - map!['ellipsis'] = '…'; - map!['ellipsisvertical'] = '⋮'; - map!['emacron'] = 'ē'; - map!['emacronacute'] = 'ḗ'; - map!['emacrongrave'] = 'ḕ'; - map!['emcyrillic'] = 'м'; - map!['emdash'] = '—'; - map!['emdashvertical'] = '︱'; - map!['emonospace'] = 'e'; - map!['emphasismarkarmenian'] = '՛'; - map!['emptyset'] = '∅'; - map!['enbopomofo'] = 'ㄣ'; - map!['encyrillic'] = 'н'; - map!['endash'] = '–'; - map!['endashvertical'] = '︲'; - map!['endescendercyrillic'] = 'ң'; - map!['eng'] = 'ŋ'; - map!['engbopomofo'] = 'ㄥ'; - map!['enghecyrillic'] = 'ҥ'; - map!['enhookcyrillic'] = 'ӈ'; - map!['enspace'] = '\u2002'; - map!['eogonek'] = 'ę'; - map!['eokorean'] = 'ㅓ'; - map!['eopen'] = 'ɛ'; - map!['eopenclosed'] = 'ʚ'; - map!['eopenreversed'] = 'ɜ'; - map!['eopenreversedclosed'] = 'ɞ'; - map!['eopenreversedhook'] = 'ɝ'; - map!['eparen'] = '⒠'; - map!['epsilon'] = 'ε'; - map!['epsilontonos'] = 'έ'; - map!['equal'] = '='; - map!['equalmonospace'] = '='; - map!['equalsmall'] = '﹦'; - map!['equalsuperior'] = '⁼'; - map!['equivalence'] = '≡'; - map!['erbopomofo'] = 'ㄦ'; - map!['ercyrillic'] = 'р'; - map!['ereversed'] = 'ɘ'; - map!['ereversedcyrillic'] = 'э'; - map!['escyrillic'] = 'с'; - map!['esdescendercyrillic'] = 'ҫ'; - map!['esh'] = 'ʃ'; - map!['eshcurl'] = 'ʆ'; - map!['eshortdeva'] = 'ऎ'; - map!['eshortvowelsigndeva'] = 'ॆ'; - map!['eshreversedloop'] = 'ƪ'; - map!['eshsquatreversed'] = 'ʅ'; - map!['esmallhiragana'] = 'ぇ'; - map!['esmallkatakana'] = 'ェ'; - map!['esmallkatakanahalfwidth'] = 'ェ'; - map!['estimated'] = '℮'; - map!['esuperior'] = ''; - map!['eta'] = 'η'; - map!['etarmenian'] = 'ը'; - map!['etatonos'] = 'ή'; - map!['eth'] = 'ð'; - map!['etilde'] = 'ẽ'; - map!['etildebelow'] = 'ḛ'; - map!['etnahtafoukhhebrew'] = '֑'; - map!['etnahtafoukhlefthebrew'] = '֑'; - map!['etnahtahebrew'] = '֑'; - map!['etnahtalefthebrew'] = '֑'; - map!['eturned'] = 'ǝ'; - map!['eukorean'] = 'ㅡ'; - map!['euro'] = '€'; - map!['evowelsignbengali'] = 'ে'; - map!['evowelsigndeva'] = 'े'; - map!['evowelsigngujarati'] = 'ે'; - map!['exclam'] = '!'; - map!['exclamarmenian'] = '՜'; - map!['exclamdbl'] = '‼'; - map!['exclamdown'] = '¡'; - map!['exclamdownsmall'] = ''; - map!['exclammonospace'] = '!'; - map!['exclamsmall'] = ''; - map!['existential'] = '∃'; - map!['ezh'] = 'ʒ'; - map!['ezhcaron'] = 'ǯ'; - map!['ezhcurl'] = 'ʓ'; - map!['ezhreversed'] = 'ƹ'; - map!['ezhtail'] = 'ƺ'; - map!['f'] = 'f'; - map!['fadeva'] = 'फ़'; - map!['fagurmukhi'] = 'ਫ਼'; - map!['fahrenheit'] = '℉'; - map!['fathaarabic'] = 'َ'; - map!['fathalowarabic'] = 'َ'; - map!['fathatanarabic'] = 'ً'; - map!['fbopomofo'] = 'ㄈ'; - map!['fcircle'] = 'ⓕ'; - map!['fdotaccent'] = 'ḟ'; - map!['feharabic'] = 'ف'; - map!['feharmenian'] = 'ֆ'; - map!['fehfinalarabic'] = 'ﻒ'; - map!['fehinitialarabic'] = 'ﻓ'; - map!['fehmedialarabic'] = 'ﻔ'; - map!['feicoptic'] = 'ϥ'; - map!['female'] = '♀'; - map!['ff'] = 'ff'; - map!['ffi'] = 'ffi'; - map!['ffl'] = 'ffl'; - map!['fi'] = 'fi'; - map!['fifteencircle'] = '⑮'; - map!['fifteenparen'] = '⒂'; - map!['fifteenperiod'] = '⒖'; - map!['figuredash'] = '‒'; - map!['filledbox'] = '■'; - map!['filledrect'] = '▬'; - map!['finalkaf'] = 'ך'; - map!['finalkafdagesh'] = 'ךּ'; - map!['finalkafdageshhebrew'] = 'ךּ'; - map!['finalkafhebrew'] = 'ך'; - map!['finalmem'] = 'ם'; - map!['finalmemhebrew'] = 'ם'; - map!['finalnun'] = 'ן'; - map!['finalnunhebrew'] = 'ן'; - map!['finalpe'] = 'ף'; - map!['finalpehebrew'] = 'ף'; - map!['finaltsadi'] = 'ץ'; - map!['finaltsadihebrew'] = 'ץ'; - map!['firsttonechinese'] = 'ˉ'; - map!['fisheye'] = '◉'; - map!['fitacyrillic'] = 'ѳ'; - map!['five'] = '5'; - map!['fivearabic'] = '٥'; - map!['fivebengali'] = '৫'; - map!['fivecircle'] = '⑤'; - map!['fivecircleinversesansserif'] = '➎'; - map!['fivedeva'] = '५'; - map!['fiveeighths'] = '⅝'; - map!['fivegujarati'] = '૫'; - map!['fivegurmukhi'] = '੫'; - map!['fivehackarabic'] = '٥'; - map!['fivehangzhou'] = '〥'; - map!['fiveideographicparen'] = '㈤'; - map!['fiveinferior'] = '₅'; - map!['fivemonospace'] = '5'; - map!['fiveoldstyle'] = ''; - map!['fiveparen'] = '⑸'; - map!['fiveperiod'] = '⒌'; - map!['fivepersian'] = '۵'; - map!['fiveroman'] = 'ⅴ'; - map!['fivesuperior'] = '⁵'; - map!['fivethai'] = '๕'; - map!['fl'] = 'fl'; - map!['florin'] = 'ƒ'; - map!['fmonospace'] = 'f'; - map!['fmsquare'] = '㎙'; - map!['fofanthai'] = 'ฟ'; - map!['fofathai'] = 'ฝ'; - map!['fongmanthai'] = '๏'; - map!['forall'] = '∀'; - map!['four'] = '4'; - map!['fourarabic'] = '٤'; - map!['fourbengali'] = '৪'; - map!['fourcircle'] = '④'; - map!['fourcircleinversesansserif'] = '➍'; - map!['fourdeva'] = '४'; - map!['fourgujarati'] = '૪'; - map!['fourgurmukhi'] = '੪'; - map!['fourhackarabic'] = '٤'; - map!['fourhangzhou'] = '〤'; - map!['fourideographicparen'] = '㈣'; - map!['fourinferior'] = '₄'; - map!['fourmonospace'] = '4'; - map!['fournumeratorbengali'] = '৷'; - map!['fouroldstyle'] = ''; - map!['fourparen'] = '⑷'; - map!['fourperiod'] = '⒋'; - map!['fourpersian'] = '۴'; - map!['fourroman'] = 'ⅳ'; - map!['foursuperior'] = '⁴'; - map!['fourteencircle'] = '⑭'; - map!['fourteenparen'] = '⒁'; - map!['fourteenperiod'] = '⒕'; - map!['fourthai'] = '๔'; - map!['fourthtonechinese'] = 'ˋ'; - map!['fparen'] = '⒡'; - map!['fraction'] = '⁄'; - map!['franc'] = '₣'; - map!['g'] = 'g'; - map!['gabengali'] = 'গ'; - map!['gacute'] = 'ǵ'; - map!['gadeva'] = 'ग'; - map!['gafarabic'] = 'گ'; - map!['gaffinalarabic'] = 'ﮓ'; - map!['gafinitialarabic'] = 'ﮔ'; - map!['gafmedialarabic'] = 'ﮕ'; - map!['gagujarati'] = 'ગ'; - map!['gagurmukhi'] = 'ਗ'; - map!['gahiragana'] = 'が'; - map!['gakatakana'] = 'ガ'; - map!['gamma'] = 'γ'; - map!['gammalatinsmall'] = 'ɣ'; - map!['gammasuperior'] = 'ˠ'; - map!['gangiacoptic'] = 'ϫ'; - map!['gbopomofo'] = 'ㄍ'; - map!['gbreve'] = 'ğ'; - map!['gcaron'] = 'ǧ'; - map!['gcedilla'] = 'ģ'; - map!['gcircle'] = 'ⓖ'; - map!['gcircumflex'] = 'ĝ'; - map!['gcommaaccent'] = 'ģ'; - map!['gdot'] = 'ġ'; - map!['gdotaccent'] = 'ġ'; - map!['gecyrillic'] = 'г'; - map!['gehiragana'] = 'げ'; - map!['gekatakana'] = 'ゲ'; - map!['geometricallyequal'] = '≑'; - map!['gereshaccenthebrew'] = '֜'; - map!['gereshhebrew'] = '׳'; - map!['gereshmuqdamhebrew'] = '֝'; - map!['germandbls'] = 'ß'; - map!['gershayimaccenthebrew'] = '֞'; - map!['gershayimhebrew'] = '״'; - map!['getamark'] = '〓'; - map!['ghabengali'] = 'ঘ'; - map!['ghadarmenian'] = 'ղ'; - map!['ghadeva'] = 'घ'; - map!['ghagujarati'] = 'ઘ'; - map!['ghagurmukhi'] = 'ਘ'; - map!['ghainarabic'] = 'غ'; - map!['ghainfinalarabic'] = 'ﻎ'; - map!['ghaininitialarabic'] = 'ﻏ'; - map!['ghainmedialarabic'] = 'ﻐ'; - map!['ghemiddlehookcyrillic'] = 'ҕ'; - map!['ghestrokecyrillic'] = 'ғ'; - map!['gheupturncyrillic'] = 'ґ'; - map!['ghhadeva'] = 'ग़'; - map!['ghhagurmukhi'] = 'ਗ਼'; - map!['ghook'] = 'ɠ'; - map!['ghzsquare'] = '㎓'; - map!['gihiragana'] = 'ぎ'; - map!['gikatakana'] = 'ギ'; - map!['gimarmenian'] = 'գ'; - map!['gimel'] = 'ג'; - map!['gimeldagesh'] = 'גּ'; - map!['gimeldageshhebrew'] = 'גּ'; - map!['gimelhebrew'] = 'ג'; - map!['gjecyrillic'] = 'ѓ'; - map!['glottalinvertedstroke'] = 'ƾ'; - map!['glottalstop'] = 'ʔ'; - map!['glottalstopinverted'] = 'ʖ'; - map!['glottalstopmod'] = 'ˀ'; - map!['glottalstopreversed'] = 'ʕ'; - map!['glottalstopreversedmod'] = 'ˁ'; - map!['glottalstopreversedsuperior'] = 'ˤ'; - map!['glottalstopstroke'] = 'ʡ'; - map!['glottalstopstrokereversed'] = 'ʢ'; - map!['gmacron'] = 'ḡ'; - map!['gmonospace'] = 'g'; - map!['gohiragana'] = 'ご'; - map!['gokatakana'] = 'ゴ'; - map!['gparen'] = '⒢'; - map!['gpasquare'] = '㎬'; - map!['gradient'] = '∇'; - map!['grave'] = '`'; - map!['gravebelowcmb'] = '̖'; - map!['gravecmb'] = '̀'; - map!['gravecomb'] = '̀'; - map!['gravedeva'] = '॓'; - map!['gravelowmod'] = 'ˎ'; - map!['gravemonospace'] = '`'; - map!['gravetonecmb'] = '̀'; - map!['greater'] = '>'; - map!['greaterequal'] = '≥'; - map!['greaterequalorless'] = '⋛'; - map!['greatermonospace'] = '>'; - map!['greaterorequivalent'] = '≳'; - map!['greaterorless'] = '≷'; - map!['greateroverequal'] = '≧'; - map!['greatersmall'] = '﹥'; - map!['gscript'] = 'ɡ'; - map!['gstroke'] = 'ǥ'; - map!['guhiragana'] = 'ぐ'; - map!['guillemotleft'] = '«'; - map!['guillemotright'] = '»'; - map!['guilsinglleft'] = '‹'; - map!['guilsinglright'] = '›'; - map!['gukatakana'] = 'グ'; - map!['guramusquare'] = '㌘'; - map!['gysquare'] = '㏉'; - map!['h'] = 'h'; - map!['haabkhasiancyrillic'] = 'ҩ'; - map!['haaltonearabic'] = 'ہ'; - map!['habengali'] = 'হ'; - map!['hadescendercyrillic'] = 'ҳ'; - map!['hadeva'] = 'ह'; - map!['hagujarati'] = 'હ'; - map!['hagurmukhi'] = 'ਹ'; - map!['haharabic'] = 'ح'; - map!['hahfinalarabic'] = 'ﺢ'; - map!['hahinitialarabic'] = 'ﺣ'; - map!['hahiragana'] = 'は'; - map!['hahmedialarabic'] = 'ﺤ'; - map!['haitusquare'] = '㌪'; - map!['hakatakana'] = 'ハ'; - map!['hakatakanahalfwidth'] = 'ハ'; - map!['halantgurmukhi'] = '੍'; - map!['hamzaarabic'] = 'ء'; - map!['hamzalowarabic'] = 'ء'; - map!['hangulfiller'] = 'ㅤ'; - map!['hardsigncyrillic'] = 'ъ'; - map!['harpoonleftbarbup'] = '↼'; - map!['harpoonrightbarbup'] = '⇀'; - map!['hasquare'] = '㏊'; - map!['hatafpatah'] = 'ֲ'; - map!['hatafpatah16'] = 'ֲ'; - map!['hatafpatah23'] = 'ֲ'; - map!['hatafpatah2f'] = 'ֲ'; - map!['hatafpatahhebrew'] = 'ֲ'; - map!['hatafpatahnarrowhebrew'] = 'ֲ'; - map!['hatafpatahquarterhebrew'] = 'ֲ'; - map!['hatafpatahwidehebrew'] = 'ֲ'; - map!['hatafqamats'] = 'ֳ'; - map!['hatafqamats1b'] = 'ֳ'; - map!['hatafqamats28'] = 'ֳ'; - map!['hatafqamats34'] = 'ֳ'; - map!['hatafqamatshebrew'] = 'ֳ'; - map!['hatafqamatsnarrowhebrew'] = 'ֳ'; - map!['hatafqamatsquarterhebrew'] = 'ֳ'; - map!['hatafqamatswidehebrew'] = 'ֳ'; - map!['hatafsegol'] = 'ֱ'; - map!['hatafsegol17'] = 'ֱ'; - map!['hatafsegol24'] = 'ֱ'; - map!['hatafsegol30'] = 'ֱ'; - map!['hatafsegolhebrew'] = 'ֱ'; - map!['hatafsegolnarrowhebrew'] = 'ֱ'; - map!['hatafsegolquarterhebrew'] = 'ֱ'; - map!['hatafsegolwidehebrew'] = 'ֱ'; - map!['hbar'] = 'ħ'; - map!['hbopomofo'] = 'ㄏ'; - map!['hbrevebelow'] = 'ḫ'; - map!['hcedilla'] = 'ḩ'; - map!['hcircle'] = 'ⓗ'; - map!['hcircumflex'] = 'ĥ'; - map!['hdieresis'] = 'ḧ'; - map!['hdotaccent'] = 'ḣ'; - map!['hdotbelow'] = 'ḥ'; - map!['he'] = 'ה'; - map!['heart'] = '♥'; - map!['heartsuitblack'] = '♥'; - map!['heartsuitwhite'] = '♡'; - map!['hedagesh'] = 'הּ'; - map!['hedageshhebrew'] = 'הּ'; - map!['hehaltonearabic'] = 'ہ'; - map!['heharabic'] = 'ه'; - map!['hehebrew'] = 'ה'; - map!['hehfinalaltonearabic'] = 'ﮧ'; - map!['hehfinalalttwoarabic'] = 'ﻪ'; - map!['hehfinalarabic'] = 'ﻪ'; - map!['hehhamzaabovefinalarabic'] = 'ﮥ'; - map!['hehhamzaaboveisolatedarabic'] = 'ﮤ'; - map!['hehinitialaltonearabic'] = 'ﮨ'; - map!['hehinitialarabic'] = 'ﻫ'; - map!['hehiragana'] = 'へ'; - map!['hehmedialaltonearabic'] = 'ﮩ'; - map!['hehmedialarabic'] = 'ﻬ'; - map!['heiseierasquare'] = '㍻'; - map!['hekatakana'] = 'ヘ'; - map!['hekatakanahalfwidth'] = 'ヘ'; - map!['hekutaarusquare'] = '㌶'; - map!['henghook'] = 'ɧ'; - map!['herutusquare'] = '㌹'; - map!['het'] = 'ח'; - map!['hethebrew'] = 'ח'; - map!['hhook'] = 'ɦ'; - map!['hhooksuperior'] = 'ʱ'; - map!['hieuhacirclekorean'] = '㉻'; - map!['hieuhaparenkorean'] = '㈛'; - map!['hieuhcirclekorean'] = '㉭'; - map!['hieuhkorean'] = 'ㅎ'; - map!['hieuhparenkorean'] = '㈍'; - map!['hihiragana'] = 'ひ'; - map!['hikatakana'] = 'ヒ'; - map!['hikatakanahalfwidth'] = 'ヒ'; - map!['hiriq'] = 'ִ'; - map!['hiriq14'] = 'ִ'; - map!['hiriq21'] = 'ִ'; - map!['hiriq2d'] = 'ִ'; - map!['hiriqhebrew'] = 'ִ'; - map!['hiriqnarrowhebrew'] = 'ִ'; - map!['hiriqquarterhebrew'] = 'ִ'; - map!['hiriqwidehebrew'] = 'ִ'; - map!['hlinebelow'] = 'ẖ'; - map!['hmonospace'] = 'h'; - map!['hoarmenian'] = 'հ'; - map!['hohipthai'] = 'ห'; - map!['hohiragana'] = 'ほ'; - map!['hokatakana'] = 'ホ'; - map!['hokatakanahalfwidth'] = 'ホ'; - map!['holam'] = 'ֹ'; - map!['holam19'] = 'ֹ'; - map!['holam26'] = 'ֹ'; - map!['holam32'] = 'ֹ'; - map!['holamhebrew'] = 'ֹ'; - map!['holamnarrowhebrew'] = 'ֹ'; - map!['holamquarterhebrew'] = 'ֹ'; - map!['holamwidehebrew'] = 'ֹ'; - map!['honokhukthai'] = 'ฮ'; - map!['hookabovecomb'] = '̉'; - map!['hookcmb'] = '̉'; - map!['hookpalatalizedbelowcmb'] = '̡'; - map!['hookretroflexbelowcmb'] = '̢'; - map!['hoonsquare'] = '㍂'; - map!['horicoptic'] = 'ϩ'; - map!['horizontalbar'] = '―'; - map!['horncmb'] = '̛'; - map!['hotsprings'] = '♨'; - map!['house'] = '⌂'; - map!['hparen'] = '⒣'; - map!['hsuperior'] = 'ʰ'; - map!['hturned'] = 'ɥ'; - map!['huhiragana'] = 'ふ'; - map!['huiitosquare'] = '㌳'; - map!['hukatakana'] = 'フ'; - map!['hukatakanahalfwidth'] = 'フ'; - map!['hungarumlaut'] = '˝'; - map!['hungarumlautcmb'] = '̋'; - map!['hv'] = 'ƕ'; - map!['hyphen'] = '-'; - map!['hypheninferior'] = ''; - map!['hyphenmonospace'] = '-'; - map!['hyphensmall'] = '﹣'; - map!['hyphensuperior'] = ''; - map!['hyphentwo'] = '‐'; - map!['i'] = 'i'; - map!['iacute'] = 'í'; - map!['iacyrillic'] = 'я'; - map!['ibengali'] = 'ই'; - map!['ibopomofo'] = 'ㄧ'; - map!['ibreve'] = 'ĭ'; - map!['icaron'] = 'ǐ'; - map!['icircle'] = 'ⓘ'; - map!['icircumflex'] = 'î'; - map!['icyrillic'] = 'і'; - map!['idblgrave'] = 'ȉ'; - map!['ideographearthcircle'] = '㊏'; - map!['ideographfirecircle'] = '㊋'; - map!['ideographicallianceparen'] = '㈿'; - map!['ideographiccallparen'] = '㈺'; - map!['ideographiccentrecircle'] = '㊥'; - map!['ideographicclose'] = '〆'; - map!['ideographiccomma'] = '、'; - map!['ideographiccommaleft'] = '、'; - map!['ideographiccongratulationparen'] = '㈷'; - map!['ideographiccorrectcircle'] = '㊣'; - map!['ideographicearthparen'] = '㈯'; - map!['ideographicenterpriseparen'] = '㈽'; - map!['ideographicexcellentcircle'] = '㊝'; - map!['ideographicfestivalparen'] = '㉀'; - map!['ideographicfinancialcircle'] = '㊖'; - map!['ideographicfinancialparen'] = '㈶'; - map!['ideographicfireparen'] = '㈫'; - map!['ideographichaveparen'] = '㈲'; - map!['ideographichighcircle'] = '㊤'; - map!['ideographiciterationmark'] = '々'; - map!['ideographiclaborcircle'] = '㊘'; - map!['ideographiclaborparen'] = '㈸'; - map!['ideographicleftcircle'] = '㊧'; - map!['ideographiclowcircle'] = '㊦'; - map!['ideographicmedicinecircle'] = '㊩'; - map!['ideographicmetalparen'] = '㈮'; - map!['ideographicmoonparen'] = '㈪'; - map!['ideographicnameparen'] = '㈴'; - map!['ideographicperiod'] = '。'; - map!['ideographicprintcircle'] = '㊞'; - map!['ideographicreachparen'] = '㉃'; - map!['ideographicrepresentparen'] = '㈹'; - map!['ideographicresourceparen'] = '㈾'; - map!['ideographicrightcircle'] = '㊨'; - map!['ideographicsecretcircle'] = '㊙'; - map!['ideographicselfparen'] = '㉂'; - map!['ideographicsocietyparen'] = '㈳'; - map!['ideographicspace'] = '\u3000'; - map!['ideographicspecialparen'] = '㈵'; - map!['ideographicstockparen'] = '㈱'; - map!['ideographicstudyparen'] = '㈻'; - map!['ideographicsunparen'] = '㈰'; - map!['ideographicsuperviseparen'] = '㈼'; - map!['ideographicwaterparen'] = '㈬'; - map!['ideographicwoodparen'] = '㈭'; - map!['ideographiczero'] = '〇'; - map!['ideographmetalcircle'] = '㊎'; - map!['ideographmooncircle'] = '㊊'; - map!['ideographnamecircle'] = '㊔'; - map!['ideographsuncircle'] = '㊐'; - map!['ideographwatercircle'] = '㊌'; - map!['ideographwoodcircle'] = '㊍'; - map!['ideva'] = 'इ'; - map!['idieresis'] = 'ï'; - map!['idieresisacute'] = 'ḯ'; - map!['idieresiscyrillic'] = 'ӥ'; - map!['idotbelow'] = 'ị'; - map!['iebrevecyrillic'] = 'ӗ'; - map!['iecyrillic'] = 'е'; - map!['ieungacirclekorean'] = '㉵'; - map!['ieungaparenkorean'] = '㈕'; - map!['ieungcirclekorean'] = '㉧'; - map!['ieungkorean'] = 'ㅇ'; - map!['ieungparenkorean'] = '㈇'; - map!['igrave'] = 'ì'; - map!['igujarati'] = 'ઇ'; - map!['igurmukhi'] = 'ਇ'; - map!['ihiragana'] = 'い'; - map!['ihookabove'] = 'ỉ'; - map!['iibengali'] = 'ঈ'; - map!['iicyrillic'] = 'и'; - map!['iideva'] = 'ई'; - map!['iigujarati'] = 'ઈ'; - map!['iigurmukhi'] = 'ਈ'; - map!['iimatragurmukhi'] = 'ੀ'; - map!['iinvertedbreve'] = 'ȋ'; - map!['iishortcyrillic'] = 'й'; - map!['iivowelsignbengali'] = 'ী'; - map!['iivowelsigndeva'] = 'ी'; - map!['iivowelsigngujarati'] = 'ી'; - map!['ij'] = 'ij'; - map!['ikatakana'] = 'イ'; - map!['ikatakanahalfwidth'] = 'イ'; - map!['ikorean'] = 'ㅣ'; - map!['ilde'] = '˜'; - map!['iluyhebrew'] = '֬'; - map!['imacron'] = 'ī'; - map!['imacroncyrillic'] = 'ӣ'; - map!['imageorapproximatelyequal'] = '≓'; - map!['imatragurmukhi'] = 'ਿ'; - map!['imonospace'] = 'i'; - map!['increment'] = '∆'; - map!['infinity'] = '∞'; - map!['iniarmenian'] = 'ի'; - map!['integral'] = '∫'; - map!['integralbottom'] = '⌡'; - map!['integralbt'] = '⌡'; - map!['integralex'] = ''; - map!['integraltop'] = '⌠'; - map!['integraltp'] = '⌠'; - map!['intersection'] = '∩'; - map!['intisquare'] = '㌅'; - map!['invbullet'] = '◘'; - map!['invcircle'] = '◙'; - map!['invsmileface'] = '☻'; - map!['iocyrillic'] = 'ё'; - map!['iogonek'] = 'į'; - map!['iota'] = 'ι'; - map!['iotadieresis'] = 'ϊ'; - map!['iotadieresistonos'] = 'ΐ'; - map!['iotalatin'] = 'ɩ'; - map!['iotatonos'] = 'ί'; - map!['iparen'] = '⒤'; - map!['irigurmukhi'] = 'ੲ'; - map!['ismallhiragana'] = 'ぃ'; - map!['ismallkatakana'] = 'ィ'; - map!['ismallkatakanahalfwidth'] = 'ィ'; - map!['issharbengali'] = '৺'; - map!['istroke'] = 'ɨ'; - map!['isuperior'] = ''; - map!['iterationhiragana'] = 'ゝ'; - map!['iterationkatakana'] = 'ヽ'; - map!['itilde'] = 'ĩ'; - map!['itildebelow'] = 'ḭ'; - map!['iubopomofo'] = 'ㄩ'; - map!['iucyrillic'] = 'ю'; - map!['ivowelsignbengali'] = 'ি'; - map!['ivowelsigndeva'] = 'ि'; - map!['ivowelsigngujarati'] = 'િ'; - map!['izhitsacyrillic'] = 'ѵ'; - map!['izhitsadblgravecyrillic'] = 'ѷ'; - map!['j'] = 'j'; - map!['jaarmenian'] = 'ձ'; - map!['jabengali'] = 'জ'; - map!['jadeva'] = 'ज'; - map!['jagujarati'] = 'જ'; - map!['jagurmukhi'] = 'ਜ'; - map!['jbopomofo'] = 'ㄐ'; - map!['jcaron'] = 'ǰ'; - map!['jcircle'] = 'ⓙ'; - map!['jcircumflex'] = 'ĵ'; - map!['jcrossedtail'] = 'ʝ'; - map!['jdotlessstroke'] = 'ɟ'; - map!['jecyrillic'] = 'ј'; - map!['jeemarabic'] = 'ج'; - map!['jeemfinalarabic'] = 'ﺞ'; - map!['jeeminitialarabic'] = 'ﺟ'; - map!['jeemmedialarabic'] = 'ﺠ'; - map!['jeharabic'] = 'ژ'; - map!['jehfinalarabic'] = 'ﮋ'; - map!['jhabengali'] = 'ঝ'; - map!['jhadeva'] = 'झ'; - map!['jhagujarati'] = 'ઝ'; - map!['jhagurmukhi'] = 'ਝ'; - map!['jheharmenian'] = 'ջ'; - map!['jis'] = '〄'; - map!['jmonospace'] = 'j'; - map!['jparen'] = '⒥'; - map!['jsuperior'] = 'ʲ'; - map!['k'] = 'k'; - map!['kabashkircyrillic'] = 'ҡ'; - map!['kabengali'] = 'ক'; - map!['kacute'] = 'ḱ'; - map!['kacyrillic'] = 'к'; - map!['kadescendercyrillic'] = 'қ'; - map!['kadeva'] = 'क'; - map!['kaf'] = 'כ'; - map!['kafarabic'] = 'ك'; - map!['kafdagesh'] = 'כּ'; - map!['kafdageshhebrew'] = 'כּ'; - map!['kaffinalarabic'] = 'ﻚ'; - map!['kafhebrew'] = 'כ'; - map!['kafinitialarabic'] = 'ﻛ'; - map!['kafmedialarabic'] = 'ﻜ'; - map!['kafrafehebrew'] = 'כֿ'; - map!['kagujarati'] = 'ક'; - map!['kagurmukhi'] = 'ਕ'; - map!['kahiragana'] = 'か'; - map!['kahookcyrillic'] = 'ӄ'; - map!['kakatakana'] = 'カ'; - map!['kakatakanahalfwidth'] = 'カ'; - map!['kappa'] = 'κ'; - map!['kappasymbolgreek'] = 'ϰ'; - map!['kapyeounmieumkorean'] = 'ㅱ'; - map!['kapyeounphieuphkorean'] = 'ㆄ'; - map!['kapyeounpieupkorean'] = 'ㅸ'; - map!['kapyeounssangpieupkorean'] = 'ㅹ'; - map!['karoriisquare'] = '㌍'; - map!['kashidaautoarabic'] = 'ـ'; - map!['kashidaautonosidebearingarabic'] = 'ـ'; - map!['kasmallkatakana'] = 'ヵ'; - map!['kasquare'] = '㎄'; - map!['kasraarabic'] = 'ِ'; - map!['kasratanarabic'] = 'ٍ'; - map!['kastrokecyrillic'] = 'ҟ'; - map!['katahiraprolongmarkhalfwidth'] = 'ー'; - map!['kaverticalstrokecyrillic'] = 'ҝ'; - map!['kbopomofo'] = 'ㄎ'; - map!['kcalsquare'] = '㎉'; - map!['kcaron'] = 'ǩ'; - map!['kcedilla'] = 'ķ'; - map!['kcircle'] = 'ⓚ'; - map!['kcommaaccent'] = 'ķ'; - map!['kdotbelow'] = 'ḳ'; - map!['keharmenian'] = 'ք'; - map!['kehiragana'] = 'け'; - map!['kekatakana'] = 'ケ'; - map!['kekatakanahalfwidth'] = 'ケ'; - map!['kenarmenian'] = 'կ'; - map!['kesmallkatakana'] = 'ヶ'; - map!['kgreenlandic'] = 'ĸ'; - map!['khabengali'] = 'খ'; - map!['khacyrillic'] = 'х'; - map!['khadeva'] = 'ख'; - map!['khagujarati'] = 'ખ'; - map!['khagurmukhi'] = 'ਖ'; - map!['khaharabic'] = 'خ'; - map!['khahfinalarabic'] = 'ﺦ'; - map!['khahinitialarabic'] = 'ﺧ'; - map!['khahmedialarabic'] = 'ﺨ'; - map!['kheicoptic'] = 'ϧ'; - map!['khhadeva'] = 'ख़'; - map!['khhagurmukhi'] = 'ਖ਼'; - map!['khieukhacirclekorean'] = '㉸'; - map!['khieukhaparenkorean'] = '㈘'; - map!['khieukhcirclekorean'] = '㉪'; - map!['khieukhkorean'] = 'ㅋ'; - map!['khieukhparenkorean'] = '㈊'; - map!['khokhaithai'] = 'ข'; - map!['khokhonthai'] = 'ฅ'; - map!['khokhuatthai'] = 'ฃ'; - map!['khokhwaithai'] = 'ค'; - map!['khomutthai'] = '๛'; - map!['khook'] = 'ƙ'; - map!['khorakhangthai'] = 'ฆ'; - map!['khzsquare'] = '㎑'; - map!['kihiragana'] = 'き'; - map!['kikatakana'] = 'キ'; - map!['kikatakanahalfwidth'] = 'キ'; - map!['kiroguramusquare'] = '㌕'; - map!['kiromeetorusquare'] = '㌖'; - map!['kirosquare'] = '㌔'; - map!['kiyeokacirclekorean'] = '㉮'; - map!['kiyeokaparenkorean'] = '㈎'; - map!['kiyeokcirclekorean'] = '㉠'; - map!['kiyeokkorean'] = 'ㄱ'; - map!['kiyeokparenkorean'] = '㈀'; - map!['kiyeoksioskorean'] = 'ㄳ'; - map!['kjecyrillic'] = 'ќ'; - map!['klinebelow'] = 'ḵ'; - map!['klsquare'] = '㎘'; - map!['kmcubedsquare'] = '㎦'; - map!['kmonospace'] = 'k'; - map!['kmsquaredsquare'] = '㎢'; - map!['kohiragana'] = 'こ'; - map!['kohmsquare'] = '㏀'; - map!['kokaithai'] = 'ก'; - map!['kokatakana'] = 'コ'; - map!['kokatakanahalfwidth'] = 'コ'; - map!['kooposquare'] = '㌞'; - map!['koppacyrillic'] = 'ҁ'; - map!['koreanstandardsymbol'] = '㉿'; - map!['koroniscmb'] = '̓'; - map!['kparen'] = '⒦'; - map!['kpasquare'] = '㎪'; - map!['ksicyrillic'] = 'ѯ'; - map!['ktsquare'] = '㏏'; - map!['kturned'] = 'ʞ'; - map!['kuhiragana'] = 'く'; - map!['kukatakana'] = 'ク'; - map!['kukatakanahalfwidth'] = 'ク'; - map!['kvsquare'] = '㎸'; - map!['kwsquare'] = '㎾'; - map!['l'] = 'l'; - map!['labengali'] = 'ল'; - map!['lacute'] = 'ĺ'; - map!['ladeva'] = 'ल'; - map!['lagujarati'] = 'લ'; - map!['lagurmukhi'] = 'ਲ'; - map!['lakkhangyaothai'] = 'ๅ'; - map!['lamaleffinalarabic'] = 'ﻼ'; - map!['lamalefhamzaabovefinalarabic'] = 'ﻸ'; - map!['lamalefhamzaaboveisolatedarabic'] = 'ﻷ'; - map!['lamalefhamzabelowfinalarabic'] = 'ﻺ'; - map!['lamalefhamzabelowisolatedarabic'] = 'ﻹ'; - map!['lamalefisolatedarabic'] = 'ﻻ'; - map!['lamalefmaddaabovefinalarabic'] = 'ﻶ'; - map!['lamalefmaddaaboveisolatedarabic'] = 'ﻵ'; - map!['lamarabic'] = 'ل'; - map!['lambda'] = 'λ'; - map!['lambdastroke'] = 'ƛ'; - map!['lamed'] = 'ל'; - map!['lameddagesh'] = 'לּ'; - map!['lameddageshhebrew'] = 'לּ'; - map!['lamedhebrew'] = 'ל'; - map!['lamfinalarabic'] = 'ﻞ'; - map!['lamhahinitialarabic'] = 'ﳊ'; - map!['laminitialarabic'] = 'ﻟ'; - map!['lamjeeminitialarabic'] = 'ﳉ'; - map!['lamkhahinitialarabic'] = 'ﳋ'; - map!['lamlamhehisolatedarabic'] = 'ﷲ'; - map!['lammedialarabic'] = 'ﻠ'; - map!['lammeemhahinitialarabic'] = 'ﶈ'; - map!['lammeeminitialarabic'] = 'ﳌ'; - map!['largecircle'] = '◯'; - map!['lbar'] = 'ƚ'; - map!['lbelt'] = 'ɬ'; - map!['lbopomofo'] = 'ㄌ'; - map!['lcaron'] = 'ľ'; - map!['lcedilla'] = 'ļ'; - map!['lcircle'] = 'ⓛ'; - map!['lcircumflexbelow'] = 'ḽ'; - map!['lcommaaccent'] = 'ļ'; - map!['ldot'] = 'ŀ'; - map!['ldotaccent'] = 'ŀ'; - map!['ldotbelow'] = 'ḷ'; - map!['ldotbelowmacron'] = 'ḹ'; - map!['leftangleabovecmb'] = '̚'; - map!['lefttackbelowcmb'] = '̘'; - map!['less'] = '<'; - map!['lessequal'] = '≤'; - map!['lessequalorgreater'] = '⋚'; - map!['lessmonospace'] = '<'; - map!['lessorequivalent'] = '≲'; - map!['lessorgreater'] = '≶'; - map!['lessoverequal'] = '≦'; - map!['lesssmall'] = '﹤'; - map!['lezh'] = 'ɮ'; - map!['lfblock'] = '▌'; - map!['lhookretroflex'] = 'ɭ'; - map!['lira'] = '₤'; - map!['liwnarmenian'] = 'լ'; - map!['lj'] = 'lj'; - map!['ljecyrillic'] = 'љ'; - map!['ll'] = ''; - map!['lladeva'] = 'ळ'; - map!['llagujarati'] = 'ળ'; - map!['llinebelow'] = 'ḻ'; - map!['llladeva'] = 'ऴ'; - map!['llvocalicbengali'] = 'ৡ'; - map!['llvocalicdeva'] = 'ॡ'; - map!['llvocalicvowelsignbengali'] = 'ৣ'; - map!['llvocalicvowelsigndeva'] = 'ॣ'; - map!['lmiddletilde'] = 'ɫ'; - map!['lmonospace'] = 'l'; - map!['lmsquare'] = '㏐'; - map!['lochulathai'] = 'ฬ'; - map!['logicaland'] = '∧'; - map!['logicalnot'] = '¬'; - map!['logicalnotreversed'] = '⌐'; - map!['logicalor'] = '∨'; - map!['lolingthai'] = 'ล'; - map!['longs'] = 'ſ'; - map!['lowlinecenterline'] = '﹎'; - map!['lowlinecmb'] = '̲'; - map!['lowlinedashed'] = '﹍'; - map!['lozenge'] = '◊'; - map!['lparen'] = '⒧'; - map!['lslash'] = 'ł'; - map!['lsquare'] = 'ℓ'; - map!['lsuperior'] = ''; - map!['ltshade'] = '░'; - map!['luthai'] = 'ฦ'; - map!['lvocalicbengali'] = 'ঌ'; - map!['lvocalicdeva'] = 'ऌ'; - map!['lvocalicvowelsignbengali'] = 'ৢ'; - map!['lvocalicvowelsigndeva'] = 'ॢ'; - map!['lxsquare'] = '㏓'; - map!['m'] = 'm'; - map!['mabengali'] = 'ম'; - map!['macron'] = '¯'; - map!['macronbelowcmb'] = '̱'; - map!['macroncmb'] = '̄'; - map!['macronlowmod'] = 'ˍ'; - map!['macronmonospace'] = ' ̄'; - map!['macute'] = 'ḿ'; - map!['madeva'] = 'म'; - map!['magujarati'] = 'મ'; - map!['magurmukhi'] = 'ਮ'; - map!['mahapakhhebrew'] = '֤'; - map!['mahapakhlefthebrew'] = '֤'; - map!['mahiragana'] = 'ま'; - map!['maichattawalowleftthai'] = ''; - map!['maichattawalowrightthai'] = ''; - map!['maichattawathai'] = '๋'; - map!['maichattawaupperleftthai'] = ''; - map!['maieklowleftthai'] = ''; - map!['maieklowrightthai'] = ''; - map!['maiekthai'] = '่'; - map!['maiekupperleftthai'] = ''; - map!['maihanakatleftthai'] = ''; - map!['maihanakatthai'] = 'ั'; - map!['maitaikhuleftthai'] = ''; - map!['maitaikhuthai'] = '็'; - map!['maitholowleftthai'] = ''; - map!['maitholowrightthai'] = ''; - map!['maithothai'] = '้'; - map!['maithoupperleftthai'] = ''; - map!['maitrilowleftthai'] = ''; - map!['maitrilowrightthai'] = ''; - map!['maitrithai'] = '๊'; - map!['maitriupperleftthai'] = ''; - map!['maiyamokthai'] = 'ๆ'; - map!['makatakana'] = 'マ'; - map!['makatakanahalfwidth'] = 'マ'; - map!['male'] = '♂'; - map!['mansyonsquare'] = '㍇'; - map!['maqafhebrew'] = '־'; - map!['mars'] = '♂'; - map!['masoracirclehebrew'] = '֯'; - map!['masquare'] = '㎃'; - map!['mbopomofo'] = 'ㄇ'; - map!['mbsquare'] = '㏔'; - map!['mcircle'] = 'ⓜ'; - map!['mcubedsquare'] = '㎥'; - map!['mdotaccent'] = 'ṁ'; - map!['mdotbelow'] = 'ṃ'; - map!['meemarabic'] = 'م'; - map!['meemfinalarabic'] = 'ﻢ'; - map!['meeminitialarabic'] = 'ﻣ'; - map!['meemmedialarabic'] = 'ﻤ'; - map!['meemmeeminitialarabic'] = 'ﳑ'; - map!['meemmeemisolatedarabic'] = 'ﱈ'; - map!['meetorusquare'] = '㍍'; - map!['mehiragana'] = 'め'; - map!['meizierasquare'] = '㍾'; - map!['mekatakana'] = 'メ'; - map!['mekatakanahalfwidth'] = 'メ'; - map!['mem'] = 'מ'; - map!['memdagesh'] = 'מּ'; - map!['memdageshhebrew'] = 'מּ'; - map!['memhebrew'] = 'מ'; - map!['menarmenian'] = 'մ'; - map!['merkhahebrew'] = '֥'; - map!['merkhakefulahebrew'] = '֦'; - map!['merkhakefulalefthebrew'] = '֦'; - map!['merkhalefthebrew'] = '֥'; - map!['mhook'] = 'ɱ'; - map!['mhzsquare'] = '㎒'; - map!['middledotkatakanahalfwidth'] = '・'; - map!['middot'] = '·'; - map!['mieumacirclekorean'] = '㉲'; - map!['mieumaparenkorean'] = '㈒'; - map!['mieumcirclekorean'] = '㉤'; - map!['mieumkorean'] = 'ㅁ'; - map!['mieumpansioskorean'] = 'ㅰ'; - map!['mieumparenkorean'] = '㈄'; - map!['mieumpieupkorean'] = 'ㅮ'; - map!['mieumsioskorean'] = 'ㅯ'; - map!['mihiragana'] = 'み'; - map!['mikatakana'] = 'ミ'; - map!['mikatakanahalfwidth'] = 'ミ'; - map!['negationslash'] = '-'; - map!['minus'] = '−'; - map!['minusbelowcmb'] = '̠'; - map!['minuscircle'] = '⊖'; - map!['minusmod'] = '˗'; - map!['minusplus'] = '∓'; - map!['minute'] = '′'; - map!['miribaarusquare'] = '㍊'; - map!['mirisquare'] = '㍉'; - map!['mlonglegturned'] = 'ɰ'; - map!['mlsquare'] = '㎖'; - map!['mmcubedsquare'] = '㎣'; - map!['mmonospace'] = 'm'; - map!['mmsquaredsquare'] = '㎟'; - map!['mohiragana'] = 'も'; - map!['mohmsquare'] = '㏁'; - map!['mokatakana'] = 'モ'; - map!['mokatakanahalfwidth'] = 'モ'; - map!['molsquare'] = '㏖'; - map!['momathai'] = 'ม'; - map!['moverssquare'] = '㎧'; - map!['moverssquaredsquare'] = '㎨'; - map!['mparen'] = '⒨'; - map!['mpasquare'] = '㎫'; - map!['mssquare'] = '㎳'; - map!['msuperior'] = ''; - map!['mturned'] = 'ɯ'; - map!['mu'] = 'µ'; - map!['mu1'] = 'µ'; - map!['muasquare'] = '㎂'; - map!['muchgreater'] = '≫'; - map!['muchless'] = '≪'; - map!['mufsquare'] = '㎌'; - map!['mugreek'] = 'μ'; - map!['mugsquare'] = '㎍'; - map!['muhiragana'] = 'む'; - map!['mukatakana'] = 'ム'; - map!['mukatakanahalfwidth'] = 'ム'; - map!['mulsquare'] = '㎕'; - map!['multiply'] = '×'; - map!['mumsquare'] = '㎛'; - map!['munahhebrew'] = '֣'; - map!['munahlefthebrew'] = '֣'; - map!['musicalnote'] = '♪'; - map!['musicalnotedbl'] = '♫'; - map!['musicflatsign'] = '♭'; - map!['musicsharpsign'] = '♯'; - map!['mussquare'] = '㎲'; - map!['muvsquare'] = '㎶'; - map!['muwsquare'] = '㎼'; - map!['mvmegasquare'] = '㎹'; - map!['mvsquare'] = '㎷'; - map!['mwmegasquare'] = '㎿'; - map!['mwsquare'] = '㎽'; - map!['n'] = 'n'; - map!['nabengali'] = 'ন'; - map!['nabla'] = '∇'; - map!['nacute'] = 'ń'; - map!['nadeva'] = 'न'; - map!['nagujarati'] = 'ન'; - map!['nagurmukhi'] = 'ਨ'; - map!['nahiragana'] = 'な'; - map!['nakatakana'] = 'ナ'; - map!['nakatakanahalfwidth'] = 'ナ'; - map!['napostrophe'] = 'ʼn'; - map!['nasquare'] = '㎁'; - map!['nbopomofo'] = 'ㄋ'; - map!['nbspace'] = '\u00a0'; - map!['ncaron'] = 'ň'; - map!['ncedilla'] = 'ņ'; - map!['ncircle'] = 'ⓝ'; - map!['ncircumflexbelow'] = 'ṋ'; - map!['ncommaaccent'] = 'ņ'; - map!['ndotaccent'] = 'ṅ'; - map!['ndotbelow'] = 'ṇ'; - map!['nehiragana'] = 'ね'; - map!['nekatakana'] = 'ネ'; - map!['nekatakanahalfwidth'] = 'ネ'; - map!['newsheqelsign'] = '₪'; - map!['nfsquare'] = '㎋'; - map!['ngabengali'] = 'ঙ'; - map!['ngadeva'] = 'ङ'; - map!['ngagujarati'] = 'ઙ'; - map!['ngagurmukhi'] = 'ਙ'; - map!['ngonguthai'] = 'ง'; - map!['nhiragana'] = 'ん'; - map!['nhookleft'] = 'ɲ'; - map!['nhookretroflex'] = 'ɳ'; - map!['nieunacirclekorean'] = '㉯'; - map!['nieunaparenkorean'] = '㈏'; - map!['nieuncieuckorean'] = 'ㄵ'; - map!['nieuncirclekorean'] = '㉡'; - map!['nieunhieuhkorean'] = 'ㄶ'; - map!['nieunkorean'] = 'ㄴ'; - map!['nieunpansioskorean'] = 'ㅨ'; - map!['nieunparenkorean'] = '㈁'; - map!['nieunsioskorean'] = 'ㅧ'; - map!['nieuntikeutkorean'] = 'ㅦ'; - map!['nihiragana'] = 'に'; - map!['nikatakana'] = 'ニ'; - map!['nikatakanahalfwidth'] = 'ニ'; - map!['nikhahitleftthai'] = ''; - map!['nikhahitthai'] = 'ํ'; - map!['nine'] = '9'; - map!['ninearabic'] = '٩'; - map!['ninebengali'] = '৯'; - map!['ninecircle'] = '⑨'; - map!['ninecircleinversesansserif'] = '➒'; - map!['ninedeva'] = '९'; - map!['ninegujarati'] = '૯'; - map!['ninegurmukhi'] = '੯'; - map!['ninehackarabic'] = '٩'; - map!['ninehangzhou'] = '〩'; - map!['nineideographicparen'] = '㈨'; - map!['nineinferior'] = '₉'; - map!['ninemonospace'] = '9'; - map!['nineoldstyle'] = ''; - map!['nineparen'] = '⑼'; - map!['nineperiod'] = '⒐'; - map!['ninepersian'] = '۹'; - map!['nineroman'] = 'ⅸ'; - map!['ninesuperior'] = '⁹'; - map!['nineteencircle'] = '⑲'; - map!['nineteenparen'] = '⒆'; - map!['nineteenperiod'] = '⒚'; - map!['ninethai'] = '๙'; - map!['nj'] = 'nj'; - map!['njecyrillic'] = 'њ'; - map!['nkatakana'] = 'ン'; - map!['nkatakanahalfwidth'] = 'ン'; - map!['nlegrightlong'] = 'ƞ'; - map!['nlinebelow'] = 'ṉ'; - map!['nmonospace'] = 'n'; - map!['nmsquare'] = '㎚'; - map!['nnabengali'] = 'ণ'; - map!['nnadeva'] = 'ण'; - map!['nnagujarati'] = 'ણ'; - map!['nnagurmukhi'] = 'ਣ'; - map!['nnnadeva'] = 'ऩ'; - map!['nohiragana'] = 'の'; - map!['nokatakana'] = 'ノ'; - map!['nokatakanahalfwidth'] = 'ノ'; - map!['nonbreakingspace'] = '\u00a0'; - map!['nonenthai'] = 'ณ'; - map!['nonuthai'] = 'น'; - map!['noonarabic'] = 'ن'; - map!['noonfinalarabic'] = 'ﻦ'; - map!['noonghunnaarabic'] = 'ں'; - map!['noonghunnafinalarabic'] = 'ﮟ'; - map!['nooninitialarabic'] = 'ﻧ'; - map!['noonjeeminitialarabic'] = 'ﳒ'; - map!['noonjeemisolatedarabic'] = 'ﱋ'; - map!['noonmedialarabic'] = 'ﻨ'; - map!['noonmeeminitialarabic'] = 'ﳕ'; - map!['noonmeemisolatedarabic'] = 'ﱎ'; - map!['noonnoonfinalarabic'] = 'ﲍ'; - map!['notcontains'] = '∌'; - map!['notelement'] = '∉'; - map!['notelementof'] = '∉'; - map!['notequal'] = '≠'; - map!['notgreater'] = '≯'; - map!['notgreaternorequal'] = '≱'; - map!['notgreaternorless'] = '≹'; - map!['notidentical'] = '≢'; - map!['notless'] = '≮'; - map!['notlessnorequal'] = '≰'; - map!['notparallel'] = '∦'; - map!['notprecedes'] = '⊀'; - map!['notsubset'] = '⊄'; - map!['notsucceeds'] = '⊁'; - map!['notsuperset'] = '⊅'; - map!['nowarmenian'] = 'ն'; - map!['nparen'] = '⒩'; - map!['nssquare'] = '㎱'; - map!['nsuperior'] = 'ⁿ'; - map!['ntilde'] = 'ñ'; - map!['nu'] = 'ν'; - map!['nuhiragana'] = 'ぬ'; - map!['nukatakana'] = 'ヌ'; - map!['nukatakanahalfwidth'] = 'ヌ'; - map!['nuktabengali'] = '়'; - map!['nuktadeva'] = '़'; - map!['nuktagujarati'] = '઼'; - map!['nuktagurmukhi'] = '਼'; - map!['numbersign'] = '#'; - map!['numbersignmonospace'] = '#'; - map!['numbersignsmall'] = '﹟'; - map!['numeralsigngreek'] = 'ʹ'; - map!['numeralsignlowergreek'] = '͵'; - map!['numero'] = '№'; - map!['nun'] = 'נ'; - map!['nundagesh'] = 'נּ'; - map!['nundageshhebrew'] = 'נּ'; - map!['nunhebrew'] = 'נ'; - map!['nvsquare'] = '㎵'; - map!['nwsquare'] = '㎻'; - map!['nyabengali'] = 'ঞ'; - map!['nyadeva'] = 'ञ'; - map!['nyagujarati'] = 'ઞ'; - map!['nyagurmukhi'] = 'ਞ'; - map!['o'] = 'o'; - map!['oacute'] = 'ó'; - map!['oangthai'] = 'อ'; - map!['obarred'] = 'ɵ'; - map!['obarredcyrillic'] = 'ө'; - map!['obarreddieresiscyrillic'] = 'ӫ'; - map!['obengali'] = 'ও'; - map!['obopomofo'] = 'ㄛ'; - map!['obreve'] = 'ŏ'; - map!['ocandradeva'] = 'ऑ'; - map!['ocandragujarati'] = 'ઑ'; - map!['ocandravowelsigndeva'] = 'ॉ'; - map!['ocandravowelsigngujarati'] = 'ૉ'; - map!['ocaron'] = 'ǒ'; - map!['ocircle'] = 'ⓞ'; - map!['ocircumflex'] = 'ô'; - map!['ocircumflexacute'] = 'ố'; - map!['ocircumflexdotbelow'] = 'ộ'; - map!['ocircumflexgrave'] = 'ồ'; - map!['ocircumflexhookabove'] = 'ổ'; - map!['ocircumflextilde'] = 'ỗ'; - map!['ocyrillic'] = 'о'; - map!['odblacute'] = 'ő'; - map!['odblgrave'] = 'ȍ'; - map!['odeva'] = 'ओ'; - map!['odieresis'] = 'ö'; - map!['odieresiscyrillic'] = 'ӧ'; - map!['odotbelow'] = 'ọ'; - map!['oe'] = 'œ'; - map!['oekorean'] = 'ㅚ'; - map!['ogonek'] = '˛'; - map!['ogonekcmb'] = '̨'; - map!['ograve'] = 'ò'; - map!['ogujarati'] = 'ઓ'; - map!['oharmenian'] = 'օ'; - map!['ohiragana'] = 'お'; - map!['ohookabove'] = 'ỏ'; - map!['ohorn'] = 'ơ'; - map!['ohornacute'] = 'ớ'; - map!['ohorndotbelow'] = 'ợ'; - map!['ohorngrave'] = 'ờ'; - map!['ohornhookabove'] = 'ở'; - map!['ohorntilde'] = 'ỡ'; - map!['ohungarumlaut'] = 'ő'; - map!['oi'] = 'ƣ'; - map!['oinvertedbreve'] = 'ȏ'; - map!['okatakana'] = 'オ'; - map!['okatakanahalfwidth'] = 'オ'; - map!['okorean'] = 'ㅗ'; - map!['olehebrew'] = '֫'; - map!['omacron'] = 'ō'; - map!['omacronacute'] = 'ṓ'; - map!['omacrongrave'] = 'ṑ'; - map!['omdeva'] = 'ॐ'; - map!['omega'] = 'ω'; - map!['omega1'] = 'ϖ'; - map!['omegacyrillic'] = 'ѡ'; - map!['omegalatinclosed'] = 'ɷ'; - map!['omegaroundcyrillic'] = 'ѻ'; - map!['omegatitlocyrillic'] = 'ѽ'; - map!['omegatonos'] = 'ώ'; - map!['omgujarati'] = 'ૐ'; - map!['omicron'] = 'ο'; - map!['omicrontonos'] = 'ό'; - map!['omonospace'] = 'o'; - map!['one'] = '1'; - map!['onearabic'] = '١'; - map!['onebengali'] = '১'; - map!['onecircle'] = '①'; - map!['onecircleinversesansserif'] = '➊'; - map!['onedeva'] = '१'; - map!['onedotenleader'] = '․'; - map!['oneeighth'] = '⅛'; - map!['onefitted'] = ''; - map!['onegujarati'] = '૧'; - map!['onegurmukhi'] = '੧'; - map!['onehackarabic'] = '١'; - map!['onehalf'] = '½'; - map!['onehangzhou'] = '〡'; - map!['oneideographicparen'] = '㈠'; - map!['oneinferior'] = '₁'; - map!['onemonospace'] = '1'; - map!['onenumeratorbengali'] = '৴'; - map!['oneoldstyle'] = ''; - map!['oneparen'] = '⑴'; - map!['oneperiod'] = '⒈'; - map!['onepersian'] = '۱'; - map!['onequarter'] = '¼'; - map!['oneroman'] = 'ⅰ'; - map!['onesuperior'] = '¹'; - map!['onethai'] = '๑'; - map!['onethird'] = '⅓'; - map!['oogonek'] = 'ǫ'; - map!['oogonekmacron'] = 'ǭ'; - map!['oogurmukhi'] = 'ਓ'; - map!['oomatragurmukhi'] = 'ੋ'; - map!['oopen'] = 'ɔ'; - map!['oparen'] = '⒪'; - map!['openbullet'] = '◦'; - map!['option'] = '⌥'; - map!['ordfeminine'] = 'ª'; - map!['ordmasculine'] = 'º'; - map!['orthogonal'] = '∟'; - map!['oshortdeva'] = 'ऒ'; - map!['oshortvowelsigndeva'] = 'ॊ'; - map!['oslash'] = 'ø'; - map!['oslashacute'] = 'ǿ'; - map!['osmallhiragana'] = 'ぉ'; - map!['osmallkatakana'] = 'ォ'; - map!['osmallkatakanahalfwidth'] = 'ォ'; - map!['ostrokeacute'] = 'ǿ'; - map!['osuperior'] = ''; - map!['otcyrillic'] = 'ѿ'; - map!['otilde'] = 'õ'; - map!['otildeacute'] = 'ṍ'; - map!['otildedieresis'] = 'ṏ'; - map!['oubopomofo'] = 'ㄡ'; - map!['overline'] = '‾'; - map!['overlinecenterline'] = '﹊'; - map!['overlinecmb'] = '̅'; - map!['overlinedashed'] = '﹉'; - map!['overlinedblwavy'] = '﹌'; - map!['overlinewavy'] = '﹋'; - map!['overscore'] = '¯'; - map!['ovowelsignbengali'] = 'ো'; - map!['ovowelsigndeva'] = 'ो'; - map!['ovowelsigngujarati'] = 'ો'; - map!['p'] = 'p'; - map!['paampssquare'] = '㎀'; - map!['paasentosquare'] = '㌫'; - map!['pabengali'] = 'প'; - map!['pacute'] = 'ṕ'; - map!['padeva'] = 'प'; - map!['pagedown'] = '⇟'; - map!['pageup'] = '⇞'; - map!['pagujarati'] = 'પ'; - map!['pagurmukhi'] = 'ਪ'; - map!['pahiragana'] = 'ぱ'; - map!['paiyannoithai'] = 'ฯ'; - map!['pakatakana'] = 'パ'; - map!['palatalizationcyrilliccmb'] = '҄'; - map!['palochkacyrillic'] = 'Ӏ'; - map!['pansioskorean'] = 'ㅿ'; - map!['paragraph'] = '¶'; - map!['parallel'] = '∥'; - map!['parenleft'] = '('; - map!['parenleftaltonearabic'] = '﴾'; - map!['parenleftbt'] = ''; - map!['parenleftex'] = ''; - map!['parenleftinferior'] = '₍'; - map!['parenleftmonospace'] = '('; - map!['parenleftsmall'] = '﹙'; - map!['parenleftsuperior'] = '⁽'; - map!['parenlefttp'] = ''; - map!['parenleftvertical'] = '︵'; - map!['parenright'] = ')'; - map!['parenrightaltonearabic'] = '﴿'; - map!['parenrightbt'] = ''; - map!['parenrightex'] = ''; - map!['parenrightinferior'] = '₎'; - map!['parenrightmonospace'] = ')'; - map!['parenrightsmall'] = '﹚'; - map!['parenrightsuperior'] = '⁾'; - map!['parenrighttp'] = ''; - map!['parenrightvertical'] = '︶'; - map!['partialdiff'] = '∂'; - map!['paseqhebrew'] = '׀'; - map!['pashtahebrew'] = '֙'; - map!['pasquare'] = '㎩'; - map!['patah'] = 'ַ'; - map!['patah11'] = 'ַ'; - map!['patah1d'] = 'ַ'; - map!['patah2a'] = 'ַ'; - map!['patahhebrew'] = 'ַ'; - map!['patahnarrowhebrew'] = 'ַ'; - map!['patahquarterhebrew'] = 'ַ'; - map!['patahwidehebrew'] = 'ַ'; - map!['pazerhebrew'] = '֡'; - map!['pbopomofo'] = 'ㄆ'; - map!['pcircle'] = 'ⓟ'; - map!['pdotaccent'] = 'ṗ'; - map!['pe'] = 'פ'; - map!['pecyrillic'] = 'п'; - map!['pedagesh'] = 'פּ'; - map!['pedageshhebrew'] = 'פּ'; - map!['peezisquare'] = '㌻'; - map!['pefinaldageshhebrew'] = 'ףּ'; - map!['peharabic'] = 'پ'; - map!['peharmenian'] = 'պ'; - map!['pehebrew'] = 'פ'; - map!['pehfinalarabic'] = 'ﭗ'; - map!['pehinitialarabic'] = 'ﭘ'; - map!['pehiragana'] = 'ぺ'; - map!['pehmedialarabic'] = 'ﭙ'; - map!['pekatakana'] = 'ペ'; - map!['pemiddlehookcyrillic'] = 'ҧ'; - map!['perafehebrew'] = 'פֿ'; - map!['percent'] = '%'; - map!['percentarabic'] = '٪'; - map!['percentmonospace'] = '%'; - map!['percentsmall'] = '﹪'; - map!['period'] = '.'; - map!['periodarmenian'] = '։'; - map!['periodcentered'] = '·'; - map!['periodhalfwidth'] = '。'; - map!['periodinferior'] = ''; - map!['periodmonospace'] = '.'; - map!['periodsmall'] = '﹒'; - map!['periodsuperior'] = ''; - map!['perispomenigreekcmb'] = '͂'; - map!['perpendicular'] = '⊥'; - map!['perthousand'] = '‰'; - map!['peseta'] = '₧'; - map!['pfsquare'] = '㎊'; - map!['phabengali'] = 'ফ'; - map!['phadeva'] = 'फ'; - map!['phagujarati'] = 'ફ'; - map!['phagurmukhi'] = 'ਫ'; - map!['phi'] = 'φ'; - map!['phi1'] = 'ϕ'; - map!['phieuphacirclekorean'] = '㉺'; - map!['phieuphaparenkorean'] = '㈚'; - map!['phieuphcirclekorean'] = '㉬'; - map!['phieuphkorean'] = 'ㅍ'; - map!['phieuphparenkorean'] = '㈌'; - map!['philatin'] = 'ɸ'; - map!['phinthuthai'] = 'ฺ'; - map!['phisymbolgreek'] = 'ϕ'; - map!['phook'] = 'ƥ'; - map!['phophanthai'] = 'พ'; - map!['phophungthai'] = 'ผ'; - map!['phosamphaothai'] = 'ภ'; - map!['pi'] = 'π'; - map!['pieupacirclekorean'] = '㉳'; - map!['pieupaparenkorean'] = '㈓'; - map!['pieupcieuckorean'] = 'ㅶ'; - map!['pieupcirclekorean'] = '㉥'; - map!['pieupkiyeokkorean'] = 'ㅲ'; - map!['pieupkorean'] = 'ㅂ'; - map!['pieupparenkorean'] = '㈅'; - map!['pieupsioskiyeokkorean'] = 'ㅴ'; - map!['pieupsioskorean'] = 'ㅄ'; - map!['pieupsiostikeutkorean'] = 'ㅵ'; - map!['pieupthieuthkorean'] = 'ㅷ'; - map!['pieuptikeutkorean'] = 'ㅳ'; - map!['pihiragana'] = 'ぴ'; - map!['pikatakana'] = 'ピ'; - map!['pisymbolgreek'] = 'ϖ'; - map!['piwrarmenian'] = 'փ'; - map!['plus'] = '+'; - map!['plusbelowcmb'] = '̟'; - map!['pluscircle'] = '⊕'; - map!['plusminus'] = '±'; - map!['plusmod'] = '˖'; - map!['plusmonospace'] = '+'; - map!['plussmall'] = '﹢'; - map!['plussuperior'] = '⁺'; - map!['pmonospace'] = 'p'; - map!['pmsquare'] = '㏘'; - map!['pohiragana'] = 'ぽ'; - map!['pointingindexdownwhite'] = '☟'; - map!['pointingindexleftwhite'] = '☜'; - map!['pointingindexrightwhite'] = '☞'; - map!['pointingindexupwhite'] = '☝'; - map!['pokatakana'] = 'ポ'; - map!['poplathai'] = 'ป'; - map!['postalmark'] = '〒'; - map!['postalmarkface'] = '〠'; - map!['pparen'] = '⒫'; - map!['precedes'] = '≺'; - map!['prescription'] = '℞'; - map!['primemod'] = 'ʹ'; - map!['primereversed'] = '‵'; - map!['product'] = '∏'; - map!['projective'] = '⌅'; - map!['prolongedkana'] = 'ー'; - map!['propellor'] = '⌘'; - map!['propersubset'] = '⊂'; - map!['propersuperset'] = '⊃'; - map!['proportion'] = '∷'; - map!['proportional'] = '∝'; - map!['psi'] = 'ψ'; - map!['psicyrillic'] = 'ѱ'; - map!['psilipneumatacyrilliccmb'] = '҆'; - map!['pssquare'] = '㎰'; - map!['puhiragana'] = 'ぷ'; - map!['pukatakana'] = 'プ'; - map!['pvsquare'] = '㎴'; - map!['pwsquare'] = '㎺'; - map!['q'] = 'q'; - map!['qadeva'] = 'क़'; - map!['qadmahebrew'] = '֨'; - map!['qafarabic'] = 'ق'; - map!['qaffinalarabic'] = 'ﻖ'; - map!['qafinitialarabic'] = 'ﻗ'; - map!['qafmedialarabic'] = 'ﻘ'; - map!['qamats'] = 'ָ'; - map!['qamats10'] = 'ָ'; - map!['qamats1a'] = 'ָ'; - map!['qamats1c'] = 'ָ'; - map!['qamats27'] = 'ָ'; - map!['qamats29'] = 'ָ'; - map!['qamats33'] = 'ָ'; - map!['qamatsde'] = 'ָ'; - map!['qamatshebrew'] = 'ָ'; - map!['qamatsnarrowhebrew'] = 'ָ'; - map!['qamatsqatanhebrew'] = 'ָ'; - map!['qamatsqatannarrowhebrew'] = 'ָ'; - map!['qamatsqatanquarterhebrew'] = 'ָ'; - map!['qamatsqatanwidehebrew'] = 'ָ'; - map!['qamatsquarterhebrew'] = 'ָ'; - map!['qamatswidehebrew'] = 'ָ'; - map!['qarneyparahebrew'] = '֟'; - map!['qbopomofo'] = 'ㄑ'; - map!['qcircle'] = 'ⓠ'; - map!['qhook'] = 'ʠ'; - map!['qmonospace'] = 'q'; - map!['qof'] = 'ק'; - map!['qofdagesh'] = 'קּ'; - map!['qofdageshhebrew'] = 'קּ'; - map!['qparen'] = '⒬'; - map!['quarternote'] = '♩'; - map!['qubuts'] = 'ֻ'; - map!['qubuts18'] = 'ֻ'; - map!['qubuts25'] = 'ֻ'; - map!['qubuts31'] = 'ֻ'; - map!['qubutshebrew'] = 'ֻ'; - map!['qubutsnarrowhebrew'] = 'ֻ'; - map!['qubutsquarterhebrew'] = 'ֻ'; - map!['qubutswidehebrew'] = 'ֻ'; - map!['question'] = '?'; - map!['questionarabic'] = '؟'; - map!['questionarmenian'] = '՞'; - map!['questiondown'] = '¿'; - map!['questiondownsmall'] = ''; - map!['questiongreek'] = ';'; - map!['questionmonospace'] = '?'; - map!['questionsmall'] = ''; - map!['quotedbl'] = '"'; - map!['quotedblbase'] = '„'; - map!['quotedblleft'] = '“'; - map!['quotedblmonospace'] = '"'; - map!['quotedblprime'] = '〞'; - map!['quotedblprimereversed'] = '〝'; - map!['quotedblright'] = '”'; - map!['quoteleft'] = '‘'; - map!['quoteleftreversed'] = '‛'; - map!['quotereversed'] = '‛'; - map!['quoteright'] = '’'; - map!['quoterightn'] = 'ʼn'; - map!['quotesinglbase'] = '‚'; - map!['quotesingle'] = "'"; - map!['quotesinglemonospace'] = '''; - map!['r'] = 'r'; - map!['raarmenian'] = 'ռ'; - map!['rabengali'] = 'র'; - map!['racute'] = 'ŕ'; - map!['radeva'] = 'र'; - map!['radical'] = '√'; - map!['radicalex'] = ''; - map!['radoverssquare'] = '㎮'; - map!['radoverssquaredsquare'] = '㎯'; - map!['radsquare'] = '㎭'; - map!['rafe'] = 'ֿ'; - map!['rafehebrew'] = 'ֿ'; - map!['ragujarati'] = 'ર'; - map!['ragurmukhi'] = 'ਰ'; - map!['rahiragana'] = 'ら'; - map!['rakatakana'] = 'ラ'; - map!['rakatakanahalfwidth'] = 'ラ'; - map!['ralowerdiagonalbengali'] = 'ৱ'; - map!['ramiddlediagonalbengali'] = 'ৰ'; - map!['ramshorn'] = 'ɤ'; - map!['ratio'] = '∶'; - map!['rbopomofo'] = 'ㄖ'; - map!['rcaron'] = 'ř'; - map!['rcedilla'] = 'ŗ'; - map!['rcircle'] = 'ⓡ'; - map!['rcommaaccent'] = 'ŗ'; - map!['rdblgrave'] = 'ȑ'; - map!['rdotaccent'] = 'ṙ'; - map!['rdotbelow'] = 'ṛ'; - map!['rdotbelowmacron'] = 'ṝ'; - map!['referencemark'] = '※'; - map!['reflexsubset'] = '⊆'; - map!['reflexsuperset'] = '⊇'; - map!['registered'] = '®'; - map!['registersans'] = ''; - map!['registerserif'] = ''; - map!['reharabic'] = 'ر'; - map!['reharmenian'] = 'ր'; - map!['rehfinalarabic'] = 'ﺮ'; - map!['rehiragana'] = 'れ'; - map!['rekatakana'] = 'レ'; - map!['rekatakanahalfwidth'] = 'レ'; - map!['resh'] = 'ר'; - map!['reshdageshhebrew'] = 'רּ'; - map!['reshhebrew'] = 'ר'; - map!['reversedtilde'] = '∽'; - map!['reviahebrew'] = '֗'; - map!['reviamugrashhebrew'] = '֗'; - map!['revlogicalnot'] = '⌐'; - map!['rfishhook'] = 'ɾ'; - map!['rfishhookreversed'] = 'ɿ'; - map!['rhabengali'] = 'ঢ়'; - map!['rhadeva'] = 'ढ़'; - map!['rho'] = 'ρ'; - map!['rhook'] = 'ɽ'; - map!['rhookturned'] = 'ɻ'; - map!['rhookturnedsuperior'] = 'ʵ'; - map!['rhosymbolgreek'] = 'ϱ'; - map!['rhotichookmod'] = '˞'; - map!['rieulacirclekorean'] = '㉱'; - map!['rieulaparenkorean'] = '㈑'; - map!['rieulcirclekorean'] = '㉣'; - map!['rieulhieuhkorean'] = 'ㅀ'; - map!['rieulkiyeokkorean'] = 'ㄺ'; - map!['rieulkiyeoksioskorean'] = 'ㅩ'; - map!['rieulkorean'] = 'ㄹ'; - map!['rieulmieumkorean'] = 'ㄻ'; - map!['rieulpansioskorean'] = 'ㅬ'; - map!['rieulparenkorean'] = '㈃'; - map!['rieulphieuphkorean'] = 'ㄿ'; - map!['rieulpieupkorean'] = 'ㄼ'; - map!['rieulpieupsioskorean'] = 'ㅫ'; - map!['rieulsioskorean'] = 'ㄽ'; - map!['rieulthieuthkorean'] = 'ㄾ'; - map!['rieultikeutkorean'] = 'ㅪ'; - map!['rieulyeorinhieuhkorean'] = 'ㅭ'; - map!['rightangle'] = '∟'; - map!['righttackbelowcmb'] = '̙'; - map!['righttriangle'] = '⊿'; - map!['rihiragana'] = 'り'; - map!['rikatakana'] = 'リ'; - map!['rikatakanahalfwidth'] = 'リ'; - map!['ring'] = '˚'; - map!['ringbelowcmb'] = '̥'; - map!['ringcmb'] = '̊'; - map!['ringhalfleft'] = 'ʿ'; - map!['ringhalfleftarmenian'] = 'ՙ'; - map!['ringhalfleftbelowcmb'] = '̜'; - map!['ringhalfleftcentered'] = '˓'; - map!['ringhalfright'] = 'ʾ'; - map!['ringhalfrightbelowcmb'] = '̹'; - map!['ringhalfrightcentered'] = '˒'; - map!['rinvertedbreve'] = 'ȓ'; - map!['rittorusquare'] = '㍑'; - map!['rlinebelow'] = 'ṟ'; - map!['rlongleg'] = 'ɼ'; - map!['rlonglegturned'] = 'ɺ'; - map!['rmonospace'] = 'r'; - map!['rohiragana'] = 'ろ'; - map!['rokatakana'] = 'ロ'; - map!['rokatakanahalfwidth'] = 'ロ'; - map!['roruathai'] = 'ร'; - map!['rparen'] = '⒭'; - map!['rrabengali'] = 'ড়'; - map!['rradeva'] = 'ऱ'; - map!['rragurmukhi'] = 'ੜ'; - map!['rreharabic'] = 'ڑ'; - map!['rrehfinalarabic'] = 'ﮍ'; - map!['rrvocalicbengali'] = 'ৠ'; - map!['rrvocalicdeva'] = 'ॠ'; - map!['rrvocalicgujarati'] = 'ૠ'; - map!['rrvocalicvowelsignbengali'] = 'ৄ'; - map!['rrvocalicvowelsigndeva'] = 'ॄ'; - map!['rrvocalicvowelsigngujarati'] = 'ૄ'; - map!['rsuperior'] = ''; - map!['rtblock'] = '▐'; - map!['rturned'] = 'ɹ'; - map!['rturnedsuperior'] = 'ʴ'; - map!['ruhiragana'] = 'る'; - map!['rukatakana'] = 'ル'; - map!['rukatakanahalfwidth'] = 'ル'; - map!['rupeemarkbengali'] = '৲'; - map!['rupeesignbengali'] = '৳'; - map!['rupiah'] = ''; - map!['ruthai'] = 'ฤ'; - map!['rvocalicbengali'] = 'ঋ'; - map!['rvocalicdeva'] = 'ऋ'; - map!['rvocalicgujarati'] = 'ઋ'; - map!['rvocalicvowelsignbengali'] = 'ৃ'; - map!['rvocalicvowelsigndeva'] = 'ृ'; - map!['rvocalicvowelsigngujarati'] = 'ૃ'; - map!['s'] = 's'; - map!['sabengali'] = 'স'; - map!['sacute'] = 'ś'; - map!['sacutedotaccent'] = 'ṥ'; - map!['sadarabic'] = 'ص'; - map!['sadeva'] = 'स'; - map!['sadfinalarabic'] = 'ﺺ'; - map!['sadinitialarabic'] = 'ﺻ'; - map!['sadmedialarabic'] = 'ﺼ'; - map!['sagujarati'] = 'સ'; - map!['sagurmukhi'] = 'ਸ'; - map!['sahiragana'] = 'さ'; - map!['sakatakana'] = 'サ'; - map!['sakatakanahalfwidth'] = 'サ'; - map!['sallallahoualayhewasallamarabic'] = 'ﷺ'; - map!['samekh'] = 'ס'; - map!['samekhdagesh'] = 'סּ'; - map!['samekhdageshhebrew'] = 'סּ'; - map!['samekhhebrew'] = 'ס'; - map!['saraaathai'] = 'า'; - map!['saraaethai'] = 'แ'; - map!['saraaimaimalaithai'] = 'ไ'; - map!['saraaimaimuanthai'] = 'ใ'; - map!['saraamthai'] = 'ำ'; - map!['saraathai'] = 'ะ'; - map!['saraethai'] = 'เ'; - map!['saraiileftthai'] = ''; - map!['saraiithai'] = 'ี'; - map!['saraileftthai'] = ''; - map!['saraithai'] = 'ิ'; - map!['saraothai'] = 'โ'; - map!['saraueeleftthai'] = ''; - map!['saraueethai'] = 'ื'; - map!['saraueleftthai'] = ''; - map!['sarauethai'] = 'ึ'; - map!['sarauthai'] = 'ุ'; - map!['sarauuthai'] = 'ู'; - map!['sbopomofo'] = 'ㄙ'; - map!['scaron'] = 'š'; - map!['scarondotaccent'] = 'ṧ'; - map!['scedilla'] = 'ş'; - map!['schwa'] = 'ə'; - map!['schwacyrillic'] = 'ә'; - map!['schwadieresiscyrillic'] = 'ӛ'; - map!['schwahook'] = 'ɚ'; - map!['scircle'] = 'ⓢ'; - map!['scircumflex'] = 'ŝ'; - map!['scommaaccent'] = 'ș'; - map!['sdotaccent'] = 'ṡ'; - map!['sdotbelow'] = 'ṣ'; - map!['sdotbelowdotaccent'] = 'ṩ'; - map!['seagullbelowcmb'] = '̼'; - map!['second'] = '″'; - map!['secondtonechinese'] = 'ˊ'; - map!['section'] = '§'; - map!['seenarabic'] = 'س'; - map!['seenfinalarabic'] = 'ﺲ'; - map!['seeninitialarabic'] = 'ﺳ'; - map!['seenmedialarabic'] = 'ﺴ'; - map!['segol'] = 'ֶ'; - map!['segol13'] = 'ֶ'; - map!['segol1f'] = 'ֶ'; - map!['segol2c'] = 'ֶ'; - map!['segolhebrew'] = 'ֶ'; - map!['segolnarrowhebrew'] = 'ֶ'; - map!['segolquarterhebrew'] = 'ֶ'; - map!['segoltahebrew'] = '֒'; - map!['segolwidehebrew'] = 'ֶ'; - map!['seharmenian'] = 'ս'; - map!['sehiragana'] = 'せ'; - map!['sekatakana'] = 'セ'; - map!['sekatakanahalfwidth'] = 'セ'; - map!['semicolon'] = ';'; - map!['semicolonarabic'] = '؛'; - map!['semicolonmonospace'] = ';'; - map!['semicolonsmall'] = '﹔'; - map!['semivoicedmarkkana'] = '゜'; - map!['semivoicedmarkkanahalfwidth'] = '゚'; - map!['sentisquare'] = '㌢'; - map!['sentosquare'] = '㌣'; - map!['seven'] = '7'; - map!['sevenarabic'] = '٧'; - map!['sevenbengali'] = '৭'; - map!['sevencircle'] = '⑦'; - map!['sevencircleinversesansserif'] = '➐'; - map!['sevendeva'] = '७'; - map!['seveneighths'] = '⅞'; - map!['sevengujarati'] = '૭'; - map!['sevengurmukhi'] = '੭'; - map!['sevenhackarabic'] = '٧'; - map!['sevenhangzhou'] = '〧'; - map!['sevenideographicparen'] = '㈦'; - map!['seveninferior'] = '₇'; - map!['sevenmonospace'] = '7'; - map!['sevenoldstyle'] = ''; - map!['sevenparen'] = '⑺'; - map!['sevenperiod'] = '⒎'; - map!['sevenpersian'] = '۷'; - map!['sevenroman'] = 'ⅶ'; - map!['sevensuperior'] = '⁷'; - map!['seventeencircle'] = '⑰'; - map!['seventeenparen'] = '⒄'; - map!['seventeenperiod'] = '⒘'; - map!['seventhai'] = '๗'; - map!['sfthyphen'] = '­'; - map!['shaarmenian'] = 'շ'; - map!['shabengali'] = 'শ'; - map!['shacyrillic'] = 'ш'; - map!['shaddaarabic'] = 'ّ'; - map!['shaddadammaarabic'] = 'ﱡ'; - map!['shaddadammatanarabic'] = 'ﱞ'; - map!['shaddafathaarabic'] = 'ﱠ'; - map!['shaddakasraarabic'] = 'ﱢ'; - map!['shaddakasratanarabic'] = 'ﱟ'; - map!['shade'] = '▒'; - map!['shadedark'] = '▓'; - map!['shadelight'] = '░'; - map!['shademedium'] = '▒'; - map!['shadeva'] = 'श'; - map!['shagujarati'] = 'શ'; - map!['shagurmukhi'] = 'ਸ਼'; - map!['shalshelethebrew'] = '֓'; - map!['shbopomofo'] = 'ㄕ'; - map!['shchacyrillic'] = 'щ'; - map!['sheenarabic'] = 'ش'; - map!['sheenfinalarabic'] = 'ﺶ'; - map!['sheeninitialarabic'] = 'ﺷ'; - map!['sheenmedialarabic'] = 'ﺸ'; - map!['sheicoptic'] = 'ϣ'; - map!['sheqel'] = '₪'; - map!['sheqelhebrew'] = '₪'; - map!['sheva'] = 'ְ'; - map!['sheva115'] = 'ְ'; - map!['sheva15'] = 'ְ'; - map!['sheva22'] = 'ְ'; - map!['sheva2e'] = 'ְ'; - map!['shevahebrew'] = 'ְ'; - map!['shevanarrowhebrew'] = 'ְ'; - map!['shevaquarterhebrew'] = 'ְ'; - map!['shevawidehebrew'] = 'ְ'; - map!['shhacyrillic'] = 'һ'; - map!['shimacoptic'] = 'ϭ'; - map!['shin'] = 'ש'; - map!['shindagesh'] = 'שּ'; - map!['shindageshhebrew'] = 'שּ'; - map!['shindageshshindot'] = 'שּׁ'; - map!['shindageshshindothebrew'] = 'שּׁ'; - map!['shindageshsindot'] = 'שּׂ'; - map!['shindageshsindothebrew'] = 'שּׂ'; - map!['shindothebrew'] = 'ׁ'; - map!['shinhebrew'] = 'ש'; - map!['shinshindot'] = 'שׁ'; - map!['shinshindothebrew'] = 'שׁ'; - map!['shinsindot'] = 'שׂ'; - map!['shinsindothebrew'] = 'שׂ'; - map!['shook'] = 'ʂ'; - map!['sigma'] = 'σ'; - map!['sigma1'] = 'ς'; - map!['sigmafinal'] = 'ς'; - map!['sigmalunatesymbolgreek'] = 'ϲ'; - map!['sihiragana'] = 'し'; - map!['sikatakana'] = 'シ'; - map!['sikatakanahalfwidth'] = 'シ'; - map!['siluqhebrew'] = 'ֽ'; - map!['siluqlefthebrew'] = 'ֽ'; - map!['similar'] = '∼'; - map!['sindothebrew'] = 'ׂ'; - map!['siosacirclekorean'] = '㉴'; - map!['siosaparenkorean'] = '㈔'; - map!['sioscieuckorean'] = 'ㅾ'; - map!['sioscirclekorean'] = '㉦'; - map!['sioskiyeokkorean'] = 'ㅺ'; - map!['sioskorean'] = 'ㅅ'; - map!['siosnieunkorean'] = 'ㅻ'; - map!['siosparenkorean'] = '㈆'; - map!['siospieupkorean'] = 'ㅽ'; - map!['siostikeutkorean'] = 'ㅼ'; - map!['six'] = '6'; - map!['sixarabic'] = '٦'; - map!['sixbengali'] = '৬'; - map!['sixcircle'] = '⑥'; - map!['sixcircleinversesansserif'] = '➏'; - map!['sixdeva'] = '६'; - map!['sixgujarati'] = '૬'; - map!['sixgurmukhi'] = '੬'; - map!['sixhackarabic'] = '٦'; - map!['sixhangzhou'] = '〦'; - map!['sixideographicparen'] = '㈥'; - map!['sixinferior'] = '₆'; - map!['sixmonospace'] = '6'; - map!['sixoldstyle'] = ''; - map!['sixparen'] = '⑹'; - map!['sixperiod'] = '⒍'; - map!['sixpersian'] = '۶'; - map!['sixroman'] = 'ⅵ'; - map!['sixsuperior'] = '⁶'; - map!['sixteencircle'] = '⑯'; - map!['sixteencurrencydenominatorbengali'] = '৹'; - map!['sixteenparen'] = '⒃'; - map!['sixteenperiod'] = '⒗'; - map!['sixthai'] = '๖'; - map!['slash'] = '/'; - map!['slashmonospace'] = '/'; - map!['slong'] = 'ſ'; - map!['slongdotaccent'] = 'ẛ'; - map!['smileface'] = '☺'; - map!['smonospace'] = 's'; - map!['sofpasuqhebrew'] = '׃'; - map!['softhyphen'] = '­'; - map!['softsigncyrillic'] = 'ь'; - map!['sohiragana'] = 'そ'; - map!['sokatakana'] = 'ソ'; - map!['sokatakanahalfwidth'] = 'ソ'; - map!['soliduslongoverlaycmb'] = '̸'; - map!['solidusshortoverlaycmb'] = '̷'; - map!['sorusithai'] = 'ษ'; - map!['sosalathai'] = 'ศ'; - map!['sosothai'] = 'ซ'; - map!['sosuathai'] = 'ส'; - map!['space'] = ' '; - map!['spacehackarabic'] = ' '; - map!['spade'] = '♠'; - map!['spadesuitblack'] = '♠'; - map!['spadesuitwhite'] = '♤'; - map!['sparen'] = '⒮'; - map!['squarebelowcmb'] = '̻'; - map!['squarecc'] = '㏄'; - map!['squarecm'] = '㎝'; - map!['squarediagonalcrosshatchfill'] = '▩'; - map!['squarehorizontalfill'] = '▤'; - map!['squarekg'] = '㎏'; - map!['squarekm'] = '㎞'; - map!['squarekmcapital'] = '㏎'; - map!['squareln'] = '㏑'; - map!['squarelog'] = '㏒'; - map!['squaremg'] = '㎎'; - map!['squaremil'] = '㏕'; - map!['squaremm'] = '㎜'; - map!['squaremsquared'] = '㎡'; - map!['squareorthogonalcrosshatchfill'] = '▦'; - map!['squareupperlefttolowerrightfill'] = '▧'; - map!['squareupperrighttolowerleftfill'] = '▨'; - map!['squareverticalfill'] = '▥'; - map!['squarewhitewithsmallblack'] = '▣'; - map!['srsquare'] = '㏛'; - map!['ssabengali'] = 'ষ'; - map!['ssadeva'] = 'ष'; - map!['ssagujarati'] = 'ષ'; - map!['ssangcieuckorean'] = 'ㅉ'; - map!['ssanghieuhkorean'] = 'ㆅ'; - map!['ssangieungkorean'] = 'ㆀ'; - map!['ssangkiyeokkorean'] = 'ㄲ'; - map!['ssangnieunkorean'] = 'ㅥ'; - map!['ssangpieupkorean'] = 'ㅃ'; - map!['ssangsioskorean'] = 'ㅆ'; - map!['ssangtikeutkorean'] = 'ㄸ'; - map!['ssuperior'] = ''; - map!['sterling'] = '£'; - map!['sterlingmonospace'] = '£'; - map!['strokelongoverlaycmb'] = '̶'; - map!['strokeshortoverlaycmb'] = '̵'; - map!['subset'] = '⊂'; - map!['subsetnotequal'] = '⊊'; - map!['subsetorequal'] = '⊆'; - map!['succeeds'] = '≻'; - map!['suchthat'] = '∋'; - map!['suhiragana'] = 'す'; - map!['sukatakana'] = 'ス'; - map!['sukatakanahalfwidth'] = 'ス'; - map!['sukunarabic'] = 'ْ'; - map!['summation'] = '∑'; - map!['sun'] = '☼'; - map!['superset'] = '⊃'; - map!['supersetnotequal'] = '⊋'; - map!['supersetorequal'] = '⊇'; - map!['svsquare'] = '㏜'; - map!['syouwaerasquare'] = '㍼'; - map!['t'] = 't'; - map!['tabengali'] = 'ত'; - map!['tackdown'] = '⊤'; - map!['tackleft'] = '⊣'; - map!['tadeva'] = 'त'; - map!['tagujarati'] = 'ત'; - map!['tagurmukhi'] = 'ਤ'; - map!['taharabic'] = 'ط'; - map!['tahfinalarabic'] = 'ﻂ'; - map!['tahinitialarabic'] = 'ﻃ'; - map!['tahiragana'] = 'た'; - map!['tahmedialarabic'] = 'ﻄ'; - map!['taisyouerasquare'] = '㍽'; - map!['takatakana'] = 'タ'; - map!['takatakanahalfwidth'] = 'タ'; - map!['tatweelarabic'] = 'ـ'; - map!['tau'] = 'τ'; - map!['tav'] = 'ת'; - map!['tavdages'] = 'תּ'; - map!['tavdagesh'] = 'תּ'; - map!['tavdageshhebrew'] = 'תּ'; - map!['tavhebrew'] = 'ת'; - map!['tbar'] = 'ŧ'; - map!['tbopomofo'] = 'ㄊ'; - map!['tcaron'] = 'ť'; - map!['tccurl'] = 'ʨ'; - map!['tcedilla'] = 'ţ'; - map!['tcheharabic'] = 'چ'; - map!['tchehfinalarabic'] = 'ﭻ'; - map!['tchehinitialarabic'] = 'ﭼ'; - map!['tchehmedialarabic'] = 'ﭽ'; - map!['tcircle'] = 'ⓣ'; - map!['tcircumflexbelow'] = 'ṱ'; - map!['tcommaaccent'] = 'ţ'; - map!['tdieresis'] = 'ẗ'; - map!['tdotaccent'] = 'ṫ'; - map!['tdotbelow'] = 'ṭ'; - map!['tecyrillic'] = 'т'; - map!['tedescendercyrillic'] = 'ҭ'; - map!['teharabic'] = 'ت'; - map!['tehfinalarabic'] = 'ﺖ'; - map!['tehhahinitialarabic'] = 'ﲢ'; - map!['tehhahisolatedarabic'] = 'ﰌ'; - map!['tehinitialarabic'] = 'ﺗ'; - map!['tehiragana'] = 'て'; - map!['tehjeeminitialarabic'] = 'ﲡ'; - map!['tehjeemisolatedarabic'] = 'ﰋ'; - map!['tehmarbutaarabic'] = 'ة'; - map!['tehmarbutafinalarabic'] = 'ﺔ'; - map!['tehmedialarabic'] = 'ﺘ'; - map!['tehmeeminitialarabic'] = 'ﲤ'; - map!['tehmeemisolatedarabic'] = 'ﰎ'; - map!['tehnoonfinalarabic'] = 'ﱳ'; - map!['tekatakana'] = 'テ'; - map!['tekatakanahalfwidth'] = 'テ'; - map!['telephone'] = '℡'; - map!['telephoneblack'] = '☎'; - map!['telishagedolahebrew'] = '֠'; - map!['telishaqetanahebrew'] = '֩'; - map!['tencircle'] = '⑩'; - map!['tenideographicparen'] = '㈩'; - map!['tenparen'] = '⑽'; - map!['tenperiod'] = '⒑'; - map!['tenroman'] = 'ⅹ'; - map!['tesh'] = 'ʧ'; - map!['tet'] = 'ט'; - map!['tetdagesh'] = 'טּ'; - map!['tetdageshhebrew'] = 'טּ'; - map!['tethebrew'] = 'ט'; - map!['tetsecyrillic'] = 'ҵ'; - map!['tevirhebrew'] = '֛'; - map!['tevirlefthebrew'] = '֛'; - map!['thabengali'] = 'থ'; - map!['thadeva'] = 'थ'; - map!['thagujarati'] = 'થ'; - map!['thagurmukhi'] = 'ਥ'; - map!['thalarabic'] = 'ذ'; - map!['thalfinalarabic'] = 'ﺬ'; - map!['thanthakhatlowleftthai'] = ''; - map!['thanthakhatlowrightthai'] = ''; - map!['thanthakhatthai'] = '์'; - map!['thanthakhatupperleftthai'] = ''; - map!['theharabic'] = 'ث'; - map!['thehfinalarabic'] = 'ﺚ'; - map!['thehinitialarabic'] = 'ﺛ'; - map!['thehmedialarabic'] = 'ﺜ'; - map!['thereexists'] = '∃'; - map!['therefore'] = '∴'; - map!['theta'] = 'θ'; - map!['theta1'] = 'ϑ'; - map!['thetasymbolgreek'] = 'ϑ'; - map!['thieuthacirclekorean'] = '㉹'; - map!['thieuthaparenkorean'] = '㈙'; - map!['thieuthcirclekorean'] = '㉫'; - map!['thieuthkorean'] = 'ㅌ'; - map!['thieuthparenkorean'] = '㈋'; - map!['thirteencircle'] = '⑬'; - map!['thirteenparen'] = '⒀'; - map!['thirteenperiod'] = '⒔'; - map!['thonangmonthothai'] = 'ฑ'; - map!['thook'] = 'ƭ'; - map!['thophuthaothai'] = 'ฒ'; - map!['thorn'] = 'þ'; - map!['thothahanthai'] = 'ท'; - map!['thothanthai'] = 'ฐ'; - map!['thothongthai'] = 'ธ'; - map!['thothungthai'] = 'ถ'; - map!['thousandcyrillic'] = '҂'; - map!['thousandsseparatorarabic'] = '٬'; - map!['thousandsseparatorpersian'] = '٬'; - map!['three'] = '3'; - map!['threearabic'] = '٣'; - map!['threebengali'] = '৩'; - map!['threecircle'] = '③'; - map!['threecircleinversesansserif'] = '➌'; - map!['threedeva'] = '३'; - map!['threeeighths'] = '⅜'; - map!['threegujarati'] = '૩'; - map!['threegurmukhi'] = '੩'; - map!['threehackarabic'] = '٣'; - map!['threehangzhou'] = '〣'; - map!['threeideographicparen'] = '㈢'; - map!['threeinferior'] = '₃'; - map!['threemonospace'] = '3'; - map!['threenumeratorbengali'] = '৶'; - map!['threeoldstyle'] = ''; - map!['threeparen'] = '⑶'; - map!['threeperiod'] = '⒊'; - map!['threepersian'] = '۳'; - map!['threequarters'] = '¾'; - map!['threequartersemdash'] = ''; - map!['threeroman'] = 'ⅲ'; - map!['threesuperior'] = '³'; - map!['threethai'] = '๓'; - map!['thzsquare'] = '㎔'; - map!['tihiragana'] = 'ち'; - map!['tikatakana'] = 'チ'; - map!['tikatakanahalfwidth'] = 'チ'; - map!['tikeutacirclekorean'] = '㉰'; - map!['tikeutaparenkorean'] = '㈐'; - map!['tikeutcirclekorean'] = '㉢'; - map!['tikeutkorean'] = 'ㄷ'; - map!['tikeutparenkorean'] = '㈂'; - map!['tilde'] = '˜'; - map!['tildebelowcmb'] = '̰'; - map!['tildecmb'] = '̃'; - map!['tildecomb'] = '̃'; - map!['tildedoublecmb'] = '͠'; - map!['tildeoperator'] = '∼'; - map!['tildeoverlaycmb'] = '̴'; - map!['tildeverticalcmb'] = '̾'; - map!['timescircle'] = '⊗'; - map!['tipehahebrew'] = '֖'; - map!['tipehalefthebrew'] = '֖'; - map!['tippigurmukhi'] = 'ੰ'; - map!['titlocyrilliccmb'] = '҃'; - map!['tiwnarmenian'] = 'տ'; - map!['tlinebelow'] = 'ṯ'; - map!['tmonospace'] = 't'; - map!['toarmenian'] = 'թ'; - map!['tohiragana'] = 'と'; - map!['tokatakana'] = 'ト'; - map!['tokatakanahalfwidth'] = 'ト'; - map!['tonebarextrahighmod'] = '˥'; - map!['tonebarextralowmod'] = '˩'; - map!['tonebarhighmod'] = '˦'; - map!['tonebarlowmod'] = '˨'; - map!['tonebarmidmod'] = '˧'; - map!['tonefive'] = 'ƽ'; - map!['tonesix'] = 'ƅ'; - map!['tonetwo'] = 'ƨ'; - map!['tonos'] = '΄'; - map!['tonsquare'] = '㌧'; - map!['topatakthai'] = 'ฏ'; - map!['tortoiseshellbracketleft'] = '〔'; - map!['tortoiseshellbracketleftsmall'] = '﹝'; - map!['tortoiseshellbracketleftvertical'] = '︹'; - map!['tortoiseshellbracketright'] = '〕'; - map!['tortoiseshellbracketrightsmall'] = '﹞'; - map!['tortoiseshellbracketrightvertical'] = '︺'; - map!['totaothai'] = 'ต'; - map!['tpalatalhook'] = 'ƫ'; - map!['tparen'] = '⒯'; - map!['trademark'] = '™'; - map!['trademarksans'] = ''; - map!['trademarkserif'] = ''; - map!['tretroflexhook'] = 'ʈ'; - map!['triagdn'] = '▼'; - map!['triaglf'] = '◄'; - map!['triagrt'] = '►'; - map!['triagup'] = '▲'; - map!['ts'] = 'ʦ'; - map!['tsadi'] = 'צ'; - map!['tsadidagesh'] = 'צּ'; - map!['tsadidageshhebrew'] = 'צּ'; - map!['tsadihebrew'] = 'צ'; - map!['tsecyrillic'] = 'ц'; - map!['tsere'] = 'ֵ'; - map!['tsere12'] = 'ֵ'; - map!['tsere1e'] = 'ֵ'; - map!['tsere2b'] = 'ֵ'; - map!['tserehebrew'] = 'ֵ'; - map!['tserenarrowhebrew'] = 'ֵ'; - map!['tserequarterhebrew'] = 'ֵ'; - map!['tserewidehebrew'] = 'ֵ'; - map!['tshecyrillic'] = 'ћ'; - map!['tsuperior'] = ''; - map!['ttabengali'] = 'ট'; - map!['ttadeva'] = 'ट'; - map!['ttagujarati'] = 'ટ'; - map!['ttagurmukhi'] = 'ਟ'; - map!['tteharabic'] = 'ٹ'; - map!['ttehfinalarabic'] = 'ﭧ'; - map!['ttehinitialarabic'] = 'ﭨ'; - map!['ttehmedialarabic'] = 'ﭩ'; - map!['tthabengali'] = 'ঠ'; - map!['tthadeva'] = 'ठ'; - map!['tthagujarati'] = 'ઠ'; - map!['tthagurmukhi'] = 'ਠ'; - map!['tturned'] = 'ʇ'; - map!['tuhiragana'] = 'つ'; - map!['tukatakana'] = 'ツ'; - map!['tukatakanahalfwidth'] = 'ツ'; - map!['tusmallhiragana'] = 'っ'; - map!['tusmallkatakana'] = 'ッ'; - map!['tusmallkatakanahalfwidth'] = 'ッ'; - map!['twelvecircle'] = '⑫'; - map!['twelveparen'] = '⑿'; - map!['twelveperiod'] = '⒓'; - map!['twelveroman'] = 'ⅻ'; - map!['twentycircle'] = '⑳'; - map!['twentyhangzhou'] = '卄'; - map!['twentyparen'] = '⒇'; - map!['twentyperiod'] = '⒛'; - map!['two'] = '2'; - map!['twoarabic'] = '٢'; - map!['twobengali'] = '২'; - map!['twocircle'] = '②'; - map!['twocircleinversesansserif'] = '➋'; - map!['twodeva'] = '२'; - map!['twodotenleader'] = '‥'; - map!['twodotleader'] = '‥'; - map!['twodotleadervertical'] = '︰'; - map!['twogujarati'] = '૨'; - map!['twogurmukhi'] = '੨'; - map!['twohackarabic'] = '٢'; - map!['twohangzhou'] = '〢'; - map!['twoideographicparen'] = '㈡'; - map!['twoinferior'] = '₂'; - map!['twomonospace'] = '2'; - map!['twonumeratorbengali'] = '৵'; - map!['twooldstyle'] = ''; - map!['twoparen'] = '⑵'; - map!['twoperiod'] = '⒉'; - map!['twopersian'] = '۲'; - map!['tworoman'] = 'ⅱ'; - map!['twostroke'] = 'ƻ'; - map!['twosuperior'] = '²'; - map!['twothai'] = '๒'; - map!['twothirds'] = '⅔'; - map!['u'] = 'u'; - map!['uacute'] = 'ú'; - map!['ubar'] = 'ʉ'; - map!['ubengali'] = 'উ'; - map!['ubopomofo'] = 'ㄨ'; - map!['ubreve'] = 'ŭ'; - map!['ucaron'] = 'ǔ'; - map!['ucircle'] = 'ⓤ'; - map!['ucircumflex'] = 'û'; - map!['ucircumflexbelow'] = 'ṷ'; - map!['ucyrillic'] = 'у'; - map!['udattadeva'] = '॑'; - map!['udblacute'] = 'ű'; - map!['udblgrave'] = 'ȕ'; - map!['udeva'] = 'उ'; - map!['udieresis'] = 'ü'; - map!['udieresisacute'] = 'ǘ'; - map!['udieresisbelow'] = 'ṳ'; - map!['udieresiscaron'] = 'ǚ'; - map!['udieresiscyrillic'] = 'ӱ'; - map!['udieresisgrave'] = 'ǜ'; - map!['udieresismacron'] = 'ǖ'; - map!['udotbelow'] = 'ụ'; - map!['ugrave'] = 'ù'; - map!['ugujarati'] = 'ઉ'; - map!['ugurmukhi'] = 'ਉ'; - map!['uhiragana'] = 'う'; - map!['uhookabove'] = 'ủ'; - map!['uhorn'] = 'ư'; - map!['uhornacute'] = 'ứ'; - map!['uhorndotbelow'] = 'ự'; - map!['uhorngrave'] = 'ừ'; - map!['uhornhookabove'] = 'ử'; - map!['uhorntilde'] = 'ữ'; - map!['uhungarumlaut'] = 'ű'; - map!['uhungarumlautcyrillic'] = 'ӳ'; - map!['uinvertedbreve'] = 'ȗ'; - map!['ukatakana'] = 'ウ'; - map!['ukatakanahalfwidth'] = 'ウ'; - map!['ukcyrillic'] = 'ѹ'; - map!['ukorean'] = 'ㅜ'; - map!['umacron'] = 'ū'; - map!['umacroncyrillic'] = 'ӯ'; - map!['umacrondieresis'] = 'ṻ'; - map!['umatragurmukhi'] = 'ੁ'; - map!['umonospace'] = 'u'; - map!['underscore'] = '_'; - map!['underscoredbl'] = '‗'; - map!['underscoremonospace'] = '_'; - map!['underscorevertical'] = '︳'; - map!['underscorewavy'] = '﹏'; - map!['union'] = '∪'; - map!['universal'] = '∀'; - map!['uogonek'] = 'ų'; - map!['uparen'] = '⒰'; - map!['upblock'] = '▀'; - map!['upperdothebrew'] = 'ׄ'; - map!['upsilon'] = 'υ'; - map!['upsilondieresis'] = 'ϋ'; - map!['upsilondieresistonos'] = 'ΰ'; - map!['upsilonlatin'] = 'ʊ'; - map!['upsilontonos'] = 'ύ'; - map!['uptackbelowcmb'] = '̝'; - map!['uptackmod'] = '˔'; - map!['uragurmukhi'] = 'ੳ'; - map!['uring'] = 'ů'; - map!['ushortcyrillic'] = 'ў'; - map!['usmallhiragana'] = 'ぅ'; - map!['usmallkatakana'] = 'ゥ'; - map!['usmallkatakanahalfwidth'] = 'ゥ'; - map!['ustraightcyrillic'] = 'ү'; - map!['ustraightstrokecyrillic'] = 'ұ'; - map!['utilde'] = 'ũ'; - map!['utildeacute'] = 'ṹ'; - map!['utildebelow'] = 'ṵ'; - map!['uubengali'] = 'ঊ'; - map!['uudeva'] = 'ऊ'; - map!['uugujarati'] = 'ઊ'; - map!['uugurmukhi'] = 'ਊ'; - map!['uumatragurmukhi'] = 'ੂ'; - map!['uuvowelsignbengali'] = 'ূ'; - map!['uuvowelsigndeva'] = 'ू'; - map!['uuvowelsigngujarati'] = 'ૂ'; - map!['uvowelsignbengali'] = 'ু'; - map!['uvowelsigndeva'] = 'ु'; - map!['uvowelsigngujarati'] = 'ુ'; - map!['v'] = 'v'; - map!['vadeva'] = 'व'; - map!['vagujarati'] = 'વ'; - map!['vagurmukhi'] = 'ਵ'; - map!['vakatakana'] = 'ヷ'; - map!['vav'] = 'ו'; - map!['vavdagesh'] = 'וּ'; - map!['vavdagesh65'] = 'וּ'; - map!['vavdageshhebrew'] = 'וּ'; - map!['vavhebrew'] = 'ו'; - map!['vavholam'] = 'וֹ'; - map!['vavholamhebrew'] = 'וֹ'; - map!['vavvavhebrew'] = 'װ'; - map!['vavyodhebrew'] = 'ױ'; - map!['vcircle'] = 'ⓥ'; - map!['vdotbelow'] = 'ṿ'; - map!['vecyrillic'] = 'в'; - map!['veharabic'] = 'ڤ'; - map!['vehfinalarabic'] = 'ﭫ'; - map!['vehinitialarabic'] = 'ﭬ'; - map!['vehmedialarabic'] = 'ﭭ'; - map!['vekatakana'] = 'ヹ'; - map!['venus'] = '♀'; - map!['verticalbar'] = '|'; - map!['verticallineabovecmb'] = '̍'; - map!['verticallinebelowcmb'] = '̩'; - map!['verticallinelowmod'] = 'ˌ'; - map!['verticallinemod'] = 'ˈ'; - map!['vewarmenian'] = 'վ'; - map!['vhook'] = 'ʋ'; - map!['vikatakana'] = 'ヸ'; - map!['viramabengali'] = '্'; - map!['viramadeva'] = '्'; - map!['viramagujarati'] = '્'; - map!['visargabengali'] = 'ঃ'; - map!['visargadeva'] = 'ः'; - map!['visargagujarati'] = 'ઃ'; - map!['vmonospace'] = 'v'; - map!['voarmenian'] = 'ո'; - map!['voicediterationhiragana'] = 'ゞ'; - map!['voicediterationkatakana'] = 'ヾ'; - map!['voicedmarkkana'] = '゛'; - map!['voicedmarkkanahalfwidth'] = '゙'; - map!['vokatakana'] = 'ヺ'; - map!['vparen'] = '⒱'; - map!['vtilde'] = 'ṽ'; - map!['vturned'] = 'ʌ'; - map!['vuhiragana'] = 'ゔ'; - map!['vukatakana'] = 'ヴ'; - map!['w'] = 'w'; - map!['wacute'] = 'ẃ'; - map!['waekorean'] = 'ㅙ'; - map!['wahiragana'] = 'わ'; - map!['wakatakana'] = 'ワ'; - map!['wakatakanahalfwidth'] = 'ワ'; - map!['wakorean'] = 'ㅘ'; - map!['wasmallhiragana'] = 'ゎ'; - map!['wasmallkatakana'] = 'ヮ'; - map!['wattosquare'] = '㍗'; - map!['wavedash'] = '〜'; - map!['wavyunderscorevertical'] = '︴'; - map!['wawarabic'] = 'و'; - map!['wawfinalarabic'] = 'ﻮ'; - map!['wawhamzaabovearabic'] = 'ؤ'; - map!['wawhamzaabovefinalarabic'] = 'ﺆ'; - map!['wbsquare'] = '㏝'; - map!['wcircle'] = 'ⓦ'; - map!['wcircumflex'] = 'ŵ'; - map!['wdieresis'] = 'ẅ'; - map!['wdotaccent'] = 'ẇ'; - map!['wdotbelow'] = 'ẉ'; - map!['wehiragana'] = 'ゑ'; - map!['weierstrass'] = '℘'; - map!['wekatakana'] = 'ヱ'; - map!['wekorean'] = 'ㅞ'; - map!['weokorean'] = 'ㅝ'; - map!['wgrave'] = 'ẁ'; - map!['whitebullet'] = '◦'; - map!['whitecircle'] = '○'; - map!['whitecircleinverse'] = '◙'; - map!['whitecornerbracketleft'] = '『'; - map!['whitecornerbracketleftvertical'] = '﹃'; - map!['whitecornerbracketright'] = '』'; - map!['whitecornerbracketrightvertical'] = '﹄'; - map!['whitediamond'] = '◇'; - map!['whitediamondcontainingblacksmalldiamond'] = '◈'; - map!['whitedownpointingsmalltriangle'] = '▿'; - map!['whitedownpointingtriangle'] = '▽'; - map!['whiteleftpointingsmalltriangle'] = '◃'; - map!['whiteleftpointingtriangle'] = '◁'; - map!['whitelenticularbracketleft'] = '〖'; - map!['whitelenticularbracketright'] = '〗'; - map!['whiterightpointingsmalltriangle'] = '▹'; - map!['whiterightpointingtriangle'] = '▷'; - map!['whitesmallsquare'] = '▫'; - map!['whitesmilingface'] = '☺'; - map!['whitesquare'] = '□'; - map!['whitestar'] = '☆'; - map!['whitetelephone'] = '☏'; - map!['whitetortoiseshellbracketleft'] = '〘'; - map!['whitetortoiseshellbracketright'] = '〙'; - map!['whiteuppointingsmalltriangle'] = '▵'; - map!['whiteuppointingtriangle'] = '△'; - map!['wihiragana'] = 'ゐ'; - map!['wikatakana'] = 'ヰ'; - map!['wikorean'] = 'ㅟ'; - map!['wmonospace'] = 'w'; - map!['wohiragana'] = 'を'; - map!['wokatakana'] = 'ヲ'; - map!['wokatakanahalfwidth'] = 'ヲ'; - map!['won'] = '₩'; - map!['wonmonospace'] = '₩'; - map!['wowaenthai'] = 'ว'; - map!['wparen'] = '⒲'; - map!['wring'] = 'ẘ'; - map!['wsuperior'] = 'ʷ'; - map!['wturned'] = 'ʍ'; - map!['wynn'] = 'ƿ'; - map!['x'] = 'x'; - map!['xabovecmb'] = '̽'; - map!['xbopomofo'] = 'ㄒ'; - map!['xcircle'] = 'ⓧ'; - map!['xdieresis'] = 'ẍ'; - map!['xdotaccent'] = 'ẋ'; - map!['xeharmenian'] = 'խ'; - map!['xi'] = 'ξ'; - map!['xmonospace'] = 'x'; - map!['xparen'] = '⒳'; - map!['xsuperior'] = 'ˣ'; - map!['y'] = 'y'; - map!['yaadosquare'] = '㍎'; - map!['yabengali'] = 'য'; - map!['yacute'] = 'ý'; - map!['yadeva'] = 'य'; - map!['yaekorean'] = 'ㅒ'; - map!['yagujarati'] = 'ય'; - map!['yagurmukhi'] = 'ਯ'; - map!['yahiragana'] = 'や'; - map!['yakatakana'] = 'ヤ'; - map!['yakatakanahalfwidth'] = 'ヤ'; - map!['yakorean'] = 'ㅑ'; - map!['yamakkanthai'] = '๎'; - map!['yasmallhiragana'] = 'ゃ'; - map!['yasmallkatakana'] = 'ャ'; - map!['yasmallkatakanahalfwidth'] = 'ャ'; - map!['yatcyrillic'] = 'ѣ'; - map!['ycircle'] = 'ⓨ'; - map!['ycircumflex'] = 'ŷ'; - map!['ydieresis'] = 'ÿ'; - map!['ydotaccent'] = 'ẏ'; - map!['ydotbelow'] = 'ỵ'; - map!['yeharabic'] = 'ي'; - map!['yehbarreearabic'] = 'ے'; - map!['yehbarreefinalarabic'] = 'ﮯ'; - map!['yehfinalarabic'] = 'ﻲ'; - map!['yehhamzaabovearabic'] = 'ئ'; - map!['yehhamzaabovefinalarabic'] = 'ﺊ'; - map!['yehhamzaaboveinitialarabic'] = 'ﺋ'; - map!['yehhamzaabovemedialarabic'] = 'ﺌ'; - map!['yehinitialarabic'] = 'ﻳ'; - map!['yehmedialarabic'] = 'ﻴ'; - map!['yehmeeminitialarabic'] = 'ﳝ'; - map!['yehmeemisolatedarabic'] = 'ﱘ'; - map!['yehnoonfinalarabic'] = 'ﲔ'; - map!['yehthreedotsbelowarabic'] = 'ۑ'; - map!['yekorean'] = 'ㅖ'; - map!['yen'] = '¥'; - map!['yenmonospace'] = '¥'; - map!['yeokorean'] = 'ㅕ'; - map!['yeorinhieuhkorean'] = 'ㆆ'; - map!['yerahbenyomohebrew'] = '֪'; - map!['yerahbenyomolefthebrew'] = '֪'; - map!['yericyrillic'] = 'ы'; - map!['yerudieresiscyrillic'] = 'ӹ'; - map!['yesieungkorean'] = 'ㆁ'; - map!['yesieungpansioskorean'] = 'ㆃ'; - map!['yesieungsioskorean'] = 'ㆂ'; - map!['yetivhebrew'] = '֚'; - map!['ygrave'] = 'ỳ'; - map!['yhook'] = 'ƴ'; - map!['yhookabove'] = 'ỷ'; - map!['yiarmenian'] = 'յ'; - map!['yicyrillic'] = 'ї'; - map!['yikorean'] = 'ㅢ'; - map!['yinyang'] = '☯'; - map!['yiwnarmenian'] = 'ւ'; - map!['ymonospace'] = 'y'; - map!['yod'] = 'י'; - map!['yoddagesh'] = 'יּ'; - map!['yoddageshhebrew'] = 'יּ'; - map!['yodhebrew'] = 'י'; - map!['yodyodhebrew'] = 'ײ'; - map!['yodyodpatahhebrew'] = 'ײַ'; - map!['yohiragana'] = 'よ'; - map!['yoikorean'] = 'ㆉ'; - map!['yokatakana'] = 'ヨ'; - map!['yokatakanahalfwidth'] = 'ヨ'; - map!['yokorean'] = 'ㅛ'; - map!['yosmallhiragana'] = 'ょ'; - map!['yosmallkatakana'] = 'ョ'; - map!['yosmallkatakanahalfwidth'] = 'ョ'; - map!['yotgreek'] = 'ϳ'; - map!['yoyaekorean'] = 'ㆈ'; - map!['yoyakorean'] = 'ㆇ'; - map!['yoyakthai'] = 'ย'; - map!['yoyingthai'] = 'ญ'; - map!['yparen'] = '⒴'; - map!['ypogegrammeni'] = 'ͺ'; - map!['ypogegrammenigreekcmb'] = 'ͅ'; - map!['yr'] = 'Ʀ'; - map!['yring'] = 'ẙ'; - map!['ysuperior'] = 'ʸ'; - map!['ytilde'] = 'ỹ'; - map!['yturned'] = 'ʎ'; - map!['yuhiragana'] = 'ゆ'; - map!['yuikorean'] = 'ㆌ'; - map!['yukatakana'] = 'ユ'; - map!['yukatakanahalfwidth'] = 'ユ'; - map!['yukorean'] = 'ㅠ'; - map!['yusbigcyrillic'] = 'ѫ'; - map!['yusbigiotifiedcyrillic'] = 'ѭ'; - map!['yuslittlecyrillic'] = 'ѧ'; - map!['yuslittleiotifiedcyrillic'] = 'ѩ'; - map!['yusmallhiragana'] = 'ゅ'; - map!['yusmallkatakana'] = 'ュ'; - map!['yusmallkatakanahalfwidth'] = 'ュ'; - map!['yuyekorean'] = 'ㆋ'; - map!['yuyeokorean'] = 'ㆊ'; - map!['yyabengali'] = 'য়'; - map!['yyadeva'] = 'य़'; - map!['z'] = 'z'; - map!['zaarmenian'] = 'զ'; - map!['zacute'] = 'ź'; - map!['zadeva'] = 'ज़'; - map!['zagurmukhi'] = 'ਜ਼'; - map!['zaharabic'] = 'ظ'; - map!['zahfinalarabic'] = 'ﻆ'; - map!['zahinitialarabic'] = 'ﻇ'; - map!['zahiragana'] = 'ざ'; - map!['zahmedialarabic'] = 'ﻈ'; - map!['zainarabic'] = 'ز'; - map!['zainfinalarabic'] = 'ﺰ'; - map!['zakatakana'] = 'ザ'; - map!['zaqefgadolhebrew'] = '֕'; - map!['zaqefqatanhebrew'] = '֔'; - map!['zarqahebrew'] = '֘'; - map!['zayin'] = 'ז'; - map!['zayindagesh'] = 'זּ'; - map!['zayindageshhebrew'] = 'זּ'; - map!['zayinhebrew'] = 'ז'; - map!['zbopomofo'] = 'ㄗ'; - map!['zcaron'] = 'ž'; - map!['zcircle'] = 'ⓩ'; - map!['zcircumflex'] = 'ẑ'; - map!['zcurl'] = 'ʑ'; - map!['zdot'] = 'ż'; - map!['zdotaccent'] = 'ż'; - map!['zdotbelow'] = 'ẓ'; - map!['zecyrillic'] = 'з'; - map!['zedescendercyrillic'] = 'ҙ'; - map!['zedieresiscyrillic'] = 'ӟ'; - map!['zehiragana'] = 'ぜ'; - map!['zekatakana'] = 'ゼ'; - map!['zero'] = '0'; - map!['zeroarabic'] = '٠'; - map!['zerobengali'] = '০'; - map!['zerodeva'] = '०'; - map!['zerogujarati'] = '૦'; - map!['zerogurmukhi'] = '੦'; - map!['zerohackarabic'] = '٠'; - map!['zeroinferior'] = '₀'; - map!['zeromonospace'] = '0'; - map!['zerooldstyle'] = ''; - map!['zeropersian'] = '۰'; - map!['zerosuperior'] = '⁰'; - map!['zerothai'] = '๐'; - map!['zerowidthjoiner'] = ''; - map!['zerowidthnonjoiner'] = '‌'; - map!['zerowidthspace'] = '​'; - map!['zeta'] = 'ζ'; - map!['zhbopomofo'] = 'ㄓ'; - map!['zhearmenian'] = 'ժ'; - map!['zhebrevecyrillic'] = 'ӂ'; - map!['zhecyrillic'] = 'ж'; - map!['zhedescendercyrillic'] = 'җ'; - map!['zhedieresiscyrillic'] = 'ӝ'; - map!['zihiragana'] = 'じ'; - map!['zikatakana'] = 'ジ'; - map!['zinorhebrew'] = '֮'; - map!['zlinebelow'] = 'ẕ'; - map!['zmonospace'] = 'z'; - map!['zohiragana'] = 'ぞ'; - map!['zokatakana'] = 'ゾ'; - map!['zparen'] = '⒵'; - map!['zretroflexhook'] = 'ʐ'; - map!['zstroke'] = 'ƶ'; - map!['zuhiragana'] = 'ず'; - map!['zukatakana'] = 'ズ'; - } - - /// internal method - String? getUnicode(String? names) { - if (names == null) { - return '\u0000'; - } - final int n = names.indexOf('.'); - if (n > 0) { - names = names.substring(0, n); - } - final List array = names.split('_'); - if (array.isNotEmpty) { - return getUnicodeForName(array[0]); - } - return '\u0000'; - } - - /// internal method - String parseHex(String hex) { - String result; - try { - result = String.fromCharCode(int.parse(hex, radix: 16)); - } catch (e) { - result = '\u0000'; - } - return result; - } - - /// internal method - String? getUnicodeForName(String name) { - if (map!.containsKey(name)) { - return map![name]; - } - if (name.startsWith('uni')) { - name = name.substring(3); - if (name.length >= 4) { - return parseHex(name.substring(0, 4)); - } - return '\u0000'; - } else { - if (name.startsWith('u')) { - return parseHex(name.substring(1, name.length)); - } - throw ArgumentError('The encoding is not supported.'); - } - } -} +// ignore_for_file: text_direction_code_point_in_literal +/// internal constructor +class AdobeGlyphList { + // Constructor + /// internal class + AdobeGlyphList() { + initialize(); + } + + // Fields + /// internal field + Map? map; + + // Implementations + /// internal method + void initialize() { + map = {}; + map!['A'] = 'A'; + map!['AE'] = 'Æ'; + map!['AEacute'] = 'Ǽ'; + map!['AEmacron'] = 'Ǣ'; + map!['AEsmall'] = ''; + map!['Aacute'] = 'Á'; + map!['Aacutesmall'] = ''; + map!['Abreve'] = 'Ă'; + map!['Abreveacute'] = 'Ắ'; + map!['Abrevecyrillic'] = 'Ӑ'; + map!['Abrevedotbelow'] = 'Ặ'; + map!['Abrevegrave'] = 'Ằ'; + map!['Abrevehookabove'] = 'Ẳ'; + map!['Abrevetilde'] = 'Ẵ'; + map!['Acaron'] = 'Ǎ'; + map!['Acircle'] = 'Ⓐ'; + map!['Acircumflex'] = 'Â'; + map!['Acircumflexacute'] = 'Ấ'; + map!['Acircumflexdotbelow'] = 'Ậ'; + map!['Acircumflexgrave'] = 'Ầ'; + map!['Acircumflexhookabove'] = 'Ẩ'; + map!['Acircumflexsmall'] = ''; + map!['Acircumflextilde'] = 'Ẫ'; + map!['Acute'] = ''; + map!['Acutesmall'] = ''; + map!['Acyrillic'] = 'А'; + map!['Adblgrave'] = 'Ȁ'; + map!['Adieresis'] = 'Ä'; + map!['Adieresiscyrillic'] = 'Ӓ'; + map!['Adieresismacron'] = 'Ǟ'; + map!['Adieresissmall'] = ''; + map!['Adotbelow'] = 'Ạ'; + map!['Adotmacron'] = 'Ǡ'; + map!['Agrave'] = 'À'; + map!['Agravesmall'] = ''; + map!['Ahookabove'] = 'Ả'; + map!['Aiecyrillic'] = 'Ӕ'; + map!['Ainvertedbreve'] = 'Ȃ'; + map!['Alpha'] = 'Α'; + map!['Alphatonos'] = 'Ά'; + map!['Amacron'] = 'Ā'; + map!['Amonospace'] = 'A'; + map!['Aogonek'] = 'Ą'; + map!['Aring'] = 'Å'; + map!['Aringacute'] = 'Ǻ'; + map!['Aringbelow'] = 'Ḁ'; + map!['Aringsmall'] = ''; + map!['Asmall'] = ''; + map!['Atilde'] = 'Ã'; + map!['Atildesmall'] = ''; + map!['Aybarmenian'] = 'Ա'; + map!['B'] = 'B'; + map!['Bcircle'] = 'Ⓑ'; + map!['Bdotaccent'] = 'Ḃ'; + map!['Bdotbelow'] = 'Ḅ'; + map!['Becyrillic'] = 'Б'; + map!['Benarmenian'] = 'Բ'; + map!['Beta'] = 'Β'; + map!['Bhook'] = 'Ɓ'; + map!['Blinebelow'] = 'Ḇ'; + map!['Bmonospace'] = 'B'; + map!['Brevesmall'] = ''; + map!['Bsmall'] = ''; + map!['Btopbar'] = 'Ƃ'; + map!['C'] = 'C'; + map!['Caarmenian'] = 'Ծ'; + map!['Cacute'] = 'Ć'; + map!['Caron'] = ''; + map!['Caronsmall'] = ''; + map!['Ccaron'] = 'Č'; + map!['Ccedilla'] = 'Ç'; + map!['Ccedillaacute'] = 'Ḉ'; + map!['Ccedillasmall'] = ''; + map!['Ccircle'] = 'Ⓒ'; + map!['Ccircumflex'] = 'Ĉ'; + map!['Cdot'] = 'Ċ'; + map!['Cdotaccent'] = 'Ċ'; + map!['Cedillasmall'] = ''; + map!['Chaarmenian'] = 'Չ'; + map!['Cheabkhasiancyrillic'] = 'Ҽ'; + map!['Checyrillic'] = 'Ч'; + map!['Chedescenderabkhasiancyrillic'] = 'Ҿ'; + map!['Chedescendercyrillic'] = 'Ҷ'; + map!['Chedieresiscyrillic'] = 'Ӵ'; + map!['Cheharmenian'] = 'Ճ'; + map!['Chekhakassiancyrillic'] = 'Ӌ'; + map!['Cheverticalstrokecyrillic'] = 'Ҹ'; + map!['Chi'] = 'Χ'; + map!['Chook'] = 'Ƈ'; + map!['Circumflexsmall'] = ''; + map!['Cmonospace'] = 'C'; + map!['Coarmenian'] = 'Ց'; + map!['Csmall'] = ''; + map!['D'] = 'D'; + map!['DZ'] = 'DZ'; + map!['DZcaron'] = 'DŽ'; + map!['Daarmenian'] = 'Դ'; + map!['Dafrican'] = 'Ɖ'; + map!['Dcaron'] = 'Ď'; + map!['Dcedilla'] = 'Ḑ'; + map!['Dcircle'] = 'Ⓓ'; + map!['Dcircumflexbelow'] = 'Ḓ'; + map!['Dcroat'] = 'Đ'; + map!['Ddotaccent'] = 'Ḋ'; + map!['Ddotbelow'] = 'Ḍ'; + map!['Decyrillic'] = 'Д'; + map!['Deicoptic'] = 'Ϯ'; + map!['Delta'] = '∆'; + map!['Deltagreek'] = 'Δ'; + map!['Dhook'] = 'Ɗ'; + map!['Dieresis'] = ''; + map!['DieresisAcute'] = ''; + map!['DieresisGrave'] = ''; + map!['Dieresissmall'] = ''; + map!['Digammagreek'] = 'Ϝ'; + map!['Djecyrillic'] = 'Ђ'; + map!['Dlinebelow'] = 'Ḏ'; + map!['Dmonospace'] = 'D'; + map!['Dotaccentsmall'] = ''; + map!['Dslash'] = 'Đ'; + map!['Dsmall'] = ''; + map!['Dtopbar'] = 'Ƌ'; + map!['Dz'] = 'Dz'; + map!['Dzcaron'] = 'Dž'; + map!['Dzeabkhasiancyrillic'] = 'Ӡ'; + map!['Dzecyrillic'] = 'Ѕ'; + map!['Dzhecyrillic'] = 'Џ'; + map!['E'] = 'E'; + map!['Eacute'] = 'É'; + map!['Eacutesmall'] = ''; + map!['Ebreve'] = 'Ĕ'; + map!['Ecaron'] = 'Ě'; + map!['Ecedillabreve'] = 'Ḝ'; + map!['Echarmenian'] = 'Ե'; + map!['Ecircle'] = 'Ⓔ'; + map!['Ecircumflex'] = 'Ê'; + map!['Ecircumflexacute'] = 'Ế'; + map!['Ecircumflexbelow'] = 'Ḙ'; + map!['Ecircumflexdotbelow'] = 'Ệ'; + map!['Ecircumflexgrave'] = 'Ề'; + map!['Ecircumflexhookabove'] = 'Ể'; + map!['Ecircumflexsmall'] = ''; + map!['Ecircumflextilde'] = 'Ễ'; + map!['Ecyrillic'] = 'Є'; + map!['Edblgrave'] = 'Ȅ'; + map!['Edieresis'] = 'Ë'; + map!['Edieresissmall'] = ''; + map!['Edot'] = 'Ė'; + map!['Edotaccent'] = 'Ė'; + map!['Edotbelow'] = 'Ẹ'; + map!['Efcyrillic'] = 'Ф'; + map!['Egrave'] = 'È'; + map!['Egravesmall'] = ''; + map!['Eharmenian'] = 'Է'; + map!['Ehookabove'] = 'Ẻ'; + map!['Eightroman'] = 'Ⅷ'; + map!['Einvertedbreve'] = 'Ȇ'; + map!['Eiotifiedcyrillic'] = 'Ѥ'; + map!['Elcyrillic'] = 'Л'; + map!['Elevenroman'] = 'Ⅺ'; + map!['Emacron'] = 'Ē'; + map!['Emacronacute'] = 'Ḗ'; + map!['Emacrongrave'] = 'Ḕ'; + map!['Emcyrillic'] = 'М'; + map!['Emonospace'] = 'E'; + map!['Encyrillic'] = 'Н'; + map!['Endescendercyrillic'] = 'Ң'; + map!['Eng'] = 'Ŋ'; + map!['Enghecyrillic'] = 'Ҥ'; + map!['Enhookcyrillic'] = 'Ӈ'; + map!['Eogonek'] = 'Ę'; + map!['Eopen'] = 'Ɛ'; + map!['Epsilon'] = 'Ε'; + map!['Epsilontonos'] = 'Έ'; + map!['Ercyrillic'] = 'Р'; + map!['Ereversed'] = 'Ǝ'; + map!['Ereversedcyrillic'] = 'Э'; + map!['Escyrillic'] = 'С'; + map!['Esdescendercyrillic'] = 'Ҫ'; + map!['Esh'] = 'Ʃ'; + map!['Esmall'] = ''; + map!['Eta'] = 'Η'; + map!['Etarmenian'] = 'Ը'; + map!['Etatonos'] = 'Ή'; + map!['Eth'] = 'Ð'; + map!['Ethsmall'] = ''; + map!['Etilde'] = 'Ẽ'; + map!['Etildebelow'] = 'Ḛ'; + map!['Euro'] = '€'; + map!['Ezh'] = 'Ʒ'; + map!['Ezhcaron'] = 'Ǯ'; + map!['Ezhreversed'] = 'Ƹ'; + map!['F'] = 'F'; + map!['Fcircle'] = 'Ⓕ'; + map!['Fdotaccent'] = 'Ḟ'; + map!['Feharmenian'] = 'Ֆ'; + map!['Feicoptic'] = 'Ϥ'; + map!['Fhook'] = 'Ƒ'; + map!['Fitacyrillic'] = 'Ѳ'; + map!['Fiveroman'] = 'Ⅴ'; + map!['Fmonospace'] = 'F'; + map!['Fourroman'] = 'Ⅳ'; + map!['Fsmall'] = ''; + map!['G'] = 'G'; + map!['GBsquare'] = '㎇'; + map!['Gacute'] = 'Ǵ'; + map!['Gamma'] = 'Γ'; + map!['Gammaafrican'] = 'Ɣ'; + map!['Gangiacoptic'] = 'Ϫ'; + map!['Gbreve'] = 'Ğ'; + map!['Gcaron'] = 'Ǧ'; + map!['Gcedilla'] = 'Ģ'; + map!['Gcircle'] = 'Ⓖ'; + map!['Gcircumflex'] = 'Ĝ'; + map!['Gcommaaccent'] = 'Ģ'; + map!['Gdot'] = 'Ġ'; + map!['Gdotaccent'] = 'Ġ'; + map!['Gecyrillic'] = 'Г'; + map!['Ghadarmenian'] = 'Ղ'; + map!['Ghemiddlehookcyrillic'] = 'Ҕ'; + map!['Ghestrokecyrillic'] = 'Ғ'; + map!['Gheupturncyrillic'] = 'Ґ'; + map!['Ghook'] = 'Ɠ'; + map!['Gimarmenian'] = 'Գ'; + map!['Gjecyrillic'] = 'Ѓ'; + map!['Gmacron'] = 'Ḡ'; + map!['Gmonospace'] = 'G'; + map!['Grave'] = ''; + map!['Gravesmall'] = ''; + map!['Gsmall'] = ''; + map!['Gsmallhook'] = 'ʛ'; + map!['Gstroke'] = 'Ǥ'; + map!['H'] = 'H'; + map!['H18533'] = '●'; + map!['H18543'] = '▪'; + map!['H18551'] = '▫'; + map!['H22073'] = '□'; + map!['HPsquare'] = '㏋'; + map!['Haabkhasiancyrillic'] = 'Ҩ'; + map!['Hadescendercyrillic'] = 'Ҳ'; + map!['Hardsigncyrillic'] = 'Ъ'; + map!['Hbar'] = 'Ħ'; + map!['Hbrevebelow'] = 'Ḫ'; + map!['Hcedilla'] = 'Ḩ'; + map!['Hcircle'] = 'Ⓗ'; + map!['Hcircumflex'] = 'Ĥ'; + map!['Hdieresis'] = 'Ḧ'; + map!['Hdotaccent'] = 'Ḣ'; + map!['Hdotbelow'] = 'Ḥ'; + map!['Hmonospace'] = 'H'; + map!['Hoarmenian'] = 'Հ'; + map!['Horicoptic'] = 'Ϩ'; + map!['Hsmall'] = ''; + map!['Hungarumlaut'] = ''; + map!['Hungarumlautsmall'] = ''; + map!['Hzsquare'] = '㎐'; + map!['I'] = 'I'; + map!['IAcyrillic'] = 'Я'; + map!['IJ'] = 'IJ'; + map!['IUcyrillic'] = 'Ю'; + map!['Iacute'] = 'Í'; + map!['Iacutesmall'] = ''; + map!['Ibreve'] = 'Ĭ'; + map!['Icaron'] = 'Ǐ'; + map!['Icircle'] = 'Ⓘ'; + map!['Icircumflex'] = 'Î'; + map!['Icircumflexsmall'] = ''; + map!['Icyrillic'] = 'І'; + map!['Idblgrave'] = 'Ȉ'; + map!['Idieresis'] = 'Ï'; + map!['Idieresisacute'] = 'Ḯ'; + map!['Idieresiscyrillic'] = 'Ӥ'; + map!['Idieresissmall'] = ''; + map!['Idot'] = 'İ'; + map!['Idotaccent'] = 'İ'; + map!['Idotbelow'] = 'Ị'; + map!['Iebrevecyrillic'] = 'Ӗ'; + map!['Iecyrillic'] = 'Е'; + map!['Ifraktur'] = 'ℑ'; + map!['Igrave'] = 'Ì'; + map!['Igravesmall'] = ''; + map!['Ihookabove'] = 'Ỉ'; + map!['Iicyrillic'] = 'И'; + map!['Iinvertedbreve'] = 'Ȋ'; + map!['Iishortcyrillic'] = 'Й'; + map!['Imacron'] = 'Ī'; + map!['Imacroncyrillic'] = 'Ӣ'; + map!['Imonospace'] = 'I'; + map!['Iniarmenian'] = 'Ի'; + map!['Iocyrillic'] = 'Ё'; + map!['Iogonek'] = 'Į'; + map!['Iota'] = 'Ι'; + map!['Iotaafrican'] = 'Ɩ'; + map!['Iotadieresis'] = 'Ϊ'; + map!['Iotatonos'] = 'Ί'; + map!['Ismall'] = ''; + map!['Istroke'] = 'Ɨ'; + map!['Itilde'] = 'Ĩ'; + map!['Itildebelow'] = 'Ḭ'; + map!['Izhitsacyrillic'] = 'Ѵ'; + map!['Izhitsadblgravecyrillic'] = 'Ѷ'; + map!['J'] = 'J'; + map!['Jaarmenian'] = 'Ձ'; + map!['Jcircle'] = 'Ⓙ'; + map!['Jcircumflex'] = 'Ĵ'; + map!['Jecyrillic'] = 'Ј'; + map!['Jheharmenian'] = 'Ջ'; + map!['Jmonospace'] = 'J'; + map!['Jsmall'] = ''; + map!['K'] = 'K'; + map!['KBsquare'] = '㎅'; + map!['KKsquare'] = '㏍'; + map!['Kabashkircyrillic'] = 'Ҡ'; + map!['Kacute'] = 'Ḱ'; + map!['Kacyrillic'] = 'К'; + map!['Kadescendercyrillic'] = 'Қ'; + map!['Kahookcyrillic'] = 'Ӄ'; + map!['Kappa'] = 'Κ'; + map!['Kastrokecyrillic'] = 'Ҟ'; + map!['Kaverticalstrokecyrillic'] = 'Ҝ'; + map!['Kcaron'] = 'Ǩ'; + map!['Kcedilla'] = 'Ķ'; + map!['Kcircle'] = 'Ⓚ'; + map!['Kcommaaccent'] = 'Ķ'; + map!['Kdotbelow'] = 'Ḳ'; + map!['Keharmenian'] = 'Ք'; + map!['Kenarmenian'] = 'Կ'; + map!['Khacyrillic'] = 'Х'; + map!['Kheicoptic'] = 'Ϧ'; + map!['Khook'] = 'Ƙ'; + map!['Kjecyrillic'] = 'Ќ'; + map!['Klinebelow'] = 'Ḵ'; + map!['Kmonospace'] = 'K'; + map!['Koppacyrillic'] = 'Ҁ'; + map!['Koppagreek'] = 'Ϟ'; + map!['Ksicyrillic'] = 'Ѯ'; + map!['Ksmall'] = ''; + map!['L'] = 'L'; + map!['LJ'] = 'LJ'; + map!['LL'] = ''; + map!['Lacute'] = 'Ĺ'; + map!['Lambda'] = 'Λ'; + map!['Lcaron'] = 'Ľ'; + map!['Lcedilla'] = 'Ļ'; + map!['Lcircle'] = 'Ⓛ'; + map!['Lcircumflexbelow'] = 'Ḽ'; + map!['Lcommaaccent'] = 'Ļ'; + map!['Ldot'] = 'Ŀ'; + map!['Ldotaccent'] = 'Ŀ'; + map!['Ldotbelow'] = 'Ḷ'; + map!['Ldotbelowmacron'] = 'Ḹ'; + map!['Liwnarmenian'] = 'Լ'; + map!['Lj'] = 'Lj'; + map!['Ljecyrillic'] = 'Љ'; + map!['Llinebelow'] = 'Ḻ'; + map!['Lmonospace'] = 'L'; + map!['Lslash'] = 'Ł'; + map!['Lslashsmall'] = ''; + map!['Lsmall'] = ''; + map!['M'] = 'M'; + map!['MBsquare'] = '㎆'; + map!['Macron'] = ''; + map!['Macronsmall'] = ''; + map!['Macute'] = 'Ḿ'; + map!['Mcircle'] = 'Ⓜ'; + map!['Mdotaccent'] = 'Ṁ'; + map!['Mdotbelow'] = 'Ṃ'; + map!['Menarmenian'] = 'Մ'; + map!['Mmonospace'] = 'M'; + map!['Msmall'] = ''; + map!['Mturned'] = 'Ɯ'; + map!['Mu'] = 'Μ'; + map!['N'] = 'N'; + map!['NJ'] = 'NJ'; + map!['Nacute'] = 'Ń'; + map!['Ncaron'] = 'Ň'; + map!['Ncedilla'] = 'Ņ'; + map!['Ncircle'] = 'Ⓝ'; + map!['Ncircumflexbelow'] = 'Ṋ'; + map!['Ncommaaccent'] = 'Ņ'; + map!['Ndotaccent'] = 'Ṅ'; + map!['Ndotbelow'] = 'Ṇ'; + map!['Nhookleft'] = 'Ɲ'; + map!['Nineroman'] = 'Ⅸ'; + map!['Nj'] = 'Nj'; + map!['Njecyrillic'] = 'Њ'; + map!['Nlinebelow'] = 'Ṉ'; + map!['Nmonospace'] = 'N'; + map!['Nowarmenian'] = 'Ն'; + map!['Nsmall'] = ''; + map!['Ntilde'] = 'Ñ'; + map!['Ntildesmall'] = ''; + map!['Nu'] = 'Ν'; + map!['O'] = 'O'; + map!['OE'] = 'Œ'; + map!['OEsmall'] = ''; + map!['Oacute'] = 'Ó'; + map!['Oacutesmall'] = ''; + map!['Obarredcyrillic'] = 'Ө'; + map!['Obarreddieresiscyrillic'] = 'Ӫ'; + map!['Obreve'] = 'Ŏ'; + map!['Ocaron'] = 'Ǒ'; + map!['Ocenteredtilde'] = 'Ɵ'; + map!['Ocircle'] = 'Ⓞ'; + map!['Ocircumflex'] = 'Ô'; + map!['Ocircumflexacute'] = 'Ố'; + map!['Ocircumflexdotbelow'] = 'Ộ'; + map!['Ocircumflexgrave'] = 'Ồ'; + map!['Ocircumflexhookabove'] = 'Ổ'; + map!['Ocircumflexsmall'] = ''; + map!['Ocircumflextilde'] = 'Ỗ'; + map!['Ocyrillic'] = 'О'; + map!['Odblacute'] = 'Ő'; + map!['Odblgrave'] = 'Ȍ'; + map!['Odieresis'] = 'Ö'; + map!['Odieresiscyrillic'] = 'Ӧ'; + map!['Odieresissmall'] = ''; + map!['Odotbelow'] = 'Ọ'; + map!['Ogoneksmall'] = ''; + map!['Ograve'] = 'Ò'; + map!['Ogravesmall'] = ''; + map!['Oharmenian'] = 'Օ'; + map!['Ohm'] = 'Ω'; + map!['Ohookabove'] = 'Ỏ'; + map!['Ohorn'] = 'Ơ'; + map!['Ohornacute'] = 'Ớ'; + map!['Ohorndotbelow'] = 'Ợ'; + map!['Ohorngrave'] = 'Ờ'; + map!['Ohornhookabove'] = 'Ở'; + map!['Ohorntilde'] = 'Ỡ'; + map!['Ohungarumlaut'] = 'Ő'; + map!['Oi'] = 'Ƣ'; + map!['Oinvertedbreve'] = 'Ȏ'; + map!['Omacron'] = 'Ō'; + map!['Omacronacute'] = 'Ṓ'; + map!['Omacrongrave'] = 'Ṑ'; + map!['Omega'] = 'Ω'; + map!['Omegacyrillic'] = 'Ѡ'; + map!['Omegagreek'] = 'Ω'; + map!['Omegaroundcyrillic'] = 'Ѻ'; + map!['Omegatitlocyrillic'] = 'Ѽ'; + map!['Omegatonos'] = 'Ώ'; + map!['Omicron'] = 'Ο'; + map!['Omicrontonos'] = 'Ό'; + map!['Omonospace'] = 'O'; + map!['Oneroman'] = 'Ⅰ'; + map!['Oogonek'] = 'Ǫ'; + map!['Oogonekmacron'] = 'Ǭ'; + map!['Oopen'] = 'Ɔ'; + map!['Oslash'] = 'Ø'; + map!['Oslashacute'] = 'Ǿ'; + map!['Oslashsmall'] = ''; + map!['Osmall'] = ''; + map!['Ostrokeacute'] = 'Ǿ'; + map!['Otcyrillic'] = 'Ѿ'; + map!['Otilde'] = 'Õ'; + map!['Otildeacute'] = 'Ṍ'; + map!['Otildedieresis'] = 'Ṏ'; + map!['Otildesmall'] = ''; + map!['P'] = 'P'; + map!['Pacute'] = 'Ṕ'; + map!['Pcircle'] = 'Ⓟ'; + map!['Pdotaccent'] = 'Ṗ'; + map!['Pecyrillic'] = 'П'; + map!['Peharmenian'] = 'Պ'; + map!['Pemiddlehookcyrillic'] = 'Ҧ'; + map!['Phi'] = 'Φ'; + map!['Phook'] = 'Ƥ'; + map!['Pi'] = 'Π'; + map!['Piwrarmenian'] = 'Փ'; + map!['Pmonospace'] = 'P'; + map!['Psi'] = 'Ψ'; + map!['Psicyrillic'] = 'Ѱ'; + map!['Psmall'] = ''; + map!['Q'] = 'Q'; + map!['Qcircle'] = 'Ⓠ'; + map!['Qmonospace'] = 'Q'; + map!['Qsmall'] = ''; + map!['R'] = 'R'; + map!['Raarmenian'] = 'Ռ'; + map!['Racute'] = 'Ŕ'; + map!['Rcaron'] = 'Ř'; + map!['Rcedilla'] = 'Ŗ'; + map!['Rcircle'] = 'Ⓡ'; + map!['Rcommaaccent'] = 'Ŗ'; + map!['Rdblgrave'] = 'Ȑ'; + map!['Rdotaccent'] = 'Ṙ'; + map!['Rdotbelow'] = 'Ṛ'; + map!['Rdotbelowmacron'] = 'Ṝ'; + map!['Reharmenian'] = 'Ր'; + map!['Rfraktur'] = 'ℜ'; + map!['Rho'] = 'Ρ'; + map!['Ringsmall'] = ''; + map!['Rinvertedbreve'] = 'Ȓ'; + map!['Rlinebelow'] = 'Ṟ'; + map!['Rmonospace'] = 'R'; + map!['Rsmall'] = ''; + map!['Rsmallinverted'] = 'ʁ'; + map!['Rsmallinvertedsuperior'] = 'ʶ'; + map!['S'] = 'S'; + map!['SF010000'] = '┌'; + map!['SF020000'] = '└'; + map!['SF030000'] = '┐'; + map!['SF040000'] = '┘'; + map!['SF050000'] = '┼'; + map!['SF060000'] = '┬'; + map!['SF070000'] = '┴'; + map!['SF080000'] = '├'; + map!['SF090000'] = '┤'; + map!['SF100000'] = '─'; + map!['SF110000'] = '│'; + map!['SF190000'] = '╡'; + map!['SF200000'] = '╢'; + map!['SF210000'] = '╖'; + map!['SF220000'] = '╕'; + map!['SF230000'] = '╣'; + map!['SF240000'] = '║'; + map!['SF250000'] = '╗'; + map!['SF260000'] = '╝'; + map!['SF270000'] = '╜'; + map!['SF280000'] = '╛'; + map!['SF360000'] = '╞'; + map!['SF370000'] = '╟'; + map!['SF380000'] = '╚'; + map!['SF390000'] = '╔'; + map!['SF400000'] = '╩'; + map!['SF410000'] = '╦'; + map!['SF420000'] = '╠'; + map!['SF430000'] = '═'; + map!['SF440000'] = '╬'; + map!['SF450000'] = '╧'; + map!['SF460000'] = '╨'; + map!['SF470000'] = '╤'; + map!['SF480000'] = '╥'; + map!['SF490000'] = '╙'; + map!['SF500000'] = '╘'; + map!['SF510000'] = '╒'; + map!['SF520000'] = '╓'; + map!['SF530000'] = '╫'; + map!['SF540000'] = '╪'; + map!['Sacute'] = 'Ś'; + map!['Sacutedotaccent'] = 'Ṥ'; + map!['Sampigreek'] = 'Ϡ'; + map!['Scaron'] = 'Š'; + map!['Scarondotaccent'] = 'Ṧ'; + map!['Scaronsmall'] = ''; + map!['Scedilla'] = 'Ş'; + map!['Schwa'] = 'Ə'; + map!['Schwacyrillic'] = 'Ә'; + map!['Schwadieresiscyrillic'] = 'Ӛ'; + map!['Scircle'] = 'Ⓢ'; + map!['Scircumflex'] = 'Ŝ'; + map!['Scommaaccent'] = 'Ș'; + map!['Sdotaccent'] = 'Ṡ'; + map!['Sdotbelow'] = 'Ṣ'; + map!['Sdotbelowdotaccent'] = 'Ṩ'; + map!['Seharmenian'] = 'Ս'; + map!['Sevenroman'] = 'Ⅶ'; + map!['Shaarmenian'] = 'Շ'; + map!['Shacyrillic'] = 'Ш'; + map!['Shchacyrillic'] = 'Щ'; + map!['Sheicoptic'] = 'Ϣ'; + map!['Shhacyrillic'] = 'Һ'; + map!['Shimacoptic'] = 'Ϭ'; + map!['Sigma'] = 'Σ'; + map!['Sixroman'] = 'Ⅵ'; + map!['Smonospace'] = 'S'; + map!['Softsigncyrillic'] = 'Ь'; + map!['Ssmall'] = ''; + map!['Stigmagreek'] = 'Ϛ'; + map!['T'] = 'T'; + map!['Tau'] = 'Τ'; + map!['Tbar'] = 'Ŧ'; + map!['Tcaron'] = 'Ť'; + map!['Tcedilla'] = 'Ţ'; + map!['Tcircle'] = 'Ⓣ'; + map!['Tcircumflexbelow'] = 'Ṱ'; + map!['Tcommaaccent'] = 'Ţ'; + map!['Tdotaccent'] = 'Ṫ'; + map!['Tdotbelow'] = 'Ṭ'; + map!['Tecyrillic'] = 'Т'; + map!['Tedescendercyrillic'] = 'Ҭ'; + map!['Tenroman'] = 'Ⅹ'; + map!['Tetsecyrillic'] = 'Ҵ'; + map!['Theta'] = 'Θ'; + map!['Thook'] = 'Ƭ'; + map!['Thorn'] = 'Þ'; + map!['Thornsmall'] = ''; + map!['Threeroman'] = 'Ⅲ'; + map!['Tildesmall'] = ''; + map!['Tiwnarmenian'] = 'Տ'; + map!['Tlinebelow'] = 'Ṯ'; + map!['Tmonospace'] = 'T'; + map!['Toarmenian'] = 'Թ'; + map!['Tonefive'] = 'Ƽ'; + map!['Tonesix'] = 'Ƅ'; + map!['Tonetwo'] = 'Ƨ'; + map!['Tretroflexhook'] = 'Ʈ'; + map!['Tsecyrillic'] = 'Ц'; + map!['Tshecyrillic'] = 'Ћ'; + map!['Tsmall'] = ''; + map!['Twelveroman'] = 'Ⅻ'; + map!['Tworoman'] = 'Ⅱ'; + map!['U'] = 'U'; + map!['Uacute'] = 'Ú'; + map!['Uacutesmall'] = ''; + map!['Ubreve'] = 'Ŭ'; + map!['Ucaron'] = 'Ǔ'; + map!['Ucircle'] = 'Ⓤ'; + map!['Ucircumflex'] = 'Û'; + map!['Ucircumflexbelow'] = 'Ṷ'; + map!['Ucircumflexsmall'] = ''; + map!['Ucyrillic'] = 'У'; + map!['Udblacute'] = 'Ű'; + map!['Udblgrave'] = 'Ȕ'; + map!['Udieresis'] = 'Ü'; + map!['Udieresisacute'] = 'Ǘ'; + map!['Udieresisbelow'] = 'Ṳ'; + map!['Udieresiscaron'] = 'Ǚ'; + map!['Udieresiscyrillic'] = 'Ӱ'; + map!['Udieresisgrave'] = 'Ǜ'; + map!['Udieresismacron'] = 'Ǖ'; + map!['Udieresissmall'] = ''; + map!['Udotbelow'] = 'Ụ'; + map!['Ugrave'] = 'Ù'; + map!['Ugravesmall'] = ''; + map!['Uhookabove'] = 'Ủ'; + map!['Uhorn'] = 'Ư'; + map!['Uhornacute'] = 'Ứ'; + map!['Uhorndotbelow'] = 'Ự'; + map!['Uhorngrave'] = 'Ừ'; + map!['Uhornhookabove'] = 'Ử'; + map!['Uhorntilde'] = 'Ữ'; + map!['Uhungarumlaut'] = 'Ű'; + map!['Uhungarumlautcyrillic'] = 'Ӳ'; + map!['Uinvertedbreve'] = 'Ȗ'; + map!['Ukcyrillic'] = 'Ѹ'; + map!['Umacron'] = 'Ū'; + map!['Umacroncyrillic'] = 'Ӯ'; + map!['Umacrondieresis'] = 'Ṻ'; + map!['Umonospace'] = 'U'; + map!['Uogonek'] = 'Ų'; + map!['Upsilon'] = 'Υ'; + map!['Upsilon1'] = 'ϒ'; + map!['Upsilonacutehooksymbolgreek'] = 'ϓ'; + map!['Upsilonafrican'] = 'Ʊ'; + map!['Upsilondieresis'] = 'Ϋ'; + map!['Upsilondieresishooksymbolgreek'] = 'ϔ'; + map!['Upsilonhooksymbol'] = 'ϒ'; + map!['Upsilontonos'] = 'Ύ'; + map!['Uring'] = 'Ů'; + map!['Ushortcyrillic'] = 'Ў'; + map!['Usmall'] = ''; + map!['Ustraightcyrillic'] = 'Ү'; + map!['Ustraightstrokecyrillic'] = 'Ұ'; + map!['Utilde'] = 'Ũ'; + map!['Utildeacute'] = 'Ṹ'; + map!['Utildebelow'] = 'Ṵ'; + map!['V'] = 'V'; + map!['Vcircle'] = 'Ⓥ'; + map!['Vdotbelow'] = 'Ṿ'; + map!['Vecyrillic'] = 'В'; + map!['Vewarmenian'] = 'Վ'; + map!['Vhook'] = 'Ʋ'; + map!['Vmonospace'] = 'V'; + map!['Voarmenian'] = 'Ո'; + map!['Vsmall'] = ''; + map!['Vtilde'] = 'Ṽ'; + map!['W'] = 'W'; + map!['Wacute'] = 'Ẃ'; + map!['Wcircle'] = 'Ⓦ'; + map!['Wcircumflex'] = 'Ŵ'; + map!['Wdieresis'] = 'Ẅ'; + map!['Wdotaccent'] = 'Ẇ'; + map!['Wdotbelow'] = 'Ẉ'; + map!['Wgrave'] = 'Ẁ'; + map!['Wmonospace'] = 'W'; + map!['Wsmall'] = ''; + map!['X'] = 'X'; + map!['Xcircle'] = 'Ⓧ'; + map!['Xdieresis'] = 'Ẍ'; + map!['Xdotaccent'] = 'Ẋ'; + map!['Xeharmenian'] = 'Խ'; + map!['Xi'] = 'Ξ'; + map!['Xmonospace'] = 'X'; + map!['Xsmall'] = ''; + map!['Y'] = 'Y'; + map!['Yacute'] = 'Ý'; + map!['Yacutesmall'] = ''; + map!['Yatcyrillic'] = 'Ѣ'; + map!['Ycircle'] = 'Ⓨ'; + map!['Ycircumflex'] = 'Ŷ'; + map!['Ydieresis'] = 'Ÿ'; + map!['Ydieresissmall'] = ''; + map!['Ydotaccent'] = 'Ẏ'; + map!['Ydotbelow'] = 'Ỵ'; + map!['Yericyrillic'] = 'Ы'; + map!['Yerudieresiscyrillic'] = 'Ӹ'; + map!['Ygrave'] = 'Ỳ'; + map!['Yhook'] = 'Ƴ'; + map!['Yhookabove'] = 'Ỷ'; + map!['Yiarmenian'] = 'Յ'; + map!['Yicyrillic'] = 'Ї'; + map!['Yiwnarmenian'] = 'Ւ'; + map!['Ymonospace'] = 'Y'; + map!['Ysmall'] = ''; + map!['Ytilde'] = 'Ỹ'; + map!['Yusbigcyrillic'] = 'Ѫ'; + map!['Yusbigiotifiedcyrillic'] = 'Ѭ'; + map!['Yuslittlecyrillic'] = 'Ѧ'; + map!['Yuslittleiotifiedcyrillic'] = 'Ѩ'; + map!['Z'] = 'Z'; + map!['Zaarmenian'] = 'Զ'; + map!['Zacute'] = 'Ź'; + map!['Zcaron'] = 'Ž'; + map!['Zcaronsmall'] = ''; + map!['Zcircle'] = 'Ⓩ'; + map!['Zcircumflex'] = 'Ẑ'; + map!['Zdot'] = 'Ż'; + map!['Zdotaccent'] = 'Ż'; + map!['Zdotbelow'] = 'Ẓ'; + map!['Zecyrillic'] = 'З'; + map!['Zedescendercyrillic'] = 'Ҙ'; + map!['Zedieresiscyrillic'] = 'Ӟ'; + map!['Zeta'] = 'Ζ'; + map!['Zhearmenian'] = 'Ժ'; + map!['Zhebrevecyrillic'] = 'Ӂ'; + map!['Zhecyrillic'] = 'Ж'; + map!['Zhedescendercyrillic'] = 'Җ'; + map!['Zhedieresiscyrillic'] = 'Ӝ'; + map!['Zlinebelow'] = 'Ẕ'; + map!['Zmonospace'] = 'Z'; + map!['Zsmall'] = ''; + map!['Zstroke'] = 'Ƶ'; + map!['a'] = 'a'; + map!['aabengali'] = 'আ'; + map!['aacute'] = 'á'; + map!['aadeva'] = 'आ'; + map!['aagujarati'] = 'આ'; + map!['aagurmukhi'] = 'ਆ'; + map!['aamatragurmukhi'] = 'ਾ'; + map!['aarusquare'] = '㌃'; + map!['aavowelsignbengali'] = 'া'; + map!['aavowelsigndeva'] = 'ा'; + map!['aavowelsigngujarati'] = 'ા'; + map!['abbreviationmarkarmenian'] = '՟'; + map!['abbreviationsigndeva'] = '॰'; + map!['abengali'] = 'অ'; + map!['abopomofo'] = 'ㄚ'; + map!['abreve'] = 'ă'; + map!['abreveacute'] = 'ắ'; + map!['abrevecyrillic'] = 'ӑ'; + map!['abrevedotbelow'] = 'ặ'; + map!['abrevegrave'] = 'ằ'; + map!['abrevehookabove'] = 'ẳ'; + map!['abrevetilde'] = 'ẵ'; + map!['acaron'] = 'ǎ'; + map!['acircle'] = 'ⓐ'; + map!['acircumflex'] = 'â'; + map!['acircumflexacute'] = 'ấ'; + map!['acircumflexdotbelow'] = 'ậ'; + map!['acircumflexgrave'] = 'ầ'; + map!['acircumflexhookabove'] = 'ẩ'; + map!['acircumflextilde'] = 'ẫ'; + map!['acute'] = '´'; + map!['acutebelowcmb'] = '̗'; + map!['acutecmb'] = '́'; + map!['acutecomb'] = '́'; + map!['acutedeva'] = '॔'; + map!['acutelowmod'] = 'ˏ'; + map!['acutetonecmb'] = '́'; + map!['acyrillic'] = 'а'; + map!['adblgrave'] = 'ȁ'; + map!['addakgurmukhi'] = 'ੱ'; + map!['adeva'] = 'अ'; + map!['adieresis'] = 'ä'; + map!['adieresiscyrillic'] = 'ӓ'; + map!['adieresismacron'] = 'ǟ'; + map!['adotbelow'] = 'ạ'; + map!['adotmacron'] = 'ǡ'; + map!['ae'] = 'æ'; + map!['aeacute'] = 'ǽ'; + map!['aekorean'] = 'ㅐ'; + map!['aemacron'] = 'ǣ'; + map!['afii00208'] = '―'; + map!['afii08941'] = '₤'; + map!['afii10017'] = 'А'; + map!['afii10018'] = 'Б'; + map!['afii10019'] = 'В'; + map!['afii10020'] = 'Г'; + map!['afii10021'] = 'Д'; + map!['afii10022'] = 'Е'; + map!['afii10023'] = 'Ё'; + map!['afii10024'] = 'Ж'; + map!['afii10025'] = 'З'; + map!['afii10026'] = 'И'; + map!['afii10027'] = 'Й'; + map!['afii10028'] = 'К'; + map!['afii10029'] = 'Л'; + map!['afii10030'] = 'М'; + map!['afii10031'] = 'Н'; + map!['afii10032'] = 'О'; + map!['afii10033'] = 'П'; + map!['afii10034'] = 'Р'; + map!['afii10035'] = 'С'; + map!['afii10036'] = 'Т'; + map!['afii10037'] = 'У'; + map!['afii10038'] = 'Ф'; + map!['afii10039'] = 'Х'; + map!['afii10040'] = 'Ц'; + map!['afii10041'] = 'Ч'; + map!['afii10042'] = 'Ш'; + map!['afii10043'] = 'Щ'; + map!['afii10044'] = 'Ъ'; + map!['afii10045'] = 'Ы'; + map!['afii10046'] = 'Ь'; + map!['afii10047'] = 'Э'; + map!['afii10048'] = 'Ю'; + map!['afii10049'] = 'Я'; + map!['afii10050'] = 'Ґ'; + map!['afii10051'] = 'Ђ'; + map!['afii10052'] = 'Ѓ'; + map!['afii10053'] = 'Є'; + map!['afii10054'] = 'Ѕ'; + map!['afii10055'] = 'І'; + map!['afii10056'] = 'Ї'; + map!['afii10057'] = 'Ј'; + map!['afii10058'] = 'Љ'; + map!['afii10059'] = 'Њ'; + map!['afii10060'] = 'Ћ'; + map!['afii10061'] = 'Ќ'; + map!['afii10062'] = 'Ў'; + map!['afii10063'] = ''; + map!['afii10064'] = ''; + map!['afii10065'] = 'а'; + map!['afii10066'] = 'б'; + map!['afii10067'] = 'в'; + map!['afii10068'] = 'г'; + map!['afii10069'] = 'д'; + map!['afii10070'] = 'е'; + map!['afii10071'] = 'ё'; + map!['afii10072'] = 'ж'; + map!['afii10073'] = 'з'; + map!['afii10074'] = 'и'; + map!['afii10075'] = 'й'; + map!['afii10076'] = 'к'; + map!['afii10077'] = 'л'; + map!['afii10078'] = 'м'; + map!['afii10079'] = 'н'; + map!['afii10080'] = 'о'; + map!['afii10081'] = 'п'; + map!['afii10082'] = 'р'; + map!['afii10083'] = 'с'; + map!['afii10084'] = 'т'; + map!['afii10085'] = 'у'; + map!['afii10086'] = 'ф'; + map!['afii10087'] = 'х'; + map!['afii10088'] = 'ц'; + map!['afii10089'] = 'ч'; + map!['afii10090'] = 'ш'; + map!['afii10091'] = 'щ'; + map!['afii10092'] = 'ъ'; + map!['afii10093'] = 'ы'; + map!['afii10094'] = 'ь'; + map!['afii10095'] = 'э'; + map!['afii10096'] = 'ю'; + map!['afii10097'] = 'я'; + map!['afii10098'] = 'ґ'; + map!['afii10099'] = 'ђ'; + map!['afii10100'] = 'ѓ'; + map!['afii10101'] = 'є'; + map!['afii10102'] = 'ѕ'; + map!['afii10103'] = 'і'; + map!['afii10104'] = 'ї'; + map!['afii10105'] = 'ј'; + map!['afii10106'] = 'љ'; + map!['afii10107'] = 'њ'; + map!['afii10108'] = 'ћ'; + map!['afii10109'] = 'ќ'; + map!['afii10110'] = 'ў'; + map!['afii10145'] = 'Џ'; + map!['afii10146'] = 'Ѣ'; + map!['afii10147'] = 'Ѳ'; + map!['afii10148'] = 'Ѵ'; + map!['afii10192'] = ''; + map!['afii10193'] = 'џ'; + map!['afii10194'] = 'ѣ'; + map!['afii10195'] = 'ѳ'; + map!['afii10196'] = 'ѵ'; + map!['afii10831'] = ''; + map!['afii10832'] = ''; + map!['afii10846'] = 'ә'; + map!['afii299'] = '‎'; + map!['afii300'] = '‏'; + map!['afii301'] = '‍'; + map!['afii57381'] = '٪'; + map!['afii57388'] = '،'; + map!['afii57392'] = '٠'; + map!['afii57393'] = '١'; + map!['afii57394'] = '٢'; + map!['afii57395'] = '٣'; + map!['afii57396'] = '٤'; + map!['afii57397'] = '٥'; + map!['afii57398'] = '٦'; + map!['afii57399'] = '٧'; + map!['afii57400'] = '٨'; + map!['afii57401'] = '٩'; + map!['afii57403'] = '؛'; + map!['afii57407'] = '؟'; + map!['afii57409'] = 'ء'; + map!['afii57410'] = 'آ'; + map!['afii57411'] = 'أ'; + map!['afii57412'] = 'ؤ'; + map!['afii57413'] = 'إ'; + map!['afii57414'] = 'ئ'; + map!['afii57415'] = 'ا'; + map!['afii57416'] = 'ب'; + map!['afii57417'] = 'ة'; + map!['afii57418'] = 'ت'; + map!['afii57419'] = 'ث'; + map!['afii57420'] = 'ج'; + map!['afii57421'] = 'ح'; + map!['afii57422'] = 'خ'; + map!['afii57423'] = 'د'; + map!['afii57424'] = 'ذ'; + map!['afii57425'] = 'ر'; + map!['afii57426'] = 'ز'; + map!['afii57427'] = 'س'; + map!['afii57428'] = 'ش'; + map!['afii57429'] = 'ص'; + map!['afii57430'] = 'ض'; + map!['afii57431'] = 'ط'; + map!['afii57432'] = 'ظ'; + map!['afii57433'] = 'ع'; + map!['afii57434'] = 'غ'; + map!['afii57440'] = 'ـ'; + map!['afii57441'] = 'ف'; + map!['afii57442'] = 'ق'; + map!['afii57443'] = 'ك'; + map!['afii57444'] = 'ل'; + map!['afii57445'] = 'م'; + map!['afii57446'] = 'ن'; + map!['afii57448'] = 'و'; + map!['afii57449'] = 'ى'; + map!['afii57450'] = 'ي'; + map!['afii57451'] = 'ً'; + map!['afii57452'] = 'ٌ'; + map!['afii57453'] = 'ٍ'; + map!['afii57454'] = 'َ'; + map!['afii57455'] = 'ُ'; + map!['afii57456'] = 'ِ'; + map!['afii57457'] = 'ّ'; + map!['afii57458'] = 'ْ'; + map!['afii57470'] = 'ه'; + map!['afii57505'] = 'ڤ'; + map!['afii57506'] = 'پ'; + map!['afii57507'] = 'چ'; + map!['afii57508'] = 'ژ'; + map!['afii57509'] = 'گ'; + map!['afii57511'] = 'ٹ'; + map!['afii57512'] = 'ڈ'; + map!['afii57513'] = 'ڑ'; + map!['afii57514'] = 'ں'; + map!['afii57519'] = 'ے'; + map!['afii57534'] = 'ە'; + map!['afii57636'] = '₪'; + map!['afii57645'] = '־'; + map!['afii57658'] = '׃'; + map!['afii57664'] = 'א'; + map!['afii57665'] = 'ב'; + map!['afii57666'] = 'ג'; + map!['afii57667'] = 'ד'; + map!['afii57668'] = 'ה'; + map!['afii57669'] = 'ו'; + map!['afii57670'] = 'ז'; + map!['afii57671'] = 'ח'; + map!['afii57672'] = 'ט'; + map!['afii57673'] = 'י'; + map!['afii57674'] = 'ך'; + map!['afii57675'] = 'כ'; + map!['afii57676'] = 'ל'; + map!['afii57677'] = 'ם'; + map!['afii57678'] = 'מ'; + map!['afii57679'] = 'ן'; + map!['afii57680'] = 'נ'; + map!['afii57681'] = 'ס'; + map!['afii57682'] = 'ע'; + map!['afii57683'] = 'ף'; + map!['afii57684'] = 'פ'; + map!['afii57685'] = 'ץ'; + map!['afii57686'] = 'צ'; + map!['afii57687'] = 'ק'; + map!['afii57688'] = 'ר'; + map!['afii57689'] = 'ש'; + map!['afii57690'] = 'ת'; + map!['afii57694'] = 'שׁ'; + map!['afii57695'] = 'שׂ'; + map!['afii57700'] = 'וֹ'; + map!['afii57705'] = 'ײַ'; + map!['afii57716'] = 'װ'; + map!['afii57717'] = 'ױ'; + map!['afii57718'] = 'ײ'; + map!['afii57723'] = 'וּ'; + map!['afii57793'] = 'ִ'; + map!['afii57794'] = 'ֵ'; + map!['afii57795'] = 'ֶ'; + map!['afii57796'] = 'ֻ'; + map!['afii57797'] = 'ָ'; + map!['afii57798'] = 'ַ'; + map!['afii57799'] = 'ְ'; + map!['afii57800'] = 'ֲ'; + map!['afii57801'] = 'ֱ'; + map!['afii57802'] = 'ֳ'; + map!['afii57803'] = 'ׂ'; + map!['afii57804'] = 'ׁ'; + map!['afii57806'] = 'ֹ'; + map!['afii57807'] = 'ּ'; + map!['afii57839'] = 'ֽ'; + map!['afii57841'] = 'ֿ'; + map!['afii57842'] = '׀'; + map!['afii57929'] = 'ʼ'; + map!['afii61248'] = '℅'; + map!['afii61289'] = 'ℓ'; + map!['afii61352'] = '№'; + map!['afii61573'] = '‬'; + map!['afii61574'] = '‭'; + map!['afii61575'] = '‮'; + map!['afii61664'] = '‌'; + map!['afii63167'] = '٭'; + map!['afii64937'] = 'ʽ'; + map!['agrave'] = 'à'; + map!['agujarati'] = 'અ'; + map!['agurmukhi'] = 'ਅ'; + map!['ahiragana'] = 'あ'; + map!['ahookabove'] = 'ả'; + map!['aibengali'] = 'ঐ'; + map!['aibopomofo'] = 'ㄞ'; + map!['aideva'] = 'ऐ'; + map!['aiecyrillic'] = 'ӕ'; + map!['aigujarati'] = 'ઐ'; + map!['aigurmukhi'] = 'ਐ'; + map!['aimatragurmukhi'] = 'ੈ'; + map!['ainarabic'] = 'ع'; + map!['ainfinalarabic'] = 'ﻊ'; + map!['aininitialarabic'] = 'ﻋ'; + map!['ainmedialarabic'] = 'ﻌ'; + map!['ainvertedbreve'] = 'ȃ'; + map!['aivowelsignbengali'] = 'ৈ'; + map!['aivowelsigndeva'] = 'ै'; + map!['aivowelsigngujarati'] = 'ૈ'; + map!['akatakana'] = 'ア'; + map!['akatakanahalfwidth'] = 'ア'; + map!['akorean'] = 'ㅏ'; + map!['alef'] = 'א'; + map!['alefarabic'] = 'ا'; + map!['alefdageshhebrew'] = 'אּ'; + map!['aleffinalarabic'] = 'ﺎ'; + map!['alefhamzaabovearabic'] = 'أ'; + map!['alefhamzaabovefinalarabic'] = 'ﺄ'; + map!['alefhamzabelowarabic'] = 'إ'; + map!['alefhamzabelowfinalarabic'] = 'ﺈ'; + map!['alefhebrew'] = 'א'; + map!['aleflamedhebrew'] = 'ﭏ'; + map!['alefmaddaabovearabic'] = 'آ'; + map!['alefmaddaabovefinalarabic'] = 'ﺂ'; + map!['alefmaksuraarabic'] = 'ى'; + map!['alefmaksurafinalarabic'] = 'ﻰ'; + map!['alefmaksurainitialarabic'] = 'ﻳ'; + map!['alefmaksuramedialarabic'] = 'ﻴ'; + map!['alefpatahhebrew'] = 'אַ'; + map!['alefqamatshebrew'] = 'אָ'; + map!['aleph'] = 'ℵ'; + map!['allequal'] = '≌'; + map!['alpha'] = 'α'; + map!['alphatonos'] = 'ά'; + map!['amacron'] = 'ā'; + map!['amonospace'] = 'a'; + map!['ampersand'] = '&'; + map!['ampersandmonospace'] = '&'; + map!['ampersandsmall'] = ''; + map!['amsquare'] = '㏂'; + map!['anbopomofo'] = 'ㄢ'; + map!['angbopomofo'] = 'ㄤ'; + map!['angkhankhuthai'] = '๚'; + map!['angle'] = '∠'; + map!['angbracketleft'] = '〈'; + map!['anglebracketleft'] = '〈'; + map!['anglebracketleftvertical'] = '︿'; + map!['angbracketright'] = '〉'; + map!['anglebracketright'] = '〉'; + map!['anglebracketrightvertical'] = '﹀'; + map!['angleleft'] = '〈'; + map!['angleright'] = '〉'; + map!['angstrom'] = 'Å'; + map!['anoteleia'] = '·'; + map!['anudattadeva'] = '॒'; + map!['anusvarabengali'] = 'ং'; + map!['anusvaradeva'] = 'ं'; + map!['anusvaragujarati'] = 'ં'; + map!['aogonek'] = 'ą'; + map!['apaatosquare'] = '㌀'; + map!['aparen'] = '⒜'; + map!['apostrophearmenian'] = '՚'; + map!['apostrophemod'] = 'ʼ'; + map!['apple'] = ''; + map!['approaches'] = '≐'; + map!['approxequal'] = '≈'; + map!['approxequalorimage'] = '≒'; + map!['approximatelyequal'] = '≅'; + map!['araeaekorean'] = 'ㆎ'; + map!['araeakorean'] = 'ㆍ'; + map!['arc'] = '⌒'; + map!['arighthalfring'] = 'ẚ'; + map!['aring'] = 'å'; + map!['aringacute'] = 'ǻ'; + map!['aringbelow'] = 'ḁ'; + map!['arrowboth'] = '↔'; + map!['arrowdashdown'] = '⇣'; + map!['arrowdashleft'] = '⇠'; + map!['arrowdashright'] = '⇢'; + map!['arrowdashup'] = '⇡'; + map!['arrowdblboth'] = '⇔'; + map!['arrowdbldown'] = '⇓'; + map!['arrowdblleft'] = '⇐'; + map!['arrowdblright'] = '⇒'; + map!['arrowdblup'] = '⇑'; + map!['arrowdown'] = '↓'; + map!['arrowdownleft'] = '↙'; + map!['arrowdownright'] = '↘'; + map!['arrowdownwhite'] = '⇩'; + map!['arrowheaddownmod'] = '˅'; + map!['arrowheadleftmod'] = '˂'; + map!['arrowheadrightmod'] = '˃'; + map!['arrowheadupmod'] = '˄'; + map!['arrowhorizex'] = ''; + map!['arrowleft'] = '←'; + map!['arrowleftdbl'] = '⇐'; + map!['arrowleftdblstroke'] = '⇍'; + map!['arrowleftoverright'] = '⇆'; + map!['arrowleftwhite'] = '⇦'; + map!['arrowright'] = '→'; + map!['arrowrightdblstroke'] = '⇏'; + map!['arrowrightheavy'] = '➞'; + map!['arrowrightoverleft'] = '⇄'; + map!['arrowrightwhite'] = '⇨'; + map!['arrowtableft'] = '⇤'; + map!['arrowtabright'] = '⇥'; + map!['arrowup'] = '↑'; + map!['arrowupdn'] = '↕'; + map!['arrowupdnbse'] = '↨'; + map!['arrowupdownbase'] = '↨'; + map!['arrowupleft'] = '↖'; + map!['arrowupleftofdown'] = '⇅'; + map!['arrowupright'] = '↗'; + map!['arrowupwhite'] = '⇧'; + map!['arrowvertex'] = ''; + map!['asciicircum'] = '^'; + map!['asciicircummonospace'] = '^'; + map!['asciitilde'] = '~'; + map!['asciitildemonospace'] = '~'; + map!['ascript'] = 'ɑ'; + map!['ascriptturned'] = 'ɒ'; + map!['asmallhiragana'] = 'ぁ'; + map!['asmallkatakana'] = 'ァ'; + map!['asmallkatakanahalfwidth'] = 'ァ'; + map!['asterisk'] = '*'; + map!['asteriskaltonearabic'] = '٭'; + map!['asteriskarabic'] = '٭'; + map!['asteriskmath'] = '∗'; + map!['asteriskmonospace'] = '*'; + map!['asterisksmall'] = '﹡'; + map!['asterism'] = '⁂'; + map!['asuperior'] = ''; + map!['asymptoticallyequal'] = '≃'; + map!['at'] = '@'; + map!['atilde'] = 'ã'; + map!['atmonospace'] = '@'; + map!['atsmall'] = '﹫'; + map!['aturned'] = 'ɐ'; + map!['aubengali'] = 'ঔ'; + map!['aubopomofo'] = 'ㄠ'; + map!['audeva'] = 'औ'; + map!['augujarati'] = 'ઔ'; + map!['augurmukhi'] = 'ਔ'; + map!['aulengthmarkbengali'] = 'ৗ'; + map!['aumatragurmukhi'] = 'ੌ'; + map!['auvowelsignbengali'] = 'ৌ'; + map!['auvowelsigndeva'] = 'ौ'; + map!['auvowelsigngujarati'] = 'ૌ'; + map!['avagrahadeva'] = 'ऽ'; + map!['aybarmenian'] = 'ա'; + map!['ayin'] = 'ע'; + map!['ayinaltonehebrew'] = 'ﬠ'; + map!['ayinhebrew'] = 'ע'; + map!['b'] = 'b'; + map!['babengali'] = 'ব'; + map!['backslash'] = r'\'; + map!['backslashmonospace'] = '\'; + map!['badeva'] = 'ब'; + map!['bagujarati'] = 'બ'; + map!['bagurmukhi'] = 'ਬ'; + map!['bahiragana'] = 'ば'; + map!['bahtthai'] = '฿'; + map!['bakatakana'] = 'バ'; + map!['bar'] = '|'; + map!['barmonospace'] = '|'; + map!['bbopomofo'] = 'ㄅ'; + map!['bcircle'] = 'ⓑ'; + map!['bdotaccent'] = 'ḃ'; + map!['bdotbelow'] = 'ḅ'; + map!['beamedsixteenthnotes'] = '♬'; + map!['because'] = '∵'; + map!['becyrillic'] = 'б'; + map!['beharabic'] = 'ب'; + map!['behfinalarabic'] = 'ﺐ'; + map!['behinitialarabic'] = 'ﺑ'; + map!['behiragana'] = 'べ'; + map!['behmedialarabic'] = 'ﺒ'; + map!['behmeeminitialarabic'] = 'ﲟ'; + map!['behmeemisolatedarabic'] = 'ﰈ'; + map!['behnoonfinalarabic'] = 'ﱭ'; + map!['bekatakana'] = 'ベ'; + map!['benarmenian'] = 'բ'; + map!['bet'] = 'ב'; + map!['beta'] = 'β'; + map!['betasymbolgreek'] = 'ϐ'; + map!['betdagesh'] = 'בּ'; + map!['betdageshhebrew'] = 'בּ'; + map!['bethebrew'] = 'ב'; + map!['betrafehebrew'] = 'בֿ'; + map!['bhabengali'] = 'ভ'; + map!['bhadeva'] = 'भ'; + map!['bhagujarati'] = 'ભ'; + map!['bhagurmukhi'] = 'ਭ'; + map!['bhook'] = 'ɓ'; + map!['bihiragana'] = 'び'; + map!['bikatakana'] = 'ビ'; + map!['bilabialclick'] = 'ʘ'; + map!['bindigurmukhi'] = 'ਂ'; + map!['birusquare'] = '㌱'; + map!['blackcircle'] = '●'; + map!['blackdiamond'] = '◆'; + map!['blackdownpointingtriangle'] = '▼'; + map!['blackleftpointingpointer'] = '◄'; + map!['blackleftpointingtriangle'] = '◀'; + map!['blacklenticularbracketleft'] = '【'; + map!['blacklenticularbracketleftvertical'] = '︻'; + map!['blacklenticularbracketright'] = '】'; + map!['blacklenticularbracketrightvertical'] = '︼'; + map!['blacklowerlefttriangle'] = '◣'; + map!['blacklowerrighttriangle'] = '◢'; + map!['blackrectangle'] = '▬'; + map!['blackrightpointingpointer'] = '►'; + map!['blackrightpointingtriangle'] = '▶'; + map!['blacksmallsquare'] = '▪'; + map!['blacksmilingface'] = '☻'; + map!['blacksquare'] = '■'; + map!['blackstar'] = '★'; + map!['blackupperlefttriangle'] = '◤'; + map!['blackupperrighttriangle'] = '◥'; + map!['blackuppointingsmalltriangle'] = '▴'; + map!['blackuppointingtriangle'] = '▲'; + map!['blank'] = '␣'; + map!['blinebelow'] = 'ḇ'; + map!['block'] = '█'; + map!['bmonospace'] = 'b'; + map!['bobaimaithai'] = 'บ'; + map!['bohiragana'] = 'ぼ'; + map!['bokatakana'] = 'ボ'; + map!['bparen'] = '⒝'; + map!['bqsquare'] = '㏃'; + map!['braceex'] = ''; + map!['braceleft'] = '{'; + map!['braceleftbt'] = ''; + map!['braceleftmid'] = ''; + map!['braceleftmonospace'] = '{'; + map!['braceleftsmall'] = '﹛'; + map!['bracelefttp'] = ''; + map!['braceleftvertical'] = '︷'; + map!['braceright'] = '}'; + map!['bracerightbt'] = ''; + map!['bracerightmid'] = ''; + map!['bracerightmonospace'] = '}'; + map!['bracerightsmall'] = '﹜'; + map!['bracerighttp'] = ''; + map!['bracerightvertical'] = '︸'; + map!['bracketleft'] = '['; + map!['bracketleftbt'] = ''; + map!['bracketleftex'] = ''; + map!['bracketleftmonospace'] = '['; + map!['bracketlefttp'] = ''; + map!['bracketright'] = ']'; + map!['bracketrightbt'] = ''; + map!['bracketrightex'] = ''; + map!['bracketrightmonospace'] = ']'; + map!['bracketrighttp'] = ''; + map!['breve'] = '˘'; + map!['brevebelowcmb'] = '̮'; + map!['brevecmb'] = '̆'; + map!['breveinvertedbelowcmb'] = '̯'; + map!['breveinvertedcmb'] = '̑'; + map!['breveinverteddoublecmb'] = '͡'; + map!['bridgebelowcmb'] = '̪'; + map!['bridgeinvertedbelowcmb'] = '̺'; + map!['brokenbar'] = '¦'; + map!['bstroke'] = 'ƀ'; + map!['bsuperior'] = ''; + map!['btopbar'] = 'ƃ'; + map!['buhiragana'] = 'ぶ'; + map!['bukatakana'] = 'ブ'; + map!['bullet'] = '•'; + map!['bulletinverse'] = '◘'; + map!['bulletoperator'] = '∙'; + map!['bullseye'] = '◎'; + map!['c'] = 'c'; + map!['caarmenian'] = 'ծ'; + map!['cabengali'] = 'চ'; + map!['cacute'] = 'ć'; + map!['cadeva'] = 'च'; + map!['cagujarati'] = 'ચ'; + map!['cagurmukhi'] = 'ਚ'; + map!['calsquare'] = '㎈'; + map!['candrabindubengali'] = 'ঁ'; + map!['candrabinducmb'] = '̐'; + map!['candrabindudeva'] = 'ँ'; + map!['candrabindugujarati'] = 'ઁ'; + map!['capslock'] = '⇪'; + map!['careof'] = '℅'; + map!['caron'] = 'ˇ'; + map!['caronbelowcmb'] = '̬'; + map!['caroncmb'] = '̌'; + map!['carriagereturn'] = '↵'; + map!['cbopomofo'] = 'ㄘ'; + map!['ccaron'] = 'č'; + map!['ccedilla'] = 'ç'; + map!['ccedillaacute'] = 'ḉ'; + map!['ccircle'] = 'ⓒ'; + map!['ccircumflex'] = 'ĉ'; + map!['ccurl'] = 'ɕ'; + map!['cdot'] = 'ċ'; + map!['cdotaccent'] = 'ċ'; + map!['cdsquare'] = '㏅'; + map!['cedilla'] = '¸'; + map!['cedillacmb'] = '̧'; + map!['cent'] = '¢'; + map!['centigrade'] = '℃'; + map!['centinferior'] = ''; + map!['centmonospace'] = '¢'; + map!['centoldstyle'] = ''; + map!['centsuperior'] = ''; + map!['chaarmenian'] = 'չ'; + map!['chabengali'] = 'ছ'; + map!['chadeva'] = 'छ'; + map!['chagujarati'] = 'છ'; + map!['chagurmukhi'] = 'ਛ'; + map!['chbopomofo'] = 'ㄔ'; + map!['cheabkhasiancyrillic'] = 'ҽ'; + map!['checkmark'] = '✓'; + map!['checyrillic'] = 'ч'; + map!['chedescenderabkhasiancyrillic'] = 'ҿ'; + map!['chedescendercyrillic'] = 'ҷ'; + map!['chedieresiscyrillic'] = 'ӵ'; + map!['cheharmenian'] = 'ճ'; + map!['chekhakassiancyrillic'] = 'ӌ'; + map!['cheverticalstrokecyrillic'] = 'ҹ'; + map!['chi'] = 'χ'; + map!['chieuchacirclekorean'] = '㉷'; + map!['chieuchaparenkorean'] = '㈗'; + map!['chieuchcirclekorean'] = '㉩'; + map!['chieuchkorean'] = 'ㅊ'; + map!['chieuchparenkorean'] = '㈉'; + map!['chochangthai'] = 'ช'; + map!['chochanthai'] = 'จ'; + map!['chochingthai'] = 'ฉ'; + map!['chochoethai'] = 'ฌ'; + map!['chook'] = 'ƈ'; + map!['cieucacirclekorean'] = '㉶'; + map!['cieucaparenkorean'] = '㈖'; + map!['cieuccirclekorean'] = '㉨'; + map!['cieuckorean'] = 'ㅈ'; + map!['cieucparenkorean'] = '㈈'; + map!['cieucuparenkorean'] = '㈜'; + map!['circle'] = '○'; + map!['circlemultiply'] = '⊗'; + map!['circleot'] = '⊙'; + map!['circleplus'] = '⊕'; + map!['circlepostalmark'] = '〶'; + map!['circlewithlefthalfblack'] = '◐'; + map!['circlewithrighthalfblack'] = '◑'; + map!['circumflex'] = 'ˆ'; + map!['circumflexbelowcmb'] = '̭'; + map!['circumflexcmb'] = '̂'; + map!['clear'] = '⌧'; + map!['clickalveolar'] = 'ǂ'; + map!['clickdental'] = 'ǀ'; + map!['clicklateral'] = 'ǁ'; + map!['clickretroflex'] = 'ǃ'; + map!['club'] = '♣'; + map!['clubsuitblack'] = '♣'; + map!['clubsuitwhite'] = '♧'; + map!['cmcubedsquare'] = '㎤'; + map!['cmonospace'] = 'c'; + map!['cmsquaredsquare'] = '㎠'; + map!['coarmenian'] = 'ց'; + map!['colon'] = ':'; + map!['colonmonetary'] = '₡'; + map!['colonmonospace'] = ':'; + map!['colonsign'] = '₡'; + map!['colonsmall'] = '﹕'; + map!['colontriangularhalfmod'] = 'ˑ'; + map!['colontriangularmod'] = 'ː'; + map!['comma'] = ','; + map!['commaabovecmb'] = '̓'; + map!['commaaboverightcmb'] = '̕'; + map!['commaaccent'] = ''; + map!['commaarabic'] = '،'; + map!['commaarmenian'] = '՝'; + map!['commainferior'] = ''; + map!['commamonospace'] = ','; + map!['commareversedabovecmb'] = '̔'; + map!['commareversedmod'] = 'ʽ'; + map!['commasmall'] = '﹐'; + map!['commasuperior'] = ''; + map!['commaturnedabovecmb'] = '̒'; + map!['commaturnedmod'] = 'ʻ'; + map!['compass'] = '☼'; + map!['congruent'] = '≅'; + map!['contourintegral'] = '∮'; + map!['control'] = '⌃'; + map!['controlACK'] = '\u0006'; + map!['controlBEL'] = r'a'; + map!['controlBS'] = '\b'; + map!['controlCAN'] = '\u0018'; + map!['controlCR'] = '\r'; + map!['controlDC1'] = '\u0011'; + map!['controlDC2'] = '\u0012'; + map!['controlDC3'] = '\u0013'; + map!['controlDC4'] = '\u0014'; + map!['controlDEL'] = '\u007f'; + map!['controlDLE'] = '\u0010'; + map!['controlEM'] = '\u0019'; + map!['controlENQ'] = '\u0005'; + map!['controlEOT'] = '\u0004'; + map!['controlESC'] = '\u001b'; + map!['controlETB'] = '\u0017'; + map!['controlETX'] = '\u0003'; + map!['controlFF'] = '\f'; + map!['controlFS'] = '\u001c'; + map!['controlGS'] = '\u001d'; + map!['controlHT'] = '\t'; + map!['controlLF'] = '\n'; + map!['controlNAK'] = '\u0015'; + map!['controlRS'] = '\u001e'; + map!['controlSI'] = '\u000f'; + map!['controlSO'] = '\u000e'; + map!['controlSOT'] = '\u0002'; + map!['controlSTX'] = '\u0001'; + map!['controlSUB'] = '\u001a'; + map!['controlSYN'] = '\u0016'; + map!['controlUS'] = '\u001f'; + map!['controlVT'] = '\v'; + map!['copyright'] = '©'; + map!['copyrightsans'] = ''; + map!['copyrightserif'] = ''; + map!['cornerbracketleft'] = '「'; + map!['cornerbracketlefthalfwidth'] = '「'; + map!['cornerbracketleftvertical'] = '﹁'; + map!['cornerbracketright'] = '」'; + map!['cornerbracketrighthalfwidth'] = '」'; + map!['cornerbracketrightvertical'] = '﹂'; + map!['corporationsquare'] = '㍿'; + map!['cosquare'] = '㏇'; + map!['coverkgsquare'] = '㏆'; + map!['cparen'] = '⒞'; + map!['cruzeiro'] = '₢'; + map!['cstretched'] = 'ʗ'; + map!['curlyand'] = '⋏'; + map!['curlyor'] = '⋎'; + map!['currency'] = '¤'; + map!['cyrBreve'] = ''; + map!['cyrFlex'] = ''; + map!['cyrbreve'] = ''; + map!['cyrflex'] = ''; + map!['d'] = 'd'; + map!['daarmenian'] = 'դ'; + map!['dabengali'] = 'দ'; + map!['dadarabic'] = 'ض'; + map!['dadeva'] = 'द'; + map!['dadfinalarabic'] = 'ﺾ'; + map!['dadinitialarabic'] = 'ﺿ'; + map!['dadmedialarabic'] = 'ﻀ'; + map!['dagesh'] = 'ּ'; + map!['dageshhebrew'] = 'ּ'; + map!['dagger'] = '†'; + map!['daggerdbl'] = '‡'; + map!['dagujarati'] = 'દ'; + map!['dagurmukhi'] = 'ਦ'; + map!['dahiragana'] = 'だ'; + map!['dakatakana'] = 'ダ'; + map!['dalarabic'] = 'د'; + map!['dalet'] = 'ד'; + map!['daletdagesh'] = 'דּ'; + map!['daletdageshhebrew'] = 'דּ'; + map!['dalethebrew'] = 'ד'; + map!['dalfinalarabic'] = 'ﺪ'; + map!['dammaarabic'] = 'ُ'; + map!['dammalowarabic'] = 'ُ'; + map!['dammatanaltonearabic'] = 'ٌ'; + map!['dammatanarabic'] = 'ٌ'; + map!['danda'] = '।'; + map!['dargahebrew'] = '֧'; + map!['dargalefthebrew'] = '֧'; + map!['dasiapneumatacyrilliccmb'] = '҅'; + map!['dblGrave'] = ''; + map!['dblanglebracketleft'] = '《'; + map!['dblanglebracketleftvertical'] = '︽'; + map!['dblanglebracketright'] = '》'; + map!['dblanglebracketrightvertical'] = '︾'; + map!['dblarchinvertedbelowcmb'] = '̫'; + map!['dblarrowleft'] = '⇔'; + map!['dblarrowright'] = '⇒'; + map!['dbldanda'] = '॥'; + map!['dblgrave'] = ''; + map!['dblgravecmb'] = '̏'; + map!['dblintegral'] = '∬'; + map!['dbllowline'] = '‗'; + map!['dbllowlinecmb'] = '̳'; + map!['dbloverlinecmb'] = '̿'; + map!['dblprimemod'] = 'ʺ'; + map!['dblverticalbar'] = '‖'; + map!['dblverticallineabovecmb'] = '̎'; + map!['dbopomofo'] = 'ㄉ'; + map!['dbsquare'] = '㏈'; + map!['dcaron'] = 'ď'; + map!['dcedilla'] = 'ḑ'; + map!['dcircle'] = 'ⓓ'; + map!['dcircumflexbelow'] = 'ḓ'; + map!['dcroat'] = 'đ'; + map!['ddabengali'] = 'ড'; + map!['ddadeva'] = 'ड'; + map!['ddagujarati'] = 'ડ'; + map!['ddagurmukhi'] = 'ਡ'; + map!['ddalarabic'] = 'ڈ'; + map!['ddalfinalarabic'] = 'ﮉ'; + map!['dddhadeva'] = 'ड़'; + map!['ddhabengali'] = 'ঢ'; + map!['ddhadeva'] = 'ढ'; + map!['ddhagujarati'] = 'ઢ'; + map!['ddhagurmukhi'] = 'ਢ'; + map!['ddotaccent'] = 'ḋ'; + map!['ddotbelow'] = 'ḍ'; + map!['decimalseparatorarabic'] = '٫'; + map!['decimalseparatorpersian'] = '٫'; + map!['decyrillic'] = 'д'; + map!['degree'] = '°'; + map!['dehihebrew'] = '֭'; + map!['dehiragana'] = 'で'; + map!['deicoptic'] = 'ϯ'; + map!['dekatakana'] = 'デ'; + map!['deleteleft'] = '⌫'; + map!['deleteright'] = '⌦'; + map!['delta'] = 'δ'; + map!['deltaturned'] = 'ƍ'; + map!['denominatorminusonenumeratorbengali'] = '৸'; + map!['dezh'] = 'ʤ'; + map!['dhabengali'] = 'ধ'; + map!['dhadeva'] = 'ध'; + map!['dhagujarati'] = 'ધ'; + map!['dhagurmukhi'] = 'ਧ'; + map!['dhook'] = 'ɗ'; + map!['dialytikatonos'] = '΅'; + map!['dialytikatonoscmb'] = '̈́'; + map!['diamond'] = '♦'; + map!['diamondsuitwhite'] = '♢'; + map!['dieresis'] = '¨'; + map!['dieresisacute'] = ''; + map!['dieresisbelowcmb'] = '̤'; + map!['dieresiscmb'] = '̈'; + map!['dieresisgrave'] = ''; + map!['dieresistonos'] = '΅'; + map!['dihiragana'] = 'ぢ'; + map!['dikatakana'] = 'ヂ'; + map!['dittomark'] = '〃'; + map!['divide'] = '÷'; + map!['divides'] = '∣'; + map!['divisionslash'] = '∕'; + map!['djecyrillic'] = 'ђ'; + map!['dkshade'] = '▓'; + map!['dlinebelow'] = 'ḏ'; + map!['dlsquare'] = '㎗'; + map!['dmacron'] = 'đ'; + map!['dmonospace'] = 'd'; + map!['dnblock'] = '▄'; + map!['dochadathai'] = 'ฎ'; + map!['dodekthai'] = 'ด'; + map!['dohiragana'] = 'ど'; + map!['dokatakana'] = 'ド'; + map!['dollar'] = r'$'; + map!['dollarinferior'] = ''; + map!['dollarmonospace'] = '$'; + map!['dollaroldstyle'] = ''; + map!['dollarsmall'] = '﹩'; + map!['dollarsuperior'] = ''; + map!['dong'] = '₫'; + map!['dorusquare'] = '㌦'; + map!['dotaccent'] = '˙'; + map!['dotaccentcmb'] = '̇'; + map!['dotbelowcmb'] = '̣'; + map!['dotbelowcomb'] = '̣'; + map!['dotkatakana'] = '・'; + map!['dotlessi'] = 'ı'; + map!['dotlessj'] = ''; + map!['dotlessjstrokehook'] = 'ʄ'; + map!['dotmath'] = '⋅'; + map!['dottedcircle'] = '◌'; + map!['doubleyodpatah'] = 'ײַ'; + map!['doubleyodpatahhebrew'] = 'ײַ'; + map!['downtackbelowcmb'] = '̞'; + map!['downtackmod'] = '˕'; + map!['dparen'] = '⒟'; + map!['dsuperior'] = ''; + map!['dtail'] = 'ɖ'; + map!['dtopbar'] = 'ƌ'; + map!['duhiragana'] = 'づ'; + map!['dukatakana'] = 'ヅ'; + map!['dz'] = 'dz'; + map!['dzaltone'] = 'ʣ'; + map!['dzcaron'] = 'dž'; + map!['dzcurl'] = 'ʥ'; + map!['dzeabkhasiancyrillic'] = 'ӡ'; + map!['dzecyrillic'] = 'ѕ'; + map!['dzhecyrillic'] = 'џ'; + map!['e'] = 'e'; + map!['eacute'] = 'é'; + map!['earth'] = '♁'; + map!['ebengali'] = 'এ'; + map!['ebopomofo'] = 'ㄜ'; + map!['ebreve'] = 'ĕ'; + map!['ecandradeva'] = 'ऍ'; + map!['ecandragujarati'] = 'ઍ'; + map!['ecandravowelsigndeva'] = 'ॅ'; + map!['ecandravowelsigngujarati'] = 'ૅ'; + map!['ecaron'] = 'ě'; + map!['ecedillabreve'] = 'ḝ'; + map!['echarmenian'] = 'ե'; + map!['echyiwnarmenian'] = 'և'; + map!['ecircle'] = 'ⓔ'; + map!['ecircumflex'] = 'ê'; + map!['ecircumflexacute'] = 'ế'; + map!['ecircumflexbelow'] = 'ḙ'; + map!['ecircumflexdotbelow'] = 'ệ'; + map!['ecircumflexgrave'] = 'ề'; + map!['ecircumflexhookabove'] = 'ể'; + map!['ecircumflextilde'] = 'ễ'; + map!['ecyrillic'] = 'є'; + map!['edblgrave'] = 'ȅ'; + map!['edeva'] = 'ए'; + map!['edieresis'] = 'ë'; + map!['edot'] = 'ė'; + map!['edotaccent'] = 'ė'; + map!['edotbelow'] = 'ẹ'; + map!['eegurmukhi'] = 'ਏ'; + map!['eematragurmukhi'] = 'ੇ'; + map!['efcyrillic'] = 'ф'; + map!['egrave'] = 'è'; + map!['egujarati'] = 'એ'; + map!['eharmenian'] = 'է'; + map!['ehbopomofo'] = 'ㄝ'; + map!['ehiragana'] = 'え'; + map!['ehookabove'] = 'ẻ'; + map!['eibopomofo'] = 'ㄟ'; + map!['eight'] = '8'; + map!['eightarabic'] = '٨'; + map!['eightbengali'] = '৮'; + map!['eightcircle'] = '⑧'; + map!['eightcircleinversesansserif'] = '➑'; + map!['eightdeva'] = '८'; + map!['eighteencircle'] = '⑱'; + map!['eighteenparen'] = '⒅'; + map!['eighteenperiod'] = '⒙'; + map!['eightgujarati'] = '૮'; + map!['eightgurmukhi'] = '੮'; + map!['eighthackarabic'] = '٨'; + map!['eighthangzhou'] = '〨'; + map!['eighthnotebeamed'] = '♫'; + map!['eightideographicparen'] = '㈧'; + map!['eightinferior'] = '₈'; + map!['eightmonospace'] = '8'; + map!['eightoldstyle'] = ''; + map!['eightparen'] = '⑻'; + map!['eightperiod'] = '⒏'; + map!['eightpersian'] = '۸'; + map!['eightroman'] = 'ⅷ'; + map!['eightsuperior'] = '⁸'; + map!['eightthai'] = '๘'; + map!['einvertedbreve'] = 'ȇ'; + map!['eiotifiedcyrillic'] = 'ѥ'; + map!['ekatakana'] = 'エ'; + map!['ekatakanahalfwidth'] = 'エ'; + map!['ekonkargurmukhi'] = 'ੴ'; + map!['ekorean'] = 'ㅔ'; + map!['elcyrillic'] = 'л'; + map!['element'] = '∈'; + map!['elevencircle'] = '⑪'; + map!['elevenparen'] = '⑾'; + map!['elevenperiod'] = '⒒'; + map!['elevenroman'] = 'ⅺ'; + map!['ellipsis'] = '…'; + map!['ellipsisvertical'] = '⋮'; + map!['emacron'] = 'ē'; + map!['emacronacute'] = 'ḗ'; + map!['emacrongrave'] = 'ḕ'; + map!['emcyrillic'] = 'м'; + map!['emdash'] = '—'; + map!['emdashvertical'] = '︱'; + map!['emonospace'] = 'e'; + map!['emphasismarkarmenian'] = '՛'; + map!['emptyset'] = '∅'; + map!['enbopomofo'] = 'ㄣ'; + map!['encyrillic'] = 'н'; + map!['endash'] = '–'; + map!['endashvertical'] = '︲'; + map!['endescendercyrillic'] = 'ң'; + map!['eng'] = 'ŋ'; + map!['engbopomofo'] = 'ㄥ'; + map!['enghecyrillic'] = 'ҥ'; + map!['enhookcyrillic'] = 'ӈ'; + map!['enspace'] = '\u2002'; + map!['eogonek'] = 'ę'; + map!['eokorean'] = 'ㅓ'; + map!['eopen'] = 'ɛ'; + map!['eopenclosed'] = 'ʚ'; + map!['eopenreversed'] = 'ɜ'; + map!['eopenreversedclosed'] = 'ɞ'; + map!['eopenreversedhook'] = 'ɝ'; + map!['eparen'] = '⒠'; + map!['epsilon'] = 'ε'; + map!['epsilontonos'] = 'έ'; + map!['equal'] = '='; + map!['equalmonospace'] = '='; + map!['equalsmall'] = '﹦'; + map!['equalsuperior'] = '⁼'; + map!['equivalence'] = '≡'; + map!['erbopomofo'] = 'ㄦ'; + map!['ercyrillic'] = 'р'; + map!['ereversed'] = 'ɘ'; + map!['ereversedcyrillic'] = 'э'; + map!['escyrillic'] = 'с'; + map!['esdescendercyrillic'] = 'ҫ'; + map!['esh'] = 'ʃ'; + map!['eshcurl'] = 'ʆ'; + map!['eshortdeva'] = 'ऎ'; + map!['eshortvowelsigndeva'] = 'ॆ'; + map!['eshreversedloop'] = 'ƪ'; + map!['eshsquatreversed'] = 'ʅ'; + map!['esmallhiragana'] = 'ぇ'; + map!['esmallkatakana'] = 'ェ'; + map!['esmallkatakanahalfwidth'] = 'ェ'; + map!['estimated'] = '℮'; + map!['esuperior'] = ''; + map!['eta'] = 'η'; + map!['etarmenian'] = 'ը'; + map!['etatonos'] = 'ή'; + map!['eth'] = 'ð'; + map!['etilde'] = 'ẽ'; + map!['etildebelow'] = 'ḛ'; + map!['etnahtafoukhhebrew'] = '֑'; + map!['etnahtafoukhlefthebrew'] = '֑'; + map!['etnahtahebrew'] = '֑'; + map!['etnahtalefthebrew'] = '֑'; + map!['eturned'] = 'ǝ'; + map!['eukorean'] = 'ㅡ'; + map!['euro'] = '€'; + map!['evowelsignbengali'] = 'ে'; + map!['evowelsigndeva'] = 'े'; + map!['evowelsigngujarati'] = 'ે'; + map!['exclam'] = '!'; + map!['exclamarmenian'] = '՜'; + map!['exclamdbl'] = '‼'; + map!['exclamdown'] = '¡'; + map!['exclamdownsmall'] = ''; + map!['exclammonospace'] = '!'; + map!['exclamsmall'] = ''; + map!['existential'] = '∃'; + map!['ezh'] = 'ʒ'; + map!['ezhcaron'] = 'ǯ'; + map!['ezhcurl'] = 'ʓ'; + map!['ezhreversed'] = 'ƹ'; + map!['ezhtail'] = 'ƺ'; + map!['f'] = 'f'; + map!['fadeva'] = 'फ़'; + map!['fagurmukhi'] = 'ਫ਼'; + map!['fahrenheit'] = '℉'; + map!['fathaarabic'] = 'َ'; + map!['fathalowarabic'] = 'َ'; + map!['fathatanarabic'] = 'ً'; + map!['fbopomofo'] = 'ㄈ'; + map!['fcircle'] = 'ⓕ'; + map!['fdotaccent'] = 'ḟ'; + map!['feharabic'] = 'ف'; + map!['feharmenian'] = 'ֆ'; + map!['fehfinalarabic'] = 'ﻒ'; + map!['fehinitialarabic'] = 'ﻓ'; + map!['fehmedialarabic'] = 'ﻔ'; + map!['feicoptic'] = 'ϥ'; + map!['female'] = '♀'; + map!['ff'] = 'ff'; + map!['ffi'] = 'ffi'; + map!['ffl'] = 'ffl'; + map!['fi'] = 'fi'; + map!['fifteencircle'] = '⑮'; + map!['fifteenparen'] = '⒂'; + map!['fifteenperiod'] = '⒖'; + map!['figuredash'] = '‒'; + map!['filledbox'] = '■'; + map!['filledrect'] = '▬'; + map!['finalkaf'] = 'ך'; + map!['finalkafdagesh'] = 'ךּ'; + map!['finalkafdageshhebrew'] = 'ךּ'; + map!['finalkafhebrew'] = 'ך'; + map!['finalmem'] = 'ם'; + map!['finalmemhebrew'] = 'ם'; + map!['finalnun'] = 'ן'; + map!['finalnunhebrew'] = 'ן'; + map!['finalpe'] = 'ף'; + map!['finalpehebrew'] = 'ף'; + map!['finaltsadi'] = 'ץ'; + map!['finaltsadihebrew'] = 'ץ'; + map!['firsttonechinese'] = 'ˉ'; + map!['fisheye'] = '◉'; + map!['fitacyrillic'] = 'ѳ'; + map!['five'] = '5'; + map!['fivearabic'] = '٥'; + map!['fivebengali'] = '৫'; + map!['fivecircle'] = '⑤'; + map!['fivecircleinversesansserif'] = '➎'; + map!['fivedeva'] = '५'; + map!['fiveeighths'] = '⅝'; + map!['fivegujarati'] = '૫'; + map!['fivegurmukhi'] = '੫'; + map!['fivehackarabic'] = '٥'; + map!['fivehangzhou'] = '〥'; + map!['fiveideographicparen'] = '㈤'; + map!['fiveinferior'] = '₅'; + map!['fivemonospace'] = '5'; + map!['fiveoldstyle'] = ''; + map!['fiveparen'] = '⑸'; + map!['fiveperiod'] = '⒌'; + map!['fivepersian'] = '۵'; + map!['fiveroman'] = 'ⅴ'; + map!['fivesuperior'] = '⁵'; + map!['fivethai'] = '๕'; + map!['fl'] = 'fl'; + map!['florin'] = 'ƒ'; + map!['fmonospace'] = 'f'; + map!['fmsquare'] = '㎙'; + map!['fofanthai'] = 'ฟ'; + map!['fofathai'] = 'ฝ'; + map!['fongmanthai'] = '๏'; + map!['forall'] = '∀'; + map!['four'] = '4'; + map!['fourarabic'] = '٤'; + map!['fourbengali'] = '৪'; + map!['fourcircle'] = '④'; + map!['fourcircleinversesansserif'] = '➍'; + map!['fourdeva'] = '४'; + map!['fourgujarati'] = '૪'; + map!['fourgurmukhi'] = '੪'; + map!['fourhackarabic'] = '٤'; + map!['fourhangzhou'] = '〤'; + map!['fourideographicparen'] = '㈣'; + map!['fourinferior'] = '₄'; + map!['fourmonospace'] = '4'; + map!['fournumeratorbengali'] = '৷'; + map!['fouroldstyle'] = ''; + map!['fourparen'] = '⑷'; + map!['fourperiod'] = '⒋'; + map!['fourpersian'] = '۴'; + map!['fourroman'] = 'ⅳ'; + map!['foursuperior'] = '⁴'; + map!['fourteencircle'] = '⑭'; + map!['fourteenparen'] = '⒁'; + map!['fourteenperiod'] = '⒕'; + map!['fourthai'] = '๔'; + map!['fourthtonechinese'] = 'ˋ'; + map!['fparen'] = '⒡'; + map!['fraction'] = '⁄'; + map!['franc'] = '₣'; + map!['g'] = 'g'; + map!['gabengali'] = 'গ'; + map!['gacute'] = 'ǵ'; + map!['gadeva'] = 'ग'; + map!['gafarabic'] = 'گ'; + map!['gaffinalarabic'] = 'ﮓ'; + map!['gafinitialarabic'] = 'ﮔ'; + map!['gafmedialarabic'] = 'ﮕ'; + map!['gagujarati'] = 'ગ'; + map!['gagurmukhi'] = 'ਗ'; + map!['gahiragana'] = 'が'; + map!['gakatakana'] = 'ガ'; + map!['gamma'] = 'γ'; + map!['gammalatinsmall'] = 'ɣ'; + map!['gammasuperior'] = 'ˠ'; + map!['gangiacoptic'] = 'ϫ'; + map!['gbopomofo'] = 'ㄍ'; + map!['gbreve'] = 'ğ'; + map!['gcaron'] = 'ǧ'; + map!['gcedilla'] = 'ģ'; + map!['gcircle'] = 'ⓖ'; + map!['gcircumflex'] = 'ĝ'; + map!['gcommaaccent'] = 'ģ'; + map!['gdot'] = 'ġ'; + map!['gdotaccent'] = 'ġ'; + map!['gecyrillic'] = 'г'; + map!['gehiragana'] = 'げ'; + map!['gekatakana'] = 'ゲ'; + map!['geometricallyequal'] = '≑'; + map!['gereshaccenthebrew'] = '֜'; + map!['gereshhebrew'] = '׳'; + map!['gereshmuqdamhebrew'] = '֝'; + map!['germandbls'] = 'ß'; + map!['gershayimaccenthebrew'] = '֞'; + map!['gershayimhebrew'] = '״'; + map!['getamark'] = '〓'; + map!['ghabengali'] = 'ঘ'; + map!['ghadarmenian'] = 'ղ'; + map!['ghadeva'] = 'घ'; + map!['ghagujarati'] = 'ઘ'; + map!['ghagurmukhi'] = 'ਘ'; + map!['ghainarabic'] = 'غ'; + map!['ghainfinalarabic'] = 'ﻎ'; + map!['ghaininitialarabic'] = 'ﻏ'; + map!['ghainmedialarabic'] = 'ﻐ'; + map!['ghemiddlehookcyrillic'] = 'ҕ'; + map!['ghestrokecyrillic'] = 'ғ'; + map!['gheupturncyrillic'] = 'ґ'; + map!['ghhadeva'] = 'ग़'; + map!['ghhagurmukhi'] = 'ਗ਼'; + map!['ghook'] = 'ɠ'; + map!['ghzsquare'] = '㎓'; + map!['gihiragana'] = 'ぎ'; + map!['gikatakana'] = 'ギ'; + map!['gimarmenian'] = 'գ'; + map!['gimel'] = 'ג'; + map!['gimeldagesh'] = 'גּ'; + map!['gimeldageshhebrew'] = 'גּ'; + map!['gimelhebrew'] = 'ג'; + map!['gjecyrillic'] = 'ѓ'; + map!['glottalinvertedstroke'] = 'ƾ'; + map!['glottalstop'] = 'ʔ'; + map!['glottalstopinverted'] = 'ʖ'; + map!['glottalstopmod'] = 'ˀ'; + map!['glottalstopreversed'] = 'ʕ'; + map!['glottalstopreversedmod'] = 'ˁ'; + map!['glottalstopreversedsuperior'] = 'ˤ'; + map!['glottalstopstroke'] = 'ʡ'; + map!['glottalstopstrokereversed'] = 'ʢ'; + map!['gmacron'] = 'ḡ'; + map!['gmonospace'] = 'g'; + map!['gohiragana'] = 'ご'; + map!['gokatakana'] = 'ゴ'; + map!['gparen'] = '⒢'; + map!['gpasquare'] = '㎬'; + map!['gradient'] = '∇'; + map!['grave'] = '`'; + map!['gravebelowcmb'] = '̖'; + map!['gravecmb'] = '̀'; + map!['gravecomb'] = '̀'; + map!['gravedeva'] = '॓'; + map!['gravelowmod'] = 'ˎ'; + map!['gravemonospace'] = '`'; + map!['gravetonecmb'] = '̀'; + map!['greater'] = '>'; + map!['greaterequal'] = '≥'; + map!['greaterequalorless'] = '⋛'; + map!['greatermonospace'] = '>'; + map!['greaterorequivalent'] = '≳'; + map!['greaterorless'] = '≷'; + map!['greateroverequal'] = '≧'; + map!['greatersmall'] = '﹥'; + map!['gscript'] = 'ɡ'; + map!['gstroke'] = 'ǥ'; + map!['guhiragana'] = 'ぐ'; + map!['guillemotleft'] = '«'; + map!['guillemotright'] = '»'; + map!['guilsinglleft'] = '‹'; + map!['guilsinglright'] = '›'; + map!['gukatakana'] = 'グ'; + map!['guramusquare'] = '㌘'; + map!['gysquare'] = '㏉'; + map!['h'] = 'h'; + map!['haabkhasiancyrillic'] = 'ҩ'; + map!['haaltonearabic'] = 'ہ'; + map!['habengali'] = 'হ'; + map!['hadescendercyrillic'] = 'ҳ'; + map!['hadeva'] = 'ह'; + map!['hagujarati'] = 'હ'; + map!['hagurmukhi'] = 'ਹ'; + map!['haharabic'] = 'ح'; + map!['hahfinalarabic'] = 'ﺢ'; + map!['hahinitialarabic'] = 'ﺣ'; + map!['hahiragana'] = 'は'; + map!['hahmedialarabic'] = 'ﺤ'; + map!['haitusquare'] = '㌪'; + map!['hakatakana'] = 'ハ'; + map!['hakatakanahalfwidth'] = 'ハ'; + map!['halantgurmukhi'] = '੍'; + map!['hamzaarabic'] = 'ء'; + map!['hamzalowarabic'] = 'ء'; + map!['hangulfiller'] = 'ㅤ'; + map!['hardsigncyrillic'] = 'ъ'; + map!['harpoonleftbarbup'] = '↼'; + map!['harpoonrightbarbup'] = '⇀'; + map!['hasquare'] = '㏊'; + map!['hatafpatah'] = 'ֲ'; + map!['hatafpatah16'] = 'ֲ'; + map!['hatafpatah23'] = 'ֲ'; + map!['hatafpatah2f'] = 'ֲ'; + map!['hatafpatahhebrew'] = 'ֲ'; + map!['hatafpatahnarrowhebrew'] = 'ֲ'; + map!['hatafpatahquarterhebrew'] = 'ֲ'; + map!['hatafpatahwidehebrew'] = 'ֲ'; + map!['hatafqamats'] = 'ֳ'; + map!['hatafqamats1b'] = 'ֳ'; + map!['hatafqamats28'] = 'ֳ'; + map!['hatafqamats34'] = 'ֳ'; + map!['hatafqamatshebrew'] = 'ֳ'; + map!['hatafqamatsnarrowhebrew'] = 'ֳ'; + map!['hatafqamatsquarterhebrew'] = 'ֳ'; + map!['hatafqamatswidehebrew'] = 'ֳ'; + map!['hatafsegol'] = 'ֱ'; + map!['hatafsegol17'] = 'ֱ'; + map!['hatafsegol24'] = 'ֱ'; + map!['hatafsegol30'] = 'ֱ'; + map!['hatafsegolhebrew'] = 'ֱ'; + map!['hatafsegolnarrowhebrew'] = 'ֱ'; + map!['hatafsegolquarterhebrew'] = 'ֱ'; + map!['hatafsegolwidehebrew'] = 'ֱ'; + map!['hbar'] = 'ħ'; + map!['hbopomofo'] = 'ㄏ'; + map!['hbrevebelow'] = 'ḫ'; + map!['hcedilla'] = 'ḩ'; + map!['hcircle'] = 'ⓗ'; + map!['hcircumflex'] = 'ĥ'; + map!['hdieresis'] = 'ḧ'; + map!['hdotaccent'] = 'ḣ'; + map!['hdotbelow'] = 'ḥ'; + map!['he'] = 'ה'; + map!['heart'] = '♥'; + map!['heartsuitblack'] = '♥'; + map!['heartsuitwhite'] = '♡'; + map!['hedagesh'] = 'הּ'; + map!['hedageshhebrew'] = 'הּ'; + map!['hehaltonearabic'] = 'ہ'; + map!['heharabic'] = 'ه'; + map!['hehebrew'] = 'ה'; + map!['hehfinalaltonearabic'] = 'ﮧ'; + map!['hehfinalalttwoarabic'] = 'ﻪ'; + map!['hehfinalarabic'] = 'ﻪ'; + map!['hehhamzaabovefinalarabic'] = 'ﮥ'; + map!['hehhamzaaboveisolatedarabic'] = 'ﮤ'; + map!['hehinitialaltonearabic'] = 'ﮨ'; + map!['hehinitialarabic'] = 'ﻫ'; + map!['hehiragana'] = 'へ'; + map!['hehmedialaltonearabic'] = 'ﮩ'; + map!['hehmedialarabic'] = 'ﻬ'; + map!['heiseierasquare'] = '㍻'; + map!['hekatakana'] = 'ヘ'; + map!['hekatakanahalfwidth'] = 'ヘ'; + map!['hekutaarusquare'] = '㌶'; + map!['henghook'] = 'ɧ'; + map!['herutusquare'] = '㌹'; + map!['het'] = 'ח'; + map!['hethebrew'] = 'ח'; + map!['hhook'] = 'ɦ'; + map!['hhooksuperior'] = 'ʱ'; + map!['hieuhacirclekorean'] = '㉻'; + map!['hieuhaparenkorean'] = '㈛'; + map!['hieuhcirclekorean'] = '㉭'; + map!['hieuhkorean'] = 'ㅎ'; + map!['hieuhparenkorean'] = '㈍'; + map!['hihiragana'] = 'ひ'; + map!['hikatakana'] = 'ヒ'; + map!['hikatakanahalfwidth'] = 'ヒ'; + map!['hiriq'] = 'ִ'; + map!['hiriq14'] = 'ִ'; + map!['hiriq21'] = 'ִ'; + map!['hiriq2d'] = 'ִ'; + map!['hiriqhebrew'] = 'ִ'; + map!['hiriqnarrowhebrew'] = 'ִ'; + map!['hiriqquarterhebrew'] = 'ִ'; + map!['hiriqwidehebrew'] = 'ִ'; + map!['hlinebelow'] = 'ẖ'; + map!['hmonospace'] = 'h'; + map!['hoarmenian'] = 'հ'; + map!['hohipthai'] = 'ห'; + map!['hohiragana'] = 'ほ'; + map!['hokatakana'] = 'ホ'; + map!['hokatakanahalfwidth'] = 'ホ'; + map!['holam'] = 'ֹ'; + map!['holam19'] = 'ֹ'; + map!['holam26'] = 'ֹ'; + map!['holam32'] = 'ֹ'; + map!['holamhebrew'] = 'ֹ'; + map!['holamnarrowhebrew'] = 'ֹ'; + map!['holamquarterhebrew'] = 'ֹ'; + map!['holamwidehebrew'] = 'ֹ'; + map!['honokhukthai'] = 'ฮ'; + map!['hookabovecomb'] = '̉'; + map!['hookcmb'] = '̉'; + map!['hookpalatalizedbelowcmb'] = '̡'; + map!['hookretroflexbelowcmb'] = '̢'; + map!['hoonsquare'] = '㍂'; + map!['horicoptic'] = 'ϩ'; + map!['horizontalbar'] = '―'; + map!['horncmb'] = '̛'; + map!['hotsprings'] = '♨'; + map!['house'] = '⌂'; + map!['hparen'] = '⒣'; + map!['hsuperior'] = 'ʰ'; + map!['hturned'] = 'ɥ'; + map!['huhiragana'] = 'ふ'; + map!['huiitosquare'] = '㌳'; + map!['hukatakana'] = 'フ'; + map!['hukatakanahalfwidth'] = 'フ'; + map!['hungarumlaut'] = '˝'; + map!['hungarumlautcmb'] = '̋'; + map!['hv'] = 'ƕ'; + map!['hyphen'] = '-'; + map!['hypheninferior'] = ''; + map!['hyphenmonospace'] = '-'; + map!['hyphensmall'] = '﹣'; + map!['hyphensuperior'] = ''; + map!['hyphentwo'] = '‐'; + map!['i'] = 'i'; + map!['iacute'] = 'í'; + map!['iacyrillic'] = 'я'; + map!['ibengali'] = 'ই'; + map!['ibopomofo'] = 'ㄧ'; + map!['ibreve'] = 'ĭ'; + map!['icaron'] = 'ǐ'; + map!['icircle'] = 'ⓘ'; + map!['icircumflex'] = 'î'; + map!['icyrillic'] = 'і'; + map!['idblgrave'] = 'ȉ'; + map!['ideographearthcircle'] = '㊏'; + map!['ideographfirecircle'] = '㊋'; + map!['ideographicallianceparen'] = '㈿'; + map!['ideographiccallparen'] = '㈺'; + map!['ideographiccentrecircle'] = '㊥'; + map!['ideographicclose'] = '〆'; + map!['ideographiccomma'] = '、'; + map!['ideographiccommaleft'] = '、'; + map!['ideographiccongratulationparen'] = '㈷'; + map!['ideographiccorrectcircle'] = '㊣'; + map!['ideographicearthparen'] = '㈯'; + map!['ideographicenterpriseparen'] = '㈽'; + map!['ideographicexcellentcircle'] = '㊝'; + map!['ideographicfestivalparen'] = '㉀'; + map!['ideographicfinancialcircle'] = '㊖'; + map!['ideographicfinancialparen'] = '㈶'; + map!['ideographicfireparen'] = '㈫'; + map!['ideographichaveparen'] = '㈲'; + map!['ideographichighcircle'] = '㊤'; + map!['ideographiciterationmark'] = '々'; + map!['ideographiclaborcircle'] = '㊘'; + map!['ideographiclaborparen'] = '㈸'; + map!['ideographicleftcircle'] = '㊧'; + map!['ideographiclowcircle'] = '㊦'; + map!['ideographicmedicinecircle'] = '㊩'; + map!['ideographicmetalparen'] = '㈮'; + map!['ideographicmoonparen'] = '㈪'; + map!['ideographicnameparen'] = '㈴'; + map!['ideographicperiod'] = '。'; + map!['ideographicprintcircle'] = '㊞'; + map!['ideographicreachparen'] = '㉃'; + map!['ideographicrepresentparen'] = '㈹'; + map!['ideographicresourceparen'] = '㈾'; + map!['ideographicrightcircle'] = '㊨'; + map!['ideographicsecretcircle'] = '㊙'; + map!['ideographicselfparen'] = '㉂'; + map!['ideographicsocietyparen'] = '㈳'; + map!['ideographicspace'] = '\u3000'; + map!['ideographicspecialparen'] = '㈵'; + map!['ideographicstockparen'] = '㈱'; + map!['ideographicstudyparen'] = '㈻'; + map!['ideographicsunparen'] = '㈰'; + map!['ideographicsuperviseparen'] = '㈼'; + map!['ideographicwaterparen'] = '㈬'; + map!['ideographicwoodparen'] = '㈭'; + map!['ideographiczero'] = '〇'; + map!['ideographmetalcircle'] = '㊎'; + map!['ideographmooncircle'] = '㊊'; + map!['ideographnamecircle'] = '㊔'; + map!['ideographsuncircle'] = '㊐'; + map!['ideographwatercircle'] = '㊌'; + map!['ideographwoodcircle'] = '㊍'; + map!['ideva'] = 'इ'; + map!['idieresis'] = 'ï'; + map!['idieresisacute'] = 'ḯ'; + map!['idieresiscyrillic'] = 'ӥ'; + map!['idotbelow'] = 'ị'; + map!['iebrevecyrillic'] = 'ӗ'; + map!['iecyrillic'] = 'е'; + map!['ieungacirclekorean'] = '㉵'; + map!['ieungaparenkorean'] = '㈕'; + map!['ieungcirclekorean'] = '㉧'; + map!['ieungkorean'] = 'ㅇ'; + map!['ieungparenkorean'] = '㈇'; + map!['igrave'] = 'ì'; + map!['igujarati'] = 'ઇ'; + map!['igurmukhi'] = 'ਇ'; + map!['ihiragana'] = 'い'; + map!['ihookabove'] = 'ỉ'; + map!['iibengali'] = 'ঈ'; + map!['iicyrillic'] = 'и'; + map!['iideva'] = 'ई'; + map!['iigujarati'] = 'ઈ'; + map!['iigurmukhi'] = 'ਈ'; + map!['iimatragurmukhi'] = 'ੀ'; + map!['iinvertedbreve'] = 'ȋ'; + map!['iishortcyrillic'] = 'й'; + map!['iivowelsignbengali'] = 'ী'; + map!['iivowelsigndeva'] = 'ी'; + map!['iivowelsigngujarati'] = 'ી'; + map!['ij'] = 'ij'; + map!['ikatakana'] = 'イ'; + map!['ikatakanahalfwidth'] = 'イ'; + map!['ikorean'] = 'ㅣ'; + map!['ilde'] = '˜'; + map!['iluyhebrew'] = '֬'; + map!['imacron'] = 'ī'; + map!['imacroncyrillic'] = 'ӣ'; + map!['imageorapproximatelyequal'] = '≓'; + map!['imatragurmukhi'] = 'ਿ'; + map!['imonospace'] = 'i'; + map!['increment'] = '∆'; + map!['infinity'] = '∞'; + map!['iniarmenian'] = 'ի'; + map!['integral'] = '∫'; + map!['integralbottom'] = '⌡'; + map!['integralbt'] = '⌡'; + map!['integralex'] = ''; + map!['integraltop'] = '⌠'; + map!['integraltp'] = '⌠'; + map!['intersection'] = '∩'; + map!['intisquare'] = '㌅'; + map!['invbullet'] = '◘'; + map!['invcircle'] = '◙'; + map!['invsmileface'] = '☻'; + map!['iocyrillic'] = 'ё'; + map!['iogonek'] = 'į'; + map!['iota'] = 'ι'; + map!['iotadieresis'] = 'ϊ'; + map!['iotadieresistonos'] = 'ΐ'; + map!['iotalatin'] = 'ɩ'; + map!['iotatonos'] = 'ί'; + map!['iparen'] = '⒤'; + map!['irigurmukhi'] = 'ੲ'; + map!['ismallhiragana'] = 'ぃ'; + map!['ismallkatakana'] = 'ィ'; + map!['ismallkatakanahalfwidth'] = 'ィ'; + map!['issharbengali'] = '৺'; + map!['istroke'] = 'ɨ'; + map!['isuperior'] = ''; + map!['iterationhiragana'] = 'ゝ'; + map!['iterationkatakana'] = 'ヽ'; + map!['itilde'] = 'ĩ'; + map!['itildebelow'] = 'ḭ'; + map!['iubopomofo'] = 'ㄩ'; + map!['iucyrillic'] = 'ю'; + map!['ivowelsignbengali'] = 'ি'; + map!['ivowelsigndeva'] = 'ि'; + map!['ivowelsigngujarati'] = 'િ'; + map!['izhitsacyrillic'] = 'ѵ'; + map!['izhitsadblgravecyrillic'] = 'ѷ'; + map!['j'] = 'j'; + map!['jaarmenian'] = 'ձ'; + map!['jabengali'] = 'জ'; + map!['jadeva'] = 'ज'; + map!['jagujarati'] = 'જ'; + map!['jagurmukhi'] = 'ਜ'; + map!['jbopomofo'] = 'ㄐ'; + map!['jcaron'] = 'ǰ'; + map!['jcircle'] = 'ⓙ'; + map!['jcircumflex'] = 'ĵ'; + map!['jcrossedtail'] = 'ʝ'; + map!['jdotlessstroke'] = 'ɟ'; + map!['jecyrillic'] = 'ј'; + map!['jeemarabic'] = 'ج'; + map!['jeemfinalarabic'] = 'ﺞ'; + map!['jeeminitialarabic'] = 'ﺟ'; + map!['jeemmedialarabic'] = 'ﺠ'; + map!['jeharabic'] = 'ژ'; + map!['jehfinalarabic'] = 'ﮋ'; + map!['jhabengali'] = 'ঝ'; + map!['jhadeva'] = 'झ'; + map!['jhagujarati'] = 'ઝ'; + map!['jhagurmukhi'] = 'ਝ'; + map!['jheharmenian'] = 'ջ'; + map!['jis'] = '〄'; + map!['jmonospace'] = 'j'; + map!['jparen'] = '⒥'; + map!['jsuperior'] = 'ʲ'; + map!['k'] = 'k'; + map!['kabashkircyrillic'] = 'ҡ'; + map!['kabengali'] = 'ক'; + map!['kacute'] = 'ḱ'; + map!['kacyrillic'] = 'к'; + map!['kadescendercyrillic'] = 'қ'; + map!['kadeva'] = 'क'; + map!['kaf'] = 'כ'; + map!['kafarabic'] = 'ك'; + map!['kafdagesh'] = 'כּ'; + map!['kafdageshhebrew'] = 'כּ'; + map!['kaffinalarabic'] = 'ﻚ'; + map!['kafhebrew'] = 'כ'; + map!['kafinitialarabic'] = 'ﻛ'; + map!['kafmedialarabic'] = 'ﻜ'; + map!['kafrafehebrew'] = 'כֿ'; + map!['kagujarati'] = 'ક'; + map!['kagurmukhi'] = 'ਕ'; + map!['kahiragana'] = 'か'; + map!['kahookcyrillic'] = 'ӄ'; + map!['kakatakana'] = 'カ'; + map!['kakatakanahalfwidth'] = 'カ'; + map!['kappa'] = 'κ'; + map!['kappasymbolgreek'] = 'ϰ'; + map!['kapyeounmieumkorean'] = 'ㅱ'; + map!['kapyeounphieuphkorean'] = 'ㆄ'; + map!['kapyeounpieupkorean'] = 'ㅸ'; + map!['kapyeounssangpieupkorean'] = 'ㅹ'; + map!['karoriisquare'] = '㌍'; + map!['kashidaautoarabic'] = 'ـ'; + map!['kashidaautonosidebearingarabic'] = 'ـ'; + map!['kasmallkatakana'] = 'ヵ'; + map!['kasquare'] = '㎄'; + map!['kasraarabic'] = 'ِ'; + map!['kasratanarabic'] = 'ٍ'; + map!['kastrokecyrillic'] = 'ҟ'; + map!['katahiraprolongmarkhalfwidth'] = 'ー'; + map!['kaverticalstrokecyrillic'] = 'ҝ'; + map!['kbopomofo'] = 'ㄎ'; + map!['kcalsquare'] = '㎉'; + map!['kcaron'] = 'ǩ'; + map!['kcedilla'] = 'ķ'; + map!['kcircle'] = 'ⓚ'; + map!['kcommaaccent'] = 'ķ'; + map!['kdotbelow'] = 'ḳ'; + map!['keharmenian'] = 'ք'; + map!['kehiragana'] = 'け'; + map!['kekatakana'] = 'ケ'; + map!['kekatakanahalfwidth'] = 'ケ'; + map!['kenarmenian'] = 'կ'; + map!['kesmallkatakana'] = 'ヶ'; + map!['kgreenlandic'] = 'ĸ'; + map!['khabengali'] = 'খ'; + map!['khacyrillic'] = 'х'; + map!['khadeva'] = 'ख'; + map!['khagujarati'] = 'ખ'; + map!['khagurmukhi'] = 'ਖ'; + map!['khaharabic'] = 'خ'; + map!['khahfinalarabic'] = 'ﺦ'; + map!['khahinitialarabic'] = 'ﺧ'; + map!['khahmedialarabic'] = 'ﺨ'; + map!['kheicoptic'] = 'ϧ'; + map!['khhadeva'] = 'ख़'; + map!['khhagurmukhi'] = 'ਖ਼'; + map!['khieukhacirclekorean'] = '㉸'; + map!['khieukhaparenkorean'] = '㈘'; + map!['khieukhcirclekorean'] = '㉪'; + map!['khieukhkorean'] = 'ㅋ'; + map!['khieukhparenkorean'] = '㈊'; + map!['khokhaithai'] = 'ข'; + map!['khokhonthai'] = 'ฅ'; + map!['khokhuatthai'] = 'ฃ'; + map!['khokhwaithai'] = 'ค'; + map!['khomutthai'] = '๛'; + map!['khook'] = 'ƙ'; + map!['khorakhangthai'] = 'ฆ'; + map!['khzsquare'] = '㎑'; + map!['kihiragana'] = 'き'; + map!['kikatakana'] = 'キ'; + map!['kikatakanahalfwidth'] = 'キ'; + map!['kiroguramusquare'] = '㌕'; + map!['kiromeetorusquare'] = '㌖'; + map!['kirosquare'] = '㌔'; + map!['kiyeokacirclekorean'] = '㉮'; + map!['kiyeokaparenkorean'] = '㈎'; + map!['kiyeokcirclekorean'] = '㉠'; + map!['kiyeokkorean'] = 'ㄱ'; + map!['kiyeokparenkorean'] = '㈀'; + map!['kiyeoksioskorean'] = 'ㄳ'; + map!['kjecyrillic'] = 'ќ'; + map!['klinebelow'] = 'ḵ'; + map!['klsquare'] = '㎘'; + map!['kmcubedsquare'] = '㎦'; + map!['kmonospace'] = 'k'; + map!['kmsquaredsquare'] = '㎢'; + map!['kohiragana'] = 'こ'; + map!['kohmsquare'] = '㏀'; + map!['kokaithai'] = 'ก'; + map!['kokatakana'] = 'コ'; + map!['kokatakanahalfwidth'] = 'コ'; + map!['kooposquare'] = '㌞'; + map!['koppacyrillic'] = 'ҁ'; + map!['koreanstandardsymbol'] = '㉿'; + map!['koroniscmb'] = '̓'; + map!['kparen'] = '⒦'; + map!['kpasquare'] = '㎪'; + map!['ksicyrillic'] = 'ѯ'; + map!['ktsquare'] = '㏏'; + map!['kturned'] = 'ʞ'; + map!['kuhiragana'] = 'く'; + map!['kukatakana'] = 'ク'; + map!['kukatakanahalfwidth'] = 'ク'; + map!['kvsquare'] = '㎸'; + map!['kwsquare'] = '㎾'; + map!['l'] = 'l'; + map!['labengali'] = 'ল'; + map!['lacute'] = 'ĺ'; + map!['ladeva'] = 'ल'; + map!['lagujarati'] = 'લ'; + map!['lagurmukhi'] = 'ਲ'; + map!['lakkhangyaothai'] = 'ๅ'; + map!['lamaleffinalarabic'] = 'ﻼ'; + map!['lamalefhamzaabovefinalarabic'] = 'ﻸ'; + map!['lamalefhamzaaboveisolatedarabic'] = 'ﻷ'; + map!['lamalefhamzabelowfinalarabic'] = 'ﻺ'; + map!['lamalefhamzabelowisolatedarabic'] = 'ﻹ'; + map!['lamalefisolatedarabic'] = 'ﻻ'; + map!['lamalefmaddaabovefinalarabic'] = 'ﻶ'; + map!['lamalefmaddaaboveisolatedarabic'] = 'ﻵ'; + map!['lamarabic'] = 'ل'; + map!['lambda'] = 'λ'; + map!['lambdastroke'] = 'ƛ'; + map!['lamed'] = 'ל'; + map!['lameddagesh'] = 'לּ'; + map!['lameddageshhebrew'] = 'לּ'; + map!['lamedhebrew'] = 'ל'; + map!['lamfinalarabic'] = 'ﻞ'; + map!['lamhahinitialarabic'] = 'ﳊ'; + map!['laminitialarabic'] = 'ﻟ'; + map!['lamjeeminitialarabic'] = 'ﳉ'; + map!['lamkhahinitialarabic'] = 'ﳋ'; + map!['lamlamhehisolatedarabic'] = 'ﷲ'; + map!['lammedialarabic'] = 'ﻠ'; + map!['lammeemhahinitialarabic'] = 'ﶈ'; + map!['lammeeminitialarabic'] = 'ﳌ'; + map!['largecircle'] = '◯'; + map!['lbar'] = 'ƚ'; + map!['lbelt'] = 'ɬ'; + map!['lbopomofo'] = 'ㄌ'; + map!['lcaron'] = 'ľ'; + map!['lcedilla'] = 'ļ'; + map!['lcircle'] = 'ⓛ'; + map!['lcircumflexbelow'] = 'ḽ'; + map!['lcommaaccent'] = 'ļ'; + map!['ldot'] = 'ŀ'; + map!['ldotaccent'] = 'ŀ'; + map!['ldotbelow'] = 'ḷ'; + map!['ldotbelowmacron'] = 'ḹ'; + map!['leftangleabovecmb'] = '̚'; + map!['lefttackbelowcmb'] = '̘'; + map!['less'] = '<'; + map!['lessequal'] = '≤'; + map!['lessequalorgreater'] = '⋚'; + map!['lessmonospace'] = '<'; + map!['lessorequivalent'] = '≲'; + map!['lessorgreater'] = '≶'; + map!['lessoverequal'] = '≦'; + map!['lesssmall'] = '﹤'; + map!['lezh'] = 'ɮ'; + map!['lfblock'] = '▌'; + map!['lhookretroflex'] = 'ɭ'; + map!['lira'] = '₤'; + map!['liwnarmenian'] = 'լ'; + map!['lj'] = 'lj'; + map!['ljecyrillic'] = 'љ'; + map!['ll'] = ''; + map!['lladeva'] = 'ळ'; + map!['llagujarati'] = 'ળ'; + map!['llinebelow'] = 'ḻ'; + map!['llladeva'] = 'ऴ'; + map!['llvocalicbengali'] = 'ৡ'; + map!['llvocalicdeva'] = 'ॡ'; + map!['llvocalicvowelsignbengali'] = 'ৣ'; + map!['llvocalicvowelsigndeva'] = 'ॣ'; + map!['lmiddletilde'] = 'ɫ'; + map!['lmonospace'] = 'l'; + map!['lmsquare'] = '㏐'; + map!['lochulathai'] = 'ฬ'; + map!['logicaland'] = '∧'; + map!['logicalnot'] = '¬'; + map!['logicalnotreversed'] = '⌐'; + map!['logicalor'] = '∨'; + map!['lolingthai'] = 'ล'; + map!['longs'] = 'ſ'; + map!['lowlinecenterline'] = '﹎'; + map!['lowlinecmb'] = '̲'; + map!['lowlinedashed'] = '﹍'; + map!['lozenge'] = '◊'; + map!['lparen'] = '⒧'; + map!['lslash'] = 'ł'; + map!['lsquare'] = 'ℓ'; + map!['lsuperior'] = ''; + map!['ltshade'] = '░'; + map!['luthai'] = 'ฦ'; + map!['lvocalicbengali'] = 'ঌ'; + map!['lvocalicdeva'] = 'ऌ'; + map!['lvocalicvowelsignbengali'] = 'ৢ'; + map!['lvocalicvowelsigndeva'] = 'ॢ'; + map!['lxsquare'] = '㏓'; + map!['m'] = 'm'; + map!['mabengali'] = 'ম'; + map!['macron'] = '¯'; + map!['macronbelowcmb'] = '̱'; + map!['macroncmb'] = '̄'; + map!['macronlowmod'] = 'ˍ'; + map!['macronmonospace'] = ' ̄'; + map!['macute'] = 'ḿ'; + map!['madeva'] = 'म'; + map!['magujarati'] = 'મ'; + map!['magurmukhi'] = 'ਮ'; + map!['mahapakhhebrew'] = '֤'; + map!['mahapakhlefthebrew'] = '֤'; + map!['mahiragana'] = 'ま'; + map!['maichattawalowleftthai'] = ''; + map!['maichattawalowrightthai'] = ''; + map!['maichattawathai'] = '๋'; + map!['maichattawaupperleftthai'] = ''; + map!['maieklowleftthai'] = ''; + map!['maieklowrightthai'] = ''; + map!['maiekthai'] = '่'; + map!['maiekupperleftthai'] = ''; + map!['maihanakatleftthai'] = ''; + map!['maihanakatthai'] = 'ั'; + map!['maitaikhuleftthai'] = ''; + map!['maitaikhuthai'] = '็'; + map!['maitholowleftthai'] = ''; + map!['maitholowrightthai'] = ''; + map!['maithothai'] = '้'; + map!['maithoupperleftthai'] = ''; + map!['maitrilowleftthai'] = ''; + map!['maitrilowrightthai'] = ''; + map!['maitrithai'] = '๊'; + map!['maitriupperleftthai'] = ''; + map!['maiyamokthai'] = 'ๆ'; + map!['makatakana'] = 'マ'; + map!['makatakanahalfwidth'] = 'マ'; + map!['male'] = '♂'; + map!['mansyonsquare'] = '㍇'; + map!['maqafhebrew'] = '־'; + map!['mars'] = '♂'; + map!['masoracirclehebrew'] = '֯'; + map!['masquare'] = '㎃'; + map!['mbopomofo'] = 'ㄇ'; + map!['mbsquare'] = '㏔'; + map!['mcircle'] = 'ⓜ'; + map!['mcubedsquare'] = '㎥'; + map!['mdotaccent'] = 'ṁ'; + map!['mdotbelow'] = 'ṃ'; + map!['meemarabic'] = 'م'; + map!['meemfinalarabic'] = 'ﻢ'; + map!['meeminitialarabic'] = 'ﻣ'; + map!['meemmedialarabic'] = 'ﻤ'; + map!['meemmeeminitialarabic'] = 'ﳑ'; + map!['meemmeemisolatedarabic'] = 'ﱈ'; + map!['meetorusquare'] = '㍍'; + map!['mehiragana'] = 'め'; + map!['meizierasquare'] = '㍾'; + map!['mekatakana'] = 'メ'; + map!['mekatakanahalfwidth'] = 'メ'; + map!['mem'] = 'מ'; + map!['memdagesh'] = 'מּ'; + map!['memdageshhebrew'] = 'מּ'; + map!['memhebrew'] = 'מ'; + map!['menarmenian'] = 'մ'; + map!['merkhahebrew'] = '֥'; + map!['merkhakefulahebrew'] = '֦'; + map!['merkhakefulalefthebrew'] = '֦'; + map!['merkhalefthebrew'] = '֥'; + map!['mhook'] = 'ɱ'; + map!['mhzsquare'] = '㎒'; + map!['middledotkatakanahalfwidth'] = '・'; + map!['middot'] = '·'; + map!['mieumacirclekorean'] = '㉲'; + map!['mieumaparenkorean'] = '㈒'; + map!['mieumcirclekorean'] = '㉤'; + map!['mieumkorean'] = 'ㅁ'; + map!['mieumpansioskorean'] = 'ㅰ'; + map!['mieumparenkorean'] = '㈄'; + map!['mieumpieupkorean'] = 'ㅮ'; + map!['mieumsioskorean'] = 'ㅯ'; + map!['mihiragana'] = 'み'; + map!['mikatakana'] = 'ミ'; + map!['mikatakanahalfwidth'] = 'ミ'; + map!['negationslash'] = '-'; + map!['minus'] = '−'; + map!['minusbelowcmb'] = '̠'; + map!['minuscircle'] = '⊖'; + map!['minusmod'] = '˗'; + map!['minusplus'] = '∓'; + map!['minute'] = '′'; + map!['miribaarusquare'] = '㍊'; + map!['mirisquare'] = '㍉'; + map!['mlonglegturned'] = 'ɰ'; + map!['mlsquare'] = '㎖'; + map!['mmcubedsquare'] = '㎣'; + map!['mmonospace'] = 'm'; + map!['mmsquaredsquare'] = '㎟'; + map!['mohiragana'] = 'も'; + map!['mohmsquare'] = '㏁'; + map!['mokatakana'] = 'モ'; + map!['mokatakanahalfwidth'] = 'モ'; + map!['molsquare'] = '㏖'; + map!['momathai'] = 'ม'; + map!['moverssquare'] = '㎧'; + map!['moverssquaredsquare'] = '㎨'; + map!['mparen'] = '⒨'; + map!['mpasquare'] = '㎫'; + map!['mssquare'] = '㎳'; + map!['msuperior'] = ''; + map!['mturned'] = 'ɯ'; + map!['mu'] = 'µ'; + map!['mu1'] = 'µ'; + map!['muasquare'] = '㎂'; + map!['muchgreater'] = '≫'; + map!['muchless'] = '≪'; + map!['mufsquare'] = '㎌'; + map!['mugreek'] = 'μ'; + map!['mugsquare'] = '㎍'; + map!['muhiragana'] = 'む'; + map!['mukatakana'] = 'ム'; + map!['mukatakanahalfwidth'] = 'ム'; + map!['mulsquare'] = '㎕'; + map!['multiply'] = '×'; + map!['mumsquare'] = '㎛'; + map!['munahhebrew'] = '֣'; + map!['munahlefthebrew'] = '֣'; + map!['musicalnote'] = '♪'; + map!['musicalnotedbl'] = '♫'; + map!['musicflatsign'] = '♭'; + map!['musicsharpsign'] = '♯'; + map!['mussquare'] = '㎲'; + map!['muvsquare'] = '㎶'; + map!['muwsquare'] = '㎼'; + map!['mvmegasquare'] = '㎹'; + map!['mvsquare'] = '㎷'; + map!['mwmegasquare'] = '㎿'; + map!['mwsquare'] = '㎽'; + map!['n'] = 'n'; + map!['nabengali'] = 'ন'; + map!['nabla'] = '∇'; + map!['nacute'] = 'ń'; + map!['nadeva'] = 'न'; + map!['nagujarati'] = 'ન'; + map!['nagurmukhi'] = 'ਨ'; + map!['nahiragana'] = 'な'; + map!['nakatakana'] = 'ナ'; + map!['nakatakanahalfwidth'] = 'ナ'; + map!['napostrophe'] = 'ʼn'; + map!['nasquare'] = '㎁'; + map!['nbopomofo'] = 'ㄋ'; + map!['nbspace'] = '\u00a0'; + map!['ncaron'] = 'ň'; + map!['ncedilla'] = 'ņ'; + map!['ncircle'] = 'ⓝ'; + map!['ncircumflexbelow'] = 'ṋ'; + map!['ncommaaccent'] = 'ņ'; + map!['ndotaccent'] = 'ṅ'; + map!['ndotbelow'] = 'ṇ'; + map!['nehiragana'] = 'ね'; + map!['nekatakana'] = 'ネ'; + map!['nekatakanahalfwidth'] = 'ネ'; + map!['newsheqelsign'] = '₪'; + map!['nfsquare'] = '㎋'; + map!['ngabengali'] = 'ঙ'; + map!['ngadeva'] = 'ङ'; + map!['ngagujarati'] = 'ઙ'; + map!['ngagurmukhi'] = 'ਙ'; + map!['ngonguthai'] = 'ง'; + map!['nhiragana'] = 'ん'; + map!['nhookleft'] = 'ɲ'; + map!['nhookretroflex'] = 'ɳ'; + map!['nieunacirclekorean'] = '㉯'; + map!['nieunaparenkorean'] = '㈏'; + map!['nieuncieuckorean'] = 'ㄵ'; + map!['nieuncirclekorean'] = '㉡'; + map!['nieunhieuhkorean'] = 'ㄶ'; + map!['nieunkorean'] = 'ㄴ'; + map!['nieunpansioskorean'] = 'ㅨ'; + map!['nieunparenkorean'] = '㈁'; + map!['nieunsioskorean'] = 'ㅧ'; + map!['nieuntikeutkorean'] = 'ㅦ'; + map!['nihiragana'] = 'に'; + map!['nikatakana'] = 'ニ'; + map!['nikatakanahalfwidth'] = 'ニ'; + map!['nikhahitleftthai'] = ''; + map!['nikhahitthai'] = 'ํ'; + map!['nine'] = '9'; + map!['ninearabic'] = '٩'; + map!['ninebengali'] = '৯'; + map!['ninecircle'] = '⑨'; + map!['ninecircleinversesansserif'] = '➒'; + map!['ninedeva'] = '९'; + map!['ninegujarati'] = '૯'; + map!['ninegurmukhi'] = '੯'; + map!['ninehackarabic'] = '٩'; + map!['ninehangzhou'] = '〩'; + map!['nineideographicparen'] = '㈨'; + map!['nineinferior'] = '₉'; + map!['ninemonospace'] = '9'; + map!['nineoldstyle'] = ''; + map!['nineparen'] = '⑼'; + map!['nineperiod'] = '⒐'; + map!['ninepersian'] = '۹'; + map!['nineroman'] = 'ⅸ'; + map!['ninesuperior'] = '⁹'; + map!['nineteencircle'] = '⑲'; + map!['nineteenparen'] = '⒆'; + map!['nineteenperiod'] = '⒚'; + map!['ninethai'] = '๙'; + map!['nj'] = 'nj'; + map!['njecyrillic'] = 'њ'; + map!['nkatakana'] = 'ン'; + map!['nkatakanahalfwidth'] = 'ン'; + map!['nlegrightlong'] = 'ƞ'; + map!['nlinebelow'] = 'ṉ'; + map!['nmonospace'] = 'n'; + map!['nmsquare'] = '㎚'; + map!['nnabengali'] = 'ণ'; + map!['nnadeva'] = 'ण'; + map!['nnagujarati'] = 'ણ'; + map!['nnagurmukhi'] = 'ਣ'; + map!['nnnadeva'] = 'ऩ'; + map!['nohiragana'] = 'の'; + map!['nokatakana'] = 'ノ'; + map!['nokatakanahalfwidth'] = 'ノ'; + map!['nonbreakingspace'] = '\u00a0'; + map!['nonenthai'] = 'ณ'; + map!['nonuthai'] = 'น'; + map!['noonarabic'] = 'ن'; + map!['noonfinalarabic'] = 'ﻦ'; + map!['noonghunnaarabic'] = 'ں'; + map!['noonghunnafinalarabic'] = 'ﮟ'; + map!['nooninitialarabic'] = 'ﻧ'; + map!['noonjeeminitialarabic'] = 'ﳒ'; + map!['noonjeemisolatedarabic'] = 'ﱋ'; + map!['noonmedialarabic'] = 'ﻨ'; + map!['noonmeeminitialarabic'] = 'ﳕ'; + map!['noonmeemisolatedarabic'] = 'ﱎ'; + map!['noonnoonfinalarabic'] = 'ﲍ'; + map!['notcontains'] = '∌'; + map!['notelement'] = '∉'; + map!['notelementof'] = '∉'; + map!['notequal'] = '≠'; + map!['notgreater'] = '≯'; + map!['notgreaternorequal'] = '≱'; + map!['notgreaternorless'] = '≹'; + map!['notidentical'] = '≢'; + map!['notless'] = '≮'; + map!['notlessnorequal'] = '≰'; + map!['notparallel'] = '∦'; + map!['notprecedes'] = '⊀'; + map!['notsubset'] = '⊄'; + map!['notsucceeds'] = '⊁'; + map!['notsuperset'] = '⊅'; + map!['nowarmenian'] = 'ն'; + map!['nparen'] = '⒩'; + map!['nssquare'] = '㎱'; + map!['nsuperior'] = 'ⁿ'; + map!['ntilde'] = 'ñ'; + map!['nu'] = 'ν'; + map!['nuhiragana'] = 'ぬ'; + map!['nukatakana'] = 'ヌ'; + map!['nukatakanahalfwidth'] = 'ヌ'; + map!['nuktabengali'] = '়'; + map!['nuktadeva'] = '़'; + map!['nuktagujarati'] = '઼'; + map!['nuktagurmukhi'] = '਼'; + map!['numbersign'] = '#'; + map!['numbersignmonospace'] = '#'; + map!['numbersignsmall'] = '﹟'; + map!['numeralsigngreek'] = 'ʹ'; + map!['numeralsignlowergreek'] = '͵'; + map!['numero'] = '№'; + map!['nun'] = 'נ'; + map!['nundagesh'] = 'נּ'; + map!['nundageshhebrew'] = 'נּ'; + map!['nunhebrew'] = 'נ'; + map!['nvsquare'] = '㎵'; + map!['nwsquare'] = '㎻'; + map!['nyabengali'] = 'ঞ'; + map!['nyadeva'] = 'ञ'; + map!['nyagujarati'] = 'ઞ'; + map!['nyagurmukhi'] = 'ਞ'; + map!['o'] = 'o'; + map!['oacute'] = 'ó'; + map!['oangthai'] = 'อ'; + map!['obarred'] = 'ɵ'; + map!['obarredcyrillic'] = 'ө'; + map!['obarreddieresiscyrillic'] = 'ӫ'; + map!['obengali'] = 'ও'; + map!['obopomofo'] = 'ㄛ'; + map!['obreve'] = 'ŏ'; + map!['ocandradeva'] = 'ऑ'; + map!['ocandragujarati'] = 'ઑ'; + map!['ocandravowelsigndeva'] = 'ॉ'; + map!['ocandravowelsigngujarati'] = 'ૉ'; + map!['ocaron'] = 'ǒ'; + map!['ocircle'] = 'ⓞ'; + map!['ocircumflex'] = 'ô'; + map!['ocircumflexacute'] = 'ố'; + map!['ocircumflexdotbelow'] = 'ộ'; + map!['ocircumflexgrave'] = 'ồ'; + map!['ocircumflexhookabove'] = 'ổ'; + map!['ocircumflextilde'] = 'ỗ'; + map!['ocyrillic'] = 'о'; + map!['odblacute'] = 'ő'; + map!['odblgrave'] = 'ȍ'; + map!['odeva'] = 'ओ'; + map!['odieresis'] = 'ö'; + map!['odieresiscyrillic'] = 'ӧ'; + map!['odotbelow'] = 'ọ'; + map!['oe'] = 'œ'; + map!['oekorean'] = 'ㅚ'; + map!['ogonek'] = '˛'; + map!['ogonekcmb'] = '̨'; + map!['ograve'] = 'ò'; + map!['ogujarati'] = 'ઓ'; + map!['oharmenian'] = 'օ'; + map!['ohiragana'] = 'お'; + map!['ohookabove'] = 'ỏ'; + map!['ohorn'] = 'ơ'; + map!['ohornacute'] = 'ớ'; + map!['ohorndotbelow'] = 'ợ'; + map!['ohorngrave'] = 'ờ'; + map!['ohornhookabove'] = 'ở'; + map!['ohorntilde'] = 'ỡ'; + map!['ohungarumlaut'] = 'ő'; + map!['oi'] = 'ƣ'; + map!['oinvertedbreve'] = 'ȏ'; + map!['okatakana'] = 'オ'; + map!['okatakanahalfwidth'] = 'オ'; + map!['okorean'] = 'ㅗ'; + map!['olehebrew'] = '֫'; + map!['omacron'] = 'ō'; + map!['omacronacute'] = 'ṓ'; + map!['omacrongrave'] = 'ṑ'; + map!['omdeva'] = 'ॐ'; + map!['omega'] = 'ω'; + map!['omega1'] = 'ϖ'; + map!['omegacyrillic'] = 'ѡ'; + map!['omegalatinclosed'] = 'ɷ'; + map!['omegaroundcyrillic'] = 'ѻ'; + map!['omegatitlocyrillic'] = 'ѽ'; + map!['omegatonos'] = 'ώ'; + map!['omgujarati'] = 'ૐ'; + map!['omicron'] = 'ο'; + map!['omicrontonos'] = 'ό'; + map!['omonospace'] = 'o'; + map!['one'] = '1'; + map!['onearabic'] = '١'; + map!['onebengali'] = '১'; + map!['onecircle'] = '①'; + map!['onecircleinversesansserif'] = '➊'; + map!['onedeva'] = '१'; + map!['onedotenleader'] = '․'; + map!['oneeighth'] = '⅛'; + map!['onefitted'] = ''; + map!['onegujarati'] = '૧'; + map!['onegurmukhi'] = '੧'; + map!['onehackarabic'] = '١'; + map!['onehalf'] = '½'; + map!['onehangzhou'] = '〡'; + map!['oneideographicparen'] = '㈠'; + map!['oneinferior'] = '₁'; + map!['onemonospace'] = '1'; + map!['onenumeratorbengali'] = '৴'; + map!['oneoldstyle'] = ''; + map!['oneparen'] = '⑴'; + map!['oneperiod'] = '⒈'; + map!['onepersian'] = '۱'; + map!['onequarter'] = '¼'; + map!['oneroman'] = 'ⅰ'; + map!['onesuperior'] = '¹'; + map!['onethai'] = '๑'; + map!['onethird'] = '⅓'; + map!['oogonek'] = 'ǫ'; + map!['oogonekmacron'] = 'ǭ'; + map!['oogurmukhi'] = 'ਓ'; + map!['oomatragurmukhi'] = 'ੋ'; + map!['oopen'] = 'ɔ'; + map!['oparen'] = '⒪'; + map!['openbullet'] = '◦'; + map!['option'] = '⌥'; + map!['ordfeminine'] = 'ª'; + map!['ordmasculine'] = 'º'; + map!['orthogonal'] = '∟'; + map!['oshortdeva'] = 'ऒ'; + map!['oshortvowelsigndeva'] = 'ॊ'; + map!['oslash'] = 'ø'; + map!['oslashacute'] = 'ǿ'; + map!['osmallhiragana'] = 'ぉ'; + map!['osmallkatakana'] = 'ォ'; + map!['osmallkatakanahalfwidth'] = 'ォ'; + map!['ostrokeacute'] = 'ǿ'; + map!['osuperior'] = ''; + map!['otcyrillic'] = 'ѿ'; + map!['otilde'] = 'õ'; + map!['otildeacute'] = 'ṍ'; + map!['otildedieresis'] = 'ṏ'; + map!['oubopomofo'] = 'ㄡ'; + map!['overline'] = '‾'; + map!['overlinecenterline'] = '﹊'; + map!['overlinecmb'] = '̅'; + map!['overlinedashed'] = '﹉'; + map!['overlinedblwavy'] = '﹌'; + map!['overlinewavy'] = '﹋'; + map!['overscore'] = '¯'; + map!['ovowelsignbengali'] = 'ো'; + map!['ovowelsigndeva'] = 'ो'; + map!['ovowelsigngujarati'] = 'ો'; + map!['p'] = 'p'; + map!['paampssquare'] = '㎀'; + map!['paasentosquare'] = '㌫'; + map!['pabengali'] = 'প'; + map!['pacute'] = 'ṕ'; + map!['padeva'] = 'प'; + map!['pagedown'] = '⇟'; + map!['pageup'] = '⇞'; + map!['pagujarati'] = 'પ'; + map!['pagurmukhi'] = 'ਪ'; + map!['pahiragana'] = 'ぱ'; + map!['paiyannoithai'] = 'ฯ'; + map!['pakatakana'] = 'パ'; + map!['palatalizationcyrilliccmb'] = '҄'; + map!['palochkacyrillic'] = 'Ӏ'; + map!['pansioskorean'] = 'ㅿ'; + map!['paragraph'] = '¶'; + map!['parallel'] = '∥'; + map!['parenleft'] = '('; + map!['parenleftaltonearabic'] = '﴾'; + map!['parenleftbt'] = ''; + map!['parenleftex'] = ''; + map!['parenleftinferior'] = '₍'; + map!['parenleftmonospace'] = '('; + map!['parenleftsmall'] = '﹙'; + map!['parenleftsuperior'] = '⁽'; + map!['parenlefttp'] = ''; + map!['parenleftvertical'] = '︵'; + map!['parenright'] = ')'; + map!['parenrightaltonearabic'] = '﴿'; + map!['parenrightbt'] = ''; + map!['parenrightex'] = ''; + map!['parenrightinferior'] = '₎'; + map!['parenrightmonospace'] = ')'; + map!['parenrightsmall'] = '﹚'; + map!['parenrightsuperior'] = '⁾'; + map!['parenrighttp'] = ''; + map!['parenrightvertical'] = '︶'; + map!['partialdiff'] = '∂'; + map!['paseqhebrew'] = '׀'; + map!['pashtahebrew'] = '֙'; + map!['pasquare'] = '㎩'; + map!['patah'] = 'ַ'; + map!['patah11'] = 'ַ'; + map!['patah1d'] = 'ַ'; + map!['patah2a'] = 'ַ'; + map!['patahhebrew'] = 'ַ'; + map!['patahnarrowhebrew'] = 'ַ'; + map!['patahquarterhebrew'] = 'ַ'; + map!['patahwidehebrew'] = 'ַ'; + map!['pazerhebrew'] = '֡'; + map!['pbopomofo'] = 'ㄆ'; + map!['pcircle'] = 'ⓟ'; + map!['pdotaccent'] = 'ṗ'; + map!['pe'] = 'פ'; + map!['pecyrillic'] = 'п'; + map!['pedagesh'] = 'פּ'; + map!['pedageshhebrew'] = 'פּ'; + map!['peezisquare'] = '㌻'; + map!['pefinaldageshhebrew'] = 'ףּ'; + map!['peharabic'] = 'پ'; + map!['peharmenian'] = 'պ'; + map!['pehebrew'] = 'פ'; + map!['pehfinalarabic'] = 'ﭗ'; + map!['pehinitialarabic'] = 'ﭘ'; + map!['pehiragana'] = 'ぺ'; + map!['pehmedialarabic'] = 'ﭙ'; + map!['pekatakana'] = 'ペ'; + map!['pemiddlehookcyrillic'] = 'ҧ'; + map!['perafehebrew'] = 'פֿ'; + map!['percent'] = '%'; + map!['percentarabic'] = '٪'; + map!['percentmonospace'] = '%'; + map!['percentsmall'] = '﹪'; + map!['period'] = '.'; + map!['periodarmenian'] = '։'; + map!['periodcentered'] = '·'; + map!['periodhalfwidth'] = '。'; + map!['periodinferior'] = ''; + map!['periodmonospace'] = '.'; + map!['periodsmall'] = '﹒'; + map!['periodsuperior'] = ''; + map!['perispomenigreekcmb'] = '͂'; + map!['perpendicular'] = '⊥'; + map!['perthousand'] = '‰'; + map!['peseta'] = '₧'; + map!['pfsquare'] = '㎊'; + map!['phabengali'] = 'ফ'; + map!['phadeva'] = 'फ'; + map!['phagujarati'] = 'ફ'; + map!['phagurmukhi'] = 'ਫ'; + map!['phi'] = 'φ'; + map!['phi1'] = 'ϕ'; + map!['phieuphacirclekorean'] = '㉺'; + map!['phieuphaparenkorean'] = '㈚'; + map!['phieuphcirclekorean'] = '㉬'; + map!['phieuphkorean'] = 'ㅍ'; + map!['phieuphparenkorean'] = '㈌'; + map!['philatin'] = 'ɸ'; + map!['phinthuthai'] = 'ฺ'; + map!['phisymbolgreek'] = 'ϕ'; + map!['phook'] = 'ƥ'; + map!['phophanthai'] = 'พ'; + map!['phophungthai'] = 'ผ'; + map!['phosamphaothai'] = 'ภ'; + map!['pi'] = 'π'; + map!['pieupacirclekorean'] = '㉳'; + map!['pieupaparenkorean'] = '㈓'; + map!['pieupcieuckorean'] = 'ㅶ'; + map!['pieupcirclekorean'] = '㉥'; + map!['pieupkiyeokkorean'] = 'ㅲ'; + map!['pieupkorean'] = 'ㅂ'; + map!['pieupparenkorean'] = '㈅'; + map!['pieupsioskiyeokkorean'] = 'ㅴ'; + map!['pieupsioskorean'] = 'ㅄ'; + map!['pieupsiostikeutkorean'] = 'ㅵ'; + map!['pieupthieuthkorean'] = 'ㅷ'; + map!['pieuptikeutkorean'] = 'ㅳ'; + map!['pihiragana'] = 'ぴ'; + map!['pikatakana'] = 'ピ'; + map!['pisymbolgreek'] = 'ϖ'; + map!['piwrarmenian'] = 'փ'; + map!['plus'] = '+'; + map!['plusbelowcmb'] = '̟'; + map!['pluscircle'] = '⊕'; + map!['plusminus'] = '±'; + map!['plusmod'] = '˖'; + map!['plusmonospace'] = '+'; + map!['plussmall'] = '﹢'; + map!['plussuperior'] = '⁺'; + map!['pmonospace'] = 'p'; + map!['pmsquare'] = '㏘'; + map!['pohiragana'] = 'ぽ'; + map!['pointingindexdownwhite'] = '☟'; + map!['pointingindexleftwhite'] = '☜'; + map!['pointingindexrightwhite'] = '☞'; + map!['pointingindexupwhite'] = '☝'; + map!['pokatakana'] = 'ポ'; + map!['poplathai'] = 'ป'; + map!['postalmark'] = '〒'; + map!['postalmarkface'] = '〠'; + map!['pparen'] = '⒫'; + map!['precedes'] = '≺'; + map!['prescription'] = '℞'; + map!['primemod'] = 'ʹ'; + map!['primereversed'] = '‵'; + map!['product'] = '∏'; + map!['projective'] = '⌅'; + map!['prolongedkana'] = 'ー'; + map!['propellor'] = '⌘'; + map!['propersubset'] = '⊂'; + map!['propersuperset'] = '⊃'; + map!['proportion'] = '∷'; + map!['proportional'] = '∝'; + map!['psi'] = 'ψ'; + map!['psicyrillic'] = 'ѱ'; + map!['psilipneumatacyrilliccmb'] = '҆'; + map!['pssquare'] = '㎰'; + map!['puhiragana'] = 'ぷ'; + map!['pukatakana'] = 'プ'; + map!['pvsquare'] = '㎴'; + map!['pwsquare'] = '㎺'; + map!['q'] = 'q'; + map!['qadeva'] = 'क़'; + map!['qadmahebrew'] = '֨'; + map!['qafarabic'] = 'ق'; + map!['qaffinalarabic'] = 'ﻖ'; + map!['qafinitialarabic'] = 'ﻗ'; + map!['qafmedialarabic'] = 'ﻘ'; + map!['qamats'] = 'ָ'; + map!['qamats10'] = 'ָ'; + map!['qamats1a'] = 'ָ'; + map!['qamats1c'] = 'ָ'; + map!['qamats27'] = 'ָ'; + map!['qamats29'] = 'ָ'; + map!['qamats33'] = 'ָ'; + map!['qamatsde'] = 'ָ'; + map!['qamatshebrew'] = 'ָ'; + map!['qamatsnarrowhebrew'] = 'ָ'; + map!['qamatsqatanhebrew'] = 'ָ'; + map!['qamatsqatannarrowhebrew'] = 'ָ'; + map!['qamatsqatanquarterhebrew'] = 'ָ'; + map!['qamatsqatanwidehebrew'] = 'ָ'; + map!['qamatsquarterhebrew'] = 'ָ'; + map!['qamatswidehebrew'] = 'ָ'; + map!['qarneyparahebrew'] = '֟'; + map!['qbopomofo'] = 'ㄑ'; + map!['qcircle'] = 'ⓠ'; + map!['qhook'] = 'ʠ'; + map!['qmonospace'] = 'q'; + map!['qof'] = 'ק'; + map!['qofdagesh'] = 'קּ'; + map!['qofdageshhebrew'] = 'קּ'; + map!['qparen'] = '⒬'; + map!['quarternote'] = '♩'; + map!['qubuts'] = 'ֻ'; + map!['qubuts18'] = 'ֻ'; + map!['qubuts25'] = 'ֻ'; + map!['qubuts31'] = 'ֻ'; + map!['qubutshebrew'] = 'ֻ'; + map!['qubutsnarrowhebrew'] = 'ֻ'; + map!['qubutsquarterhebrew'] = 'ֻ'; + map!['qubutswidehebrew'] = 'ֻ'; + map!['question'] = '?'; + map!['questionarabic'] = '؟'; + map!['questionarmenian'] = '՞'; + map!['questiondown'] = '¿'; + map!['questiondownsmall'] = ''; + map!['questiongreek'] = ';'; + map!['questionmonospace'] = '?'; + map!['questionsmall'] = ''; + map!['quotedbl'] = '"'; + map!['quotedblbase'] = '„'; + map!['quotedblleft'] = '“'; + map!['quotedblmonospace'] = '"'; + map!['quotedblprime'] = '〞'; + map!['quotedblprimereversed'] = '〝'; + map!['quotedblright'] = '”'; + map!['quoteleft'] = '‘'; + map!['quoteleftreversed'] = '‛'; + map!['quotereversed'] = '‛'; + map!['quoteright'] = '’'; + map!['quoterightn'] = 'ʼn'; + map!['quotesinglbase'] = '‚'; + map!['quotesingle'] = "'"; + map!['quotesinglemonospace'] = '''; + map!['r'] = 'r'; + map!['raarmenian'] = 'ռ'; + map!['rabengali'] = 'র'; + map!['racute'] = 'ŕ'; + map!['radeva'] = 'र'; + map!['radical'] = '√'; + map!['radicalex'] = ''; + map!['radoverssquare'] = '㎮'; + map!['radoverssquaredsquare'] = '㎯'; + map!['radsquare'] = '㎭'; + map!['rafe'] = 'ֿ'; + map!['rafehebrew'] = 'ֿ'; + map!['ragujarati'] = 'ર'; + map!['ragurmukhi'] = 'ਰ'; + map!['rahiragana'] = 'ら'; + map!['rakatakana'] = 'ラ'; + map!['rakatakanahalfwidth'] = 'ラ'; + map!['ralowerdiagonalbengali'] = 'ৱ'; + map!['ramiddlediagonalbengali'] = 'ৰ'; + map!['ramshorn'] = 'ɤ'; + map!['ratio'] = '∶'; + map!['rbopomofo'] = 'ㄖ'; + map!['rcaron'] = 'ř'; + map!['rcedilla'] = 'ŗ'; + map!['rcircle'] = 'ⓡ'; + map!['rcommaaccent'] = 'ŗ'; + map!['rdblgrave'] = 'ȑ'; + map!['rdotaccent'] = 'ṙ'; + map!['rdotbelow'] = 'ṛ'; + map!['rdotbelowmacron'] = 'ṝ'; + map!['referencemark'] = '※'; + map!['reflexsubset'] = '⊆'; + map!['reflexsuperset'] = '⊇'; + map!['registered'] = '®'; + map!['registersans'] = ''; + map!['registerserif'] = ''; + map!['reharabic'] = 'ر'; + map!['reharmenian'] = 'ր'; + map!['rehfinalarabic'] = 'ﺮ'; + map!['rehiragana'] = 'れ'; + map!['rekatakana'] = 'レ'; + map!['rekatakanahalfwidth'] = 'レ'; + map!['resh'] = 'ר'; + map!['reshdageshhebrew'] = 'רּ'; + map!['reshhebrew'] = 'ר'; + map!['reversedtilde'] = '∽'; + map!['reviahebrew'] = '֗'; + map!['reviamugrashhebrew'] = '֗'; + map!['revlogicalnot'] = '⌐'; + map!['rfishhook'] = 'ɾ'; + map!['rfishhookreversed'] = 'ɿ'; + map!['rhabengali'] = 'ঢ়'; + map!['rhadeva'] = 'ढ़'; + map!['rho'] = 'ρ'; + map!['rhook'] = 'ɽ'; + map!['rhookturned'] = 'ɻ'; + map!['rhookturnedsuperior'] = 'ʵ'; + map!['rhosymbolgreek'] = 'ϱ'; + map!['rhotichookmod'] = '˞'; + map!['rieulacirclekorean'] = '㉱'; + map!['rieulaparenkorean'] = '㈑'; + map!['rieulcirclekorean'] = '㉣'; + map!['rieulhieuhkorean'] = 'ㅀ'; + map!['rieulkiyeokkorean'] = 'ㄺ'; + map!['rieulkiyeoksioskorean'] = 'ㅩ'; + map!['rieulkorean'] = 'ㄹ'; + map!['rieulmieumkorean'] = 'ㄻ'; + map!['rieulpansioskorean'] = 'ㅬ'; + map!['rieulparenkorean'] = '㈃'; + map!['rieulphieuphkorean'] = 'ㄿ'; + map!['rieulpieupkorean'] = 'ㄼ'; + map!['rieulpieupsioskorean'] = 'ㅫ'; + map!['rieulsioskorean'] = 'ㄽ'; + map!['rieulthieuthkorean'] = 'ㄾ'; + map!['rieultikeutkorean'] = 'ㅪ'; + map!['rieulyeorinhieuhkorean'] = 'ㅭ'; + map!['rightangle'] = '∟'; + map!['righttackbelowcmb'] = '̙'; + map!['righttriangle'] = '⊿'; + map!['rihiragana'] = 'り'; + map!['rikatakana'] = 'リ'; + map!['rikatakanahalfwidth'] = 'リ'; + map!['ring'] = '˚'; + map!['ringbelowcmb'] = '̥'; + map!['ringcmb'] = '̊'; + map!['ringhalfleft'] = 'ʿ'; + map!['ringhalfleftarmenian'] = 'ՙ'; + map!['ringhalfleftbelowcmb'] = '̜'; + map!['ringhalfleftcentered'] = '˓'; + map!['ringhalfright'] = 'ʾ'; + map!['ringhalfrightbelowcmb'] = '̹'; + map!['ringhalfrightcentered'] = '˒'; + map!['rinvertedbreve'] = 'ȓ'; + map!['rittorusquare'] = '㍑'; + map!['rlinebelow'] = 'ṟ'; + map!['rlongleg'] = 'ɼ'; + map!['rlonglegturned'] = 'ɺ'; + map!['rmonospace'] = 'r'; + map!['rohiragana'] = 'ろ'; + map!['rokatakana'] = 'ロ'; + map!['rokatakanahalfwidth'] = 'ロ'; + map!['roruathai'] = 'ร'; + map!['rparen'] = '⒭'; + map!['rrabengali'] = 'ড়'; + map!['rradeva'] = 'ऱ'; + map!['rragurmukhi'] = 'ੜ'; + map!['rreharabic'] = 'ڑ'; + map!['rrehfinalarabic'] = 'ﮍ'; + map!['rrvocalicbengali'] = 'ৠ'; + map!['rrvocalicdeva'] = 'ॠ'; + map!['rrvocalicgujarati'] = 'ૠ'; + map!['rrvocalicvowelsignbengali'] = 'ৄ'; + map!['rrvocalicvowelsigndeva'] = 'ॄ'; + map!['rrvocalicvowelsigngujarati'] = 'ૄ'; + map!['rsuperior'] = ''; + map!['rtblock'] = '▐'; + map!['rturned'] = 'ɹ'; + map!['rturnedsuperior'] = 'ʴ'; + map!['ruhiragana'] = 'る'; + map!['rukatakana'] = 'ル'; + map!['rukatakanahalfwidth'] = 'ル'; + map!['rupeemarkbengali'] = '৲'; + map!['rupeesignbengali'] = '৳'; + map!['rupiah'] = ''; + map!['ruthai'] = 'ฤ'; + map!['rvocalicbengali'] = 'ঋ'; + map!['rvocalicdeva'] = 'ऋ'; + map!['rvocalicgujarati'] = 'ઋ'; + map!['rvocalicvowelsignbengali'] = 'ৃ'; + map!['rvocalicvowelsigndeva'] = 'ृ'; + map!['rvocalicvowelsigngujarati'] = 'ૃ'; + map!['s'] = 's'; + map!['sabengali'] = 'স'; + map!['sacute'] = 'ś'; + map!['sacutedotaccent'] = 'ṥ'; + map!['sadarabic'] = 'ص'; + map!['sadeva'] = 'स'; + map!['sadfinalarabic'] = 'ﺺ'; + map!['sadinitialarabic'] = 'ﺻ'; + map!['sadmedialarabic'] = 'ﺼ'; + map!['sagujarati'] = 'સ'; + map!['sagurmukhi'] = 'ਸ'; + map!['sahiragana'] = 'さ'; + map!['sakatakana'] = 'サ'; + map!['sakatakanahalfwidth'] = 'サ'; + map!['sallallahoualayhewasallamarabic'] = 'ﷺ'; + map!['samekh'] = 'ס'; + map!['samekhdagesh'] = 'סּ'; + map!['samekhdageshhebrew'] = 'סּ'; + map!['samekhhebrew'] = 'ס'; + map!['saraaathai'] = 'า'; + map!['saraaethai'] = 'แ'; + map!['saraaimaimalaithai'] = 'ไ'; + map!['saraaimaimuanthai'] = 'ใ'; + map!['saraamthai'] = 'ำ'; + map!['saraathai'] = 'ะ'; + map!['saraethai'] = 'เ'; + map!['saraiileftthai'] = ''; + map!['saraiithai'] = 'ี'; + map!['saraileftthai'] = ''; + map!['saraithai'] = 'ิ'; + map!['saraothai'] = 'โ'; + map!['saraueeleftthai'] = ''; + map!['saraueethai'] = 'ื'; + map!['saraueleftthai'] = ''; + map!['sarauethai'] = 'ึ'; + map!['sarauthai'] = 'ุ'; + map!['sarauuthai'] = 'ู'; + map!['sbopomofo'] = 'ㄙ'; + map!['scaron'] = 'š'; + map!['scarondotaccent'] = 'ṧ'; + map!['scedilla'] = 'ş'; + map!['schwa'] = 'ə'; + map!['schwacyrillic'] = 'ә'; + map!['schwadieresiscyrillic'] = 'ӛ'; + map!['schwahook'] = 'ɚ'; + map!['scircle'] = 'ⓢ'; + map!['scircumflex'] = 'ŝ'; + map!['scommaaccent'] = 'ș'; + map!['sdotaccent'] = 'ṡ'; + map!['sdotbelow'] = 'ṣ'; + map!['sdotbelowdotaccent'] = 'ṩ'; + map!['seagullbelowcmb'] = '̼'; + map!['second'] = '″'; + map!['secondtonechinese'] = 'ˊ'; + map!['section'] = '§'; + map!['seenarabic'] = 'س'; + map!['seenfinalarabic'] = 'ﺲ'; + map!['seeninitialarabic'] = 'ﺳ'; + map!['seenmedialarabic'] = 'ﺴ'; + map!['segol'] = 'ֶ'; + map!['segol13'] = 'ֶ'; + map!['segol1f'] = 'ֶ'; + map!['segol2c'] = 'ֶ'; + map!['segolhebrew'] = 'ֶ'; + map!['segolnarrowhebrew'] = 'ֶ'; + map!['segolquarterhebrew'] = 'ֶ'; + map!['segoltahebrew'] = '֒'; + map!['segolwidehebrew'] = 'ֶ'; + map!['seharmenian'] = 'ս'; + map!['sehiragana'] = 'せ'; + map!['sekatakana'] = 'セ'; + map!['sekatakanahalfwidth'] = 'セ'; + map!['semicolon'] = ';'; + map!['semicolonarabic'] = '؛'; + map!['semicolonmonospace'] = ';'; + map!['semicolonsmall'] = '﹔'; + map!['semivoicedmarkkana'] = '゜'; + map!['semivoicedmarkkanahalfwidth'] = '゚'; + map!['sentisquare'] = '㌢'; + map!['sentosquare'] = '㌣'; + map!['seven'] = '7'; + map!['sevenarabic'] = '٧'; + map!['sevenbengali'] = '৭'; + map!['sevencircle'] = '⑦'; + map!['sevencircleinversesansserif'] = '➐'; + map!['sevendeva'] = '७'; + map!['seveneighths'] = '⅞'; + map!['sevengujarati'] = '૭'; + map!['sevengurmukhi'] = '੭'; + map!['sevenhackarabic'] = '٧'; + map!['sevenhangzhou'] = '〧'; + map!['sevenideographicparen'] = '㈦'; + map!['seveninferior'] = '₇'; + map!['sevenmonospace'] = '7'; + map!['sevenoldstyle'] = ''; + map!['sevenparen'] = '⑺'; + map!['sevenperiod'] = '⒎'; + map!['sevenpersian'] = '۷'; + map!['sevenroman'] = 'ⅶ'; + map!['sevensuperior'] = '⁷'; + map!['seventeencircle'] = '⑰'; + map!['seventeenparen'] = '⒄'; + map!['seventeenperiod'] = '⒘'; + map!['seventhai'] = '๗'; + map!['sfthyphen'] = '­'; + map!['shaarmenian'] = 'շ'; + map!['shabengali'] = 'শ'; + map!['shacyrillic'] = 'ш'; + map!['shaddaarabic'] = 'ّ'; + map!['shaddadammaarabic'] = 'ﱡ'; + map!['shaddadammatanarabic'] = 'ﱞ'; + map!['shaddafathaarabic'] = 'ﱠ'; + map!['shaddakasraarabic'] = 'ﱢ'; + map!['shaddakasratanarabic'] = 'ﱟ'; + map!['shade'] = '▒'; + map!['shadedark'] = '▓'; + map!['shadelight'] = '░'; + map!['shademedium'] = '▒'; + map!['shadeva'] = 'श'; + map!['shagujarati'] = 'શ'; + map!['shagurmukhi'] = 'ਸ਼'; + map!['shalshelethebrew'] = '֓'; + map!['shbopomofo'] = 'ㄕ'; + map!['shchacyrillic'] = 'щ'; + map!['sheenarabic'] = 'ش'; + map!['sheenfinalarabic'] = 'ﺶ'; + map!['sheeninitialarabic'] = 'ﺷ'; + map!['sheenmedialarabic'] = 'ﺸ'; + map!['sheicoptic'] = 'ϣ'; + map!['sheqel'] = '₪'; + map!['sheqelhebrew'] = '₪'; + map!['sheva'] = 'ְ'; + map!['sheva115'] = 'ְ'; + map!['sheva15'] = 'ְ'; + map!['sheva22'] = 'ְ'; + map!['sheva2e'] = 'ְ'; + map!['shevahebrew'] = 'ְ'; + map!['shevanarrowhebrew'] = 'ְ'; + map!['shevaquarterhebrew'] = 'ְ'; + map!['shevawidehebrew'] = 'ְ'; + map!['shhacyrillic'] = 'һ'; + map!['shimacoptic'] = 'ϭ'; + map!['shin'] = 'ש'; + map!['shindagesh'] = 'שּ'; + map!['shindageshhebrew'] = 'שּ'; + map!['shindageshshindot'] = 'שּׁ'; + map!['shindageshshindothebrew'] = 'שּׁ'; + map!['shindageshsindot'] = 'שּׂ'; + map!['shindageshsindothebrew'] = 'שּׂ'; + map!['shindothebrew'] = 'ׁ'; + map!['shinhebrew'] = 'ש'; + map!['shinshindot'] = 'שׁ'; + map!['shinshindothebrew'] = 'שׁ'; + map!['shinsindot'] = 'שׂ'; + map!['shinsindothebrew'] = 'שׂ'; + map!['shook'] = 'ʂ'; + map!['sigma'] = 'σ'; + map!['sigma1'] = 'ς'; + map!['sigmafinal'] = 'ς'; + map!['sigmalunatesymbolgreek'] = 'ϲ'; + map!['sihiragana'] = 'し'; + map!['sikatakana'] = 'シ'; + map!['sikatakanahalfwidth'] = 'シ'; + map!['siluqhebrew'] = 'ֽ'; + map!['siluqlefthebrew'] = 'ֽ'; + map!['similar'] = '∼'; + map!['sindothebrew'] = 'ׂ'; + map!['siosacirclekorean'] = '㉴'; + map!['siosaparenkorean'] = '㈔'; + map!['sioscieuckorean'] = 'ㅾ'; + map!['sioscirclekorean'] = '㉦'; + map!['sioskiyeokkorean'] = 'ㅺ'; + map!['sioskorean'] = 'ㅅ'; + map!['siosnieunkorean'] = 'ㅻ'; + map!['siosparenkorean'] = '㈆'; + map!['siospieupkorean'] = 'ㅽ'; + map!['siostikeutkorean'] = 'ㅼ'; + map!['six'] = '6'; + map!['sixarabic'] = '٦'; + map!['sixbengali'] = '৬'; + map!['sixcircle'] = '⑥'; + map!['sixcircleinversesansserif'] = '➏'; + map!['sixdeva'] = '६'; + map!['sixgujarati'] = '૬'; + map!['sixgurmukhi'] = '੬'; + map!['sixhackarabic'] = '٦'; + map!['sixhangzhou'] = '〦'; + map!['sixideographicparen'] = '㈥'; + map!['sixinferior'] = '₆'; + map!['sixmonospace'] = '6'; + map!['sixoldstyle'] = ''; + map!['sixparen'] = '⑹'; + map!['sixperiod'] = '⒍'; + map!['sixpersian'] = '۶'; + map!['sixroman'] = 'ⅵ'; + map!['sixsuperior'] = '⁶'; + map!['sixteencircle'] = '⑯'; + map!['sixteencurrencydenominatorbengali'] = '৹'; + map!['sixteenparen'] = '⒃'; + map!['sixteenperiod'] = '⒗'; + map!['sixthai'] = '๖'; + map!['slash'] = '/'; + map!['slashmonospace'] = '/'; + map!['slong'] = 'ſ'; + map!['slongdotaccent'] = 'ẛ'; + map!['smileface'] = '☺'; + map!['smonospace'] = 's'; + map!['sofpasuqhebrew'] = '׃'; + map!['softhyphen'] = '­'; + map!['softsigncyrillic'] = 'ь'; + map!['sohiragana'] = 'そ'; + map!['sokatakana'] = 'ソ'; + map!['sokatakanahalfwidth'] = 'ソ'; + map!['soliduslongoverlaycmb'] = '̸'; + map!['solidusshortoverlaycmb'] = '̷'; + map!['sorusithai'] = 'ษ'; + map!['sosalathai'] = 'ศ'; + map!['sosothai'] = 'ซ'; + map!['sosuathai'] = 'ส'; + map!['space'] = ' '; + map!['spacehackarabic'] = ' '; + map!['spade'] = '♠'; + map!['spadesuitblack'] = '♠'; + map!['spadesuitwhite'] = '♤'; + map!['sparen'] = '⒮'; + map!['squarebelowcmb'] = '̻'; + map!['squarecc'] = '㏄'; + map!['squarecm'] = '㎝'; + map!['squarediagonalcrosshatchfill'] = '▩'; + map!['squarehorizontalfill'] = '▤'; + map!['squarekg'] = '㎏'; + map!['squarekm'] = '㎞'; + map!['squarekmcapital'] = '㏎'; + map!['squareln'] = '㏑'; + map!['squarelog'] = '㏒'; + map!['squaremg'] = '㎎'; + map!['squaremil'] = '㏕'; + map!['squaremm'] = '㎜'; + map!['squaremsquared'] = '㎡'; + map!['squareorthogonalcrosshatchfill'] = '▦'; + map!['squareupperlefttolowerrightfill'] = '▧'; + map!['squareupperrighttolowerleftfill'] = '▨'; + map!['squareverticalfill'] = '▥'; + map!['squarewhitewithsmallblack'] = '▣'; + map!['srsquare'] = '㏛'; + map!['ssabengali'] = 'ষ'; + map!['ssadeva'] = 'ष'; + map!['ssagujarati'] = 'ષ'; + map!['ssangcieuckorean'] = 'ㅉ'; + map!['ssanghieuhkorean'] = 'ㆅ'; + map!['ssangieungkorean'] = 'ㆀ'; + map!['ssangkiyeokkorean'] = 'ㄲ'; + map!['ssangnieunkorean'] = 'ㅥ'; + map!['ssangpieupkorean'] = 'ㅃ'; + map!['ssangsioskorean'] = 'ㅆ'; + map!['ssangtikeutkorean'] = 'ㄸ'; + map!['ssuperior'] = ''; + map!['sterling'] = '£'; + map!['sterlingmonospace'] = '£'; + map!['strokelongoverlaycmb'] = '̶'; + map!['strokeshortoverlaycmb'] = '̵'; + map!['subset'] = '⊂'; + map!['subsetnotequal'] = '⊊'; + map!['subsetorequal'] = '⊆'; + map!['succeeds'] = '≻'; + map!['suchthat'] = '∋'; + map!['suhiragana'] = 'す'; + map!['sukatakana'] = 'ス'; + map!['sukatakanahalfwidth'] = 'ス'; + map!['sukunarabic'] = 'ْ'; + map!['summation'] = '∑'; + map!['sun'] = '☼'; + map!['superset'] = '⊃'; + map!['supersetnotequal'] = '⊋'; + map!['supersetorequal'] = '⊇'; + map!['svsquare'] = '㏜'; + map!['syouwaerasquare'] = '㍼'; + map!['t'] = 't'; + map!['tabengali'] = 'ত'; + map!['tackdown'] = '⊤'; + map!['tackleft'] = '⊣'; + map!['tadeva'] = 'त'; + map!['tagujarati'] = 'ત'; + map!['tagurmukhi'] = 'ਤ'; + map!['taharabic'] = 'ط'; + map!['tahfinalarabic'] = 'ﻂ'; + map!['tahinitialarabic'] = 'ﻃ'; + map!['tahiragana'] = 'た'; + map!['tahmedialarabic'] = 'ﻄ'; + map!['taisyouerasquare'] = '㍽'; + map!['takatakana'] = 'タ'; + map!['takatakanahalfwidth'] = 'タ'; + map!['tatweelarabic'] = 'ـ'; + map!['tau'] = 'τ'; + map!['tav'] = 'ת'; + map!['tavdages'] = 'תּ'; + map!['tavdagesh'] = 'תּ'; + map!['tavdageshhebrew'] = 'תּ'; + map!['tavhebrew'] = 'ת'; + map!['tbar'] = 'ŧ'; + map!['tbopomofo'] = 'ㄊ'; + map!['tcaron'] = 'ť'; + map!['tccurl'] = 'ʨ'; + map!['tcedilla'] = 'ţ'; + map!['tcheharabic'] = 'چ'; + map!['tchehfinalarabic'] = 'ﭻ'; + map!['tchehinitialarabic'] = 'ﭼ'; + map!['tchehmedialarabic'] = 'ﭽ'; + map!['tcircle'] = 'ⓣ'; + map!['tcircumflexbelow'] = 'ṱ'; + map!['tcommaaccent'] = 'ţ'; + map!['tdieresis'] = 'ẗ'; + map!['tdotaccent'] = 'ṫ'; + map!['tdotbelow'] = 'ṭ'; + map!['tecyrillic'] = 'т'; + map!['tedescendercyrillic'] = 'ҭ'; + map!['teharabic'] = 'ت'; + map!['tehfinalarabic'] = 'ﺖ'; + map!['tehhahinitialarabic'] = 'ﲢ'; + map!['tehhahisolatedarabic'] = 'ﰌ'; + map!['tehinitialarabic'] = 'ﺗ'; + map!['tehiragana'] = 'て'; + map!['tehjeeminitialarabic'] = 'ﲡ'; + map!['tehjeemisolatedarabic'] = 'ﰋ'; + map!['tehmarbutaarabic'] = 'ة'; + map!['tehmarbutafinalarabic'] = 'ﺔ'; + map!['tehmedialarabic'] = 'ﺘ'; + map!['tehmeeminitialarabic'] = 'ﲤ'; + map!['tehmeemisolatedarabic'] = 'ﰎ'; + map!['tehnoonfinalarabic'] = 'ﱳ'; + map!['tekatakana'] = 'テ'; + map!['tekatakanahalfwidth'] = 'テ'; + map!['telephone'] = '℡'; + map!['telephoneblack'] = '☎'; + map!['telishagedolahebrew'] = '֠'; + map!['telishaqetanahebrew'] = '֩'; + map!['tencircle'] = '⑩'; + map!['tenideographicparen'] = '㈩'; + map!['tenparen'] = '⑽'; + map!['tenperiod'] = '⒑'; + map!['tenroman'] = 'ⅹ'; + map!['tesh'] = 'ʧ'; + map!['tet'] = 'ט'; + map!['tetdagesh'] = 'טּ'; + map!['tetdageshhebrew'] = 'טּ'; + map!['tethebrew'] = 'ט'; + map!['tetsecyrillic'] = 'ҵ'; + map!['tevirhebrew'] = '֛'; + map!['tevirlefthebrew'] = '֛'; + map!['thabengali'] = 'থ'; + map!['thadeva'] = 'थ'; + map!['thagujarati'] = 'થ'; + map!['thagurmukhi'] = 'ਥ'; + map!['thalarabic'] = 'ذ'; + map!['thalfinalarabic'] = 'ﺬ'; + map!['thanthakhatlowleftthai'] = ''; + map!['thanthakhatlowrightthai'] = ''; + map!['thanthakhatthai'] = '์'; + map!['thanthakhatupperleftthai'] = ''; + map!['theharabic'] = 'ث'; + map!['thehfinalarabic'] = 'ﺚ'; + map!['thehinitialarabic'] = 'ﺛ'; + map!['thehmedialarabic'] = 'ﺜ'; + map!['thereexists'] = '∃'; + map!['therefore'] = '∴'; + map!['theta'] = 'θ'; + map!['theta1'] = 'ϑ'; + map!['thetasymbolgreek'] = 'ϑ'; + map!['thieuthacirclekorean'] = '㉹'; + map!['thieuthaparenkorean'] = '㈙'; + map!['thieuthcirclekorean'] = '㉫'; + map!['thieuthkorean'] = 'ㅌ'; + map!['thieuthparenkorean'] = '㈋'; + map!['thirteencircle'] = '⑬'; + map!['thirteenparen'] = '⒀'; + map!['thirteenperiod'] = '⒔'; + map!['thonangmonthothai'] = 'ฑ'; + map!['thook'] = 'ƭ'; + map!['thophuthaothai'] = 'ฒ'; + map!['thorn'] = 'þ'; + map!['thothahanthai'] = 'ท'; + map!['thothanthai'] = 'ฐ'; + map!['thothongthai'] = 'ธ'; + map!['thothungthai'] = 'ถ'; + map!['thousandcyrillic'] = '҂'; + map!['thousandsseparatorarabic'] = '٬'; + map!['thousandsseparatorpersian'] = '٬'; + map!['three'] = '3'; + map!['threearabic'] = '٣'; + map!['threebengali'] = '৩'; + map!['threecircle'] = '③'; + map!['threecircleinversesansserif'] = '➌'; + map!['threedeva'] = '३'; + map!['threeeighths'] = '⅜'; + map!['threegujarati'] = '૩'; + map!['threegurmukhi'] = '੩'; + map!['threehackarabic'] = '٣'; + map!['threehangzhou'] = '〣'; + map!['threeideographicparen'] = '㈢'; + map!['threeinferior'] = '₃'; + map!['threemonospace'] = '3'; + map!['threenumeratorbengali'] = '৶'; + map!['threeoldstyle'] = ''; + map!['threeparen'] = '⑶'; + map!['threeperiod'] = '⒊'; + map!['threepersian'] = '۳'; + map!['threequarters'] = '¾'; + map!['threequartersemdash'] = ''; + map!['threeroman'] = 'ⅲ'; + map!['threesuperior'] = '³'; + map!['threethai'] = '๓'; + map!['thzsquare'] = '㎔'; + map!['tihiragana'] = 'ち'; + map!['tikatakana'] = 'チ'; + map!['tikatakanahalfwidth'] = 'チ'; + map!['tikeutacirclekorean'] = '㉰'; + map!['tikeutaparenkorean'] = '㈐'; + map!['tikeutcirclekorean'] = '㉢'; + map!['tikeutkorean'] = 'ㄷ'; + map!['tikeutparenkorean'] = '㈂'; + map!['tilde'] = '˜'; + map!['tildebelowcmb'] = '̰'; + map!['tildecmb'] = '̃'; + map!['tildecomb'] = '̃'; + map!['tildedoublecmb'] = '͠'; + map!['tildeoperator'] = '∼'; + map!['tildeoverlaycmb'] = '̴'; + map!['tildeverticalcmb'] = '̾'; + map!['timescircle'] = '⊗'; + map!['tipehahebrew'] = '֖'; + map!['tipehalefthebrew'] = '֖'; + map!['tippigurmukhi'] = 'ੰ'; + map!['titlocyrilliccmb'] = '҃'; + map!['tiwnarmenian'] = 'տ'; + map!['tlinebelow'] = 'ṯ'; + map!['tmonospace'] = 't'; + map!['toarmenian'] = 'թ'; + map!['tohiragana'] = 'と'; + map!['tokatakana'] = 'ト'; + map!['tokatakanahalfwidth'] = 'ト'; + map!['tonebarextrahighmod'] = '˥'; + map!['tonebarextralowmod'] = '˩'; + map!['tonebarhighmod'] = '˦'; + map!['tonebarlowmod'] = '˨'; + map!['tonebarmidmod'] = '˧'; + map!['tonefive'] = 'ƽ'; + map!['tonesix'] = 'ƅ'; + map!['tonetwo'] = 'ƨ'; + map!['tonos'] = '΄'; + map!['tonsquare'] = '㌧'; + map!['topatakthai'] = 'ฏ'; + map!['tortoiseshellbracketleft'] = '〔'; + map!['tortoiseshellbracketleftsmall'] = '﹝'; + map!['tortoiseshellbracketleftvertical'] = '︹'; + map!['tortoiseshellbracketright'] = '〕'; + map!['tortoiseshellbracketrightsmall'] = '﹞'; + map!['tortoiseshellbracketrightvertical'] = '︺'; + map!['totaothai'] = 'ต'; + map!['tpalatalhook'] = 'ƫ'; + map!['tparen'] = '⒯'; + map!['trademark'] = '™'; + map!['trademarksans'] = ''; + map!['trademarkserif'] = ''; + map!['tretroflexhook'] = 'ʈ'; + map!['triagdn'] = '▼'; + map!['triaglf'] = '◄'; + map!['triagrt'] = '►'; + map!['triagup'] = '▲'; + map!['ts'] = 'ʦ'; + map!['tsadi'] = 'צ'; + map!['tsadidagesh'] = 'צּ'; + map!['tsadidageshhebrew'] = 'צּ'; + map!['tsadihebrew'] = 'צ'; + map!['tsecyrillic'] = 'ц'; + map!['tsere'] = 'ֵ'; + map!['tsere12'] = 'ֵ'; + map!['tsere1e'] = 'ֵ'; + map!['tsere2b'] = 'ֵ'; + map!['tserehebrew'] = 'ֵ'; + map!['tserenarrowhebrew'] = 'ֵ'; + map!['tserequarterhebrew'] = 'ֵ'; + map!['tserewidehebrew'] = 'ֵ'; + map!['tshecyrillic'] = 'ћ'; + map!['tsuperior'] = ''; + map!['ttabengali'] = 'ট'; + map!['ttadeva'] = 'ट'; + map!['ttagujarati'] = 'ટ'; + map!['ttagurmukhi'] = 'ਟ'; + map!['tteharabic'] = 'ٹ'; + map!['ttehfinalarabic'] = 'ﭧ'; + map!['ttehinitialarabic'] = 'ﭨ'; + map!['ttehmedialarabic'] = 'ﭩ'; + map!['tthabengali'] = 'ঠ'; + map!['tthadeva'] = 'ठ'; + map!['tthagujarati'] = 'ઠ'; + map!['tthagurmukhi'] = 'ਠ'; + map!['tturned'] = 'ʇ'; + map!['tuhiragana'] = 'つ'; + map!['tukatakana'] = 'ツ'; + map!['tukatakanahalfwidth'] = 'ツ'; + map!['tusmallhiragana'] = 'っ'; + map!['tusmallkatakana'] = 'ッ'; + map!['tusmallkatakanahalfwidth'] = 'ッ'; + map!['twelvecircle'] = '⑫'; + map!['twelveparen'] = '⑿'; + map!['twelveperiod'] = '⒓'; + map!['twelveroman'] = 'ⅻ'; + map!['twentycircle'] = '⑳'; + map!['twentyhangzhou'] = '卄'; + map!['twentyparen'] = '⒇'; + map!['twentyperiod'] = '⒛'; + map!['two'] = '2'; + map!['twoarabic'] = '٢'; + map!['twobengali'] = '২'; + map!['twocircle'] = '②'; + map!['twocircleinversesansserif'] = '➋'; + map!['twodeva'] = '२'; + map!['twodotenleader'] = '‥'; + map!['twodotleader'] = '‥'; + map!['twodotleadervertical'] = '︰'; + map!['twogujarati'] = '૨'; + map!['twogurmukhi'] = '੨'; + map!['twohackarabic'] = '٢'; + map!['twohangzhou'] = '〢'; + map!['twoideographicparen'] = '㈡'; + map!['twoinferior'] = '₂'; + map!['twomonospace'] = '2'; + map!['twonumeratorbengali'] = '৵'; + map!['twooldstyle'] = ''; + map!['twoparen'] = '⑵'; + map!['twoperiod'] = '⒉'; + map!['twopersian'] = '۲'; + map!['tworoman'] = 'ⅱ'; + map!['twostroke'] = 'ƻ'; + map!['twosuperior'] = '²'; + map!['twothai'] = '๒'; + map!['twothirds'] = '⅔'; + map!['u'] = 'u'; + map!['uacute'] = 'ú'; + map!['ubar'] = 'ʉ'; + map!['ubengali'] = 'উ'; + map!['ubopomofo'] = 'ㄨ'; + map!['ubreve'] = 'ŭ'; + map!['ucaron'] = 'ǔ'; + map!['ucircle'] = 'ⓤ'; + map!['ucircumflex'] = 'û'; + map!['ucircumflexbelow'] = 'ṷ'; + map!['ucyrillic'] = 'у'; + map!['udattadeva'] = '॑'; + map!['udblacute'] = 'ű'; + map!['udblgrave'] = 'ȕ'; + map!['udeva'] = 'उ'; + map!['udieresis'] = 'ü'; + map!['udieresisacute'] = 'ǘ'; + map!['udieresisbelow'] = 'ṳ'; + map!['udieresiscaron'] = 'ǚ'; + map!['udieresiscyrillic'] = 'ӱ'; + map!['udieresisgrave'] = 'ǜ'; + map!['udieresismacron'] = 'ǖ'; + map!['udotbelow'] = 'ụ'; + map!['ugrave'] = 'ù'; + map!['ugujarati'] = 'ઉ'; + map!['ugurmukhi'] = 'ਉ'; + map!['uhiragana'] = 'う'; + map!['uhookabove'] = 'ủ'; + map!['uhorn'] = 'ư'; + map!['uhornacute'] = 'ứ'; + map!['uhorndotbelow'] = 'ự'; + map!['uhorngrave'] = 'ừ'; + map!['uhornhookabove'] = 'ử'; + map!['uhorntilde'] = 'ữ'; + map!['uhungarumlaut'] = 'ű'; + map!['uhungarumlautcyrillic'] = 'ӳ'; + map!['uinvertedbreve'] = 'ȗ'; + map!['ukatakana'] = 'ウ'; + map!['ukatakanahalfwidth'] = 'ウ'; + map!['ukcyrillic'] = 'ѹ'; + map!['ukorean'] = 'ㅜ'; + map!['umacron'] = 'ū'; + map!['umacroncyrillic'] = 'ӯ'; + map!['umacrondieresis'] = 'ṻ'; + map!['umatragurmukhi'] = 'ੁ'; + map!['umonospace'] = 'u'; + map!['underscore'] = '_'; + map!['underscoredbl'] = '‗'; + map!['underscoremonospace'] = '_'; + map!['underscorevertical'] = '︳'; + map!['underscorewavy'] = '﹏'; + map!['union'] = '∪'; + map!['universal'] = '∀'; + map!['uogonek'] = 'ų'; + map!['uparen'] = '⒰'; + map!['upblock'] = '▀'; + map!['upperdothebrew'] = 'ׄ'; + map!['upsilon'] = 'υ'; + map!['upsilondieresis'] = 'ϋ'; + map!['upsilondieresistonos'] = 'ΰ'; + map!['upsilonlatin'] = 'ʊ'; + map!['upsilontonos'] = 'ύ'; + map!['uptackbelowcmb'] = '̝'; + map!['uptackmod'] = '˔'; + map!['uragurmukhi'] = 'ੳ'; + map!['uring'] = 'ů'; + map!['ushortcyrillic'] = 'ў'; + map!['usmallhiragana'] = 'ぅ'; + map!['usmallkatakana'] = 'ゥ'; + map!['usmallkatakanahalfwidth'] = 'ゥ'; + map!['ustraightcyrillic'] = 'ү'; + map!['ustraightstrokecyrillic'] = 'ұ'; + map!['utilde'] = 'ũ'; + map!['utildeacute'] = 'ṹ'; + map!['utildebelow'] = 'ṵ'; + map!['uubengali'] = 'ঊ'; + map!['uudeva'] = 'ऊ'; + map!['uugujarati'] = 'ઊ'; + map!['uugurmukhi'] = 'ਊ'; + map!['uumatragurmukhi'] = 'ੂ'; + map!['uuvowelsignbengali'] = 'ূ'; + map!['uuvowelsigndeva'] = 'ू'; + map!['uuvowelsigngujarati'] = 'ૂ'; + map!['uvowelsignbengali'] = 'ু'; + map!['uvowelsigndeva'] = 'ु'; + map!['uvowelsigngujarati'] = 'ુ'; + map!['v'] = 'v'; + map!['vadeva'] = 'व'; + map!['vagujarati'] = 'વ'; + map!['vagurmukhi'] = 'ਵ'; + map!['vakatakana'] = 'ヷ'; + map!['vav'] = 'ו'; + map!['vavdagesh'] = 'וּ'; + map!['vavdagesh65'] = 'וּ'; + map!['vavdageshhebrew'] = 'וּ'; + map!['vavhebrew'] = 'ו'; + map!['vavholam'] = 'וֹ'; + map!['vavholamhebrew'] = 'וֹ'; + map!['vavvavhebrew'] = 'װ'; + map!['vavyodhebrew'] = 'ױ'; + map!['vcircle'] = 'ⓥ'; + map!['vdotbelow'] = 'ṿ'; + map!['vecyrillic'] = 'в'; + map!['veharabic'] = 'ڤ'; + map!['vehfinalarabic'] = 'ﭫ'; + map!['vehinitialarabic'] = 'ﭬ'; + map!['vehmedialarabic'] = 'ﭭ'; + map!['vekatakana'] = 'ヹ'; + map!['venus'] = '♀'; + map!['verticalbar'] = '|'; + map!['verticallineabovecmb'] = '̍'; + map!['verticallinebelowcmb'] = '̩'; + map!['verticallinelowmod'] = 'ˌ'; + map!['verticallinemod'] = 'ˈ'; + map!['vewarmenian'] = 'վ'; + map!['vhook'] = 'ʋ'; + map!['vikatakana'] = 'ヸ'; + map!['viramabengali'] = '্'; + map!['viramadeva'] = '्'; + map!['viramagujarati'] = '્'; + map!['visargabengali'] = 'ঃ'; + map!['visargadeva'] = 'ः'; + map!['visargagujarati'] = 'ઃ'; + map!['vmonospace'] = 'v'; + map!['voarmenian'] = 'ո'; + map!['voicediterationhiragana'] = 'ゞ'; + map!['voicediterationkatakana'] = 'ヾ'; + map!['voicedmarkkana'] = '゛'; + map!['voicedmarkkanahalfwidth'] = '゙'; + map!['vokatakana'] = 'ヺ'; + map!['vparen'] = '⒱'; + map!['vtilde'] = 'ṽ'; + map!['vturned'] = 'ʌ'; + map!['vuhiragana'] = 'ゔ'; + map!['vukatakana'] = 'ヴ'; + map!['w'] = 'w'; + map!['wacute'] = 'ẃ'; + map!['waekorean'] = 'ㅙ'; + map!['wahiragana'] = 'わ'; + map!['wakatakana'] = 'ワ'; + map!['wakatakanahalfwidth'] = 'ワ'; + map!['wakorean'] = 'ㅘ'; + map!['wasmallhiragana'] = 'ゎ'; + map!['wasmallkatakana'] = 'ヮ'; + map!['wattosquare'] = '㍗'; + map!['wavedash'] = '〜'; + map!['wavyunderscorevertical'] = '︴'; + map!['wawarabic'] = 'و'; + map!['wawfinalarabic'] = 'ﻮ'; + map!['wawhamzaabovearabic'] = 'ؤ'; + map!['wawhamzaabovefinalarabic'] = 'ﺆ'; + map!['wbsquare'] = '㏝'; + map!['wcircle'] = 'ⓦ'; + map!['wcircumflex'] = 'ŵ'; + map!['wdieresis'] = 'ẅ'; + map!['wdotaccent'] = 'ẇ'; + map!['wdotbelow'] = 'ẉ'; + map!['wehiragana'] = 'ゑ'; + map!['weierstrass'] = '℘'; + map!['wekatakana'] = 'ヱ'; + map!['wekorean'] = 'ㅞ'; + map!['weokorean'] = 'ㅝ'; + map!['wgrave'] = 'ẁ'; + map!['whitebullet'] = '◦'; + map!['whitecircle'] = '○'; + map!['whitecircleinverse'] = '◙'; + map!['whitecornerbracketleft'] = '『'; + map!['whitecornerbracketleftvertical'] = '﹃'; + map!['whitecornerbracketright'] = '』'; + map!['whitecornerbracketrightvertical'] = '﹄'; + map!['whitediamond'] = '◇'; + map!['whitediamondcontainingblacksmalldiamond'] = '◈'; + map!['whitedownpointingsmalltriangle'] = '▿'; + map!['whitedownpointingtriangle'] = '▽'; + map!['whiteleftpointingsmalltriangle'] = '◃'; + map!['whiteleftpointingtriangle'] = '◁'; + map!['whitelenticularbracketleft'] = '〖'; + map!['whitelenticularbracketright'] = '〗'; + map!['whiterightpointingsmalltriangle'] = '▹'; + map!['whiterightpointingtriangle'] = '▷'; + map!['whitesmallsquare'] = '▫'; + map!['whitesmilingface'] = '☺'; + map!['whitesquare'] = '□'; + map!['whitestar'] = '☆'; + map!['whitetelephone'] = '☏'; + map!['whitetortoiseshellbracketleft'] = '〘'; + map!['whitetortoiseshellbracketright'] = '〙'; + map!['whiteuppointingsmalltriangle'] = '▵'; + map!['whiteuppointingtriangle'] = '△'; + map!['wihiragana'] = 'ゐ'; + map!['wikatakana'] = 'ヰ'; + map!['wikorean'] = 'ㅟ'; + map!['wmonospace'] = 'w'; + map!['wohiragana'] = 'を'; + map!['wokatakana'] = 'ヲ'; + map!['wokatakanahalfwidth'] = 'ヲ'; + map!['won'] = '₩'; + map!['wonmonospace'] = '₩'; + map!['wowaenthai'] = 'ว'; + map!['wparen'] = '⒲'; + map!['wring'] = 'ẘ'; + map!['wsuperior'] = 'ʷ'; + map!['wturned'] = 'ʍ'; + map!['wynn'] = 'ƿ'; + map!['x'] = 'x'; + map!['xabovecmb'] = '̽'; + map!['xbopomofo'] = 'ㄒ'; + map!['xcircle'] = 'ⓧ'; + map!['xdieresis'] = 'ẍ'; + map!['xdotaccent'] = 'ẋ'; + map!['xeharmenian'] = 'խ'; + map!['xi'] = 'ξ'; + map!['xmonospace'] = 'x'; + map!['xparen'] = '⒳'; + map!['xsuperior'] = 'ˣ'; + map!['y'] = 'y'; + map!['yaadosquare'] = '㍎'; + map!['yabengali'] = 'য'; + map!['yacute'] = 'ý'; + map!['yadeva'] = 'य'; + map!['yaekorean'] = 'ㅒ'; + map!['yagujarati'] = 'ય'; + map!['yagurmukhi'] = 'ਯ'; + map!['yahiragana'] = 'や'; + map!['yakatakana'] = 'ヤ'; + map!['yakatakanahalfwidth'] = 'ヤ'; + map!['yakorean'] = 'ㅑ'; + map!['yamakkanthai'] = '๎'; + map!['yasmallhiragana'] = 'ゃ'; + map!['yasmallkatakana'] = 'ャ'; + map!['yasmallkatakanahalfwidth'] = 'ャ'; + map!['yatcyrillic'] = 'ѣ'; + map!['ycircle'] = 'ⓨ'; + map!['ycircumflex'] = 'ŷ'; + map!['ydieresis'] = 'ÿ'; + map!['ydotaccent'] = 'ẏ'; + map!['ydotbelow'] = 'ỵ'; + map!['yeharabic'] = 'ي'; + map!['yehbarreearabic'] = 'ے'; + map!['yehbarreefinalarabic'] = 'ﮯ'; + map!['yehfinalarabic'] = 'ﻲ'; + map!['yehhamzaabovearabic'] = 'ئ'; + map!['yehhamzaabovefinalarabic'] = 'ﺊ'; + map!['yehhamzaaboveinitialarabic'] = 'ﺋ'; + map!['yehhamzaabovemedialarabic'] = 'ﺌ'; + map!['yehinitialarabic'] = 'ﻳ'; + map!['yehmedialarabic'] = 'ﻴ'; + map!['yehmeeminitialarabic'] = 'ﳝ'; + map!['yehmeemisolatedarabic'] = 'ﱘ'; + map!['yehnoonfinalarabic'] = 'ﲔ'; + map!['yehthreedotsbelowarabic'] = 'ۑ'; + map!['yekorean'] = 'ㅖ'; + map!['yen'] = '¥'; + map!['yenmonospace'] = '¥'; + map!['yeokorean'] = 'ㅕ'; + map!['yeorinhieuhkorean'] = 'ㆆ'; + map!['yerahbenyomohebrew'] = '֪'; + map!['yerahbenyomolefthebrew'] = '֪'; + map!['yericyrillic'] = 'ы'; + map!['yerudieresiscyrillic'] = 'ӹ'; + map!['yesieungkorean'] = 'ㆁ'; + map!['yesieungpansioskorean'] = 'ㆃ'; + map!['yesieungsioskorean'] = 'ㆂ'; + map!['yetivhebrew'] = '֚'; + map!['ygrave'] = 'ỳ'; + map!['yhook'] = 'ƴ'; + map!['yhookabove'] = 'ỷ'; + map!['yiarmenian'] = 'յ'; + map!['yicyrillic'] = 'ї'; + map!['yikorean'] = 'ㅢ'; + map!['yinyang'] = '☯'; + map!['yiwnarmenian'] = 'ւ'; + map!['ymonospace'] = 'y'; + map!['yod'] = 'י'; + map!['yoddagesh'] = 'יּ'; + map!['yoddageshhebrew'] = 'יּ'; + map!['yodhebrew'] = 'י'; + map!['yodyodhebrew'] = 'ײ'; + map!['yodyodpatahhebrew'] = 'ײַ'; + map!['yohiragana'] = 'よ'; + map!['yoikorean'] = 'ㆉ'; + map!['yokatakana'] = 'ヨ'; + map!['yokatakanahalfwidth'] = 'ヨ'; + map!['yokorean'] = 'ㅛ'; + map!['yosmallhiragana'] = 'ょ'; + map!['yosmallkatakana'] = 'ョ'; + map!['yosmallkatakanahalfwidth'] = 'ョ'; + map!['yotgreek'] = 'ϳ'; + map!['yoyaekorean'] = 'ㆈ'; + map!['yoyakorean'] = 'ㆇ'; + map!['yoyakthai'] = 'ย'; + map!['yoyingthai'] = 'ญ'; + map!['yparen'] = '⒴'; + map!['ypogegrammeni'] = 'ͺ'; + map!['ypogegrammenigreekcmb'] = 'ͅ'; + map!['yr'] = 'Ʀ'; + map!['yring'] = 'ẙ'; + map!['ysuperior'] = 'ʸ'; + map!['ytilde'] = 'ỹ'; + map!['yturned'] = 'ʎ'; + map!['yuhiragana'] = 'ゆ'; + map!['yuikorean'] = 'ㆌ'; + map!['yukatakana'] = 'ユ'; + map!['yukatakanahalfwidth'] = 'ユ'; + map!['yukorean'] = 'ㅠ'; + map!['yusbigcyrillic'] = 'ѫ'; + map!['yusbigiotifiedcyrillic'] = 'ѭ'; + map!['yuslittlecyrillic'] = 'ѧ'; + map!['yuslittleiotifiedcyrillic'] = 'ѩ'; + map!['yusmallhiragana'] = 'ゅ'; + map!['yusmallkatakana'] = 'ュ'; + map!['yusmallkatakanahalfwidth'] = 'ュ'; + map!['yuyekorean'] = 'ㆋ'; + map!['yuyeokorean'] = 'ㆊ'; + map!['yyabengali'] = 'য়'; + map!['yyadeva'] = 'य़'; + map!['z'] = 'z'; + map!['zaarmenian'] = 'զ'; + map!['zacute'] = 'ź'; + map!['zadeva'] = 'ज़'; + map!['zagurmukhi'] = 'ਜ਼'; + map!['zaharabic'] = 'ظ'; + map!['zahfinalarabic'] = 'ﻆ'; + map!['zahinitialarabic'] = 'ﻇ'; + map!['zahiragana'] = 'ざ'; + map!['zahmedialarabic'] = 'ﻈ'; + map!['zainarabic'] = 'ز'; + map!['zainfinalarabic'] = 'ﺰ'; + map!['zakatakana'] = 'ザ'; + map!['zaqefgadolhebrew'] = '֕'; + map!['zaqefqatanhebrew'] = '֔'; + map!['zarqahebrew'] = '֘'; + map!['zayin'] = 'ז'; + map!['zayindagesh'] = 'זּ'; + map!['zayindageshhebrew'] = 'זּ'; + map!['zayinhebrew'] = 'ז'; + map!['zbopomofo'] = 'ㄗ'; + map!['zcaron'] = 'ž'; + map!['zcircle'] = 'ⓩ'; + map!['zcircumflex'] = 'ẑ'; + map!['zcurl'] = 'ʑ'; + map!['zdot'] = 'ż'; + map!['zdotaccent'] = 'ż'; + map!['zdotbelow'] = 'ẓ'; + map!['zecyrillic'] = 'з'; + map!['zedescendercyrillic'] = 'ҙ'; + map!['zedieresiscyrillic'] = 'ӟ'; + map!['zehiragana'] = 'ぜ'; + map!['zekatakana'] = 'ゼ'; + map!['zero'] = '0'; + map!['zeroarabic'] = '٠'; + map!['zerobengali'] = '০'; + map!['zerodeva'] = '०'; + map!['zerogujarati'] = '૦'; + map!['zerogurmukhi'] = '੦'; + map!['zerohackarabic'] = '٠'; + map!['zeroinferior'] = '₀'; + map!['zeromonospace'] = '0'; + map!['zerooldstyle'] = ''; + map!['zeropersian'] = '۰'; + map!['zerosuperior'] = '⁰'; + map!['zerothai'] = '๐'; + map!['zerowidthjoiner'] = ''; + map!['zerowidthnonjoiner'] = '‌'; + map!['zerowidthspace'] = '​'; + map!['zeta'] = 'ζ'; + map!['zhbopomofo'] = 'ㄓ'; + map!['zhearmenian'] = 'ժ'; + map!['zhebrevecyrillic'] = 'ӂ'; + map!['zhecyrillic'] = 'ж'; + map!['zhedescendercyrillic'] = 'җ'; + map!['zhedieresiscyrillic'] = 'ӝ'; + map!['zihiragana'] = 'じ'; + map!['zikatakana'] = 'ジ'; + map!['zinorhebrew'] = '֮'; + map!['zlinebelow'] = 'ẕ'; + map!['zmonospace'] = 'z'; + map!['zohiragana'] = 'ぞ'; + map!['zokatakana'] = 'ゾ'; + map!['zparen'] = '⒵'; + map!['zretroflexhook'] = 'ʐ'; + map!['zstroke'] = 'ƶ'; + map!['zuhiragana'] = 'ず'; + map!['zukatakana'] = 'ズ'; + } + + /// internal method + String? getUnicode(String? names) { + if (names == null) { + return '\u0000'; + } + final int n = names.indexOf('.'); + if (n > 0) { + names = names.substring(0, n); + } + final List array = names.split('_'); + if (array.isNotEmpty) { + return getUnicodeForName(array[0]); + } + return '\u0000'; + } + + /// internal method + String parseHex(String hex) { + String result; + try { + result = String.fromCharCode(int.parse(hex, radix: 16)); + } catch (e) { + result = '\u0000'; + } + return result; + } + + /// internal method + String? getUnicodeForName(String name) { + if (map!.containsKey(name)) { + return map![name]; + } + if (name.startsWith('uni')) { + name = name.substring(3); + if (name.length >= 4) { + return parseHex(name.substring(0, 4)); + } + return '\u0000'; + } else { + if (name.startsWith('u')) { + return parseHex(name.substring(1, name.length)); + } + throw ArgumentError('The encoding is not supported.'); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_structure.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_structure.dart index 87d753c28..604c03a05 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_structure.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/font_structure.dart @@ -1,5178 +1,5264 @@ -import 'dart:convert'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../graphics/fonts/enums.dart'; -import '../../graphics/fonts/pdf_cjk_standard_font.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_standard_font.dart'; -import '../../io/decode_big_endian.dart'; -import '../../io/pdf_constants.dart'; -import '../../io/pdf_cross_table.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_number.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_stream.dart'; -import '../../primitives/pdf_string.dart'; -import 'font_file2.dart'; -import 'xobject_element.dart'; - -/// internal class -class FontStructure { - //constructor - /// internal constructor - FontStructure([IPdfPrimitive? fontDict, String? fontRefNum]) { - if (fontDict != null) { - fontDictionary = fontDict as PdfDictionary; - if (fontDictionary.containsKey(PdfName('Subtype'))) { - fontType = fontDictionary.items![PdfName('Subtype')] as PdfName?; - } - } - _initialize(); - if (fontRefNum != null) { - fontRefNumber = fontRefNum; - if (fontType != null) { - if (fontType!.name == 'Type3') { - if (fontDictionary.items!.containsKey(PdfName('CharProcs'))) { - PdfDictionary? charProcs; - if (fontDictionary['CharProcs'] is PdfDictionary) { - charProcs = fontDictionary['CharProcs'] as PdfDictionary?; - } else { - charProcs = - (fontDictionary['CharProcs']! as PdfReferenceHolder).object - as PdfDictionary?; - } - final List names = charProcs!.items!.keys.toList(); - int i = 0; - // ignore: avoid_function_literals_in_foreach_calls - charProcs.items!.values.forEach((IPdfPrimitive? value) { - if (value != null && value is PdfReferenceHolder) { - final PdfReferenceHolder holder = value; - type3FontCharProcsDict[names[i]!.name] = - holder.object as PdfStream?; - i++; - } - }); - } - } else if (fontType!.name == 'Type1') { - isStandardFont = _checkStandardFont(); - } else if (fontType!.name == 'Type0') { - isStandardCJKFont = _checkStandardCJKFont(); - } - } - } - _fontStyle = [PdfFontStyle.regular]; - defaultGlyphWidth = isCid ? 1000 : 0; - _containsCmap = true; - differenceEncoding = {}; - } - - //Fields - /// internal field - bool isWhiteSpace = false; - - /// internal field - bool isSameFont = false; - String? _fontEncoding; - - /// internal field - late PdfDictionary fontDictionary; - String? _fontName; - - /// internal field - double? fontSize; - Map? _characterMapTable; - Map? _reverseMapTable; - - /// internal field - Map tempMapTable = {}; - - /// internal field - Map? differenceEncoding; - - /// internal field - List tempStringList = []; - Map? _differencesDictionary; - - /// internal field - late Map differenceTable; - Map? _octDecMapTable; - Map? _macEncodeTable; - final Map _macRomanMapTable = {}; - final Map _winansiMapTable = {}; - - /// internal field - Map reverseDictMapping = {}; - - /// internal field - PdfDictionary? cidSystemInfoDictionary; - - /// internal field - Map? cidToGidTable; - Map? _cidToGidReverseMapTable; - - /// internal field - Map type3FontCharProcsDict = {}; - - /// internal field - bool isContainFontfile2 = false; - - /// internal field - bool isMappingDone = false; - - /// internal field - bool isSystemFontExist = false; - - /// internal field - bool isTextExtraction = false; - - /// internal field - bool isEmbedded = false; - - /// internal field - bool containsCmap = true; - - /// internal field - late String zapfPostScript; - - /// internal field - late String fontRefNumber; - - /// internal field - PdfName? fontType; - - /// internal field - bool isAdobeIdentity = false; - bool _isCidFontType = false; - List? _fontStyle; - Map? _fontGlyphWidth; - - /// internal field - double? defaultGlyphWidth; - late bool _containsCmap; - Map? _unicodeCharMapTable; - - /// internal field - late double type1GlyphHeight; - - /// internal field - late bool isStandardFont; - - /// internal field - late bool isStandardCJKFont; - - /// internal field - PdfFont? font; - String? _standardFontName = ''; - String? _standardCJKFontName = ''; - - /// internal field - late List standardFontNames; - - /// internal field - late List standardCJKFontNames; - - /// internal field - late List cjkEncoding; - late List _windows1252MapTable; - - /// internal field - bool isLayout = false; - - /// internal field - bool macRomanEncoded = false; - - //Properties - /// internal property - String? get fontEncoding => _fontEncoding ??= getFontEncoding(); - - /// internal property - Map get characterMapTable => - _characterMapTable ??= getCharacterMapTable(); - - set characterMapTable(Map value) { - _characterMapTable = value; - } - - /// internal property - Map get differencesDictionary => - _differencesDictionary ??= getDifferencesDictionary(); - - set differencesDictionary(Map value) { - _differencesDictionary = value; - } - - /// internal property - Map get octDecMapTable => _octDecMapTable ??= {}; - - set octDecMapTable(Map value) { - _octDecMapTable = value; - } - - /// internal property - Map? get reverseMapTable => - _reverseMapTable ??= getReverseMapTable(); - - set reverseMapTable(Map? value) { - _reverseMapTable = value; - } - - /// internal property - Map get cidToGidReverseMapTable => - _cidToGidReverseMapTable ??= {}; - - set cidToGidReverseMapTable(Map value) { - _cidToGidReverseMapTable = value; - } - - /// internal property - Map? get macEncodeTable { - if (_macEncodeTable == null) { - getMacEncodeTable(); - } - return _macEncodeTable; - } - - set macEncodeTable(Map? value) { - _macEncodeTable = value; - } - - /// internal property - String? get fontName => _fontName ??= getFontName(); - - /// internal property - bool get isCid { - _isCidFontType = isCIDFontType(); - return _isCidFontType; - } - - set isCid(bool value) { - _isCidFontType = value; - } - - /// internal property - List? get fontStyle { - if (_fontStyle!.length == 1 && _fontStyle![0] == PdfFontStyle.regular) { - _fontStyle = getFontStyle(); - } - return _fontStyle; - } - - /// internal property - Map? get fontGlyphWidths { - if (_fontGlyphWidth == null) { - if (fontEncoding == 'Identity-H' || fontEncoding == 'Identity#2DH') { - _getGlyphWidths(); - } else { - _getGlyphWidthsNonIdH(); - } - } - return _fontGlyphWidth; - } - - /// internal property - Map? get unicodeCharMapTable { - _unicodeCharMapTable ??= {}; - return _unicodeCharMapTable; - } - - set unicodeCharMapTable(Map? value) { - _unicodeCharMapTable = value; - } - - /// internal property - PdfNumber? get flags => _getFlagValue(); - - //Implementation - void _initialize() { - differenceTable = {}; - zapfPostScript = ''; - fontRefNumber = ''; - type1GlyphHeight = 0; - isStandardFont = false; - isStandardCJKFont = false; - standardCJKFontNames = [ - 'HYGoThic-Medium,BoldItalic', - 'HYGoThic-Medium,Bold', - 'HYGoThic-Medium,Italic', - 'HYGoThic-Medium', - 'MHei-Medium,BoldItalic', - 'MHei-Medium,Bold', - 'MHei-Medium', - 'MHei-Medium,Italic', - 'MSung-Light,BoldItalic', - 'MSung-Light,Bold', - 'MSung-Light,Italic', - 'MSung-Light', - 'STSong-Light,BoldItalic', - 'STSong-Light,Bold', - 'STSong-Light,Italic', - 'STSong-Light', - 'HeiseiMin-W3,BoldItalic', - 'HeiseiMin-W3,Bold', - 'HeiseiMin-W3,Italic', - 'HeiseiMin-W3', - 'HeiseiKakuGo-W5,BoldItalic', - 'HeiseiKakuGo-W5,Bold', - 'HeiseiKakuGo-W5,Italic', - 'HeiseiKakuGo-W5', - 'HYSMyeongJo-Medium,BoldItalic', - 'HYSMyeongJo-Medium,Bold', - 'HYSMyeongJo-Medium,Italic', - 'HYSMyeongJo-Medium', - ]; - cjkEncoding = [ - 'UniKS-UCS2-H', - 'UniJIS-UCS2-H', - 'UniCNS-UCS2-H', - 'UniGB-UCS2-H', - ]; - standardFontNames = [ - 'Helvetica', - 'Helvetica-Bold', - 'Helvetica,Bold', - 'Helvetica-BoldOblique', - 'Helvetica,BoldItalic', - 'Helvetica-Oblique', - 'Helvetica,Italic', - 'Courier New', - 'Courier', - 'Courier-Bold', - 'Courier New,Bold', - 'Courier-BoldOblique', - 'Courier New,BoldItalic', - 'Courier-Oblique', - 'Courier New,Italic', - 'Times New Roman', - 'Times New Roman,Bold', - 'Times New Roman,BoldItalic', - 'Times New Roman,Italic', - 'Times-Roman', - 'Times-Bold', - 'Times-Italic', - 'Times-BoldItalic', - 'Symbol', - 'ZapfDingbats', - ]; - _windows1252MapTable = [ - '\u0000', - '\u0001', - '\u0002', - '\u0003', - '\u0004', - '\u0005', - '\u0006', - '\u0007', - '\b', - '\t', - '\n', - '\v', - '\f', - '\r', - '\u000e', - '\u000f', - '\u0010', - '\u0011', - '\u0012', - '\u0013', - '\u0014', - '\u0015', - '\u0016', - '\u0017', - '\u0018', - '\u0019', - '\u001a', - '\u001b', - '\u001c', - '\u001d', - '\u001e', - '\u001f', - ' ', - '!', - '"', - '#', - r'$', - '%', - '&', - "'", - '(', - ')', - '*', - '+', - ',', - '-', - '.', - '/', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - ':', - ';', - '<', - '=', - '>', - '?', - '@', - 'A', - 'B', - 'C', - 'D', - 'E', - 'F', - 'G', - 'H', - 'I', - 'J', - 'K', - 'L', - 'M', - 'N', - 'O', - 'P', - 'Q', - 'R', - 'S', - 'T', - 'U', - 'V', - 'W', - 'X', - 'Y', - 'Z', - '[', - r'\', - ']', - '^', - '_', - '`', - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', - 'g', - 'h', - 'i', - 'j', - 'k', - 'l', - 'm', - 'n', - 'o', - 'p', - 'q', - 'r', - 's', - 't', - 'u', - 'v', - 'w', - 'x', - 'y', - 'z', - '{', - '|', - '}', - '~', - '\u007f', - '€', - '\u0081', - '‚', - 'ƒ', - '„', - '…', - '†', - '‡', - 'ˆ', - '‰', - 'Š', - '‹', - 'Œ', - '\u008d', - 'Ž', - '\u008f', - '\u0090', - '‘', - '’', - '“', - '”', - '•', - '–', - '—', - '˜', - '™', - 'š', - '›', - 'œ', - '\u009d', - 'ž', - 'Ÿ', - ' ', - '¡', - '¢', - '£', - '¤', - '¥', - '¦', - '§', - '¨', - '©', - 'ª', - '«', - '¬', - '­', - '®', - '¯', - '°', - '±', - '²', - '³', - '´', - 'µ', - '¶', - '·', - '¸', - '¹', - 'º', - '»', - '¼', - '½', - '¾', - '¿', - 'À', - 'Á', - 'Â', - 'Ã', - 'Ä', - 'Å', - 'Æ', - 'Ç', - 'È', - 'É', - 'Ê', - 'Ë', - 'Ì', - 'Í', - 'Î', - 'Ï', - 'Ð', - 'Ñ', - 'Ò', - 'Ó', - 'Ô', - 'Õ', - 'Ö', - '×', - 'Ø', - 'Ù', - 'Ú', - 'Û', - 'Ü', - 'Ý', - 'Þ', - 'ß', - 'à', - 'á', - 'â', - 'ã', - 'ä', - 'å', - 'æ', - 'ç', - 'è', - 'é', - 'ê', - 'ë', - 'ì', - 'í', - 'î', - 'ï', - 'ð', - 'ñ', - 'ò', - 'ó', - 'ô', - 'õ', - 'ö', - '÷', - 'ø', - 'ú', - 'û', - 'ü', - 'ý', - 'þ', - 'ÿ', - ]; - } - - PdfNumber? _getFlagValue() { - PdfNumber? flagvalue; - if (fontEncoding != 'Identity-H') { - if (fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor)) { - IPdfPrimitive? primitive = - fontDictionary[PdfDictionaryProperties.fontDescriptor]; - if (primitive != null && primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfDictionary) { - final PdfDictionary dic = primitive; - if (dic.containsKey(PdfDictionaryProperties.flags)) { - primitive = dic[PdfDictionaryProperties.flags]; - if (primitive is PdfNumber) { - flagvalue = primitive; - return flagvalue; - } - } - } - } - } - } else { - if (fontDictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { - IPdfPrimitive? primitive = - fontDictionary[PdfDictionaryProperties.descendantFonts]; - if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - } - if (primitive != null && primitive is PdfArray) { - final PdfArray descenarray = primitive; - if (descenarray.count > 0 && descenarray[0] is PdfReferenceHolder) { - final PdfReferenceHolder referenceholder = - descenarray[0]! as PdfReferenceHolder; - final IPdfPrimitive? primitiveObject = referenceholder.object; - if (primitiveObject != null && primitiveObject is PdfDictionary) { - final PdfDictionary dictionary = primitiveObject; - if (dictionary.containsKey( - PdfDictionaryProperties.fontDescriptor, - )) { - IPdfPrimitive? fontDescriptor = - dictionary[PdfDictionaryProperties.fontDescriptor]; - PdfDictionary? descriptorDictionary; - if (fontDescriptor is PdfReferenceHolder) { - fontDescriptor = fontDescriptor.object; - if (fontDescriptor != null && - fontDescriptor is PdfDictionary) { - descriptorDictionary = fontDescriptor; - } - } else if (fontDescriptor is PdfDictionary) { - descriptorDictionary = fontDescriptor; - } - if (descriptorDictionary != null && - descriptorDictionary.containsKey( - PdfDictionaryProperties.flags, - )) { - primitive = - descriptorDictionary[PdfDictionaryProperties.flags]; - if (primitive is PdfNumber) { - flagvalue = primitive; - return flagvalue; - } - } - } - } - } - } - } - } - return flagvalue; - } - - void _getGlyphWidths() { - if (fontEncoding == 'Identity-H' || fontEncoding == 'Identity#2DH') { - PdfDictionary dictionary = fontDictionary; - if (dictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { - IPdfPrimitive? primitive = - dictionary[PdfDictionaryProperties.descendantFonts]; - PdfArray? arr; - if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfArray) { - arr = primitive; - } - } else if (primitive is PdfArray) { - arr = primitive; - } - if (arr != null && arr.count > 0) { - if (arr[0] is PdfDictionary) { - dictionary = arr[0]! as PdfDictionary; - } else if (arr[0] is PdfReferenceHolder) { - final IPdfPrimitive? holder = - (arr[0]! as PdfReferenceHolder).object; - if (holder != null && holder is PdfDictionary) { - dictionary = holder; - } - } - } - } - _fontGlyphWidth = {}; - PdfArray? w; - int index = 0; - int endIndex = 0; - PdfArray? widthArray; - if (dictionary.containsKey(PdfDictionaryProperties.w)) { - IPdfPrimitive? holder = dictionary[PdfDictionaryProperties.w]; - if (holder is PdfArray) { - w = holder; - } else if (holder is PdfReferenceHolder) { - holder = holder.object; - if (holder != null && holder is PdfArray) { - w = holder; - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.dw)) { - final IPdfPrimitive? holder = dictionary[PdfDictionaryProperties.dw]; - if (holder is PdfNumber) { - defaultGlyphWidth = holder.value!.toDouble(); - } - } - try { - if (w == null) { - return; - } - for (int i = 0; i < w.count;) { - if (w[i] is PdfNumber) { - index = (w[i]! as PdfNumber).value!.toInt(); - } - i++; - if (w[i] is PdfArray) { - widthArray = w[i]! as PdfArray; - for (int j = 0; j < widthArray.count; j++) { - if (!_containsCmap) { - _fontGlyphWidth![index] = - (widthArray[j]! as PdfNumber).value!.toInt(); - } else if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = - (widthArray[j]! as PdfNumber).value!.toInt(); - } - index++; - } - } else if (w[i] is PdfNumber) { - endIndex = (w[i]! as PdfNumber).value!.toInt(); - i++; - for (; index <= endIndex; index++) { - if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); - } - } - } else if (w[i] is PdfReferenceHolder) { - widthArray = (w[i]! as PdfReferenceHolder).object as PdfArray?; - for (int j = 0; j < widthArray!.count; j++) { - if (!_containsCmap) { - _fontGlyphWidth![index] = - (widthArray[j]! as PdfNumber).value!.toInt(); - } else { - if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = - (widthArray[j]! as PdfNumber).value!.toInt(); - } - } - index++; - } - } - i++; - } - } catch (e) { - _fontGlyphWidth = null; - } - w = null; - widthArray = null; - } - } - - void _getGlyphWidthsNonIdH() { - int firstChar = 0; - final PdfDictionary dictionary = fontDictionary; - if (dictionary.containsKey(PdfDictionaryProperties.dw)) { - defaultGlyphWidth = - (dictionary[PdfDictionaryProperties.dw]! as PdfNumber).value! - .toDouble(); - } - if (dictionary.containsKey(PdfDictionaryProperties.firstChar)) { - firstChar = - (dictionary[PdfDictionaryProperties.firstChar]! as PdfNumber).value! - .toInt(); - } - _fontGlyphWidth = {}; - PdfArray? w; - int index = 0; - if (dictionary.containsKey(PdfDictionaryProperties.widths)) { - IPdfPrimitive? primitive = dictionary[PdfDictionaryProperties.widths]; - if (primitive is PdfArray) { - w = primitive; - } else if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfArray) { - w = primitive; - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { - IPdfPrimitive? primitive = - dictionary[PdfDictionaryProperties.descendantFonts]; - if (primitive != null && primitive is PdfArray) { - final PdfArray descendantdicArray = primitive; - if (descendantdicArray.count > 0 && - descendantdicArray[0] is PdfReferenceHolder) { - primitive = (descendantdicArray[0]! as PdfReferenceHolder).object; - if (primitive != null && primitive is PdfDictionary) { - final PdfDictionary descendantDictionary = primitive; - if (descendantDictionary.containsKey(PdfDictionaryProperties.w)) { - primitive = descendantDictionary[PdfDictionaryProperties.w]; - if (primitive is PdfArray) { - w = primitive; - } - } - } - } - } - } - - if (w != null) { - try { - for (int i = 0; i < w.count; i++) { - index = firstChar + i; - if (characterMapTable.isNotEmpty || - differencesDictionary.isNotEmpty) { - if (characterMapTable.containsKey(index)) { - if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); - } - } else if (differencesDictionary.containsKey(index.toString())) { - if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); - } - } else if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); - } - } else if (w[i] is PdfArray) { - final PdfArray tempW = w[i]! as PdfArray; - for (int j = i; j < tempW.count; j++) { - index = firstChar + j; - if (characterMapTable.isNotEmpty || - differencesDictionary.isNotEmpty) { - if (characterMapTable.containsKey(index)) { - final String mappingString = characterMapTable[index]!; - final int entryValue = mappingString.codeUnitAt(0); - if (!_fontGlyphWidth!.containsKey(entryValue)) { - _fontGlyphWidth![entryValue] = - (tempW[j]! as PdfNumber).value!.toInt(); - } - } else if (differencesDictionary.containsKey( - index.toString(), - )) { - if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = - (tempW[j]! as PdfNumber).value!.toInt(); - } - } else { - if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = - (tempW[j]! as PdfNumber).value!.toInt(); - } - } - } else { - _fontGlyphWidth![index] = - (tempW[j]! as PdfNumber).value!.toInt(); - } - } - } else { - final int value = (w[i]! as PdfNumber).value!.toInt(); - if (!_fontGlyphWidth!.containsKey(index)) { - _fontGlyphWidth![index] = value; - } - } - } - } catch (e) { - _fontGlyphWidth = null; - } - } - } - - bool _checkStandardFont() { - bool result = !_checkStandardFontDictionary(); - if (result && - fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { - IPdfPrimitive? primitive = - fontDictionary[PdfDictionaryProperties.baseFont]; - PdfName? baseFont; - if (primitive is PdfName) { - baseFont = primitive; - } else if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfName) { - baseFont = primitive; - } - } - if (baseFont != null) { - _standardFontName = baseFont.name; - result &= standardFontNames.contains( - _resolveFontName(_standardFontName), - ); - } else { - result = false; - } - } else { - result = false; - } - return result; - } - - bool _checkStandardCJKFont() { - bool result = !_checkStandardFontDictionary(); - if (result && - fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { - IPdfPrimitive? primitive = - fontDictionary[PdfDictionaryProperties.baseFont]; - PdfName? baseFont; - if (primitive is PdfName) { - baseFont = primitive; - } else if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfName) { - baseFont = primitive; - } - } - if (baseFont != null) { - _standardCJKFontName = baseFont.name; - PdfName? encoding; - if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { - primitive = fontDictionary[PdfDictionaryProperties.encoding]; - if (primitive is PdfName) { - encoding = primitive; - } else if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfName) { - encoding = primitive; - } - } - } - result &= encoding != null && cjkEncoding.contains(encoding.name); - result &= - _standardCJKFontName != '' && - standardCJKFontNames.contains(_standardCJKFontName); - } else { - result = false; - } - } else { - result = false; - } - return result; - } - - String _resolveFontName(String? fontName) { - final String tempFontName = fontName.toString(); - if (tempFontName.contains('times') || tempFontName.contains('Times')) { - return 'Times New Roman'; - } - if (tempFontName.contains('Helvetica')) { - return 'Helvetica'; - } - return tempFontName; - } - - bool _checkStandardFontDictionary() { - return fontDictionary.containsKey(PdfDictionaryProperties.widths) || - fontDictionary.containsKey(PdfDictionaryProperties.firstChar) || - fontDictionary.containsKey(PdfDictionaryProperties.lastChar) || - fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor); - } - - /// internal method - PdfFont? createStandardFont(double size) { - if (_standardFontName != null && _standardFontName != '') { - if (_standardFontName!.contains('#')) { - _standardFontName = decodeHexFontName(_standardFontName!); - } - final PdfFontFamily fontFamily = _getFontFamily(_standardFontName!); - final List styles = _getFontStyle(_standardFontName!); - if (styles.contains(PdfFontStyle.bold) && - styles.contains(PdfFontStyle.italic)) { - font = PdfStandardFont( - fontFamily, - size, - multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], - ); - } else if (styles.contains(PdfFontStyle.bold)) { - font = PdfStandardFont(fontFamily, size, style: PdfFontStyle.bold); - } else if (styles.contains(PdfFontStyle.italic)) { - font = PdfStandardFont(fontFamily, size, style: PdfFontStyle.italic); - } else { - font = PdfStandardFont(fontFamily, size); - } - } - return font; - } - - /// internal method - PdfFont? createStandardCJKFont(double size) { - if (_standardCJKFontName != '') { - final PdfCjkFontFamily fontFamily = _getCJKFontFamily( - _standardCJKFontName!, - ); - final List styles = _getCJKFontStyle(_standardCJKFontName!); - if (styles.contains(PdfFontStyle.bold) && - styles.contains(PdfFontStyle.italic)) { - font = PdfCjkStandardFont( - fontFamily, - size, - multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], - ); - } else if (styles.contains(PdfFontStyle.bold)) { - font = PdfCjkStandardFont(fontFamily, size, style: PdfFontStyle.bold); - } else if (styles.contains(PdfFontStyle.italic)) { - font = PdfCjkStandardFont(fontFamily, size, style: PdfFontStyle.italic); - } else { - font = PdfCjkStandardFont(fontFamily, size); - } - } - return font; - } - - PdfFontFamily _getFontFamily(String fontName) { - PdfFontFamily fontFamily; - if (fontName.contains('-')) { - fontName = fontName.split('-')[0]; - } - switch (fontName) { - case 'Times': - fontFamily = PdfFontFamily.timesRoman; - break; - case 'Helvetica': - fontFamily = PdfFontFamily.helvetica; - break; - case 'Courier': - fontFamily = PdfFontFamily.courier; - break; - case 'Symbol': - fontFamily = PdfFontFamily.symbol; - break; - case 'ZapfDingbats': - fontFamily = PdfFontFamily.zapfDingbats; - break; - default: - throw ArgumentError.value(fontName, 'fontName', 'invalid font name'); - } - return fontFamily; - } - - PdfCjkFontFamily _getCJKFontFamily(String fontName) { - PdfCjkFontFamily fontFamily; - if (fontName.contains(',')) { - fontName = fontName.split(',')[0]; - } - switch (fontName) { - case 'HYGoThic-Medium': - fontFamily = PdfCjkFontFamily.hanyangSystemsGothicMedium; - break; - case 'MHei-Medium': - fontFamily = PdfCjkFontFamily.monotypeHeiMedium; - break; - case 'MSung-Light': - fontFamily = PdfCjkFontFamily.monotypeSungLight; - break; - case 'STSong-Light': - fontFamily = PdfCjkFontFamily.sinoTypeSongLight; - break; - case 'HeiseiMin-W3': - fontFamily = PdfCjkFontFamily.heiseiMinchoW3; - break; - case 'HeiseiKakuGo-W5': - fontFamily = PdfCjkFontFamily.heiseiKakuGothicW5; - break; - case 'HYSMyeongJo-Medium': - fontFamily = PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium; - break; - default: - throw ArgumentError.value(fontName, 'fontName', 'invalid font name'); - } - return fontFamily; - } - - /// Extracts the font encoding associated with the text string - /// Font style. - String? getFontEncoding() { - PdfName? baseFont = PdfName(); - String? fontEncoding = ''; - if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { - if (fontDictionary[PdfDictionaryProperties.encoding] is PdfName) { - baseFont = fontDictionary[PdfDictionaryProperties.encoding] as PdfName?; - fontEncoding = baseFont!.name; - } else { - PdfDictionary? baseFontDict = PdfDictionary(); - if (fontDictionary[PdfDictionaryProperties.encoding] is PdfDictionary) { - baseFontDict = - fontDictionary[PdfDictionaryProperties.encoding] - as PdfDictionary?; - if (baseFontDict == null) { - baseFont = - (fontDictionary[PdfDictionaryProperties.encoding]! - as PdfReferenceHolder) - .object - as PdfName?; - fontEncoding = baseFont!.name; - } - } else if (fontDictionary[PdfDictionaryProperties.encoding] - is PdfReferenceHolder) { - final IPdfPrimitive? primitive = PdfCrossTable.dereference( - fontDictionary[PdfDictionaryProperties.encoding], - ); - if (primitive != null && primitive is PdfName) { - baseFont = primitive; - fontEncoding = baseFont.name; - } else if (primitive != null && primitive is PdfDictionary) { - baseFontDict = primitive; - } - } - if (baseFontDict != null && - baseFontDict.containsKey(PdfDictionaryProperties.type)) { - fontEncoding = - (baseFontDict[PdfDictionaryProperties.type]! as PdfName).name; - } - } - } - if (fontEncoding == 'CMap') { - fontEncoding = 'Identity-H'; - } - return fontEncoding; - } - - /// internal method - Map? getReverseMapTable() { - _reverseMapTable = {}; - characterMapTable.forEach((double k, String v) { - if (!_reverseMapTable!.containsKey(v)) { - _reverseMapTable![v] = k; - } - }); - return _reverseMapTable; - } - - /// Extracts the font name associated with the string. - String? getFontName() { - String? fontName = ''; - isSystemFontExist = false; - if (fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { - PdfName? baseFont; - if (fontDictionary[PdfDictionaryProperties.baseFont] is PdfName) { - baseFont = fontDictionary[PdfDictionaryProperties.baseFont] as PdfName?; - } else if (fontDictionary[PdfDictionaryProperties.baseFont] - is PdfReferenceHolder) { - baseFont = - (fontDictionary[PdfDictionaryProperties.baseFont]! - as PdfReferenceHolder) - .object - as PdfName?; - } - String font = baseFont!.name!; - if (font.contains('#20') && !font.contains('+')) { - final int startIndex = font.lastIndexOf('#20'); - font = font.substring(0, startIndex); - font = '$font+'; - } - if (font.contains('+')) {} - if (!isSystemFontExist) { - if (baseFont.name!.contains('+')) { - fontName = baseFont.name!.split('+')[1]; - } else { - fontName = baseFont.name; - } - - if (fontName!.contains('-')) { - fontName = fontName.split('-')[0]; - } else if (fontName.contains(',')) { - fontName = fontName.split(',')[0]; - } - if (fontName.contains('MT')) { - fontName = fontName.replaceAll('MT', ''); - } - if (fontName.contains('#20')) { - fontName = fontName.replaceAll('#20', ' '); - } - if (fontName.contains('#')) { - fontName = decodeHexFontName(fontName); - } - } - } - return fontName; - } - - /// internal method - List getFontStyle() { - List styles = []; - if (fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { - IPdfPrimitive? primitive = - fontDictionary[PdfDictionaryProperties.baseFont]; - PdfName? baseFont; - if (primitive is PdfName) { - baseFont = primitive; - } else if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive is PdfName) { - baseFont = primitive; - } - } - if (baseFont != null) { - styles = _getFontStyle(baseFont.name!); - } - } - if (styles.isEmpty) { - styles.add(PdfFontStyle.regular); - } - return styles; - } - - List _getCJKFontStyle(String baseFont) { - final List styles = []; - String style = ''; - if (baseFont.contains(',')) { - style = baseFont.split(',')[1]; - } - switch (style) { - case 'Italic': - styles.add(PdfFontStyle.italic); - break; - case 'Bold': - styles.add(PdfFontStyle.bold); - break; - case 'BoldItalic': - styles.add(PdfFontStyle.bold); - styles.add(PdfFontStyle.italic); - break; - default: - styles.add(PdfFontStyle.regular); - } - return styles; - } - - List _getFontStyle(String baseFont) { - final List styles = []; - if (baseFont.contains('-') || baseFont.contains(',')) { - String style = ''; - if (baseFont.contains('-')) { - style = baseFont.split('-')[1]; - } else if (baseFont.contains(',')) { - style = baseFont.split(',')[1]; - } - style = style.replaceAll('MT', ''); - switch (style) { - case 'Italic': - case 'Oblique': - styles.add(PdfFontStyle.italic); - break; - case 'Bold': - styles.add(PdfFontStyle.bold); - break; - case 'BoldItalic': - case 'BoldOblique': - styles.add(PdfFontStyle.bold); - styles.add(PdfFontStyle.italic); - break; - default: - styles.add(PdfFontStyle.regular); - } - } else { - if (baseFont.contains('Bold')) { - styles.add(PdfFontStyle.bold); - } - if (baseFont.contains('BoldItalic') || baseFont.contains('BoldOblique')) { - styles.add(PdfFontStyle.bold); - styles.add(PdfFontStyle.italic); - } - if (baseFont.contains('Italic') || baseFont.contains('Oblique')) { - styles.add(PdfFontStyle.italic); - } - } - if (styles.isEmpty) { - styles.add(PdfFontStyle.regular); - } - return styles; - } - - /// internal method - String decodeHexFontName(String fontName) { - String? newFontname; - for (int i = 0; i < fontName.length; i++) { - if (fontName[i] == '#') { - final String hexValue = fontName[i + 1] + fontName[i + 2]; - final int decimalValue = int.parse(hexValue, radix: 16); - if (decimalValue != 0) { - final String charValue = String.fromCharCode(decimalValue); - newFontname = fontName.replaceAll('#$hexValue', charValue); - i = i + 2; - } - if (!fontName.contains('#')) { - break; - } - } - } - return newFontname.toString(); - } - - /// Builds the mapping table that is used to map the - /// decoded text to get the expected text. - /// Returns a Map with key as the encoded - /// element and value as the value to be mapped to. - Map getCharacterMapTable() { - int endOfTable = 0; - final Map mapTable = {}; - if (fontDictionary.containsKey(PdfDictionaryProperties.toUnicode)) { - IPdfPrimitive? unicodeMap = - fontDictionary[PdfDictionaryProperties.toUnicode]; - - PdfStream? mapStream; - if (unicodeMap is PdfReferenceHolder) { - mapStream = unicodeMap.object as PdfStream?; - } else { - mapStream = unicodeMap as PdfStream?; - } - unicodeMap = null; - if (mapStream != null) { - mapStream.decompress(); - mapStream.changed = false; - final String text = utf8.decode(mapStream.dataStream!); - bool isBfRange = false, isBfChar = false; - int start, end, startCmap, endCmap, endPointer; - startCmap = text.indexOf('begincmap'); - endCmap = text.indexOf('endcmap'); - endPointer = startCmap; - start = startCmap; - end = endCmap; - if (endPointer == -1) { - return mapTable; - } - while (true) { - if (!isBfRange) { - start = text.indexOf('beginbfchar', endPointer); - if (start < 0) { - isBfChar = false; - start = startCmap; - endPointer = startCmap; - end = endCmap; - } else { - end = text.indexOf('endbfchar', start); - endPointer = end; - isBfChar = true; - } - } - if (!isBfChar) { - final int bfrangestart = text.indexOf('beginbfrange', endPointer); - - if (bfrangestart < 0) { - isBfRange = false; - } else { - final int bfrangeend = text.indexOf('endbfrange', endPointer + 5); - start = bfrangestart; - end = bfrangeend; - endPointer = end; - isBfRange = true; - } - } - if (isBfChar || isBfRange) { - final String sub = text.substring(start, end); - if (isBfChar) { - final List tableEntry = sub.split(RegExp('[\n-\r]')); - if (!tableEntry[0].contains('\n') && - !tableEntry[0].contains('\r')) { - List tempTmp = []; - for (int j = 0; j < tableEntry.length; j++) { - tempTmp = getHexCode(tableEntry[j]); - final int c = tempTmp.length; - for (int k = 0; k < c / 2; k++) { - if (tempTmp.length >= 2) { - final List tmpList = []; - tmpList.add(tempTmp[0]); - tmpList.add(tempTmp[1]); - tempTmp.remove(tempTmp[0]); - tempTmp.remove(tempTmp[0]); - if (tmpList.length > 1) { - if (tmpList[1].length > 4) { - String tableValue = tmpList[1]; - tableValue = tableValue.replaceAll(' ', ''); - String mapValue = ''; - final int numberOfCharacters = tableValue.length ~/ 4; - for (int j2 = 0; j2 < numberOfCharacters; j2++) { - final String mapChar = String.fromCharCode( - int.parse( - tableValue.substring(0, 4), - radix: 16, - ).toSigned(64), - ); - tableValue = tableValue.substring(4); - mapValue += mapChar; - } - mapValue = checkContainInvalidChar(mapValue); - if (!mapTable.containsKey( - int.parse(tmpList[0], radix: 16).toSigned(64), - )) { - mapTable[int.parse( - tmpList[0], - radix: 16, - ).toSigned(64).toDouble()] = - mapValue; - } - continue; - } - if (tmpList.length > 1 && - tmpList[0] != '' && - tmpList[1] != '' && - !mapTable.containsKey( - int.parse(tmpList[0], radix: 16).toSigned(64), - )) { - final String mapValue = String.fromCharCode( - int.parse(tmpList[1], radix: 16).toSigned(64), - ); - mapTable[int.parse( - tmpList[0], - radix: 16, - ).toSigned(64).toDouble()] = - mapValue; - } - } - } - } - } - } else { - for (int i = 0; i < tableEntry.length; i++) { - tempStringList = getHexCode(tableEntry[i]); - if (tempStringList.length > 1) { - if (tempStringList[1].length > 4) { - String tableValue = tempStringList[1]; - tableValue = tableValue.replaceAll(' ', ''); - String mapValue = ''; - final int numberOfCharacters = tableValue.length ~/ 4; - for (int j = 0; j < numberOfCharacters; j++) { - final String mapChar = String.fromCharCode( - int.parse( - tableValue.substring(0, 4), - radix: 16, - ).toSigned(64), - ); - tableValue = tableValue.substring(4); - mapValue += mapChar; - } - mapValue = checkContainInvalidChar(mapValue); - if (!mapTable.containsKey( - int.parse(tempStringList[0], radix: 16).toSigned(64), - )) { - mapTable[int.parse( - tempStringList[0], - radix: 16, - ).toSigned(64).toDouble()] = - mapValue; - } - continue; - } - if (!mapTable.containsKey( - int.parse(tempStringList[0]).toSigned(64), - )) { - final String mapValue = String.fromCharCode( - int.parse(tempStringList[1], radix: 16).toSigned(64), - ); - mapTable[int.parse( - tempStringList[0], - radix: 16, - ).toSigned(64).toDouble()] = - mapValue; - } - } - } - } - } else if (isBfRange) { - double startRange, endRange; - final List tableEntry = sub.split(RegExp('[\n-\r]')); - String str = ' '; - for (int i = 0; i < tableEntry.length; i++) { - if (tableEntry[i].contains('[')) { - final int subArrayStatIndex = tableEntry[i].indexOf('['); - final int subArrayEndIndex = tableEntry[i].indexOf(']'); - if (subArrayEndIndex == -1) { - str = tableEntry[i].substring( - subArrayStatIndex, - tableEntry[i].length, - ); - i++; - while (true) { - if (tableEntry[i].contains(']')) { - str += tableEntry[i].substring( - 0, - tableEntry[i].indexOf(']'), - ); - break; - } else { - str += tableEntry[i]; - i++; - } - } - } else { - str = tableEntry[i].substring( - subArrayStatIndex, - subArrayEndIndex, - ); - } - List subArray = []; - subArray = getHexCode(str); - String tableEntryValue = ' '; - if (subArrayEndIndex == -1) { - for (int j = endOfTable + 1; j <= i; j++) { - tableEntryValue += tableEntry[j]; - } - tempStringList = getHexCode(tableEntryValue); - } else { - tempStringList = getHexCode(tableEntry[i]); - } - endOfTable = i; - if (tempStringList.length > 1) { - startRange = - int.parse( - tempStringList[0], - radix: 16, - ).toSigned(64).toDouble(); - endRange = - int.parse( - tempStringList[1], - radix: 16, - ).toSigned(64).toDouble(); - int t = 0; - for ( - double j = startRange, k = 0; - j <= endRange; - j++, k++, t++ - ) { - String mapString = ''; - int l = 0; - while (l < subArray[t].length) { - final String mapValueHex = subArray[t].substring( - l, - l + 4, - ); - final int hexEquivalent = int.parse( - mapValueHex, - radix: 16, - ).toSigned(64); - final int hex = hexEquivalent; - final String hexString = hex.toRadixString(16); - final int mapValue = int.parse( - hexString, - radix: 16, - ).toSigned(64); - final String mapChar = String.fromCharCode(mapValue); - mapString += mapChar; - l += 4; - } - if (!mapTable.containsKey(j)) { - mapTable[j] = mapString; - } - } - } - } else { - tempStringList = getHexCode(tableEntry[i]); - if (tempStringList.length == 3) { - startRange = - int.parse( - tempStringList[0], - radix: 16, - ).toSigned(64).toDouble(); - endRange = - int.parse( - tempStringList[1], - radix: 16, - ).toSigned(64).toDouble(); - String mapValueHex = tempStringList[2]; - if (tempStringList[2].length > 4) { - final String mapFirstHex = mapValueHex.substring(0, 4); - final int hexFirstEquivalent = int.parse( - mapFirstHex, - radix: 16, - ).toSigned(64); - final int mapFirstValue = int.parse( - hexFirstEquivalent.toRadixString(16), - radix: 16, - ).toSigned(64); - final String mapFirstChar = String.fromCharCode( - mapFirstValue, - ); - mapValueHex = mapValueHex.substring(5, 8); - final int hexEquivalent = int.parse( - mapValueHex, - radix: 16, - ).toSigned(64); - for ( - double j = startRange, k = 0; - j <= endRange; - j++, k++ - ) { - final int hex = hexEquivalent + k.toInt(); - final String hexString = hex.toRadixString(16); - final int mapValue = int.parse( - hexString, - radix: 16, - ).toSigned(64); - String mapChar = - mapFirstChar + String.fromCharCode(mapValue); - mapChar = checkContainInvalidChar(mapChar); - if (!mapTable.containsKey(j)) { - mapTable[j] = mapChar; - } - } - } else { - final int hexEquivalent = int.parse( - mapValueHex, - radix: 16, - ).toSigned(64); - for ( - double j = startRange, k = 0; - j <= endRange; - j++, k++ - ) { - final int hex = hexEquivalent + k.toInt(); - final String hexString = hex.toRadixString(16); - final int mapValue = int.parse( - hexString, - radix: 16, - ).toSigned(64); - final String mapChar = String.fromCharCode(mapValue); - if (!mapTable.containsKey(j)) { - mapTable[j] = mapChar; - } - } - } - } else if (tempStringList.length > 1) { - int semiCount; - semiCount = tempStringList.length; - for (int k = 0; k < semiCount;) { - final String mapValue = String.fromCharCode( - int.parse( - tempStringList[k + 2], - radix: 16, - ).toSigned(64), - ); - mapTable[int.parse( - tempStringList[k], - radix: 16, - ).toSigned(64).toDouble()] = - mapValue; - k = k + 3; - } - } - } - } - } - } else { - break; - } - } - } - mapStream = null; - } - if (isSameFont == true) { - mapTable.forEach((double k, String v) { - if (!tempMapTable.containsKey(k)) { - tempMapTable[k] = v; - } else { - tempMapTable.remove(k); - tempMapTable[k] = v; - } - }); - } - return mapTable; - } - - /// Builds the mapping table that is used to map the decoded - /// text to get the expected text. - Map getDifferencesDictionary() { - final Map differencesDictionary = {}; - PdfDictionary? encodingDictionary; - - if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { - if (fontDictionary[PdfDictionaryProperties.encoding] - is PdfReferenceHolder) { - final IPdfPrimitive? primitive = PdfCrossTable.dereference( - fontDictionary[PdfDictionaryProperties.encoding], - ); - if (primitive != null && primitive is PdfDictionary) { - encodingDictionary = primitive; - } - } else if (fontDictionary[PdfDictionaryProperties.encoding] - is PdfDictionary) { - encodingDictionary = - fontDictionary[PdfDictionaryProperties.encoding] as PdfDictionary?; - } - - if (encodingDictionary != null) { - if (encodingDictionary.containsKey( - PdfDictionaryProperties.differences, - )) { - int differenceCount = 0; - final IPdfPrimitive? obj = - encodingDictionary[PdfDictionaryProperties.differences]; - PdfArray? differences; - if (obj is PdfArray) { - differences = obj; - } else if (obj is PdfReferenceHolder && obj.object is PdfArray) { - differences = obj.object as PdfArray?; - } - if (differences != null) { - for (int i = 0; i < differences.count; i++) { - String? text = ''; - if (differences[i] is PdfNumber) { - final PdfNumber number = differences[i]! as PdfNumber; - text = number.value.toString(); - differenceCount = number.value!.toInt(); - } else if (differences[i] is PdfName) { - text = (differences[i]! as PdfName).name; - if ((fontType!.name == 'Type1') && (text == '.notdef')) { - text = ' '; - differencesDictionary[differenceCount - .toString()] = getLatinCharacter(text); - differenceCount++; - } else { - text = getLatinCharacter(text); - text = getSpecialCharacter(text); - if (!differencesDictionary.containsKey( - differenceCount.toString(), - )) { - differencesDictionary[differenceCount - .toString()] = getLatinCharacter(text); - } - differenceCount++; - } - } - } - differences = null; - } - } - } - } - encodingDictionary = null; - return differencesDictionary; - } - - /// Gets Latin Character - /// Latin Character Set (APPENDIX D Pdf version-1.7) Page- 997 - String? getLatinCharacter(String? decodedCharacter) { - switch (decodedCharacter) { - case 'zero': - return '0'; - case 'one': - return '1'; - case 'two': - return '2'; - case 'three': - return '3'; - case 'four': - return '4'; - case 'five': - return '5'; - case 'six': - return '6'; - case 'seven': - return '7'; - case 'eight': - return '8'; - case 'nine': - return '9'; - case 'aacute': - return 'á'; - case 'asciicircum': - return '^'; - case 'asciitilde': - return '~'; - case 'asterisk': - return '*'; - case 'at': - return '@'; - case 'atilde': - return 'ã'; - case 'backslash': - return r'\'; - case 'bar': - return '|'; - case 'braceleft': - return '{'; - case 'braceright': - return '}'; - case 'bracketleft': - return '['; - case 'bracketright': - return ']'; - case 'breve': - return '˘'; - case 'brokenbar': - return '|'; - case 'bullet3': - return '•'; - case 'bullet': - return '•'; - case 'caron': - return 'ˇ'; - case 'ccedilla': - return 'ç'; - case 'cedilla': - return '¸'; - case 'cent': - return '¢'; - case 'circumflex': - return 'ˆ'; - case 'colon': - return ':'; - case 'comma': - return ','; - case 'copyright': - return '©'; - case 'currency1': - return '¤'; - case 'dagger': - return '†'; - case 'daggerdbl': - return '‡'; - case 'degree': - return '°'; - case 'dieresis': - return '¨'; - case 'divide': - return '÷'; - case 'dollar': - return r'$'; - case 'dotaccent': - return '˙'; - case 'dotlessi': - return 'ı'; - case 'eacute': - return 'é'; - case 'middot': - return '˙'; - case 'edieresis': - return 'ë'; - case 'egrave': - return 'è'; - case 'ellipsis': - return '...'; - case 'emdash': - return '—'; - case 'endash': - return '–'; - case 'equal': - return '='; - case 'eth': - return 'ð'; - case 'exclam': - return '!'; - case 'exclamdown': - return '¡'; - //case 'fi': - // return 'fl'; - case 'florin': - return 'ƒ'; - case 'fraction': - return '⁄'; - case 'germandbls': - return 'ß'; - case 'grave': - return '`'; - case 'greater': - return '>'; - case 'guillemotleft4': - return '«'; - case 'guillemotright4': - return '»'; - case 'guilsinglleft': - return '‹'; - case 'guilsinglright': - return '›'; - case 'hungarumlaut': - return '˝'; - case 'hyphen5': - return '-'; - case 'iacute': - return 'í'; - case 'icircumflex': - return 'î'; - case 'idieresis': - return 'ï'; - case 'igrave': - return 'ì'; - case 'less': - return '<'; - case 'logicalnot': - return '¬'; - case 'lslash': - return 'ł'; - case 'Lslash': - return 'Ł'; - case 'macron': - return '¯'; - case 'minus': - return '−'; - case 'mu': - return 'μ'; - case 'multiply': - return '×'; - case 'ntilde': - return 'ñ'; - case 'numbersign': - return '#'; - case 'oacute': - return 'ó'; - case 'ocircumflex': - return 'ô'; - case 'odieresis': - return 'ö'; - case 'oe': - return 'oe'; - case 'ogonek': - return '˛'; - case 'ograve': - return 'ò'; - case 'onehalf': - return '1/2'; - case 'onequarter': - return '1/4'; - case 'onesuperior': - return '¹'; - case 'ordfeminine': - return 'ª'; - case 'ordmasculine': - return 'º'; - case 'otilde': - return 'õ'; - case 'paragraph': - return '¶'; - case 'parenleft': - return '('; - case 'parenright': - return ')'; - case 'percent': - return '%'; - case 'period': - return '.'; - case 'periodcentered': - return '·'; - case 'perthousand': - return '‰'; - case 'plus': - return '+'; - case 'plusminus': - return '±'; - case 'question': - return '?'; - case 'questiondown': - return '¿'; - case 'quotedbl': - return '"'; - case 'quotedblbase': - return '„'; - case 'quotedblleft': - return '“'; - case 'quotedblright': - return '”'; - case 'quoteleft': - return '‘'; - case 'quoteright': - return '’'; - case 'quotesinglbase': - return '‚'; - case 'quotesingle': - return "'"; - case 'registered': - return '®'; - case 'ring': - return '˚'; - case 'scaron': - return 'š'; - case 'section': - return '§'; - case 'semicolon': - return ';'; - case 'slash': - return '/'; - case 'space6': - return ' '; - case 'space': - return ' '; - case 'udieresis': - return 'ü'; - case 'uacute': - return 'ú'; - case 'Ecircumflex': - return 'Ê'; - case 'hyphen': - return '-'; - case 'underscore': - return '_'; - case 'adieresis': - return 'ä'; - case 'ampersand': - return '&'; - case 'Adieresis': - return 'Ä'; - case 'Udieresis': - return 'Ü'; - case 'ccaron': - return 'č'; - case 'Scaron': - return 'Š'; - case 'zcaron': - return 'ž'; - case 'sterling': - return '£'; - case 'agrave': - return 'à'; - case 'ecircumflex': - return 'ê'; - case 'acircumflex': - return 'â'; - case 'Oacute': - return 'Ó'; - default: - return decodedCharacter; - } - } - - /// Gets Latin Character - /// Latin Character Set (APPENDIX D Pdf version-1.7) Page- 997 - String? getSpecialCharacter(String? decodedCharacter) { - switch (decodedCharacter) { - case 'head2right': - return '\u27A2'; - case 'aacute': - return 'a\u0301'; - case 'eacute': - return 'e\u0301'; - case 'iacute': - return 'i\u0301'; - case 'oacute': - return 'o\u0301'; - case 'uacute': - return 'u\u0301'; - case 'circleright': - return '\u27B2'; - case 'bleft': - return '\u21E6'; - case 'bright': - return '\u21E8'; - case 'bup': - return '\u21E7'; - case 'bdown': - return '\u21E9'; - case 'barb4right': - return '\u2794'; - case 'bleftright': - return '\u2B04'; - case 'bupdown': - return '\u21F3'; - case 'bnw': - return '\u2B00'; - case 'bne': - return '\u2B01'; - case 'bsw': - return '\u2B03'; - case 'bse': - return '\u2B02'; - case 'bdash1': - return '\u25AD'; - case 'bdash2': - return '\u25AB'; - case 'xmarkbld': - return '\u2717'; - case 'checkbld': - return '\u2713'; - case 'boxxmarkbld': - return '\u2612'; - case 'boxcheckbld': - return '\u2611'; - case 'space': - return '\u0020'; - case 'pencil': - return '\u270F'; - case 'scissors': - return '\u2702'; - case 'scissorscutting': - return '\u2701'; - case 'readingglasses': - return '\u2701'; - case 'bell': - return '\u2701'; - case 'book': - return '\u2701'; - case 'telephonesolid': - return '\u2701'; - case 'telhandsetcirc': - return '\u2701'; - case 'envelopeback': - return '\u2701'; - case 'hourglass': - return '\u231B'; - case 'keyboard': - return '\u2328'; - case 'tapereel': - return '\u2707'; - case 'handwrite': - return '\u270D'; - case 'handv': - return '\u270C'; - case 'handptleft': - return '\u261C'; - case 'handptright': - return '\u261E'; - case 'handptup': - return '\u261D'; - case 'handptdown': - return '\u261F'; - case 'smileface': - return '\u263A'; - case 'frownface': - return '\u2639'; - case 'skullcrossbones': - return '\u2620'; - case 'flag': - return '\u2690'; - case 'pennant': - return '\u1F6A9'; - case 'airplane': - return '\u2708'; - case 'sunshine': - return '\u263C'; - case 'droplet': - return '\u1F4A7'; - case 'snowflake': - return '\u2744'; - case 'crossshadow': - return '\u271E'; - case 'crossmaltese': - return '\u2720'; - case 'starofdavid': - return '\u2721'; - case 'crescentstar': - return '\u262A'; - case 'yinyang': - return '\u262F'; - case 'om': - return '\u0950'; - case 'wheel': - return '\u2638'; - case 'aries': - return '\u2648'; - case 'taurus': - return '\u2649'; - case 'gemini': - return '\u264A'; - case 'cancer': - return '\u264B'; - case 'leo': - return '\u264C'; - case 'virgo': - return '\u264D'; - case 'libra': - return '\u264E'; - case 'scorpio': - return '\u264F'; - case 'saggitarius': - return '\u2650'; - case 'capricorn': - return '\u2651'; - case 'aquarius': - return '\u2652'; - case 'pisces': - return '\u2653'; - case 'ampersanditlc': - return '\u0026'; - case 'ampersandit': - return '\u0026'; - case 'circle6': - return '\u25CF'; - case 'circleshadowdwn': - return '\u274D'; - case 'square6': - return '\u25A0'; - case 'box3': - return '\u25A1'; - case 'boxshadowdwn': - return '\u2751'; - case 'boxshadowup': - return '\u2752'; - case 'lozenge4': - return '\u2B27'; - case 'lozenge6': - return '\u29EB'; - case 'rhombus6': - return '\u25C6'; - case 'xrhombus': - return '\u2756'; - case 'rhombus4': - return '\u2B25'; - case 'clear': - return '\u2327'; - case 'escape': - return '\u2353'; - case 'command': - return '\u2318'; - case 'rosette': - return '\u2740'; - case 'rosettesolid': - return '\u273F'; - case 'quotedbllftbld': - return '\u275D'; - case 'quotedblrtbld': - return '\u275E'; - case '.notdef': - return '\u25AF'; - case 'zerosans': - return '\u24EA'; - case 'onesans': - return '\u2460'; - case 'twosans': - return '\u2461'; - case 'threesans': - return '\u2462'; - case 'foursans': - return '\u2463'; - case 'fivesans': - return '\u2464'; - case 'sixsans': - return '\u2465'; - case 'sevensans': - return '\u2466'; - case 'eightsans': - return '\u2467'; - case 'ninesans': - return '\u2468'; - case 'tensans': - return '\u2469'; - case 'zerosansinv': - return '\u24FF'; - case 'onesansinv': - return '\u2776'; - case 'twosansinv': - return '\u2777'; - case 'threesansinv': - return '\u2778'; - case 'foursansinv': - return '\u2779'; - case 'circle2': - return '\u00B7'; - case 'circle4': - return '\u2022'; - case 'square2': - return '\u25AA'; - case 'ring2': - return '\u25CB'; - case 'ringbutton2': - return '\u25C9'; - case 'target': - return '\u25CE'; - case 'square4': - return '\u25AA'; - case 'box2': - return '\u25FB'; - case 'crosstar2': - return '\u2726'; - case 'pentastar2': - return '\u2605'; - case 'hexstar2': - return '\u2736'; - case 'octastar2': - return '\u2734'; - case 'dodecastar3': - return '\u2739'; - case 'octastar4': - return '\u2735'; - case 'registercircle': - return '\u2316'; - case 'cuspopen': - return '\u27E1'; - case 'cuspopen1': - return '\u2311'; - case 'circlestar': - return '\u2605'; - case 'starshadow': - return '\u2730'; - case 'deleteleft': - return '\u232B'; - case 'deleteright': - return '\u2326'; - case 'scissorsoutline': - return '\u2704'; - case 'telephone': - return '\u260F'; - case 'telhandset': - return '\u1F4DE'; - case 'handptlft1': - return '\u261C'; - case 'handptrt1': - return '\u261E'; - case 'handptlftsld1': - return '\u261A'; - case 'handptrtsld1': - return '\u261B'; - case 'handptup1': - return '\u261D'; - case 'handptdwn1': - return '\u261F'; - case 'xmark': - return '\u2717'; - case 'check': - return '\u2713'; - case 'boxcheck': - return '\u2611'; - case 'boxx': - return '\u2612'; - case 'boxxbld': - return '\u2612'; - case 'circlex': - return '=\u2314'; - case 'circlexbld': - return '\u2314'; - case 'prohibit': - case 'prohibitbld': - return '\u29B8'; - case 'ampersanditaldm': - case 'ampersandbld': - case 'ampersandsans': - case 'ampersandsandm': - return '\u0026'; - case 'interrobang': - case 'interrobangdm': - case 'interrobangsans': - case 'interrobngsandm': - return '\u203D'; - case 'sacute': - return 'ś'; - case 'Sacute': - return 'Ś'; - case 'eogonek': - return 'ę'; - case 'cacute': - return 'ć'; - case 'aogonek': - return 'ą'; - default: - return decodedCharacter; - } - } - - /// internal method - void getMacEncodeTable() { - _macEncodeTable = {}; - _macEncodeTable![127] = ' '; - _macEncodeTable![128] = 'Ä'; - _macEncodeTable![129] = 'Å'; - _macEncodeTable![130] = 'Ç'; - _macEncodeTable![131] = 'É'; - _macEncodeTable![132] = 'Ñ'; - _macEncodeTable![133] = 'Ö'; - _macEncodeTable![134] = 'Ü'; - _macEncodeTable![135] = 'á'; - _macEncodeTable![136] = 'à'; - _macEncodeTable![137] = 'â'; - _macEncodeTable![138] = 'ä'; - _macEncodeTable![139] = 'ã'; - _macEncodeTable![140] = 'å'; - _macEncodeTable![141] = 'ç'; - _macEncodeTable![142] = 'é'; - _macEncodeTable![143] = 'è'; - _macEncodeTable![144] = 'ê'; - _macEncodeTable![145] = 'ë'; - _macEncodeTable![146] = 'í'; - _macEncodeTable![147] = 'ì'; - _macEncodeTable![148] = 'î'; - _macEncodeTable![149] = 'ï'; - _macEncodeTable![150] = 'ñ'; - _macEncodeTable![151] = 'ó'; - _macEncodeTable![152] = 'ò'; - _macEncodeTable![153] = 'ô'; - _macEncodeTable![154] = 'ö'; - _macEncodeTable![155] = 'õ'; - _macEncodeTable![156] = 'ú'; - _macEncodeTable![157] = 'ù'; - _macEncodeTable![158] = 'û'; - _macEncodeTable![159] = 'ü'; - _macEncodeTable![160] = '†'; - _macEncodeTable![161] = '°'; - _macEncodeTable![162] = '¢'; - _macEncodeTable![163] = '£'; - _macEncodeTable![164] = '§'; - _macEncodeTable![165] = '•'; - _macEncodeTable![166] = '¶'; - _macEncodeTable![167] = 'ß'; - _macEncodeTable![168] = '®'; - _macEncodeTable![169] = '©'; - _macEncodeTable![170] = '™'; - _macEncodeTable![171] = '´'; - _macEncodeTable![172] = '¨'; - _macEncodeTable![173] = '≠'; - _macEncodeTable![174] = 'Æ'; - _macEncodeTable![175] = 'Ø'; - _macEncodeTable![176] = '∞'; - _macEncodeTable![177] = '±'; - _macEncodeTable![178] = '≤'; - _macEncodeTable![179] = '≥'; - _macEncodeTable![180] = '¥'; - _macEncodeTable![181] = 'µ'; - _macEncodeTable![182] = '∂'; - _macEncodeTable![183] = '∑'; - _macEncodeTable![184] = '∏'; - _macEncodeTable![185] = 'π'; - _macEncodeTable![186] = '∫'; - _macEncodeTable![187] = 'ª'; - _macEncodeTable![188] = 'º'; - _macEncodeTable![189] = 'Ω'; - _macEncodeTable![190] = 'æ'; - _macEncodeTable![191] = 'ø'; - _macEncodeTable![192] = '¿'; - _macEncodeTable![193] = '¡'; - _macEncodeTable![194] = '¬'; - _macEncodeTable![195] = '√'; - _macEncodeTable![196] = 'ƒ'; - _macEncodeTable![197] = '≈'; - _macEncodeTable![198] = '∆'; - _macEncodeTable![199] = '«'; - _macEncodeTable![200] = '»'; - _macEncodeTable![201] = '…'; - _macEncodeTable![202] = ' '; - _macEncodeTable![203] = 'À'; - _macEncodeTable![204] = 'Ã'; - _macEncodeTable![205] = 'Õ'; - _macEncodeTable![206] = 'Œ'; - _macEncodeTable![207] = 'œ'; - _macEncodeTable![208] = '–'; - _macEncodeTable![209] = '—'; - _macEncodeTable![210] = '“'; - _macEncodeTable![211] = '”'; - _macEncodeTable![212] = '‘'; - _macEncodeTable![213] = '’'; - _macEncodeTable![214] = '÷'; - _macEncodeTable![215] = '◊'; - _macEncodeTable![216] = 'ÿ'; - _macEncodeTable![217] = 'Ÿ'; - _macEncodeTable![218] = '⁄'; - _macEncodeTable![219] = '€'; - _macEncodeTable![220] = '‹'; - _macEncodeTable![221] = '›'; - _macEncodeTable![222] = 'fi'; - _macEncodeTable![223] = 'fl'; - _macEncodeTable![224] = '‡'; - _macEncodeTable![225] = '·'; - _macEncodeTable![226] = ','; - _macEncodeTable![227] = '„'; - _macEncodeTable![228] = '‰'; - _macEncodeTable![229] = 'Â'; - _macEncodeTable![230] = 'Ê'; - _macEncodeTable![231] = 'Á'; - _macEncodeTable![232] = 'Ë'; - _macEncodeTable![233] = 'È'; - _macEncodeTable![234] = 'Í'; - _macEncodeTable![235] = 'Î'; - _macEncodeTable![236] = 'Ï'; - _macEncodeTable![237] = 'Ì'; - _macEncodeTable![238] = 'Ó'; - _macEncodeTable![239] = 'Ô'; - _macEncodeTable![240] = ''; - _macEncodeTable![241] = 'Ò'; - _macEncodeTable![242] = 'Ú'; - _macEncodeTable![243] = 'Û'; - _macEncodeTable![244] = 'Ù'; - _macEncodeTable![245] = 'ı'; - _macEncodeTable![246] = 'ˆ'; - _macEncodeTable![247] = '˜'; - _macEncodeTable![248] = '¯'; - _macEncodeTable![249] = '˘'; - _macEncodeTable![250] = '˙'; - _macEncodeTable![251] = '˚'; - _macEncodeTable![252] = '¸'; - _macEncodeTable![253] = '˝'; - _macEncodeTable![254] = '˛'; - _macEncodeTable![255] = 'ˇ'; - } - - /// internal method - String skipEscapeSequence(String text) { - if (text.contains(r'\')) { - final int i = text.indexOf(r'\'); - if (i + 1 != text.length) { - final String escapeSequence = text.substring(i + 1, i + 2); - switch (escapeSequence) { - case 'a': - text = text.replaceAll(r'\u0007', '\u0007'); - break; - case 'b': - text = text.replaceAll(r'\b', '\b'); - break; - case 'e': - text = text.replaceAll(r'\e', r'\e'); - break; - case 'f': - text = text.replaceAll(r'\f', '\f'); - break; - case 'n': - text = text.replaceAll(r'\n', '\n'); - break; - case 'r': - text = text.replaceAll(r'\r', '\r'); - break; - case 't': - text = text.replaceAll(r'\t', '\t'); - break; - case 'v': - text = text.replaceAll(r'\v', '\v'); - break; - case "'": - // ignore: use_raw_strings - text = text.replaceAll("\\'", "'"); - break; - default: - { - if (escapeSequence.codeUnitAt(0) == 3) { - text = text.replaceAll(r'\', r'\"'); - } else if (escapeSequence.codeUnitAt(0) >= 127) { - text = text.replaceAll(r'\', ''); - } else { - try { - text = unescape(text); - } catch (e) { - if (text.isNotEmpty) { - text = unescape(RegExp.escape(text)); - } else { - throw Exception(); - } - } - } - break; - } - } - } - } - return text; - } - - /// Organizes the hex string enclosed within the '<' '>' brackets - /// hexCode - Mapping string in the map table of the document - List getHexCode(String hexCode) { - final List tmp = []; - String tmpvalue = hexCode; - int startValue = 0; - int stopValue = 0; - String txtValue; - for (int j1 = 0; startValue >= 0; j1++) { - startValue = tmpvalue.indexOf('<'); - stopValue = tmpvalue.indexOf('>'); - if (startValue >= 0 && stopValue >= 0) { - txtValue = tmpvalue.substring(startValue + 1, stopValue); - tmp.add(txtValue); - tmpvalue = tmpvalue.substring(stopValue + 1, tmpvalue.length); - } - } - return tmp; - } - - /// internal method - String checkContainInvalidChar(String charvalue) { - for (int i = 0; i < charvalue.length; i++) { - switch (charvalue.codeUnitAt(i)) { - case 160: //No-break space - { - charvalue = ' '; - break; - } - case 61558: //Invalid Character - { - charvalue = ''; - break; - } - } - } - return charvalue; - } - - /// internal method - String decodeTextExtraction( - String textToDecode, - bool isSameFont, [ - List? charcodes, - ]) { - String decodedText = ''; - String encodedText = textToDecode; - this.isSameFont = isSameFont; - bool hasEscapeChar = false; - bool isHex = false; - switch (encodedText[0]) { - case '(': - { - while (encodedText.contains('\\\n')) { - final int n = encodedText.indexOf('\\\n'); - final List str = encodedText.split(''); - str.removeRange(n, n + 2); - encodedText = str.join(); - } - encodedText = encodedText.substring(1, encodedText.length - 1); - decodedText = getLiteralString(encodedText, charcodes); - // ignore: use_raw_strings - if (decodedText.contains('\\\\') && fontEncoding == 'Identity-H') { - hasEscapeChar = true; - decodedText = skipEscapeSequence(decodedText); - } - if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { - if (fontDictionary[PdfDictionaryProperties.encoding] is PdfName) { - if ([ - 'Identity-H', - 'UniCNS-UCS2-H', - 'UniKS-UCS2-H', - 'UniJIS-UCS2-H', - 'UniGB-UCS2-H', - ].contains( - (fontDictionary[PdfDictionaryProperties.encoding]! as PdfName) - .name, - )) { - String text = decodedText; - if (!hasEscapeChar) { - do { - text = skipEscapeSequence(text); - } while (hasEscapeCharacter(text)); - } - final List bytes = []; - for (int i = 0; i < text.length; i++) { - bytes.add(text[i].codeUnitAt(0).toUnsigned(8)); - } - decodedText = decodeBigEndian(bytes); - } - } - } - } - break; - case '[': - { - while (encodedText.contains('\\\n')) { - final int n = encodedText.indexOf('\\\n'); - final List str = encodedText.split(''); - str.removeRange(n, n + 2); - encodedText = str.join(); - } - encodedText = encodedText.substring(1, encodedText.length - 1); - while (encodedText.isNotEmpty) { - isHex = false; - int textStart = encodedText.indexOf('('); - int textEnd = encodedText.indexOf(')'); - final int textHexStart = encodedText.indexOf('<'); - final int textHexEnd = encodedText.indexOf('>'); - - if (textHexStart < textStart && textHexStart > -1) { - textStart = textHexStart; - textEnd = textHexEnd; - isHex = true; - } - if (textStart < 0) { - textStart = encodedText.indexOf('<'); - textEnd = encodedText.indexOf('>'); - if (textStart >= 0) { - isHex = true; - } else { - break; - } - } else if (textEnd > 0) { - while (encodedText[textEnd - 1] == r'\') { - if (encodedText.contains(')', textEnd + 1)) { - textEnd = encodedText.indexOf(')', textEnd + 1); - } else { - break; - } - } - } - - final String tempString = encodedText.substring( - textStart + 1, - textEnd, - ); - if (isHex) { - decodedText += getHexaDecimalString(tempString, charcodes); - } else { - decodedText += getLiteralString(tempString, charcodes); - } - - encodedText = encodedText.substring( - textEnd + 1, - encodedText.length, - ); - } - } - break; - case '<': - { - final String hexEncodedText = encodedText.substring( - 1, - encodedText.length - 1, - ); - decodedText = getHexaDecimalString(hexEncodedText, charcodes); - isHex = true; - } - break; - default: - break; - } - - if (fontEncoding != 'Identity-H' || - (fontEncoding == 'Identity-H') || - (fontEncoding == 'Identity-H' && containsCmap)) { - isMappingDone = true; - if (characterMapTable.isNotEmpty) { - decodedText = mapCharactersFromTable(decodedText, isHex); - } else if (differencesDictionary.isNotEmpty) { - decodedText = mapDifferences(decodedText); - } else if (fontEncoding != '') { - decodedText = skipEscapeSequence(decodedText); - } - } - - if (cidToGidTable != null && !isTextExtraction) { - decodedText = mapCidToGid(decodedText); - } - if (_fontName == 'ZapfDingbats' && !isEmbedded) { - decodedText = mapZapf(decodedText); - } - if (fontEncoding == 'MacRomanEncoding') { - macRomanEncoded = true; - String tempstring = ''; - for (int i = 0; i < decodedText.length; i++) { - final int b = decodedText[i].codeUnitAt(0).toUnsigned(8); - if (b > 126) { - final String x = macEncodeTable![b]!; - tempstring += x; - } else { - tempstring += decodedText[i]; - } - } - if (tempstring != '') { - decodedText = tempstring; - } - } - if (decodedText.contains('\u0092')) { - decodedText = decodedText.replaceAll('\u0092', '’'); - } - if (decodedText.contains(RegExp('[\n-\r]'))) { - decodedText = decodedText.replaceAll(RegExp('[\n-\r]'), '’'); - } - isWhiteSpace = decodedText.isEmpty || (decodedText.trimRight() == ''); - return decodedText; - } - - /// internal method - List decodeCjkTextExtractionTJ(String textToDecode, bool isSameFont) { - String decodedText = ''; - String encodedText = textToDecode; - String listElement; - this.isSameFont = isSameFont; - final List decodedList = []; - if (encodedText[0] == '[') { - while (encodedText.contains('\\\n')) { - final int n = encodedText.indexOf('\\\n'); - final List str = encodedText.split(''); - str.removeRange(n, n + 2); - encodedText = str.join(); - } - encodedText = encodedText.substring(1, encodedText.length - 1); - while (encodedText.isNotEmpty) { - bool isHex = false; - int textStart = encodedText.indexOf('('); - int textEnd = encodedText.indexOf(')'); - for (int j = textEnd + 1; j < encodedText.length; j++) { - if (encodedText[j] == '(') { - break; - } else if (encodedText[j] == ')') { - textEnd = j; - break; - } - } - final int textHexStart = encodedText.indexOf('<'); - final int textHexEnd = encodedText.indexOf('>'); - if (textHexStart < textStart && textHexStart > -1) { - textStart = textHexStart; - textEnd = textHexEnd; - isHex = true; - } - if (textStart < 0) { - textStart = encodedText.indexOf('<'); - textEnd = encodedText.indexOf('>'); - if (textStart >= 0) { - isHex = true; - } else { - listElement = encodedText; - decodedList.add(listElement); - break; - } - } - if (textEnd < 0 && encodedText.isNotEmpty) { - listElement = encodedText; - decodedList.add(listElement); - break; - } else if (textEnd > 0) { - while (encodedText[textEnd - 1] == r'\') { - if (textEnd - 1 > 0 && encodedText[textEnd - 2] == r'\') { - break; - } - if (encodedText.contains(')', textEnd + 1)) { - textEnd = encodedText.indexOf(')', textEnd + 1); - } else { - break; - } - } - } - if (textStart != 0) { - listElement = encodedText.substring(0, textStart); - decodedList.add(listElement); - } - final String tempString = encodedText.substring(textStart + 1, textEnd); - listElement = - isHex - ? getHexaDecimalCJKString(tempString) - : getLiteralString(tempString); - decodedText += listElement; - listElement = skipEscapeSequence(listElement); - if (listElement.isNotEmpty) { - if (listElement[0].codeUnitAt(0) >= 3584 && - listElement[0].codeUnitAt(0) <= 3711 && - decodedList.isNotEmpty) { - String previous = decodedList[0]; - previous = previous.replaceRange( - previous.length - 1, - previous.length, - '', - ); - previous += listElement; - listElement = previous; - decodedList[0] = '${fromUnicodeText(listElement)}s'; - } else if ((listElement[0].codeUnitAt(0) == 32 || - listElement[0].codeUnitAt(0) == 47) && - listElement.length > 1) { - if (listElement[1].codeUnitAt(0) >= 3584 && - listElement[1].codeUnitAt(0) <= 3711 && - decodedList.isNotEmpty) { - String previous = decodedList[0]; - previous = previous.replaceRange( - previous.length - 1, - previous.length, - '', - ); - previous += listElement; - listElement = previous; - decodedList[0] = '${fromUnicodeText(listElement)}s'; - } else { - listElement = '${fromUnicodeText(listElement)}s'; - decodedList.add(listElement); - } - } else { - listElement = '${fromUnicodeText(listElement)}s'; - decodedList.add(listElement); - } - } else { - listElement = '${fromUnicodeText(listElement)}s'; - decodedList.add(listElement); - } - encodedText = encodedText.substring(textEnd + 1, encodedText.length); - } - } - decodedText = skipEscapeSequence(decodedText); - isWhiteSpace = decodedText.isEmpty || (decodedText.trimRight() == ''); - return decodedList; - } - - /// internal method - String getHexaDecimalCJKString(String hexEncodedText) { - int index = 0; - String result = ''; - while (index < hexEncodedText.length) { - final String hex = hexEncodedText.substring(index, index + 2); - final int charCode = int.parse(hex, radix: 16); - result += String.fromCharCode(charCode); - index += 2; - } - return result; - } - - /// internal method - Map, String> decodeTextExtractionTJ( - String textToDecode, - bool isSameFont, - ) { - String decodedText = ''; - String encodedText = textToDecode; - String listElement; - List charCodes = []; - this.isSameFont = isSameFont; - final Map, String> decodedList = , String>{}; - switch (encodedText[0]) { - case '(': - { - while (encodedText.contains('\\\n')) { - final int n = encodedText.indexOf('\\\n'); - final List str = encodedText.split(''); - str.removeRange(n, n + 2); - encodedText = str.join(); - } - encodedText = encodedText.substring(1, encodedText.length - 1); - decodedText = getLiteralString(encodedText); - if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { - if (fontDictionary[PdfDictionaryProperties.encoding] is PdfName) { - if ((fontDictionary[PdfDictionaryProperties.encoding]! as PdfName) - .name == - 'Identity-H') { - final String text = skipEscapeSequence(decodedText); - - final List bytes = []; - for (int i = 0; i < text.length; i++) { - bytes.add(text[i].codeUnitAt(0).toUnsigned(8)); - } - decodedText = decodeBigEndian(bytes); - } - } - } - } - break; - case '[': - { - while (encodedText.contains('\\\n')) { - final int n = encodedText.indexOf('\\\n'); - final List str = encodedText.split(''); - str.removeRange(n, n + 2); - encodedText = str.join(); - } - encodedText = encodedText.substring(1, encodedText.length - 1); - while (encodedText.isNotEmpty) { - bool isHex = false; - int textStart = encodedText.indexOf('('); - int textEnd = encodedText.indexOf(')'); - for (int j = textEnd + 1; j < encodedText.length; j++) { - if (encodedText[j] == '(') { - break; - } else if (encodedText[j] == ')') { - textEnd = j; - break; - } - } - final int textHexStart = encodedText.indexOf('<'); - final int textHexEnd = encodedText.indexOf('>'); - if (textHexStart < textStart && textHexStart > -1) { - textStart = textHexStart; - textEnd = textHexEnd; - isHex = true; - } - if (textStart < 0) { - textStart = encodedText.indexOf('<'); - textEnd = encodedText.indexOf('>'); - if (textStart >= 0) { - isHex = true; - } else { - listElement = encodedText; - if (listElement.trim() != '') { - decodedList[charCodes] = listElement; - charCodes = []; - } - break; - } - } - if (textEnd < 0 && encodedText.isNotEmpty) { - listElement = encodedText; - if (listElement.trim() != '') { - decodedList[charCodes] = listElement; - charCodes = []; - } - break; - } else if (textEnd > 0) { - while (encodedText[textEnd - 1] == r'\') { - if (textEnd - 1 > 0 && encodedText[textEnd - 2] == r'\') { - break; - } - if (encodedText.contains(')', textEnd + 1)) { - textEnd = encodedText.indexOf(')', textEnd + 1); - } else { - break; - } - } - } - if (textStart != 0) { - listElement = encodedText.substring(0, textStart); - if (listElement.trim() != '') { - decodedList[charCodes] = listElement; - charCodes = []; - } - } - final String tempString = encodedText.substring( - textStart + 1, - textEnd, - ); - if (isHex) { - listElement = getHexaDecimalString(tempString, charCodes); - if (listElement.contains(r'\')) { - // ignore: use_raw_strings - listElement = listElement.replaceAll('\\', '\\\\'); - } - decodedText += listElement; - } else { - listElement = getLiteralString(tempString, charCodes); - decodedText += listElement; - } - if (listElement.contains('\u0000') && - !characterMapTable.containsKey(0)) { - listElement = listElement.replaceAll( - '\u0000', - '', - ); //replace empty character. - } - listElement = skipEscapeSequence(listElement); - if (fontEncoding != 'Identity-H' || - (fontEncoding == 'Identity-H') || - (fontEncoding == 'Identity-H' && containsCmap)) { - isMappingDone = true; - if (characterMapTable.isNotEmpty) { - listElement = mapCharactersFromTable(listElement, isHex); - } else if (differencesDictionary.isNotEmpty) { - listElement = mapDifferences(listElement); - } else if (fontEncoding != '') { - listElement = skipEscapeSequence(listElement); - } - } - if (cidToGidTable != null && !isTextExtraction) { - listElement = mapCidToGid(listElement); - } - if (!isLayout && - encodedText - .substring(textEnd + 1, encodedText.length) - .trim() - .isEmpty) { - listElement = listElement.trimRight(); - } - if (listElement.contains(RegExp('[\n-\r]'))) { - listElement = listElement.replaceAll(RegExp('[\n-\r]'), ''); - } - if (listElement.isNotEmpty) { - if (listElement[0].codeUnitAt(0) >= 3584 && - listElement[0].codeUnitAt(0) <= 3711 && - decodedList.isNotEmpty) { - String previous = decodedList.values.toList()[0]; - previous = previous.replaceRange( - previous.length - 1, - previous.length, - '', - ); - previous += listElement; - listElement = previous; - decodedList[decodedList.keys.toList()[0]] = '${listElement}s'; - } else if ((listElement[0].codeUnitAt(0) == 32 || - listElement[0].codeUnitAt(0) == 47) && - listElement.length > 1) { - if (listElement[1].codeUnitAt(0) >= 3584 && - listElement[1].codeUnitAt(0) <= 3711 && - decodedList.isNotEmpty) { - String previous = decodedList.values.toList()[0]; - previous = previous.replaceRange( - previous.length - 1, - previous.length, - '', - ); - previous += listElement; - listElement = previous; - decodedList[decodedList.keys.toList()[0]] = '${listElement}s'; - } else { - listElement += 's'; - decodedList[charCodes] = listElement; - charCodes = []; - } - } else { - listElement += 's'; - decodedList[charCodes] = listElement; - charCodes = []; - } - } else { - listElement = '${listElement.trimRight()}s'; - decodedList[charCodes] = listElement; - charCodes = []; - } - encodedText = encodedText.substring( - textEnd + 1, - encodedText.length, - ); - } - } - break; - case '<': - { - final String hexEncodedText = encodedText.substring( - 1, - encodedText.length - 1, - ); - decodedText = getHexaDecimalString(hexEncodedText, charCodes); - } - break; - default: - break; - } - decodedText = skipEscapeSequence(decodedText); - isWhiteSpace = - decodedText.isEmpty || - (!decodedText.contains(RegExp(r'[\f\r]')) && - decodedText.trimRight().isEmpty); - return decodedList; - } - - /// internal method - String fromUnicodeText(String value) { - String result = ''; - if (value.length % 2 != 0) { - for (int i = 0; i < value.length; i++) { - if (i + 1 < value.length) { - result += String.fromCharCode( - (value.codeUnitAt(i) * 256) + value.codeUnitAt(i + 1), - ); - i++; - } else { - result += String.fromCharCode(value.codeUnitAt(i)); - } - } - } else { - for (int i = 0; i < value.length; i++) { - result += String.fromCharCode( - (value.codeUnitAt(i) * 256) + value.codeUnitAt(i + 1), - ); - i++; - } - } - isWhiteSpace = result.isEmpty || result.trimRight() == ''; - return result; - } - - /// internal method - String getEncodedText(String textElement, bool isSameFont) { - String encodedText = ''; - String textToEncode = textElement; - this.isSameFont = isSameFont; - bool hasEscapeChar = false; - switch (textToEncode[0]) { - case '(': - { - if (textToEncode.contains('\\\n')) { - final int n = textToEncode.indexOf('\\\n'); - final List str = textToEncode.split(''); - str.removeRange(n, n + 2); - textToEncode = str.join(); - } - textToEncode = textToEncode.substring(1, textToEncode.length - 1); - encodedText = getLiteralString(textToEncode); - // ignore: use_raw_strings - if (encodedText.contains('\\\\') && fontEncoding == 'Identity-H') { - hasEscapeChar = true; - encodedText = skipEscapeSequence(encodedText); - } - if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { - final IPdfPrimitive? primitive = - fontDictionary[PdfDictionaryProperties.encoding]; - if (primitive is PdfName) { - final String? encoding = primitive.name; - if (encoding == 'Identity-H') { - String text = encodedText; - if (!hasEscapeChar) { - if (text.contains(r'\a') || - text.contains(r'\') || - text.contains(r'\b') || - text.contains(r'\f') || - text.contains(r'\r') || - text.contains(r'\t') || - text.contains(r'\n') || - text.contains(r'\v') || - // ignore: avoid_escaping_inner_quotes - text.contains('\\\'')) { - while (text.contains(r'\a') || - text.contains(r'\') || - text.contains(r'\b') || - text.contains(r'\f') || - text.contains(r'\r') || - text.contains(r'\t') || - text.contains(r'\n') || - text.contains(r'\v') || - // ignore: avoid_escaping_inner_quotes - text.contains('\\\'')) { - text = skipEscapeSequence(text); - } - } else { - text = skipEscapeSequence(text); - } - } - final List bytes = []; - for (int i = 0; i < text.length; i++) { - bytes.add(text.codeUnitAt(0).toUnsigned(8)); - } - if (encoding == 'Identity-H') { - encodedText = decodeBigEndian(bytes); - } - if (encodedText.contains(r'\')) { - // ignore: use_raw_strings - encodedText = encodedText.replaceAll('\\', '\\\\'); - } - } - } - } - } - break; - case '[': - { - if (textToEncode.contains('\\\n')) { - final int n = textToEncode.indexOf('\\\n'); - final List str = textToEncode.split(''); - str.removeRange(n, n + 2); - textToEncode = str.join(); - } - textToEncode = textToEncode.substring(1, textToEncode.length - 1); - while (textToEncode.isNotEmpty) { - bool isHex = false; - int textStart = textToEncode.indexOf('('); - int textEnd = textToEncode.indexOf(')'); - final int textHexStart = textToEncode.indexOf('<'); - final int textHexEnd = textToEncode.indexOf('>'); - for (int j = textEnd + 1; j < textToEncode.length; j++) { - if (textToEncode[j] == '(') { - break; - } else if (textToEncode[j] == ')') { - textEnd = j; - break; - } - } - if (textHexStart < textStart && textHexStart > -1) { - textStart = textHexStart; - textEnd = textHexEnd; - isHex = true; - } - if (textStart < 0) { - textStart = textToEncode.indexOf('<'); - textEnd = textToEncode.indexOf('>'); - if (textStart >= 0) { - isHex = true; - } else { - break; - } - } else if (textEnd > 0) { - while (textToEncode[textEnd - 1] == r'\') { - if (textToEncode.contains(')', textEnd + 1)) { - textEnd = textToEncode.indexOf(')', textEnd + 1); - } else { - break; - } - } - } - final String tempString = textToEncode.substring( - textStart + 1, - textEnd, - ); - if (isHex) { - encodedText += getHexaDecimalString(tempString); - } else if (!isHex && fontEncoding == 'Identity-H') { - encodedText += getRawString(tempString); - } else { - encodedText += getLiteralString(tempString); - } - textToEncode = textToEncode.substring( - textEnd + 1, - textToEncode.length, - ); - } - } - break; - case '<': - { - final String hexEncodedText = textToEncode.substring( - 1, - textToEncode.length - 1, - ); - encodedText = getHexaDecimalString(hexEncodedText); - if (encodedText.contains(r'\')) { - // ignore: use_raw_strings - encodedText = encodedText.replaceAll('\\', '\\\\'); - } - } - break; - default: - break; - } - if (encodedText.contains('\u0000') && - characterMapTable.isNotEmpty && - !characterMapTable.containsKey('\u0000'.codeUnitAt(0))) { - encodedText = encodedText.replaceAll('\u0000', ''); - } - if (!isTextExtraction) { - encodedText = skipEscapeSequence(encodedText); - } - isWhiteSpace = - encodedText.isEmpty || - (!encodedText.contains(RegExp(r'[\f\r]')) && - encodedText.trimRight().isEmpty); - return encodedText; - } - - /// internal method - bool isCIDFontType() { - bool iscid = false; - if (fontDictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { - IPdfPrimitive? primitive = - fontDictionary[PdfDictionaryProperties.descendantFonts]; - if (primitive is PdfReferenceHolder) { - final PdfReferenceHolder descendantFontArrayReference = primitive; - primitive = descendantFontArrayReference.object; - if (primitive is PdfArray) { - final PdfArray descendantFontArray = primitive; - if (descendantFontArray.count > 0 && - descendantFontArray[0] is PdfReferenceHolder) { - primitive = (descendantFontArray[0]! as PdfReferenceHolder).object; - if (primitive is PdfDictionary) { - final PdfDictionary descendantDictionary = primitive; - if (descendantDictionary.containsKey( - PdfDictionaryProperties.subtype, - )) { - primitive = - descendantDictionary[PdfDictionaryProperties.subtype]; - if (primitive is PdfName) { - final PdfName subtype = - descendantDictionary[PdfDictionaryProperties.subtype]! - as PdfName; - if (subtype.name == 'CIDFontType2' || - subtype.name == 'CIDFontType0') { - iscid = true; - } - } - } - } - } - } - } else if (primitive is PdfArray) { - final PdfArray descendantFontArray = primitive; - if (descendantFontArray.count > 0 && - descendantFontArray[0] is PdfReferenceHolder) { - primitive = (descendantFontArray[0]! as PdfReferenceHolder).object; - if (primitive is PdfDictionary) { - final PdfDictionary descendantDictionary = primitive; - if (descendantDictionary.containsKey( - PdfDictionaryProperties.subtype, - )) { - primitive = descendantDictionary[PdfDictionaryProperties.subtype]; - if (primitive is PdfName) { - final PdfName subtype = - descendantDictionary[PdfDictionaryProperties.subtype]! - as PdfName; - if (subtype.name == 'CIDFontType2' || - subtype.name == 'CIDFontType0') { - iscid = true; - } - } - } - } - } - } - } - return iscid; - } - - /// internal method - String getRawString(String decodedText) { - String rawString = ''; - int charCode = 0; - bool isNonPrintable = false; - if (fontEncoding != null && fontEncoding == 'Identity-H' && isCid) { - for (int i = 0; i < decodedText.length; i++) { - final String rawChar = decodedText[i]; - final int codeUnit = decodedText.codeUnitAt(i); - if (codeUnit == 1) { - charCode = codeUnit; - rawString += rawChar; - } else if (rawChar == r'\') { - isNonPrintable = true; - rawString += r'\'; - } else if (isNonPrintable) { - String escapeChar = rawChar; - bool isEscapeCharacter = false; - switch (escapeChar) { - case 'n': - { - escapeChar = '\n'; - isEscapeCharacter = true; - break; - } - case 'b': - { - escapeChar = '\b'; - isEscapeCharacter = true; - break; - } - case 't': - { - escapeChar = '\t'; - isEscapeCharacter = true; - break; - } - case 'r': - { - escapeChar = '\r'; - isEscapeCharacter = true; - break; - } - case 'f': - { - escapeChar = '\f'; - isEscapeCharacter = true; - break; - } - default: - { - charCode = (charCode * 256) + codeUnit; - rawString += String.fromCharCode(charCode); - isNonPrintable = false; - charCode = 0; - } - break; - } - if (isEscapeCharacter) { - rawString += escapeChar; - isNonPrintable = false; - charCode = 0; - } - } else { - charCode = (charCode * 256) + codeUnit; - rawString += String.fromCharCode(charCode); - charCode = 0; - } - } - decodedText = rawString; - } - return decodedText; - } - - /// Takes in the decoded text and maps it with its - /// corresponding entry in the CharacterMapTable - String mapDifferences(String? encodedText) { - String decodedText = ''; - bool skip = false; - if (isTextExtraction) { - try { - encodedText = unescape(encodedText!); - } catch (e) { - if (encodedText != null && encodedText.isNotEmpty) { - encodedText = RegExp.escape( - encodedText, - ).replaceAll(r"\'''", r"'''").replaceAll(r'\\', r'\'); - } else { - throw ArgumentError(e.toString()); - } - } - } else { - skipEscapeSequence(encodedText!); - } - for (int i = 0; i < encodedText.length; i++) { - final int character = encodedText.codeUnitAt(i); - if (differencesDictionary.containsKey(character.toString())) { - final String tempString = differencesDictionary[character.toString()]!; - if ((tempString.length > 1) && - (fontType!.name != 'Type3') && - (!isTextExtraction)) { - decodedText += character.toString(); - } else { - if (!isTextExtraction) { - String textDecoded = differencesDictionary[character.toString()]!; - if (textDecoded.length == 7 && - textDecoded.toLowerCase().startsWith('uni')) { - textDecoded = String.fromCharCode( - int.parse(textDecoded.substring(3), radix: 16), - ); - } - decodedText += textDecoded; - } else { - if (!differencesDictionary.containsKey(character.toString())) { - final AdobeGlyphList glyphList = AdobeGlyphList(); - decodedText += glyphList.getUnicode(tempString)!; - glyphList.map!.clear(); - } else { - final String textDecoded = - differencesDictionary[character.toString()]!; - decodedText += textDecoded; - } - } - } - if (!reverseDictMapping.containsKey( - differencesDictionary[character.toString()], - )) { - reverseDictMapping[differencesDictionary[character.toString()]] = - character; - } - if (fontName == 'Wingdings') { - decodedText = mapDifferenceOfWingDings(decodedText); - } - - final String? specialCharacter = getSpecialCharacter(decodedText); - if (decodedText != specialCharacter && !isEmbedded) { - decodedText = decodedText.replaceAll(decodedText, specialCharacter!); - } - skip = false; - } else { - if (skip) { - switch (encodedText[i]) { - case 'n': - if (differencesDictionary.containsKey( - '\n'.codeUnitAt(0).toString(), - )) { - decodedText += - differencesDictionary['\n'.codeUnitAt(0).toString()]!; - } - break; - case 'r': - if (differencesDictionary.containsKey( - '\r'.codeUnitAt(0).toString(), - )) { - decodedText += - differencesDictionary['\r'.codeUnitAt(0).toString()]!; - } - break; - default: - break; - } - skip = false; - } else if (encodedText[i] == r'\') { - skip = true; - } else { - decodedText += encodedText[i]; - } - } - } - return decodedText; - } - - /// internal method - String mapZapf(String encodedText) { - String decodedtext = ''; - for (int i = 0; i < encodedText.length; i++) { - final int character = encodedText.codeUnitAt(i); - final String result = character.toRadixString(16); - switch (result.toUpperCase()) { - case '20': - decodedtext += '\u0020'; - zapfPostScript += 'space '; - break; - case '21': - decodedtext += '\u2701'; - zapfPostScript += 'a1 '; - break; - case '22': - decodedtext += '\u2702'; - zapfPostScript += 'a2 '; - break; - case '23': - decodedtext += '\u2703'; - zapfPostScript += 'a202 '; - break; - case '24': - decodedtext += '\u2704'; - zapfPostScript += 'a3 '; - break; - case '25': - decodedtext += '\u260E'; - zapfPostScript += 'a4 '; - break; - case '26': - decodedtext += '\u2706'; - zapfPostScript += 'a5 '; - break; - case '27': - decodedtext += '\u2707'; - zapfPostScript += 'a119 '; - break; - case '28': - decodedtext += '\u2708'; - zapfPostScript += 'a118 '; - break; - case '29': - decodedtext += '\u2709'; - zapfPostScript += 'a117 '; - break; - case '2A': - decodedtext += '\u261B'; - zapfPostScript += 'a11 '; - break; - case '2B': - decodedtext += '\u261E'; - zapfPostScript += 'a12 '; - break; - case '2C': - decodedtext += '\u270C'; - zapfPostScript += 'a13 '; - break; - case '2D': - decodedtext += '\u270D'; - zapfPostScript += 'a14 '; - break; - case '2E': - decodedtext += '\u270E'; - zapfPostScript += 'a15 '; - break; - case '2F': - decodedtext += '\u270F'; - zapfPostScript += 'a16 '; - break; - case '30': - decodedtext += '\u2710'; - zapfPostScript += 'a105 '; - break; - case '31': - decodedtext += '\u2711'; - zapfPostScript += 'a17 '; - break; - case '32': - decodedtext += '\u2712'; - zapfPostScript += 'a18 '; - break; - case '33': - decodedtext += '\u2713'; - zapfPostScript += 'a19 '; - break; - case '34': - decodedtext += '\u2714'; - zapfPostScript += 'a20 '; - break; - case '35': - decodedtext += '\u2715'; - zapfPostScript += 'a21 '; - break; - case '36': - decodedtext += '\u2716'; - zapfPostScript += 'a22 '; - break; - case '37': - decodedtext += '\u2717'; - zapfPostScript += 'a23 '; - break; - case '38': - decodedtext += '\u2718'; - zapfPostScript += 'a24 '; - break; - case '39': - decodedtext += '\u2719'; - zapfPostScript += 'a25 '; - break; - case '3A': - decodedtext += '\u271A'; - zapfPostScript += 'a26 '; - break; - case '3B': - decodedtext += '\u271B'; - zapfPostScript += 'a27 '; - break; - case '3C': - decodedtext += '\u271C'; - zapfPostScript += 'a28 '; - break; - case '3D': - decodedtext += '\u271D'; - zapfPostScript += 'a6 '; - break; - case '3E': - decodedtext += '\u271E'; - zapfPostScript += 'a7 '; - break; - case '3F': - decodedtext += '\u271F'; - zapfPostScript += 'a8 '; - break; - case '40': - decodedtext += '\u2720'; - zapfPostScript += 'a9 '; - break; - case '41': - decodedtext += '\u2721'; - zapfPostScript += 'a10 '; - break; - case '42': - decodedtext += '\u2722'; - zapfPostScript += 'a29 '; - break; - case '43': - decodedtext += '\u2723'; - zapfPostScript += 'a30 '; - break; - case '44': - decodedtext += '\u2724'; - zapfPostScript += 'a31 '; - break; - case '45': - decodedtext += '\u2725'; - zapfPostScript += 'a32 '; - break; - case '46': - decodedtext += '\u2726'; - zapfPostScript += 'a33 '; - break; - case '47': - decodedtext += '\u2727'; - zapfPostScript += 'a34 '; - break; - case '48': - decodedtext += '\u2605'; - zapfPostScript += 'a35 '; - break; - case '49': - decodedtext += '\u2729'; - zapfPostScript += 'a36 '; - break; - case '4A': - decodedtext += '\u272A'; - zapfPostScript += 'a37 '; - break; - case '4B': - decodedtext += '\u272B'; - zapfPostScript += 'a38 '; - break; - case '4C': - decodedtext += '\u272C'; - zapfPostScript += 'a39 '; - break; - case '4D': - decodedtext += '\u272D'; - zapfPostScript += 'a40 '; - break; - case '4E': - decodedtext += '\u272E'; - zapfPostScript += 'a41 '; - break; - case '4F': - decodedtext += '\u272F'; - zapfPostScript += 'a42 '; - break; - case '50': - decodedtext += '\u2730'; - zapfPostScript += 'a43 '; - break; - case '51': - decodedtext += '\u2731'; - zapfPostScript += 'a44 '; - break; - case '52': - decodedtext += '\u2732'; - zapfPostScript += 'a45 '; - break; - case '53': - decodedtext += '\u2733'; - zapfPostScript += 'a46 '; - break; - case '54': - decodedtext += '\u2734'; - zapfPostScript += 'a47 '; - break; - case '55': - decodedtext += '\u2735'; - zapfPostScript += 'a48 '; - break; - case '56': - decodedtext += '\u2736'; - zapfPostScript += 'a49 '; - break; - case '57': - decodedtext += '\u2737'; - zapfPostScript += 'a50 '; - break; - case '58': - decodedtext += '\u2738'; - zapfPostScript += 'a51 '; - break; - case '59': - decodedtext += '\u2739'; - zapfPostScript += 'a52 '; - break; - case '5A': - decodedtext += '\u273A'; - zapfPostScript += 'a53 '; - break; - case '5B': - decodedtext += '\u273B'; - zapfPostScript += 'a54 '; - break; - case '5C': - decodedtext += '\u273C'; - zapfPostScript += 'a55 '; - break; - case '5D': - decodedtext += '\u273D'; - zapfPostScript += 'a56 '; - break; - case '5E': - decodedtext += '\u273E'; - zapfPostScript += 'a57 '; - break; - case '5F': - decodedtext += '\u273F'; - zapfPostScript += 'a58 '; - break; - case '60': - decodedtext += '\u2740'; - zapfPostScript += 'a59 '; - break; - case '61': - decodedtext += '\u2741'; - zapfPostScript += 'a60 '; - break; - case '62': - decodedtext += '\u2742'; - zapfPostScript += 'a61 '; - break; - case '63': - decodedtext += '\u2743'; - zapfPostScript += 'a62 '; - break; - case '64': - decodedtext += '\u2744'; - zapfPostScript += 'a63 '; - break; - case '65': - decodedtext += '\u2745'; - zapfPostScript += 'a64 '; - break; - case '66': - decodedtext += '\u2746'; - zapfPostScript += 'a65 '; - break; - case '67': - decodedtext += '\u2747'; - zapfPostScript += 'a66 '; - break; - case '68': - decodedtext += '\u2748'; - zapfPostScript += 'a67 '; - break; - case '69': - decodedtext += '\u2749'; - zapfPostScript += 'a68 '; - break; - case '6A': - decodedtext += '\u274A'; - zapfPostScript += 'a69 '; - break; - case '6B': - decodedtext += '\u274B'; - zapfPostScript += 'a70 '; - break; - case '6C': - decodedtext += '\u25CF'; - zapfPostScript += 'a71 '; - break; - case '6D': - decodedtext += '\u254D'; - zapfPostScript += 'a72 '; - break; - case '6E': - decodedtext += '\u25A0'; - zapfPostScript += 'a73 '; - break; - case '6F': - decodedtext += '\u274F'; - zapfPostScript += 'a74 '; - break; - case '70': - decodedtext += '\u2750'; - zapfPostScript += 'a203 '; - break; - case '71': - decodedtext += '\u2751'; - zapfPostScript += 'a75 '; - break; - case '72': - decodedtext += '\u2752'; - zapfPostScript += 'a204 '; - break; - case '73': - decodedtext += '\u25B2'; - zapfPostScript += 'a76 '; - break; - case '74': - decodedtext += '\u25BC'; - zapfPostScript += 'a77 '; - break; - case '75': - decodedtext += '\u27C6'; - zapfPostScript += 'a78 '; - break; - case '76': - decodedtext += '\u2756'; - zapfPostScript += 'a79 '; - break; - case '77': - decodedtext += '\u25D7'; - zapfPostScript += 'a81 '; - break; - case '78': - decodedtext += '\u2758'; - zapfPostScript += 'a82 '; - break; - case '79': - decodedtext += '\u2759'; - zapfPostScript += 'a83 '; - break; - case '7A': - decodedtext += '\u275A'; - zapfPostScript += 'a84 '; - break; - case '7B': - decodedtext += '\u275B'; - zapfPostScript += 'a97 '; - break; - case '7C': - decodedtext += '\u275C'; - zapfPostScript += 'a98 '; - break; - case '7D': - decodedtext += '\u275D'; - zapfPostScript += 'a99 '; - break; - case '7E': - decodedtext += '\u275E'; - zapfPostScript += 'a100 '; - break; - case '80': - decodedtext += '\uF8D7'; - zapfPostScript += 'a89 '; - break; - case '81': - decodedtext += '\uF8D8'; - zapfPostScript += 'a90 '; - break; - case '82': - decodedtext += '\uF8D9'; - zapfPostScript += 'a93 '; - break; - case '83': - decodedtext += '\uF8DA'; - zapfPostScript += 'a94 '; - break; - case '84': - decodedtext += '\uF8DB'; - zapfPostScript += 'a91 '; - break; - case '85': - decodedtext += '\uF8DC'; - zapfPostScript += 'a92 '; - break; - case '86': - decodedtext += '\uF8DD'; - zapfPostScript += 'a205 '; - break; - case '87': - decodedtext += '\uF8DE'; - zapfPostScript += 'a85 '; - break; - case '88': - decodedtext += '\uF8DF'; - zapfPostScript += 'a206 '; - break; - case '89': - decodedtext += '\uF8E0'; - zapfPostScript += 'a86 '; - break; - case '8A': - decodedtext += '\uF8E1'; - zapfPostScript += 'a87 '; - break; - case '8B': - decodedtext += '\uF8E2'; - zapfPostScript += 'a88 '; - break; - case '8C': - decodedtext += '\uF8E3'; - zapfPostScript += 'a95 '; - break; - case '8D': - decodedtext += '\uF8E4'; - zapfPostScript += 'a96 '; - break; - case 'A1': - decodedtext += '\u2761'; - zapfPostScript += 'a101 '; - break; - case 'A2': - decodedtext += '\u2762'; - zapfPostScript += 'a102 '; - break; - case 'A3': - decodedtext += '\u2763'; - zapfPostScript += 'a103 '; - break; - case 'A4': - decodedtext += '\u2764'; - zapfPostScript += 'a104 '; - break; - case 'A5': - decodedtext += '\u2765'; - zapfPostScript += 'a106 '; - break; - case 'A6': - decodedtext += '\u2766'; - zapfPostScript += 'a107 '; - break; - case 'A7': - decodedtext += '\u2767'; - zapfPostScript += 'a108 '; - break; - case 'A8': - decodedtext += '\u2663'; - zapfPostScript += 'a112 '; - break; - case 'A9': - decodedtext += '\u2666'; - zapfPostScript += 'a111 '; - break; - case 'AA': - decodedtext += '\u2665'; - zapfPostScript += 'a110 '; - break; - case 'AB': - decodedtext += '\u2660'; - zapfPostScript += 'a109 '; - break; - case 'AC': - decodedtext += '\u2460'; - zapfPostScript += 'a120 '; - break; - case 'AD': - decodedtext += '\u2461'; - zapfPostScript += 'a121 '; - break; - case 'AE': - decodedtext += '\u2462'; - zapfPostScript += 'a122 '; - break; - case 'AF': - decodedtext += '\u2463'; - zapfPostScript += 'a123 '; - break; - case 'B0': - decodedtext += '\u2464'; - zapfPostScript += 'a124 '; - break; - case 'B1': - decodedtext += '\u2465'; - zapfPostScript += 'a125 '; - break; - case 'B2': - decodedtext += '\u2466'; - zapfPostScript += 'a126 '; - break; - case 'B3': - decodedtext += '\u2467'; - zapfPostScript += 'a127 '; - break; - case 'B4': - decodedtext += '\u2468'; - zapfPostScript += 'a128 '; - break; - case 'B5': - decodedtext += '\u2469'; - zapfPostScript += 'a129 '; - break; - case 'B6': - decodedtext += '\u2776'; - zapfPostScript += 'a130 '; - break; - case 'B7': - decodedtext += '\u2777'; - zapfPostScript += 'a131 '; - break; - case 'B8': - decodedtext += '\u2778'; - zapfPostScript += 'a132 '; - break; - case 'B9': - decodedtext += '\u2779'; - zapfPostScript += 'a133 '; - break; - case 'BA': - decodedtext += '\u277A'; - zapfPostScript += 'a134 '; - break; - case 'BB': - decodedtext += '\u277B'; - zapfPostScript += 'a135 '; - break; - case 'BC': - decodedtext += '\u277C'; - zapfPostScript += 'a136 '; - break; - case 'BD': - decodedtext += '\u277D'; - zapfPostScript += 'a137 '; - break; - case 'BE': - decodedtext += '\u277E'; - zapfPostScript += 'a138 '; - break; - case 'BF': - decodedtext += '\u277F'; - zapfPostScript += 'a139 '; - break; - case 'C0': - decodedtext += '\u2780'; - zapfPostScript += 'a140 '; - break; - case 'C1': - decodedtext += '\u2781'; - zapfPostScript += 'a141 '; - break; - case 'C2': - decodedtext += '\u2782'; - zapfPostScript += 'a142 '; - break; - case 'C3': - decodedtext += '\u2783'; - zapfPostScript += 'a143 '; - break; - case 'C4': - decodedtext += '\u2784'; - zapfPostScript += 'a144 '; - break; - case 'C5': - decodedtext += '\u2785'; - zapfPostScript += 'a145 '; - break; - case 'C6': - decodedtext += '\u2786'; - zapfPostScript += 'a146 '; - break; - case 'C7': - decodedtext += '\u2787'; - zapfPostScript += 'a147 '; - break; - case 'C8': - decodedtext += '\u2788'; - zapfPostScript += 'a148 '; - break; - case 'C9': - decodedtext += '\u2789'; - zapfPostScript += 'a149 '; - break; - case 'CA': - decodedtext += '\u278A'; - zapfPostScript += '150 '; - break; - case 'CB': - decodedtext += '\u278B'; - zapfPostScript += 'a151 '; - break; - case 'CC': - decodedtext += '\u278C'; - zapfPostScript += 'a152 '; - break; - case 'CD': - decodedtext += '\u278D'; - zapfPostScript += 'a153 '; - break; - case 'CE': - decodedtext += '\u278E'; - zapfPostScript += 'a154 '; - break; - case 'CF': - decodedtext += '\u278F'; - zapfPostScript += 'a155 '; - break; - case 'D0': - decodedtext += '\u2790'; - zapfPostScript += 'a156 '; - break; - case 'D1': - decodedtext += '\u2791'; - zapfPostScript += 'a157 '; - break; - case 'D2': - decodedtext += '\u2792'; - zapfPostScript += 'a158 '; - break; - case 'D3': - decodedtext += '\u2793'; - zapfPostScript += 'a159 '; - break; - case 'D4': - decodedtext += '\u2794'; - zapfPostScript += 'a160 '; - break; - case 'D5': - decodedtext += '\u2192'; - zapfPostScript += 'a161 '; - break; - case 'D6': - decodedtext += '\u2194'; - zapfPostScript += 'a163 '; - break; - case 'D7': - decodedtext += '\u2195'; - zapfPostScript += 'a164 '; - break; - case 'D8': - decodedtext += '\u2798'; - zapfPostScript += 'a196 '; - break; - case 'D9': - decodedtext += '\u2799'; - zapfPostScript += 'a165 '; - break; - case 'DA': - decodedtext += '\u279A'; - zapfPostScript += 'a192 '; - break; - case 'DB': - decodedtext += '\u279B'; - zapfPostScript += 'a166 '; - break; - case 'DC': - decodedtext += '\u279C'; - zapfPostScript += 'a167 '; - break; - case 'DD': - decodedtext += '\u279D'; - zapfPostScript += 'a168 '; - break; - case 'DE': - decodedtext += '\u279E'; - zapfPostScript += 'a169 '; - break; - case 'DF': - decodedtext += '\u279F'; - zapfPostScript += 'a170 '; - break; - case 'E0': - decodedtext += '\u27A0'; - zapfPostScript += 'a171 '; - break; - case 'E1': - decodedtext += '\u27A1'; - zapfPostScript += 'a172 '; - break; - case 'E2': - decodedtext += '\u27A2'; - zapfPostScript += 'a173 '; - break; - case 'E3': - decodedtext += '\u27A3'; - zapfPostScript += 'a162 '; - break; - case 'E4': - decodedtext += '\u27A4'; - zapfPostScript += 'a174 '; - break; - case 'E5': - decodedtext += '\u27A5'; - zapfPostScript += 'a175 '; - break; - case 'E6': - decodedtext += '\u27A6'; - zapfPostScript += 'a176 '; - break; - case 'E7': - decodedtext += '\u27A7'; - zapfPostScript += 'a177 '; - break; - case 'E8': - decodedtext += '\u27A8'; - zapfPostScript += 'a178 '; - break; - case 'E9': - decodedtext += '\u27A9'; - zapfPostScript += 'a179 '; - break; - case 'EA': - decodedtext += '\u27AA'; - zapfPostScript += 'a193 '; - break; - case 'EB': - decodedtext += '\u27AB'; - zapfPostScript += 'a180 '; - break; - case 'EC': - decodedtext += '\u27AC'; - zapfPostScript += 'a199 '; - break; - case 'ED': - decodedtext += '\u27AD'; - zapfPostScript += 'a181 '; - break; - case 'EE': - decodedtext += '\u27AE'; - zapfPostScript += 'a200 '; - break; - case 'EF': - decodedtext += '\u27AF'; - zapfPostScript += 'a182 '; - break; - case 'F1': - decodedtext += '\u27B1'; - zapfPostScript += 'a201 '; - break; - case 'F2': - decodedtext += '\u27B2'; - zapfPostScript += 'a183 '; - break; - case 'F3': - decodedtext += '\u27B3'; - zapfPostScript += 'a184 '; - break; - case 'F4': - decodedtext += '\u27B4'; - zapfPostScript += 'a197 '; - break; - case 'F5': - decodedtext += '\u27B5'; - zapfPostScript += 'a185 '; - break; - case 'F6': - decodedtext += '\u27B6'; - zapfPostScript += 'a194 '; - break; - case 'F7': - decodedtext += '\u27B7'; - zapfPostScript += 'a198 '; - break; - case 'F8': - decodedtext += '\u27B8'; - zapfPostScript += 'a186 '; - break; - case 'F9': - decodedtext += '\u27B9'; - zapfPostScript += 'a195 '; - break; - case 'FA': - decodedtext += '\u27BA'; - zapfPostScript += 'a187 '; - break; - case 'FB': - decodedtext += '\u27BB'; - zapfPostScript += 'a188 '; - break; - case 'FC': - decodedtext += '\u27BC'; - zapfPostScript += 'a189 '; - break; - case 'FD': - decodedtext += '\u27BD'; - zapfPostScript += 'a190 '; - break; - case 'FE': - decodedtext += '\u27BE'; - zapfPostScript += 'a191 '; - break; - - default: - if (reverseMapTable!.containsKey(encodedText)) { - decodedtext = encodedText; - final int charPosition = reverseMapTable![decodedtext]!.toInt(); - if (differenceTable.isNotEmpty && - differenceTable.containsKey(charPosition)) { - zapfPostScript = differenceTable[charPosition]!; - } - } else { - decodedtext = '\u2708'; - zapfPostScript = 'a118'; - } - break; - } - } - return decodedtext; - } - - /// internal method - String mapDifferenceOfWingDings(String decodedText) { - if (decodedText.length > 1 && decodedText.contains('c')) { - if (decodedText.indexOf('c') == 0) { - decodedText = decodedText.replaceAll(decodedText[0], ''); - int characterValue = 0; - try { - characterValue = int.parse(decodedText).toSigned(32); - } catch (e) { - characterValue = 0; - } - decodedText = String.fromCharCode(characterValue); - } - } - return decodedText; - } - - /// internal method - String mapCidToGid(String decodedText) { - String finalText = ''; - bool skip = false; - - for (int i = 0; i < decodedText.length; i++) { - final int character = decodedText.codeUnitAt(0); - if (cidToGidTable!.containsKey(character) && !skip) { - String mappingString = cidToGidTable![character]!; - if (mappingString.contains('�')) { - final int index = mappingString.indexOf('�'); - mappingString = mappingString.replaceAll(mappingString[index], ''); - } - if (mappingString.isNotEmpty) { - if (!cidToGidReverseMapTable.containsKey( - mappingString.codeUnitAt(0), - )) { - cidToGidReverseMapTable[mappingString.codeUnitAt(0)] = character; - } - } - finalText += mappingString; - skip = false; - } else if (tempMapTable.containsKey(character) && !skip) { - String mappingString = tempMapTable[character]!; - if (mappingString.contains('�')) { - final int index = mappingString.indexOf('�'); - mappingString = mappingString.replaceAll(mappingString[index], ''); - } - finalText += mappingString; - skip = false; - } else { - if (skip) { - switch (String.fromCharCode(character)) { - case 'n': - if (cidToGidTable!.containsKey(10)) { - finalText += characterMapTable[10]!; - } - break; - case 'r': - if (cidToGidTable!.containsKey(13)) { - finalText += characterMapTable[13]!; - } - break; - case 'b': - if (cidToGidTable!.containsKey(8)) { - finalText += characterMapTable[8]!; - } - break; - case 'a': - if (cidToGidTable!.containsKey(7)) { - finalText += characterMapTable[7]!; - } - break; - case 'f': - if (cidToGidTable!.containsKey(12)) { - finalText += characterMapTable[12]!; - } - break; - case 't': - if (cidToGidTable!.containsKey(9)) { - finalText += characterMapTable[9]!; - } - break; - case 'v': - if (cidToGidTable!.containsKey(11)) { - finalText += characterMapTable[11]!; - } - break; - case "'": - if (cidToGidTable!.containsKey(39)) { - finalText += characterMapTable[39]!; - } - break; - default: - { - if (cidToGidTable!.containsKey(character)) { - finalText += characterMapTable[character]!; - } - } - break; - } - skip = false; - } else if (decodedText[i] == r'\') { - skip = true; - } - } - } - return finalText; - } - - /// internal method - bool hasEscapeCharacter(String text) { - return text.contains(r'\u0007') || - text.contains(r'\') || - text.contains(r'\b') || - text.contains(r'\f') || - text.contains(r'\r') || - text.contains(r'\t') || - text.contains(r'\n') || - text.contains(r'\v') || - text.contains(r"\'") || - text.contains(r'\u0000'); - } - - /// Decodes the octal text in the encoded text. - String getLiteralString(String encodedText, [List? charCodes]) { - String decodedText = encodedText; - int octalIndex = -1; - int limit = 3; - bool isMacCharProcessed = false; - bool isWinAnsiProcessed = false; - final List octalIndexCollection = []; - // ignore: use_raw_strings - while ((decodedText.contains(r'\') && (!decodedText.contains('\\\\'))) || - decodedText.contains('\u0000')) { - String octalText = ''; - if (decodedText.contains(r'\', octalIndex + 1)) { - octalIndex = decodedText.indexOf(r'\', octalIndex + 1); - } else { - octalIndex = decodedText.indexOf('\u0000', octalIndex + 1); - if (octalIndex < 0) { - break; - } - limit = 2; - } - for ( - int i = octalIndex + 1; - i <= octalIndex + limit; - i++ - ) //check for octal characters - { - if (i < decodedText.length) { - int val = 0; - try { - val = int.parse(decodedText[i]).toSigned(32); - if (val <= 8) { - octalText += decodedText[i]; - } - } on Exception { - octalText = ''; - break; - } - } else { - octalText = ''; - } - } - - if (octalText != '') { - final int decimalValue = int.parse(octalText, radix: 8).toUnsigned(64); - String temp = ''; - final String decodedChar = String.fromCharCode(decimalValue); - if (characterMapTable.isNotEmpty) { - temp = decodedChar; - } else if (differencesDictionary.isNotEmpty && - differencesDictionary.containsKey(decimalValue.toString())) { - temp = decodedChar; - } else { - if (fontEncoding != 'MacRomanEncoding') { - final List charbytes = [decimalValue.toUnsigned(8)]; - temp = _getWindows1252DecodedText(charbytes); - List tempchar; - tempchar = [ - _getWindows1252DecodedText([decimalValue.toUnsigned(8)]), - ]; - int charvalue = 0; - for (final String tempchar1 in tempchar) { - charvalue = tempchar1.codeUnitAt(0); - } - if (!octDecMapTable.containsKey(charvalue)) { - octDecMapTable[charvalue] = decimalValue; - } - isWinAnsiProcessed = true; - } else { - final List charbytes = [decimalValue.toUnsigned(8)]; - temp = String.fromCharCodes(charbytes); - final List tempchar = [ - String.fromCharCodes([decimalValue.toUnsigned(8)]), - ]; - int charvalue = 0; - for (final String tempchar1 in tempchar) { - charvalue = tempchar1.codeUnitAt(0); - } - if (!octDecMapTable.containsKey(charvalue)) { - octDecMapTable[charvalue] = decimalValue; - } - isMacCharProcessed = true; - } - } - (charCodes ??= []).add(decimalValue); - decodedText = decodedText.replaceRange( - octalIndex, - octalIndex + limit + 1, - '', - ); - final List str = decodedText.split(''); - str.insert(octalIndex, temp); - octalIndexCollection.add(octalIndex); - decodedText = str.join(); - } - } - final List str = decodedText.split(''); - int count = str.length; - if (octalIndexCollection.length != str.length) { - final Map escapeSequence = { - 'b': '\b', - 'e': r'\e', - 'f': '\f', - 'n': '\n', - 'r': '\r', - 't': '\t', - 'v': '\v', - "'": "'", - }; - if (decodedText.contains(r'\')) { - for (int i = count - 2; i >= 0; i--) { - if (str[i] == r'\') { - final String sequence = str[i + 1]; - if (escapeSequence.containsKey(sequence)) { - str.removeAt(i + 1); - str[i] = escapeSequence[sequence]!; - //Re-initializes octal index based on escape sequence. - for (int j = 0; j < octalIndexCollection.length; j++) { - if (octalIndexCollection[j] > i) { - octalIndexCollection[j] = octalIndexCollection[j] - 1; - } - } - //Update the octal index collection and char codes, - //if character map table contains the escape sequence. - for (int j = 0; j < octalIndexCollection.length; j++) { - if (characterMapTable.containsKey( - escapeSequence[sequence]!.codeUnitAt(0), - )) { - if (i < octalIndexCollection[j]) { - octalIndexCollection.insert(j, i); - charCodes!.insert( - j, - escapeSequence[sequence]!.codeUnitAt(0), - ); - break; - } else if (j == octalIndexCollection.length - 1 && - i > octalIndexCollection[j]) { - octalIndexCollection.add(i); - charCodes!.add(escapeSequence[sequence]!.codeUnitAt(0)); - break; - } - } else { - break; - } - } - count--; - } - } - } - } - escapeSequence.clear(); - } - int combinedGlyphDiff = 0; - for (int i = 0; i < count; i++) { - if (!octalIndexCollection.contains(i)) { - if (characterMapTable.containsKey(str[i].codeUnitAt(0))) { - (charCodes ??= []).insert( - i + combinedGlyphDiff, - str[i].codeUnitAt(0), - ); - } else { - (charCodes ??= []).insert(i + combinedGlyphDiff, 0); - } - } else if (characterMapTable.containsKey(str[i].codeUnitAt(0))) { - final String mappingString = characterMapTable[str[i].codeUnitAt(0)]!; - final int mappingStringLength = mappingString.length; - if (mappingStringLength > 1) { - for (int j = i + 1; j < i + mappingStringLength; j++) { - charCodes!.insert(j + combinedGlyphDiff, 'combined'); - } - combinedGlyphDiff += mappingStringLength - 1; - } - } - } - if (decodedText.contains(r'\') && fontEncoding != 'Identity-H') { - if (decodedText.length > 1) { - final int index = decodedText.indexOf(r'\'); - final String char = decodedText[index + 1]; - if (char == '(' || char == ')') { - unescape(decodedText); - // ignore: use_raw_strings - } else if (!decodedText.contains('\\\\')) { - int initialLength = 0; - while ((decodedText.contains(r'\')) && - (decodedText.length != initialLength)) { - initialLength = decodedText.length; - decodedText = skipEscapeSequence(decodedText); - } - } - } - } - if ((fontEncoding == 'MacRomanEncoding') && (!isMacCharProcessed)) { - getMacEncodeTable(); - for (int i = 0; i < decodedText.length; i++) { - final int decimalValue = decodedText[i].codeUnitAt(0); - if (_macEncodeTable!.containsValue(decodedText[i])) { - if (!_macRomanMapTable.containsKey(decimalValue)) { - final int charbytes = decimalValue.toUnsigned(8); - _macRomanMapTable[decimalValue] = String.fromCharCode(charbytes); - } - } - } - } - if ((fontEncoding == 'WinAnsiEncoding') && (!isWinAnsiProcessed)) { - for (int i = 0; i < encodedText.length; i++) { - final int decimalValue = encodedText[i].codeUnitAt(0); - //// In WinAnsiEncoding, all unused codes greater than 40 map to the bullet character. - if (decimalValue == 127 || - decimalValue == 129 || - decimalValue == 131 || - decimalValue == 136 || - decimalValue == 141 || - decimalValue == 143 || - decimalValue == 144 || - decimalValue == 152 || - decimalValue == 157 || - decimalValue == 173 || - decimalValue == 209) { - final String mappedChar = String.fromCharCode(149); - if (!_winansiMapTable.containsKey(decimalValue)) { - _winansiMapTable[decimalValue] = mappedChar; - } - } - } - } - return decodedText; - } - - String _getWindows1252DecodedText(List charcodes) { - String result = ''; - // ignore: avoid_function_literals_in_foreach_calls - charcodes.forEach((int code) { - if (code >= 0 && code < 256) { - result += _windows1252MapTable[code]; - } - }); - return result; - } - - /// Decodes the HEX encoded string and returns Decoded string. - String getHexaDecimalString( - String hexEncodedText, [ - List? charCodes, - ]) { - String decodedText = ''; - // IsHexaDecimalString = true; - if (hexEncodedText.isNotEmpty) { - final PdfName fontType = - fontDictionary.items![PdfName('Subtype')]! as PdfName; - int limit = 2; - if (fontType.name != 'Type1' && - fontType.name != 'TrueType' && - fontType.name != 'Type3') { - limit = 4; - } - hexEncodedText = escapeSymbols(hexEncodedText); - final String tempHexEncodedText = hexEncodedText; - final String tempDecodedText = decodedText; - late String decodedTxt; - while (hexEncodedText.isNotEmpty) { - if (hexEncodedText.length % 4 != 0) { - limit = 2; - } - String hexChar = hexEncodedText.substring(0, limit); - - if (fontDictionary.containsKey( - PdfDictionaryProperties.descendantFonts, - ) && - !fontDictionary.containsKey(PdfDictionaryProperties.toUnicode)) { - final IPdfPrimitive? descendantArray = - fontDictionary[PdfDictionaryProperties.descendantFonts]; - if (descendantArray != null && descendantArray is PdfArray) { - PdfDictionary? descendantDictionary; - if (descendantArray[0] is PdfReferenceHolder) { - descendantDictionary = - (descendantArray[0]! as PdfReferenceHolder).object - as PdfDictionary?; - } else if (descendantArray[0] is PdfDictionary) { - descendantDictionary = descendantArray[0]! as PdfDictionary; - } - if (descendantDictionary != null) { - PdfDictionary? descriptorDictionary; - if (descendantDictionary.containsKey( - PdfDictionaryProperties.fontDescriptor, - )) { - IPdfPrimitive? primitive = - descendantDictionary[PdfDictionaryProperties - .fontDescriptor]; - if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfDictionary) { - descriptorDictionary = primitive; - } - } else if (primitive is PdfDictionary) { - descriptorDictionary = primitive; - } - } - if (descriptorDictionary != null) { - if (descendantDictionary.containsKey( - PdfDictionaryProperties.subtype, - ) && - !descriptorDictionary.containsKey( - PdfDictionaryProperties.fontFile2, - )) { - final PdfName subtype = - descendantDictionary[PdfDictionaryProperties.subtype]! - as PdfName; - if (subtype.name == 'CIDFontType2') { - hexChar = mapHebrewCharacters(hexChar); - } - } - } - } - } else if (fontDictionary.items!.containsKey( - PdfName(PdfDictionaryProperties.descendantFonts), - )) { - final PdfReferenceHolder? descendantFontArrayReference = - fontDictionary.items![PdfName( - PdfDictionaryProperties.descendantFonts, - )] - as PdfReferenceHolder?; - if (descendantFontArrayReference != null) { - PdfName? subtype; - final PdfArray descendantFontArray = - descendantFontArrayReference.object! as PdfArray; - if (descendantFontArray[0] is PdfReferenceHolder) { - final PdfDictionary? descendantDictionary = - (descendantFontArray[0]! as PdfReferenceHolder).object - as PdfDictionary?; - if (descendantDictionary != null && - descendantDictionary.containsKey( - PdfDictionaryProperties.cidSystemInfo, - ) && - descendantDictionary.containsKey( - PdfDictionaryProperties.subtype, - )) { - subtype = - descendantDictionary[PdfDictionaryProperties.subtype] - as PdfName?; - final PdfDictionary? cidSystemInfo = - (descendantDictionary[PdfDictionaryProperties - .cidSystemInfo]! - as PdfReferenceHolder) - .object - as PdfDictionary?; - if (cidSystemInfo != null && - cidSystemInfo.containsKey( - PdfDictionaryProperties.registry, - ) && - cidSystemInfo.containsKey( - PdfDictionaryProperties.ordering, - ) && - cidSystemInfo.containsKey( - PdfDictionaryProperties.supplement, - )) { - final PdfString pdfRegistry = - cidSystemInfo[PdfDictionaryProperties.registry]! - as PdfString; - final PdfNumber? pdfSupplement = - cidSystemInfo[PdfDictionaryProperties.supplement] - as PdfNumber?; - final PdfString? pdfOrdering = - cidSystemInfo[PdfDictionaryProperties.ordering] - as PdfString?; - if (pdfRegistry.value != null && - pdfSupplement!.value != null && - pdfOrdering!.value != null) { - if (pdfRegistry.value == 'Adobe' && - pdfOrdering.value == 'Identity' && - pdfSupplement.value == 0 && - subtype!.name == 'CIDFontType2' && - cidSystemInfoDictionary == null && - !isContainFontfile2) { - isAdobeIdentity = true; - hexChar = mapIdentityCharacters(hexChar); - } - } - } - } - } - } - } - } - final int hexNum = int.parse(hexChar, radix: 16).toSigned(64); - (charCodes ??= []).add(hexNum); - decodedText += String.fromCharCode(hexNum); - hexEncodedText = hexEncodedText.substring(limit, hexEncodedText.length); - decodedTxt = decodedText; - } - if ((decodedTxt.contains('“') || - decodedTxt.contains('”') || - decodedTxt.contains('’')) && - tempHexEncodedText.length < limit) { - decodedText = tempDecodedText; - final int hexNum = int.parse( - tempHexEncodedText, - radix: 16, - ).toSigned(32); - (charCodes ??= []).add(hexNum); - hexEncodedText = String.fromCharCode(hexNum); - decodedText += hexEncodedText; - } - int combinedGlyphDiff = 0; - for (int i = 0; i < decodedText.length; i++) { - if (characterMapTable.containsKey(decodedText[i].codeUnitAt(0))) { - final String mappingString = - characterMapTable[decodedText[i].codeUnitAt(0)]!; - final int mappingStringLength = mappingString.length; - if (mappingStringLength > 1) { - for (int j = i + 1; j < i + mappingStringLength; j++) { - charCodes!.insert(j + combinedGlyphDiff, 'combined'); - } - combinedGlyphDiff += mappingStringLength - 1; - } - } - } - } - return decodedText; - } - - /// internal method - String mapHebrewCharacters(String hexChar) { - if (hexChar.substring(0, 2) == '02') { - int i = int.parse(hexChar); - i += 816; - hexChar = i.toRadixString(16); - } else if (hexChar.substring(0, 2) == '00') { - if (hexChar.substring(2, 3) == '0' || hexChar.substring(2, 3) == '1') { - int i = int.parse(hexChar); - i += 29; - hexChar = i.toRadixString(16); - } else { - int i = int.parse(hexChar); - i += 1335; - hexChar = i.toRadixString(16); - } - } - return hexChar; - } - - /// internal method - String mapIdentityCharacters(String hexChar) { - if (hexChar.substring(0, 2) == '00') { - if (hexChar.substring(2, 3) != '0' || hexChar.substring(2, 3) != '1') { - int i = int.parse(hexChar); - i += 29; - hexChar = i.toRadixString(16); - } else { - int i = int.parse(hexChar); - i += 1335; - hexChar = i.toRadixString(16); - } - } - return hexChar; - } - - /// Method to remove the new line character - String escapeSymbols(String text) { - while (text.contains('\n')) { - text = text.replaceAll('\n', ''); - } - return text; - } - - /// Takes in the decoded text and maps it with its - /// corresponding entry in the CharacterMapTable - String mapCharactersFromTable(String decodedText, [bool isHex = false]) { - String finalText = ''; - bool skip = false; - for (int i = 0; i < decodedText.length; i++) { - final String character = decodedText[i]; - if (characterMapTable.containsKey(character.codeUnitAt(0)) && !skip) { - String mappingString = characterMapTable[character.codeUnitAt(0)]!; - if (mappingString.contains('�')) { - mappingString = mappingString.replaceAll('�', ''); - if (fontName!.contains('ZapfDingbats')) { - mappingString = character; - } - } - if (fontEncoding != 'Identity-H' && - !isTextExtraction && - characterMapTable.length != reverseMapTable!.length) { - if (isCancel(mappingString) || - isNonPrintableCharacter( - character, - )) //Contains 'CANCEL' of ASCII value 24 - { - mappingString = character; - } - } - finalText += mappingString; - skip = false; - } else if (!characterMapTable.containsKey(character.codeUnitAt(0)) && - !skip && - !isHex) { - final List bytes = encodeBigEndian(character); - if (bytes[0] != 92) { - if (characterMapTable.containsKey(bytes[0])) { - finalText += characterMapTable[bytes[0]]!; - skip = false; - } - } - } else if (tempMapTable.containsKey(character.codeUnitAt(0)) && !skip) { - String? mappingString = tempMapTable[character.codeUnitAt(0)]; - if (character == r'\' && isTextExtraction) { - mappingString = ''; - } - if (mappingString!.contains('�')) { - final int index = mappingString.indexOf('�'); - mappingString = mappingString.replaceAll(mappingString[index], ''); - } - finalText += mappingString; - skip = false; - } else { - if (skip) { - switch (character) { - case 'n': - if (characterMapTable.containsKey(10)) { - finalText += characterMapTable[10]!; - } - break; - case 'r': - if (characterMapTable.containsKey(13)) { - finalText += characterMapTable[13]!; - } - break; - case 'b': - if (characterMapTable.containsKey(8)) { - finalText += characterMapTable[8]!; - } - break; - case 'a': - if (characterMapTable.containsKey(7)) { - finalText += characterMapTable[7]!; - } - break; - case 'f': - if (characterMapTable.containsKey(12)) { - finalText += characterMapTable[12]!; - } - break; - case 't': - if (characterMapTable.containsKey(9)) { - finalText += characterMapTable[9]!; - } - break; - case 'v': - if (characterMapTable.containsKey(11)) { - finalText += characterMapTable[11]!; - } - break; - case "'": - if (characterMapTable.containsKey(39)) { - finalText += characterMapTable[39]!; - } - break; - default: - { - if (characterMapTable.containsKey(character.codeUnitAt(0))) { - finalText += characterMapTable[character.codeUnitAt(0)]!; - } - } - break; - } - skip = false; - } else if (character == r'\') { - skip = true; - } else { - finalText += character; - } - } - } - return finalText; - } - - /// internal method - bool isCancel(String mappingString) { - bool isCancel = false; - if (mappingString == '') { - isCancel = true; - } - return isCancel; - } - - /// Checks whether the specified character is Non-Printable character or not. - bool isNonPrintableCharacter(String str) { - bool isNonPrintable = false; - if (!isTextExtraction && - fontType!.name == 'Type1' && - fontEncoding == 'Encoding' && - fontName != 'ZapfDingbats' && - (characterMapTable.length == differencesDictionary.length)) { - final int character = str.codeUnitAt(0); - if ((character >= 0 && character <= 31) || character == 127) { - isNonPrintable = true; - } - } - return isNonPrintable; - } - - /// Disposes the instance. - void dispose() { - _differencesDictionary = null; - if (_characterMapTable != null && _characterMapTable!.isNotEmpty) { - _characterMapTable!.clear(); - } - _characterMapTable = null; - if (_reverseMapTable != null && _reverseMapTable!.isNotEmpty) { - _reverseMapTable!.clear(); - } - _reverseMapTable = null; - if (reverseDictMapping.isNotEmpty) { - reverseDictMapping.clear(); - } - if (cidToGidTable != null && cidToGidTable!.isNotEmpty) { - cidToGidTable!.clear(); - } - cidToGidTable = null; - if (_differencesDictionary != null && _differencesDictionary!.isNotEmpty) { - _differencesDictionary!.clear(); - } - _differencesDictionary = null; - if (_fontGlyphWidth != null && _fontGlyphWidth!.isNotEmpty) { - _fontGlyphWidth!.clear(); - } - _fontGlyphWidth = null; - if (tempMapTable.isNotEmpty) { - tempMapTable.clear(); - } - if (_octDecMapTable != null && _octDecMapTable!.isNotEmpty) { - _octDecMapTable!.clear(); - } - _octDecMapTable = null; - if (_cidToGidReverseMapTable != null && - _cidToGidReverseMapTable!.isNotEmpty) { - _cidToGidReverseMapTable!.clear(); - } - _cidToGidReverseMapTable = null; - if (differenceTable.isNotEmpty) { - differenceTable.clear(); - } - if (differenceEncoding != null && differenceEncoding!.isNotEmpty) { - differenceEncoding!.clear(); - } - differenceEncoding = null; - if (type3FontCharProcsDict.isNotEmpty) { - type3FontCharProcsDict.clear(); - } - if (tempStringList.isNotEmpty) { - tempStringList.clear(); - } - if (_unicodeCharMapTable != null && _unicodeCharMapTable!.isNotEmpty) { - _unicodeCharMapTable!.clear(); - } - _unicodeCharMapTable = null; - if (_macEncodeTable != null && _macEncodeTable!.isNotEmpty) { - _macEncodeTable!.clear(); - } - _macEncodeTable = null; - if (_winansiMapTable.isNotEmpty) { - _winansiMapTable.clear(); - } - if (_windows1252MapTable.isNotEmpty) { - _windows1252MapTable.clear(); - } - if (_macRomanMapTable.isNotEmpty) { - _macRomanMapTable.clear(); - } - if (standardCJKFontNames.isNotEmpty) { - standardCJKFontNames.clear(); - } - if (standardFontNames.isNotEmpty) { - standardFontNames.clear(); - } - } -} +import 'dart:convert'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../graphics/fonts/enums.dart'; +import '../../graphics/fonts/pdf_cjk_standard_font.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_standard_font.dart'; +import '../../io/decode_big_endian.dart'; +import '../../io/pdf_constants.dart'; +import '../../io/pdf_cross_table.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_number.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_stream.dart'; +import '../../primitives/pdf_string.dart'; +import 'font_file2.dart'; +import 'xobject_element.dart'; + +/// internal class +class FontStructure { + //constructor + /// internal constructor + FontStructure([IPdfPrimitive? fontDict, String? fontRefNum]) { + if (fontDict != null) { + fontDictionary = fontDict as PdfDictionary; + if (fontDictionary.containsKey(PdfName('Subtype'))) { + fontType = fontDictionary.items![PdfName('Subtype')] as PdfName?; + } + } + _initialize(); + if (fontRefNum != null) { + fontRefNumber = fontRefNum; + if (fontType != null) { + if (fontType!.name == 'Type3') { + if (fontDictionary.items!.containsKey(PdfName('CharProcs'))) { + PdfDictionary? charProcs; + if (fontDictionary['CharProcs'] is PdfDictionary) { + charProcs = fontDictionary['CharProcs'] as PdfDictionary?; + } else { + charProcs = + (fontDictionary['CharProcs']! as PdfReferenceHolder).object + as PdfDictionary?; + } + final List names = charProcs!.items!.keys.toList(); + int i = 0; + // ignore: avoid_function_literals_in_foreach_calls + charProcs.items!.values.forEach((IPdfPrimitive? value) { + if (value != null && value is PdfReferenceHolder) { + final PdfReferenceHolder holder = value; + type3FontCharProcsDict[names[i]!.name] = + holder.object as PdfStream?; + i++; + } + }); + } + } else if (fontType!.name == 'Type1') { + isStandardFont = _checkStandardFont(); + } else if (fontType!.name == 'Type0') { + isStandardCJKFont = _checkStandardCJKFont(); + } + } + } + _fontStyle = [PdfFontStyle.regular]; + defaultGlyphWidth = isCid ? 1000 : 0; + _containsCmap = true; + differenceEncoding = {}; + } + + //Fields + /// internal field + bool isWhiteSpace = false; + + /// internal field + bool isSameFont = false; + String? _fontEncoding; + + /// internal field + late PdfDictionary fontDictionary; + String? _fontName; + + /// internal field + double? fontSize; + Map? _characterMapTable; + Map? _reverseMapTable; + + /// internal field + Map tempMapTable = {}; + + /// internal field + Map? differenceEncoding; + + /// internal field + List tempStringList = []; + Map? _differencesDictionary; + + /// internal field + late Map differenceTable; + Map? _octDecMapTable; + Map? _macEncodeTable; + final Map _macRomanMapTable = {}; + final Map _winansiMapTable = {}; + + /// internal field + Map reverseDictMapping = {}; + + /// internal field + PdfDictionary? cidSystemInfoDictionary; + + /// internal field + Map? cidToGidTable; + Map? _cidToGidReverseMapTable; + + /// internal field + Map type3FontCharProcsDict = {}; + + /// internal field + bool isContainFontfile2 = false; + + /// internal field + bool isMappingDone = false; + + /// internal field + bool isSystemFontExist = false; + + /// internal field + bool isTextExtraction = false; + + /// internal field + bool isEmbedded = false; + + /// internal field + bool containsCmap = true; + + /// internal field + late String zapfPostScript; + + /// internal field + late String fontRefNumber; + + /// internal field + PdfName? fontType; + + /// internal field + bool isAdobeIdentity = false; + bool _isCidFontType = false; + List? _fontStyle; + Map? _fontGlyphWidth; + + /// internal field + double? defaultGlyphWidth; + late bool _containsCmap; + Map? _unicodeCharMapTable; + + /// internal field + late double type1GlyphHeight; + + /// internal field + late bool isStandardFont; + + /// internal field + late bool isStandardCJKFont; + + /// internal field + PdfFont? font; + String? _standardFontName = ''; + String? _standardCJKFontName = ''; + + /// internal field + late List standardFontNames; + + /// internal field + late List standardCJKFontNames; + + /// internal field + late List cjkEncoding; + late List _windows1252MapTable; + + /// internal field + bool isLayout = false; + + /// internal field + bool macRomanEncoded = false; + + //Properties + /// internal property + String? get fontEncoding => _fontEncoding ??= getFontEncoding(); + + /// internal property + Map get characterMapTable => + _characterMapTable ??= getCharacterMapTable(); + + set characterMapTable(Map value) { + _characterMapTable = value; + } + + /// internal property + Map get differencesDictionary => + _differencesDictionary ??= getDifferencesDictionary(); + + set differencesDictionary(Map value) { + _differencesDictionary = value; + } + + /// internal property + Map get octDecMapTable => _octDecMapTable ??= {}; + + set octDecMapTable(Map value) { + _octDecMapTable = value; + } + + /// internal property + Map? get reverseMapTable => + _reverseMapTable ??= getReverseMapTable(); + + set reverseMapTable(Map? value) { + _reverseMapTable = value; + } + + /// internal property + Map get cidToGidReverseMapTable => + _cidToGidReverseMapTable ??= {}; + + set cidToGidReverseMapTable(Map value) { + _cidToGidReverseMapTable = value; + } + + /// internal property + Map? get macEncodeTable { + if (_macEncodeTable == null) { + getMacEncodeTable(); + } + return _macEncodeTable; + } + + set macEncodeTable(Map? value) { + _macEncodeTable = value; + } + + /// internal property + String? get fontName => _fontName ??= getFontName(); + + /// internal property + bool get isCid { + _isCidFontType = isCIDFontType(); + return _isCidFontType; + } + + set isCid(bool value) { + _isCidFontType = value; + } + + /// internal property + List? get fontStyle { + if (_fontStyle!.length == 1 && _fontStyle![0] == PdfFontStyle.regular) { + _fontStyle = getFontStyle(); + } + return _fontStyle; + } + + /// internal property + Map? get fontGlyphWidths { + if (_fontGlyphWidth == null) { + if (fontEncoding == 'Identity-H' || fontEncoding == 'Identity#2DH') { + _getGlyphWidths(); + } else { + _getGlyphWidthsNonIdH(); + } + } + return _fontGlyphWidth; + } + + /// internal property + Map? get unicodeCharMapTable { + _unicodeCharMapTable ??= {}; + return _unicodeCharMapTable; + } + + set unicodeCharMapTable(Map? value) { + _unicodeCharMapTable = value; + } + + /// internal property + PdfNumber? get flags => _getFlagValue(); + + //Implementation + void _initialize() { + differenceTable = {}; + zapfPostScript = ''; + fontRefNumber = ''; + type1GlyphHeight = 0; + isStandardFont = false; + isStandardCJKFont = false; + standardCJKFontNames = [ + 'HYGoThic-Medium,BoldItalic', + 'HYGoThic-Medium,Bold', + 'HYGoThic-Medium,Italic', + 'HYGoThic-Medium', + 'MHei-Medium,BoldItalic', + 'MHei-Medium,Bold', + 'MHei-Medium', + 'MHei-Medium,Italic', + 'MSung-Light,BoldItalic', + 'MSung-Light,Bold', + 'MSung-Light,Italic', + 'MSung-Light', + 'STSong-Light,BoldItalic', + 'STSong-Light,Bold', + 'STSong-Light,Italic', + 'STSong-Light', + 'HeiseiMin-W3,BoldItalic', + 'HeiseiMin-W3,Bold', + 'HeiseiMin-W3,Italic', + 'HeiseiMin-W3', + 'HeiseiKakuGo-W5,BoldItalic', + 'HeiseiKakuGo-W5,Bold', + 'HeiseiKakuGo-W5,Italic', + 'HeiseiKakuGo-W5', + 'HYSMyeongJo-Medium,BoldItalic', + 'HYSMyeongJo-Medium,Bold', + 'HYSMyeongJo-Medium,Italic', + 'HYSMyeongJo-Medium', + ]; + cjkEncoding = [ + 'UniKS-UCS2-H', + 'UniJIS-UCS2-H', + 'UniCNS-UCS2-H', + 'UniGB-UCS2-H', + ]; + standardFontNames = [ + 'Helvetica', + 'Helvetica-Bold', + 'Helvetica,Bold', + 'Helvetica-BoldOblique', + 'Helvetica,BoldItalic', + 'Helvetica-Oblique', + 'Helvetica,Italic', + 'Courier New', + 'Courier', + 'Courier-Bold', + 'Courier New,Bold', + 'Courier-BoldOblique', + 'Courier New,BoldItalic', + 'Courier-Oblique', + 'Courier New,Italic', + 'Times New Roman', + 'Times New Roman,Bold', + 'Times New Roman,BoldItalic', + 'Times New Roman,Italic', + 'Times-Roman', + 'Times-Bold', + 'Times-Italic', + 'Times-BoldItalic', + 'Symbol', + 'ZapfDingbats', + ]; + _windows1252MapTable = [ + '\u0000', + '\u0001', + '\u0002', + '\u0003', + '\u0004', + '\u0005', + '\u0006', + '\u0007', + '\b', + '\t', + '\n', + '\v', + '\f', + '\r', + '\u000e', + '\u000f', + '\u0010', + '\u0011', + '\u0012', + '\u0013', + '\u0014', + '\u0015', + '\u0016', + '\u0017', + '\u0018', + '\u0019', + '\u001a', + '\u001b', + '\u001c', + '\u001d', + '\u001e', + '\u001f', + ' ', + '!', + '"', + '#', + r'$', + '%', + '&', + "'", + '(', + ')', + '*', + '+', + ',', + '-', + '.', + '/', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + ':', + ';', + '<', + '=', + '>', + '?', + '@', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '[', + r'\', + ']', + '^', + '_', + '`', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + '{', + '|', + '}', + '~', + '\u007f', + '€', + '\u0081', + '‚', + 'ƒ', + '„', + '…', + '†', + '‡', + 'ˆ', + '‰', + 'Š', + '‹', + 'Œ', + '\u008d', + 'Ž', + '\u008f', + '\u0090', + '‘', + '’', + '“', + '”', + '•', + '–', + '—', + '˜', + '™', + 'š', + '›', + 'œ', + '\u009d', + 'ž', + 'Ÿ', + ' ', + '¡', + '¢', + '£', + '¤', + '¥', + '¦', + '§', + '¨', + '©', + 'ª', + '«', + '¬', + '­', + '®', + '¯', + '°', + '±', + '²', + '³', + '´', + 'µ', + '¶', + '·', + '¸', + '¹', + 'º', + '»', + '¼', + '½', + '¾', + '¿', + 'À', + 'Á', + 'Â', + 'Ã', + 'Ä', + 'Å', + 'Æ', + 'Ç', + 'È', + 'É', + 'Ê', + 'Ë', + 'Ì', + 'Í', + 'Î', + 'Ï', + 'Ð', + 'Ñ', + 'Ò', + 'Ó', + 'Ô', + 'Õ', + 'Ö', + '×', + 'Ø', + 'Ù', + 'Ú', + 'Û', + 'Ü', + 'Ý', + 'Þ', + 'ß', + 'à', + 'á', + 'â', + 'ã', + 'ä', + 'å', + 'æ', + 'ç', + 'è', + 'é', + 'ê', + 'ë', + 'ì', + 'í', + 'î', + 'ï', + 'ð', + 'ñ', + 'ò', + 'ó', + 'ô', + 'õ', + 'ö', + '÷', + 'ø', + 'ú', + 'û', + 'ü', + 'ý', + 'þ', + 'ÿ', + ]; + } + + PdfNumber? _getFlagValue() { + PdfNumber? flagvalue; + if (fontEncoding != 'Identity-H') { + if (fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor)) { + IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.fontDescriptor]; + if (primitive != null && primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfDictionary) { + final PdfDictionary dic = primitive; + if (dic.containsKey(PdfDictionaryProperties.flags)) { + primitive = dic[PdfDictionaryProperties.flags]; + if (primitive is PdfNumber) { + flagvalue = primitive; + return flagvalue; + } + } + } + } + } + } else { + if (fontDictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { + IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.descendantFonts]; + if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + } + if (primitive != null && primitive is PdfArray) { + final PdfArray descenarray = primitive; + if (descenarray.count > 0 && descenarray[0] is PdfReferenceHolder) { + final PdfReferenceHolder referenceholder = + descenarray[0]! as PdfReferenceHolder; + final IPdfPrimitive? primitiveObject = referenceholder.object; + if (primitiveObject != null && primitiveObject is PdfDictionary) { + final PdfDictionary dictionary = primitiveObject; + if (dictionary.containsKey( + PdfDictionaryProperties.fontDescriptor, + )) { + IPdfPrimitive? fontDescriptor = + dictionary[PdfDictionaryProperties.fontDescriptor]; + PdfDictionary? descriptorDictionary; + if (fontDescriptor is PdfReferenceHolder) { + fontDescriptor = fontDescriptor.object; + if (fontDescriptor != null && + fontDescriptor is PdfDictionary) { + descriptorDictionary = fontDescriptor; + } + } else if (fontDescriptor is PdfDictionary) { + descriptorDictionary = fontDescriptor; + } + if (descriptorDictionary != null && + descriptorDictionary.containsKey( + PdfDictionaryProperties.flags, + )) { + primitive = + descriptorDictionary[PdfDictionaryProperties.flags]; + if (primitive is PdfNumber) { + flagvalue = primitive; + return flagvalue; + } + } + } + } + } + } + } + } + return flagvalue; + } + + void _getGlyphWidths() { + if (fontEncoding == 'Identity-H' || fontEncoding == 'Identity#2DH') { + PdfDictionary dictionary = fontDictionary; + if (dictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { + IPdfPrimitive? primitive = + dictionary[PdfDictionaryProperties.descendantFonts]; + PdfArray? arr; + if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfArray) { + arr = primitive; + } + } else if (primitive is PdfArray) { + arr = primitive; + } + if (arr != null && arr.count > 0) { + if (arr[0] is PdfDictionary) { + dictionary = arr[0]! as PdfDictionary; + } else if (arr[0] is PdfReferenceHolder) { + final IPdfPrimitive? holder = + (arr[0]! as PdfReferenceHolder).object; + if (holder != null && holder is PdfDictionary) { + dictionary = holder; + } + } + } + } + _fontGlyphWidth = {}; + PdfArray? w; + int index = 0; + int endIndex = 0; + PdfArray? widthArray; + if (dictionary.containsKey(PdfDictionaryProperties.w)) { + IPdfPrimitive? holder = dictionary[PdfDictionaryProperties.w]; + if (holder is PdfArray) { + w = holder; + } else if (holder is PdfReferenceHolder) { + holder = holder.object; + if (holder != null && holder is PdfArray) { + w = holder; + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.dw)) { + final IPdfPrimitive? holder = dictionary[PdfDictionaryProperties.dw]; + if (holder is PdfNumber) { + defaultGlyphWidth = holder.value!.toDouble(); + } + } + try { + if (w == null) { + return; + } + for (int i = 0; i < w.count;) { + if (w[i] is PdfNumber) { + index = (w[i]! as PdfNumber).value!.toInt(); + } + i++; + if (w[i] is PdfArray) { + widthArray = w[i]! as PdfArray; + for (int j = 0; j < widthArray.count; j++) { + if (!_containsCmap) { + _fontGlyphWidth![index] = + (widthArray[j]! as PdfNumber).value!.toInt(); + } else if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = + (widthArray[j]! as PdfNumber).value!.toInt(); + } + index++; + } + } else if (w[i] is PdfNumber) { + endIndex = (w[i]! as PdfNumber).value!.toInt(); + i++; + for (; index <= endIndex; index++) { + if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); + } + } + } else if (w[i] is PdfReferenceHolder) { + widthArray = (w[i]! as PdfReferenceHolder).object as PdfArray?; + for (int j = 0; j < widthArray!.count; j++) { + if (!_containsCmap) { + _fontGlyphWidth![index] = + (widthArray[j]! as PdfNumber).value!.toInt(); + } else { + if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = + (widthArray[j]! as PdfNumber).value!.toInt(); + } + } + index++; + } + } + i++; + } + } catch (e) { + _fontGlyphWidth = null; + } + w = null; + widthArray = null; + } + } + + void _getGlyphWidthsNonIdH() { + int firstChar = 0; + final PdfDictionary dictionary = fontDictionary; + if (dictionary.containsKey(PdfDictionaryProperties.dw)) { + defaultGlyphWidth = + (dictionary[PdfDictionaryProperties.dw]! as PdfNumber).value! + .toDouble(); + } + if (dictionary.containsKey(PdfDictionaryProperties.firstChar)) { + firstChar = + (dictionary[PdfDictionaryProperties.firstChar]! as PdfNumber).value! + .toInt(); + } + _fontGlyphWidth = {}; + PdfArray? w; + int index = 0; + if (dictionary.containsKey(PdfDictionaryProperties.widths)) { + IPdfPrimitive? primitive = dictionary[PdfDictionaryProperties.widths]; + if (primitive is PdfArray) { + w = primitive; + } else if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfArray) { + w = primitive; + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { + IPdfPrimitive? primitive = + dictionary[PdfDictionaryProperties.descendantFonts]; + if (primitive != null && primitive is PdfArray) { + final PdfArray descendantdicArray = primitive; + if (descendantdicArray.count > 0 && + descendantdicArray[0] is PdfReferenceHolder) { + primitive = (descendantdicArray[0]! as PdfReferenceHolder).object; + if (primitive != null && primitive is PdfDictionary) { + final PdfDictionary descendantDictionary = primitive; + if (descendantDictionary.containsKey(PdfDictionaryProperties.w)) { + primitive = descendantDictionary[PdfDictionaryProperties.w]; + if (primitive is PdfArray) { + w = primitive; + } + } + } + } + } + } + + if (w != null) { + try { + for (int i = 0; i < w.count; i++) { + index = firstChar + i; + if (characterMapTable.isNotEmpty || + differencesDictionary.isNotEmpty) { + if (characterMapTable.containsKey(index)) { + if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); + } + } else if (differencesDictionary.containsKey(index.toString())) { + if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); + } + } else if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = (w[i]! as PdfNumber).value!.toInt(); + } + } else if (w[i] is PdfArray) { + final PdfArray tempW = w[i]! as PdfArray; + for (int j = i; j < tempW.count; j++) { + index = firstChar + j; + if (characterMapTable.isNotEmpty || + differencesDictionary.isNotEmpty) { + if (characterMapTable.containsKey(index)) { + final String mappingString = characterMapTable[index]!; + final int entryValue = mappingString.codeUnitAt(0); + if (!_fontGlyphWidth!.containsKey(entryValue)) { + _fontGlyphWidth![entryValue] = + (tempW[j]! as PdfNumber).value!.toInt(); + } + } else if (differencesDictionary.containsKey( + index.toString(), + )) { + if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = + (tempW[j]! as PdfNumber).value!.toInt(); + } + } else { + if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = + (tempW[j]! as PdfNumber).value!.toInt(); + } + } + } else { + _fontGlyphWidth![index] = + (tempW[j]! as PdfNumber).value!.toInt(); + } + } + } else { + final int value = (w[i]! as PdfNumber).value!.toInt(); + if (!_fontGlyphWidth!.containsKey(index)) { + _fontGlyphWidth![index] = value; + } + } + } + } catch (e) { + _fontGlyphWidth = null; + } + } + } + + bool _checkStandardFont() { + bool result = !_checkStandardFontDictionary(); + if (result && + fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { + IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.baseFont]; + PdfName? baseFont; + if (primitive is PdfName) { + baseFont = primitive; + } else if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfName) { + baseFont = primitive; + } + } + if (baseFont != null) { + _standardFontName = baseFont.name; + result &= standardFontNames.contains( + _resolveFontName(_standardFontName), + ); + // Pre-extract font styles for standard fonts + if (result && _standardFontName != null) { + _fontStyle = _getFontStyle(_standardFontName!); + } + } else { + result = false; + } + } else { + result = false; + } + return result; + } + + bool _checkStandardCJKFont() { + bool result = !_checkStandardFontDictionary(); + if (result && + fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { + IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.baseFont]; + PdfName? baseFont; + if (primitive is PdfName) { + baseFont = primitive; + } else if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfName) { + baseFont = primitive; + } + } + if (baseFont != null) { + _standardCJKFontName = baseFont.name; + PdfName? encoding; + if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { + primitive = fontDictionary[PdfDictionaryProperties.encoding]; + if (primitive is PdfName) { + encoding = primitive; + } else if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfName) { + encoding = primitive; + } + } + } + result &= encoding != null && cjkEncoding.contains(encoding.name); + result &= + _standardCJKFontName != '' && + standardCJKFontNames.contains(_standardCJKFontName); + + // Pre-extract font styles for standard CJK fonts + if (result && _standardCJKFontName != null) { + _fontStyle = _getCJKFontStyle(_standardCJKFontName!); + } else if (_standardCJKFontName != null && + encoding != null && + cjkEncoding.contains(encoding.name)) { + // Even if exact match not found, still extract styles if base font is standard CJK and encoding is valid + // This handles cases like "HYGoThic-Medium,BoldUnderline" where underline is not in standardCJKFontNames list + final String baseNameOnly = + _standardCJKFontName!.split('-')[0].split(',')[0]; + if (standardCJKFontNames.any( + (String name) => name.startsWith(baseNameOnly), + )) { + _fontStyle = _getCJKFontStyle(_standardCJKFontName!); + } + } + } else { + result = false; + } + } else { + result = false; + } + return result; + } + + String _resolveFontName(String? fontName) { + final String tempFontName = fontName.toString(); + if (tempFontName.contains('times') || tempFontName.contains('Times')) { + return 'Times New Roman'; + } + if (tempFontName.contains('Helvetica')) { + return 'Helvetica'; + } + return tempFontName; + } + + bool _checkStandardFontDictionary() { + return fontDictionary.containsKey(PdfDictionaryProperties.widths) || + fontDictionary.containsKey(PdfDictionaryProperties.firstChar) || + fontDictionary.containsKey(PdfDictionaryProperties.lastChar) || + fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor); + } + + /// internal method + PdfFont? createStandardFont(double size) { + if (_standardFontName != null && _standardFontName != '') { + if (_standardFontName!.contains('#')) { + _standardFontName = decodeHexFontName(_standardFontName!); + } + final PdfFontFamily fontFamily = _getFontFamily(_standardFontName!); + final List styles = _getFontStyle(_standardFontName!); + if (styles.contains(PdfFontStyle.bold) && + styles.contains(PdfFontStyle.italic)) { + font = PdfStandardFont( + fontFamily, + size, + multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], + ); + } else if (styles.contains(PdfFontStyle.bold)) { + font = PdfStandardFont(fontFamily, size, style: PdfFontStyle.bold); + } else if (styles.contains(PdfFontStyle.italic)) { + font = PdfStandardFont(fontFamily, size, style: PdfFontStyle.italic); + } else { + font = PdfStandardFont(fontFamily, size); + } + } + return font; + } + + /// internal method + PdfFont? createStandardCJKFont(double size) { + if (_standardCJKFontName != '') { + final PdfCjkFontFamily fontFamily = _getCJKFontFamily( + _standardCJKFontName!, + ); + final List styles = _getCJKFontStyle(_standardCJKFontName!); + if (styles.contains(PdfFontStyle.bold) && + styles.contains(PdfFontStyle.italic)) { + font = PdfCjkStandardFont( + fontFamily, + size, + multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], + ); + } else if (styles.contains(PdfFontStyle.bold)) { + font = PdfCjkStandardFont(fontFamily, size, style: PdfFontStyle.bold); + } else if (styles.contains(PdfFontStyle.italic)) { + font = PdfCjkStandardFont(fontFamily, size, style: PdfFontStyle.italic); + } else { + font = PdfCjkStandardFont(fontFamily, size); + } + } + return font; + } + + PdfFontFamily _getFontFamily(String fontName) { + PdfFontFamily fontFamily; + if (fontName.contains('-')) { + fontName = fontName.split('-')[0]; + } + switch (fontName) { + case 'Times': + fontFamily = PdfFontFamily.timesRoman; + break; + case 'Helvetica': + fontFamily = PdfFontFamily.helvetica; + break; + case 'Courier': + fontFamily = PdfFontFamily.courier; + break; + case 'Symbol': + fontFamily = PdfFontFamily.symbol; + break; + case 'ZapfDingbats': + fontFamily = PdfFontFamily.zapfDingbats; + break; + default: + throw ArgumentError.value(fontName, 'fontName', 'invalid font name'); + } + return fontFamily; + } + + PdfCjkFontFamily _getCJKFontFamily(String fontName) { + PdfCjkFontFamily fontFamily; + if (fontName.contains(',')) { + fontName = fontName.split(',')[0]; + } + switch (fontName) { + case 'HYGoThic-Medium': + fontFamily = PdfCjkFontFamily.hanyangSystemsGothicMedium; + break; + case 'MHei-Medium': + fontFamily = PdfCjkFontFamily.monotypeHeiMedium; + break; + case 'MSung-Light': + fontFamily = PdfCjkFontFamily.monotypeSungLight; + break; + case 'STSong-Light': + fontFamily = PdfCjkFontFamily.sinoTypeSongLight; + break; + case 'HeiseiMin-W3': + fontFamily = PdfCjkFontFamily.heiseiMinchoW3; + break; + case 'HeiseiKakuGo-W5': + fontFamily = PdfCjkFontFamily.heiseiKakuGothicW5; + break; + case 'HYSMyeongJo-Medium': + fontFamily = PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium; + break; + default: + throw ArgumentError.value(fontName, 'fontName', 'invalid font name'); + } + return fontFamily; + } + + /// Extracts the font encoding associated with the text string + /// Font style. + String? getFontEncoding() { + PdfName? baseFont = PdfName(); + String? fontEncoding = ''; + if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { + if (fontDictionary[PdfDictionaryProperties.encoding] is PdfName) { + baseFont = fontDictionary[PdfDictionaryProperties.encoding] as PdfName?; + fontEncoding = baseFont!.name; + } else { + PdfDictionary? baseFontDict = PdfDictionary(); + if (fontDictionary[PdfDictionaryProperties.encoding] is PdfDictionary) { + baseFontDict = + fontDictionary[PdfDictionaryProperties.encoding] + as PdfDictionary?; + if (baseFontDict == null) { + baseFont = + (fontDictionary[PdfDictionaryProperties.encoding]! + as PdfReferenceHolder) + .object + as PdfName?; + fontEncoding = baseFont!.name; + } + } else if (fontDictionary[PdfDictionaryProperties.encoding] + is PdfReferenceHolder) { + final IPdfPrimitive? primitive = PdfCrossTable.dereference( + fontDictionary[PdfDictionaryProperties.encoding], + ); + if (primitive != null && primitive is PdfName) { + baseFont = primitive; + fontEncoding = baseFont.name; + } else if (primitive != null && primitive is PdfDictionary) { + baseFontDict = primitive; + } + } + if (baseFontDict != null && + baseFontDict.containsKey(PdfDictionaryProperties.type)) { + fontEncoding = + (baseFontDict[PdfDictionaryProperties.type]! as PdfName).name; + } + } + } + if (fontEncoding == 'CMap') { + fontEncoding = 'Identity-H'; + } + return fontEncoding; + } + + /// internal method + Map? getReverseMapTable() { + _reverseMapTable = {}; + characterMapTable.forEach((double k, String v) { + if (!_reverseMapTable!.containsKey(v)) { + _reverseMapTable![v] = k; + } + }); + return _reverseMapTable; + } + + /// Extracts the font name associated with the string. + String? getFontName() { + String? fontName = ''; + isSystemFontExist = false; + if (fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { + PdfName? baseFont; + if (fontDictionary[PdfDictionaryProperties.baseFont] is PdfName) { + baseFont = fontDictionary[PdfDictionaryProperties.baseFont] as PdfName?; + } else if (fontDictionary[PdfDictionaryProperties.baseFont] + is PdfReferenceHolder) { + baseFont = + (fontDictionary[PdfDictionaryProperties.baseFont]! + as PdfReferenceHolder) + .object + as PdfName?; + } + String font = baseFont!.name!; + if (font.contains('#20') && !font.contains('+')) { + final int startIndex = font.lastIndexOf('#20'); + font = font.substring(0, startIndex); + font = '$font+'; + } + if (font.contains('+')) {} + if (!isSystemFontExist) { + if (baseFont.name!.contains('+')) { + fontName = baseFont.name!.split('+')[1]; + } else { + fontName = baseFont.name; + } + + if (fontName!.contains('-')) { + fontName = fontName.split('-')[0]; + } else if (fontName.contains(',')) { + fontName = fontName.split(',')[0]; + } + if (fontName.contains('MT')) { + fontName = fontName.replaceAll('MT', ''); + } + if (fontName.contains('#20')) { + fontName = fontName.replaceAll('#20', ' '); + } + if (fontName.contains('#')) { + fontName = decodeHexFontName(fontName); + } + } + } + return fontName; + } + + /// internal method + List getFontStyle() { + List styles = []; + + // First, try to extract styles from baseFont name + if (fontDictionary.containsKey(PdfDictionaryProperties.baseFont)) { + IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.baseFont]; + PdfName? baseFont; + if (primitive is PdfName) { + baseFont = primitive; + } else if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive is PdfName) { + baseFont = primitive; + } + } + if (baseFont != null) { + styles = _getFontStyle(baseFont.name!); + } + } + + // If no styles found from baseFont name, check FontDescriptor flags + if (styles.isEmpty || + (styles.length == 1 && styles[0] == PdfFontStyle.regular)) { + final List descriptorStyles = + _getStylesFromFontDescriptor(); + if (descriptorStyles.isNotEmpty && + !(descriptorStyles.length == 1 && + descriptorStyles[0] == PdfFontStyle.regular)) { + styles = descriptorStyles; + } + } + + if (styles.isEmpty) { + styles.add(PdfFontStyle.regular); + } + return styles; + } + + /// Extracts font styles from FontDescriptor flags + /// Bit 6 (64) in flags indicates Italic style + List _getStylesFromFontDescriptor() { + final List styles = []; + + if (fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor)) { + IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.fontDescriptor]; + + if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + } + + if (primitive is PdfDictionary) { + if (primitive.containsKey(PdfDictionaryProperties.flags)) { + final IPdfPrimitive? flagPrimitive = + primitive[PdfDictionaryProperties.flags]; + if (flagPrimitive is PdfNumber) { + final int flagValue = flagPrimitive.value?.toInt() ?? 0; + // Bit 6 (value 64) indicates Italic + if ((flagValue & 64) != 0) { + styles.add(PdfFontStyle.italic); + } + } + } + } + } + + if (styles.isEmpty) { + styles.add(PdfFontStyle.regular); + } + return styles; + } + + List _getCJKFontStyle(String baseFont) { + final List styles = []; + String normalizedFont = baseFont; + if (baseFont.contains(',')) { + normalizedFont = baseFont.split(',')[1]; + } + // If no comma found, baseFont is used as-is (could be just the style property like "Bold", "Underline", etc.) + + // Check for combined styles first to avoid duplicates + if (normalizedFont.contains('BoldItalic')) { + styles.add(PdfFontStyle.bold); + styles.add(PdfFontStyle.italic); + } else { + // Check individual styles only if combined style not found + if (normalizedFont.contains('Bold')) { + styles.add(PdfFontStyle.bold); + } + if (normalizedFont.contains('Italic')) { + styles.add(PdfFontStyle.italic); + } + } + + // Always check for additional properties + if (normalizedFont.contains('Underline')) { + styles.add(PdfFontStyle.underline); + } + if (normalizedFont.contains('Strikethrough') || + normalizedFont.contains('StrikeOut')) { + styles.add(PdfFontStyle.strikethrough); + } + + if (styles.isEmpty) { + styles.add(PdfFontStyle.regular); + } + return styles; + } + + List _getFontStyle(String baseFont) { + final List styles = []; + + // Normalize the font name for style extraction + String normalizedFont = baseFont; + if (baseFont.contains('-') || baseFont.contains(',')) { + if (baseFont.contains('-')) { + normalizedFont = baseFont.split('-')[1]; + } else if (baseFont.contains(',')) { + normalizedFont = baseFont.split(',')[1]; + } + normalizedFont = normalizedFont.replaceAll('MT', ''); + } + // If no separator found, baseFont is used as-is (could be just the style property like "Bold", "Underline", etc.) + + // Check for combined styles first to avoid duplicates + if (normalizedFont.contains('BoldItalic') || + normalizedFont.contains('BoldOblique')) { + styles.add(PdfFontStyle.bold); + styles.add(PdfFontStyle.italic); + } else { + // Check individual styles only if combined style not found + if (normalizedFont.contains('Bold')) { + styles.add(PdfFontStyle.bold); + } + if (normalizedFont.contains('Italic') || + normalizedFont.contains('Oblique')) { + styles.add(PdfFontStyle.italic); + } + } + + // Always check for additional properties + if (normalizedFont.contains('Underline')) { + styles.add(PdfFontStyle.underline); + } + if (normalizedFont.contains('Strikethrough') || + normalizedFont.contains('StrikeOut')) { + styles.add(PdfFontStyle.strikethrough); + } + + if (styles.isEmpty) { + styles.add(PdfFontStyle.regular); + } + return styles; + } + + /// internal method + String decodeHexFontName(String fontName) { + String? newFontname; + for (int i = 0; i < fontName.length; i++) { + if (fontName[i] == '#') { + final String hexValue = fontName[i + 1] + fontName[i + 2]; + final int decimalValue = int.parse(hexValue, radix: 16); + if (decimalValue != 0) { + final String charValue = String.fromCharCode(decimalValue); + newFontname = fontName.replaceAll('#$hexValue', charValue); + i = i + 2; + } + if (!fontName.contains('#')) { + break; + } + } + } + return newFontname.toString(); + } + + /// Builds the mapping table that is used to map the + /// decoded text to get the expected text. + /// Returns a Map with key as the encoded + /// element and value as the value to be mapped to. + Map getCharacterMapTable() { + int endOfTable = 0; + final Map mapTable = {}; + if (fontDictionary.containsKey(PdfDictionaryProperties.toUnicode)) { + IPdfPrimitive? unicodeMap = + fontDictionary[PdfDictionaryProperties.toUnicode]; + + PdfStream? mapStream; + if (unicodeMap is PdfReferenceHolder) { + mapStream = unicodeMap.object as PdfStream?; + } else { + mapStream = unicodeMap as PdfStream?; + } + unicodeMap = null; + if (mapStream != null) { + mapStream.decompress(); + mapStream.changed = false; + final String text = utf8.decode(mapStream.dataStream!); + bool isBfRange = false, isBfChar = false; + int start, end, startCmap, endCmap, endPointer; + startCmap = text.indexOf('begincmap'); + endCmap = text.indexOf('endcmap'); + endPointer = startCmap; + start = startCmap; + end = endCmap; + if (endPointer == -1) { + return mapTable; + } + while (true) { + if (!isBfRange) { + start = text.indexOf('beginbfchar', endPointer); + if (start < 0) { + isBfChar = false; + start = startCmap; + endPointer = startCmap; + end = endCmap; + } else { + end = text.indexOf('endbfchar', start); + endPointer = end; + isBfChar = true; + } + } + if (!isBfChar) { + final int bfrangestart = text.indexOf('beginbfrange', endPointer); + + if (bfrangestart < 0) { + isBfRange = false; + } else { + final int bfrangeend = text.indexOf('endbfrange', endPointer + 5); + start = bfrangestart; + end = bfrangeend; + endPointer = end; + isBfRange = true; + } + } + if (isBfChar || isBfRange) { + final String sub = text.substring(start, end); + if (isBfChar) { + final List tableEntry = sub.split(RegExp('[\n-\r]')); + if (!tableEntry[0].contains('\n') && + !tableEntry[0].contains('\r')) { + List tempTmp = []; + for (int j = 0; j < tableEntry.length; j++) { + tempTmp = getHexCode(tableEntry[j]); + final int c = tempTmp.length; + for (int k = 0; k < c / 2; k++) { + if (tempTmp.length >= 2) { + final List tmpList = []; + tmpList.add(tempTmp[0]); + tmpList.add(tempTmp[1]); + tempTmp.remove(tempTmp[0]); + tempTmp.remove(tempTmp[0]); + if (tmpList.length > 1) { + if (tmpList[1].length > 4) { + String tableValue = tmpList[1]; + tableValue = tableValue.replaceAll(' ', ''); + String mapValue = ''; + final int numberOfCharacters = tableValue.length ~/ 4; + for (int j2 = 0; j2 < numberOfCharacters; j2++) { + final String mapChar = String.fromCharCode( + int.parse( + tableValue.substring(0, 4), + radix: 16, + ).toSigned(64), + ); + tableValue = tableValue.substring(4); + mapValue += mapChar; + } + mapValue = checkContainInvalidChar(mapValue); + if (!mapTable.containsKey( + int.parse(tmpList[0], radix: 16).toSigned(64), + )) { + mapTable[int.parse( + tmpList[0], + radix: 16, + ).toSigned(64).toDouble()] = + mapValue; + } + continue; + } + if (tmpList.length > 1 && + tmpList[0] != '' && + tmpList[1] != '' && + !mapTable.containsKey( + int.parse(tmpList[0], radix: 16).toSigned(64), + )) { + final String mapValue = String.fromCharCode( + int.parse(tmpList[1], radix: 16).toSigned(64), + ); + mapTable[int.parse( + tmpList[0], + radix: 16, + ).toSigned(64).toDouble()] = + mapValue; + } + } + } + } + } + } else { + for (int i = 0; i < tableEntry.length; i++) { + tempStringList = getHexCode(tableEntry[i]); + if (tempStringList.length > 1) { + if (tempStringList[1].length > 4) { + String tableValue = tempStringList[1]; + tableValue = tableValue.replaceAll(' ', ''); + String mapValue = ''; + final int numberOfCharacters = tableValue.length ~/ 4; + for (int j = 0; j < numberOfCharacters; j++) { + final String mapChar = String.fromCharCode( + int.parse( + tableValue.substring(0, 4), + radix: 16, + ).toSigned(64), + ); + tableValue = tableValue.substring(4); + mapValue += mapChar; + } + mapValue = checkContainInvalidChar(mapValue); + if (!mapTable.containsKey( + int.parse(tempStringList[0], radix: 16).toSigned(64), + )) { + mapTable[int.parse( + tempStringList[0], + radix: 16, + ).toSigned(64).toDouble()] = + mapValue; + } + continue; + } + if (!mapTable.containsKey( + int.parse(tempStringList[0]).toSigned(64), + )) { + final String mapValue = String.fromCharCode( + int.parse(tempStringList[1], radix: 16).toSigned(64), + ); + mapTable[int.parse( + tempStringList[0], + radix: 16, + ).toSigned(64).toDouble()] = + mapValue; + } + } + } + } + } else if (isBfRange) { + double startRange, endRange; + final List tableEntry = sub.split(RegExp('[\n-\r]')); + String str = ' '; + for (int i = 0; i < tableEntry.length; i++) { + if (tableEntry[i].contains('[')) { + final int subArrayStatIndex = tableEntry[i].indexOf('['); + final int subArrayEndIndex = tableEntry[i].indexOf(']'); + if (subArrayEndIndex == -1) { + str = tableEntry[i].substring( + subArrayStatIndex, + tableEntry[i].length, + ); + i++; + while (true) { + if (tableEntry[i].contains(']')) { + str += tableEntry[i].substring( + 0, + tableEntry[i].indexOf(']'), + ); + break; + } else { + str += tableEntry[i]; + i++; + } + } + } else { + str = tableEntry[i].substring( + subArrayStatIndex, + subArrayEndIndex, + ); + } + List subArray = []; + subArray = getHexCode(str); + String tableEntryValue = ' '; + if (subArrayEndIndex == -1) { + for (int j = endOfTable + 1; j <= i; j++) { + tableEntryValue += tableEntry[j]; + } + tempStringList = getHexCode(tableEntryValue); + } else { + tempStringList = getHexCode(tableEntry[i]); + } + endOfTable = i; + if (tempStringList.length > 1) { + startRange = + int.parse( + tempStringList[0], + radix: 16, + ).toSigned(64).toDouble(); + endRange = + int.parse( + tempStringList[1], + radix: 16, + ).toSigned(64).toDouble(); + int t = 0; + for ( + double j = startRange, k = 0; + j <= endRange; + j++, k++, t++ + ) { + String mapString = ''; + int l = 0; + while (l < subArray[t].length) { + final String mapValueHex = subArray[t].substring( + l, + l + 4, + ); + final int hexEquivalent = int.parse( + mapValueHex, + radix: 16, + ).toSigned(64); + final int hex = hexEquivalent; + final String hexString = hex.toRadixString(16); + final int mapValue = int.parse( + hexString, + radix: 16, + ).toSigned(64); + final String mapChar = String.fromCharCode(mapValue); + mapString += mapChar; + l += 4; + } + if (!mapTable.containsKey(j)) { + mapTable[j] = mapString; + } + } + } + } else { + tempStringList = getHexCode(tableEntry[i]); + if (tempStringList.length == 3) { + startRange = + int.parse( + tempStringList[0], + radix: 16, + ).toSigned(64).toDouble(); + endRange = + int.parse( + tempStringList[1], + radix: 16, + ).toSigned(64).toDouble(); + String mapValueHex = tempStringList[2]; + if (tempStringList[2].length > 4) { + final String mapFirstHex = mapValueHex.substring(0, 4); + final int hexFirstEquivalent = int.parse( + mapFirstHex, + radix: 16, + ).toSigned(64); + final int mapFirstValue = int.parse( + hexFirstEquivalent.toRadixString(16), + radix: 16, + ).toSigned(64); + final String mapFirstChar = String.fromCharCode( + mapFirstValue, + ); + mapValueHex = mapValueHex.substring(5, 8); + final int hexEquivalent = int.parse( + mapValueHex, + radix: 16, + ).toSigned(64); + for ( + double j = startRange, k = 0; + j <= endRange; + j++, k++ + ) { + final int hex = hexEquivalent + k.toInt(); + final String hexString = hex.toRadixString(16); + final int mapValue = int.parse( + hexString, + radix: 16, + ).toSigned(64); + String mapChar = + mapFirstChar + String.fromCharCode(mapValue); + mapChar = checkContainInvalidChar(mapChar); + if (!mapTable.containsKey(j)) { + mapTable[j] = mapChar; + } + } + } else { + final int hexEquivalent = int.parse( + mapValueHex, + radix: 16, + ).toSigned(64); + for ( + double j = startRange, k = 0; + j <= endRange; + j++, k++ + ) { + final int hex = hexEquivalent + k.toInt(); + final String hexString = hex.toRadixString(16); + final int mapValue = int.parse( + hexString, + radix: 16, + ).toSigned(64); + final String mapChar = String.fromCharCode(mapValue); + if (!mapTable.containsKey(j)) { + mapTable[j] = mapChar; + } + } + } + } else if (tempStringList.length > 1) { + int semiCount; + semiCount = tempStringList.length; + for (int k = 0; k < semiCount;) { + final String mapValue = String.fromCharCode( + int.parse( + tempStringList[k + 2], + radix: 16, + ).toSigned(64), + ); + mapTable[int.parse( + tempStringList[k], + radix: 16, + ).toSigned(64).toDouble()] = + mapValue; + k = k + 3; + } + } + } + } + } + } else { + break; + } + } + } + mapStream = null; + } + if (isSameFont == true) { + mapTable.forEach((double k, String v) { + if (!tempMapTable.containsKey(k)) { + tempMapTable[k] = v; + } else { + tempMapTable.remove(k); + tempMapTable[k] = v; + } + }); + } + return mapTable; + } + + /// Builds the mapping table that is used to map the decoded + /// text to get the expected text. + Map getDifferencesDictionary() { + final Map differencesDictionary = {}; + PdfDictionary? encodingDictionary; + + if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { + if (fontDictionary[PdfDictionaryProperties.encoding] + is PdfReferenceHolder) { + final IPdfPrimitive? primitive = PdfCrossTable.dereference( + fontDictionary[PdfDictionaryProperties.encoding], + ); + if (primitive != null && primitive is PdfDictionary) { + encodingDictionary = primitive; + } + } else if (fontDictionary[PdfDictionaryProperties.encoding] + is PdfDictionary) { + encodingDictionary = + fontDictionary[PdfDictionaryProperties.encoding] as PdfDictionary?; + } + + if (encodingDictionary != null) { + if (encodingDictionary.containsKey( + PdfDictionaryProperties.differences, + )) { + int differenceCount = 0; + final IPdfPrimitive? obj = + encodingDictionary[PdfDictionaryProperties.differences]; + PdfArray? differences; + if (obj is PdfArray) { + differences = obj; + } else if (obj is PdfReferenceHolder && obj.object is PdfArray) { + differences = obj.object as PdfArray?; + } + if (differences != null) { + for (int i = 0; i < differences.count; i++) { + String? text = ''; + if (differences[i] is PdfNumber) { + final PdfNumber number = differences[i]! as PdfNumber; + text = number.value.toString(); + differenceCount = number.value!.toInt(); + } else if (differences[i] is PdfName) { + text = (differences[i]! as PdfName).name; + if ((fontType!.name == 'Type1') && (text == '.notdef')) { + text = ' '; + differencesDictionary[differenceCount + .toString()] = getLatinCharacter(text); + differenceCount++; + } else { + text = getLatinCharacter(text); + text = getSpecialCharacter(text); + if (!differencesDictionary.containsKey( + differenceCount.toString(), + )) { + differencesDictionary[differenceCount + .toString()] = getLatinCharacter(text); + } + differenceCount++; + } + } + } + differences = null; + } + } + } + } + encodingDictionary = null; + return differencesDictionary; + } + + /// Gets Latin Character + /// Latin Character Set (APPENDIX D Pdf version-1.7) Page- 997 + String? getLatinCharacter(String? decodedCharacter) { + switch (decodedCharacter) { + case 'zero': + return '0'; + case 'one': + return '1'; + case 'two': + return '2'; + case 'three': + return '3'; + case 'four': + return '4'; + case 'five': + return '5'; + case 'six': + return '6'; + case 'seven': + return '7'; + case 'eight': + return '8'; + case 'nine': + return '9'; + case 'aacute': + return 'á'; + case 'asciicircum': + return '^'; + case 'asciitilde': + return '~'; + case 'asterisk': + return '*'; + case 'at': + return '@'; + case 'atilde': + return 'ã'; + case 'backslash': + return r'\'; + case 'bar': + return '|'; + case 'braceleft': + return '{'; + case 'braceright': + return '}'; + case 'bracketleft': + return '['; + case 'bracketright': + return ']'; + case 'breve': + return '˘'; + case 'brokenbar': + return '|'; + case 'bullet3': + return '•'; + case 'bullet': + return '•'; + case 'caron': + return 'ˇ'; + case 'ccedilla': + return 'ç'; + case 'cedilla': + return '¸'; + case 'cent': + return '¢'; + case 'circumflex': + return 'ˆ'; + case 'colon': + return ':'; + case 'comma': + return ','; + case 'copyright': + return '©'; + case 'currency1': + return '¤'; + case 'dagger': + return '†'; + case 'daggerdbl': + return '‡'; + case 'degree': + return '°'; + case 'dieresis': + return '¨'; + case 'divide': + return '÷'; + case 'dollar': + return r'$'; + case 'dotaccent': + return '˙'; + case 'dotlessi': + return 'ı'; + case 'eacute': + return 'é'; + case 'middot': + return '˙'; + case 'edieresis': + return 'ë'; + case 'egrave': + return 'è'; + case 'ellipsis': + return '...'; + case 'emdash': + return '—'; + case 'endash': + return '–'; + case 'equal': + return '='; + case 'eth': + return 'ð'; + case 'exclam': + return '!'; + case 'exclamdown': + return '¡'; + //case 'fi': + // return 'fl'; + case 'florin': + return 'ƒ'; + case 'fraction': + return '⁄'; + case 'germandbls': + return 'ß'; + case 'grave': + return '`'; + case 'greater': + return '>'; + case 'guillemotleft4': + return '«'; + case 'guillemotright4': + return '»'; + case 'guilsinglleft': + return '‹'; + case 'guilsinglright': + return '›'; + case 'hungarumlaut': + return '˝'; + case 'hyphen5': + return '-'; + case 'iacute': + return 'í'; + case 'icircumflex': + return 'î'; + case 'idieresis': + return 'ï'; + case 'igrave': + return 'ì'; + case 'less': + return '<'; + case 'logicalnot': + return '¬'; + case 'lslash': + return 'ł'; + case 'Lslash': + return 'Ł'; + case 'macron': + return '¯'; + case 'minus': + return '−'; + case 'mu': + return 'μ'; + case 'multiply': + return '×'; + case 'ntilde': + return 'ñ'; + case 'numbersign': + return '#'; + case 'oacute': + return 'ó'; + case 'ocircumflex': + return 'ô'; + case 'odieresis': + return 'ö'; + case 'oe': + return 'oe'; + case 'ogonek': + return '˛'; + case 'ograve': + return 'ò'; + case 'onehalf': + return '1/2'; + case 'onequarter': + return '1/4'; + case 'onesuperior': + return '¹'; + case 'ordfeminine': + return 'ª'; + case 'ordmasculine': + return 'º'; + case 'otilde': + return 'õ'; + case 'paragraph': + return '¶'; + case 'parenleft': + return '('; + case 'parenright': + return ')'; + case 'percent': + return '%'; + case 'period': + return '.'; + case 'periodcentered': + return '·'; + case 'perthousand': + return '‰'; + case 'plus': + return '+'; + case 'plusminus': + return '±'; + case 'question': + return '?'; + case 'questiondown': + return '¿'; + case 'quotedbl': + return '"'; + case 'quotedblbase': + return '„'; + case 'quotedblleft': + return '“'; + case 'quotedblright': + return '”'; + case 'quoteleft': + return '‘'; + case 'quoteright': + return '’'; + case 'quotesinglbase': + return '‚'; + case 'quotesingle': + return "'"; + case 'registered': + return '®'; + case 'ring': + return '˚'; + case 'scaron': + return 'š'; + case 'section': + return '§'; + case 'semicolon': + return ';'; + case 'slash': + return '/'; + case 'space6': + return ' '; + case 'space': + return ' '; + case 'udieresis': + return 'ü'; + case 'uacute': + return 'ú'; + case 'Ecircumflex': + return 'Ê'; + case 'hyphen': + return '-'; + case 'underscore': + return '_'; + case 'adieresis': + return 'ä'; + case 'ampersand': + return '&'; + case 'Adieresis': + return 'Ä'; + case 'Udieresis': + return 'Ü'; + case 'ccaron': + return 'č'; + case 'Scaron': + return 'Š'; + case 'zcaron': + return 'ž'; + case 'sterling': + return '£'; + case 'agrave': + return 'à'; + case 'ecircumflex': + return 'ê'; + case 'acircumflex': + return 'â'; + case 'Oacute': + return 'Ó'; + default: + return decodedCharacter; + } + } + + /// Gets Latin Character + /// Latin Character Set (APPENDIX D Pdf version-1.7) Page- 997 + String? getSpecialCharacter(String? decodedCharacter) { + switch (decodedCharacter) { + case 'head2right': + return '\u27A2'; + case 'aacute': + return 'a\u0301'; + case 'eacute': + return 'e\u0301'; + case 'iacute': + return 'i\u0301'; + case 'oacute': + return 'o\u0301'; + case 'uacute': + return 'u\u0301'; + case 'circleright': + return '\u27B2'; + case 'bleft': + return '\u21E6'; + case 'bright': + return '\u21E8'; + case 'bup': + return '\u21E7'; + case 'bdown': + return '\u21E9'; + case 'barb4right': + return '\u2794'; + case 'bleftright': + return '\u2B04'; + case 'bupdown': + return '\u21F3'; + case 'bnw': + return '\u2B00'; + case 'bne': + return '\u2B01'; + case 'bsw': + return '\u2B03'; + case 'bse': + return '\u2B02'; + case 'bdash1': + return '\u25AD'; + case 'bdash2': + return '\u25AB'; + case 'xmarkbld': + return '\u2717'; + case 'checkbld': + return '\u2713'; + case 'boxxmarkbld': + return '\u2612'; + case 'boxcheckbld': + return '\u2611'; + case 'space': + return '\u0020'; + case 'pencil': + return '\u270F'; + case 'scissors': + return '\u2702'; + case 'scissorscutting': + return '\u2701'; + case 'readingglasses': + return '\u2701'; + case 'bell': + return '\u2701'; + case 'book': + return '\u2701'; + case 'telephonesolid': + return '\u2701'; + case 'telhandsetcirc': + return '\u2701'; + case 'envelopeback': + return '\u2701'; + case 'hourglass': + return '\u231B'; + case 'keyboard': + return '\u2328'; + case 'tapereel': + return '\u2707'; + case 'handwrite': + return '\u270D'; + case 'handv': + return '\u270C'; + case 'handptleft': + return '\u261C'; + case 'handptright': + return '\u261E'; + case 'handptup': + return '\u261D'; + case 'handptdown': + return '\u261F'; + case 'smileface': + return '\u263A'; + case 'frownface': + return '\u2639'; + case 'skullcrossbones': + return '\u2620'; + case 'flag': + return '\u2690'; + case 'pennant': + return '\u1F6A9'; + case 'airplane': + return '\u2708'; + case 'sunshine': + return '\u263C'; + case 'droplet': + return '\u1F4A7'; + case 'snowflake': + return '\u2744'; + case 'crossshadow': + return '\u271E'; + case 'crossmaltese': + return '\u2720'; + case 'starofdavid': + return '\u2721'; + case 'crescentstar': + return '\u262A'; + case 'yinyang': + return '\u262F'; + case 'om': + return '\u0950'; + case 'wheel': + return '\u2638'; + case 'aries': + return '\u2648'; + case 'taurus': + return '\u2649'; + case 'gemini': + return '\u264A'; + case 'cancer': + return '\u264B'; + case 'leo': + return '\u264C'; + case 'virgo': + return '\u264D'; + case 'libra': + return '\u264E'; + case 'scorpio': + return '\u264F'; + case 'saggitarius': + return '\u2650'; + case 'capricorn': + return '\u2651'; + case 'aquarius': + return '\u2652'; + case 'pisces': + return '\u2653'; + case 'ampersanditlc': + return '\u0026'; + case 'ampersandit': + return '\u0026'; + case 'circle6': + return '\u25CF'; + case 'circleshadowdwn': + return '\u274D'; + case 'square6': + return '\u25A0'; + case 'box3': + return '\u25A1'; + case 'boxshadowdwn': + return '\u2751'; + case 'boxshadowup': + return '\u2752'; + case 'lozenge4': + return '\u2B27'; + case 'lozenge6': + return '\u29EB'; + case 'rhombus6': + return '\u25C6'; + case 'xrhombus': + return '\u2756'; + case 'rhombus4': + return '\u2B25'; + case 'clear': + return '\u2327'; + case 'escape': + return '\u2353'; + case 'command': + return '\u2318'; + case 'rosette': + return '\u2740'; + case 'rosettesolid': + return '\u273F'; + case 'quotedbllftbld': + return '\u275D'; + case 'quotedblrtbld': + return '\u275E'; + case '.notdef': + return '\u25AF'; + case 'zerosans': + return '\u24EA'; + case 'onesans': + return '\u2460'; + case 'twosans': + return '\u2461'; + case 'threesans': + return '\u2462'; + case 'foursans': + return '\u2463'; + case 'fivesans': + return '\u2464'; + case 'sixsans': + return '\u2465'; + case 'sevensans': + return '\u2466'; + case 'eightsans': + return '\u2467'; + case 'ninesans': + return '\u2468'; + case 'tensans': + return '\u2469'; + case 'zerosansinv': + return '\u24FF'; + case 'onesansinv': + return '\u2776'; + case 'twosansinv': + return '\u2777'; + case 'threesansinv': + return '\u2778'; + case 'foursansinv': + return '\u2779'; + case 'circle2': + return '\u00B7'; + case 'circle4': + return '\u2022'; + case 'square2': + return '\u25AA'; + case 'ring2': + return '\u25CB'; + case 'ringbutton2': + return '\u25C9'; + case 'target': + return '\u25CE'; + case 'square4': + return '\u25AA'; + case 'box2': + return '\u25FB'; + case 'crosstar2': + return '\u2726'; + case 'pentastar2': + return '\u2605'; + case 'hexstar2': + return '\u2736'; + case 'octastar2': + return '\u2734'; + case 'dodecastar3': + return '\u2739'; + case 'octastar4': + return '\u2735'; + case 'registercircle': + return '\u2316'; + case 'cuspopen': + return '\u27E1'; + case 'cuspopen1': + return '\u2311'; + case 'circlestar': + return '\u2605'; + case 'starshadow': + return '\u2730'; + case 'deleteleft': + return '\u232B'; + case 'deleteright': + return '\u2326'; + case 'scissorsoutline': + return '\u2704'; + case 'telephone': + return '\u260F'; + case 'telhandset': + return '\u1F4DE'; + case 'handptlft1': + return '\u261C'; + case 'handptrt1': + return '\u261E'; + case 'handptlftsld1': + return '\u261A'; + case 'handptrtsld1': + return '\u261B'; + case 'handptup1': + return '\u261D'; + case 'handptdwn1': + return '\u261F'; + case 'xmark': + return '\u2717'; + case 'check': + return '\u2713'; + case 'boxcheck': + return '\u2611'; + case 'boxx': + return '\u2612'; + case 'boxxbld': + return '\u2612'; + case 'circlex': + return '=\u2314'; + case 'circlexbld': + return '\u2314'; + case 'prohibit': + case 'prohibitbld': + return '\u29B8'; + case 'ampersanditaldm': + case 'ampersandbld': + case 'ampersandsans': + case 'ampersandsandm': + return '\u0026'; + case 'interrobang': + case 'interrobangdm': + case 'interrobangsans': + case 'interrobngsandm': + return '\u203D'; + case 'sacute': + return 'ś'; + case 'Sacute': + return 'Ś'; + case 'eogonek': + return 'ę'; + case 'cacute': + return 'ć'; + case 'aogonek': + return 'ą'; + default: + return decodedCharacter; + } + } + + /// internal method + void getMacEncodeTable() { + _macEncodeTable = {}; + _macEncodeTable![127] = ' '; + _macEncodeTable![128] = 'Ä'; + _macEncodeTable![129] = 'Å'; + _macEncodeTable![130] = 'Ç'; + _macEncodeTable![131] = 'É'; + _macEncodeTable![132] = 'Ñ'; + _macEncodeTable![133] = 'Ö'; + _macEncodeTable![134] = 'Ü'; + _macEncodeTable![135] = 'á'; + _macEncodeTable![136] = 'à'; + _macEncodeTable![137] = 'â'; + _macEncodeTable![138] = 'ä'; + _macEncodeTable![139] = 'ã'; + _macEncodeTable![140] = 'å'; + _macEncodeTable![141] = 'ç'; + _macEncodeTable![142] = 'é'; + _macEncodeTable![143] = 'è'; + _macEncodeTable![144] = 'ê'; + _macEncodeTable![145] = 'ë'; + _macEncodeTable![146] = 'í'; + _macEncodeTable![147] = 'ì'; + _macEncodeTable![148] = 'î'; + _macEncodeTable![149] = 'ï'; + _macEncodeTable![150] = 'ñ'; + _macEncodeTable![151] = 'ó'; + _macEncodeTable![152] = 'ò'; + _macEncodeTable![153] = 'ô'; + _macEncodeTable![154] = 'ö'; + _macEncodeTable![155] = 'õ'; + _macEncodeTable![156] = 'ú'; + _macEncodeTable![157] = 'ù'; + _macEncodeTable![158] = 'û'; + _macEncodeTable![159] = 'ü'; + _macEncodeTable![160] = '†'; + _macEncodeTable![161] = '°'; + _macEncodeTable![162] = '¢'; + _macEncodeTable![163] = '£'; + _macEncodeTable![164] = '§'; + _macEncodeTable![165] = '•'; + _macEncodeTable![166] = '¶'; + _macEncodeTable![167] = 'ß'; + _macEncodeTable![168] = '®'; + _macEncodeTable![169] = '©'; + _macEncodeTable![170] = '™'; + _macEncodeTable![171] = '´'; + _macEncodeTable![172] = '¨'; + _macEncodeTable![173] = '≠'; + _macEncodeTable![174] = 'Æ'; + _macEncodeTable![175] = 'Ø'; + _macEncodeTable![176] = '∞'; + _macEncodeTable![177] = '±'; + _macEncodeTable![178] = '≤'; + _macEncodeTable![179] = '≥'; + _macEncodeTable![180] = '¥'; + _macEncodeTable![181] = 'µ'; + _macEncodeTable![182] = '∂'; + _macEncodeTable![183] = '∑'; + _macEncodeTable![184] = '∏'; + _macEncodeTable![185] = 'π'; + _macEncodeTable![186] = '∫'; + _macEncodeTable![187] = 'ª'; + _macEncodeTable![188] = 'º'; + _macEncodeTable![189] = 'Ω'; + _macEncodeTable![190] = 'æ'; + _macEncodeTable![191] = 'ø'; + _macEncodeTable![192] = '¿'; + _macEncodeTable![193] = '¡'; + _macEncodeTable![194] = '¬'; + _macEncodeTable![195] = '√'; + _macEncodeTable![196] = 'ƒ'; + _macEncodeTable![197] = '≈'; + _macEncodeTable![198] = '∆'; + _macEncodeTable![199] = '«'; + _macEncodeTable![200] = '»'; + _macEncodeTable![201] = '…'; + _macEncodeTable![202] = ' '; + _macEncodeTable![203] = 'À'; + _macEncodeTable![204] = 'Ã'; + _macEncodeTable![205] = 'Õ'; + _macEncodeTable![206] = 'Œ'; + _macEncodeTable![207] = 'œ'; + _macEncodeTable![208] = '–'; + _macEncodeTable![209] = '—'; + _macEncodeTable![210] = '“'; + _macEncodeTable![211] = '”'; + _macEncodeTable![212] = '‘'; + _macEncodeTable![213] = '’'; + _macEncodeTable![214] = '÷'; + _macEncodeTable![215] = '◊'; + _macEncodeTable![216] = 'ÿ'; + _macEncodeTable![217] = 'Ÿ'; + _macEncodeTable![218] = '⁄'; + _macEncodeTable![219] = '€'; + _macEncodeTable![220] = '‹'; + _macEncodeTable![221] = '›'; + _macEncodeTable![222] = 'fi'; + _macEncodeTable![223] = 'fl'; + _macEncodeTable![224] = '‡'; + _macEncodeTable![225] = '·'; + _macEncodeTable![226] = ','; + _macEncodeTable![227] = '„'; + _macEncodeTable![228] = '‰'; + _macEncodeTable![229] = 'Â'; + _macEncodeTable![230] = 'Ê'; + _macEncodeTable![231] = 'Á'; + _macEncodeTable![232] = 'Ë'; + _macEncodeTable![233] = 'È'; + _macEncodeTable![234] = 'Í'; + _macEncodeTable![235] = 'Î'; + _macEncodeTable![236] = 'Ï'; + _macEncodeTable![237] = 'Ì'; + _macEncodeTable![238] = 'Ó'; + _macEncodeTable![239] = 'Ô'; + _macEncodeTable![240] = ''; + _macEncodeTable![241] = 'Ò'; + _macEncodeTable![242] = 'Ú'; + _macEncodeTable![243] = 'Û'; + _macEncodeTable![244] = 'Ù'; + _macEncodeTable![245] = 'ı'; + _macEncodeTable![246] = 'ˆ'; + _macEncodeTable![247] = '˜'; + _macEncodeTable![248] = '¯'; + _macEncodeTable![249] = '˘'; + _macEncodeTable![250] = '˙'; + _macEncodeTable![251] = '˚'; + _macEncodeTable![252] = '¸'; + _macEncodeTable![253] = '˝'; + _macEncodeTable![254] = '˛'; + _macEncodeTable![255] = 'ˇ'; + } + + /// internal method + String skipEscapeSequence(String text) { + if (text.contains(r'\')) { + final int i = text.indexOf(r'\'); + if (i + 1 != text.length) { + final String escapeSequence = text.substring(i + 1, i + 2); + switch (escapeSequence) { + case 'a': + text = text.replaceAll(r'\u0007', '\u0007'); + break; + case 'b': + text = text.replaceAll(r'\b', '\b'); + break; + case 'e': + text = text.replaceAll(r'\e', r'\e'); + break; + case 'f': + text = text.replaceAll(r'\f', '\f'); + break; + case 'n': + text = text.replaceAll(r'\n', '\n'); + break; + case 'r': + text = text.replaceAll(r'\r', '\r'); + break; + case 't': + text = text.replaceAll(r'\t', '\t'); + break; + case 'v': + text = text.replaceAll(r'\v', '\v'); + break; + case "'": + // ignore: use_raw_strings + text = text.replaceAll("\\'", "'"); + break; + default: + { + if (escapeSequence.codeUnitAt(0) == 3) { + text = text.replaceAll(r'\', r'\"'); + } else if (escapeSequence.codeUnitAt(0) >= 127) { + text = text.replaceAll(r'\', ''); + } else { + try { + text = unescape(text); + } catch (e) { + if (text.isNotEmpty) { + text = unescape(RegExp.escape(text)); + } else { + throw Exception(); + } + } + } + break; + } + } + } + } + return text; + } + + /// Organizes the hex string enclosed within the '<' '>' brackets + /// hexCode - Mapping string in the map table of the document + List getHexCode(String hexCode) { + final List tmp = []; + String tmpvalue = hexCode; + int startValue = 0; + int stopValue = 0; + String txtValue; + for (int j1 = 0; startValue >= 0; j1++) { + startValue = tmpvalue.indexOf('<'); + stopValue = tmpvalue.indexOf('>'); + if (startValue >= 0 && stopValue >= 0) { + txtValue = tmpvalue.substring(startValue + 1, stopValue); + tmp.add(txtValue); + tmpvalue = tmpvalue.substring(stopValue + 1, tmpvalue.length); + } + } + return tmp; + } + + /// internal method + String checkContainInvalidChar(String charvalue) { + for (int i = 0; i < charvalue.length; i++) { + switch (charvalue.codeUnitAt(i)) { + case 160: //No-break space + { + charvalue = ' '; + break; + } + case 61558: //Invalid Character + { + charvalue = ''; + break; + } + } + } + return charvalue; + } + + /// internal method + String decodeTextExtraction( + String textToDecode, + bool isSameFont, [ + List? charcodes, + ]) { + String decodedText = ''; + String encodedText = textToDecode; + this.isSameFont = isSameFont; + bool hasEscapeChar = false; + bool isHex = false; + switch (encodedText[0]) { + case '(': + { + while (encodedText.contains('\\\n')) { + final int n = encodedText.indexOf('\\\n'); + final List str = encodedText.split(''); + str.removeRange(n, n + 2); + encodedText = str.join(); + } + encodedText = encodedText.substring(1, encodedText.length - 1); + decodedText = getLiteralString(encodedText, charcodes); + // ignore: use_raw_strings + if (decodedText.contains('\\\\') && fontEncoding == 'Identity-H') { + hasEscapeChar = true; + decodedText = skipEscapeSequence(decodedText); + } + if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { + if (fontDictionary[PdfDictionaryProperties.encoding] is PdfName) { + if ([ + 'Identity-H', + 'UniCNS-UCS2-H', + 'UniKS-UCS2-H', + 'UniJIS-UCS2-H', + 'UniGB-UCS2-H', + ].contains( + (fontDictionary[PdfDictionaryProperties.encoding]! as PdfName) + .name, + )) { + String text = decodedText; + if (!hasEscapeChar) { + do { + text = skipEscapeSequence(text); + } while (hasEscapeCharacter(text)); + } + final List bytes = []; + for (int i = 0; i < text.length; i++) { + bytes.add(text[i].codeUnitAt(0).toUnsigned(8)); + } + decodedText = decodeBigEndian(bytes); + } + } + } + } + break; + case '[': + { + while (encodedText.contains('\\\n')) { + final int n = encodedText.indexOf('\\\n'); + final List str = encodedText.split(''); + str.removeRange(n, n + 2); + encodedText = str.join(); + } + encodedText = encodedText.substring(1, encodedText.length - 1); + while (encodedText.isNotEmpty) { + isHex = false; + int textStart = encodedText.indexOf('('); + int textEnd = encodedText.indexOf(')'); + final int textHexStart = encodedText.indexOf('<'); + final int textHexEnd = encodedText.indexOf('>'); + + if (textHexStart < textStart && textHexStart > -1) { + textStart = textHexStart; + textEnd = textHexEnd; + isHex = true; + } + if (textStart < 0) { + textStart = encodedText.indexOf('<'); + textEnd = encodedText.indexOf('>'); + if (textStart >= 0) { + isHex = true; + } else { + break; + } + } else if (textEnd > 0) { + while (encodedText[textEnd - 1] == r'\') { + if (encodedText.contains(')', textEnd + 1)) { + textEnd = encodedText.indexOf(')', textEnd + 1); + } else { + break; + } + } + } + + final String tempString = encodedText.substring( + textStart + 1, + textEnd, + ); + if (isHex) { + decodedText += getHexaDecimalString(tempString, charcodes); + } else { + decodedText += getLiteralString(tempString, charcodes); + } + + encodedText = encodedText.substring( + textEnd + 1, + encodedText.length, + ); + } + } + break; + case '<': + { + final String hexEncodedText = encodedText.substring( + 1, + encodedText.length - 1, + ); + decodedText = getHexaDecimalString(hexEncodedText, charcodes); + isHex = true; + } + break; + default: + break; + } + + if (fontEncoding != 'Identity-H' || + (fontEncoding == 'Identity-H') || + (fontEncoding == 'Identity-H' && containsCmap)) { + isMappingDone = true; + if (characterMapTable.isNotEmpty) { + decodedText = mapCharactersFromTable(decodedText, isHex); + } else if (differencesDictionary.isNotEmpty) { + decodedText = mapDifferences(decodedText); + } else if (fontEncoding != '') { + decodedText = skipEscapeSequence(decodedText); + } + } + + if (cidToGidTable != null && !isTextExtraction) { + decodedText = mapCidToGid(decodedText); + } + if (_fontName == 'ZapfDingbats' && !isEmbedded) { + decodedText = mapZapf(decodedText); + } + if (fontEncoding == 'MacRomanEncoding') { + macRomanEncoded = true; + String tempstring = ''; + for (int i = 0; i < decodedText.length; i++) { + final int b = decodedText[i].codeUnitAt(0).toUnsigned(8); + if (b > 126) { + final String x = macEncodeTable![b]!; + tempstring += x; + } else { + tempstring += decodedText[i]; + } + } + if (tempstring != '') { + decodedText = tempstring; + } + } + if (decodedText.contains('\u0092')) { + decodedText = decodedText.replaceAll('\u0092', '’'); + } + if (decodedText.contains(RegExp('[\n-\r]'))) { + decodedText = decodedText.replaceAll(RegExp('[\n-\r]'), '’'); + } + isWhiteSpace = decodedText.isEmpty || (decodedText.trimRight() == ''); + return decodedText; + } + + /// internal method + List decodeCjkTextExtractionTJ(String textToDecode, bool isSameFont) { + String decodedText = ''; + String encodedText = textToDecode; + String listElement; + this.isSameFont = isSameFont; + final List decodedList = []; + if (encodedText[0] == '[') { + while (encodedText.contains('\\\n')) { + final int n = encodedText.indexOf('\\\n'); + final List str = encodedText.split(''); + str.removeRange(n, n + 2); + encodedText = str.join(); + } + encodedText = encodedText.substring(1, encodedText.length - 1); + while (encodedText.isNotEmpty) { + bool isHex = false; + int textStart = encodedText.indexOf('('); + int textEnd = encodedText.indexOf(')'); + for (int j = textEnd + 1; j < encodedText.length; j++) { + if (encodedText[j] == '(') { + break; + } else if (encodedText[j] == ')') { + textEnd = j; + break; + } + } + final int textHexStart = encodedText.indexOf('<'); + final int textHexEnd = encodedText.indexOf('>'); + if (textHexStart < textStart && textHexStart > -1) { + textStart = textHexStart; + textEnd = textHexEnd; + isHex = true; + } + if (textStart < 0) { + textStart = encodedText.indexOf('<'); + textEnd = encodedText.indexOf('>'); + if (textStart >= 0) { + isHex = true; + } else { + listElement = encodedText; + decodedList.add(listElement); + break; + } + } + if (textEnd < 0 && encodedText.isNotEmpty) { + listElement = encodedText; + decodedList.add(listElement); + break; + } else if (textEnd > 0) { + while (encodedText[textEnd - 1] == r'\') { + if (textEnd - 1 > 0 && encodedText[textEnd - 2] == r'\') { + break; + } + if (encodedText.contains(')', textEnd + 1)) { + textEnd = encodedText.indexOf(')', textEnd + 1); + } else { + break; + } + } + } + if (textStart != 0) { + listElement = encodedText.substring(0, textStart); + decodedList.add(listElement); + } + final String tempString = encodedText.substring(textStart + 1, textEnd); + listElement = + isHex + ? getHexaDecimalCJKString(tempString) + : getLiteralString(tempString); + decodedText += listElement; + listElement = skipEscapeSequence(listElement); + if (listElement.isNotEmpty) { + if (listElement[0].codeUnitAt(0) >= 3584 && + listElement[0].codeUnitAt(0) <= 3711 && + decodedList.isNotEmpty) { + String previous = decodedList[0]; + previous = previous.replaceRange( + previous.length - 1, + previous.length, + '', + ); + previous += listElement; + listElement = previous; + decodedList[0] = '${fromUnicodeText(listElement)}s'; + } else if ((listElement[0].codeUnitAt(0) == 32 || + listElement[0].codeUnitAt(0) == 47) && + listElement.length > 1) { + if (listElement[1].codeUnitAt(0) >= 3584 && + listElement[1].codeUnitAt(0) <= 3711 && + decodedList.isNotEmpty) { + String previous = decodedList[0]; + previous = previous.replaceRange( + previous.length - 1, + previous.length, + '', + ); + previous += listElement; + listElement = previous; + decodedList[0] = '${fromUnicodeText(listElement)}s'; + } else { + listElement = '${fromUnicodeText(listElement)}s'; + decodedList.add(listElement); + } + } else { + listElement = '${fromUnicodeText(listElement)}s'; + decodedList.add(listElement); + } + } else { + listElement = '${fromUnicodeText(listElement)}s'; + decodedList.add(listElement); + } + encodedText = encodedText.substring(textEnd + 1, encodedText.length); + } + } + decodedText = skipEscapeSequence(decodedText); + isWhiteSpace = decodedText.isEmpty || (decodedText.trimRight() == ''); + return decodedList; + } + + /// internal method + String getHexaDecimalCJKString(String hexEncodedText) { + int index = 0; + String result = ''; + while (index < hexEncodedText.length) { + final String hex = hexEncodedText.substring(index, index + 2); + final int charCode = int.parse(hex, radix: 16); + result += String.fromCharCode(charCode); + index += 2; + } + return result; + } + + /// internal method + Map, String> decodeTextExtractionTJ( + String textToDecode, + bool isSameFont, + ) { + String decodedText = ''; + String encodedText = textToDecode; + String listElement; + List charCodes = []; + this.isSameFont = isSameFont; + final Map, String> decodedList = , String>{}; + switch (encodedText[0]) { + case '(': + { + while (encodedText.contains('\\\n')) { + final int n = encodedText.indexOf('\\\n'); + final List str = encodedText.split(''); + str.removeRange(n, n + 2); + encodedText = str.join(); + } + encodedText = encodedText.substring(1, encodedText.length - 1); + decodedText = getLiteralString(encodedText); + if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { + if (fontDictionary[PdfDictionaryProperties.encoding] is PdfName) { + if ((fontDictionary[PdfDictionaryProperties.encoding]! as PdfName) + .name == + 'Identity-H') { + final String text = skipEscapeSequence(decodedText); + + final List bytes = []; + for (int i = 0; i < text.length; i++) { + bytes.add(text[i].codeUnitAt(0).toUnsigned(8)); + } + decodedText = decodeBigEndian(bytes); + } + } + } + } + break; + case '[': + { + while (encodedText.contains('\\\n')) { + final int n = encodedText.indexOf('\\\n'); + final List str = encodedText.split(''); + str.removeRange(n, n + 2); + encodedText = str.join(); + } + encodedText = encodedText.substring(1, encodedText.length - 1); + while (encodedText.isNotEmpty) { + bool isHex = false; + int textStart = encodedText.indexOf('('); + int textEnd = encodedText.indexOf(')'); + for (int j = textEnd + 1; j < encodedText.length; j++) { + if (encodedText[j] == '(') { + break; + } else if (encodedText[j] == ')') { + textEnd = j; + break; + } + } + final int textHexStart = encodedText.indexOf('<'); + final int textHexEnd = encodedText.indexOf('>'); + if (textHexStart < textStart && textHexStart > -1) { + textStart = textHexStart; + textEnd = textHexEnd; + isHex = true; + } + if (textStart < 0) { + textStart = encodedText.indexOf('<'); + textEnd = encodedText.indexOf('>'); + if (textStart >= 0) { + isHex = true; + } else { + listElement = encodedText; + if (listElement.trim() != '') { + decodedList[charCodes] = listElement; + charCodes = []; + } + break; + } + } + if (textEnd < 0 && encodedText.isNotEmpty) { + listElement = encodedText; + if (listElement.trim() != '') { + decodedList[charCodes] = listElement; + charCodes = []; + } + break; + } else if (textEnd > 0) { + while (encodedText[textEnd - 1] == r'\') { + if (textEnd - 1 > 0 && encodedText[textEnd - 2] == r'\') { + break; + } + if (encodedText.contains(')', textEnd + 1)) { + textEnd = encodedText.indexOf(')', textEnd + 1); + } else { + break; + } + } + } + if (textStart != 0) { + listElement = encodedText.substring(0, textStart); + if (listElement.trim() != '') { + decodedList[charCodes] = listElement; + charCodes = []; + } + } + final String tempString = encodedText.substring( + textStart + 1, + textEnd, + ); + if (isHex) { + listElement = getHexaDecimalString(tempString, charCodes); + if (listElement.contains(r'\')) { + // ignore: use_raw_strings + listElement = listElement.replaceAll('\\', '\\\\'); + } + decodedText += listElement; + } else { + listElement = getLiteralString(tempString, charCodes); + decodedText += listElement; + } + if (listElement.contains('\u0000') && + !characterMapTable.containsKey(0)) { + listElement = listElement.replaceAll( + '\u0000', + '', + ); //replace empty character. + } + listElement = skipEscapeSequence(listElement); + if (fontEncoding != 'Identity-H' || + (fontEncoding == 'Identity-H') || + (fontEncoding == 'Identity-H' && containsCmap)) { + isMappingDone = true; + if (characterMapTable.isNotEmpty) { + listElement = mapCharactersFromTable(listElement, isHex); + } else if (differencesDictionary.isNotEmpty) { + listElement = mapDifferences(listElement); + } else if (fontEncoding != '') { + listElement = skipEscapeSequence(listElement); + } + } + if (cidToGidTable != null && !isTextExtraction) { + listElement = mapCidToGid(listElement); + } + if (!isLayout && + encodedText + .substring(textEnd + 1, encodedText.length) + .trim() + .isEmpty) { + listElement = listElement.trimRight(); + } + if (listElement.contains(RegExp('[\n-\r]'))) { + listElement = listElement.replaceAll(RegExp('[\n-\r]'), ''); + } + if (listElement.isNotEmpty) { + if (listElement[0].codeUnitAt(0) >= 3584 && + listElement[0].codeUnitAt(0) <= 3711 && + decodedList.isNotEmpty) { + String previous = decodedList.values.toList()[0]; + previous = previous.replaceRange( + previous.length - 1, + previous.length, + '', + ); + previous += listElement; + listElement = previous; + decodedList[decodedList.keys.toList()[0]] = '${listElement}s'; + } else if ((listElement[0].codeUnitAt(0) == 32 || + listElement[0].codeUnitAt(0) == 47) && + listElement.length > 1) { + if (listElement[1].codeUnitAt(0) >= 3584 && + listElement[1].codeUnitAt(0) <= 3711 && + decodedList.isNotEmpty) { + String previous = decodedList.values.toList()[0]; + previous = previous.replaceRange( + previous.length - 1, + previous.length, + '', + ); + previous += listElement; + listElement = previous; + decodedList[decodedList.keys.toList()[0]] = '${listElement}s'; + } else { + listElement += 's'; + decodedList[charCodes] = listElement; + charCodes = []; + } + } else { + listElement += 's'; + decodedList[charCodes] = listElement; + charCodes = []; + } + } else { + listElement = '${listElement.trimRight()}s'; + decodedList[charCodes] = listElement; + charCodes = []; + } + encodedText = encodedText.substring( + textEnd + 1, + encodedText.length, + ); + } + } + break; + case '<': + { + final String hexEncodedText = encodedText.substring( + 1, + encodedText.length - 1, + ); + decodedText = getHexaDecimalString(hexEncodedText, charCodes); + } + break; + default: + break; + } + decodedText = skipEscapeSequence(decodedText); + isWhiteSpace = + decodedText.isEmpty || + (!decodedText.contains(RegExp(r'[\f\r]')) && + decodedText.trimRight().isEmpty); + return decodedList; + } + + /// internal method + String fromUnicodeText(String value) { + String result = ''; + if (value.length % 2 != 0) { + for (int i = 0; i < value.length; i++) { + if (i + 1 < value.length) { + result += String.fromCharCode( + (value.codeUnitAt(i) * 256) + value.codeUnitAt(i + 1), + ); + i++; + } else { + result += String.fromCharCode(value.codeUnitAt(i)); + } + } + } else { + for (int i = 0; i < value.length; i++) { + result += String.fromCharCode( + (value.codeUnitAt(i) * 256) + value.codeUnitAt(i + 1), + ); + i++; + } + } + isWhiteSpace = result.isEmpty || result.trimRight() == ''; + return result; + } + + /// internal method + String getEncodedText(String textElement, bool isSameFont) { + String encodedText = ''; + String textToEncode = textElement; + this.isSameFont = isSameFont; + bool hasEscapeChar = false; + switch (textToEncode[0]) { + case '(': + { + if (textToEncode.contains('\\\n')) { + final int n = textToEncode.indexOf('\\\n'); + final List str = textToEncode.split(''); + str.removeRange(n, n + 2); + textToEncode = str.join(); + } + textToEncode = textToEncode.substring(1, textToEncode.length - 1); + encodedText = getLiteralString(textToEncode); + // ignore: use_raw_strings + if (encodedText.contains('\\\\') && fontEncoding == 'Identity-H') { + hasEscapeChar = true; + encodedText = skipEscapeSequence(encodedText); + } + if (fontDictionary.containsKey(PdfDictionaryProperties.encoding)) { + final IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.encoding]; + if (primitive is PdfName) { + final String? encoding = primitive.name; + if (encoding == 'Identity-H') { + String text = encodedText; + if (!hasEscapeChar) { + if (text.contains(r'\a') || + text.contains(r'\') || + text.contains(r'\b') || + text.contains(r'\f') || + text.contains(r'\r') || + text.contains(r'\t') || + text.contains(r'\n') || + text.contains(r'\v') || + // ignore: avoid_escaping_inner_quotes + text.contains('\\\'')) { + while (text.contains(r'\a') || + text.contains(r'\') || + text.contains(r'\b') || + text.contains(r'\f') || + text.contains(r'\r') || + text.contains(r'\t') || + text.contains(r'\n') || + text.contains(r'\v') || + // ignore: avoid_escaping_inner_quotes + text.contains('\\\'')) { + text = skipEscapeSequence(text); + } + } else { + text = skipEscapeSequence(text); + } + } + final List bytes = []; + for (int i = 0; i < text.length; i++) { + bytes.add(text.codeUnitAt(0).toUnsigned(8)); + } + if (encoding == 'Identity-H') { + encodedText = decodeBigEndian(bytes); + } + if (encodedText.contains(r'\')) { + // ignore: use_raw_strings + encodedText = encodedText.replaceAll('\\', '\\\\'); + } + } + } + } + } + break; + case '[': + { + if (textToEncode.contains('\\\n')) { + final int n = textToEncode.indexOf('\\\n'); + final List str = textToEncode.split(''); + str.removeRange(n, n + 2); + textToEncode = str.join(); + } + textToEncode = textToEncode.substring(1, textToEncode.length - 1); + while (textToEncode.isNotEmpty) { + bool isHex = false; + int textStart = textToEncode.indexOf('('); + int textEnd = textToEncode.indexOf(')'); + final int textHexStart = textToEncode.indexOf('<'); + final int textHexEnd = textToEncode.indexOf('>'); + for (int j = textEnd + 1; j < textToEncode.length; j++) { + if (textToEncode[j] == '(') { + break; + } else if (textToEncode[j] == ')') { + textEnd = j; + break; + } + } + if (textHexStart < textStart && textHexStart > -1) { + textStart = textHexStart; + textEnd = textHexEnd; + isHex = true; + } + if (textStart < 0) { + textStart = textToEncode.indexOf('<'); + textEnd = textToEncode.indexOf('>'); + if (textStart >= 0) { + isHex = true; + } else { + break; + } + } else if (textEnd > 0) { + while (textToEncode[textEnd - 1] == r'\') { + if (textToEncode.contains(')', textEnd + 1)) { + textEnd = textToEncode.indexOf(')', textEnd + 1); + } else { + break; + } + } + } + final String tempString = textToEncode.substring( + textStart + 1, + textEnd, + ); + if (isHex) { + encodedText += getHexaDecimalString(tempString); + } else if (!isHex && fontEncoding == 'Identity-H') { + encodedText += getRawString(tempString); + } else { + encodedText += getLiteralString(tempString); + } + textToEncode = textToEncode.substring( + textEnd + 1, + textToEncode.length, + ); + } + } + break; + case '<': + { + final String hexEncodedText = textToEncode.substring( + 1, + textToEncode.length - 1, + ); + encodedText = getHexaDecimalString(hexEncodedText); + if (encodedText.contains(r'\')) { + // ignore: use_raw_strings + encodedText = encodedText.replaceAll('\\', '\\\\'); + } + } + break; + default: + break; + } + if (encodedText.contains('\u0000') && + characterMapTable.isNotEmpty && + !characterMapTable.containsKey('\u0000'.codeUnitAt(0))) { + encodedText = encodedText.replaceAll('\u0000', ''); + } + if (!isTextExtraction) { + encodedText = skipEscapeSequence(encodedText); + } + isWhiteSpace = + encodedText.isEmpty || + (!encodedText.contains(RegExp(r'[\f\r]')) && + encodedText.trimRight().isEmpty); + return encodedText; + } + + /// internal method + bool isCIDFontType() { + bool iscid = false; + if (fontDictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { + IPdfPrimitive? primitive = + fontDictionary[PdfDictionaryProperties.descendantFonts]; + if (primitive is PdfReferenceHolder) { + final PdfReferenceHolder descendantFontArrayReference = primitive; + primitive = descendantFontArrayReference.object; + if (primitive is PdfArray) { + final PdfArray descendantFontArray = primitive; + if (descendantFontArray.count > 0 && + descendantFontArray[0] is PdfReferenceHolder) { + primitive = (descendantFontArray[0]! as PdfReferenceHolder).object; + if (primitive is PdfDictionary) { + final PdfDictionary descendantDictionary = primitive; + if (descendantDictionary.containsKey( + PdfDictionaryProperties.subtype, + )) { + primitive = + descendantDictionary[PdfDictionaryProperties.subtype]; + if (primitive is PdfName) { + final PdfName subtype = + descendantDictionary[PdfDictionaryProperties.subtype]! + as PdfName; + if (subtype.name == 'CIDFontType2' || + subtype.name == 'CIDFontType0') { + iscid = true; + } + } + } + } + } + } + } else if (primitive is PdfArray) { + final PdfArray descendantFontArray = primitive; + if (descendantFontArray.count > 0 && + descendantFontArray[0] is PdfReferenceHolder) { + primitive = (descendantFontArray[0]! as PdfReferenceHolder).object; + if (primitive is PdfDictionary) { + final PdfDictionary descendantDictionary = primitive; + if (descendantDictionary.containsKey( + PdfDictionaryProperties.subtype, + )) { + primitive = descendantDictionary[PdfDictionaryProperties.subtype]; + if (primitive is PdfName) { + final PdfName subtype = + descendantDictionary[PdfDictionaryProperties.subtype]! + as PdfName; + if (subtype.name == 'CIDFontType2' || + subtype.name == 'CIDFontType0') { + iscid = true; + } + } + } + } + } + } + } + return iscid; + } + + /// internal method + String getRawString(String decodedText) { + String rawString = ''; + int charCode = 0; + bool isNonPrintable = false; + if (fontEncoding != null && fontEncoding == 'Identity-H' && isCid) { + for (int i = 0; i < decodedText.length; i++) { + final String rawChar = decodedText[i]; + final int codeUnit = decodedText.codeUnitAt(i); + if (codeUnit == 1) { + charCode = codeUnit; + rawString += rawChar; + } else if (rawChar == r'\') { + isNonPrintable = true; + rawString += r'\'; + } else if (isNonPrintable) { + String escapeChar = rawChar; + bool isEscapeCharacter = false; + switch (escapeChar) { + case 'n': + { + escapeChar = '\n'; + isEscapeCharacter = true; + break; + } + case 'b': + { + escapeChar = '\b'; + isEscapeCharacter = true; + break; + } + case 't': + { + escapeChar = '\t'; + isEscapeCharacter = true; + break; + } + case 'r': + { + escapeChar = '\r'; + isEscapeCharacter = true; + break; + } + case 'f': + { + escapeChar = '\f'; + isEscapeCharacter = true; + break; + } + default: + { + charCode = (charCode * 256) + codeUnit; + rawString += String.fromCharCode(charCode); + isNonPrintable = false; + charCode = 0; + } + break; + } + if (isEscapeCharacter) { + rawString += escapeChar; + isNonPrintable = false; + charCode = 0; + } + } else { + charCode = (charCode * 256) + codeUnit; + rawString += String.fromCharCode(charCode); + charCode = 0; + } + } + decodedText = rawString; + } + return decodedText; + } + + /// Takes in the decoded text and maps it with its + /// corresponding entry in the CharacterMapTable + String mapDifferences(String? encodedText) { + String decodedText = ''; + bool skip = false; + if (isTextExtraction) { + try { + encodedText = unescape(encodedText!); + } catch (e) { + if (encodedText != null && encodedText.isNotEmpty) { + encodedText = RegExp.escape( + encodedText, + ).replaceAll(r"\'''", r"'''").replaceAll(r'\\', r'\'); + } else { + throw ArgumentError(e.toString()); + } + } + } else { + skipEscapeSequence(encodedText!); + } + for (int i = 0; i < encodedText.length; i++) { + final int character = encodedText.codeUnitAt(i); + if (differencesDictionary.containsKey(character.toString())) { + final String tempString = differencesDictionary[character.toString()]!; + if ((tempString.length > 1) && + (fontType!.name != 'Type3') && + (!isTextExtraction)) { + decodedText += character.toString(); + } else { + if (!isTextExtraction) { + String textDecoded = differencesDictionary[character.toString()]!; + if (textDecoded.length == 7 && + textDecoded.toLowerCase().startsWith('uni')) { + textDecoded = String.fromCharCode( + int.parse(textDecoded.substring(3), radix: 16), + ); + } + decodedText += textDecoded; + } else { + if (!differencesDictionary.containsKey(character.toString())) { + final AdobeGlyphList glyphList = AdobeGlyphList(); + decodedText += glyphList.getUnicode(tempString)!; + glyphList.map!.clear(); + } else { + final String textDecoded = + differencesDictionary[character.toString()]!; + decodedText += textDecoded; + } + } + } + if (!reverseDictMapping.containsKey( + differencesDictionary[character.toString()], + )) { + reverseDictMapping[differencesDictionary[character.toString()]] = + character; + } + if (fontName == 'Wingdings') { + decodedText = mapDifferenceOfWingDings(decodedText); + } + + final String? specialCharacter = getSpecialCharacter(decodedText); + if (decodedText != specialCharacter && !isEmbedded) { + decodedText = decodedText.replaceAll(decodedText, specialCharacter!); + } + skip = false; + } else { + if (skip) { + switch (encodedText[i]) { + case 'n': + if (differencesDictionary.containsKey( + '\n'.codeUnitAt(0).toString(), + )) { + decodedText += + differencesDictionary['\n'.codeUnitAt(0).toString()]!; + } + break; + case 'r': + if (differencesDictionary.containsKey( + '\r'.codeUnitAt(0).toString(), + )) { + decodedText += + differencesDictionary['\r'.codeUnitAt(0).toString()]!; + } + break; + default: + break; + } + skip = false; + } else if (encodedText[i] == r'\') { + skip = true; + } else { + decodedText += encodedText[i]; + } + } + } + return decodedText; + } + + /// internal method + String mapZapf(String encodedText) { + String decodedtext = ''; + for (int i = 0; i < encodedText.length; i++) { + final int character = encodedText.codeUnitAt(i); + final String result = character.toRadixString(16); + switch (result.toUpperCase()) { + case '20': + decodedtext += '\u0020'; + zapfPostScript += 'space '; + break; + case '21': + decodedtext += '\u2701'; + zapfPostScript += 'a1 '; + break; + case '22': + decodedtext += '\u2702'; + zapfPostScript += 'a2 '; + break; + case '23': + decodedtext += '\u2703'; + zapfPostScript += 'a202 '; + break; + case '24': + decodedtext += '\u2704'; + zapfPostScript += 'a3 '; + break; + case '25': + decodedtext += '\u260E'; + zapfPostScript += 'a4 '; + break; + case '26': + decodedtext += '\u2706'; + zapfPostScript += 'a5 '; + break; + case '27': + decodedtext += '\u2707'; + zapfPostScript += 'a119 '; + break; + case '28': + decodedtext += '\u2708'; + zapfPostScript += 'a118 '; + break; + case '29': + decodedtext += '\u2709'; + zapfPostScript += 'a117 '; + break; + case '2A': + decodedtext += '\u261B'; + zapfPostScript += 'a11 '; + break; + case '2B': + decodedtext += '\u261E'; + zapfPostScript += 'a12 '; + break; + case '2C': + decodedtext += '\u270C'; + zapfPostScript += 'a13 '; + break; + case '2D': + decodedtext += '\u270D'; + zapfPostScript += 'a14 '; + break; + case '2E': + decodedtext += '\u270E'; + zapfPostScript += 'a15 '; + break; + case '2F': + decodedtext += '\u270F'; + zapfPostScript += 'a16 '; + break; + case '30': + decodedtext += '\u2710'; + zapfPostScript += 'a105 '; + break; + case '31': + decodedtext += '\u2711'; + zapfPostScript += 'a17 '; + break; + case '32': + decodedtext += '\u2712'; + zapfPostScript += 'a18 '; + break; + case '33': + decodedtext += '\u2713'; + zapfPostScript += 'a19 '; + break; + case '34': + decodedtext += '\u2714'; + zapfPostScript += 'a20 '; + break; + case '35': + decodedtext += '\u2715'; + zapfPostScript += 'a21 '; + break; + case '36': + decodedtext += '\u2716'; + zapfPostScript += 'a22 '; + break; + case '37': + decodedtext += '\u2717'; + zapfPostScript += 'a23 '; + break; + case '38': + decodedtext += '\u2718'; + zapfPostScript += 'a24 '; + break; + case '39': + decodedtext += '\u2719'; + zapfPostScript += 'a25 '; + break; + case '3A': + decodedtext += '\u271A'; + zapfPostScript += 'a26 '; + break; + case '3B': + decodedtext += '\u271B'; + zapfPostScript += 'a27 '; + break; + case '3C': + decodedtext += '\u271C'; + zapfPostScript += 'a28 '; + break; + case '3D': + decodedtext += '\u271D'; + zapfPostScript += 'a6 '; + break; + case '3E': + decodedtext += '\u271E'; + zapfPostScript += 'a7 '; + break; + case '3F': + decodedtext += '\u271F'; + zapfPostScript += 'a8 '; + break; + case '40': + decodedtext += '\u2720'; + zapfPostScript += 'a9 '; + break; + case '41': + decodedtext += '\u2721'; + zapfPostScript += 'a10 '; + break; + case '42': + decodedtext += '\u2722'; + zapfPostScript += 'a29 '; + break; + case '43': + decodedtext += '\u2723'; + zapfPostScript += 'a30 '; + break; + case '44': + decodedtext += '\u2724'; + zapfPostScript += 'a31 '; + break; + case '45': + decodedtext += '\u2725'; + zapfPostScript += 'a32 '; + break; + case '46': + decodedtext += '\u2726'; + zapfPostScript += 'a33 '; + break; + case '47': + decodedtext += '\u2727'; + zapfPostScript += 'a34 '; + break; + case '48': + decodedtext += '\u2605'; + zapfPostScript += 'a35 '; + break; + case '49': + decodedtext += '\u2729'; + zapfPostScript += 'a36 '; + break; + case '4A': + decodedtext += '\u272A'; + zapfPostScript += 'a37 '; + break; + case '4B': + decodedtext += '\u272B'; + zapfPostScript += 'a38 '; + break; + case '4C': + decodedtext += '\u272C'; + zapfPostScript += 'a39 '; + break; + case '4D': + decodedtext += '\u272D'; + zapfPostScript += 'a40 '; + break; + case '4E': + decodedtext += '\u272E'; + zapfPostScript += 'a41 '; + break; + case '4F': + decodedtext += '\u272F'; + zapfPostScript += 'a42 '; + break; + case '50': + decodedtext += '\u2730'; + zapfPostScript += 'a43 '; + break; + case '51': + decodedtext += '\u2731'; + zapfPostScript += 'a44 '; + break; + case '52': + decodedtext += '\u2732'; + zapfPostScript += 'a45 '; + break; + case '53': + decodedtext += '\u2733'; + zapfPostScript += 'a46 '; + break; + case '54': + decodedtext += '\u2734'; + zapfPostScript += 'a47 '; + break; + case '55': + decodedtext += '\u2735'; + zapfPostScript += 'a48 '; + break; + case '56': + decodedtext += '\u2736'; + zapfPostScript += 'a49 '; + break; + case '57': + decodedtext += '\u2737'; + zapfPostScript += 'a50 '; + break; + case '58': + decodedtext += '\u2738'; + zapfPostScript += 'a51 '; + break; + case '59': + decodedtext += '\u2739'; + zapfPostScript += 'a52 '; + break; + case '5A': + decodedtext += '\u273A'; + zapfPostScript += 'a53 '; + break; + case '5B': + decodedtext += '\u273B'; + zapfPostScript += 'a54 '; + break; + case '5C': + decodedtext += '\u273C'; + zapfPostScript += 'a55 '; + break; + case '5D': + decodedtext += '\u273D'; + zapfPostScript += 'a56 '; + break; + case '5E': + decodedtext += '\u273E'; + zapfPostScript += 'a57 '; + break; + case '5F': + decodedtext += '\u273F'; + zapfPostScript += 'a58 '; + break; + case '60': + decodedtext += '\u2740'; + zapfPostScript += 'a59 '; + break; + case '61': + decodedtext += '\u2741'; + zapfPostScript += 'a60 '; + break; + case '62': + decodedtext += '\u2742'; + zapfPostScript += 'a61 '; + break; + case '63': + decodedtext += '\u2743'; + zapfPostScript += 'a62 '; + break; + case '64': + decodedtext += '\u2744'; + zapfPostScript += 'a63 '; + break; + case '65': + decodedtext += '\u2745'; + zapfPostScript += 'a64 '; + break; + case '66': + decodedtext += '\u2746'; + zapfPostScript += 'a65 '; + break; + case '67': + decodedtext += '\u2747'; + zapfPostScript += 'a66 '; + break; + case '68': + decodedtext += '\u2748'; + zapfPostScript += 'a67 '; + break; + case '69': + decodedtext += '\u2749'; + zapfPostScript += 'a68 '; + break; + case '6A': + decodedtext += '\u274A'; + zapfPostScript += 'a69 '; + break; + case '6B': + decodedtext += '\u274B'; + zapfPostScript += 'a70 '; + break; + case '6C': + decodedtext += '\u25CF'; + zapfPostScript += 'a71 '; + break; + case '6D': + decodedtext += '\u254D'; + zapfPostScript += 'a72 '; + break; + case '6E': + decodedtext += '\u25A0'; + zapfPostScript += 'a73 '; + break; + case '6F': + decodedtext += '\u274F'; + zapfPostScript += 'a74 '; + break; + case '70': + decodedtext += '\u2750'; + zapfPostScript += 'a203 '; + break; + case '71': + decodedtext += '\u2751'; + zapfPostScript += 'a75 '; + break; + case '72': + decodedtext += '\u2752'; + zapfPostScript += 'a204 '; + break; + case '73': + decodedtext += '\u25B2'; + zapfPostScript += 'a76 '; + break; + case '74': + decodedtext += '\u25BC'; + zapfPostScript += 'a77 '; + break; + case '75': + decodedtext += '\u27C6'; + zapfPostScript += 'a78 '; + break; + case '76': + decodedtext += '\u2756'; + zapfPostScript += 'a79 '; + break; + case '77': + decodedtext += '\u25D7'; + zapfPostScript += 'a81 '; + break; + case '78': + decodedtext += '\u2758'; + zapfPostScript += 'a82 '; + break; + case '79': + decodedtext += '\u2759'; + zapfPostScript += 'a83 '; + break; + case '7A': + decodedtext += '\u275A'; + zapfPostScript += 'a84 '; + break; + case '7B': + decodedtext += '\u275B'; + zapfPostScript += 'a97 '; + break; + case '7C': + decodedtext += '\u275C'; + zapfPostScript += 'a98 '; + break; + case '7D': + decodedtext += '\u275D'; + zapfPostScript += 'a99 '; + break; + case '7E': + decodedtext += '\u275E'; + zapfPostScript += 'a100 '; + break; + case '80': + decodedtext += '\uF8D7'; + zapfPostScript += 'a89 '; + break; + case '81': + decodedtext += '\uF8D8'; + zapfPostScript += 'a90 '; + break; + case '82': + decodedtext += '\uF8D9'; + zapfPostScript += 'a93 '; + break; + case '83': + decodedtext += '\uF8DA'; + zapfPostScript += 'a94 '; + break; + case '84': + decodedtext += '\uF8DB'; + zapfPostScript += 'a91 '; + break; + case '85': + decodedtext += '\uF8DC'; + zapfPostScript += 'a92 '; + break; + case '86': + decodedtext += '\uF8DD'; + zapfPostScript += 'a205 '; + break; + case '87': + decodedtext += '\uF8DE'; + zapfPostScript += 'a85 '; + break; + case '88': + decodedtext += '\uF8DF'; + zapfPostScript += 'a206 '; + break; + case '89': + decodedtext += '\uF8E0'; + zapfPostScript += 'a86 '; + break; + case '8A': + decodedtext += '\uF8E1'; + zapfPostScript += 'a87 '; + break; + case '8B': + decodedtext += '\uF8E2'; + zapfPostScript += 'a88 '; + break; + case '8C': + decodedtext += '\uF8E3'; + zapfPostScript += 'a95 '; + break; + case '8D': + decodedtext += '\uF8E4'; + zapfPostScript += 'a96 '; + break; + case 'A1': + decodedtext += '\u2761'; + zapfPostScript += 'a101 '; + break; + case 'A2': + decodedtext += '\u2762'; + zapfPostScript += 'a102 '; + break; + case 'A3': + decodedtext += '\u2763'; + zapfPostScript += 'a103 '; + break; + case 'A4': + decodedtext += '\u2764'; + zapfPostScript += 'a104 '; + break; + case 'A5': + decodedtext += '\u2765'; + zapfPostScript += 'a106 '; + break; + case 'A6': + decodedtext += '\u2766'; + zapfPostScript += 'a107 '; + break; + case 'A7': + decodedtext += '\u2767'; + zapfPostScript += 'a108 '; + break; + case 'A8': + decodedtext += '\u2663'; + zapfPostScript += 'a112 '; + break; + case 'A9': + decodedtext += '\u2666'; + zapfPostScript += 'a111 '; + break; + case 'AA': + decodedtext += '\u2665'; + zapfPostScript += 'a110 '; + break; + case 'AB': + decodedtext += '\u2660'; + zapfPostScript += 'a109 '; + break; + case 'AC': + decodedtext += '\u2460'; + zapfPostScript += 'a120 '; + break; + case 'AD': + decodedtext += '\u2461'; + zapfPostScript += 'a121 '; + break; + case 'AE': + decodedtext += '\u2462'; + zapfPostScript += 'a122 '; + break; + case 'AF': + decodedtext += '\u2463'; + zapfPostScript += 'a123 '; + break; + case 'B0': + decodedtext += '\u2464'; + zapfPostScript += 'a124 '; + break; + case 'B1': + decodedtext += '\u2465'; + zapfPostScript += 'a125 '; + break; + case 'B2': + decodedtext += '\u2466'; + zapfPostScript += 'a126 '; + break; + case 'B3': + decodedtext += '\u2467'; + zapfPostScript += 'a127 '; + break; + case 'B4': + decodedtext += '\u2468'; + zapfPostScript += 'a128 '; + break; + case 'B5': + decodedtext += '\u2469'; + zapfPostScript += 'a129 '; + break; + case 'B6': + decodedtext += '\u2776'; + zapfPostScript += 'a130 '; + break; + case 'B7': + decodedtext += '\u2777'; + zapfPostScript += 'a131 '; + break; + case 'B8': + decodedtext += '\u2778'; + zapfPostScript += 'a132 '; + break; + case 'B9': + decodedtext += '\u2779'; + zapfPostScript += 'a133 '; + break; + case 'BA': + decodedtext += '\u277A'; + zapfPostScript += 'a134 '; + break; + case 'BB': + decodedtext += '\u277B'; + zapfPostScript += 'a135 '; + break; + case 'BC': + decodedtext += '\u277C'; + zapfPostScript += 'a136 '; + break; + case 'BD': + decodedtext += '\u277D'; + zapfPostScript += 'a137 '; + break; + case 'BE': + decodedtext += '\u277E'; + zapfPostScript += 'a138 '; + break; + case 'BF': + decodedtext += '\u277F'; + zapfPostScript += 'a139 '; + break; + case 'C0': + decodedtext += '\u2780'; + zapfPostScript += 'a140 '; + break; + case 'C1': + decodedtext += '\u2781'; + zapfPostScript += 'a141 '; + break; + case 'C2': + decodedtext += '\u2782'; + zapfPostScript += 'a142 '; + break; + case 'C3': + decodedtext += '\u2783'; + zapfPostScript += 'a143 '; + break; + case 'C4': + decodedtext += '\u2784'; + zapfPostScript += 'a144 '; + break; + case 'C5': + decodedtext += '\u2785'; + zapfPostScript += 'a145 '; + break; + case 'C6': + decodedtext += '\u2786'; + zapfPostScript += 'a146 '; + break; + case 'C7': + decodedtext += '\u2787'; + zapfPostScript += 'a147 '; + break; + case 'C8': + decodedtext += '\u2788'; + zapfPostScript += 'a148 '; + break; + case 'C9': + decodedtext += '\u2789'; + zapfPostScript += 'a149 '; + break; + case 'CA': + decodedtext += '\u278A'; + zapfPostScript += '150 '; + break; + case 'CB': + decodedtext += '\u278B'; + zapfPostScript += 'a151 '; + break; + case 'CC': + decodedtext += '\u278C'; + zapfPostScript += 'a152 '; + break; + case 'CD': + decodedtext += '\u278D'; + zapfPostScript += 'a153 '; + break; + case 'CE': + decodedtext += '\u278E'; + zapfPostScript += 'a154 '; + break; + case 'CF': + decodedtext += '\u278F'; + zapfPostScript += 'a155 '; + break; + case 'D0': + decodedtext += '\u2790'; + zapfPostScript += 'a156 '; + break; + case 'D1': + decodedtext += '\u2791'; + zapfPostScript += 'a157 '; + break; + case 'D2': + decodedtext += '\u2792'; + zapfPostScript += 'a158 '; + break; + case 'D3': + decodedtext += '\u2793'; + zapfPostScript += 'a159 '; + break; + case 'D4': + decodedtext += '\u2794'; + zapfPostScript += 'a160 '; + break; + case 'D5': + decodedtext += '\u2192'; + zapfPostScript += 'a161 '; + break; + case 'D6': + decodedtext += '\u2194'; + zapfPostScript += 'a163 '; + break; + case 'D7': + decodedtext += '\u2195'; + zapfPostScript += 'a164 '; + break; + case 'D8': + decodedtext += '\u2798'; + zapfPostScript += 'a196 '; + break; + case 'D9': + decodedtext += '\u2799'; + zapfPostScript += 'a165 '; + break; + case 'DA': + decodedtext += '\u279A'; + zapfPostScript += 'a192 '; + break; + case 'DB': + decodedtext += '\u279B'; + zapfPostScript += 'a166 '; + break; + case 'DC': + decodedtext += '\u279C'; + zapfPostScript += 'a167 '; + break; + case 'DD': + decodedtext += '\u279D'; + zapfPostScript += 'a168 '; + break; + case 'DE': + decodedtext += '\u279E'; + zapfPostScript += 'a169 '; + break; + case 'DF': + decodedtext += '\u279F'; + zapfPostScript += 'a170 '; + break; + case 'E0': + decodedtext += '\u27A0'; + zapfPostScript += 'a171 '; + break; + case 'E1': + decodedtext += '\u27A1'; + zapfPostScript += 'a172 '; + break; + case 'E2': + decodedtext += '\u27A2'; + zapfPostScript += 'a173 '; + break; + case 'E3': + decodedtext += '\u27A3'; + zapfPostScript += 'a162 '; + break; + case 'E4': + decodedtext += '\u27A4'; + zapfPostScript += 'a174 '; + break; + case 'E5': + decodedtext += '\u27A5'; + zapfPostScript += 'a175 '; + break; + case 'E6': + decodedtext += '\u27A6'; + zapfPostScript += 'a176 '; + break; + case 'E7': + decodedtext += '\u27A7'; + zapfPostScript += 'a177 '; + break; + case 'E8': + decodedtext += '\u27A8'; + zapfPostScript += 'a178 '; + break; + case 'E9': + decodedtext += '\u27A9'; + zapfPostScript += 'a179 '; + break; + case 'EA': + decodedtext += '\u27AA'; + zapfPostScript += 'a193 '; + break; + case 'EB': + decodedtext += '\u27AB'; + zapfPostScript += 'a180 '; + break; + case 'EC': + decodedtext += '\u27AC'; + zapfPostScript += 'a199 '; + break; + case 'ED': + decodedtext += '\u27AD'; + zapfPostScript += 'a181 '; + break; + case 'EE': + decodedtext += '\u27AE'; + zapfPostScript += 'a200 '; + break; + case 'EF': + decodedtext += '\u27AF'; + zapfPostScript += 'a182 '; + break; + case 'F1': + decodedtext += '\u27B1'; + zapfPostScript += 'a201 '; + break; + case 'F2': + decodedtext += '\u27B2'; + zapfPostScript += 'a183 '; + break; + case 'F3': + decodedtext += '\u27B3'; + zapfPostScript += 'a184 '; + break; + case 'F4': + decodedtext += '\u27B4'; + zapfPostScript += 'a197 '; + break; + case 'F5': + decodedtext += '\u27B5'; + zapfPostScript += 'a185 '; + break; + case 'F6': + decodedtext += '\u27B6'; + zapfPostScript += 'a194 '; + break; + case 'F7': + decodedtext += '\u27B7'; + zapfPostScript += 'a198 '; + break; + case 'F8': + decodedtext += '\u27B8'; + zapfPostScript += 'a186 '; + break; + case 'F9': + decodedtext += '\u27B9'; + zapfPostScript += 'a195 '; + break; + case 'FA': + decodedtext += '\u27BA'; + zapfPostScript += 'a187 '; + break; + case 'FB': + decodedtext += '\u27BB'; + zapfPostScript += 'a188 '; + break; + case 'FC': + decodedtext += '\u27BC'; + zapfPostScript += 'a189 '; + break; + case 'FD': + decodedtext += '\u27BD'; + zapfPostScript += 'a190 '; + break; + case 'FE': + decodedtext += '\u27BE'; + zapfPostScript += 'a191 '; + break; + + default: + if (reverseMapTable!.containsKey(encodedText)) { + decodedtext = encodedText; + final int charPosition = reverseMapTable![decodedtext]!.toInt(); + if (differenceTable.isNotEmpty && + differenceTable.containsKey(charPosition)) { + zapfPostScript = differenceTable[charPosition]!; + } + } else { + decodedtext = '\u2708'; + zapfPostScript = 'a118'; + } + break; + } + } + return decodedtext; + } + + /// internal method + String mapDifferenceOfWingDings(String decodedText) { + if (decodedText.length > 1 && decodedText.contains('c')) { + if (decodedText.indexOf('c') == 0) { + decodedText = decodedText.replaceAll(decodedText[0], ''); + int characterValue = 0; + try { + characterValue = int.parse(decodedText).toSigned(32); + } catch (e) { + characterValue = 0; + } + decodedText = String.fromCharCode(characterValue); + } + } + return decodedText; + } + + /// internal method + String mapCidToGid(String decodedText) { + String finalText = ''; + bool skip = false; + + for (int i = 0; i < decodedText.length; i++) { + final int character = decodedText.codeUnitAt(0); + if (cidToGidTable!.containsKey(character) && !skip) { + String mappingString = cidToGidTable![character]!; + if (mappingString.contains('�')) { + final int index = mappingString.indexOf('�'); + mappingString = mappingString.replaceAll(mappingString[index], ''); + } + if (mappingString.isNotEmpty) { + if (!cidToGidReverseMapTable.containsKey( + mappingString.codeUnitAt(0), + )) { + cidToGidReverseMapTable[mappingString.codeUnitAt(0)] = character; + } + } + finalText += mappingString; + skip = false; + } else if (tempMapTable.containsKey(character) && !skip) { + String mappingString = tempMapTable[character]!; + if (mappingString.contains('�')) { + final int index = mappingString.indexOf('�'); + mappingString = mappingString.replaceAll(mappingString[index], ''); + } + finalText += mappingString; + skip = false; + } else { + if (skip) { + switch (String.fromCharCode(character)) { + case 'n': + if (cidToGidTable!.containsKey(10)) { + finalText += characterMapTable[10]!; + } + break; + case 'r': + if (cidToGidTable!.containsKey(13)) { + finalText += characterMapTable[13]!; + } + break; + case 'b': + if (cidToGidTable!.containsKey(8)) { + finalText += characterMapTable[8]!; + } + break; + case 'a': + if (cidToGidTable!.containsKey(7)) { + finalText += characterMapTable[7]!; + } + break; + case 'f': + if (cidToGidTable!.containsKey(12)) { + finalText += characterMapTable[12]!; + } + break; + case 't': + if (cidToGidTable!.containsKey(9)) { + finalText += characterMapTable[9]!; + } + break; + case 'v': + if (cidToGidTable!.containsKey(11)) { + finalText += characterMapTable[11]!; + } + break; + case "'": + if (cidToGidTable!.containsKey(39)) { + finalText += characterMapTable[39]!; + } + break; + default: + { + if (cidToGidTable!.containsKey(character)) { + finalText += characterMapTable[character]!; + } + } + break; + } + skip = false; + } else if (decodedText[i] == r'\') { + skip = true; + } + } + } + return finalText; + } + + /// internal method + bool hasEscapeCharacter(String text) { + return text.contains(r'\u0007') || + text.contains(r'\') || + text.contains(r'\b') || + text.contains(r'\f') || + text.contains(r'\r') || + text.contains(r'\t') || + text.contains(r'\n') || + text.contains(r'\v') || + text.contains(r"\'") || + text.contains(r'\u0000'); + } + + /// Decodes the octal text in the encoded text. + String getLiteralString(String encodedText, [List? charCodes]) { + String decodedText = encodedText; + int octalIndex = -1; + int limit = 3; + bool isMacCharProcessed = false; + bool isWinAnsiProcessed = false; + final List octalIndexCollection = []; + // ignore: use_raw_strings + while ((decodedText.contains(r'\') && (!decodedText.contains('\\\\'))) || + decodedText.contains('\u0000')) { + String octalText = ''; + if (decodedText.contains(r'\', octalIndex + 1)) { + octalIndex = decodedText.indexOf(r'\', octalIndex + 1); + } else { + octalIndex = decodedText.indexOf('\u0000', octalIndex + 1); + if (octalIndex < 0) { + break; + } + limit = 2; + } + for ( + int i = octalIndex + 1; + i <= octalIndex + limit; + i++ + ) //check for octal characters + { + if (i < decodedText.length) { + int val = 0; + try { + val = int.parse(decodedText[i]).toSigned(32); + if (val <= 8) { + octalText += decodedText[i]; + } + } on Exception { + octalText = ''; + break; + } + } else { + octalText = ''; + } + } + + if (octalText != '') { + final int decimalValue = int.parse(octalText, radix: 8).toUnsigned(64); + String temp = ''; + final String decodedChar = String.fromCharCode(decimalValue); + if (characterMapTable.isNotEmpty) { + temp = decodedChar; + } else if (differencesDictionary.isNotEmpty && + differencesDictionary.containsKey(decimalValue.toString())) { + temp = decodedChar; + } else { + if (fontEncoding != 'MacRomanEncoding') { + final List charbytes = [decimalValue.toUnsigned(8)]; + temp = _getWindows1252DecodedText(charbytes); + List tempchar; + tempchar = [ + _getWindows1252DecodedText([decimalValue.toUnsigned(8)]), + ]; + int charvalue = 0; + for (final String tempchar1 in tempchar) { + charvalue = tempchar1.codeUnitAt(0); + } + if (!octDecMapTable.containsKey(charvalue)) { + octDecMapTable[charvalue] = decimalValue; + } + isWinAnsiProcessed = true; + } else { + final List charbytes = [decimalValue.toUnsigned(8)]; + temp = String.fromCharCodes(charbytes); + final List tempchar = [ + String.fromCharCodes([decimalValue.toUnsigned(8)]), + ]; + int charvalue = 0; + for (final String tempchar1 in tempchar) { + charvalue = tempchar1.codeUnitAt(0); + } + if (!octDecMapTable.containsKey(charvalue)) { + octDecMapTable[charvalue] = decimalValue; + } + isMacCharProcessed = true; + } + } + (charCodes ??= []).add(decimalValue); + decodedText = decodedText.replaceRange( + octalIndex, + octalIndex + limit + 1, + '', + ); + final List str = decodedText.split(''); + str.insert(octalIndex, temp); + octalIndexCollection.add(octalIndex); + decodedText = str.join(); + } + } + final List str = decodedText.split(''); + int count = str.length; + if (octalIndexCollection.length != str.length) { + final Map escapeSequence = { + 'b': '\b', + 'e': r'\e', + 'f': '\f', + 'n': '\n', + 'r': '\r', + 't': '\t', + 'v': '\v', + "'": "'", + }; + if (decodedText.contains(r'\')) { + for (int i = count - 2; i >= 0; i--) { + if (str[i] == r'\') { + final String sequence = str[i + 1]; + if (escapeSequence.containsKey(sequence)) { + str.removeAt(i + 1); + str[i] = escapeSequence[sequence]!; + //Re-initializes octal index based on escape sequence. + for (int j = 0; j < octalIndexCollection.length; j++) { + if (octalIndexCollection[j] > i) { + octalIndexCollection[j] = octalIndexCollection[j] - 1; + } + } + //Update the octal index collection and char codes, + //if character map table contains the escape sequence. + for (int j = 0; j < octalIndexCollection.length; j++) { + if (characterMapTable.containsKey( + escapeSequence[sequence]!.codeUnitAt(0), + )) { + if (i < octalIndexCollection[j]) { + octalIndexCollection.insert(j, i); + charCodes!.insert( + j, + escapeSequence[sequence]!.codeUnitAt(0), + ); + break; + } else if (j == octalIndexCollection.length - 1 && + i > octalIndexCollection[j]) { + octalIndexCollection.add(i); + charCodes!.add(escapeSequence[sequence]!.codeUnitAt(0)); + break; + } + } else { + break; + } + } + count--; + } + } + } + } + escapeSequence.clear(); + } + int combinedGlyphDiff = 0; + for (int i = 0; i < count; i++) { + if (!octalIndexCollection.contains(i)) { + if (characterMapTable.containsKey(str[i].codeUnitAt(0))) { + (charCodes ??= []).insert( + i + combinedGlyphDiff, + str[i].codeUnitAt(0), + ); + } else { + (charCodes ??= []).insert(i + combinedGlyphDiff, 0); + } + } else if (characterMapTable.containsKey(str[i].codeUnitAt(0))) { + final String mappingString = characterMapTable[str[i].codeUnitAt(0)]!; + final int mappingStringLength = mappingString.length; + if (mappingStringLength > 1) { + for (int j = i + 1; j < i + mappingStringLength; j++) { + charCodes!.insert(j + combinedGlyphDiff, 'combined'); + } + combinedGlyphDiff += mappingStringLength - 1; + } + } + } + if (decodedText.contains(r'\') && fontEncoding != 'Identity-H') { + if (decodedText.length > 1) { + final int index = decodedText.indexOf(r'\'); + final String char = decodedText[index + 1]; + if (char == '(' || char == ')') { + unescape(decodedText); + // ignore: use_raw_strings + } else if (!decodedText.contains('\\\\')) { + int initialLength = 0; + while ((decodedText.contains(r'\')) && + (decodedText.length != initialLength)) { + initialLength = decodedText.length; + decodedText = skipEscapeSequence(decodedText); + } + } + } + } + if ((fontEncoding == 'MacRomanEncoding') && (!isMacCharProcessed)) { + getMacEncodeTable(); + for (int i = 0; i < decodedText.length; i++) { + final int decimalValue = decodedText[i].codeUnitAt(0); + if (_macEncodeTable!.containsValue(decodedText[i])) { + if (!_macRomanMapTable.containsKey(decimalValue)) { + final int charbytes = decimalValue.toUnsigned(8); + _macRomanMapTable[decimalValue] = String.fromCharCode(charbytes); + } + } + } + } + if ((fontEncoding == 'WinAnsiEncoding') && (!isWinAnsiProcessed)) { + for (int i = 0; i < encodedText.length; i++) { + final int decimalValue = encodedText[i].codeUnitAt(0); + //// In WinAnsiEncoding, all unused codes greater than 40 map to the bullet character. + if (decimalValue == 127 || + decimalValue == 129 || + decimalValue == 131 || + decimalValue == 136 || + decimalValue == 141 || + decimalValue == 143 || + decimalValue == 144 || + decimalValue == 152 || + decimalValue == 157 || + decimalValue == 173 || + decimalValue == 209) { + final String mappedChar = String.fromCharCode(149); + if (!_winansiMapTable.containsKey(decimalValue)) { + _winansiMapTable[decimalValue] = mappedChar; + } + } + } + } + return decodedText; + } + + String _getWindows1252DecodedText(List charcodes) { + String result = ''; + // ignore: avoid_function_literals_in_foreach_calls + charcodes.forEach((int code) { + if (code >= 0 && code < 256) { + result += _windows1252MapTable[code]; + } + }); + return result; + } + + /// Decodes the HEX encoded string and returns Decoded string. + String getHexaDecimalString( + String hexEncodedText, [ + List? charCodes, + ]) { + String decodedText = ''; + // IsHexaDecimalString = true; + if (hexEncodedText.isNotEmpty) { + final PdfName fontType = + fontDictionary.items![PdfName('Subtype')]! as PdfName; + int limit = 2; + if (fontType.name != 'Type1' && + fontType.name != 'TrueType' && + fontType.name != 'Type3') { + limit = 4; + } + hexEncodedText = escapeSymbols(hexEncodedText); + final String tempHexEncodedText = hexEncodedText; + final String tempDecodedText = decodedText; + late String decodedTxt; + while (hexEncodedText.isNotEmpty) { + if (hexEncodedText.length % 4 != 0) { + limit = 2; + } + String hexChar = hexEncodedText.substring(0, limit); + + if (fontDictionary.containsKey( + PdfDictionaryProperties.descendantFonts, + ) && + !fontDictionary.containsKey(PdfDictionaryProperties.toUnicode)) { + final IPdfPrimitive? descendantArray = + fontDictionary[PdfDictionaryProperties.descendantFonts]; + if (descendantArray != null && descendantArray is PdfArray) { + PdfDictionary? descendantDictionary; + if (descendantArray[0] is PdfReferenceHolder) { + descendantDictionary = + (descendantArray[0]! as PdfReferenceHolder).object + as PdfDictionary?; + } else if (descendantArray[0] is PdfDictionary) { + descendantDictionary = descendantArray[0]! as PdfDictionary; + } + if (descendantDictionary != null) { + PdfDictionary? descriptorDictionary; + if (descendantDictionary.containsKey( + PdfDictionaryProperties.fontDescriptor, + )) { + IPdfPrimitive? primitive = + descendantDictionary[PdfDictionaryProperties + .fontDescriptor]; + if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfDictionary) { + descriptorDictionary = primitive; + } + } else if (primitive is PdfDictionary) { + descriptorDictionary = primitive; + } + } + if (descriptorDictionary != null) { + if (descendantDictionary.containsKey( + PdfDictionaryProperties.subtype, + ) && + !descriptorDictionary.containsKey( + PdfDictionaryProperties.fontFile2, + )) { + final PdfName subtype = + descendantDictionary[PdfDictionaryProperties.subtype]! + as PdfName; + if (subtype.name == 'CIDFontType2') { + hexChar = mapHebrewCharacters(hexChar); + } + } + } + } + } else if (fontDictionary.items!.containsKey( + PdfName(PdfDictionaryProperties.descendantFonts), + )) { + final PdfReferenceHolder? descendantFontArrayReference = + fontDictionary.items![PdfName( + PdfDictionaryProperties.descendantFonts, + )] + as PdfReferenceHolder?; + if (descendantFontArrayReference != null) { + PdfName? subtype; + final PdfArray descendantFontArray = + descendantFontArrayReference.object! as PdfArray; + if (descendantFontArray[0] is PdfReferenceHolder) { + final PdfDictionary? descendantDictionary = + (descendantFontArray[0]! as PdfReferenceHolder).object + as PdfDictionary?; + if (descendantDictionary != null && + descendantDictionary.containsKey( + PdfDictionaryProperties.cidSystemInfo, + ) && + descendantDictionary.containsKey( + PdfDictionaryProperties.subtype, + )) { + subtype = + descendantDictionary[PdfDictionaryProperties.subtype] + as PdfName?; + final PdfDictionary? cidSystemInfo = + (descendantDictionary[PdfDictionaryProperties + .cidSystemInfo]! + as PdfReferenceHolder) + .object + as PdfDictionary?; + if (cidSystemInfo != null && + cidSystemInfo.containsKey( + PdfDictionaryProperties.registry, + ) && + cidSystemInfo.containsKey( + PdfDictionaryProperties.ordering, + ) && + cidSystemInfo.containsKey( + PdfDictionaryProperties.supplement, + )) { + final PdfString pdfRegistry = + cidSystemInfo[PdfDictionaryProperties.registry]! + as PdfString; + final PdfNumber? pdfSupplement = + cidSystemInfo[PdfDictionaryProperties.supplement] + as PdfNumber?; + final PdfString? pdfOrdering = + cidSystemInfo[PdfDictionaryProperties.ordering] + as PdfString?; + if (pdfRegistry.value != null && + pdfSupplement!.value != null && + pdfOrdering!.value != null) { + if (pdfRegistry.value == 'Adobe' && + pdfOrdering.value == 'Identity' && + pdfSupplement.value == 0 && + subtype!.name == 'CIDFontType2' && + cidSystemInfoDictionary == null && + !isContainFontfile2) { + isAdobeIdentity = true; + hexChar = mapIdentityCharacters(hexChar); + } + } + } + } + } + } + } + } + final int hexNum = int.parse(hexChar, radix: 16).toSigned(64); + (charCodes ??= []).add(hexNum); + decodedText += String.fromCharCode(hexNum); + hexEncodedText = hexEncodedText.substring(limit, hexEncodedText.length); + decodedTxt = decodedText; + } + if ((decodedTxt.contains('“') || + decodedTxt.contains('”') || + decodedTxt.contains('’')) && + tempHexEncodedText.length < limit) { + decodedText = tempDecodedText; + final int hexNum = int.parse( + tempHexEncodedText, + radix: 16, + ).toSigned(32); + (charCodes ??= []).add(hexNum); + hexEncodedText = String.fromCharCode(hexNum); + decodedText += hexEncodedText; + } + int combinedGlyphDiff = 0; + for (int i = 0; i < decodedText.length; i++) { + if (characterMapTable.containsKey(decodedText[i].codeUnitAt(0))) { + final String mappingString = + characterMapTable[decodedText[i].codeUnitAt(0)]!; + final int mappingStringLength = mappingString.length; + if (mappingStringLength > 1) { + for (int j = i + 1; j < i + mappingStringLength; j++) { + charCodes!.insert(j + combinedGlyphDiff, 'combined'); + } + combinedGlyphDiff += mappingStringLength - 1; + } + } + } + } + return decodedText; + } + + /// internal method + String mapHebrewCharacters(String hexChar) { + if (hexChar.substring(0, 2) == '02') { + int i = int.parse(hexChar); + i += 816; + hexChar = i.toRadixString(16); + } else if (hexChar.substring(0, 2) == '00') { + if (hexChar.substring(2, 3) == '0' || hexChar.substring(2, 3) == '1') { + int i = int.parse(hexChar); + i += 29; + hexChar = i.toRadixString(16); + } else { + int i = int.parse(hexChar); + i += 1335; + hexChar = i.toRadixString(16); + } + } + return hexChar; + } + + /// internal method + String mapIdentityCharacters(String hexChar) { + if (hexChar.substring(0, 2) == '00') { + if (hexChar.substring(2, 3) != '0' || hexChar.substring(2, 3) != '1') { + int i = int.parse(hexChar); + i += 29; + hexChar = i.toRadixString(16); + } else { + int i = int.parse(hexChar); + i += 1335; + hexChar = i.toRadixString(16); + } + } + return hexChar; + } + + /// Method to remove the new line character + String escapeSymbols(String text) { + while (text.contains('\n')) { + text = text.replaceAll('\n', ''); + } + return text; + } + + /// Takes in the decoded text and maps it with its + /// corresponding entry in the CharacterMapTable + String mapCharactersFromTable(String decodedText, [bool isHex = false]) { + String finalText = ''; + bool skip = false; + for (int i = 0; i < decodedText.length; i++) { + final String character = decodedText[i]; + if (characterMapTable.containsKey(character.codeUnitAt(0)) && !skip) { + String mappingString = characterMapTable[character.codeUnitAt(0)]!; + if (mappingString.contains('�')) { + mappingString = mappingString.replaceAll('�', ''); + if (fontName!.contains('ZapfDingbats')) { + mappingString = character; + } + } + if (fontEncoding != 'Identity-H' && + !isTextExtraction && + characterMapTable.length != reverseMapTable!.length) { + if (isCancel(mappingString) || + isNonPrintableCharacter( + character, + )) //Contains 'CANCEL' of ASCII value 24 + { + mappingString = character; + } + } + finalText += mappingString; + skip = false; + } else if (!characterMapTable.containsKey(character.codeUnitAt(0)) && + !skip && + !isHex) { + final List bytes = encodeBigEndian(character); + if (bytes[0] != 92) { + if (characterMapTable.containsKey(bytes[0])) { + finalText += characterMapTable[bytes[0]]!; + skip = false; + } + } + } else if (tempMapTable.containsKey(character.codeUnitAt(0)) && !skip) { + String? mappingString = tempMapTable[character.codeUnitAt(0)]; + if (character == r'\' && isTextExtraction) { + mappingString = ''; + } + if (mappingString!.contains('�')) { + final int index = mappingString.indexOf('�'); + mappingString = mappingString.replaceAll(mappingString[index], ''); + } + finalText += mappingString; + skip = false; + } else { + if (skip) { + switch (character) { + case 'n': + if (characterMapTable.containsKey(10)) { + finalText += characterMapTable[10]!; + } + break; + case 'r': + if (characterMapTable.containsKey(13)) { + finalText += characterMapTable[13]!; + } + break; + case 'b': + if (characterMapTable.containsKey(8)) { + finalText += characterMapTable[8]!; + } + break; + case 'a': + if (characterMapTable.containsKey(7)) { + finalText += characterMapTable[7]!; + } + break; + case 'f': + if (characterMapTable.containsKey(12)) { + finalText += characterMapTable[12]!; + } + break; + case 't': + if (characterMapTable.containsKey(9)) { + finalText += characterMapTable[9]!; + } + break; + case 'v': + if (characterMapTable.containsKey(11)) { + finalText += characterMapTable[11]!; + } + break; + case "'": + if (characterMapTable.containsKey(39)) { + finalText += characterMapTable[39]!; + } + break; + default: + { + if (characterMapTable.containsKey(character.codeUnitAt(0))) { + finalText += characterMapTable[character.codeUnitAt(0)]!; + } + } + break; + } + skip = false; + } else if (character == r'\') { + skip = true; + } else { + finalText += character; + } + } + } + return finalText; + } + + /// internal method + bool isCancel(String mappingString) { + bool isCancel = false; + if (mappingString == '') { + isCancel = true; + } + return isCancel; + } + + /// Checks whether the specified character is Non-Printable character or not. + bool isNonPrintableCharacter(String str) { + bool isNonPrintable = false; + if (!isTextExtraction && + fontType!.name == 'Type1' && + fontEncoding == 'Encoding' && + fontName != 'ZapfDingbats' && + (characterMapTable.length == differencesDictionary.length)) { + final int character = str.codeUnitAt(0); + if ((character >= 0 && character <= 31) || character == 127) { + isNonPrintable = true; + } + } + return isNonPrintable; + } + + /// Disposes the instance. + void dispose() { + _differencesDictionary = null; + if (_characterMapTable != null && _characterMapTable!.isNotEmpty) { + _characterMapTable!.clear(); + } + _characterMapTable = null; + if (_reverseMapTable != null && _reverseMapTable!.isNotEmpty) { + _reverseMapTable!.clear(); + } + _reverseMapTable = null; + if (reverseDictMapping.isNotEmpty) { + reverseDictMapping.clear(); + } + if (cidToGidTable != null && cidToGidTable!.isNotEmpty) { + cidToGidTable!.clear(); + } + cidToGidTable = null; + if (_differencesDictionary != null && _differencesDictionary!.isNotEmpty) { + _differencesDictionary!.clear(); + } + _differencesDictionary = null; + if (_fontGlyphWidth != null && _fontGlyphWidth!.isNotEmpty) { + _fontGlyphWidth!.clear(); + } + _fontGlyphWidth = null; + if (tempMapTable.isNotEmpty) { + tempMapTable.clear(); + } + if (_octDecMapTable != null && _octDecMapTable!.isNotEmpty) { + _octDecMapTable!.clear(); + } + _octDecMapTable = null; + if (_cidToGidReverseMapTable != null && + _cidToGidReverseMapTable!.isNotEmpty) { + _cidToGidReverseMapTable!.clear(); + } + _cidToGidReverseMapTable = null; + if (differenceTable.isNotEmpty) { + differenceTable.clear(); + } + if (differenceEncoding != null && differenceEncoding!.isNotEmpty) { + differenceEncoding!.clear(); + } + differenceEncoding = null; + if (type3FontCharProcsDict.isNotEmpty) { + type3FontCharProcsDict.clear(); + } + if (tempStringList.isNotEmpty) { + tempStringList.clear(); + } + if (_unicodeCharMapTable != null && _unicodeCharMapTable!.isNotEmpty) { + _unicodeCharMapTable!.clear(); + } + _unicodeCharMapTable = null; + if (_macEncodeTable != null && _macEncodeTable!.isNotEmpty) { + _macEncodeTable!.clear(); + } + _macEncodeTable = null; + if (_winansiMapTable.isNotEmpty) { + _winansiMapTable.clear(); + } + if (_windows1252MapTable.isNotEmpty) { + _windows1252MapTable.clear(); + } + if (_macRomanMapTable.isNotEmpty) { + _macRomanMapTable.clear(); + } + if (standardCJKFontNames.isNotEmpty) { + standardCJKFontNames.clear(); + } + if (standardFontNames.isNotEmpty) { + standardFontNames.clear(); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/glyph.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/glyph.dart index 779637261..494168c6a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/glyph.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/glyph.dart @@ -1,84 +1,87 @@ -import 'dart:ui'; - -import '../../graphics/fonts/enums.dart'; -import 'matrix_helper.dart'; - -/// internal class -class Glyph { - /// internal constructor - Glyph() { - _initialize(); - } - - //Fields - late double _descent; - - //Properties - /// internal field - late double ascent; - - /// internal field - late MatrixHelper transformMatrix; - - /// internal field - late Rect boundingRect; - - /// internal field - late double charSpacing; - - /// internal field - late double wordSpacing; - - /// internal field - late double horizontalScaling; - - /// internal field - late double fontSize; - - /// internal field - String fontFamily = ''; - - /// internal field - String name = ''; - - /// internal field - int charId = -1; - - /// internal field - late double width; - - /// internal field - List fontStyle = []; - - /// internal field - String toUnicode = ''; - - /// internal field - late bool isRotated; - - /// internal field - late int rotationAngle; - - /// internal field - double get descent { - return _descent; - } - - set descent(double value) { - _descent = (value > 0) ? -value : value; - } - - //Implementation - void _initialize() { - rotationAngle = 0; - isRotated = false; - ascent = 1000; - descent = 0; - transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - charSpacing = 0; - wordSpacing = 0; - horizontalScaling = 100; - fontSize = 0; - width = 0; - } -} +import 'dart:ui'; + +import '../../../../../pdf.dart'; +import 'matrix_helper.dart'; + +/// internal class +class Glyph { + /// internal constructor + Glyph() { + _initialize(); + } + + //Fields + late double _descent; + + //Properties + /// internal field + late double ascent; + + /// internal field + late MatrixHelper transformMatrix; + + /// internal field + late Rect boundingRect; + + /// internal field + late double charSpacing; + + /// internal field + late double wordSpacing; + + /// internal field + late double horizontalScaling; + + /// internal field + late double fontSize; + + /// internal field + String fontFamily = ''; + + /// internal field + String name = ''; + + /// internal field + int charId = -1; + + /// internal field + late double width; + + /// internal field + List fontStyle = []; + + /// internal field + String toUnicode = ''; + + /// internal field + late bool isRotated; + + /// internal field + late int rotationAngle; + + /// The fill color of this glyph + PdfColor? textColor; + + /// internal field + double get descent { + return _descent; + } + + set descent(double value) { + _descent = (value > 0) ? -value : value; + } + + //Implementation + void _initialize() { + rotationAngle = 0; + isRotated = false; + ascent = 1000; + descent = 0; + transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + charSpacing = 0; + wordSpacing = 0; + horizontalScaling = 100; + fontSize = 0; + width = 0; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data.dart index 79c2fa03c..cb332db59 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data.dart @@ -1,120 +1,130 @@ -import 'matrix_helper.dart'; - -/// internal class -class GraphicObjectData { - /// internal constructor - GraphicObjectData() { - mitterLength = 0; - horizontalScaling = 100; - rise = 0; - transformMatrixTM = MatrixHelper(0, 0, 0, 0, 0, 0); - characterSpacing = 0; - wordSpacing = 0; - nonStrokingOpacity = 1; - strokingOpacity = 1; - textLeading = 0; - fontSize = 0; - } - - //Fields - /// internal field - MatrixHelper? currentTransformationMatrix; - - /// internal field - MatrixHelper? drawing2dMatrixCTM; - - /// internal field - MatrixHelper? documentMatrix; - - /// internal field - MatrixHelper? textLineMatrix; - - /// internal field - MatrixHelper? textMatrix; - - /// internal field - MatrixHelper? textMatrixUpdate; - - /// internal field - MatrixHelper? transformMatrixTM; - - /// internal field - double? horizontalScaling; - - /// internal field - double? mitterLength; - - /// internal field - int? rise; - - /// internal field - double? characterSpacing; - - /// internal field - double? wordSpacing; - - /// internal field - double? nonStrokingOpacity; - - /// internal field - double? strokingOpacity; - - /// internal field - String? currentFont; - - /// internal field - double? textLeading; - - /// internal field - double? fontSize; -} - -/// internal class -class GraphicsObject { - /// internal constructor - GraphicsObject() { - transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - } - - /// internal field - MatrixHelper? transformMatrix; - GraphicsState? _graphicState; - - //Implementation - /// internal method - GraphicsState? save() { - _graphicState = GraphicsState(); - _graphicState!._transformMatrix = transformMatrix; - return _graphicState; - } - - /// internal method - void restore(GraphicsState graphicState) { - transformMatrix = graphicState._transformMatrix; - } - - /// internal method - void multiplyTransform(MatrixHelper matrix) { - transformMatrix = transformMatrix! * matrix; - } - - /// internal method - void scaleTransform(double scaleX, double scaleY) { - transformMatrix = transformMatrix!.scale(scaleX, scaleY, 0, 0); - } - - /// internal method - void translateTransform(double offsetX, double offsetY) { - transformMatrix = transformMatrix!.translate(offsetX, offsetY); - } - - /// internal method - void rotateTransform(double angle) { - transformMatrix = transformMatrix!.rotate(angle, 0, 0); - } -} - -/// internal class -class GraphicsState { - MatrixHelper? _transformMatrix; -} +import '../../graphics/pdf_color.dart'; +import 'matrix_helper.dart'; + +/// internal class +class GraphicObjectData { + /// internal constructor + GraphicObjectData() { + mitterLength = 0; + horizontalScaling = 100; + rise = 0; + transformMatrixTM = MatrixHelper(0, 0, 0, 0, 0, 0); + characterSpacing = 0; + wordSpacing = 0; + nonStrokingOpacity = 1; + strokingOpacity = 1; + textLeading = 0; + fontSize = 0; + // Default text color is black + fillColor = PdfColor(0, 0, 0); + strokeColor = PdfColor(0, 0, 0); + } + + //Fields + /// internal field + MatrixHelper? currentTransformationMatrix; + + /// Non-stroking (fill) color for text rendering + PdfColor? fillColor; + + /// Stroking color for text outlines + PdfColor? strokeColor; + + /// internal field + MatrixHelper? drawing2dMatrixCTM; + + /// internal field + MatrixHelper? documentMatrix; + + /// internal field + MatrixHelper? textLineMatrix; + + /// internal field + MatrixHelper? textMatrix; + + /// internal field + MatrixHelper? textMatrixUpdate; + + /// internal field + MatrixHelper? transformMatrixTM; + + /// internal field + double? horizontalScaling; + + /// internal field + double? mitterLength; + + /// internal field + int? rise; + + /// internal field + double? characterSpacing; + + /// internal field + double? wordSpacing; + + /// internal field + double? nonStrokingOpacity; + + /// internal field + double? strokingOpacity; + + /// internal field + String? currentFont; + + /// internal field + double? textLeading; + + /// internal field + double? fontSize; +} + +/// internal class +class GraphicsObject { + /// internal constructor + GraphicsObject() { + transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + } + + /// internal field + MatrixHelper? transformMatrix; + GraphicsState? _graphicState; + + //Implementation + /// internal method + GraphicsState? save() { + _graphicState = GraphicsState(); + _graphicState!._transformMatrix = transformMatrix; + return _graphicState; + } + + /// internal method + void restore(GraphicsState graphicState) { + transformMatrix = graphicState._transformMatrix; + } + + /// internal method + void multiplyTransform(MatrixHelper matrix) { + transformMatrix = transformMatrix! * matrix; + } + + /// internal method + void scaleTransform(double scaleX, double scaleY) { + transformMatrix = transformMatrix!.scale(scaleX, scaleY, 0, 0); + } + + /// internal method + void translateTransform(double offsetX, double offsetY) { + transformMatrix = transformMatrix!.translate(offsetX, offsetY); + } + + /// internal method + void rotateTransform(double angle) { + transformMatrix = transformMatrix!.rotate(angle, 0, 0); + } +} + +/// internal class +class GraphicsState { + MatrixHelper? _transformMatrix; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data_collection.dart index 263350109..cd84df442 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/graphic_object_data_collection.dart @@ -1,113 +1,113 @@ -import 'dart:collection'; - -import 'graphic_object_data.dart'; - -/// internal class -class GraphicObjectDataCollection { - //constructor - /// internal constructor - GraphicObjectDataCollection() { - _elements = Queue(); - } - - //fields - late Queue _elements; - - //properties - /// internal method - GraphicObjectData get last => _elements.last; - - /// internal method - int get count => _elements.length; - - //implementation - /// internal method - void push(GraphicObjectData element) { - _elements.addLast(element); - } - - /// internal method - GraphicObjectData pop() { - return _elements.removeLast(); - } - - /// internal property - double? get textLeading { - double? result; - if (last.currentFont != null) { - result = last.textLeading; - } else { - result = 0; - for (int i = count - 1; i >= 0; i--) { - final GraphicObjectData element = _elements.elementAt(i); - if (element.currentFont != null) { - result = element.textLeading; - } - } - } - return result; - } - - /// internal property - String? get currentFont { - String? result; - if (last.currentFont != null) { - result = last.currentFont; - } else { - result = ''; - for (int i = count - 1; i >= 0; i--) { - final GraphicObjectData element = _elements.elementAt(i); - if (element.currentFont != null) { - result = element.currentFont; - break; - } - } - } - return result; - } - - /// internal property - double? get fontSize { - double? result; - if (last.currentFont != null) { - result = last.fontSize; - } else { - result = 0; - for (int i = count - 1; i >= 0; i--) { - final GraphicObjectData element = _elements.elementAt(i); - if (element.currentFont != null) { - result = element.fontSize; - break; - } - } - } - return result; - } -} - -/// internal class -class GraphicStateCollection { - //constructor - /// internal constructor - GraphicStateCollection() { - _elements = Queue(); - } - - //fields - late Queue _elements; - - //Properties - /// internal property - int get count => _elements.length; - - //Implementation - /// internal method - void push(GraphicsState? element) { - _elements.addLast(element); - } - - /// internal method - GraphicsState? pop() { - return _elements.removeLast(); - } -} +import 'dart:collection'; + +import 'graphic_object_data.dart'; + +/// internal class +class GraphicObjectDataCollection { + //constructor + /// internal constructor + GraphicObjectDataCollection() { + _elements = Queue(); + } + + //fields + late Queue _elements; + + //properties + /// internal method + GraphicObjectData get last => _elements.last; + + /// internal method + int get count => _elements.length; + + //implementation + /// internal method + void push(GraphicObjectData element) { + _elements.addLast(element); + } + + /// internal method + GraphicObjectData pop() { + return _elements.removeLast(); + } + + /// internal property + double? get textLeading { + double? result; + if (last.currentFont != null) { + result = last.textLeading; + } else { + result = 0; + for (int i = count - 1; i >= 0; i--) { + final GraphicObjectData element = _elements.elementAt(i); + if (element.currentFont != null) { + result = element.textLeading; + } + } + } + return result; + } + + /// internal property + String? get currentFont { + String? result; + if (last.currentFont != null) { + result = last.currentFont; + } else { + result = ''; + for (int i = count - 1; i >= 0; i--) { + final GraphicObjectData element = _elements.elementAt(i); + if (element.currentFont != null) { + result = element.currentFont; + break; + } + } + } + return result; + } + + /// internal property + double? get fontSize { + double? result; + if (last.currentFont != null) { + result = last.fontSize; + } else { + result = 0; + for (int i = count - 1; i >= 0; i--) { + final GraphicObjectData element = _elements.elementAt(i); + if (element.currentFont != null) { + result = element.fontSize; + break; + } + } + } + return result; + } +} + +/// internal class +class GraphicStateCollection { + //constructor + /// internal constructor + GraphicStateCollection() { + _elements = Queue(); + } + + //fields + late Queue _elements; + + //Properties + /// internal property + int get count => _elements.length; + + //Implementation + /// internal method + void push(GraphicsState? element) { + _elements.addLast(element); + } + + /// internal method + GraphicsState? pop() { + return _elements.removeLast(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/image_renderer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/image_renderer.dart index aca16d722..fd0dc4c51 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/image_renderer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/image_renderer.dart @@ -1,976 +1,1119 @@ -import 'dart:convert'; -import 'dart:ui'; - -import 'font_structure.dart'; -import 'glyph.dart'; -import 'graphic_object_data.dart'; -import 'graphic_object_data_collection.dart'; -import 'matrix_helper.dart'; -import 'page_resource_loader.dart'; -import 'parser/content_parser.dart'; -import 'text_element.dart'; -import 'xobject_element.dart'; - -/// internal class -class ImageRenderer { - /// internal constructor - ImageRenderer( - PdfRecordCollection? contentElements, - PdfPageResources resources, - this.currentPageHeight, [ - GraphicsObject? g, - ]) { - const int dpiX = 96; - _graphicsObject = GraphicsObject(); - _graphicsState = GraphicStateCollection(); - graphicsObjects = GraphicObjectDataCollection(); - final GraphicObjectData newObject = GraphicObjectData(); - newObject.currentTransformationMatrix = MatrixHelper( - 1.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - ); - final MatrixHelper transformMatrix = - g != null ? g.transformMatrix! : _graphicsObject!.transformMatrix!; - newObject.currentTransformationMatrix!.translate( - transformMatrix.offsetX / 1.333, - transformMatrix.offsetY / 1.333, - ); - newObject.drawing2dMatrixCTM = MatrixHelper(1, 0, 0, 1, 0, 0); - newObject.drawing2dMatrixCTM!.translate( - transformMatrix.offsetX / 1.333, - transformMatrix.offsetY / 1.333, - ); - newObject.documentMatrix = MatrixHelper( - 1.33333333333333 * (dpiX / 96) * transformMatrix.m11, - 0, - 0, - -1.33333333333333 * (dpiX / 96) * transformMatrix.m22, - 0, - currentPageHeight! * transformMatrix.m22, - ); - graphicsObjects!.push(newObject); - graphicsObjects!.push(newObject); - _contentElements = contentElements; - _resources = resources; - imageRenderGlyphList = []; - _initialize(); - } - - //Fields - /// internal field - GraphicObjectDataCollection? graphicsObjects; - GraphicStateCollection? _graphicsState; - GraphicsObject? _graphicsObject; - PdfRecordCollection? _contentElements; - PdfPageResources? _resources; - String? _actualText; - - /// internal field - double? currentPageHeight; - - /// internal field - late List imageRenderGlyphList; - PdfRecordCollection? _type3RecordCollection; - late bool _isType3Font; - late List _symbolChars; - - /// internal field - late bool isXGraphics; - - /// internal field - late int xobjectGraphicsCount; - int? _renderingMode; - late bool _textMatrix; - late bool _isCurrentPositionChanged; - Offset? _currentLocation; - late Offset _endTextPosition; - - /// internal field - late bool isScaledText; - late bool _skipRendering; - late Map _layersVisibilityDictionary; - late int _inlayersCount; - - /// internal field - bool? selectablePrintDocument; - - /// internal field - double? pageHeight; - - /// internal field - late bool isExtractLineCollection; - double? _textScaling = 100; - late bool _isNextFill; - - /// internal field - double? pageRotation; - - /// internal field - double? zoomFactor; - Map? _substitutedFontsList; - late double _textElementWidth; - - /// internal field - late List extractTextElement; - late List _whiteSpace; - //Properties - /// internal property - GraphicObjectData get objects => graphicsObjects!.last; - - /// internal property - MatrixHelper? get textLineMatrix { - return objects.textLineMatrix; - } - - set textLineMatrix(MatrixHelper? value) { - objects.textLineMatrix = value; - } - - /// internal property - MatrixHelper? get textMatrix { - return objects.textMatrix; - } - - set textMatrix(MatrixHelper? value) { - objects.textMatrix = value; - } - - /// internal property - MatrixHelper? get drawing2dMatrixCTM { - return objects.drawing2dMatrixCTM; - } - - set drawing2dMatrixCTM(MatrixHelper? value) { - objects.drawing2dMatrixCTM = value; - } - - /// internal property - MatrixHelper? get currentTransformationMatrix { - return objects.currentTransformationMatrix; - } - - set currentTransformationMatrix(MatrixHelper? value) { - objects.currentTransformationMatrix = value; - } - - /// internal property - MatrixHelper? get documentMatrix { - return objects.documentMatrix; - } - - set documentMatrix(MatrixHelper? value) { - objects.documentMatrix = value; - } - - /// internal property - Offset? get currentLocation { - return _currentLocation; - } - - set currentLocation(Offset? value) { - _currentLocation = value; - _isCurrentPositionChanged = true; - } - - /// internal property - double? get textLeading => graphicsObjects!.textLeading; - - set textLeading(double? value) { - objects.textLeading = value; - } - - /// internal property - String? get currentFont => graphicsObjects!.currentFont; - - set currentFont(String? value) { - objects.currentFont = value; - } - - /// internal property - double? get fontSize => graphicsObjects!.fontSize; - - set fontSize(double? value) { - objects.fontSize = value; - } - - //Implementation - void _initialize() { - selectablePrintDocument = false; - _isType3Font = false; - _symbolChars = ['(', ')', '[', ']', '<', '>']; - isXGraphics = false; - xobjectGraphicsCount = 0; - _renderingMode = 0; - _textMatrix = false; - _isCurrentPositionChanged = false; - _currentLocation = Offset.zero; - isScaledText = false; - _skipRendering = false; - _layersVisibilityDictionary = {}; - _inlayersCount = 0; - pageHeight = 0; - isExtractLineCollection = false; - _isNextFill = false; - pageRotation = 0; - zoomFactor = 1; - _substitutedFontsList = {}; - extractTextElement = []; - _whiteSpace = []; - } - - /// internal method - void renderAsImage() { - final PdfRecordCollection? pdfRecordCollection = - _isType3Font ? _type3RecordCollection : _contentElements; - if (pdfRecordCollection != null) { - final List records = pdfRecordCollection.recordCollection; - for (int i = 0; i < records.length; i++) { - final PdfRecord record = records[i]; - final String token = record.operatorName!; - final List? elements = record.operands; - for (int j = 0; j < _symbolChars.length; j++) { - if (token.contains(_symbolChars[j])) { - token.replaceAll(_symbolChars[j], ''); - } - } - switch (token.trim()) { - case 'BDC': - { - if (elements!.length > 1) { - final String layerID = elements[1].replaceAll('/', ''); - if (_layersVisibilityDictionary.containsKey(layerID) && - !_layersVisibilityDictionary[layerID]!) { - _skipRendering = true; - } - if (_skipRendering) { - _inlayersCount++; - } - if (elements[1].contains('ActualText') && - elements[1].contains('(')) { - _actualText = elements[1].substring( - elements[1].indexOf('(') + 1, - elements[1].lastIndexOf(')'), - ); - const String bigEndianPreambleString = 'þÿ'; - if (_actualText != null && - _actualText!.startsWith(bigEndianPreambleString)) { - _actualText = null; - } - } - } - } - break; - case 'EMC': - { - if (_inlayersCount > 0) { - _inlayersCount--; - } - if (_inlayersCount <= 0) { - _skipRendering = false; - } - _actualText = null; - } - break; - case 'q': - { - final GraphicObjectData data = GraphicObjectData(); - if (graphicsObjects!.count > 0) { - final GraphicObjectData prevData = graphicsObjects!.last; - data.currentTransformationMatrix = - prevData.currentTransformationMatrix; - data.mitterLength = prevData.mitterLength; - data.textLineMatrix = prevData.textLineMatrix; - data.documentMatrix = prevData.documentMatrix; - data.textMatrixUpdate = prevData.textMatrixUpdate; - data.drawing2dMatrixCTM = prevData.drawing2dMatrixCTM; - data.horizontalScaling = prevData.horizontalScaling; - data.rise = prevData.rise; - data.transformMatrixTM = prevData.transformMatrixTM; - data.characterSpacing = prevData.characterSpacing; - data.wordSpacing = prevData.wordSpacing; - data.nonStrokingOpacity = prevData.nonStrokingOpacity; - data.strokingOpacity = prevData.strokingOpacity; - } - if (isXGraphics) { - xobjectGraphicsCount++; - } - graphicsObjects!.push(data); - final GraphicsState? state = _graphicsObject!.save(); - _graphicsState!.push(state); - break; - } - case 'Q': - { - if (isXGraphics) { - xobjectGraphicsCount--; - } - graphicsObjects!.pop(); - if (_graphicsState!.count > 0) { - _graphicsObject!.restore(_graphicsState!.pop()!); - } - break; - } - case 'Tr': - { - _renderingMode = int.parse(elements![0]); - break; - } - case 'Tm': - { - final double a = double.tryParse(elements![0])!; - final double b = double.tryParse(elements[1])!; - final double c = double.tryParse(elements[2])!; - final double d = double.tryParse(elements[3])!; - final double e = double.tryParse(elements[4])!; - final double f = double.tryParse(elements[5])!; - _setTextMatrix(a, b, c, d, e, f); - if (_textMatrix) { - _graphicsObject!.restore(_graphicsState!.pop()!); - } - final GraphicsState? state = _graphicsObject!.save(); - _graphicsState!.push(state); - _graphicsObject!.multiplyTransform( - MatrixHelper(a, -b, -c, d, e, -f), - ); - currentLocation = Offset.zero; - _textMatrix = true; - break; - } - case 'cm': - { - final double a = double.tryParse(elements![0])!; - final double b = double.tryParse(elements[1])!; - final double c = double.tryParse(elements[2])!; - final double d = double.tryParse(elements[3])!; - final double e = double.tryParse(elements[4])!; - final double f = double.tryParse(elements[5])!; - drawing2dMatrixCTM = _setMatrix(a, b, c, d, e, f); - break; - } - case 'BT': - { - textLineMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - textMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - currentLocation = Offset.zero; - break; - } - case 'ET': - { - currentLocation = Offset.zero; - if (isScaledText) { - isScaledText = false; - _graphicsObject!.restore(_graphicsState!.pop()!); - } - if (_textMatrix) { - _graphicsObject!.restore(_graphicsState!.pop()!); - _textMatrix = false; - } - if (_renderingMode == 2 && - pdfRecordCollection.recordCollection.length > i + 1 && - pdfRecordCollection.recordCollection[i + 1].operatorName != - 'q') { - _renderingMode = 0; - } - break; - } - case 'T*': - { - _moveToNextLineWithCurrentTextLeading(); - _drawNewLine(); - break; - } - case 'TJ': - { - if (_skipRendering) { - break; - } - if (fontSize != 0) { - _renderTextElementWithSpacing(elements!, token); - } - break; - } - case 'Tj': - { - if (_skipRendering) { - break; - } - if (fontSize != 0) { - _renderTextElementWithLeading(elements!, token); - } - break; - } - case "'": - { - _moveToNextLineWithCurrentTextLeading(); - final MatrixHelper transformMatrix = _getTextRenderingMatrix( - false, - ); - objects.textMatrixUpdate = transformMatrix; - if (_textScaling != 100) { - final GraphicsState? state = _graphicsObject!.save(); - _graphicsState!.push(state); - _graphicsObject!.scaleTransform(_textScaling! / 100, 1); - isScaledText = true; - currentLocation = Offset( - currentLocation!.dx / (_textScaling! / 100), - currentLocation!.dy, - ); - } - _renderTextElementWithLeading(elements!, token); - break; - } - - case 'Tf': - { - _renderFont(elements!); - break; - } - case 'TD': - { - currentLocation = Offset( - currentLocation!.dx + double.tryParse(elements![0])!, - currentLocation!.dy - double.tryParse(elements[1])!, - ); - _moveToNextLineWithLeading(elements); - break; - } - case 'Td': - { - final double dx = double.tryParse(elements![0])!; - final double dy = double.tryParse(elements[1])!; - currentLocation = Offset( - currentLocation!.dx + dx, - currentLocation!.dy - dy, - ); - _moveToNextLine(dx, dy); - break; - } - case 'TL': - { - textLeading = -double.tryParse(elements![0])!; - break; - } - case 'Tw': - { - _getWordSpacing(elements!); - break; - } - case 'Tc': - { - _getCharacterSpacing(elements!); - break; - } - case 'Tz': - { - _getScalingFactor(elements!); - break; - } - case 'Do': - { - if (_skipRendering) { - break; - } - _getXObject(elements!); - break; - } - case 're': - { - if (_skipRendering) { - break; - } - if (i < pdfRecordCollection.count && - pdfRecordCollection.recordCollection[i + 1].operatorName == - 'f') { - _isNextFill = true; - } - if (!(drawing2dMatrixCTM!.m11 == 0 && - drawing2dMatrixCTM!.m21 == 0 && - _isNextFill)) { - _getClipRectangle(elements!); - } - break; - } - case 'b': - case 'b*': - { - if (_skipRendering) { - break; - } - final MatrixHelper initialmatrix = documentMatrix!; - final MatrixHelper currentCTM = MatrixHelper( - drawing2dMatrixCTM!.m11, - drawing2dMatrixCTM!.m12, - drawing2dMatrixCTM!.m21, - drawing2dMatrixCTM!.m22, - drawing2dMatrixCTM!.offsetX, - drawing2dMatrixCTM!.offsetY, - ); - final MatrixHelper result = currentCTM * initialmatrix; - final MatrixHelper transformMatrix = MatrixHelper( - result.m11, - result.m12, - result.m21, - result.m22, - result.offsetX, - result.offsetY, - ); - MatrixHelper graphicsTransformMatrix = MatrixHelper( - 1, - 0, - 0, - 1, - 0, - 0, - ); - graphicsTransformMatrix = - graphicsTransformMatrix * transformMatrix; - _graphicsObject!.transformMatrix = - MatrixHelper(1, 0, 0, 1, 0, 0) * transformMatrix; - break; - } - case 'W': - case 'W*': - _graphicsObject!.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - break; - default: - break; - } - } - } - } - - MatrixHelper _getTextRenderingMatrix(bool isPath) { - MatrixHelper mat = MatrixHelper( - fontSize! * (objects.horizontalScaling! / 100), - 0, - 0, - isPath ? fontSize! : (-fontSize!), - 0, - (isPath ? objects.rise! : (fontSize! + objects.rise!)) as double, - ); - mat *= textLineMatrix! * currentTransformationMatrix!; - return mat; - } - - void _getWordSpacing(List spacing) { - objects.wordSpacing = double.tryParse(spacing[0]); - } - - void _getCharacterSpacing(List spacing) { - objects.characterSpacing = double.tryParse(spacing[0]); - } - - void _getClipRectangle(List rectangle) { - double x = double.tryParse(rectangle[0])!; - final double y = double.tryParse(rectangle[1])!; - double? height = double.tryParse(rectangle[3]); - if (x < 0 && height! < 0 && _isNextFill) { - if (-height >= currentPageHeight!) { - x = 0; - height = 0; - } - } - _isNextFill = false; - _currentLocation = Offset(x, y + height!); - } - - void _renderFont(List fontElements) { - int i; - for (i = 0; i < fontElements.length; i++) { - if (fontElements[i].contains('/')) { - currentFont = fontElements[i].replaceAll('/', ''); - break; - } - } - fontSize = double.tryParse(fontElements[i + 1]); - if (_resources!.containsKey(currentFont)) { - final FontStructure structure = - _resources![currentFont!] as FontStructure; - if (structure.isStandardFont) { - structure.createStandardFont(fontSize!); - } else if (structure.isStandardCJKFont) { - structure.createStandardCJKFont(fontSize!); - } - } - } - - void _drawNewLine() { - _isCurrentPositionChanged = true; - if ((-textLeading!) != 0) { - _currentLocation = Offset( - _currentLocation!.dx, - (-textLeading!) < 0 - ? _currentLocation!.dy - (-textLeading!) - : _currentLocation!.dy + (-textLeading!), - ); - } else { - _currentLocation = Offset( - _currentLocation!.dx, - _currentLocation!.dy + fontSize!, - ); - } - } - - void _getScalingFactor(List elements) { - _textScaling = double.tryParse(elements[0]); - objects.horizontalScaling = double.tryParse(elements[0]); - } - - void _getXObject(List xobjectElement) { - final String key = xobjectElement[0].replaceAll('/', ''); - if (_resources!.containsKey(key)) { - final dynamic resource = _resources![key]; - if (resource is XObjectElement) { - List? xObjectGlyphs; - final XObjectElement xObjectElement = resource; - xObjectElement.isExtractTextLine = isExtractLineCollection; - if (selectablePrintDocument!) { - xObjectElement.isPrintSelected = selectablePrintDocument; - xObjectElement.pageHeight = pageHeight; - } - final Map result = xObjectElement.renderTextElement( - _graphicsObject, - _resources, - _graphicsState, - graphicsObjects, - currentPageHeight, - xObjectGlyphs, - ); - _graphicsState = result['graphicStates'] as GraphicStateCollection?; - graphicsObjects = result['objects'] as GraphicObjectDataCollection?; - xObjectGlyphs = result['glyphList'] as List?; - final List? tempExtractTextElement = - result['extractTextElement'] as List?; - if (tempExtractTextElement != null && - tempExtractTextElement.isNotEmpty) { - extractTextElement.addAll(tempExtractTextElement); - } - imageRenderGlyphList.addAll(xObjectGlyphs!); - xObjectGlyphs.clear(); - } - } - } - - void _renderTextElementWithLeading( - List textElements, - String tokenType, - ) { - String text = textElements.join(); - final List retrievedCharCodes = []; - if (_resources!.containsKey(currentFont)) { - final FontStructure structure = - _resources![currentFont!] as FontStructure; - structure.isSameFont = _resources!.isSameFont(); - structure.fontSize = fontSize; - if (!structure.isEmbedded && - structure.font != null && - structure.isStandardCJKFont) { - text = structure.fromUnicodeText(structure.getEncodedText(text, true)); - } else if (!structure.isEmbedded && - structure.font != null && - structure.isStandardFont) { - text = structure.getEncodedText(text, true); - } else { - text = structure.decodeTextExtraction( - text, - _resources!.isSameFont(), - retrievedCharCodes, - ); - } - if (_actualText != null && _actualText!.isNotEmpty) { - text = _actualText!; - _actualText = null; - } - final TextElement element = TextElement(text, documentMatrix); - element.fontStyle = structure.fontStyle!; - element.fontName = structure.fontName!; - element.fontSize = fontSize!; - element.textScaling = _textScaling; - element.fontEncoding = structure.fontEncoding; - element.fontGlyphWidths = structure.fontGlyphWidths; - element.defaultGlyphWidth = structure.defaultGlyphWidth; - element.text = text; - element.unicodeCharMapTable = structure.unicodeCharMapTable; - final Map glyphWidths = structure.fontGlyphWidths!; - element.characterMapTable = structure.characterMapTable; - element.reverseMapTable = structure.reverseMapTable; - element.structure = structure; - element.isEmbeddedFont = structure.isEmbedded; - element.currentTransformationMatrix = currentTransformationMatrix; - element.textLineMatrix = textMatrix; - element.rise = objects.rise; - element.transformMatrix = documentMatrix; - element.documentMatrix = documentMatrix; - element.fontId = currentFont; - element.octDecMapTable = structure.octDecMapTable; - element.textHorizontalScaling = objects.horizontalScaling; - element.zapfPostScript = structure.zapfPostScript; - element.lineWidth = objects.mitterLength; - element.renderingMode = _renderingMode; - element.pageRotation = pageRotation; - element.zoomFactor = zoomFactor; - element.substitutedFontsList = _substitutedFontsList; - element.wordSpacing = objects.wordSpacing; - element.characterSpacing = objects.characterSpacing; - element.isExtractTextData = isExtractLineCollection; - final MatrixHelper tempTextMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - tempTextMatrix.type = MatrixTypes.identity; - if (_isCurrentPositionChanged) { - _isCurrentPositionChanged = false; - _endTextPosition = currentLocation!; - final Map renderedResult = element.renderTextElement( - _graphicsObject, - Offset( - _endTextPosition.dx, - _endTextPosition.dy + ((-textLeading!) / 4), - ), - _textScaling, - glyphWidths, - structure.type1GlyphHeight, - structure.differenceTable, - structure.differencesDictionary, - structure.differenceEncoding, - tempTextMatrix, - retrievedCharCodes, - ); - _textElementWidth = renderedResult['textElementWidth'] as double; - textMatrix = renderedResult['tempTextMatrix'] as MatrixHelper; - } else { - _endTextPosition = Offset( - _endTextPosition.dx + _textElementWidth, - _endTextPosition.dy, - ); - final Map renderedResult = element.renderTextElement( - _graphicsObject, - Offset( - _endTextPosition.dx, - _endTextPosition.dy + (-textLeading! / 4), - ), - _textScaling, - glyphWidths, - structure.type1GlyphHeight, - structure.differenceTable, - structure.differencesDictionary, - structure.differenceEncoding, - tempTextMatrix, - ); - _textElementWidth = renderedResult['textElementWidth'] as double; - textMatrix = renderedResult['tempTextMatrix'] as MatrixHelper; - } - if (!structure.isWhiteSpace) { - if (_whiteSpace.isNotEmpty && - extractTextElement.isNotEmpty && - _whiteSpace.length == 1) { - if (extractTextElement[extractTextElement.length - 1] - .textLineMatrix! - .offsetY == - element.textLineMatrix!.offsetY && - _whiteSpace[0].textLineMatrix!.offsetY == - element.textLineMatrix!.offsetY) { - if (_whiteSpace[0].text.isNotEmpty) { - element.textElementGlyphList.insert( - 0, - _whiteSpace[0].textElementGlyphList[0], - ); - } - extractTextElement.add(_whiteSpace[0]); - } - _whiteSpace = []; - } - imageRenderGlyphList.addAll(element.textElementGlyphList); - if (isExtractLineCollection) { - extractTextElement.add(element); - } - _whiteSpace = []; - } else { - _whiteSpace.add(element); - } - } - } - - void _renderTextElementWithSpacing( - List textElements, - String tokenType, - ) { - List decodedList = []; - Map, String> decodedListCollection = - , String>{}; - final String text = textElements.join(); - if (_resources!.containsKey(currentFont)) { - final FontStructure structure = - _resources![currentFont!] as FontStructure; - structure.isSameFont = _resources!.isSameFont(); - structure.fontSize = fontSize; - List? characterSpacings; - if (!structure.isEmbedded && - structure.isStandardCJKFont && - structure.font != null) { - decodedList = structure.decodeCjkTextExtractionTJ( - text, - _resources!.isSameFont(), - ); - for (final String decodedString in decodedList) { - decodedListCollection[[]] = decodedString; - } - } else { - decodedListCollection = structure.decodeTextExtractionTJ( - text, - _resources!.isSameFont(), - ); - } - final List bytes = utf8.encode( - structure.getEncodedText(text, _resources!.isSameFont()), - ); - final Map encodedTextBytes = {}; - int z = 0; - for (int j = 0; j < bytes.length; j = j + 2) { - encodedTextBytes[z] = bytes[j]; - z++; - } - final TextElement element = TextElement(text, documentMatrix); - element.fontStyle = structure.fontStyle!; - element.fontName = structure.fontName!; - element.fontSize = fontSize!; - element.textScaling = _textScaling; - element.encodedTextBytes = encodedTextBytes; - element.fontEncoding = structure.fontEncoding; - element.fontGlyphWidths = structure.fontGlyphWidths; - element.defaultGlyphWidth = structure.defaultGlyphWidth; - element.renderingMode = _renderingMode; - element.unicodeCharMapTable = structure.unicodeCharMapTable; - final Map glyphWidths = structure.fontGlyphWidths!; - element.cidToGidReverseMapTable = structure.cidToGidReverseMapTable; - element.characterMapTable = structure.characterMapTable; - element.reverseMapTable = structure.reverseMapTable; - // //element.fontfile2Glyph = structure.glyphFontFile2; - element.structure = structure; - element.isEmbeddedFont = structure.isEmbedded; - element.currentTransformationMatrix = currentTransformationMatrix; - element.textLineMatrix = textMatrix; - element.rise = objects.rise; - element.transformMatrix = documentMatrix; - element.documentMatrix = documentMatrix; - element.fontId = currentFont; - element.octDecMapTable = structure.octDecMapTable; - element.textHorizontalScaling = objects.horizontalScaling; - element.zapfPostScript = structure.zapfPostScript; - element.lineWidth = objects.mitterLength; - element.renderingMode = _renderingMode; - element.pageRotation = pageRotation; - element.zoomFactor = zoomFactor; - element.substitutedFontsList = _substitutedFontsList; - element.isExtractTextData = isExtractLineCollection; - if (structure.flags != null) { - element.fontFlag = structure.flags!.value!.toInt(); - } - element.wordSpacing = objects.wordSpacing; - element.characterSpacing = objects.characterSpacing; - final MatrixHelper tempTextMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - tempTextMatrix.type = MatrixTypes.identity; - if (_isCurrentPositionChanged) { - _isCurrentPositionChanged = false; - _endTextPosition = currentLocation!; - } else { - _endTextPosition = Offset( - _endTextPosition.dx + _textElementWidth, - _endTextPosition.dy, - ); - } - final Map renderedResult = element.renderWithSpacing( - _graphicsObject, - Offset(_endTextPosition.dx, _endTextPosition.dy - fontSize!), - decodedListCollection, - characterSpacings, - _textScaling, - glyphWidths, - structure.type1GlyphHeight, - structure.differenceTable, - structure.differencesDictionary, - structure.differenceEncoding, - tempTextMatrix, - ); - _textElementWidth = renderedResult['textElementWidth'] as double; - textMatrix = renderedResult['tempTextMatrix'] as MatrixHelper; - if (!structure.isWhiteSpace) { - if (_whiteSpace.isNotEmpty && - extractTextElement.isNotEmpty && - _whiteSpace.length == 1) { - if (extractTextElement[extractTextElement.length - 1] - .textLineMatrix! - .offsetY == - element.textLineMatrix!.offsetY && - _whiteSpace[0].textLineMatrix!.offsetY == - element.textLineMatrix!.offsetY && - _whiteSpace[0].textElementGlyphList.isNotEmpty) { - element.textElementGlyphList.insert( - 0, - _whiteSpace[0].textElementGlyphList[0], - ); - extractTextElement.add(_whiteSpace[0]); - } - _whiteSpace = []; - } - imageRenderGlyphList.addAll(element.textElementGlyphList); - if (isExtractLineCollection) { - extractTextElement.add(element); - } - _whiteSpace = []; - } else { - _whiteSpace.add(element); - } - } - } - - void _moveToNextLineWithCurrentTextLeading() { - _moveToNextLine(0, textLeading!); - } - - void _moveToNextLineWithLeading(List elements) { - final double dx = double.tryParse(elements[0])!; - final double dy = double.tryParse(elements[1])!; - textLeading = dy; - _moveToNextLine(dx, dy); - } - - void _moveToNextLine(double tx, double ty) { - textMatrix = MatrixHelper(1, 0, 0, 1, tx, ty) * textLineMatrix!; - textLineMatrix = textMatrix!.clone(); - } - - void _setTextMatrix( - double a, - double b, - double c, - double d, - double e, - double f, - ) { - textMatrix = MatrixHelper(a, b, c, d, e, f); - textLineMatrix = textMatrix!.clone(); - } - - MatrixHelper _setMatrix( - double a, - double b, - double c, - double d, - double e, - double f, - ) { - currentTransformationMatrix = - MatrixHelper(a, b, c, d, e, f) * - graphicsObjects!.last.currentTransformationMatrix!; - return MatrixHelper( - currentTransformationMatrix!.m11, - currentTransformationMatrix!.m12, - currentTransformationMatrix!.m21, - currentTransformationMatrix!.m22, - currentTransformationMatrix!.offsetX, - currentTransformationMatrix!.offsetY, - ); - } -} +import 'dart:convert'; +import 'dart:ui'; + +import '../../graphics/pdf_color.dart'; +import 'font_structure.dart'; +import 'glyph.dart'; +import 'graphic_object_data.dart'; +import 'graphic_object_data_collection.dart'; +import 'matrix_helper.dart'; +import 'page_resource_loader.dart'; +import 'parser/content_parser.dart'; +import 'text_element.dart'; +import 'xobject_element.dart'; + +/// internal class +class ImageRenderer { + /// internal constructor + ImageRenderer( + PdfRecordCollection? contentElements, + PdfPageResources resources, + this.currentPageHeight, [ + GraphicsObject? g, + ]) { + const int dpiX = 96; + _graphicsObject = GraphicsObject(); + _graphicsState = GraphicStateCollection(); + graphicsObjects = GraphicObjectDataCollection(); + final GraphicObjectData newObject = GraphicObjectData(); + newObject.currentTransformationMatrix = MatrixHelper( + 1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + ); + final MatrixHelper transformMatrix = + g != null ? g.transformMatrix! : _graphicsObject!.transformMatrix!; + newObject.currentTransformationMatrix!.translate( + transformMatrix.offsetX / 1.333, + transformMatrix.offsetY / 1.333, + ); + newObject.drawing2dMatrixCTM = MatrixHelper(1, 0, 0, 1, 0, 0); + newObject.drawing2dMatrixCTM!.translate( + transformMatrix.offsetX / 1.333, + transformMatrix.offsetY / 1.333, + ); + newObject.documentMatrix = MatrixHelper( + 1.33333333333333 * (dpiX / 96) * transformMatrix.m11, + 0, + 0, + -1.33333333333333 * (dpiX / 96) * transformMatrix.m22, + 0, + currentPageHeight! * transformMatrix.m22, + ); + // Initialize colors to black (default for PDF) + newObject.fillColor = PdfColor(0, 0, 0); + newObject.strokeColor = PdfColor(0, 0, 0); + graphicsObjects!.push(newObject); + graphicsObjects!.push(newObject); + _contentElements = contentElements; + _resources = resources; + imageRenderGlyphList = []; + _initialize(); + } + + //Fields + /// internal field + GraphicObjectDataCollection? graphicsObjects; + GraphicStateCollection? _graphicsState; + GraphicsObject? _graphicsObject; + PdfRecordCollection? _contentElements; + PdfPageResources? _resources; + String? _actualText; + + /// internal field + double? currentPageHeight; + + /// internal field + late List imageRenderGlyphList; + PdfRecordCollection? _type3RecordCollection; + late bool _isType3Font; + late List _symbolChars; + + /// internal field + late bool isXGraphics; + + /// internal field + late int xobjectGraphicsCount; + int? _renderingMode; + late bool _textMatrix; + late bool _isCurrentPositionChanged; + Offset? _currentLocation; + late Offset _endTextPosition; + + /// internal field + late bool isScaledText; + late bool _skipRendering; + late Map _layersVisibilityDictionary; + late int _inlayersCount; + + /// internal field + bool? selectablePrintDocument; + + /// internal field + double? pageHeight; + + /// internal field + late bool isExtractLineCollection; + double? _textScaling = 100; + late bool _isNextFill; + + /// internal field + double? pageRotation; + + /// internal field + double? zoomFactor; + Map? _substitutedFontsList; + late double _textElementWidth; + + /// internal field + late List extractTextElement; + late List _whiteSpace; + //Properties + /// internal property + GraphicObjectData get objects => graphicsObjects!.last; + + /// internal property + MatrixHelper? get textLineMatrix { + return objects.textLineMatrix; + } + + set textLineMatrix(MatrixHelper? value) { + objects.textLineMatrix = value; + } + + /// internal property + MatrixHelper? get textMatrix { + return objects.textMatrix; + } + + set textMatrix(MatrixHelper? value) { + objects.textMatrix = value; + } + + /// internal property + MatrixHelper? get drawing2dMatrixCTM { + return objects.drawing2dMatrixCTM; + } + + set drawing2dMatrixCTM(MatrixHelper? value) { + objects.drawing2dMatrixCTM = value; + } + + /// internal property + MatrixHelper? get currentTransformationMatrix { + return objects.currentTransformationMatrix; + } + + set currentTransformationMatrix(MatrixHelper? value) { + objects.currentTransformationMatrix = value; + } + + /// internal property + MatrixHelper? get documentMatrix { + return objects.documentMatrix; + } + + set documentMatrix(MatrixHelper? value) { + objects.documentMatrix = value; + } + + /// internal property + Offset? get currentLocation { + return _currentLocation; + } + + set currentLocation(Offset? value) { + _currentLocation = value; + _isCurrentPositionChanged = true; + } + + /// internal property + double? get textLeading => graphicsObjects!.textLeading; + + set textLeading(double? value) { + objects.textLeading = value; + } + + /// internal property + String? get currentFont => graphicsObjects!.currentFont; + + set currentFont(String? value) { + objects.currentFont = value; + } + + /// internal property + double? get fontSize => graphicsObjects!.fontSize; + + set fontSize(double? value) { + objects.fontSize = value; + } + + //Implementation + void _initialize() { + selectablePrintDocument = false; + _isType3Font = false; + _symbolChars = ['(', ')', '[', ']', '<', '>']; + isXGraphics = false; + xobjectGraphicsCount = 0; + _renderingMode = 0; + _textMatrix = false; + _isCurrentPositionChanged = false; + _currentLocation = Offset.zero; + isScaledText = false; + _skipRendering = false; + _layersVisibilityDictionary = {}; + _inlayersCount = 0; + pageHeight = 0; + isExtractLineCollection = false; + _isNextFill = false; + pageRotation = 0; + zoomFactor = 1; + _substitutedFontsList = {}; + extractTextElement = []; + _whiteSpace = []; + } + + /// internal method + void renderAsImage() { + final PdfRecordCollection? pdfRecordCollection = + _isType3Font ? _type3RecordCollection : _contentElements; + if (pdfRecordCollection != null) { + final List records = pdfRecordCollection.recordCollection; + for (int i = 0; i < records.length; i++) { + final PdfRecord record = records[i]; + final String token = record.operatorName!; + final List? elements = record.operands; + for (int j = 0; j < _symbolChars.length; j++) { + if (token.contains(_symbolChars[j])) { + token.replaceAll(_symbolChars[j], ''); + } + } + + switch (token.trim()) { + case 'BDC': + { + if (elements!.length > 1) { + final String layerID = elements[1].replaceAll('/', ''); + if (_layersVisibilityDictionary.containsKey(layerID) && + !_layersVisibilityDictionary[layerID]!) { + _skipRendering = true; + } + if (_skipRendering) { + _inlayersCount++; + } + if (elements[1].contains('ActualText') && + elements[1].contains('(')) { + _actualText = elements[1].substring( + elements[1].indexOf('(') + 1, + elements[1].lastIndexOf(')'), + ); + const String bigEndianPreambleString = 'þÿ'; + if (_actualText != null && + _actualText!.startsWith(bigEndianPreambleString)) { + _actualText = null; + } + } + } + } + break; + case 'EMC': + { + if (_inlayersCount > 0) { + _inlayersCount--; + } + if (_inlayersCount <= 0) { + _skipRendering = false; + } + _actualText = null; + } + break; + case 'q': + { + final GraphicObjectData data = GraphicObjectData(); + if (graphicsObjects!.count > 0) { + final GraphicObjectData prevData = graphicsObjects!.last; + data.currentTransformationMatrix = + prevData.currentTransformationMatrix; + data.mitterLength = prevData.mitterLength; + data.textLineMatrix = prevData.textLineMatrix; + data.documentMatrix = prevData.documentMatrix; + data.textMatrixUpdate = prevData.textMatrixUpdate; + data.drawing2dMatrixCTM = prevData.drawing2dMatrixCTM; + data.horizontalScaling = prevData.horizontalScaling; + data.rise = prevData.rise; + data.transformMatrixTM = prevData.transformMatrixTM; + data.characterSpacing = prevData.characterSpacing; + data.wordSpacing = prevData.wordSpacing; + data.nonStrokingOpacity = prevData.nonStrokingOpacity; + data.strokingOpacity = prevData.strokingOpacity; + data.fillColor = prevData.fillColor; + data.strokeColor = prevData.strokeColor; + } + if (isXGraphics) { + xobjectGraphicsCount++; + } + graphicsObjects!.push(data); + final GraphicsState? state = _graphicsObject!.save(); + _graphicsState!.push(state); + break; + } + case 'Q': + { + if (isXGraphics) { + xobjectGraphicsCount--; + } + graphicsObjects!.pop(); + if (_graphicsState!.count > 0) { + _graphicsObject!.restore(_graphicsState!.pop()!); + } + break; + } + case 'Tr': + { + _renderingMode = int.parse(elements![0]); + break; + } + case 'Tm': + { + final double a = double.tryParse(elements![0])!; + final double b = double.tryParse(elements[1])!; + final double c = double.tryParse(elements[2])!; + final double d = double.tryParse(elements[3])!; + final double e = double.tryParse(elements[4])!; + final double f = double.tryParse(elements[5])!; + _setTextMatrix(a, b, c, d, e, f); + if (_textMatrix) { + _graphicsObject!.restore(_graphicsState!.pop()!); + } + final GraphicsState? state = _graphicsObject!.save(); + _graphicsState!.push(state); + _graphicsObject!.multiplyTransform( + MatrixHelper(a, -b, -c, d, e, -f), + ); + currentLocation = Offset.zero; + _textMatrix = true; + break; + } + case 'cm': + { + final double a = double.tryParse(elements![0])!; + final double b = double.tryParse(elements[1])!; + final double c = double.tryParse(elements[2])!; + final double d = double.tryParse(elements[3])!; + final double e = double.tryParse(elements[4])!; + final double f = double.tryParse(elements[5])!; + drawing2dMatrixCTM = _setMatrix(a, b, c, d, e, f); + break; + } + case 'BT': + { + textLineMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + textMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + currentLocation = Offset.zero; + break; + } + case 'ET': + { + currentLocation = Offset.zero; + if (isScaledText) { + isScaledText = false; + _graphicsObject!.restore(_graphicsState!.pop()!); + } + if (_textMatrix) { + _graphicsObject!.restore(_graphicsState!.pop()!); + _textMatrix = false; + } + if (_renderingMode == 2 && + pdfRecordCollection.recordCollection.length > i + 1 && + pdfRecordCollection.recordCollection[i + 1].operatorName != + 'q') { + _renderingMode = 0; + } + break; + } + case 'T*': + { + _moveToNextLineWithCurrentTextLeading(); + _drawNewLine(); + break; + } + case 'TJ': + { + if (_skipRendering) { + break; + } + if (fontSize != 0) { + _renderTextElementWithSpacing(elements!, token); + } + break; + } + case 'Tj': + { + if (_skipRendering) { + break; + } + if (fontSize != 0) { + _renderTextElementWithLeading(elements!, token); + } + break; + } + case "'": + { + _moveToNextLineWithCurrentTextLeading(); + final MatrixHelper transformMatrix = _getTextRenderingMatrix( + false, + ); + objects.textMatrixUpdate = transformMatrix; + if (_textScaling != 100) { + final GraphicsState? state = _graphicsObject!.save(); + _graphicsState!.push(state); + _graphicsObject!.scaleTransform(_textScaling! / 100, 1); + isScaledText = true; + currentLocation = Offset( + currentLocation!.dx / (_textScaling! / 100), + currentLocation!.dy, + ); + } + _renderTextElementWithLeading(elements!, token); + break; + } + + case 'Tf': + { + _renderFont(elements!); + break; + } + case 'TD': + { + currentLocation = Offset( + currentLocation!.dx + double.tryParse(elements![0])!, + currentLocation!.dy - double.tryParse(elements[1])!, + ); + _moveToNextLineWithLeading(elements); + break; + } + case 'Td': + { + final double dx = double.tryParse(elements![0])!; + final double dy = double.tryParse(elements[1])!; + currentLocation = Offset( + currentLocation!.dx + dx, + currentLocation!.dy - dy, + ); + _moveToNextLine(dx, dy); + break; + } + case 'TL': + { + textLeading = -double.tryParse(elements![0])!; + break; + } + case 'Tw': + { + _getWordSpacing(elements!); + break; + } + case 'Tc': + { + _getCharacterSpacing(elements!); + break; + } + case 'Tz': + { + _getScalingFactor(elements!); + break; + } + case 'Do': + { + if (_skipRendering) { + break; + } + _getXObject(elements!); + break; + } + case 're': + { + if (_skipRendering) { + break; + } + if (i < pdfRecordCollection.count && + pdfRecordCollection.recordCollection[i + 1].operatorName == + 'f') { + _isNextFill = true; + } + if (!(drawing2dMatrixCTM!.m11 == 0 && + drawing2dMatrixCTM!.m21 == 0 && + _isNextFill)) { + _getClipRectangle(elements!); + } + break; + } + case 'b': + case 'b*': + { + if (_skipRendering) { + break; + } + final MatrixHelper initialmatrix = documentMatrix!; + final MatrixHelper currentCTM = MatrixHelper( + drawing2dMatrixCTM!.m11, + drawing2dMatrixCTM!.m12, + drawing2dMatrixCTM!.m21, + drawing2dMatrixCTM!.m22, + drawing2dMatrixCTM!.offsetX, + drawing2dMatrixCTM!.offsetY, + ); + final MatrixHelper result = currentCTM * initialmatrix; + final MatrixHelper transformMatrix = MatrixHelper( + result.m11, + result.m12, + result.m21, + result.m22, + result.offsetX, + result.offsetY, + ); + MatrixHelper graphicsTransformMatrix = MatrixHelper( + 1, + 0, + 0, + 1, + 0, + 0, + ); + graphicsTransformMatrix = + graphicsTransformMatrix * transformMatrix; + _graphicsObject!.transformMatrix = + MatrixHelper(1, 0, 0, 1, 0, 0) * transformMatrix; + break; + } + case 'W': + case 'W*': + _graphicsObject!.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + break; + case 'g': + case 'G': + case 'rg': + case 'RG': + case 'k': + case 'K': + { + if (token == 'g' || token == 'rg' || token == 'k') { + _setFillColor(elements!, token); + } else { + _setStrokeColor(elements!, token); + } + break; + } + default: + break; + } + } + } + } + + MatrixHelper _getTextRenderingMatrix(bool isPath) { + MatrixHelper mat = MatrixHelper( + fontSize! * (objects.horizontalScaling! / 100), + 0, + 0, + isPath ? fontSize! : (-fontSize!), + 0, + (isPath ? objects.rise! : (fontSize! + objects.rise!)) as double, + ); + mat *= textLineMatrix! * currentTransformationMatrix!; + return mat; + } + + void _getWordSpacing(List spacing) { + objects.wordSpacing = double.tryParse(spacing[0]); + } + + void _getCharacterSpacing(List spacing) { + objects.characterSpacing = double.tryParse(spacing[0]); + } + + void _getClipRectangle(List rectangle) { + double x = double.tryParse(rectangle[0])!; + final double y = double.tryParse(rectangle[1])!; + double? height = double.tryParse(rectangle[3]); + if (x < 0 && height! < 0 && _isNextFill) { + if (-height >= currentPageHeight!) { + x = 0; + height = 0; + } + } + _isNextFill = false; + _currentLocation = Offset(x, y + height!); + } + + void _renderFont(List fontElements) { + int i; + for (i = 0; i < fontElements.length; i++) { + if (fontElements[i].contains('/')) { + currentFont = fontElements[i].replaceAll('/', ''); + break; + } + } + fontSize = double.tryParse(fontElements[i + 1]); + if (_resources!.containsKey(currentFont)) { + final FontStructure structure = + _resources![currentFont!] as FontStructure; + if (structure.isStandardFont) { + structure.createStandardFont(fontSize!); + } else if (structure.isStandardCJKFont) { + structure.createStandardCJKFont(fontSize!); + } + } + } + + void _drawNewLine() { + _isCurrentPositionChanged = true; + if ((-textLeading!) != 0) { + _currentLocation = Offset( + _currentLocation!.dx, + (-textLeading!) < 0 + ? _currentLocation!.dy - (-textLeading!) + : _currentLocation!.dy + (-textLeading!), + ); + } else { + _currentLocation = Offset( + _currentLocation!.dx, + _currentLocation!.dy + fontSize!, + ); + } + } + + void _getScalingFactor(List elements) { + _textScaling = double.tryParse(elements[0]); + objects.horizontalScaling = double.tryParse(elements[0]); + } + + void _setFillColor(List elements, String token) { + if (token == 'g') { + if (elements.isNotEmpty) { + try { + final double gray = double.parse(elements[0]); + if (gray >= 0 && gray <= 1) { + objects.fillColor = PdfColor( + (gray * 255).toInt(), + (gray * 255).toInt(), + (gray * 255).toInt(), + ); + } + } catch (e) { + // Invalid color value, skip + } + } + } else if (token == 'rg') { + if (elements.length >= 3) { + try { + final double r = double.parse(elements[0]); + final double g = double.parse(elements[1]); + final double b = double.parse(elements[2]); + if (r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1) { + objects.fillColor = PdfColor( + (r * 255).toInt(), + (g * 255).toInt(), + (b * 255).toInt(), + ); + } + } catch (e) { + // Invalid color value, skip + } + } + } else if (token == 'k') { + if (elements.length >= 4) { + try { + final double c = double.parse(elements[0]); + final double m = double.parse(elements[1]); + final double y = double.parse(elements[2]); + final double k = double.parse(elements[3]); + if (c >= 0 && + c <= 1 && + m >= 0 && + m <= 1 && + y >= 0 && + y <= 1 && + k >= 0 && + k <= 1) { + final double r = 255 * (1 - c) * (1 - k); + final double g = 255 * (1 - m) * (1 - k); + final double b = 255 * (1 - y) * (1 - k); + objects.fillColor = PdfColor(r.toInt(), g.toInt(), b.toInt()); + } + } catch (e) { + // Invalid color value, skip + } + } + } + } + + void _setStrokeColor(List elements, String token) { + if (token == 'G') { + if (elements.isNotEmpty) { + try { + final double gray = double.parse(elements[0]); + if (gray >= 0 && gray <= 1) { + objects.strokeColor = PdfColor( + (gray * 255).toInt(), + (gray * 255).toInt(), + (gray * 255).toInt(), + ); + } + } catch (e) { + // Invalid color value, skip + } + } + } else if (token == 'RG') { + if (elements.length >= 3) { + try { + final double r = double.parse(elements[0]); + final double g = double.parse(elements[1]); + final double b = double.parse(elements[2]); + if (r >= 0 && r <= 1 && g >= 0 && g <= 1 && b >= 0 && b <= 1) { + objects.strokeColor = PdfColor( + (r * 255).toInt(), + (g * 255).toInt(), + (b * 255).toInt(), + ); + } + } catch (e) { + // Invalid color value, skip + } + } + } else if (token == 'K') { + if (elements.length >= 4) { + try { + final double c = double.parse(elements[0]); + final double m = double.parse(elements[1]); + final double y = double.parse(elements[2]); + final double k = double.parse(elements[3]); + if (c >= 0 && + c <= 1 && + m >= 0 && + m <= 1 && + y >= 0 && + y <= 1 && + k >= 0 && + k <= 1) { + final double r = 255 * (1 - c) * (1 - k); + final double g = 255 * (1 - m) * (1 - k); + final double b = 255 * (1 - y) * (1 - k); + objects.strokeColor = PdfColor(r.toInt(), g.toInt(), b.toInt()); + } + } catch (e) { + // Invalid color value, skip + } + } + } + } + + void _getXObject(List xobjectElement) { + final String key = xobjectElement[0].replaceAll('/', ''); + if (_resources!.containsKey(key)) { + final dynamic resource = _resources![key]; + if (resource is XObjectElement) { + List? xObjectGlyphs; + final XObjectElement xObjectElement = resource; + xObjectElement.isExtractTextLine = isExtractLineCollection; + if (selectablePrintDocument!) { + xObjectElement.isPrintSelected = selectablePrintDocument; + xObjectElement.pageHeight = pageHeight; + } + final Map result = xObjectElement.renderTextElement( + _graphicsObject, + _resources, + _graphicsState, + graphicsObjects, + currentPageHeight, + xObjectGlyphs, + ); + _graphicsState = result['graphicStates'] as GraphicStateCollection?; + graphicsObjects = result['objects'] as GraphicObjectDataCollection?; + xObjectGlyphs = result['glyphList'] as List?; + final List? tempExtractTextElement = + result['extractTextElement'] as List?; + if (tempExtractTextElement != null && + tempExtractTextElement.isNotEmpty) { + extractTextElement.addAll(tempExtractTextElement); + } + imageRenderGlyphList.addAll(xObjectGlyphs!); + xObjectGlyphs.clear(); + } + } + } + + void _renderTextElementWithLeading( + List textElements, + String tokenType, + ) { + String text = textElements.join(); + final List retrievedCharCodes = []; + if (_resources!.containsKey(currentFont)) { + final FontStructure structure = + _resources![currentFont!] as FontStructure; + structure.isSameFont = _resources!.isSameFont(); + structure.fontSize = fontSize; + if (!structure.isEmbedded && + structure.font != null && + structure.isStandardCJKFont) { + text = structure.fromUnicodeText(structure.getEncodedText(text, true)); + } else if (!structure.isEmbedded && + structure.font != null && + structure.isStandardFont) { + text = structure.getEncodedText(text, true); + } else { + text = structure.decodeTextExtraction( + text, + _resources!.isSameFont(), + retrievedCharCodes, + ); + } + if (_actualText != null && _actualText!.isNotEmpty) { + text = _actualText!; + _actualText = null; + } + final TextElement element = TextElement(text, documentMatrix); + element.fontStyle = structure.fontStyle!; + element.fontName = structure.fontName!; + element.fontSize = fontSize!; + element.textScaling = _textScaling; + element.fontEncoding = structure.fontEncoding; + element.fontGlyphWidths = structure.fontGlyphWidths; + element.defaultGlyphWidth = structure.defaultGlyphWidth; + element.text = text; + element.unicodeCharMapTable = structure.unicodeCharMapTable; + final Map glyphWidths = structure.fontGlyphWidths!; + element.characterMapTable = structure.characterMapTable; + element.reverseMapTable = structure.reverseMapTable; + element.structure = structure; + element.isEmbeddedFont = structure.isEmbedded; + element.currentTransformationMatrix = currentTransformationMatrix; + element.textLineMatrix = textMatrix; + element.rise = objects.rise; + element.transformMatrix = documentMatrix; + element.documentMatrix = documentMatrix; + element.fontId = currentFont; + element.octDecMapTable = structure.octDecMapTable; + element.textHorizontalScaling = objects.horizontalScaling; + element.zapfPostScript = structure.zapfPostScript; + element.lineWidth = objects.mitterLength; + element.renderingMode = _renderingMode; + element.pageRotation = pageRotation; + element.zoomFactor = zoomFactor; + element.substitutedFontsList = _substitutedFontsList; + element.wordSpacing = objects.wordSpacing; + element.characterSpacing = objects.characterSpacing; + element.isExtractTextData = isExtractLineCollection; + element.textColor = objects.fillColor ?? PdfColor(0, 0, 0); + final MatrixHelper tempTextMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + tempTextMatrix.type = MatrixTypes.identity; + if (_isCurrentPositionChanged) { + _isCurrentPositionChanged = false; + _endTextPosition = currentLocation!; + final Map renderedResult = element.renderTextElement( + _graphicsObject, + Offset( + _endTextPosition.dx, + _endTextPosition.dy + ((-textLeading!) / 4), + ), + _textScaling, + glyphWidths, + structure.type1GlyphHeight, + structure.differenceTable, + structure.differencesDictionary, + structure.differenceEncoding, + tempTextMatrix, + retrievedCharCodes, + ); + _textElementWidth = renderedResult['textElementWidth'] as double; + textMatrix = renderedResult['tempTextMatrix'] as MatrixHelper; + } else { + _endTextPosition = Offset( + _endTextPosition.dx + _textElementWidth, + _endTextPosition.dy, + ); + final Map renderedResult = element.renderTextElement( + _graphicsObject, + Offset( + _endTextPosition.dx, + _endTextPosition.dy + (-textLeading! / 4), + ), + _textScaling, + glyphWidths, + structure.type1GlyphHeight, + structure.differenceTable, + structure.differencesDictionary, + structure.differenceEncoding, + tempTextMatrix, + ); + _textElementWidth = renderedResult['textElementWidth'] as double; + textMatrix = renderedResult['tempTextMatrix'] as MatrixHelper; + } + if (!structure.isWhiteSpace) { + if (_whiteSpace.isNotEmpty && + extractTextElement.isNotEmpty && + _whiteSpace.length == 1) { + if (extractTextElement[extractTextElement.length - 1] + .textLineMatrix! + .offsetY == + element.textLineMatrix!.offsetY && + _whiteSpace[0].textLineMatrix!.offsetY == + element.textLineMatrix!.offsetY) { + if (_whiteSpace[0].text.isNotEmpty) { + element.textElementGlyphList.insert( + 0, + _whiteSpace[0].textElementGlyphList[0], + ); + } + extractTextElement.add(_whiteSpace[0]); + } + _whiteSpace = []; + } + imageRenderGlyphList.addAll(element.textElementGlyphList); + if (isExtractLineCollection) { + extractTextElement.add(element); + } + _whiteSpace = []; + } else { + _whiteSpace.add(element); + } + } + } + + void _renderTextElementWithSpacing( + List textElements, + String tokenType, + ) { + List decodedList = []; + Map, String> decodedListCollection = + , String>{}; + final String text = textElements.join(); + if (_resources!.containsKey(currentFont)) { + final FontStructure structure = + _resources![currentFont!] as FontStructure; + structure.isSameFont = _resources!.isSameFont(); + structure.fontSize = fontSize; + List? characterSpacings; + if (!structure.isEmbedded && + structure.isStandardCJKFont && + structure.font != null) { + decodedList = structure.decodeCjkTextExtractionTJ( + text, + _resources!.isSameFont(), + ); + for (final String decodedString in decodedList) { + decodedListCollection[[]] = decodedString; + } + } else { + decodedListCollection = structure.decodeTextExtractionTJ( + text, + _resources!.isSameFont(), + ); + } + final List bytes = utf8.encode( + structure.getEncodedText(text, _resources!.isSameFont()), + ); + final Map encodedTextBytes = {}; + int z = 0; + for (int j = 0; j < bytes.length; j = j + 2) { + encodedTextBytes[z] = bytes[j]; + z++; + } + final TextElement element = TextElement(text, documentMatrix); + element.fontStyle = structure.fontStyle!; + element.fontName = structure.fontName!; + element.fontSize = fontSize!; + element.textScaling = _textScaling; + element.encodedTextBytes = encodedTextBytes; + element.fontEncoding = structure.fontEncoding; + element.fontGlyphWidths = structure.fontGlyphWidths; + element.defaultGlyphWidth = structure.defaultGlyphWidth; + element.renderingMode = _renderingMode; + element.unicodeCharMapTable = structure.unicodeCharMapTable; + final Map glyphWidths = structure.fontGlyphWidths!; + element.cidToGidReverseMapTable = structure.cidToGidReverseMapTable; + element.characterMapTable = structure.characterMapTable; + element.reverseMapTable = structure.reverseMapTable; + // //element.fontfile2Glyph = structure.glyphFontFile2; + element.structure = structure; + element.isEmbeddedFont = structure.isEmbedded; + element.currentTransformationMatrix = currentTransformationMatrix; + element.textLineMatrix = textMatrix; + element.rise = objects.rise; + element.transformMatrix = documentMatrix; + element.documentMatrix = documentMatrix; + element.fontId = currentFont; + element.octDecMapTable = structure.octDecMapTable; + element.textHorizontalScaling = objects.horizontalScaling; + element.zapfPostScript = structure.zapfPostScript; + element.lineWidth = objects.mitterLength; + element.renderingMode = _renderingMode; + element.pageRotation = pageRotation; + element.zoomFactor = zoomFactor; + element.substitutedFontsList = _substitutedFontsList; + element.isExtractTextData = isExtractLineCollection; + if (structure.flags != null) { + element.fontFlag = structure.flags!.value!.toInt(); + } + element.wordSpacing = objects.wordSpacing; + element.characterSpacing = objects.characterSpacing; + element.textColor = objects.fillColor ?? PdfColor(0, 0, 0); + final MatrixHelper tempTextMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + tempTextMatrix.type = MatrixTypes.identity; + if (_isCurrentPositionChanged) { + _isCurrentPositionChanged = false; + _endTextPosition = currentLocation!; + } else { + _endTextPosition = Offset( + _endTextPosition.dx + _textElementWidth, + _endTextPosition.dy, + ); + } + final Map renderedResult = element.renderWithSpacing( + _graphicsObject, + Offset(_endTextPosition.dx, _endTextPosition.dy - fontSize!), + decodedListCollection, + characterSpacings, + _textScaling, + glyphWidths, + structure.type1GlyphHeight, + structure.differenceTable, + structure.differencesDictionary, + structure.differenceEncoding, + tempTextMatrix, + ); + _textElementWidth = renderedResult['textElementWidth'] as double; + textMatrix = renderedResult['tempTextMatrix'] as MatrixHelper; + if (!structure.isWhiteSpace) { + if (_whiteSpace.isNotEmpty && + extractTextElement.isNotEmpty && + _whiteSpace.length == 1) { + if (extractTextElement[extractTextElement.length - 1] + .textLineMatrix! + .offsetY == + element.textLineMatrix!.offsetY && + _whiteSpace[0].textLineMatrix!.offsetY == + element.textLineMatrix!.offsetY && + _whiteSpace[0].textElementGlyphList.isNotEmpty) { + element.textElementGlyphList.insert( + 0, + _whiteSpace[0].textElementGlyphList[0], + ); + extractTextElement.add(_whiteSpace[0]); + } + _whiteSpace = []; + } + imageRenderGlyphList.addAll(element.textElementGlyphList); + if (isExtractLineCollection) { + extractTextElement.add(element); + } + _whiteSpace = []; + } else { + _whiteSpace.add(element); + } + } + } + + void _moveToNextLineWithCurrentTextLeading() { + _moveToNextLine(0, textLeading!); + } + + void _moveToNextLineWithLeading(List elements) { + final double dx = double.tryParse(elements[0])!; + final double dy = double.tryParse(elements[1])!; + textLeading = dy; + _moveToNextLine(dx, dy); + } + + void _moveToNextLine(double tx, double ty) { + textMatrix = MatrixHelper(1, 0, 0, 1, tx, ty) * textLineMatrix!; + textLineMatrix = textMatrix!.clone(); + } + + void _setTextMatrix( + double a, + double b, + double c, + double d, + double e, + double f, + ) { + textMatrix = MatrixHelper(a, b, c, d, e, f); + textLineMatrix = textMatrix!.clone(); + } + + MatrixHelper _setMatrix( + double a, + double b, + double c, + double d, + double e, + double f, + ) { + currentTransformationMatrix = + MatrixHelper(a, b, c, d, e, f) * + graphicsObjects!.last.currentTransformationMatrix!; + return MatrixHelper( + currentTransformationMatrix!.m11, + currentTransformationMatrix!.m12, + currentTransformationMatrix!.m21, + currentTransformationMatrix!.m22, + currentTransformationMatrix!.offsetX, + currentTransformationMatrix!.offsetY, + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matched_item.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matched_item.dart index f45afd710..7388ed806 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matched_item.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matched_item.dart @@ -1,30 +1,30 @@ -import 'dart:ui'; - -/// Details of the searched text -class MatchedItem { - //Constructor - MatchedItem._(this.text, this._boundsCollection, this.pageIndex); - - //Fields - /// The searched text. - late String text; - - /// Rectangle bounds of the searched text. - late Rect bounds = _boundsCollection[0]; - - /// Page number of the searched text. - late int pageIndex; - - //Internal fields - /// Rectangle bounds collection of the searched text. - final List _boundsCollection; -} - -// ignore: avoid_classes_with_only_static_members -/// [MatchedItem] helper -class MatchedItemHelper { - /// internal method - static MatchedItem initialize(String text, List bounds, int pageIndex) { - return MatchedItem._(text, bounds, pageIndex); - } -} +import 'dart:ui'; + +/// Details of the searched text +class MatchedItem { + //Constructor + MatchedItem._(this.text, this._boundsCollection, this.pageIndex); + + //Fields + /// The searched text. + late String text; + + /// Rectangle bounds of the searched text. + late Rect bounds = _boundsCollection[0]; + + /// Page number of the searched text. + late int pageIndex; + + //Internal fields + /// Rectangle bounds collection of the searched text. + final List _boundsCollection; +} + +// ignore: avoid_classes_with_only_static_members +/// [MatchedItem] helper +class MatchedItemHelper { + /// internal method + static MatchedItem initialize(String text, List bounds, int pageIndex) { + return MatchedItem._(text, bounds, pageIndex); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matrix_helper.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matrix_helper.dart index 00a3816c1..540a1f2f3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matrix_helper.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/matrix_helper.dart @@ -1,233 +1,233 @@ -import 'dart:math'; -import 'dart:ui'; - -/// internal class -class MatrixHelper { - /// internal constructor - MatrixHelper( - this.m11, - this.m12, - this.m21, - this.m22, - this.offsetX, - this.offsetY, - ) { - type = MatrixTypes.unknown; - _checkMatrixType(); - } - - /// internal property - static MatrixHelper get identity => - MatrixHelper(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); - - //Fields - /// internal field - late double m11; - - /// internal field - late double m12; - - /// internal field - late double m21; - - /// internal field - late double m22; - - /// internal field - late double offsetX; - - /// internal field - late double offsetY; - - /// internal field - late MatrixTypes type; - - //Implementation - /// internal property - MatrixHelper operator *(MatrixHelper matrix) { - return MatrixHelper( - m11 * matrix.m11 + m12 * matrix.m21, - m11 * matrix.m12 + m12 * matrix.m22, - m21 * matrix.m11 + m22 * matrix.m21, - m21 * matrix.m12 + m22 * matrix.m22, - offsetX * matrix.m11 + offsetY * matrix.m21 + matrix.offsetX, - offsetX * matrix.m12 + offsetY * matrix.m22 + matrix.offsetY, - ); - } - - /// internal method - MatrixHelper translate(double offsetX, double offsetY) { - if (type == MatrixTypes.identity) { - setMatrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY, MatrixTypes.translation); - } else { - if (type == MatrixTypes.unknown) { - this.offsetX += offsetX; - this.offsetY += offsetY; - } else { - this.offsetX += offsetX; - this.offsetY += offsetY; - type = _getType( - _getTypeIndex(type) | _getTypeIndex(MatrixTypes.translation), - ); - } - } - return this; - } - - /// internal method - void setMatrix( - double m11, - double m12, - double m21, - double m22, - double offsetX, - double offsetY, - MatrixTypes type, - ) { - this.m11 = m11; - this.m12 = m12; - this.m21 = m21; - this.m22 = m22; - this.offsetX = offsetX; - this.offsetY = offsetY; - this.type = type; - } - - void _checkMatrixType() { - type = MatrixTypes.identity; - if (m21 != 0.0 || m12 != 0.0) { - type = MatrixTypes.unknown; - return; - } - if (m11 != 1.0 || m22 != 1.0) { - type = MatrixTypes.scaling; - } - if (offsetX != 0.0 || offsetY != 0.0) { - type = _getType( - _getTypeIndex(type) | _getTypeIndex(MatrixTypes.translation), - ); - } - if (_getTypeIndex(type) & 3 == _getTypeIndex(MatrixTypes.identity)) { - type = MatrixTypes.identity; - } - } - - MatrixTypes _getType(int typeIndex) { - if (typeIndex == 0) { - return MatrixTypes.identity; - } else if (typeIndex == 1) { - return MatrixTypes.translation; - } else if (typeIndex == 2) { - return MatrixTypes.scaling; - } else if (typeIndex == 3) { - return MatrixTypes.scalingAndTranslation; - } else if (typeIndex == 4) { - return MatrixTypes.unknown; - } else { - throw ArgumentError.value(typeIndex, 'typeIndex', 'Invalid Type'); - } - } - - int _getTypeIndex(MatrixTypes type) { - switch (type) { - case MatrixTypes.identity: - return 0; - case MatrixTypes.translation: - return 1; - case MatrixTypes.scaling: - return 2; - case MatrixTypes.scalingAndTranslation: - return 3; - case MatrixTypes.unknown: - return 4; - } - } - - /// internal method - MatrixHelper scale( - double scaleX, - double scaleY, - double centerX, - double centerY, - ) { - final MatrixHelper newMatrix = - MatrixHelper(scaleX, 0.0, 0.0, scaleY, centerX, centerY) * this; - setMatrix( - newMatrix.m11, - newMatrix.m12, - newMatrix.m21, - newMatrix.m22, - newMatrix.offsetX, - newMatrix.offsetY, - newMatrix.type, - ); - return this; - } - - /// internal method - MatrixHelper rotate(double angle, double centerX, double centerY) { - angle = 3.1415926535897931 * angle / 180.0; - final double num1 = sin(angle); - final double num2 = cos(angle); - MatrixHelper matrix = MatrixHelper( - num2, - num1, - -num1, - num2, - centerX * (1.0 - num2) + centerY * num1, - centerY * (1.0 - num2) - centerX * num1, - ); - matrix.type = MatrixTypes.unknown; - matrix *= this; - setMatrix( - matrix.m11, - matrix.m12, - matrix.m21, - matrix.m22, - matrix.offsetX, - matrix.offsetY, - matrix.type, - ); - return this; - } - - /// internal method - Offset transform(Offset point) { - return Offset( - point.dx * m11 + point.dy * m21 + offsetX, - point.dx * m12 + point.dy * m22 + offsetY, - ); - } - - /// internal method - MatrixHelper clone() { - final MatrixHelper result = MatrixHelper( - m11, - m12, - m21, - m22, - offsetX, - offsetY, - ); - result.type = type; - return result; - } -} - -/// internal enumerator -enum MatrixTypes { - /// internal enumerator - identity, - - /// internal enumerator - translation, - - /// internal enumerator - scaling, - - /// internal enumerator - scalingAndTranslation, - - /// internal enumerator - unknown, -} +import 'dart:math'; +import 'dart:ui'; + +/// internal class +class MatrixHelper { + /// internal constructor + MatrixHelper( + this.m11, + this.m12, + this.m21, + this.m22, + this.offsetX, + this.offsetY, + ) { + type = MatrixTypes.unknown; + _checkMatrixType(); + } + + /// internal property + static MatrixHelper get identity => + MatrixHelper(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + + //Fields + /// internal field + late double m11; + + /// internal field + late double m12; + + /// internal field + late double m21; + + /// internal field + late double m22; + + /// internal field + late double offsetX; + + /// internal field + late double offsetY; + + /// internal field + late MatrixTypes type; + + //Implementation + /// internal property + MatrixHelper operator *(MatrixHelper matrix) { + return MatrixHelper( + m11 * matrix.m11 + m12 * matrix.m21, + m11 * matrix.m12 + m12 * matrix.m22, + m21 * matrix.m11 + m22 * matrix.m21, + m21 * matrix.m12 + m22 * matrix.m22, + offsetX * matrix.m11 + offsetY * matrix.m21 + matrix.offsetX, + offsetX * matrix.m12 + offsetY * matrix.m22 + matrix.offsetY, + ); + } + + /// internal method + MatrixHelper translate(double offsetX, double offsetY) { + if (type == MatrixTypes.identity) { + setMatrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY, MatrixTypes.translation); + } else { + if (type == MatrixTypes.unknown) { + this.offsetX += offsetX; + this.offsetY += offsetY; + } else { + this.offsetX += offsetX; + this.offsetY += offsetY; + type = _getType( + _getTypeIndex(type) | _getTypeIndex(MatrixTypes.translation), + ); + } + } + return this; + } + + /// internal method + void setMatrix( + double m11, + double m12, + double m21, + double m22, + double offsetX, + double offsetY, + MatrixTypes type, + ) { + this.m11 = m11; + this.m12 = m12; + this.m21 = m21; + this.m22 = m22; + this.offsetX = offsetX; + this.offsetY = offsetY; + this.type = type; + } + + void _checkMatrixType() { + type = MatrixTypes.identity; + if (m21 != 0.0 || m12 != 0.0) { + type = MatrixTypes.unknown; + return; + } + if (m11 != 1.0 || m22 != 1.0) { + type = MatrixTypes.scaling; + } + if (offsetX != 0.0 || offsetY != 0.0) { + type = _getType( + _getTypeIndex(type) | _getTypeIndex(MatrixTypes.translation), + ); + } + if (_getTypeIndex(type) & 3 == _getTypeIndex(MatrixTypes.identity)) { + type = MatrixTypes.identity; + } + } + + MatrixTypes _getType(int typeIndex) { + if (typeIndex == 0) { + return MatrixTypes.identity; + } else if (typeIndex == 1) { + return MatrixTypes.translation; + } else if (typeIndex == 2) { + return MatrixTypes.scaling; + } else if (typeIndex == 3) { + return MatrixTypes.scalingAndTranslation; + } else if (typeIndex == 4) { + return MatrixTypes.unknown; + } else { + throw ArgumentError.value(typeIndex, 'typeIndex', 'Invalid Type'); + } + } + + int _getTypeIndex(MatrixTypes type) { + switch (type) { + case MatrixTypes.identity: + return 0; + case MatrixTypes.translation: + return 1; + case MatrixTypes.scaling: + return 2; + case MatrixTypes.scalingAndTranslation: + return 3; + case MatrixTypes.unknown: + return 4; + } + } + + /// internal method + MatrixHelper scale( + double scaleX, + double scaleY, + double centerX, + double centerY, + ) { + final MatrixHelper newMatrix = + MatrixHelper(scaleX, 0.0, 0.0, scaleY, centerX, centerY) * this; + setMatrix( + newMatrix.m11, + newMatrix.m12, + newMatrix.m21, + newMatrix.m22, + newMatrix.offsetX, + newMatrix.offsetY, + newMatrix.type, + ); + return this; + } + + /// internal method + MatrixHelper rotate(double angle, double centerX, double centerY) { + angle = 3.1415926535897931 * angle / 180.0; + final double num1 = sin(angle); + final double num2 = cos(angle); + MatrixHelper matrix = MatrixHelper( + num2, + num1, + -num1, + num2, + centerX * (1.0 - num2) + centerY * num1, + centerY * (1.0 - num2) - centerX * num1, + ); + matrix.type = MatrixTypes.unknown; + matrix *= this; + setMatrix( + matrix.m11, + matrix.m12, + matrix.m21, + matrix.m22, + matrix.offsetX, + matrix.offsetY, + matrix.type, + ); + return this; + } + + /// internal method + Offset transform(Offset point) { + return Offset( + point.dx * m11 + point.dy * m21 + offsetX, + point.dx * m12 + point.dy * m22 + offsetY, + ); + } + + /// internal method + MatrixHelper clone() { + final MatrixHelper result = MatrixHelper( + m11, + m12, + m21, + m22, + offsetX, + offsetY, + ); + result.type = type; + return result; + } +} + +/// internal enumerator +enum MatrixTypes { + /// internal enumerator + identity, + + /// internal enumerator + translation, + + /// internal enumerator + scaling, + + /// internal enumerator + scalingAndTranslation, + + /// internal enumerator + unknown, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/page_resource_loader.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/page_resource_loader.dart index fdb118a08..838539888 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/page_resource_loader.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/page_resource_loader.dart @@ -1,327 +1,327 @@ -import '../../../interfaces/pdf_interface.dart'; -import '../../graphics/pdf_resources.dart'; -import '../../io/cross_table.dart'; -import '../../io/pdf_constants.dart'; -import '../../io/pdf_cross_table.dart'; -import '../../pages/enum.dart'; -import '../../pages/pdf_page.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_stream.dart'; -import 'font_structure.dart'; -import 'xobject_element.dart'; - -/// internal class -class PageResourceLoader { - /// internal constructor - PageResourceLoader(); - - //Implementations - /// internal method - PdfPageResources getPageResources(PdfPage page) { - PdfPageResources pageResources = PdfPageResources(); - double resourceNumber = 0; - PdfDictionary? resources = PdfPageHelper.getHelper(page).getResources(); - pageResources = updatePageResources( - pageResources, - getFontResources(resources, page), - ); - pageResources = updatePageResources( - pageResources, - getFormResources(resources, PdfPageHelper.getHelper(page).crossTable), - ); - while (resources != null && - resources.containsKey(PdfDictionaryProperties.xObject)) { - PdfDictionary? tempResources = resources; - PdfDictionary? xobjects; - if (resources[PdfDictionaryProperties.xObject] is PdfReferenceHolder) { - xobjects = - (resources[PdfDictionaryProperties.xObject]! as PdfReferenceHolder) - .object - as PdfDictionary?; - } else { - xobjects = resources[PdfDictionaryProperties.xObject] as PdfDictionary?; - } - resources = - xobjects![PdfDictionaryProperties.resources] as PdfDictionary?; - final PdfCrossTable? crosstable = - PdfPageHelper.getHelper(page).crossTable; - for (final PdfName? objKey in xobjects.items!.keys) { - final IPdfPrimitive? objValue = xobjects[objKey]; - PdfDictionary? xobjectDictionary; - PdfReferenceHolder? referenceHolder; - if (objValue is PdfReferenceHolder && - objValue.object is PdfDictionary) { - referenceHolder = objValue; - xobjectDictionary = referenceHolder.object as PdfDictionary?; - } else if (objValue is PdfDictionary) { - xobjectDictionary = objValue; - } - if (xobjectDictionary != null && - xobjectDictionary.containsKey(PdfDictionaryProperties.resources)) { - if (xobjectDictionary[PdfDictionaryProperties.resources] - is PdfReferenceHolder) { - final PdfReferenceHolder resourceReference = - xobjectDictionary[PdfDictionaryProperties.resources]! - as PdfReferenceHolder; - if (resourceNumber != resourceReference.reference!.objNum) { - resources = resourceReference.object as PdfDictionary?; - resourceNumber = resourceReference.reference!.objNum!.toDouble(); - } else { - continue; - } - } else { - resources = - xobjectDictionary[PdfDictionaryProperties.resources] - as PdfDictionary?; - } - xobjectDictionary = null; - if (resources == tempResources) { - resources = null; - tempResources = null; - } - pageResources = updatePageResources( - pageResources, - getFontResources(resources, page), - ); - } else { - if (objKey != null && - !pageResources.resources.containsKey(objKey.name) && - crosstable != null && - referenceHolder != null && - referenceHolder.reference != null && - referenceHolder.reference!.objNum != null && - referenceHolder.reference!.objNum! > 0) { - crosstable.items!.remove(referenceHolder.reference!.objNum!); - crosstable.objNumbers.remove(referenceHolder.reference); - if (crosstable.crossTable != null) { - final ObjectInformation? oi = - crosstable.crossTable![referenceHolder.reference!.objNum!]; - oi!.obj = null; - } - } - } - } - } - // m_commonMatrix = commonMatrix; - if (page.rotation == PdfPageRotateAngle.rotateAngle90) { - pageResources.resources[PdfDictionaryProperties.rotate] = 90.toDouble(); - } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { - pageResources.resources[PdfDictionaryProperties.rotate] = 180.toDouble(); - } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { - pageResources.resources[PdfDictionaryProperties.rotate] = 270.toDouble(); - } - return pageResources; - } - - /// internal method - Map getFormResources( - PdfDictionary? resourceDictionary, [ - PdfCrossTable? crosstable, - ]) { - final Map pageResources = {}; - if (resourceDictionary != null && - resourceDictionary.containsKey(PdfDictionaryProperties.xObject)) { - final IPdfPrimitive? primitive = - resourceDictionary[PdfDictionaryProperties.xObject]; - PdfDictionary? xObjects; - if (primitive is PdfReferenceHolder) { - final IPdfPrimitive? holder = primitive.object; - if (holder != null && holder is PdfDictionary) { - xObjects = holder; - } - } else if (primitive is PdfDictionary) { - xObjects = primitive; - } - if (xObjects != null) { - xObjects.items!.forEach((PdfName? key, IPdfPrimitive? value) { - PdfDictionary? xObjectDictionary; - PdfReferenceHolder? referenceHolder; - if (value is PdfReferenceHolder && value.object is PdfDictionary) { - referenceHolder = value; - xObjectDictionary = referenceHolder.object as PdfDictionary?; - } else if (value is PdfDictionary) { - xObjectDictionary = value; - } - if (xObjectDictionary != null && - xObjectDictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? subType = - xObjectDictionary[PdfDictionaryProperties.subtype]; - if (subType is PdfName && - (subType.name == PdfDictionaryProperties.form || - (subType.name != PdfDictionaryProperties.image && - !pageResources.containsKey(key!.name)))) { - pageResources[key!.name] = XObjectElement( - xObjectDictionary, - key.name, - ); - } else if (xObjectDictionary is PdfStream) { - if (crosstable != null && - referenceHolder != null && - referenceHolder.reference != null && - referenceHolder.reference!.objNum != null && - referenceHolder.reference!.objNum! > 0) { - crosstable.items!.remove(referenceHolder.reference!.objNum!); - crosstable.objNumbers.remove(referenceHolder.reference); - if (crosstable.crossTable != null) { - final ObjectInformation? oi = - crosstable.crossTable![referenceHolder - .reference! - .objNum!]; - oi!.obj = null; - } - } - } - } - xObjectDictionary = null; - }); - } - xObjects = null; - } - return pageResources; - } - - // Collects all the fonts in the page in a dictionary. - // Returns dictionary containing font name and the font. - /// internal method - Map getFontResources( - PdfDictionary? resourceDictionary, [ - PdfPage? page, - ]) { - final Map pageResources = {}; - if (resourceDictionary != null) { - IPdfPrimitive? fonts = resourceDictionary[PdfDictionaryProperties.font]; - if (fonts != null) { - PdfDictionary? fontsDictionary; - if (fonts is PdfReferenceHolder) { - fontsDictionary = fonts.object as PdfDictionary?; - } else { - fontsDictionary = fonts as PdfDictionary; - } - - if (fontsDictionary != null) { - fontsDictionary.items!.forEach((PdfName? k, IPdfPrimitive? v) { - if (v is PdfReferenceHolder) { - if (v.reference != null) { - pageResources[k!.name] = FontStructure( - v.object, - v.reference.toString(), - ); - } else { - pageResources[k!.name] = FontStructure(v.object); - } - } else { - if (v is PdfDictionary) { - pageResources[k!.name] = FontStructure(v); - } else { - pageResources[k!.name] = FontStructure( - v, - (v! as PdfReferenceHolder).reference.toString(), - ); - } - } - }); - } - } - if (page != null) { - final IPdfPrimitive? parentPage = - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .parent]; - if (parentPage != null) { - final IPdfPrimitive? parentRef = - (parentPage as PdfReferenceHolder).object; - final PdfResources parentResources = PdfResources( - parentRef as PdfDictionary?, - ); - fonts = parentResources[PdfDictionaryProperties.font]; - if (fonts != null && fonts is PdfDictionary) { - final PdfDictionary fontsDictionary = fonts; - fontsDictionary.items!.forEach((PdfName? k, IPdfPrimitive? v) { - if (v is PdfDictionary) { - pageResources[k!.name] = (v as PdfReferenceHolder).object; - } - pageResources[k!.name] = FontStructure( - v, - (v! as PdfReferenceHolder).reference.toString(), - ); - }); - } - } - } - } - return pageResources; - } - - /// Updates the resources in the page - PdfPageResources updatePageResources( - PdfPageResources pageResources, - Map objects, - ) { - objects.forEach((String? k, Object? v) { - pageResources.add(k, v); - }); - return pageResources; - } -} - -/// internal class -class PdfPageResources { - /// Initializes the new instance of the class [PdfPageResources]. - PdfPageResources() { - resources = {}; - } - - //Fields - /// internal field - late Map resources; - - /// internal field - final Map fontCollection = {}; - - /// internal property - dynamic operator [](String key) => _returnValue(key); - - dynamic _returnValue(String key) { - if (resources.containsKey(key)) { - return resources[key]; - } else { - return null; - } - } - - /// Returns true if the FontCollection has same font face. - bool isSameFont() { - int i = 0; - fontCollection.forEach((String? k, FontStructure v) { - fontCollection.forEach((String? k1, FontStructure v1) { - if (v.fontName != v1.fontName) { - i = 1; - } - }); - }); - if (i == 0) { - return true; - } else { - return false; - } - } - - /// Adds the resource with the specified name. - void add(String? resourceName, Object? resource) { - if (resourceName == 'ProcSet') { - return; - } - if (!resources.containsKey(resourceName)) { - resources[resourceName] = resource; - if (resource is FontStructure) { - fontCollection[resourceName] = resource; - } - } - } - - /// internal method - bool containsKey(String? key) { - return resources.containsKey(key); - } -} +import '../../../interfaces/pdf_interface.dart'; +import '../../graphics/pdf_resources.dart'; +import '../../io/cross_table.dart'; +import '../../io/pdf_constants.dart'; +import '../../io/pdf_cross_table.dart'; +import '../../pages/enum.dart'; +import '../../pages/pdf_page.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_stream.dart'; +import 'font_structure.dart'; +import 'xobject_element.dart'; + +/// internal class +class PageResourceLoader { + /// internal constructor + PageResourceLoader(); + + //Implementations + /// internal method + PdfPageResources getPageResources(PdfPage page) { + PdfPageResources pageResources = PdfPageResources(); + double resourceNumber = 0; + PdfDictionary? resources = PdfPageHelper.getHelper(page).getResources(); + pageResources = updatePageResources( + pageResources, + getFontResources(resources, page), + ); + pageResources = updatePageResources( + pageResources, + getFormResources(resources, PdfPageHelper.getHelper(page).crossTable), + ); + while (resources != null && + resources.containsKey(PdfDictionaryProperties.xObject)) { + PdfDictionary? tempResources = resources; + PdfDictionary? xobjects; + if (resources[PdfDictionaryProperties.xObject] is PdfReferenceHolder) { + xobjects = + (resources[PdfDictionaryProperties.xObject]! as PdfReferenceHolder) + .object + as PdfDictionary?; + } else { + xobjects = resources[PdfDictionaryProperties.xObject] as PdfDictionary?; + } + resources = + xobjects![PdfDictionaryProperties.resources] as PdfDictionary?; + final PdfCrossTable? crosstable = + PdfPageHelper.getHelper(page).crossTable; + for (final PdfName? objKey in xobjects.items!.keys) { + final IPdfPrimitive? objValue = xobjects[objKey]; + PdfDictionary? xobjectDictionary; + PdfReferenceHolder? referenceHolder; + if (objValue is PdfReferenceHolder && + objValue.object is PdfDictionary) { + referenceHolder = objValue; + xobjectDictionary = referenceHolder.object as PdfDictionary?; + } else if (objValue is PdfDictionary) { + xobjectDictionary = objValue; + } + if (xobjectDictionary != null && + xobjectDictionary.containsKey(PdfDictionaryProperties.resources)) { + if (xobjectDictionary[PdfDictionaryProperties.resources] + is PdfReferenceHolder) { + final PdfReferenceHolder resourceReference = + xobjectDictionary[PdfDictionaryProperties.resources]! + as PdfReferenceHolder; + if (resourceNumber != resourceReference.reference!.objNum) { + resources = resourceReference.object as PdfDictionary?; + resourceNumber = resourceReference.reference!.objNum!.toDouble(); + } else { + continue; + } + } else { + resources = + xobjectDictionary[PdfDictionaryProperties.resources] + as PdfDictionary?; + } + xobjectDictionary = null; + if (resources == tempResources) { + resources = null; + tempResources = null; + } + pageResources = updatePageResources( + pageResources, + getFontResources(resources, page), + ); + } else { + if (objKey != null && + !pageResources.resources.containsKey(objKey.name) && + crosstable != null && + referenceHolder != null && + referenceHolder.reference != null && + referenceHolder.reference!.objNum != null && + referenceHolder.reference!.objNum! > 0) { + crosstable.items!.remove(referenceHolder.reference!.objNum!); + crosstable.objNumbers.remove(referenceHolder.reference); + if (crosstable.crossTable != null) { + final ObjectInformation? oi = + crosstable.crossTable![referenceHolder.reference!.objNum!]; + oi!.obj = null; + } + } + } + } + } + // m_commonMatrix = commonMatrix; + if (page.rotation == PdfPageRotateAngle.rotateAngle90) { + pageResources.resources[PdfDictionaryProperties.rotate] = 90.toDouble(); + } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { + pageResources.resources[PdfDictionaryProperties.rotate] = 180.toDouble(); + } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { + pageResources.resources[PdfDictionaryProperties.rotate] = 270.toDouble(); + } + return pageResources; + } + + /// internal method + Map getFormResources( + PdfDictionary? resourceDictionary, [ + PdfCrossTable? crosstable, + ]) { + final Map pageResources = {}; + if (resourceDictionary != null && + resourceDictionary.containsKey(PdfDictionaryProperties.xObject)) { + final IPdfPrimitive? primitive = + resourceDictionary[PdfDictionaryProperties.xObject]; + PdfDictionary? xObjects; + if (primitive is PdfReferenceHolder) { + final IPdfPrimitive? holder = primitive.object; + if (holder != null && holder is PdfDictionary) { + xObjects = holder; + } + } else if (primitive is PdfDictionary) { + xObjects = primitive; + } + if (xObjects != null) { + xObjects.items!.forEach((PdfName? key, IPdfPrimitive? value) { + PdfDictionary? xObjectDictionary; + PdfReferenceHolder? referenceHolder; + if (value is PdfReferenceHolder && value.object is PdfDictionary) { + referenceHolder = value; + xObjectDictionary = referenceHolder.object as PdfDictionary?; + } else if (value is PdfDictionary) { + xObjectDictionary = value; + } + if (xObjectDictionary != null && + xObjectDictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? subType = + xObjectDictionary[PdfDictionaryProperties.subtype]; + if (subType is PdfName && + (subType.name == PdfDictionaryProperties.form || + (subType.name != PdfDictionaryProperties.image && + !pageResources.containsKey(key!.name)))) { + pageResources[key!.name] = XObjectElement( + xObjectDictionary, + key.name, + ); + } else if (xObjectDictionary is PdfStream) { + if (crosstable != null && + referenceHolder != null && + referenceHolder.reference != null && + referenceHolder.reference!.objNum != null && + referenceHolder.reference!.objNum! > 0) { + crosstable.items!.remove(referenceHolder.reference!.objNum!); + crosstable.objNumbers.remove(referenceHolder.reference); + if (crosstable.crossTable != null) { + final ObjectInformation? oi = + crosstable.crossTable![referenceHolder + .reference! + .objNum!]; + oi!.obj = null; + } + } + } + } + xObjectDictionary = null; + }); + } + xObjects = null; + } + return pageResources; + } + + // Collects all the fonts in the page in a dictionary. + // Returns dictionary containing font name and the font. + /// internal method + Map getFontResources( + PdfDictionary? resourceDictionary, [ + PdfPage? page, + ]) { + final Map pageResources = {}; + if (resourceDictionary != null) { + IPdfPrimitive? fonts = resourceDictionary[PdfDictionaryProperties.font]; + if (fonts != null) { + PdfDictionary? fontsDictionary; + if (fonts is PdfReferenceHolder) { + fontsDictionary = fonts.object as PdfDictionary?; + } else { + fontsDictionary = fonts as PdfDictionary; + } + + if (fontsDictionary != null) { + fontsDictionary.items!.forEach((PdfName? k, IPdfPrimitive? v) { + if (v is PdfReferenceHolder) { + if (v.reference != null) { + pageResources[k!.name] = FontStructure( + v.object, + v.reference.toString(), + ); + } else { + pageResources[k!.name] = FontStructure(v.object); + } + } else { + if (v is PdfDictionary) { + pageResources[k!.name] = FontStructure(v); + } else { + pageResources[k!.name] = FontStructure( + v, + (v! as PdfReferenceHolder).reference.toString(), + ); + } + } + }); + } + } + if (page != null) { + final IPdfPrimitive? parentPage = + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .parent]; + if (parentPage != null) { + final IPdfPrimitive? parentRef = + (parentPage as PdfReferenceHolder).object; + final PdfResources parentResources = PdfResources( + parentRef as PdfDictionary?, + ); + fonts = parentResources[PdfDictionaryProperties.font]; + if (fonts != null && fonts is PdfDictionary) { + final PdfDictionary fontsDictionary = fonts; + fontsDictionary.items!.forEach((PdfName? k, IPdfPrimitive? v) { + if (v is PdfDictionary) { + pageResources[k!.name] = (v as PdfReferenceHolder).object; + } + pageResources[k!.name] = FontStructure( + v, + (v! as PdfReferenceHolder).reference.toString(), + ); + }); + } + } + } + } + return pageResources; + } + + /// Updates the resources in the page + PdfPageResources updatePageResources( + PdfPageResources pageResources, + Map objects, + ) { + objects.forEach((String? k, Object? v) { + pageResources.add(k, v); + }); + return pageResources; + } +} + +/// internal class +class PdfPageResources { + /// Initializes the new instance of the class [PdfPageResources]. + PdfPageResources() { + resources = {}; + } + + //Fields + /// internal field + late Map resources; + + /// internal field + final Map fontCollection = {}; + + /// internal property + dynamic operator [](String key) => _returnValue(key); + + dynamic _returnValue(String key) { + if (resources.containsKey(key)) { + return resources[key]; + } else { + return null; + } + } + + /// Returns true if the FontCollection has same font face. + bool isSameFont() { + int i = 0; + fontCollection.forEach((String? k, FontStructure v) { + fontCollection.forEach((String? k1, FontStructure v1) { + if (v.fontName != v1.fontName) { + i = 1; + } + }); + }); + if (i == 0) { + return true; + } else { + return false; + } + } + + /// Adds the resource with the specified name. + void add(String? resourceName, Object? resource) { + if (resourceName == 'ProcSet') { + return; + } + if (!resources.containsKey(resourceName)) { + resources[resourceName] = resource; + if (resource is FontStructure) { + fontCollection[resourceName] = resource; + } + } + } + + /// internal method + bool containsKey(String? key) { + return resources.containsKey(key); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart index c2b6448b8..822f1b68f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_lexer.dart @@ -1,459 +1,462 @@ -/// internal class -class ContentLexer { - // Constructor - /// internal constructor - ContentLexer(List? contentStream) { - _contentStream = contentStream; - operatorParams = StringBuffer(); - } - - // fields - List? _contentStream; - String _currentChar = '0'; - String _nextChar = '0'; - int _charPointer = 0; - bool _isArtifactContentEnds = false; - bool _isContentEnded = false; - String? _tempContent; - - /// internal field - bool isContainsArtifacts = false; - - /// internal field - StringBuffer? operatorParams; - - // Implementation - /// internal method - PdfToken getNextToken() { - _resetToken(); - final String ch = String.fromCharCode(int.parse(_moveToNextChar())); - switch (ch) { - case '%': - return _getComment(); - - case '/': - return _getName(); - - case '+': - case '-': - return _getNumber(); - - case '[': - case '(': - return _getLiteralString(); - - case '<': - return _getHexadecimalString(); - - case '.': - return _getNumber(); - - case '"': - case "'": - return _getOperator(); - } - if (isDigit(ch)) { - return _getNumber(); - } - - if (isLetter(ch)) { - return _getOperator(); - } - - if (ch == '65535') { - return PdfToken.eof; - } - - return PdfToken.nullType; - } - - /// internal method - bool isDigit(String s, [int idx = 0]) => (s.codeUnitAt(idx) ^ 0x30) <= 9; - - /// internal method - bool isLetter(String s) { - if (s.contains(RegExp(r'[A-Z]')) || s.contains(RegExp(r'[a-z]'))) { - return true; - } else { - return false; - } - } - - void _resetToken() { - operatorParams!.clear(); - } - - String _moveToNextChar() { - while (_currentChar != '65535') { - switch (_currentChar) { - case '0': - case '9': - case '10': - case '12': - case '13': - case '8': - case '32': - case '20': - getNextChar(); // line feeds and spaces - break; - - default: - return _currentChar; - } - } - return _currentChar; - } - - /// internal method - String getNextChar([bool value = false]) { - if (value) { - return _nextChar; - } - if (_contentStream!.length <= _charPointer) { - if (_nextChar == '81' || (_currentChar == '68' && _nextChar == '111')) { - _currentChar = _nextChar; - _nextChar = '65535'; - return _currentChar; - } - _currentChar = '65535'; - _nextChar = '65535'; - } else { - _currentChar = _nextChar; - _nextChar = _contentStream![_charPointer++].toString(); - if (_currentChar == '13') { - if (_nextChar == '10') { - _currentChar = _nextChar; - if (_contentStream!.length <= _charPointer) { - _nextChar = '65535'; - } else { - _nextChar = _contentStream![_charPointer++].toString(); - } - } else { - _currentChar = '10'; - } - } - } - return _currentChar; - } - - PdfToken _getComment() { - _resetToken(); - String ch; - while ((ch = _consumeValue()) != '10' && ch != '65535') {} - return PdfToken.comment; - } - - PdfToken _getName() { - _resetToken(); - while (true) { - final String ch = _consumeValue(); - final String data = String.fromCharCode(int.parse(ch)); - if (_isWhiteSpace(ch) || _isDelimiter(data)) { - break; - } - } - return PdfToken.name; - } - - PdfToken _getNumber() { - String ch = _currentChar; - if (ch == '43' || ch == '45') { - operatorParams!.write(String.fromCharCode(int.parse(_currentChar))); - ch = getNextChar(); - } - while (true) { - if (isDigit(String.fromCharCode(int.parse(ch)))) { - operatorParams!.write(String.fromCharCode(int.parse(_currentChar))); - } else if (ch == '46') { - operatorParams!.write(String.fromCharCode(int.parse(_currentChar))); - } else { - break; - } - ch = getNextChar(); - } - return PdfToken.integer; - } - - String _consumeValue() { - _tempContent = String.fromCharCode(int.parse(_currentChar)); - operatorParams!.write(_tempContent); - if (isContainsArtifacts && - operatorParams.toString().contains('/Contents') && - !_isContentEnded) { - _isArtifactContentEnds = true; - if (String.fromCharCode(int.parse(_nextChar)) == ')' && - String.fromCharCode(int.parse(_currentChar)) != r'\') { - _isArtifactContentEnds = false; - _isContentEnded = true; - } - } - return getNextChar(); - } - - PdfToken _getLiteralString() { - String beginChar; - _resetToken(); - - if (String.fromCharCode(int.parse(_currentChar)) == '(') { - beginChar = _currentChar; - } else { - beginChar = _currentChar; - } - String literal; - String ch = _consumeValue(); - while (true) { - if (String.fromCharCode(int.parse(beginChar)) == '(') { - literal = _getLiterals(ch); - operatorParams!.write(literal); - ch = String.fromCharCode(int.parse(getNextChar())); - break; - } else { - if (String.fromCharCode(int.parse(ch)) == '(') { - ch = _consumeValue(); - literal = _getLiterals(ch); - operatorParams!.write(literal); - ch = getNextChar(); - continue; - } else if (String.fromCharCode(int.parse(ch)) == ']') { - ch = _consumeValue(); - break; - } - ch = _consumeValue(); - } - } - return PdfToken.string; - } - - String _getLiterals(String ch) { - int parenthesesCount = 0; - String literal = ''; - while (true) { - ch = String.fromCharCode(int.parse(ch)); - if (ch == r'\') { - literal += ch; - ch = String.fromCharCode(int.parse(getNextChar())); - literal += ch; - ch = getNextChar(); - continue; - } - - if (ch == '(') { - parenthesesCount++; - literal += ch; - ch = getNextChar(); - continue; - } - - if (ch == ')' && parenthesesCount != 0) { - literal += ch; - ch = getNextChar(); - parenthesesCount--; - continue; - } - - if (ch == ')' && parenthesesCount == 0) { - literal += ch; - return literal; - } - literal += ch; - ch = getNextChar(); - } - } - - PdfToken _getHexadecimalString() { - int parentLevel = 0; - bool skipParentLevel = false; - String ch = String.fromCharCode(int.parse(_consumeValue())); - while (true) { - if (ch == '<') { - if (!skipParentLevel) { - parentLevel++; - } - ch = String.fromCharCode(int.parse(_consumeValue())); - } else if (ch == '>' && !_isArtifactContentEnds) { - if (parentLevel == 0) { - _consumeValue(); - break; - } else if (parentLevel == 1) { - ch = String.fromCharCode(int.parse(_consumeValue())); - if (ch == '>') { - parentLevel--; - } - if (parentLevel == 1 && - (ch == ' ' || (isContainsArtifacts && ch == 'B'))) { - break; - } - } else { - if (ch == '>') { - parentLevel--; - } - ch = String.fromCharCode(int.parse(_consumeValue())); - } - } else if (operatorParams != null && - operatorParams.toString().contains('ActualText') && - ch == '(') { - skipParentLevel = true; - ch = String.fromCharCode(int.parse(_consumeValue())); - } else if (operatorParams != null && - operatorParams.toString().contains('ActualText') && - ch == ')') { - skipParentLevel = false; - ch = String.fromCharCode(int.parse(_consumeValue())); - } else { - ch = String.fromCharCode(int.parse(_consumeValue())); - } - } - _isContentEnded = false; - isContainsArtifacts = false; - return PdfToken.hexString; - } - - PdfToken _getOperator() { - _resetToken(); - String ch = String.fromCharCode(int.parse(_currentChar)); - - while (_isOperator(ch)) { - ch = String.fromCharCode(int.parse(_consumeValue())); - } - return PdfToken.operators; - } - - /// internal method - String getNextInlineChar() { - if (_contentStream!.length <= _charPointer) { - _currentChar = '65535'; - _nextChar = '65535'; - } else { - _currentChar = _nextChar; - _nextChar = _contentStream![_charPointer++].toString(); - if (_currentChar == '13') { - if (_nextChar == '10') { - _currentChar = '13'; - } else { - _currentChar = '10'; - } - } - } - return _currentChar; - } - - /// internal method - String getNextCharforInlineStream() { - if (_contentStream!.length <= _charPointer) { - _currentChar = '65535'; - _nextChar = '65535'; - } else { - _currentChar = _nextChar; - _nextChar = _contentStream![_charPointer++].toString(); - if (_currentChar == '13') { - if (_nextChar == '10') { - _currentChar = _nextChar; - if (_contentStream!.length <= _charPointer) { - _nextChar = '65535'; - } else { - _nextChar = _contentStream![_charPointer++].toString(); - } - } - } - } - return _currentChar; - } - - /// internal method - void resetContentPointer(int count) { - _charPointer = _charPointer - count; - } - - bool _isOperator(String ch) { - if (isLetter(ch)) { - return true; - } - switch (ch) { - case '*': - case "'": - case '"': - case '1': - case '0': - return true; - } - return false; - } - - bool _isWhiteSpace(String ch) { - switch (ch) { - case '0': - case '32': - case '9': - case '10': - case '12': - case '13': - case '20': - return true; - } - return false; - } - - bool _isDelimiter(String ch) { - switch (ch) { - case '(': - case ')': - case '<': - case '>': - case '[': - case ']': - case '/': - case '%': - return true; - } - return false; - } - - /// internal method - void dispose() { - if (_contentStream != null) { - _contentStream = null; - } - } -} - -/// internal enumerator -enum PdfToken { - /// internal enumerator - nullType, - - /// internal enumerator - comment, - - /// internal enumerator - integer, - - /// internal enumerator - real, - - /// internal enumerator - string, - - /// internal enumerator - hexString, - - /// internal enumerator - unicodeString, - - /// internal enumerator - unicodeHexString, - - /// internal enumerator - name, - - /// internal enumerator - operators, - - /// internal enumerator - beginArray, - - /// internal enumerator - endArray, - - /// internal enumerator - eof, -} +/// internal class +class ContentLexer { + // Constructor + /// internal constructor + ContentLexer(List? contentStream) { + _contentStream = contentStream; + operatorParams = StringBuffer(); + } + + // fields + List? _contentStream; + String _currentChar = '0'; + String _nextChar = '0'; + int _charPointer = 0; + bool _isArtifactContentEnds = false; + bool _isContentEnded = false; + String? _tempContent; + + /// internal field + bool isContainsArtifacts = false; + + /// internal field + StringBuffer? operatorParams; + + // Implementation + /// internal method + PdfToken getNextToken() { + _resetToken(); + final String ch = String.fromCharCode(int.parse(_moveToNextChar())); + switch (ch) { + case '%': + return _getComment(); + + case '/': + return _getName(); + + case '+': + case '-': + return _getNumber(); + + case '[': + case '(': + return _getLiteralString(); + + case '<': + return _getHexadecimalString(); + + case '.': + return _getNumber(); + + case '"': + case "'": + return _getOperator(); + } + if (isDigit(ch)) { + return _getNumber(); + } + + if (isLetter(ch)) { + return _getOperator(); + } + + if (ch == '65535') { + return PdfToken.eof; + } + + return PdfToken.nullType; + } + + /// internal method + bool isDigit(String s, [int idx = 0]) => (s.codeUnitAt(idx) ^ 0x30) <= 9; + + /// internal method + bool isLetter(String s) { + if (s.contains(RegExp(r'[A-Z]')) || s.contains(RegExp(r'[a-z]'))) { + return true; + } else { + return false; + } + } + + void _resetToken() { + operatorParams!.clear(); + } + + String _moveToNextChar() { + while (_currentChar != '65535') { + switch (_currentChar) { + case '0': + case '9': + case '10': + case '12': + case '13': + case '8': + case '32': + case '20': + getNextChar(); // line feeds and spaces + break; + + default: + return _currentChar; + } + } + return _currentChar; + } + + /// internal method + String getNextChar([bool value = false]) { + if (value) { + return _nextChar; + } + if (_contentStream!.length <= _charPointer) { + if (_nextChar == '81' || (_currentChar == '68' && _nextChar == '111')) { + _currentChar = _nextChar; + _nextChar = '65535'; + return _currentChar; + } + _currentChar = '65535'; + _nextChar = '65535'; + } else { + _currentChar = _nextChar; + _nextChar = _contentStream![_charPointer++].toString(); + if (_currentChar == '13') { + if (_nextChar == '10') { + _currentChar = _nextChar; + if (_contentStream!.length <= _charPointer) { + _nextChar = '65535'; + } else { + _nextChar = _contentStream![_charPointer++].toString(); + } + } else { + _currentChar = '10'; + } + } + } + return _currentChar; + } + + PdfToken _getComment() { + _resetToken(); + String ch; + while ((ch = _consumeValue()) != '10' && ch != '65535') {} + return PdfToken.comment; + } + + PdfToken _getName() { + _resetToken(); + while (true) { + final String ch = _consumeValue(); + final String data = String.fromCharCode(int.parse(ch)); + if (_isWhiteSpace(ch) || _isDelimiter(data)) { + break; + } + } + return PdfToken.name; + } + + PdfToken _getNumber() { + String ch = _currentChar; + if (ch == '43' || ch == '45') { + operatorParams!.write(String.fromCharCode(int.parse(_currentChar))); + ch = getNextChar(); + } + while (true) { + if (isDigit(String.fromCharCode(int.parse(ch)))) { + operatorParams!.write(String.fromCharCode(int.parse(_currentChar))); + } else if (ch == '46') { + operatorParams!.write(String.fromCharCode(int.parse(_currentChar))); + } else { + break; + } + ch = getNextChar(); + } + return PdfToken.integer; + } + + String _consumeValue() { + _tempContent = String.fromCharCode(int.parse(_currentChar)); + operatorParams!.write(_tempContent); + if (isContainsArtifacts && + operatorParams.toString().contains('/Contents') && + !_isContentEnded) { + _isArtifactContentEnds = true; + if (String.fromCharCode(int.parse(_nextChar)) == ')' && + String.fromCharCode(int.parse(_currentChar)) != r'\') { + _isArtifactContentEnds = false; + _isContentEnded = true; + } + } + return getNextChar(); + } + + PdfToken _getLiteralString() { + String beginChar; + _resetToken(); + + if (String.fromCharCode(int.parse(_currentChar)) == '(') { + beginChar = _currentChar; + } else { + beginChar = _currentChar; + } + String literal; + String ch = _consumeValue(); + while (true) { + if (String.fromCharCode(int.parse(beginChar)) == '(') { + literal = _getLiterals(ch); + operatorParams!.write(literal); + ch = String.fromCharCode(int.parse(getNextChar())); + break; + } else { + if (String.fromCharCode(int.parse(ch)) == '(') { + ch = _consumeValue(); + literal = _getLiterals(ch); + operatorParams!.write(literal); + ch = getNextChar(); + continue; + } else if (String.fromCharCode(int.parse(ch)) == ']') { + ch = _consumeValue(); + break; + } + ch = _consumeValue(); + } + } + return PdfToken.string; + } + + String _getLiterals(String ch) { + int parenthesesCount = 0; + String literal = ''; + while (true) { + ch = String.fromCharCode(int.parse(ch)); + if (ch == r'\') { + literal += ch; + ch = String.fromCharCode(int.parse(getNextChar())); + literal += ch; + ch = getNextChar(); + continue; + } + + if (ch == '(') { + parenthesesCount++; + literal += ch; + ch = getNextChar(); + continue; + } + + if (ch == ')' && parenthesesCount != 0) { + literal += ch; + ch = getNextChar(); + parenthesesCount--; + continue; + } + + if (ch == ')' && parenthesesCount == 0) { + literal += ch; + return literal; + } + literal += ch; + ch = getNextChar(); + } + } + + PdfToken _getHexadecimalString() { + int parentLevel = 0; + bool skipParentLevel = false; + String ch = String.fromCharCode(int.parse(_consumeValue())); + while (true) { + if (ch == '<') { + if (!skipParentLevel) { + parentLevel++; + } + ch = String.fromCharCode(int.parse(_consumeValue())); + } else if (ch == '>' && !_isArtifactContentEnds) { + if (parentLevel == 0) { + _consumeValue(); + break; + } else if (parentLevel == 1) { + ch = String.fromCharCode(int.parse(_consumeValue())); + if (ch == '>') { + parentLevel--; + } + if (parentLevel == 1 && + (ch == ' ' || (isContainsArtifacts && ch == 'B'))) { + break; + } + } else { + if (ch == '>') { + parentLevel--; + } + ch = String.fromCharCode(int.parse(_consumeValue())); + } + } else if (operatorParams != null && + operatorParams.toString().contains('ActualText') && + ch == '(') { + skipParentLevel = true; + ch = String.fromCharCode(int.parse(_consumeValue())); + } else if (operatorParams != null && + operatorParams.toString().contains('ActualText') && + ch == ')') { + skipParentLevel = false; + ch = String.fromCharCode(int.parse(_consumeValue())); + } else { + ch = String.fromCharCode(int.parse(_consumeValue())); + } + if (ch == '\uffff') { + break; + } + } + _isContentEnded = false; + isContainsArtifacts = false; + return PdfToken.hexString; + } + + PdfToken _getOperator() { + _resetToken(); + String ch = String.fromCharCode(int.parse(_currentChar)); + + while (_isOperator(ch)) { + ch = String.fromCharCode(int.parse(_consumeValue())); + } + return PdfToken.operators; + } + + /// internal method + String getNextInlineChar() { + if (_contentStream!.length <= _charPointer) { + _currentChar = '65535'; + _nextChar = '65535'; + } else { + _currentChar = _nextChar; + _nextChar = _contentStream![_charPointer++].toString(); + if (_currentChar == '13') { + if (_nextChar == '10') { + _currentChar = '13'; + } else { + _currentChar = '10'; + } + } + } + return _currentChar; + } + + /// internal method + String getNextCharforInlineStream() { + if (_contentStream!.length <= _charPointer) { + _currentChar = '65535'; + _nextChar = '65535'; + } else { + _currentChar = _nextChar; + _nextChar = _contentStream![_charPointer++].toString(); + if (_currentChar == '13') { + if (_nextChar == '10') { + _currentChar = _nextChar; + if (_contentStream!.length <= _charPointer) { + _nextChar = '65535'; + } else { + _nextChar = _contentStream![_charPointer++].toString(); + } + } + } + } + return _currentChar; + } + + /// internal method + void resetContentPointer(int count) { + _charPointer = _charPointer - count; + } + + bool _isOperator(String ch) { + if (isLetter(ch)) { + return true; + } + switch (ch) { + case '*': + case "'": + case '"': + case '1': + case '0': + return true; + } + return false; + } + + bool _isWhiteSpace(String ch) { + switch (ch) { + case '0': + case '32': + case '9': + case '10': + case '12': + case '13': + case '20': + return true; + } + return false; + } + + bool _isDelimiter(String ch) { + switch (ch) { + case '(': + case ')': + case '<': + case '>': + case '[': + case ']': + case '/': + case '%': + return true; + } + return false; + } + + /// internal method + void dispose() { + if (_contentStream != null) { + _contentStream = null; + } + } +} + +/// internal enumerator +enum PdfToken { + /// internal enumerator + nullType, + + /// internal enumerator + comment, + + /// internal enumerator + integer, + + /// internal enumerator + real, + + /// internal enumerator + string, + + /// internal enumerator + hexString, + + /// internal enumerator + unicodeString, + + /// internal enumerator + unicodeHexString, + + /// internal enumerator + name, + + /// internal enumerator + operators, + + /// internal enumerator + beginArray, + + /// internal enumerator + endArray, + + /// internal enumerator + eof, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_parser.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_parser.dart index 324f1468a..efbfb4fe2 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_parser.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/parser/content_parser.dart @@ -1,403 +1,403 @@ -import 'content_lexer.dart'; - -/// internal class -class ContentParser { - /// internal constructor - ContentParser(List? contentStream) { - _lexer = ContentLexer(contentStream); - _operatorParams = _lexer.operatorParams; - _recordCollection = PdfRecordCollection(); - isTextExtractionProcess = false; - } - - // Fields - late ContentLexer _lexer; - StringBuffer? _operatorParams; - PdfRecordCollection? _recordCollection; - bool _isByteOperands = false; - final bool _conformanceEnabled = false; - - /// internal field - late bool isTextExtractionProcess; - - static const List _operators = [ - 'b', - 'B', - 'bx', - 'Bx', - 'BDC', - 'BI', - 'BMC', - 'BT', - 'BX', - 'c', - 'cm', - 'CS', - 'cs', - 'd', - 'd0', - 'd1', - 'Do', - 'DP', - 'EI', - 'EMC', - 'ET', - 'EX', - 'f', - 'F', - 'fx', - 'G', - 'g', - 'gs', - 'h', - 'i', - 'ID', - 'j', - 'J', - 'K', - 'k', - 'l', - 'm', - 'M', - 'MP', - 'n', - 'q', - 'Q', - 're', - 'RG', - 'rg', - 'ri', - 's', - 'S', - 'SC', - 'sc', - 'SCN', - 'scn', - 'sh', - 'f*', - 'Tx', - 'Tc', - 'Td', - 'TD', - 'Tf', - 'Tj', - 'TJ', - 'TL', - 'Tm', - 'Tr', - 'Ts', - 'Tw', - 'Tz', - 'v', - 'w', - 'W', - 'W*', - 'Wx', - 'y', - 'T*', - 'b*', - 'B*', - "'", - '"', - 'true', - ]; - - // Implementation - /// internal method - PdfRecordCollection? readContent() { - _parseObject(PdfToken.eof); - if (isTextExtractionProcess) { - _lexer.dispose(); - } - return _recordCollection; - } - - void _parseObject(PdfToken stop) { - PdfToken symbol; - final List operands = []; - - while ((symbol = _getNextToken()) != PdfToken.eof) { - if (symbol == stop || symbol == PdfToken.nullType) { - return; - } - switch (symbol) { - case PdfToken.comment: - break; - - case PdfToken.integer: - operands.add(_operatorParams.toString()); - break; - - case PdfToken.real: - operands.add(_operatorParams.toString()); - break; - - case PdfToken.string: - case PdfToken.hexString: - case PdfToken.unicodeString: - case PdfToken.unicodeHexString: - operands.add(_operatorParams.toString()); - break; - - case PdfToken.name: - if (_operatorParams.toString() == '/Artifact') { - _lexer.isContainsArtifacts = true; - } - operands.add(_operatorParams.toString()); - break; - - case PdfToken.operators: - if (_operatorParams.toString() == 'true') { - operands.add(_operatorParams.toString()); - } else if (_operatorParams.toString() == 'ID') { - _createRecord(operands); - operands.clear(); - _consumeValue(operands); - } else { - _createRecord(operands); - operands.clear(); - } - break; - - case PdfToken.beginArray: - break; - - case PdfToken.endArray: - ArgumentError.value('Error while parsing content'); - break; - - // ignore: no_default_cases - default: - break; - } - } - } - - PdfToken _getNextToken() { - return _lexer.getNextToken(); - } - - void _createRecord(List operands, [List? inlineImageBytes]) { - final String operand = _operatorParams.toString(); - final int occurence = _operators.indexOf(operand); - if (occurence < 0) { - ArgumentError.value('Invalid operand'); - } - PdfRecord record; - final List op = - operands.isNotEmpty - ? List.filled(operands.length, '', growable: true) - : []; - if (operands.isNotEmpty) { - List.copyRange(op, 0, operands); - } - if (!_isByteOperands) { - record = PdfRecord(operand, op); - } else { - final List imBytes = - inlineImageBytes!.isNotEmpty - ? List.filled(inlineImageBytes.length, 0, growable: true) - : []; - if (inlineImageBytes.isNotEmpty) { - List.copyRange(imBytes, 0, inlineImageBytes); - } - record = PdfRecord.fromImage(operand, imBytes); - } - _recordCollection!.add(record); - } - - void _consumeValue(List operands) { - String currentChar = '0'; - String nextChar = '0'; - String secondNextChar = '0'; - final List inlineImageBytes = []; - if (_conformanceEnabled) { - List thirdChar; - while (true) { - thirdChar = []; - int contentCount = 0; - currentChar = _lexer.getNextCharforInlineStream(); - if (String.fromCharCode(int.parse(currentChar)) == 'E') { - nextChar = _lexer.getNextInlineChar(); - if (String.fromCharCode(int.parse(nextChar)) == 'I') { - secondNextChar = _lexer.getNextInlineChar(); - final String snc = String.fromCharCode(int.parse(secondNextChar)); - thirdChar.add(_lexer.getNextChar(true)); - if ((snc == ' ' || - snc == '\n' || - secondNextChar == '65535' || - snc == '\r') && - thirdChar.isNotEmpty) { - while (thirdChar[thirdChar.length - 1] == ' ' || - thirdChar[thirdChar.length - 1] == '\r' || - thirdChar[thirdChar.length - 1] == '\n') { - thirdChar.add(_lexer.getNextChar()); - contentCount++; - } - } - if (!isTextExtractionProcess) { - _lexer.resetContentPointer(contentCount); - } - if ((snc == ' ' || - snc == '\n' || - secondNextChar == '65535' || - snc == '\r') && - thirdChar.isNotEmpty) { - if (String.fromCharCode( - int.parse(thirdChar[thirdChar.length - 1]), - ) == - 'Q' || - thirdChar[thirdChar.length - 1] == '65535' || - String.fromCharCode( - int.parse(thirdChar[thirdChar.length - 1]), - ) == - 'S') { - _operatorParams!.clear(); - _operatorParams!.write( - String.fromCharCode(int.parse(currentChar)), - ); - _operatorParams!.write( - String.fromCharCode(int.parse(nextChar)), - ); - _isByteOperands = true; - _createRecord(operands, inlineImageBytes); - _isByteOperands = false; - inlineImageBytes.clear(); - nextChar = _lexer.getNextInlineChar(); - break; - } else { - inlineImageBytes.add(int.parse(currentChar)); - inlineImageBytes.add(int.parse(nextChar)); - inlineImageBytes.add(int.parse(secondNextChar)); - if (thirdChar.length > 1) { - thirdChar.removeAt(0); - thirdChar.removeAt(thirdChar.length - 1); - } - for (final String c in thirdChar) { - inlineImageBytes.add(int.parse(c)); - } - currentChar = _lexer.getNextCharforInlineStream(); - } - } else { - inlineImageBytes.add(int.parse(currentChar)); - inlineImageBytes.add(int.parse(nextChar)); - inlineImageBytes.add(int.parse(secondNextChar)); - if (thirdChar.isNotEmpty) { - for (final String tc in thirdChar) { - inlineImageBytes.add(int.parse(tc)); - } - } - currentChar = _lexer.getNextCharforInlineStream(); - } - } else { - inlineImageBytes.add(int.parse(currentChar)); - inlineImageBytes.add(int.parse(nextChar)); - } - } else { - inlineImageBytes.add(int.parse(currentChar)); - } - thirdChar.clear(); - } - } else { - String thirdChar; - while (true) { - int contentCount = 0; - currentChar = _lexer.getNextCharforInlineStream(); - if (String.fromCharCode(int.parse(currentChar)) == 'E') { - nextChar = _lexer.getNextInlineChar(); - if (String.fromCharCode(int.parse(nextChar)) == 'I') { - secondNextChar = _lexer.getNextInlineChar(); - final String snc = String.fromCharCode(int.parse(secondNextChar)); - thirdChar = _lexer.getNextChar(true); - while (String.fromCharCode(int.parse(thirdChar)) == ' ' || - String.fromCharCode(int.parse(thirdChar)) == '\r' || - String.fromCharCode(int.parse(thirdChar)) == '\n') { - thirdChar = _lexer.getNextChar(); - contentCount++; - } - if (!isTextExtractionProcess) { - _lexer.resetContentPointer(contentCount); - } - if (snc == ' ' || - snc == '\n' || - secondNextChar == '65535' || - snc == '\r') { - if (String.fromCharCode(int.parse(thirdChar)) == 'Q' || - thirdChar == '65535' || - String.fromCharCode(int.parse(thirdChar)) == 'S') { - _operatorParams!.clear(); - _operatorParams!.write( - String.fromCharCode(int.parse(currentChar)), - ); - _operatorParams!.write( - String.fromCharCode(int.parse(nextChar)), - ); - _isByteOperands = true; - _createRecord(operands, inlineImageBytes); - _isByteOperands = false; - inlineImageBytes.clear(); - nextChar = _lexer.getNextInlineChar(); - break; - } - } else { - inlineImageBytes.add(int.parse(currentChar)); - inlineImageBytes.add(int.parse(nextChar)); - inlineImageBytes.add(int.parse(secondNextChar)); - inlineImageBytes.add(int.parse(thirdChar)); - currentChar = _lexer.getNextCharforInlineStream(); - } - } else { - inlineImageBytes.add(int.parse(currentChar)); - inlineImageBytes.add(int.parse(nextChar)); - } - } else { - inlineImageBytes.add(int.parse(currentChar)); - } - } - } - } -} - -/// internal class -class PdfRecordCollection { - // Constructor - /// internal constructor - PdfRecordCollection() { - recordCollection = []; - } - - // Fields - /// internal field - late List recordCollection; - - //Properties - /// internal property - int get count => recordCollection.length; - - // Implementation - /// internal method - void add(PdfRecord record) { - recordCollection.add(record); - } -} - -/// internal class -class PdfRecord { - // Constructor - /// internal constructor - PdfRecord(this.operatorName, this.operands); - - /// internal constructor - PdfRecord.fromImage(this.operatorName, this.inlineImageBytes); - - // Fields - /// internal field - String? operatorName; - - /// internal field - List? operands; - - /// internal field - // ignore: unused_field - List? inlineImageBytes; -} +import 'content_lexer.dart'; + +/// internal class +class ContentParser { + /// internal constructor + ContentParser(List? contentStream) { + _lexer = ContentLexer(contentStream); + _operatorParams = _lexer.operatorParams; + _recordCollection = PdfRecordCollection(); + isTextExtractionProcess = false; + } + + // Fields + late ContentLexer _lexer; + StringBuffer? _operatorParams; + PdfRecordCollection? _recordCollection; + bool _isByteOperands = false; + final bool _conformanceEnabled = false; + + /// internal field + late bool isTextExtractionProcess; + + static const List _operators = [ + 'b', + 'B', + 'bx', + 'Bx', + 'BDC', + 'BI', + 'BMC', + 'BT', + 'BX', + 'c', + 'cm', + 'CS', + 'cs', + 'd', + 'd0', + 'd1', + 'Do', + 'DP', + 'EI', + 'EMC', + 'ET', + 'EX', + 'f', + 'F', + 'fx', + 'G', + 'g', + 'gs', + 'h', + 'i', + 'ID', + 'j', + 'J', + 'K', + 'k', + 'l', + 'm', + 'M', + 'MP', + 'n', + 'q', + 'Q', + 're', + 'RG', + 'rg', + 'ri', + 's', + 'S', + 'SC', + 'sc', + 'SCN', + 'scn', + 'sh', + 'f*', + 'Tx', + 'Tc', + 'Td', + 'TD', + 'Tf', + 'Tj', + 'TJ', + 'TL', + 'Tm', + 'Tr', + 'Ts', + 'Tw', + 'Tz', + 'v', + 'w', + 'W', + 'W*', + 'Wx', + 'y', + 'T*', + 'b*', + 'B*', + "'", + '"', + 'true', + ]; + + // Implementation + /// internal method + PdfRecordCollection? readContent() { + _parseObject(PdfToken.eof); + if (isTextExtractionProcess) { + _lexer.dispose(); + } + return _recordCollection; + } + + void _parseObject(PdfToken stop) { + PdfToken symbol; + final List operands = []; + + while ((symbol = _getNextToken()) != PdfToken.eof) { + if (symbol == stop || symbol == PdfToken.nullType) { + return; + } + switch (symbol) { + case PdfToken.comment: + break; + + case PdfToken.integer: + operands.add(_operatorParams.toString()); + break; + + case PdfToken.real: + operands.add(_operatorParams.toString()); + break; + + case PdfToken.string: + case PdfToken.hexString: + case PdfToken.unicodeString: + case PdfToken.unicodeHexString: + operands.add(_operatorParams.toString()); + break; + + case PdfToken.name: + if (_operatorParams.toString() == '/Artifact') { + _lexer.isContainsArtifacts = true; + } + operands.add(_operatorParams.toString()); + break; + + case PdfToken.operators: + if (_operatorParams.toString() == 'true') { + operands.add(_operatorParams.toString()); + } else if (_operatorParams.toString() == 'ID') { + _createRecord(operands); + operands.clear(); + _consumeValue(operands); + } else { + _createRecord(operands); + operands.clear(); + } + break; + + case PdfToken.beginArray: + break; + + case PdfToken.endArray: + ArgumentError.value('Error while parsing content'); + break; + + // ignore: no_default_cases + default: + break; + } + } + } + + PdfToken _getNextToken() { + return _lexer.getNextToken(); + } + + void _createRecord(List operands, [List? inlineImageBytes]) { + final String operand = _operatorParams.toString(); + final int occurence = _operators.indexOf(operand); + if (occurence < 0) { + ArgumentError.value('Invalid operand'); + } + PdfRecord record; + final List op = + operands.isNotEmpty + ? List.filled(operands.length, '', growable: true) + : []; + if (operands.isNotEmpty) { + List.copyRange(op, 0, operands); + } + if (!_isByteOperands) { + record = PdfRecord(operand, op); + } else { + final List imBytes = + inlineImageBytes!.isNotEmpty + ? List.filled(inlineImageBytes.length, 0, growable: true) + : []; + if (inlineImageBytes.isNotEmpty) { + List.copyRange(imBytes, 0, inlineImageBytes); + } + record = PdfRecord.fromImage(operand, imBytes); + } + _recordCollection!.add(record); + } + + void _consumeValue(List operands) { + String currentChar = '0'; + String nextChar = '0'; + String secondNextChar = '0'; + final List inlineImageBytes = []; + if (_conformanceEnabled) { + List thirdChar; + while (true) { + thirdChar = []; + int contentCount = 0; + currentChar = _lexer.getNextCharforInlineStream(); + if (String.fromCharCode(int.parse(currentChar)) == 'E') { + nextChar = _lexer.getNextInlineChar(); + if (String.fromCharCode(int.parse(nextChar)) == 'I') { + secondNextChar = _lexer.getNextInlineChar(); + final String snc = String.fromCharCode(int.parse(secondNextChar)); + thirdChar.add(_lexer.getNextChar(true)); + if ((snc == ' ' || + snc == '\n' || + secondNextChar == '65535' || + snc == '\r') && + thirdChar.isNotEmpty) { + while (thirdChar[thirdChar.length - 1] == ' ' || + thirdChar[thirdChar.length - 1] == '\r' || + thirdChar[thirdChar.length - 1] == '\n') { + thirdChar.add(_lexer.getNextChar()); + contentCount++; + } + } + if (!isTextExtractionProcess) { + _lexer.resetContentPointer(contentCount); + } + if ((snc == ' ' || + snc == '\n' || + secondNextChar == '65535' || + snc == '\r') && + thirdChar.isNotEmpty) { + if (String.fromCharCode( + int.parse(thirdChar[thirdChar.length - 1]), + ) == + 'Q' || + thirdChar[thirdChar.length - 1] == '65535' || + String.fromCharCode( + int.parse(thirdChar[thirdChar.length - 1]), + ) == + 'S') { + _operatorParams!.clear(); + _operatorParams!.write( + String.fromCharCode(int.parse(currentChar)), + ); + _operatorParams!.write( + String.fromCharCode(int.parse(nextChar)), + ); + _isByteOperands = true; + _createRecord(operands, inlineImageBytes); + _isByteOperands = false; + inlineImageBytes.clear(); + nextChar = _lexer.getNextInlineChar(); + break; + } else { + inlineImageBytes.add(int.parse(currentChar)); + inlineImageBytes.add(int.parse(nextChar)); + inlineImageBytes.add(int.parse(secondNextChar)); + if (thirdChar.length > 1) { + thirdChar.removeAt(0); + thirdChar.removeAt(thirdChar.length - 1); + } + for (final String c in thirdChar) { + inlineImageBytes.add(int.parse(c)); + } + currentChar = _lexer.getNextCharforInlineStream(); + } + } else { + inlineImageBytes.add(int.parse(currentChar)); + inlineImageBytes.add(int.parse(nextChar)); + inlineImageBytes.add(int.parse(secondNextChar)); + if (thirdChar.isNotEmpty) { + for (final String tc in thirdChar) { + inlineImageBytes.add(int.parse(tc)); + } + } + currentChar = _lexer.getNextCharforInlineStream(); + } + } else { + inlineImageBytes.add(int.parse(currentChar)); + inlineImageBytes.add(int.parse(nextChar)); + } + } else { + inlineImageBytes.add(int.parse(currentChar)); + } + thirdChar.clear(); + } + } else { + String thirdChar; + while (true) { + int contentCount = 0; + currentChar = _lexer.getNextCharforInlineStream(); + if (String.fromCharCode(int.parse(currentChar)) == 'E') { + nextChar = _lexer.getNextInlineChar(); + if (String.fromCharCode(int.parse(nextChar)) == 'I') { + secondNextChar = _lexer.getNextInlineChar(); + final String snc = String.fromCharCode(int.parse(secondNextChar)); + thirdChar = _lexer.getNextChar(true); + while (String.fromCharCode(int.parse(thirdChar)) == ' ' || + String.fromCharCode(int.parse(thirdChar)) == '\r' || + String.fromCharCode(int.parse(thirdChar)) == '\n') { + thirdChar = _lexer.getNextChar(); + contentCount++; + } + if (!isTextExtractionProcess) { + _lexer.resetContentPointer(contentCount); + } + if (snc == ' ' || + snc == '\n' || + secondNextChar == '65535' || + snc == '\r') { + if (String.fromCharCode(int.parse(thirdChar)) == 'Q' || + thirdChar == '65535' || + String.fromCharCode(int.parse(thirdChar)) == 'S') { + _operatorParams!.clear(); + _operatorParams!.write( + String.fromCharCode(int.parse(currentChar)), + ); + _operatorParams!.write( + String.fromCharCode(int.parse(nextChar)), + ); + _isByteOperands = true; + _createRecord(operands, inlineImageBytes); + _isByteOperands = false; + inlineImageBytes.clear(); + nextChar = _lexer.getNextInlineChar(); + break; + } + } else { + inlineImageBytes.add(int.parse(currentChar)); + inlineImageBytes.add(int.parse(nextChar)); + inlineImageBytes.add(int.parse(secondNextChar)); + inlineImageBytes.add(int.parse(thirdChar)); + currentChar = _lexer.getNextCharforInlineStream(); + } + } else { + inlineImageBytes.add(int.parse(currentChar)); + inlineImageBytes.add(int.parse(nextChar)); + } + } else { + inlineImageBytes.add(int.parse(currentChar)); + } + } + } + } +} + +/// internal class +class PdfRecordCollection { + // Constructor + /// internal constructor + PdfRecordCollection() { + recordCollection = []; + } + + // Fields + /// internal field + late List recordCollection; + + //Properties + /// internal property + int get count => recordCollection.length; + + // Implementation + /// internal method + void add(PdfRecord record) { + recordCollection.add(record); + } +} + +/// internal class +class PdfRecord { + // Constructor + /// internal constructor + PdfRecord(this.operatorName, this.operands); + + /// internal constructor + PdfRecord.fromImage(this.operatorName, this.inlineImageBytes); + + // Fields + /// internal field + String? operatorName; + + /// internal field + List? operands; + + /// internal field + // ignore: unused_field + List? inlineImageBytes; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart index 7472e22f1..c86b37c37 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/pdf_text_extractor.dart @@ -1,2360 +1,2423 @@ -import 'dart:ui'; - -import 'package:intl/intl.dart' as bidi; - -import '../../../interfaces/pdf_interface.dart'; -import '../../graphics/fonts/enums.dart'; -import '../../graphics/fonts/pdf_cjk_standard_font.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_standard_font.dart'; -import '../../graphics/fonts/rtl/arabic_shape_renderer.dart'; -import '../../graphics/fonts/rtl/bidi.dart'; -import '../../io/pdf_constants.dart'; -import '../../pages/enum.dart'; -import '../../pages/pdf_page.dart'; -import '../../pages/pdf_page_layer_collection.dart'; -import '../../pdf_document/pdf_document.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_stream.dart'; -import 'enums.dart'; -import 'font_structure.dart'; -import 'glyph.dart'; -import 'image_renderer.dart'; -import 'matched_item.dart'; -import 'matrix_helper.dart'; -import 'page_resource_loader.dart'; -import 'parser/content_parser.dart'; -import 'text_element.dart'; -import 'text_glyph.dart'; -import 'text_line.dart'; -import 'text_word.dart'; -import 'xobject_element.dart'; - -/// Represents a text extractor from an existing PDF document -class PdfTextExtractor { - //Constructor - /// Initialize a new instance of the [PdfTextExtractor] class - /// from the instance of [PdfDocument] - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData); - /// //Extract text from all pages - /// String text = PdfTextExtractor(document).extractText(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfTextExtractor(PdfDocument document) { - if (!PdfDocumentHelper.getHelper(document).isLoadedDocument) { - ArgumentError.value( - document, - 'document', - 'document instance is not a loaded PDF document', - ); - } - _document = document; - _initialize(); - } - - //Fields - late PdfDocument _document; - late List _symbolChars; - String? _currentFont; - double? _fontSize; - PdfPage? _currentPage; - late PageResourceLoader _resourceLoader; - late int _currentPageIndex; - bool _isLayout = false; - double _characterSpacing = 0; - double _wordSpacing = 0; - MatrixHelper? _textLineMatrix; - late MatrixHelper? _textMatrix; - late MatrixHelper? _currentTextMatrix; - Rect? _tempBoundingRectangle; - bool _hasLeading = false; - bool _hasET = false; - late MatrixHelper _currentTransformationMatrix; - bool _hasBDC = false; - Bidi? _bidiInstance; - MatrixHelper? _initialTransform; - String? _actualText; - - //Properties - Bidi get _bidi { - _bidiInstance ??= Bidi(); - return _bidiInstance!; - } - - //Public methods - /// Extract text from an existing PDF document - /// - /// startPageIndex and endPageIndex specifies the page range to be selected - /// to extract text. - /// for example, startPageIndex is 0 and endPageIndex is 9 - /// is used to extract text from first page to 10 page of loaded PDF - /// - /// for extracting text from particular page, - /// we can set an index of the page to startPageIndex - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData); - /// //Extract text from all pages - /// String text = PdfTextExtractor(document).extractText(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String extractText({ - int? startPageIndex, - int? endPageIndex, - bool? layoutText, - }) { - _isLayout = layoutText ?? false; - return _extractText(startPageIndex, endPageIndex); - } - - /// Extract [TextLine] from an existing PDF document - /// - /// startPageIndex and endPageIndex specifies the page range to be selected - /// to extract text line. - /// for example, startPageIndex is 0 and endPageIndex is 9 - /// is used to extract text line from first page to 10 page of loaded PDF - /// - /// for extracting text line from particular page, - /// we can set an index of the page to startPageIndex - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData); - /// //Extract text from all pages - /// List textLine = PdfTextExtractor(document).extractTextLines(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - List extractTextLines({int? startPageIndex, int? endPageIndex}) { - return _extractTextLines(startPageIndex, endPageIndex); - } - - /// Returns the information of the matched texts in a specific page - /// based on the list of string to be searched - /// - /// startPageIndex and endPageIndex specifies the page range to be selected - /// to find text. - /// for example, startPageIndex is 0 and endPageIndex is 9 - /// is used to find text from first page to 10 page of loaded PDF - /// - /// for finding text and get matched item from particular page, - /// we can set an index of the page to startPageIndex - /// - /// search option defines the constants that specify the option - /// for text search - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData); - /// //list of string to be searched. - /// List searchString = ['text1', 'text2']; - /// //Find text and get matched items. - /// List textLine = PdfTextExtractor(document).findText(searchString); - /// //Dispose the document. - /// document.dispose(); - /// ``` - List findText( - List searchString, { - int? startPageIndex, - int? endPageIndex, - TextSearchOption? searchOption, - }) { - return _findText(searchString, startPageIndex, endPageIndex, searchOption); - } - - //Implementation - void _checkPageNumber(int pageNumber) { - if (pageNumber < 0 || pageNumber >= _document.pages.count) { - throw ArgumentError.value(pageNumber, 'pageNumber', 'Index out of range'); - } - } - - void _initialize() { - _symbolChars = ['(', ')', '[', ']', '<', '>']; - _resourceLoader = PageResourceLoader(); - _currentTextMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - _textLineMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - _textMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - _tempBoundingRectangle = Rect.zero; - _currentTransformationMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - } - - String _extractText(int? startPageIndex, int? endPageIndex) { - if (startPageIndex == null) { - if (endPageIndex != null) { - throw ArgumentError.value( - endPageIndex, - 'endPageIndex', - 'Invalid argument. start page index cannot be null', - ); - } else { - return _extractTextFromRange(0, _document.pages.count - 1); - } - } else if (endPageIndex == null) { - _checkPageNumber(startPageIndex); - _currentPageIndex = startPageIndex; - return _getText(_document.pages[startPageIndex]); - } else { - _checkPageNumber(startPageIndex); - _checkPageNumber(endPageIndex); - return _extractTextFromRange(startPageIndex, endPageIndex); - } - } - - List _extractTextLines(int? startPageIndex, int? endPageIndex) { - if (startPageIndex == null) { - if (endPageIndex != null) { - throw ArgumentError.value( - endPageIndex, - 'endPageIndex', - 'Invalid argument. start page index cannot be null', - ); - } else { - return _extractTextLineFromRange(0, _document.pages.count - 1); - } - } else if (endPageIndex == null) { - _checkPageNumber(startPageIndex); - _currentPageIndex = startPageIndex; - return _getTextLine(_document.pages[startPageIndex]); - } else { - _checkPageNumber(startPageIndex); - _checkPageNumber(endPageIndex); - return _extractTextLineFromRange(startPageIndex, endPageIndex); - } - } - - List _findText( - List searchString, - int? startPageIndex, - int? endPageIndex, - TextSearchOption? searchOption, - ) { - if (startPageIndex == null) { - if (endPageIndex != null) { - throw ArgumentError.value( - endPageIndex, - 'endPageIndex', - 'Invalid argument. start page index cannot be null', - ); - } else { - return _findTextFromRange( - 0, - _document.pages.count - 1, - searchString, - searchOption, - ); - } - } else if (endPageIndex == null) { - _checkPageNumber(startPageIndex); - _currentPageIndex = startPageIndex; - return _searchInBackground( - _document.pages[startPageIndex], - searchString, - searchOption, - ); - } else { - _checkPageNumber(startPageIndex); - _checkPageNumber(endPageIndex); - return _findTextFromRange( - startPageIndex, - endPageIndex, - searchString, - searchOption, - ); - } - } - - String _extractTextFromRange(int startPageIndex, int endPageIndex) { - String resultText = ''; - for (int i = startPageIndex; i <= endPageIndex; i++) { - final String text = _getText(_document.pages[i]); - resultText = - resultText + - (i > startPageIndex && - (!_isLayout || (_isLayout && !resultText.endsWith('\n'))) - ? '\r\n' - : '') + - text; - } - return resultText; - } - - List _extractTextLineFromRange( - int startPageIndex, - int endPageIndex, - ) { - final List result = []; - for (int i = startPageIndex; i <= endPageIndex; i++) { - _currentPageIndex = i; - final List textLines = _getTextLine(_document.pages[i]); - if (textLines.isNotEmpty) { - result.addAll(textLines); - } - } - return result; - } - - List _findTextFromRange( - int startPageIndex, - int endPageIndex, - List searchString, - TextSearchOption? searchOption, - ) { - final List result = []; - for (int i = startPageIndex; i <= endPageIndex; i++) { - _currentPageIndex = i; - final List textLines = _searchInBackground( - _document.pages[i], - searchString, - searchOption, - ); - if (textLines.isNotEmpty) { - result.addAll(textLines); - } - } - return result; - } - - String _getText(PdfPage page) { - _currentPage = page; - _fontSize = 0; - PdfPageHelper.getHelper(page).isTextExtraction = true; - final bool isChanged = _checkPageDictionary(page); - final bool isContentChanged = _checkContentArray(page); - final PdfRecordCollection? recordCollection = _getRecordCollection(page); - PdfPageResources? pageResources = _resourceLoader.getPageResources(page); - String resultantText; - if (_isLayout) { - try { - _initialTransform = MatrixHelper( - 1.3333333333333333, - 0, - 0, - -1.3333333333333333, - 0, - page.size.height * 1.3333333333333333, - ); - } catch (e) { - _initialTransform = MatrixHelper.identity; - } - resultantText = _renderTextAsLayout(recordCollection, pageResources); - } else { - resultantText = _renderText(recordCollection, pageResources); - } - if (recordCollection != null) { - recordCollection.recordCollection.clear(); - } - if (pageResources.resources.isNotEmpty) { - pageResources.resources.forEach((String? key, Object? value) { - if (value != null && value is FontStructure) { - value.dispose(); - } - }); - pageResources.resources.clear(); - } - if (pageResources.fontCollection.isNotEmpty) { - pageResources.fontCollection.forEach((String? key, FontStructure value) { - value.dispose(); - }); - pageResources.fontCollection.clear(); - } - pageResources = null; - if (resultantText != '') { - resultantText = _skipEscapeSequence(resultantText); - } - PdfPageHelper.getHelper(page).contents.changed = isContentChanged; - PdfPageHelper.getHelper(page).dictionary!.changed = isChanged; - PdfPageHelper.getHelper(page).isTextExtraction = false; - return resultantText; - } - - List _getTextLine(PdfPage pdfPage) { - final List result = []; - _currentPage = pdfPage; - _fontSize = 0; - PdfPageHelper.getHelper(pdfPage).isTextExtraction = true; - final bool isChanged = _checkPageDictionary(pdfPage); - final bool isContentChanged = _checkContentArray(pdfPage); - final PdfRecordCollection? recordCollection = _getRecordCollection(pdfPage); - final PdfPageResources pageResources = _resourceLoader.getPageResources( - pdfPage, - ); - final ImageRenderer renderer = ImageRenderer( - recordCollection, - pageResources, - pdfPage.size.height * 1.3333333333333333, - ); - renderer.isExtractLineCollection = true; - final double rotation = _getPageRotation(pdfPage); - renderer.pageRotation = rotation; - renderer.renderAsImage(); - renderer.isExtractLineCollection = false; - int i = 0; - double? width = 0; - double? height = 0; - double? dx = 0; - double? dy = 0; - int offsetY = 0; - double yPos = 0; - String pagestring = ''; - int lineStartIndex = 0; - TextLine textLine = TextLineHelper.initialize(); - if (pagestring == '') { - for (final Glyph s in renderer.imageRenderGlyphList) { - pagestring = pagestring + s.toUnicode; - } - } - if (renderer.extractTextElement.isNotEmpty) { - for (int k = 0; k < renderer.extractTextElement.length; k++) { - bool hasRotation = false; - if (i < renderer.imageRenderGlyphList.length) { - final Glyph tempGlyph = renderer.imageRenderGlyphList[i]; - if (tempGlyph.isRotated && rotation == 270) { - yPos = tempGlyph.boundingRect.left; - hasRotation = true; - } else { - yPos = tempGlyph.boundingRect.top; - } - if (k == 0) { - offsetY = yPos.toInt(); - } - if ((i != 0 && - yPos.toInt() != offsetY && - renderer.extractTextElement[k].renderedText != '') || - (i == renderer.imageRenderGlyphList.length - 1)) { - offsetY = yPos.toInt(); - if (textLine.wordCollection.isNotEmpty) { - result.add( - _prepareTextLine( - textLine, - renderer, - lineStartIndex, - i, - rotation, - ), - ); - } - lineStartIndex = i; - textLine = TextLineHelper.initialize(); - } - final TextElement textElement = renderer.extractTextElement[k]; - final List words = _splitRenderedText( - textElement.renderedText, - renderer.imageRenderGlyphList, - i, - ); - textElement.text = ' '; - TextWord? textwords; - List glyphs = []; - for (int x = 0; x < words.length; x++) { - if (pagestring.contains(words[x]) && words[x].isNotEmpty) { - glyphs = []; - int lastIndex = i; - for ( - int m = i; - m < i + words[x].length && - m < renderer.imageRenderGlyphList.length; - m++ - ) { - final Glyph tempGlyph = renderer.imageRenderGlyphList[m]; - final Rect tempBounds = tempGlyph.boundingRect; - final Rect glyphBounds = Rect.fromLTRB( - tempBounds.left, - tempBounds.top, - tempBounds.right, - tempBounds.bottom, - ); - final TextGlyph textGlyph = TextGlyphHelper.initialize( - tempGlyph.toUnicode, - textElement.fontName, - textElement.fontStyle, - _calculateBounds(glyphBounds), - textElement.fontSize, - tempGlyph.isRotated, - ); - glyphs.add(textGlyph); - lastIndex = m; - } - Rect? wordBound; - dx = renderer.imageRenderGlyphList[i].boundingRect.left; - dy = renderer.imageRenderGlyphList[i].boundingRect.top; - if (hasRotation && rotation == 270) { - width = renderer.imageRenderGlyphList[i].boundingRect.width; - height = - renderer - .imageRenderGlyphList[lastIndex] - .boundingRect - .bottom; - wordBound = Rect.fromLTWH(dx, dy, width, height - dy); - } else { - height = renderer.imageRenderGlyphList[i].boundingRect.height; - if (dx > - renderer - .imageRenderGlyphList[lastIndex] - .boundingRect - .left) { - width = - (dx - - renderer - .imageRenderGlyphList[lastIndex] - .boundingRect - .left) + - renderer - .imageRenderGlyphList[lastIndex] - .boundingRect - .width; - } else { - width = - (renderer - .imageRenderGlyphList[lastIndex] - .boundingRect - .left) + - renderer - .imageRenderGlyphList[lastIndex] - .boundingRect - .width; - } - wordBound = Rect.fromLTWH(dx, dy, width - dx, height); - } - i = lastIndex + 1; - String word = words[x]; - if (word.isNotEmpty && bidi.Bidi.hasAnyRtl(word)) { - word = - _bidi.getLogicalToVisualString(word, true)['rtlText'] - as String; - } - textwords = TextWordHelper.initialize( - word, - textElement.fontName, - textElement.fontStyle, - glyphs, - _calculateBounds(wordBound), - textElement.fontSize, - ); - textLine.wordCollection.add(textwords); - } - textElement.text = words[x]; - if (textElement.text != '') { - if (x < words.length - 1 && - i <= renderer.imageRenderGlyphList.length - 1 && - renderer.imageRenderGlyphList[i].toUnicode == ' ') { - if (i != 0) { - final Map tempResult = _addSpace( - textwords, - renderer, - textElement, - i, - dx, - dy, - width, - height, - ); - dx = tempResult['dx'] as double?; - dy = tempResult['dy'] as double?; - width = tempResult['width'] as double?; - height = tempResult['height'] as double?; - final Rect wordBound = Rect.fromLTWH( - dx!, - dy!, - width!, - height!, - ); - tempResult['word'].bounds = _calculateBounds(wordBound); - textLine.wordCollection.add(tempResult['word']); - } - i = i + 1; - } - if (x < words.length - 1 && - i <= renderer.imageRenderGlyphList.length - 1 && - renderer.imageRenderGlyphList[i].toUnicode == ' ' && - ((renderer.imageRenderGlyphList[i].isRotated && - (rotation == 270 || rotation == 90)) || - renderer.imageRenderGlyphList[i].boundingRect.top - .toInt() == - offsetY)) { - i = i + 1; - } - } else { - if (i <= renderer.imageRenderGlyphList.length - 1) { - if (x != words.length - 1 && - renderer.imageRenderGlyphList[i].toUnicode == ' ') { - if (i != 0) { - final Map tempResult = _addSpace( - textwords, - renderer, - textElement, - i, - dx, - dy, - width, - height, - ); - dx = tempResult['dx'] as double?; - dy = tempResult['dy'] as double?; - width = tempResult['width'] as double?; - height = tempResult['height'] as double?; - final Rect wordBound = Rect.fromLTWH( - dx!, - dy!, - width!, - height!, - ); - tempResult['word'].bounds = _calculateBounds(wordBound); - textLine.wordCollection.add(tempResult['word']); - } - i = i + 1; - } - } - } - } - if (i != 0 && - yPos.toInt() != offsetY && - renderer.extractTextElement[k].renderedText != '' && - renderer.extractTextElement[k].renderedText != ' ' || - (i == renderer.imageRenderGlyphList.length - 1)) { - if (renderer.extractTextElement.isNotEmpty && k == 0) { - offsetY = yPos.toInt(); - if (textLine.wordCollection.isNotEmpty) { - result.add( - _prepareTextLine( - textLine, - renderer, - lineStartIndex, - i, - rotation, - ), - ); - } - lineStartIndex = i; - textLine = TextLineHelper.initialize(); - } - } - } - } - final TextElement element = - renderer.extractTextElement[renderer.extractTextElement.length - 1]; - if (textLine.wordCollection.isNotEmpty && - !result.contains(textLine) && - element.renderedText != '' && - element.renderedText != ' ') { - result.add( - _prepareTextLine(textLine, renderer, lineStartIndex, i, rotation), - ); - textLine = TextLineHelper.initialize(); - } - } - if (textLine.wordCollection.isNotEmpty && !result.contains(textLine)) { - result.add( - _prepareTextLine(textLine, renderer, lineStartIndex, i, rotation), - ); - textLine = TextLineHelper.initialize(); - } - PdfPageHelper.getHelper(pdfPage).contents.changed = isContentChanged; - PdfPageHelper.getHelper(pdfPage).dictionary!.changed = isChanged; - PdfPageHelper.getHelper(pdfPage).isTextExtraction = false; - return result; - } - - //Splits the words in a rendered text and returns the list of words. - List _splitRenderedText(String text, List glyphs, int index) { - List words = []; - String tempString = ''; - Rect? previousRect; - bool isSplit = false; - if (text.isNotEmpty && - !text.codeUnits.any((int element) => element > 255) && - text[0] == glyphs[index].toUnicode) { - for (int i = index, j = 0; j < text.length; i++, j++) { - try { - final Glyph textGlyph = glyphs[i]; - if (text[j] == ' ') { - if (tempString.isNotEmpty) { - words.add(tempString); - } - if (j == 0 || (j != text.length - 1 && text[j - 1] == ' ')) { - words.add(''); - } - if (j + 1 >= text.length) { - words.add(''); - } - previousRect = null; - tempString = ''; - continue; - } - final Rect currentRect = textGlyph.boundingRect; - if (previousRect != null) { - if ((previousRect.left + previousRect.width - currentRect.left) - .abs() > - 1.5) { - isSplit = true; - } else { - tempString += text[j]; - } - } else { - tempString += text[j]; - } - if (isSplit) { - words.add(tempString); - isSplit = false; - previousRect = null; - tempString = ''; - i--; - j--; - } else { - previousRect = currentRect; - } - } catch (e) { - words = text.split(' '); - return words; - } - } - if (tempString.isNotEmpty) { - words.add(tempString); - } - } else { - words = text.split(' '); - } - return words; - } - - List _searchInBackground( - PdfPage page, - List searchString, - TextSearchOption? searchOption, - ) { - final List result = []; - _isLayout = true; - final String pageText = _getText(page); - _isLayout = false; - final bool containsRtl = bidi.Bidi.hasAnyRtl(pageText); - if (pageText != '') { - bool isMatched = _isMatchFound( - searchString, - searchOption, - pageText, - containsRtl, - ); - if (isMatched || containsRtl) { - _currentPage = page; - _fontSize = 0; - PdfPageHelper.getHelper(page).isTextExtraction = true; - final bool isChanged = _checkPageDictionary(page); - final bool isContentChanged = _checkContentArray(page); - final PdfRecordCollection? recordCollection = _getRecordCollection( - page, - ); - final PdfPageResources pageResources = _resourceLoader.getPageResources( - page, - ); - final ImageRenderer renderer = ImageRenderer( - recordCollection, - pageResources, - page.size.height * 1.3333333333333333, - ); - renderer.pageRotation = _getPageRotation(page); - renderer.renderAsImage(); - String renderedString = ''; - final Map combinedGlyphLength = {}; - if (renderer.imageRenderGlyphList.isNotEmpty) { - for (final Glyph glyph in renderer.imageRenderGlyphList) { - final String currentText = glyph.toUnicode; - if (currentText.length > 1) { - combinedGlyphLength[renderedString.length] = currentText.length; - } - renderedString = renderedString + glyph.toUnicode; - } - List? visualOrderedTextGlyph; - if (containsRtl) { - final Map visualOrderResult = _bidi - .getLogicalToVisualString(renderedString, true); - renderedString = visualOrderResult['rtlText'] as String; - final List visualOrderIndexes = - visualOrderResult['orderedIndexes'] as List; - visualOrderedTextGlyph = []; - if (combinedGlyphLength.isNotEmpty) { - combinedGlyphLength.forEach((int key, int value) { - if (visualOrderIndexes.contains(key)) { - final int newIndex = visualOrderIndexes.indexOf(key); - if (newIndex + 1 < visualOrderIndexes.length && - visualOrderIndexes[newIndex + 1] == key + 1) { - visualOrderIndexes.removeRange( - newIndex + 1, - newIndex + value, - ); - } else if (newIndex - 1 > -1 && - visualOrderIndexes[newIndex - 1] == key + 1) { - visualOrderIndexes.removeRange( - newIndex - value + 1, - newIndex, - ); - } - } - }); - } - final int glyphListLength = renderer.imageRenderGlyphList.length; - for (int i = 0; i < visualOrderIndexes.length; i++) { - int index = visualOrderIndexes[i]; - if (combinedGlyphLength.isNotEmpty) { - int tempValue = 0; - for (final int element in combinedGlyphLength.values) { - tempValue += element - 1; - } - for (final int key - in combinedGlyphLength.keys.toList().reversed) { - if (index > key) { - index -= tempValue; - break; - } - tempValue -= combinedGlyphLength[key]! - 1; - } - } - if (index < glyphListLength) { - visualOrderedTextGlyph.add( - renderer.imageRenderGlyphList[index], - ); - } - } - } - final List renderedStringCollection = [ - renderedString, - ]; - final List?> textGlyphCollection = ?>[ - visualOrderedTextGlyph ?? renderer.imageRenderGlyphList, - ]; - if (renderedString.contains(' ') || - renderedString.contains('\t\t')) { - String innerSpaceTrimmedString = renderedString; - final List innerSpaceTrimmedTextGlyph = - (visualOrderedTextGlyph ?? renderer.imageRenderGlyphList) - .toList(); - while (innerSpaceTrimmedString.contains(' ') || - innerSpaceTrimmedString.contains('\t\t')) { - int spaceStartIndex = innerSpaceTrimmedString.indexOf(' '); - if (spaceStartIndex < 0) { - spaceStartIndex = innerSpaceTrimmedString.indexOf('\t\t'); - } - if (spaceStartIndex >= 0) { - final List stringList = innerSpaceTrimmedString.split( - '', - ); - int i = spaceStartIndex + 2; - for (i = spaceStartIndex + 2; i < stringList.length; i++) { - if (stringList[i] == ' ' || stringList[i] == '\t') { - continue; - } else if (i >= stringList.length) { - break; - } else { - stringList.removeRange(spaceStartIndex + 1, i); - innerSpaceTrimmedTextGlyph.removeRange( - spaceStartIndex + 1, - i, - ); - break; - } - } - innerSpaceTrimmedString = stringList.join(); - if (i >= stringList.length) { - break; - } - } - } - renderedStringCollection.add(innerSpaceTrimmedString); - textGlyphCollection.add(innerSpaceTrimmedTextGlyph); - } - if (!isMatched) { - for (final String renderedText in renderedStringCollection) { - isMatched = _isMatchFound( - searchString, - searchOption, - renderedText, - containsRtl, - ); - if (isMatched) { - break; - } - } - } - if (isMatched) { - _getMatchedItems( - page, - searchString, - searchOption, - renderedStringCollection, - combinedGlyphLength, - textGlyphCollection, - result, - ); - } - } - PdfPageHelper.getHelper(page).contents.changed = isContentChanged; - PdfPageHelper.getHelper(page).dictionary!.changed = isChanged; - PdfPageHelper.getHelper(page).isTextExtraction = false; - } - } - return result; - } - - bool _isMatchFound( - List searchString, - TextSearchOption? searchOption, - String pageText, - bool containsRtl, - ) { - ArabicShapeRenderer? shapeRenderer; - if (containsRtl) { - shapeRenderer = ArabicShapeRenderer(); - } - bool isMatched = false; - for (int i = 0; i < searchString.length; i++) { - final String term = searchString[i]; - if (searchOption != null && - (searchOption == TextSearchOption.caseSensitive || - searchOption == TextSearchOption.both)) { - if (pageText.contains(term)) { - isMatched = true; - if (!containsRtl) { - break; - } - } - } else if (pageText.toLowerCase().contains(term.toLowerCase())) { - isMatched = true; - if (!containsRtl) { - break; - } - } - if (containsRtl && bidi.Bidi.hasAnyRtl(term)) { - final String renderedTerm = shapeRenderer!.shape(term.split(''), 0); - if (pageText.toLowerCase().contains(renderedTerm.toLowerCase())) { - if (!searchString.contains(renderedTerm)) { - searchString.add(renderedTerm); - } - isMatched = true; - } - if (term != renderedTerm && term.length < 5) { - List termCollection = [term]; - for (int j = 0; j < term.length; j++) { - if (shapeRenderer.arabicMapTable.containsKey(term[j])) { - final List? shapedChars = - shapeRenderer.arabicMapTable[term[j]]; - if (shapedChars != null && shapedChars.isNotEmpty) { - final List tempTermCollection = termCollection.toList(); - for (final String char in shapedChars) { - for (final String tempTerm in termCollection) { - final List termList = tempTerm.split(''); - termList[j] = char; - final String tempRenderedTerm = termList.join(); - if (!tempTermCollection.contains(tempRenderedTerm)) { - tempTermCollection.add(tempRenderedTerm); - if (!searchString.contains(tempRenderedTerm) && - pageText.toLowerCase().contains( - tempRenderedTerm.toLowerCase(), - )) { - searchString.add(tempRenderedTerm); - isMatched = true; - } - } - } - } - termCollection.clear(); - termCollection = tempTermCollection.toList(); - tempTermCollection.clear(); - } - } - } - termCollection.clear(); - } - } - } - return isMatched; - } - - void _getMatchedItems( - PdfPage page, - List searchString, - TextSearchOption? searchOption, - List renderedStringCollection, - Map combinedGlyphLength, - List?> glyphListCollection, - List result, - ) { - if (renderedStringCollection.isNotEmpty && - renderedStringCollection[0] != '') { - final Map> mappedIndexes = >{}; - final List textLengthCollection = []; - for (int i = 0; i < renderedStringCollection.length; i++) { - if (searchOption == null || - (searchOption != TextSearchOption.caseSensitive && - searchOption != TextSearchOption.both)) { - renderedStringCollection[i] = - renderedStringCollection[i].toLowerCase(); - } - textLengthCollection.add(renderedStringCollection[i].length); - } - for (final String term in searchString) { - if (term != '' && !mappedIndexes.containsKey(term)) { - final List indexes = []; - final String currentText = - (searchOption != null && - (searchOption == TextSearchOption.caseSensitive || - searchOption == TextSearchOption.both)) - ? term - : term.toLowerCase(); - int startIndex = 0; - final int length = currentText.length; - for (int i = 0; i < renderedStringCollection.length; i++) { - while (startIndex <= textLengthCollection[i] && - renderedStringCollection[i].contains(currentText, startIndex)) { - int index = renderedStringCollection[i].indexOf( - currentText, - startIndex, - ); - final int tempIndex = index; - if (searchOption != null && - (searchOption == TextSearchOption.wholeWords || - searchOption == TextSearchOption.both)) { - if (index == 0 || - _hasEscapeCharacter( - renderedStringCollection[i][index - 1], - )) { - if (index + length == textLengthCollection[i]) { - if (combinedGlyphLength.isNotEmpty) { - index = _checkCombinedTextIndex( - index, - combinedGlyphLength, - ); - } - indexes.add(index); - } else if (_hasEscapeCharacter( - renderedStringCollection[i][index + length], - )) { - if (combinedGlyphLength.isNotEmpty) { - index = _checkCombinedTextIndex( - index, - combinedGlyphLength, - ); - } - indexes.add(index); - } - } - } else { - if (combinedGlyphLength.isNotEmpty) { - index = _checkCombinedTextIndex(index, combinedGlyphLength); - } - indexes.add(index); - } - startIndex = tempIndex + 1; - } - if (indexes.isNotEmpty) { - for (final int index in indexes) { - if (glyphListCollection[i] != null && - index < glyphListCollection[i]!.length) { - final List rect = _calculatedTextounds( - glyphListCollection[i]!, - term, - index, - page, - bidi.Bidi.hasAnyRtl(term), - ); - result.add( - MatchedItemHelper.initialize(term, rect, _currentPageIndex), - ); - } - } - break; - } - } - } - } - } - } - - int _checkCombinedTextIndex( - int textIndex, - Map combinedGlyphLength, - ) { - int adjustableLength = 0; - combinedGlyphLength.forEach((int index, int length) { - if (index < textIndex) { - adjustableLength += length - 1; - } - }); - return textIndex - adjustableLength; - } - - PdfRecordCollection? _getRecordCollection(PdfPage page) { - PdfRecordCollection? recordCollection; - List? combinedData = PdfPageLayerCollectionHelper.getHelper( - page.layers, - ).combineContent(true); - if (combinedData != null) { - final ContentParser parser = ContentParser(combinedData); - parser.isTextExtractionProcess = true; - recordCollection = parser.readContent(); - parser.isTextExtractionProcess = false; - combinedData.clear(); - } - combinedData = null; - return recordCollection; - } - - bool _checkPageDictionary(PdfPage page) { - return PdfPageHelper.getHelper(page).dictionary!.changed != null && - PdfPageHelper.getHelper(page).dictionary!.changed!; - } - - bool _checkContentArray(PdfPage page) { - bool isContentChanged = false; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.contents)) { - final IPdfPrimitive? contents = - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .contents]; - if (contents is PdfReferenceHolder) { - final PdfReferenceHolder holder = contents; - final IPdfPrimitive? primitive = holder.object; - if (primitive is PdfArray) { - isContentChanged = primitive.changed!; - } else if (primitive is PdfStream) { - isContentChanged = primitive.changed!; - } - } else if (contents is PdfArray) { - isContentChanged = contents.changed!; - } - } - return isContentChanged; - } - - Map _addSpace( - TextWord? textwords, - ImageRenderer renderer, - TextElement textElement, - int i, - double? dx, - double? dy, - double? width, - double? height, - ) { - final Rect tempBounds = renderer.imageRenderGlyphList[i].boundingRect; - final Rect glyphBounds = Rect.fromLTWH( - tempBounds.left, - tempBounds.top, - tempBounds.width, - tempBounds.height, - ); - final TextGlyph textGlyph = TextGlyphHelper.initialize( - renderer.imageRenderGlyphList[i].toUnicode, - textElement.fontName, - textElement.fontStyle, - _calculateBounds(glyphBounds), - textElement.fontSize, - renderer.imageRenderGlyphList[i].isRotated, - ); - dx = renderer.imageRenderGlyphList[i].boundingRect.left; - dy = renderer.imageRenderGlyphList[i].boundingRect.top; - height = renderer.imageRenderGlyphList[i].boundingRect.height; - if (dx > renderer.imageRenderGlyphList[i].boundingRect.left) { - width = - (dx - renderer.imageRenderGlyphList[i].boundingRect.left) + - renderer.imageRenderGlyphList[i].boundingRect.width; - } else { - width = - (renderer.imageRenderGlyphList[i].boundingRect.left - dx) + - renderer.imageRenderGlyphList[i].boundingRect.width; - } - return { - 'word': TextWordHelper.initialize( - ' ', - textElement.fontName, - textElement.fontStyle, - [textGlyph], - Rect.fromLTWH(dx, dy, width, height), - textElement.fontSize, - ), - 'dx': dx, - 'dy': dy, - 'width': width, - 'height': height, - }; - } - - List _calculatedTextounds( - List glyphs, - String text, - int index, - PdfPage page, - bool isRTL, - ) { - Rect textBounds = Rect.zero; - if (!isRTL) { - textBounds = _getLTRBounds(glyphs, text, index, page); - } else { - final bool isBidi = bidi.Bidi.hasAnyLtr(text); - String tempString = ''; - if (isBidi) { - final Map textCollection = {}; - final List boundsCollection = []; - int indexValue = index; - for (int i = 0; i < text.length; i++) { - if (i < text.length - 1 && - (((bidi.Bidi.startsWithRtl(text[i]) || text[i] == ' ') && - (glyphs[index + i].boundingRect.left - - (glyphs[index + i + 1].boundingRect.left + - glyphs[index + i + 1].boundingRect.width)) - .abs() < - 0.001) || - (bidi.Bidi.startsWithLtr(text[i]) && - ((glyphs[index + i].boundingRect.left + - glyphs[index + i].boundingRect.width) - - glyphs[index + i + 1].boundingRect.left) - .abs() < - 0.001))) { - tempString += glyphs[index + i].toUnicode; - } else { - tempString += glyphs[index + i].toUnicode; - textCollection[indexValue] = tempString; - indexValue = index + i + 1; - tempString = ''; - } - } - textCollection.forEach((int key, String value) { - if (bidi.Bidi.hasAnyRtl(value)) { - boundsCollection.add( - _calculateBounds(_getRTLBounds(glyphs, value, key, page)), - ); - } else { - boundsCollection.add( - _calculateBounds(_getLTRBounds(glyphs, value, key, page)), - ); - } - }); - return boundsCollection; - } else { - textBounds = _getRTLBounds(glyphs, text, index, page); - } - } - return [_calculateBounds(textBounds)]; - } - - Rect _getLTRBounds(List glyphs, String text, int index, PdfPage page) { - final Glyph startGlyph = glyphs[index]; - double x = startGlyph.boundingRect.left; - double y = startGlyph.boundingRect.top; - double width = 0; - double height = startGlyph.boundingRect.height; - //For complex script glyph mapping - int endIndex = index + text.length - 1; - int length = text.length; - String tempString = ''; - for (int i = 0; i < text.length; i++) { - tempString += glyphs[index + i].toUnicode; - if (tempString == text) { - endIndex = index + i; - length = i + 1; - break; - } - } - final Glyph endGlyph = glyphs[endIndex]; - if (startGlyph.boundingRect.top == endGlyph.boundingRect.top || - (startGlyph.boundingRect.top - endGlyph.boundingRect.top).abs() < - 0.001) { - if (x > endGlyph.boundingRect.left) { - width = (x - endGlyph.boundingRect.left) + endGlyph.boundingRect.width; - if (page.rotation == PdfPageRotateAngle.rotateAngle0 || - page.rotation == PdfPageRotateAngle.rotateAngle180) { - width = startGlyph.boundingRect.height; - for (int i = 0; i < length; i++) { - height += glyphs[index + i].boundingRect.width; - if (glyphs[index + i].boundingRect.height > width) { - width = glyphs[index + i].boundingRect.height; - } - } - } else { - width = startGlyph.boundingRect.width; - for (int i = 0; i < length; i++) { - height += glyphs[index + i].boundingRect.height; - if (glyphs[index + i].boundingRect.width > width) { - width = glyphs[index + i].boundingRect.width; - } - } - } - x -= width; - } else { - width = (endGlyph.boundingRect.left - x) + endGlyph.boundingRect.width; - } - } else if (startGlyph.boundingRect.left == endGlyph.boundingRect.left || - (startGlyph.boundingRect.left - endGlyph.boundingRect.left).abs() < - 0.001) { - if (startGlyph.boundingRect.top != endGlyph.boundingRect.top && - !((startGlyph.boundingRect.top - endGlyph.boundingRect.top).abs() < - 0.001)) { - height = 0; - if (page.rotation == PdfPageRotateAngle.rotateAngle0 || - page.rotation == PdfPageRotateAngle.rotateAngle180) { - width = startGlyph.boundingRect.height; - for (int i = 0; i < length; i++) { - height += glyphs[index + i].boundingRect.width; - if (glyphs[index + i].boundingRect.height > 0) { - width = glyphs[index + i].boundingRect.height; - } - } - } else { - width = startGlyph.boundingRect.width; - for (int i = 0; i < length; i++) { - height += glyphs[index + i].boundingRect.height; - width = glyphs[index + i].boundingRect.width; - } - } - if (y > endGlyph.boundingRect.top || startGlyph.rotationAngle == 270) { - x = startGlyph.boundingRect.left - width + 1; - y = startGlyph.boundingRect.top - height; - } else if (y < endGlyph.boundingRect.top || - startGlyph.rotationAngle == 90) { - x = startGlyph.boundingRect.left - 1; - y = startGlyph.boundingRect.top; - } - } - } - return Rect.fromLTWH(x, y, width, height); - } - - Rect _getRTLBounds(List glyphs, String text, int index, PdfPage page) { - final Glyph startGlyph = glyphs[index]; - double x = startGlyph.boundingRect.left; - final double y = startGlyph.boundingRect.top; - double width = 0; - final double height = startGlyph.boundingRect.height; - //For complex script glyph mapping - int endIndex = index + text.length - 1; - String tempString = ''; - for (int i = 0; i < text.length; i++) { - tempString += glyphs[index + i].toUnicode; - if (tempString == text) { - endIndex = index + i; - break; - } - } - final Glyph endGlyph = glyphs[endIndex]; - if (startGlyph.boundingRect.top == endGlyph.boundingRect.top || - (startGlyph.boundingRect.top - endGlyph.boundingRect.top).abs() < - 0.001) { - width = (x - endGlyph.boundingRect.left) + startGlyph.boundingRect.width; - x = startGlyph.boundingRect.left + startGlyph.boundingRect.width - width; - } - return Rect.fromLTWH(x, y, width, height); - } - - bool _hasEscapeCharacter(String text) { - return text.contains(' ') || - text.contains(r'\u0007') || - text.contains(r'\') || - text.contains(r'\b') || - text.contains(r'\f') || - text.contains(r'\r') || - text.contains(r'\t') || - text.contains(r'\n') || - text.contains(r'\v') || - text.contains(r"\'") || - text.contains(r'\u0000'); - } - - Rect _calculateBounds(Rect bounds) { - if (_currentPage != null) { - if (!PdfPageHelper.getHelper(_currentPage!).cropBox.isEmpty && - PdfPageHelper.getHelper(_currentPage!).cropBox != - PdfPageHelper.getHelper(_currentPage!).mediaBox) { - final double x = - bounds.left - PdfPageHelper.getHelper(_currentPage!).cropBox.left; - final double y = - bounds.top + PdfPageHelper.getHelper(_currentPage!).cropBox.top; - return Rect.fromLTWH(x, y, bounds.width, bounds.height); - } else if (!PdfPageHelper.getHelper(_currentPage!).mediaBox.isEmpty && - (PdfPageHelper.getHelper(_currentPage!).mediaBox.left != 0 || - PdfPageHelper.getHelper(_currentPage!).mediaBox.top != 0)) { - final double cLeft = - PdfPageHelper.getHelper(_currentPage!).mediaBox.left; - final double ctop = PdfPageHelper.getHelper(_currentPage!).mediaBox.top; - final double x = bounds.left - cLeft; - final double y = bounds.top + ctop; - return Rect.fromLTWH(x, y, bounds.width, bounds.height); - } - } - return bounds; - } - - TextLine _prepareTextLine( - TextLine textLine, - ImageRenderer renderer, - int lineStartIndex, - int glyphIndex, - double rotation, - ) { - bool isSameFontName = true; - bool isSameFontSize = true; - bool isSameFontStyle = true; - String? fontName = ''; - double? fontSize = 0; - textLine.pageIndex = _currentPageIndex; - List? fontStyle = [PdfFontStyle.regular]; - if (rotation == 270 && - renderer.imageRenderGlyphList[lineStartIndex].isRotated) { - textLine.bounds = Rect.fromLTWH( - renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left, - renderer.imageRenderGlyphList[lineStartIndex].boundingRect.top, - renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.width, - renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.bottom - - renderer.imageRenderGlyphList[lineStartIndex].boundingRect.top, - ); - } else { - textLine.bounds = Rect.fromLTWH( - renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left, - renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.top, - renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.right - - renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left, - renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.height, - ); - } - textLine.bounds = _calculateBounds(textLine.bounds); - Rect? prevBounds; - for (int i = 0; i < textLine.wordCollection.length; i++) { - final TextWord word = textLine.wordCollection[i]; - if (i == 0) { - fontName = word.fontName; - fontSize = word.fontSize; - fontStyle = word.fontStyle; - } - if (prevBounds != null && - (prevBounds.left + prevBounds.width - word.bounds.left).abs() > 1 && - !textLine.text.endsWith(' ') && - !bidi.Bidi.hasAnyRtl(textLine.text)) { - textLine.text += ' '; - } - textLine.text += word.text; - prevBounds = word.bounds; - if (fontName == word.fontName && isSameFontName) { - textLine.fontName = fontName!; - } else { - isSameFontName = false; - textLine.fontName = ''; - } - if (fontSize == word.fontSize && isSameFontSize) { - textLine.fontSize = fontSize!; - } else { - isSameFontSize = false; - textLine.fontSize = 0; - } - - if (fontStyle == word.fontStyle && isSameFontStyle) { - textLine.fontStyle = fontStyle!; - } else { - isSameFontStyle = false; - textLine.fontStyle = [PdfFontStyle.regular]; - } - if (!isSameFontName) { - isSameFontName = true; - } - if (!isSameFontSize) { - isSameFontSize = true; - } - if (!isSameFontStyle) { - isSameFontStyle = true; - } - } - if (textLine.text.isNotEmpty && bidi.Bidi.hasAnyRtl(textLine.text)) { - textLine.text = - _bidi.getLogicalToVisualString(textLine.text, true)['rtlText'] - as String; - } - return textLine; - } - - String _renderText( - PdfRecordCollection? recordCollection, - PdfPageResources pageResources, - ) { - String resultantText = ''; - if (recordCollection != null && - recordCollection.recordCollection.isNotEmpty) { - final List records = recordCollection.recordCollection; - for (int i = 0; i < records.length; i++) { - final PdfRecord record = records[i]; - final String token = record.operatorName!; - final List? elements = record.operands; - for (int j = 0; j < _symbolChars.length; j++) { - if (token.contains(_symbolChars[j])) { - token.replaceAll(_symbolChars[j], ''); - } - } - switch (token.trim()) { - case 'T*': - { - resultantText += '\r\n'; - break; - } - case 'Tf': - { - _renderFont(elements!, pageResources); - break; - } - case 'ET': - { - resultantText += '\r\n'; - break; - } - case 'BDC': - { - if (elements != null && - elements.length > 1 && - elements[1].contains('ActualText') && - elements[1].contains('(')) { - _initializeActualText(elements[1]); - } - break; - } - case 'EMC': - _actualText = null; - break; - case 'Tj': - case 'TJ': - case "'": - { - final String? resultText = - (_actualText != null && _actualText!.isNotEmpty) - ? _actualText - : _renderTextElement( - elements!, - token, - pageResources, - null, - ); - if (resultText != null) { - resultantText += resultText; - } - if (token == "'") { - resultantText += '\r\n'; - } - break; - } - case 'Do': - { - final String? result = _getXObject( - resultantText, - elements!, - pageResources, - ); - if (result != null && result != '') { - resultantText += result; - } - break; - } - default: - break; - } - } - } - return resultantText; - } - - String _renderTextAsLayout( - PdfRecordCollection? recordCollection, - PdfPageResources pageResources, - ) { - double? currentMatrixY = 0; - double? prevMatrixY = 0; - double? currentY = 0; - double? prevY = 0; - double differenceX = 0; - String? currentText = ''; - bool hasTj = false; - bool hasTm = false; - _hasBDC = false; - String resultantText = ''; - double? textLeading = 0; - double? horizontalScaling = 100; - bool hasNoSpacing = false; - bool spaceBetweenWord = false; - bool isSpaceAdded = false; - _tempBoundingRectangle = Rect.zero; - if (recordCollection != null && - recordCollection.recordCollection.isNotEmpty) { - final List records = recordCollection.recordCollection; - for (int i = 0; i < records.length; i++) { - final PdfRecord record = records[i]; - final String token = record.operatorName!; - final List? elements = record.operands; - for (int j = 0; j < _symbolChars.length; j++) { - if (token.contains(_symbolChars[j])) { - token.replaceAll(_symbolChars[j], ''); - } - } - switch (token.trim()) { - case 'q': - { - _hasET = false; - break; - } - case 'Tw': - { - _wordSpacing = double.tryParse(elements![0])!; - break; - } - case 'Tc': - { - _characterSpacing = double.tryParse(elements![0])!; - break; - } - case 'Tm': - { - hasTm = true; - final double a = double.tryParse(elements![0])!; - final double b = double.tryParse(elements[1])!; - final double c = double.tryParse(elements[2])!; - final double d = double.tryParse(elements[3])!; - final double e = double.tryParse(elements[4])!; - final double f = double.tryParse(elements[5])!; - _textLineMatrix = MatrixHelper(a, b, c, d, e, f); - _textMatrix = MatrixHelper(a, b, c, d, e, f); - if (_textMatrix!.offsetY == _textLineMatrix!.offsetY && - _textMatrix!.offsetX != _textLineMatrix!.offsetX) { - _textLineMatrix = _textMatrix!.clone(); - } - if (_textLineMatrix!.offsetY != _currentTextMatrix!.offsetY || - ((_textLineMatrix!.offsetX != _currentTextMatrix!.offsetX) && - _hasBDC && - !hasTj)) { - _tempBoundingRectangle = Rect.zero; - _hasBDC = false; - } - break; - } - case 'TL': - { - textLeading = -double.tryParse(elements![0])!; - break; - } - case 'cm': - { - _hasET = false; - currentMatrixY = double.tryParse(elements![5]); - final int current = currentMatrixY!.toInt(); - final int prev = prevMatrixY!.toInt(); - final int locationY = (current - prev) ~/ 10; - if ((current != prev) && - hasTm && - (locationY < 0 || locationY >= 1) && - resultantText.isNotEmpty && - !resultantText.endsWith('\n')) { - resultantText += '\r\n'; - hasTm = false; - } - prevMatrixY = currentMatrixY; - break; - } - case 'BDC': - { - _hasBDC = true; - if (elements != null && - elements.length > 1 && - elements[1].contains('ActualText') && - elements[1].contains('(')) { - _initializeActualText(elements[1]); - } else { - _hasET = true; - } - break; - } - case 'EMC': - _actualText = null; - break; - case 'TD': - { - textLeading = double.tryParse(elements![1]); - _textMatrix = - MatrixHelper( - 1, - 0, - 0, - 1, - double.tryParse(elements[0])!, - double.tryParse(elements[1])!, - ) * - _textLineMatrix!; - _textLineMatrix = _textMatrix!.clone(); - if (_textLineMatrix!.offsetY != _currentTextMatrix!.offsetY || - (_hasBDC && - _textLineMatrix!.offsetX != _currentTextMatrix!.offsetX && - !hasTj)) { - _tempBoundingRectangle = Rect.zero; - _hasBDC = false; - } - break; - } - case 'Td': - { - _textMatrix = - MatrixHelper( - 1, - 0, - 0, - 1, - double.tryParse(elements![0])!, - double.tryParse(elements[1])!, - ) * - _textLineMatrix!; - _textLineMatrix = _textMatrix!.clone(); - if (_textLineMatrix!.offsetY != _currentTextMatrix!.offsetY || - (_hasBDC && - _textLineMatrix!.offsetX != - _currentTextMatrix!.offsetX)) { - _tempBoundingRectangle = Rect.zero; - _hasBDC = false; - } - if ((_textLineMatrix!.offsetX - _currentTextMatrix!.offsetX) - .abs() > - 0 && - !spaceBetweenWord && - hasTj) { - differenceX = - _textLineMatrix!.offsetX - _currentTextMatrix!.offsetX; - spaceBetweenWord = true; - } - break; - } - case 'Tz': - { - horizontalScaling = double.tryParse(elements![0]); - break; - } - case 'BT': - { - _textMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - _textLineMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - break; - } - case 'T*': - { - _textMatrix = - MatrixHelper(1, 0, 0, 1, 0, textLeading!) * _textLineMatrix!; - _textLineMatrix = _textMatrix!.clone(); - break; - } - case 'Tf': - { - _renderFont(elements!, pageResources); - break; - } - case 'ET': - { - _hasET = true; - final double endTextPosition = - (_textLineMatrix!.offsetX - _tempBoundingRectangle!.right) / - 10; - if (_hasLeading && endTextPosition == 0 && hasNoSpacing) { - resultantText += ' '; - _tempBoundingRectangle = Rect.zero; - _hasLeading = false; - isSpaceAdded = true; - } - break; - } - case 'Tj': - case 'TJ': - { - final String currentToken = token.trim(); - currentY = _textMatrix!.offsetY; - double difference = 0; - if (_fontSize! >= 10) { - difference = ((currentY - prevY!) / 10).round().toDouble(); - } else { - difference = - ((currentY - prevY!) / _fontSize!).round().toDouble(); - } - if (difference < 0) { - difference = -difference; - } - if (prevY != 0 && difference >= 1) { - if (resultantText.isNotEmpty && !resultantText.endsWith('\n')) { - resultantText += '\r\n'; - } - } else if (spaceBetweenWord) { - if (differenceX > _fontSize!) { - differenceX = 0; - } - bool isEncoded = true; - if (elements != null) { - final String text = elements.join(); - isEncoded = - text[0] != '(' || - (text[0] == '(' && _hasOctalEscape(text)); - } - if (currentToken == 'Tj' && - (_hasET || !isEncoded) && - resultantText.isNotEmpty && - !resultantText.endsWith(' ')) { - resultantText += ' '; - } - } - spaceBetweenWord = false; - hasTj = true; - currentText = - currentToken == 'TJ' - ? _renderTextElementTJ( - elements!, - token, - pageResources, - horizontalScaling, - ) - : _renderTextElement( - elements!, - token, - pageResources, - horizontalScaling, - ); - if (_actualText != null && _actualText!.isNotEmpty) { - currentText = _actualText; - _actualText = null; - } - _currentTextMatrix = _textLineMatrix!.clone(); - prevY = currentY; - resultantText += currentText!; - if (currentToken == 'TJ' && - _textLineMatrix!.m11 != 1 && - _textLineMatrix!.m22 != 1 && - _hasET && - currentText.isNotEmpty) { - resultantText += ' '; - } - _hasET = false; - _textMatrix = _textLineMatrix!.clone(); - if (currentToken == 'TJ') { - _hasBDC = false; - } - break; - } - case "'": - { - currentY = _textMatrix!.offsetY; - hasNoSpacing = false; - double difference = 0; - if (_fontSize! >= 10) { - difference = ((currentY - prevY!) / 10).round().toDouble(); - } else { - difference = - ((currentY - prevY!) / _fontSize!).round().toDouble(); - } - if (difference < 0) { - difference = -difference; - } - _hasLeading = true; - if (prevY != 0 && - (difference >= 1 || - (i > 0 && records[i - 1].operatorName! == "'")) && - resultantText.isNotEmpty && - !resultantText.endsWith('\n')) { - if (isSpaceAdded && - resultantText.isNotEmpty && - resultantText.endsWith(' ')) { - resultantText = resultantText.substring( - 0, - resultantText.length - 1, - ); - } - resultantText += '\r\n'; - } - isSpaceAdded = false; - prevY = currentY; - final int currentXPosition = _textLineMatrix!.offsetX - .toInt() - .toSigned(64); - final int prevXPosition = _currentTextMatrix!.offsetX - .toInt() - .toSigned(64); - if ((prevXPosition - currentXPosition) > 0) { - hasNoSpacing = true; - } - _textMatrix = - MatrixHelper(1, 0, 0, 1, 0, textLeading!) * _textLineMatrix!; - _textLineMatrix = _textMatrix!.clone(); - currentText = _renderTextElement( - elements!, - token, - pageResources, - horizontalScaling, - ); - _currentTextMatrix = _textLineMatrix!.clone(); - resultantText += currentText!; - break; - } - case 'Do': - { - final String? result = _getXObject( - resultantText, - elements!, - pageResources, - ); - if (result != null && result != '') { - resultantText += result; - } - break; - } - default: - break; - } - } - } - if (isSpaceAdded && - resultantText.isNotEmpty && - resultantText.endsWith(' ')) { - resultantText = resultantText.substring(0, resultantText.length - 1); - } - return resultantText - .replaceAll(RegExp(r' {2,}'), ' ') - .replaceAll(' \r\n', '\r\n'); - } - - bool _hasOctalEscape(String input) { - final RegExp octalPattern = RegExp(r'\\[0-7]{1,3}'); - return octalPattern.hasMatch(input); - } - - void _initializeActualText(String text) { - _actualText = text.substring(text.indexOf('(') + 1, text.lastIndexOf(')')); - const String bigEndianPreambleString = 'þÿ'; - if (_actualText != null && - _actualText!.startsWith(bigEndianPreambleString)) { - _actualText = null; - } - } - - String _skipEscapeSequence(String text) { - int index = -1; - do { - index = text.indexOf(r'\', index + 1); - if (text.length > index + 1) { - final String nextLiteral = text[index + 1]; - if (index >= 0 && - (nextLiteral == r'\' || nextLiteral == '(' || nextLiteral == ')')) { - text = text.replaceFirst(text[index], '', index); - } - } else { - text = text.replaceFirst(text[index], '', index); - index = -1; - } - } while (index >= 0); - return text; - } - - void _renderFont(List elements, PdfPageResources resources) { - int i = 0; - for (i = 0; i < elements.length; i++) { - if (elements[i].contains('/')) { - _currentFont = elements[i].replaceAll('/', ''); - break; - } - } - _fontSize = double.tryParse(elements[i + 1]); - if (resources.containsKey(_currentFont)) { - final FontStructure structure = resources[_currentFont!] as FontStructure; - if (structure.isStandardFont) { - structure.createStandardFont(_fontSize!); - } else if (structure.isStandardCJKFont) { - structure.createStandardCJKFont(_fontSize!); - } - } - } - - String _renderTextElementTJ( - List elements, - String tokenType, - PdfPageResources pageResources, - double? horizontalScaling, - ) { - List decodedList = []; - Map?, String> decodedListCollection = ?, String>{}; - final String text = elements.join(); - String tempText = ''; - if (pageResources.containsKey(_currentFont)) { - FontStructure? fontStructure; - final dynamic returnValue = pageResources[_currentFont!]; - if (returnValue != null && returnValue is FontStructure) { - fontStructure = returnValue; - } - fontStructure!.isTextExtraction = true; - fontStructure.isLayout = _isLayout; - fontStructure.fontSize = _fontSize; - if (!fontStructure.isEmbedded && - fontStructure.isStandardCJKFont && - fontStructure.font != null) { - decodedList = fontStructure.decodeCjkTextExtractionTJ( - text, - pageResources.isSameFont(), - ); - } else { - decodedListCollection = fontStructure.decodeTextExtractionTJ( - text, - pageResources.isSameFont(), - ); - decodedList = decodedListCollection.values.toList(); - } - fontStructure.isTextExtraction = false; - tempText = _renderTextFromTJ( - decodedList, - horizontalScaling, - fontStructure, - ); - if (bidi.Bidi.hasAnyRtl(tempText)) { - tempText = - _bidi.getLogicalToVisualString(tempText, true)['rtlText'] as String; - } - } - return tempText; - } - - String _renderTextFromTJ( - List decodedList, - double? horizontalScaling, - FontStructure? fontStructure, - ) { - String extractedText = ''; - for (String word in decodedList) { - final double? space = double.tryParse(word); - if (space != null) { - _textLineMatrix = _updateTextMatrixWithSpacing( - space, - horizontalScaling!, - ); - if ((_textLineMatrix!.offsetX - _textMatrix!.offsetX).toInt() > 1 && - !_hasBDC) { - extractedText += ' '; - } - } else { - double characterWidth = 1.0; - if (word != '' && word[word.length - 1] == 's') { - word = word.substring(0, word.length - 1); - } - if (fontStructure != null && - fontStructure.fontEncoding == 'MacRomanEncoding') { - String tempstring = ''; - for (int i = 0; i < word.length; i++) { - final int b = word[i].codeUnitAt(0).toUnsigned(8); - if (b > 126) { - final String x = fontStructure.macEncodeTable![b]!; - tempstring += x; - } else { - tempstring += word[i]; - } - } - if (tempstring != '') { - word = tempstring; - } - } - for (int i = 0; i < word.length; i++) { - final String renderedCharacter = word[i]; - MatrixHelper transform = MatrixHelper(1, 0, 0, 1, 0, 0); - if (!fontStructure!.isEmbedded && - fontStructure.isStandardFont && - fontStructure.font != null) { - final PdfStandardFont font = fontStructure.font! as PdfStandardFont; - characterWidth = - PdfStandardFontHelper.getHelper( - font, - ).getCharWidthInternal(renderedCharacter) * - PdfFontHelper.characterSizeMultiplier; - } else if (!fontStructure.isEmbedded && - fontStructure.isStandardCJKFont && - fontStructure.font != null) { - final PdfCjkStandardFont font = - fontStructure.font! as PdfCjkStandardFont; - characterWidth = - PdfCjkStandardFontHelper.getHelper( - font, - ).getCharWidthInternal(renderedCharacter) * - PdfFontHelper.characterSizeMultiplier; - } else { - characterWidth = _getCharacterWidth( - renderedCharacter, - fontStructure, - ); - } - _textMatrix = _getTextRenderingMatrix(horizontalScaling!); - final MatrixHelper identity = MatrixHelper.identity.clone(); - identity.scale(0.01, 0.01, 0.0, 0.0); - identity.translate(0.0, 1.0); - final MatrixHelper matrix = transform.clone(); - transform = matrix; - double? tempFontSize; - if (_textMatrix!.m11 > 0) { - tempFontSize = _textMatrix!.m11; - } else if (_textMatrix!.m12 != 0 && _textMatrix!.m21 != 0) { - if (_textMatrix!.m12 < 0) { - tempFontSize = -_textMatrix!.m12; - } else { - tempFontSize = _textMatrix!.m12; - } - } else { - tempFontSize = _fontSize; - } - final Rect boundingRect = Rect.fromLTWH( - matrix.offsetX / 1.3333333333333333, - (matrix.offsetY - tempFontSize!) / 1.3333333333333333, - characterWidth * tempFontSize, - tempFontSize, - ); - if (_tempBoundingRectangle != null) { - final double boundingDifference = - ((boundingRect.left - _tempBoundingRectangle!.right) / 10) - .round() - .toDouble(); - if ((_tempBoundingRectangle!.right != 0 && - boundingRect.left != 0) && - boundingDifference >= 1 && - _hasLeading) { - extractedText += ' '; - } - } - extractedText += renderedCharacter; - _textLineMatrix = _updateTextMatrix( - characterWidth, - horizontalScaling, - ); - _tempBoundingRectangle = boundingRect; - _textMatrix = _textLineMatrix!.clone(); - } - } - } - return extractedText; - } - - String? _renderTextElement( - List elements, - String tokenType, - PdfPageResources pageResources, - double? horizontalScaling, - ) { - try { - String text = elements.join(); - if (!pageResources.containsKey(_currentFont)) { - if (_currentFont != null && _currentFont!.contains('-')) { - _currentFont = _currentFont!.replaceAll('-', '#2D'); - } - } - if (pageResources.containsKey(_currentFont)) { - FontStructure? fontStructure; - final dynamic returnValue = pageResources[_currentFont!]; - if (returnValue != null && returnValue is FontStructure) { - fontStructure = returnValue; - } - fontStructure!.isTextExtraction = true; - fontStructure.fontSize = _fontSize; - text = fontStructure.decodeTextExtraction(text, true); - if (_isLayout) { - text = _renderTextFromLeading( - text, - _textLineMatrix, - fontStructure, - horizontalScaling, - ); - } - fontStructure.isTextExtraction = false; - } - if (bidi.Bidi.hasAnyRtl(text)) { - text = _bidi.getLogicalToVisualString(text, true)['rtlText'] as String; - } - return text; - } catch (e) { - return null; - } - } - - String _renderTextFromLeading( - String decodedText, - MatrixHelper? textLineMatrix, - FontStructure structure, [ - double? horizontalScaling = 100, - ]) { - String extractedText = ''; - for (int i = 0; i < decodedText.length; i++) { - final String ch = decodedText[i]; - double characterWidth; - if (structure.isStandardFont) { - final PdfStandardFont font = structure.font! as PdfStandardFont; - characterWidth = - PdfStandardFontHelper.getHelper(font).getCharWidthInternal(ch) * - PdfFontHelper.characterSizeMultiplier; - } else if (structure.isStandardCJKFont) { - final PdfCjkStandardFont font = structure.font! as PdfCjkStandardFont; - characterWidth = - PdfCjkStandardFontHelper.getHelper(font).getCharWidthInternal(ch) * - PdfFontHelper.characterSizeMultiplier; - } else { - characterWidth = _getCharacterWidth(ch, structure); - } - _textMatrix = _getTextRenderingMatrix(horizontalScaling!); - final MatrixHelper identity = MatrixHelper.identity; - identity.scale(0.01, 0.01, 0.0, 0.0); - identity.translate(0.0, 1.0); - MatrixHelper tranformation = identity * _textMatrix!; - if (_initialTransform != null) { - tranformation = tranformation * _initialTransform!; - } - MatrixHelper matrix = MatrixHelper(1, 0, 0, 1, 0, 0); - matrix = matrix * tranformation; - double? tempFontSize; - if (_textMatrix!.m11 > 0) { - tempFontSize = _textMatrix!.m11; - } else if (_textMatrix!.m12 != 0 && _textMatrix!.m21 != 0) { - if (_textMatrix!.m12 < 0) { - tempFontSize = -_textMatrix!.m12; - } else { - tempFontSize = _textMatrix!.m12; - } - } else { - tempFontSize = structure.fontSize; - } - final Rect boundingRect = Rect.fromLTWH( - matrix.offsetX / 1.3333333333333333, - (matrix.offsetY - tempFontSize!) / 1.3333333333333333, - characterWidth * tempFontSize, - tempFontSize, - ); - if (_tempBoundingRectangle != null) { - final double boundingDifference = - ((boundingRect.left - _tempBoundingRectangle!.right) / 10) - .round() - .toDouble(); - if ((_tempBoundingRectangle!.right != 0 && boundingRect.left != 0) && - boundingDifference >= 1 && - _hasLeading) { - extractedText += ' '; - } - } - extractedText += ch; - _textLineMatrix = _updateTextMatrix(characterWidth, 100); - _tempBoundingRectangle = boundingRect; - } - return extractedText; - } - - String? _getXObject( - String resultantText, - List xobjectElement, - PdfPageResources pageResources, - ) { - String? result; - final String key = xobjectElement[0].replaceAll('/', ''); - if (pageResources.containsKey(key)) { - final dynamic element = pageResources[key]; - if (element is XObjectElement) { - final PdfRecordCollection collection = element.render(pageResources)!; - final PdfDictionary xobjects = element.dictionary!; - PdfPageResources childResource = PdfPageResources(); - if (xobjects.containsKey(PdfDictionaryProperties.resources)) { - PdfDictionary? pageDictionary = PdfDictionary(); - final IPdfPrimitive? resource = - xobjects[PdfDictionaryProperties.resources]; - if (resource is PdfReferenceHolder && - resource.object is PdfDictionary) { - pageDictionary = resource.object as PdfDictionary?; - } else if (resource is PdfDictionary) { - pageDictionary = resource; - } - childResource = _resourceLoader.updatePageResources( - childResource, - _resourceLoader.getFormResources(pageDictionary), - ); - childResource = _resourceLoader.updatePageResources( - childResource, - _resourceLoader.getFontResources(pageDictionary, _currentPage), - ); - } else { - childResource = _updateFontResources(pageResources); - } - if (_isLayout) { - result = '${_renderTextAsLayout(collection, childResource)}\r\n'; - } else { - result = _renderText(collection, childResource); - } - collection.recordCollection.clear(); - } - } - return result; - } - - PdfPageResources _updateFontResources(PdfPageResources pageResources) { - final PdfPageResources resources = PdfPageResources(); - pageResources.resources.forEach((String? key, dynamic value) { - if (value is FontStructure) { - resources.resources[key] = value; - resources.fontCollection[key] = value; - } - }); - return resources; - } - - MatrixHelper? _updateTextMatrixWithSpacing( - double space, - double horizontalScaling, - ) { - final double x = -(space * 0.001 * _fontSize! * horizontalScaling / 100); - final Offset point = _textLineMatrix!.transform(Offset.zero); - final Offset point2 = _textLineMatrix!.transform(Offset(x, 0.0)); - if (point.dx != point2.dx) { - _textLineMatrix!.offsetX = point2.dx; - } else { - _textLineMatrix!.offsetY = point2.dy; - } - return _textLineMatrix; - } - - MatrixHelper _getTextRenderingMatrix(double textHorizontalScaling) { - return MatrixHelper( - _fontSize! * (textHorizontalScaling / 100), - 0, - 0, - -_fontSize!, - 0, - _fontSize!, - ) * - _textLineMatrix! * - _currentTransformationMatrix; - } - - double _getCharacterWidth(String character, FontStructure structure) { - final int charID = character.codeUnitAt(0); - return (structure.fontGlyphWidths != null && - structure.fontType!.name == 'TrueType' && - structure.fontGlyphWidths!.containsKey(charID)) - ? structure.fontGlyphWidths![charID]! * 0.001 - : 1.0; - } - - MatrixHelper _updateTextMatrix( - double characterWidth, - double horizontalScaling, - ) { - final double offsetX = - (characterWidth * _fontSize! + _characterSpacing + _wordSpacing) * - (horizontalScaling / 100); - return MatrixHelper(1.0, 0.0, 0.0, 1.0, offsetX, 0.0) * _textLineMatrix!; - } - - double _getPageRotation(PdfPage page) { - if (page.rotation == PdfPageRotateAngle.rotateAngle90) { - return 90; - } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { - return 180; - } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { - return 270; - } else { - return 0; - } - } -} +import 'dart:ui'; + +import 'package:intl/intl.dart' as bidi; + +import '../../../interfaces/pdf_interface.dart'; +import '../../graphics/fonts/enums.dart'; +import '../../graphics/fonts/pdf_cjk_standard_font.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_standard_font.dart'; +import '../../graphics/fonts/rtl/arabic_shape_renderer.dart'; +import '../../graphics/fonts/rtl/bidi.dart'; +import '../../graphics/pdf_color.dart'; +import '../../io/pdf_constants.dart'; +import '../../pages/enum.dart'; +import '../../pages/pdf_page.dart'; +import '../../pages/pdf_page_layer_collection.dart'; +import '../../pdf_document/pdf_document.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_stream.dart'; +import 'enums.dart'; +import 'font_structure.dart'; +import 'glyph.dart'; +import 'image_renderer.dart'; +import 'matched_item.dart'; +import 'matrix_helper.dart'; +import 'page_resource_loader.dart'; +import 'parser/content_parser.dart'; +import 'text_element.dart'; +import 'text_glyph.dart'; +import 'text_line.dart'; +import 'text_word.dart'; +import 'xobject_element.dart'; + +/// Represents a text extractor from an existing PDF document +class PdfTextExtractor { + //Constructor + /// Initialize a new instance of the [PdfTextExtractor] class + /// from the instance of [PdfDocument] + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData); + /// //Extract text from all pages + /// String text = PdfTextExtractor(document).extractText(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfTextExtractor(PdfDocument document) { + if (!PdfDocumentHelper.getHelper(document).isLoadedDocument) { + ArgumentError.value( + document, + 'document', + 'document instance is not a loaded PDF document', + ); + } + _document = document; + _initialize(); + } + + //Fields + late PdfDocument _document; + late List _symbolChars; + String? _currentFont; + double? _fontSize; + PdfPage? _currentPage; + late PageResourceLoader _resourceLoader; + late int _currentPageIndex; + bool _isLayout = false; + double _characterSpacing = 0; + double _wordSpacing = 0; + MatrixHelper? _textLineMatrix; + late MatrixHelper? _textMatrix; + late MatrixHelper? _currentTextMatrix; + Rect? _tempBoundingRectangle; + bool _hasLeading = false; + bool _hasET = false; + late MatrixHelper _currentTransformationMatrix; + bool _hasBDC = false; + Bidi? _bidiInstance; + MatrixHelper? _initialTransform; + String? _actualText; + + //Properties + Bidi get _bidi { + _bidiInstance ??= Bidi(); + return _bidiInstance!; + } + + //Public methods + /// Extract text from an existing PDF document + /// + /// startPageIndex and endPageIndex specifies the page range to be selected + /// to extract text. + /// for example, startPageIndex is 0 and endPageIndex is 9 + /// is used to extract text from first page to 10 page of loaded PDF + /// + /// for extracting text from particular page, + /// we can set an index of the page to startPageIndex + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData); + /// //Extract text from all pages + /// String text = PdfTextExtractor(document).extractText(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String extractText({ + int? startPageIndex, + int? endPageIndex, + bool? layoutText, + }) { + _isLayout = layoutText ?? false; + return _extractText(startPageIndex, endPageIndex); + } + + /// Extract [TextLine] from an existing PDF document + /// + /// startPageIndex and endPageIndex specifies the page range to be selected + /// to extract text line. + /// for example, startPageIndex is 0 and endPageIndex is 9 + /// is used to extract text line from first page to 10 page of loaded PDF + /// + /// for extracting text line from particular page, + /// we can set an index of the page to startPageIndex + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData); + /// //Extract text from all pages + /// List textLine = PdfTextExtractor(document).extractTextLines(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + List extractTextLines({int? startPageIndex, int? endPageIndex}) { + return _extractTextLines(startPageIndex, endPageIndex); + } + + /// Returns the information of the matched texts in a specific page + /// based on the list of string to be searched + /// + /// startPageIndex and endPageIndex specifies the page range to be selected + /// to find text. + /// for example, startPageIndex is 0 and endPageIndex is 9 + /// is used to find text from first page to 10 page of loaded PDF + /// + /// for finding text and get matched item from particular page, + /// we can set an index of the page to startPageIndex + /// + /// search option defines the constants that specify the option + /// for text search + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData); + /// //list of string to be searched. + /// List searchString = ['text1', 'text2']; + /// //Find text and get matched items. + /// List textLine = PdfTextExtractor(document).findText(searchString); + /// //Dispose the document. + /// document.dispose(); + /// ``` + List findText( + List searchString, { + int? startPageIndex, + int? endPageIndex, + TextSearchOption? searchOption, + }) { + return _findText(searchString, startPageIndex, endPageIndex, searchOption); + } + + //Implementation + void _checkPageNumber(int pageNumber) { + if (pageNumber < 0 || pageNumber >= _document.pages.count) { + throw ArgumentError.value(pageNumber, 'pageNumber', 'Index out of range'); + } + } + + void _initialize() { + _symbolChars = ['(', ')', '[', ']', '<', '>']; + _resourceLoader = PageResourceLoader(); + _currentTextMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + _textLineMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + _textMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + _tempBoundingRectangle = Rect.zero; + _currentTransformationMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + } + + String _extractText(int? startPageIndex, int? endPageIndex) { + if (startPageIndex == null) { + if (endPageIndex != null) { + throw ArgumentError.value( + endPageIndex, + 'endPageIndex', + 'Invalid argument. start page index cannot be null', + ); + } else { + return _extractTextFromRange(0, _document.pages.count - 1); + } + } else if (endPageIndex == null) { + _checkPageNumber(startPageIndex); + _currentPageIndex = startPageIndex; + return _getText(_document.pages[startPageIndex]); + } else { + _checkPageNumber(startPageIndex); + _checkPageNumber(endPageIndex); + return _extractTextFromRange(startPageIndex, endPageIndex); + } + } + + List _extractTextLines(int? startPageIndex, int? endPageIndex) { + if (startPageIndex == null) { + if (endPageIndex != null) { + throw ArgumentError.value( + endPageIndex, + 'endPageIndex', + 'Invalid argument. start page index cannot be null', + ); + } else { + return _extractTextLineFromRange(0, _document.pages.count - 1); + } + } else if (endPageIndex == null) { + _checkPageNumber(startPageIndex); + _currentPageIndex = startPageIndex; + return _getTextLine(_document.pages[startPageIndex]); + } else { + _checkPageNumber(startPageIndex); + _checkPageNumber(endPageIndex); + return _extractTextLineFromRange(startPageIndex, endPageIndex); + } + } + + List _findText( + List searchString, + int? startPageIndex, + int? endPageIndex, + TextSearchOption? searchOption, + ) { + if (startPageIndex == null) { + if (endPageIndex != null) { + throw ArgumentError.value( + endPageIndex, + 'endPageIndex', + 'Invalid argument. start page index cannot be null', + ); + } else { + return _findTextFromRange( + 0, + _document.pages.count - 1, + searchString, + searchOption, + ); + } + } else if (endPageIndex == null) { + _checkPageNumber(startPageIndex); + _currentPageIndex = startPageIndex; + return _searchInBackground( + _document.pages[startPageIndex], + searchString, + searchOption, + ); + } else { + _checkPageNumber(startPageIndex); + _checkPageNumber(endPageIndex); + return _findTextFromRange( + startPageIndex, + endPageIndex, + searchString, + searchOption, + ); + } + } + + String _extractTextFromRange(int startPageIndex, int endPageIndex) { + String resultText = ''; + for (int i = startPageIndex; i <= endPageIndex; i++) { + final String text = _getText(_document.pages[i]); + resultText = + resultText + + (i > startPageIndex && + (!_isLayout || (_isLayout && !resultText.endsWith('\n'))) + ? '\r\n' + : '') + + text; + } + return resultText; + } + + List _extractTextLineFromRange( + int startPageIndex, + int endPageIndex, + ) { + final List result = []; + for (int i = startPageIndex; i <= endPageIndex; i++) { + _currentPageIndex = i; + final List textLines = _getTextLine(_document.pages[i]); + if (textLines.isNotEmpty) { + result.addAll(textLines); + } + } + return result; + } + + List _findTextFromRange( + int startPageIndex, + int endPageIndex, + List searchString, + TextSearchOption? searchOption, + ) { + final List result = []; + for (int i = startPageIndex; i <= endPageIndex; i++) { + _currentPageIndex = i; + final List textLines = _searchInBackground( + _document.pages[i], + searchString, + searchOption, + ); + if (textLines.isNotEmpty) { + result.addAll(textLines); + } + } + return result; + } + + String _getText(PdfPage page) { + _currentPage = page; + _fontSize = 0; + PdfPageHelper.getHelper(page).isTextExtraction = true; + final bool isChanged = _checkPageDictionary(page); + final bool isContentChanged = _checkContentArray(page); + final PdfRecordCollection? recordCollection = _getRecordCollection(page); + PdfPageResources? pageResources = _resourceLoader.getPageResources(page); + String resultantText; + if (_isLayout) { + try { + _initialTransform = MatrixHelper( + 1.3333333333333333, + 0, + 0, + -1.3333333333333333, + 0, + page.size.height * 1.3333333333333333, + ); + } catch (e) { + _initialTransform = MatrixHelper.identity; + } + resultantText = _renderTextAsLayout(recordCollection, pageResources); + } else { + resultantText = _renderText(recordCollection, pageResources); + } + if (recordCollection != null) { + recordCollection.recordCollection.clear(); + } + if (pageResources.resources.isNotEmpty) { + pageResources.resources.forEach((String? key, Object? value) { + if (value != null && value is FontStructure) { + value.dispose(); + } + }); + pageResources.resources.clear(); + } + if (pageResources.fontCollection.isNotEmpty) { + pageResources.fontCollection.forEach((String? key, FontStructure value) { + value.dispose(); + }); + pageResources.fontCollection.clear(); + } + pageResources = null; + if (resultantText != '') { + resultantText = _skipEscapeSequence(resultantText); + } + PdfPageHelper.getHelper(page).contents.changed = isContentChanged; + PdfPageHelper.getHelper(page).dictionary!.changed = isChanged; + PdfPageHelper.getHelper(page).isTextExtraction = false; + return resultantText; + } + + List _getTextLine(PdfPage pdfPage) { + final List result = []; + _currentPage = pdfPage; + _fontSize = 0; + PdfPageHelper.getHelper(pdfPage).isTextExtraction = true; + final bool isChanged = _checkPageDictionary(pdfPage); + final bool isContentChanged = _checkContentArray(pdfPage); + final PdfRecordCollection? recordCollection = _getRecordCollection(pdfPage); + final PdfPageResources pageResources = _resourceLoader.getPageResources( + pdfPage, + ); + final ImageRenderer renderer = ImageRenderer( + recordCollection, + pageResources, + pdfPage.size.height * 1.3333333333333333, + ); + renderer.isExtractLineCollection = true; + final double rotation = _getPageRotation(pdfPage); + renderer.pageRotation = rotation; + renderer.renderAsImage(); + renderer.isExtractLineCollection = false; + int i = 0; + double? width = 0; + double? height = 0; + double? dx = 0; + double? dy = 0; + int offsetY = 0; + double yPos = 0; + String pagestring = ''; + int lineStartIndex = 0; + TextLine textLine = TextLineHelper.initialize(); + if (pagestring == '') { + for (final Glyph s in renderer.imageRenderGlyphList) { + pagestring = pagestring + s.toUnicode; + } + } + if (renderer.extractTextElement.isNotEmpty) { + for (int k = 0; k < renderer.extractTextElement.length; k++) { + bool hasRotation = false; + if (i < renderer.imageRenderGlyphList.length) { + final Glyph tempGlyph = renderer.imageRenderGlyphList[i]; + if (tempGlyph.isRotated && (rotation == 270 || rotation == 90)) { + yPos = tempGlyph.boundingRect.left; + hasRotation = true; + } else { + yPos = tempGlyph.boundingRect.top; + } + if (k == 0) { + offsetY = yPos.toInt(); + } + if ((i != 0 && + yPos.toInt() != offsetY && + renderer.extractTextElement[k].renderedText != '') || + (i == renderer.imageRenderGlyphList.length - 1)) { + offsetY = yPos.toInt(); + if (textLine.wordCollection.isNotEmpty) { + result.add( + _prepareTextLine( + textLine, + renderer, + lineStartIndex, + i, + rotation, + ), + ); + } + lineStartIndex = i; + textLine = TextLineHelper.initialize(); + } + final TextElement textElement = renderer.extractTextElement[k]; + final List words = _splitRenderedText( + textElement.renderedText, + renderer.imageRenderGlyphList, + i, + ); + textElement.text = ' '; + TextWord? textwords; + List glyphs = []; + for (int x = 0; x < words.length; x++) { + if (pagestring.contains(words[x]) && words[x].isNotEmpty) { + glyphs = []; + int lastIndex = i; + for ( + int m = i; + m < i + words[x].length && + m < renderer.imageRenderGlyphList.length; + m++ + ) { + final Glyph tempGlyph = renderer.imageRenderGlyphList[m]; + final Rect tempBounds = tempGlyph.boundingRect; + final Rect glyphBounds = Rect.fromLTRB( + tempBounds.left, + tempBounds.top, + tempBounds.right, + tempBounds.bottom, + ); + final TextGlyph textGlyph = TextGlyphHelper.initialize( + tempGlyph.toUnicode, + textElement.fontName, + textElement.fontStyle, + _calculateBounds(glyphBounds), + textElement.fontSize, + tempGlyph.isRotated, + ); + glyphs.add(textGlyph); + lastIndex = m; + } + Rect? wordBound; + dx = renderer.imageRenderGlyphList[i].boundingRect.left; + dy = renderer.imageRenderGlyphList[i].boundingRect.top; + if (hasRotation && rotation == 270) { + width = renderer.imageRenderGlyphList[i].boundingRect.width; + height = + renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .bottom; + wordBound = Rect.fromLTWH(dx, dy, width, height - dy); + } else if (hasRotation && rotation == 90) { + final double startX = + renderer.imageRenderGlyphList[i].boundingRect.left; + final double startY = + renderer.imageRenderGlyphList[i].boundingRect.top; + final double endY = + renderer.imageRenderGlyphList[lastIndex].boundingRect.top; + final double lineWidth = + renderer.imageRenderGlyphList[i].boundingRect.width; + final double lineHeight = + (startY - endY).abs() + + renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .height; + wordBound = Rect.fromLTWH(startX, endY, lineWidth, lineHeight); + } else { + height = renderer.imageRenderGlyphList[i].boundingRect.height; + if (dx > + renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .left) { + width = + (dx - + renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .left) + + renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .width; + } else { + width = + (renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .left) + + renderer + .imageRenderGlyphList[lastIndex] + .boundingRect + .width; + } + wordBound = Rect.fromLTWH(dx, dy, width - dx, height); + } + i = lastIndex + 1; + String word = words[x]; + if (word.isNotEmpty && bidi.Bidi.hasAnyRtl(word)) { + word = + _bidi.getLogicalToVisualString(word, true)['rtlText'] + as String; + } + textwords = TextWordHelper.initialize( + word, + textElement.fontName, + textElement.fontStyle, + glyphs, + _calculateBounds(wordBound), + textElement.fontSize, + i < renderer.imageRenderGlyphList.length + ? renderer.imageRenderGlyphList[i].textColor + : null, + ); + textLine.wordCollection.add(textwords); + } + textElement.text = words[x]; + if (textElement.text != '') { + if (x < words.length - 1 && + i <= renderer.imageRenderGlyphList.length - 1 && + renderer.imageRenderGlyphList[i].toUnicode == ' ') { + if (i != 0) { + final Map tempResult = _addSpace( + textwords, + renderer, + textElement, + i, + dx, + dy, + width, + height, + ); + dx = tempResult['dx'] as double?; + dy = tempResult['dy'] as double?; + width = tempResult['width'] as double?; + height = tempResult['height'] as double?; + final Rect wordBound = Rect.fromLTWH( + dx!, + dy!, + width!, + height!, + ); + tempResult['word'].bounds = _calculateBounds(wordBound); + textLine.wordCollection.add(tempResult['word']); + } + i = i + 1; + } + if (x < words.length - 1 && + i <= renderer.imageRenderGlyphList.length - 1 && + renderer.imageRenderGlyphList[i].toUnicode == ' ' && + ((renderer.imageRenderGlyphList[i].isRotated && + (rotation == 270 || rotation == 90)) || + renderer.imageRenderGlyphList[i].boundingRect.top + .toInt() == + offsetY)) { + i = i + 1; + } + } else { + if (i <= renderer.imageRenderGlyphList.length - 1) { + if (x != words.length - 1 && + renderer.imageRenderGlyphList[i].toUnicode == ' ') { + if (i != 0) { + final Map tempResult = _addSpace( + textwords, + renderer, + textElement, + i, + dx, + dy, + width, + height, + ); + dx = tempResult['dx'] as double?; + dy = tempResult['dy'] as double?; + width = tempResult['width'] as double?; + height = tempResult['height'] as double?; + final Rect wordBound = Rect.fromLTWH( + dx!, + dy!, + width!, + height!, + ); + tempResult['word'].bounds = _calculateBounds(wordBound); + textLine.wordCollection.add(tempResult['word']); + } + i = i + 1; + } + } + } + } + if (i != 0 && + yPos.toInt() != offsetY && + renderer.extractTextElement[k].renderedText != '' && + renderer.extractTextElement[k].renderedText != ' ' || + (i == renderer.imageRenderGlyphList.length - 1)) { + if (renderer.extractTextElement.isNotEmpty && k == 0) { + offsetY = yPos.toInt(); + if (textLine.wordCollection.isNotEmpty) { + result.add( + _prepareTextLine( + textLine, + renderer, + lineStartIndex, + i, + rotation, + ), + ); + } + lineStartIndex = i; + textLine = TextLineHelper.initialize(); + } + } + } + } + final TextElement element = + renderer.extractTextElement[renderer.extractTextElement.length - 1]; + if (textLine.wordCollection.isNotEmpty && + !result.contains(textLine) && + element.renderedText != '' && + element.renderedText != ' ') { + result.add( + _prepareTextLine(textLine, renderer, lineStartIndex, i, rotation), + ); + textLine = TextLineHelper.initialize(); + } + } + if (textLine.wordCollection.isNotEmpty && !result.contains(textLine)) { + result.add( + _prepareTextLine(textLine, renderer, lineStartIndex, i, rotation), + ); + textLine = TextLineHelper.initialize(); + } + PdfPageHelper.getHelper(pdfPage).contents.changed = isContentChanged; + PdfPageHelper.getHelper(pdfPage).dictionary!.changed = isChanged; + PdfPageHelper.getHelper(pdfPage).isTextExtraction = false; + return result; + } + + //Splits the words in a rendered text and returns the list of words. + List _splitRenderedText(String text, List glyphs, int index) { + List words = []; + String tempString = ''; + Rect? previousRect; + bool isSplit = false; + if (text.isNotEmpty && + !text.codeUnits.any((int element) => element > 255) && + text[0] == glyphs[index].toUnicode) { + for (int i = index, j = 0; j < text.length; i++, j++) { + try { + final Glyph textGlyph = glyphs[i]; + if (text[j] == ' ') { + if (tempString.isNotEmpty) { + words.add(tempString); + } + if (j == 0 || (j != text.length - 1 && text[j - 1] == ' ')) { + words.add(''); + } + if (j + 1 >= text.length) { + words.add(''); + } + previousRect = null; + tempString = ''; + continue; + } + final Rect currentRect = textGlyph.boundingRect; + if (previousRect != null) { + if (_currentPage!.rotation.name != 'rotateAngle90' && + (previousRect.left + previousRect.width - currentRect.left) + .abs() > + 1.5) { + isSplit = true; + } else if (_currentPage!.rotation.name == 'rotateAngle90' && + textGlyph.isRotated && + (previousRect.width - currentRect.width).abs() > 1.5) { + isSplit = true; + } else { + tempString += text[j]; + } + } else { + tempString += text[j]; + } + if (isSplit) { + words.add(tempString); + isSplit = false; + previousRect = null; + tempString = ''; + i--; + j--; + } else { + previousRect = currentRect; + } + } catch (e) { + words = text.split(' '); + return words; + } + } + if (tempString.isNotEmpty) { + words.add(tempString); + } + } else { + words = text.split(' '); + } + return words; + } + + List _searchInBackground( + PdfPage page, + List searchString, + TextSearchOption? searchOption, + ) { + final List result = []; + _isLayout = true; + final String pageText = _getText(page); + _isLayout = false; + final bool containsRtl = bidi.Bidi.hasAnyRtl(pageText); + if (pageText != '') { + bool isMatched = _isMatchFound( + searchString, + searchOption, + pageText, + containsRtl, + ); + if (isMatched || containsRtl) { + _currentPage = page; + _fontSize = 0; + PdfPageHelper.getHelper(page).isTextExtraction = true; + final bool isChanged = _checkPageDictionary(page); + final bool isContentChanged = _checkContentArray(page); + final PdfRecordCollection? recordCollection = _getRecordCollection( + page, + ); + final PdfPageResources pageResources = _resourceLoader.getPageResources( + page, + ); + final ImageRenderer renderer = ImageRenderer( + recordCollection, + pageResources, + page.size.height * 1.3333333333333333, + ); + renderer.pageRotation = _getPageRotation(page); + renderer.renderAsImage(); + String renderedString = ''; + final Map combinedGlyphLength = {}; + if (renderer.imageRenderGlyphList.isNotEmpty) { + for (final Glyph glyph in renderer.imageRenderGlyphList) { + final String currentText = glyph.toUnicode; + if (currentText.length > 1) { + combinedGlyphLength[renderedString.length] = currentText.length; + } + renderedString = renderedString + glyph.toUnicode; + } + List? visualOrderedTextGlyph; + if (containsRtl) { + final Map visualOrderResult = _bidi + .getLogicalToVisualString(renderedString, true); + renderedString = visualOrderResult['rtlText'] as String; + final List visualOrderIndexes = + visualOrderResult['orderedIndexes'] as List; + visualOrderedTextGlyph = []; + if (combinedGlyphLength.isNotEmpty) { + combinedGlyphLength.forEach((int key, int value) { + if (visualOrderIndexes.contains(key)) { + final int newIndex = visualOrderIndexes.indexOf(key); + if (newIndex + 1 < visualOrderIndexes.length && + visualOrderIndexes[newIndex + 1] == key + 1) { + visualOrderIndexes.removeRange( + newIndex + 1, + newIndex + value, + ); + } else if (newIndex - 1 > -1 && + visualOrderIndexes[newIndex - 1] == key + 1) { + visualOrderIndexes.removeRange( + newIndex - value + 1, + newIndex, + ); + } + } + }); + } + final int glyphListLength = renderer.imageRenderGlyphList.length; + for (int i = 0; i < visualOrderIndexes.length; i++) { + int index = visualOrderIndexes[i]; + if (combinedGlyphLength.isNotEmpty) { + int tempValue = 0; + for (final int element in combinedGlyphLength.values) { + tempValue += element - 1; + } + for (final int key + in combinedGlyphLength.keys.toList().reversed) { + if (index > key) { + index -= tempValue; + break; + } + tempValue -= combinedGlyphLength[key]! - 1; + } + } + if (index < glyphListLength) { + visualOrderedTextGlyph.add( + renderer.imageRenderGlyphList[index], + ); + } + } + } + final List renderedStringCollection = [ + renderedString, + ]; + final List?> textGlyphCollection = ?>[ + visualOrderedTextGlyph ?? renderer.imageRenderGlyphList, + ]; + if (renderedString.contains(' ') || + renderedString.contains('\t\t')) { + String innerSpaceTrimmedString = renderedString; + final List innerSpaceTrimmedTextGlyph = + (visualOrderedTextGlyph ?? renderer.imageRenderGlyphList) + .toList(); + while (innerSpaceTrimmedString.contains(' ') || + innerSpaceTrimmedString.contains('\t\t')) { + int spaceStartIndex = innerSpaceTrimmedString.indexOf(' '); + if (spaceStartIndex < 0) { + spaceStartIndex = innerSpaceTrimmedString.indexOf('\t\t'); + } + if (spaceStartIndex >= 0) { + final List stringList = innerSpaceTrimmedString.split( + '', + ); + int i = spaceStartIndex + 2; + for (i = spaceStartIndex + 2; i < stringList.length; i++) { + if (stringList[i] == ' ' || stringList[i] == '\t') { + continue; + } else if (i >= stringList.length) { + break; + } else { + stringList.removeRange(spaceStartIndex + 1, i); + innerSpaceTrimmedTextGlyph.removeRange( + spaceStartIndex + 1, + i, + ); + break; + } + } + innerSpaceTrimmedString = stringList.join(); + if (i >= stringList.length) { + break; + } + } + } + renderedStringCollection.add(innerSpaceTrimmedString); + textGlyphCollection.add(innerSpaceTrimmedTextGlyph); + } + if (!isMatched) { + for (final String renderedText in renderedStringCollection) { + isMatched = _isMatchFound( + searchString, + searchOption, + renderedText, + containsRtl, + ); + if (isMatched) { + break; + } + } + } + if (isMatched) { + _getMatchedItems( + page, + searchString, + searchOption, + renderedStringCollection, + combinedGlyphLength, + textGlyphCollection, + result, + ); + } + } + PdfPageHelper.getHelper(page).contents.changed = isContentChanged; + PdfPageHelper.getHelper(page).dictionary!.changed = isChanged; + PdfPageHelper.getHelper(page).isTextExtraction = false; + } + } + return result; + } + + bool _isMatchFound( + List searchString, + TextSearchOption? searchOption, + String pageText, + bool containsRtl, + ) { + ArabicShapeRenderer? shapeRenderer; + if (containsRtl) { + shapeRenderer = ArabicShapeRenderer(); + } + bool isMatched = false; + for (int i = 0; i < searchString.length; i++) { + final String term = searchString[i]; + if (searchOption != null && + (searchOption == TextSearchOption.caseSensitive || + searchOption == TextSearchOption.both)) { + if (pageText.contains(term)) { + isMatched = true; + if (!containsRtl) { + break; + } + } + } else if (pageText.toLowerCase().contains(term.toLowerCase())) { + isMatched = true; + if (!containsRtl) { + break; + } + } + if (containsRtl && bidi.Bidi.hasAnyRtl(term)) { + final String renderedTerm = shapeRenderer!.shape(term.split(''), 0); + if (pageText.toLowerCase().contains(renderedTerm.toLowerCase())) { + if (!searchString.contains(renderedTerm)) { + searchString.add(renderedTerm); + } + isMatched = true; + } + if (term != renderedTerm && term.length < 5) { + List termCollection = [term]; + for (int j = 0; j < term.length; j++) { + if (shapeRenderer.arabicMapTable.containsKey(term[j])) { + final List? shapedChars = + shapeRenderer.arabicMapTable[term[j]]; + if (shapedChars != null && shapedChars.isNotEmpty) { + final List tempTermCollection = termCollection.toList(); + for (final String char in shapedChars) { + for (final String tempTerm in termCollection) { + final List termList = tempTerm.split(''); + termList[j] = char; + final String tempRenderedTerm = termList.join(); + if (!tempTermCollection.contains(tempRenderedTerm)) { + tempTermCollection.add(tempRenderedTerm); + if (!searchString.contains(tempRenderedTerm) && + pageText.toLowerCase().contains( + tempRenderedTerm.toLowerCase(), + )) { + searchString.add(tempRenderedTerm); + isMatched = true; + } + } + } + } + termCollection.clear(); + termCollection = tempTermCollection.toList(); + tempTermCollection.clear(); + } + } + } + termCollection.clear(); + } + } + } + return isMatched; + } + + void _getMatchedItems( + PdfPage page, + List searchString, + TextSearchOption? searchOption, + List renderedStringCollection, + Map combinedGlyphLength, + List?> glyphListCollection, + List result, + ) { + if (renderedStringCollection.isNotEmpty && + renderedStringCollection[0] != '') { + final Map> mappedIndexes = >{}; + final List textLengthCollection = []; + for (int i = 0; i < renderedStringCollection.length; i++) { + if (searchOption == null || + (searchOption != TextSearchOption.caseSensitive && + searchOption != TextSearchOption.both)) { + renderedStringCollection[i] = + renderedStringCollection[i].toLowerCase(); + } + textLengthCollection.add(renderedStringCollection[i].length); + } + for (final String term in searchString) { + if (term != '' && !mappedIndexes.containsKey(term)) { + final List indexes = []; + final String currentText = + (searchOption != null && + (searchOption == TextSearchOption.caseSensitive || + searchOption == TextSearchOption.both)) + ? term + : term.toLowerCase(); + int startIndex = 0; + final int length = currentText.length; + for (int i = 0; i < renderedStringCollection.length; i++) { + while (startIndex <= textLengthCollection[i] && + renderedStringCollection[i].contains(currentText, startIndex)) { + int index = renderedStringCollection[i].indexOf( + currentText, + startIndex, + ); + final int tempIndex = index; + if (searchOption != null && + (searchOption == TextSearchOption.wholeWords || + searchOption == TextSearchOption.both)) { + if (index == 0 || + _hasEscapeCharacter( + renderedStringCollection[i][index - 1], + )) { + if (index + length == textLengthCollection[i]) { + if (combinedGlyphLength.isNotEmpty) { + index = _checkCombinedTextIndex( + index, + combinedGlyphLength, + ); + } + indexes.add(index); + } else if (_hasEscapeCharacter( + renderedStringCollection[i][index + length], + )) { + if (combinedGlyphLength.isNotEmpty) { + index = _checkCombinedTextIndex( + index, + combinedGlyphLength, + ); + } + indexes.add(index); + } + } + } else { + if (combinedGlyphLength.isNotEmpty) { + index = _checkCombinedTextIndex(index, combinedGlyphLength); + } + indexes.add(index); + } + startIndex = tempIndex + 1; + } + if (indexes.isNotEmpty) { + for (final int index in indexes) { + if (glyphListCollection[i] != null && + index < glyphListCollection[i]!.length) { + final List rect = _calculatedTextounds( + glyphListCollection[i]!, + term, + index, + page, + bidi.Bidi.hasAnyRtl(term), + ); + result.add( + MatchedItemHelper.initialize(term, rect, _currentPageIndex), + ); + } + } + break; + } + } + } + } + } + } + + int _checkCombinedTextIndex( + int textIndex, + Map combinedGlyphLength, + ) { + int adjustableLength = 0; + combinedGlyphLength.forEach((int index, int length) { + if (index < textIndex) { + adjustableLength += length - 1; + } + }); + return textIndex - adjustableLength; + } + + PdfRecordCollection? _getRecordCollection(PdfPage page) { + PdfRecordCollection? recordCollection; + List? combinedData = PdfPageLayerCollectionHelper.getHelper( + page.layers, + ).combineContent(true); + if (combinedData != null) { + final ContentParser parser = ContentParser(combinedData); + parser.isTextExtractionProcess = true; + recordCollection = parser.readContent(); + parser.isTextExtractionProcess = false; + combinedData.clear(); + } + combinedData = null; + return recordCollection; + } + + bool _checkPageDictionary(PdfPage page) { + return PdfPageHelper.getHelper(page).dictionary!.changed != null && + PdfPageHelper.getHelper(page).dictionary!.changed!; + } + + bool _checkContentArray(PdfPage page) { + bool isContentChanged = false; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.contents)) { + final IPdfPrimitive? contents = + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .contents]; + if (contents is PdfReferenceHolder) { + final PdfReferenceHolder holder = contents; + final IPdfPrimitive? primitive = holder.object; + if (primitive is PdfArray) { + isContentChanged = primitive.changed!; + } else if (primitive is PdfStream) { + isContentChanged = primitive.changed!; + } + } else if (contents is PdfArray) { + isContentChanged = contents.changed!; + } + } + return isContentChanged; + } + + Map _addSpace( + TextWord? textwords, + ImageRenderer renderer, + TextElement textElement, + int i, + double? dx, + double? dy, + double? width, + double? height, + ) { + if (i >= renderer.imageRenderGlyphList.length) { + return { + 'word': null, + 'dx': dx, + 'dy': dy, + 'width': width, + 'height': height, + }; + } + final Rect tempBounds = renderer.imageRenderGlyphList[i].boundingRect; + final Rect glyphBounds = Rect.fromLTWH( + tempBounds.left, + tempBounds.top, + tempBounds.width, + tempBounds.height, + ); + final TextGlyph textGlyph = TextGlyphHelper.initialize( + renderer.imageRenderGlyphList[i].toUnicode, + textElement.fontName, + textElement.fontStyle, + _calculateBounds(glyphBounds), + textElement.fontSize, + renderer.imageRenderGlyphList[i].isRotated, + ); + dx = renderer.imageRenderGlyphList[i].boundingRect.left; + dy = renderer.imageRenderGlyphList[i].boundingRect.top; + height = renderer.imageRenderGlyphList[i].boundingRect.height; + if (dx > renderer.imageRenderGlyphList[i].boundingRect.left) { + width = + (dx - renderer.imageRenderGlyphList[i].boundingRect.left) + + renderer.imageRenderGlyphList[i].boundingRect.width; + } else { + width = + (renderer.imageRenderGlyphList[i].boundingRect.left - dx) + + renderer.imageRenderGlyphList[i].boundingRect.width; + } + return { + 'word': TextWordHelper.initialize( + ' ', + textElement.fontName, + textElement.fontStyle, + [textGlyph], + Rect.fromLTWH(dx, dy, width, height), + textElement.fontSize, + i < renderer.imageRenderGlyphList.length + ? renderer.imageRenderGlyphList[i].textColor + : null, + ), + 'dx': dx, + 'dy': dy, + 'width': width, + 'height': height, + }; + } + + List _calculatedTextounds( + List glyphs, + String text, + int index, + PdfPage page, + bool isRTL, + ) { + Rect textBounds = Rect.zero; + if (!isRTL) { + textBounds = _getLTRBounds(glyphs, text, index, page); + } else { + final bool isBidi = bidi.Bidi.hasAnyLtr(text); + String tempString = ''; + if (isBidi) { + final Map textCollection = {}; + final List boundsCollection = []; + int indexValue = index; + for (int i = 0; i < text.length; i++) { + if (i < text.length - 1 && + (((bidi.Bidi.startsWithRtl(text[i]) || text[i] == ' ') && + (glyphs[index + i].boundingRect.left - + (glyphs[index + i + 1].boundingRect.left + + glyphs[index + i + 1].boundingRect.width)) + .abs() < + 0.001) || + (bidi.Bidi.startsWithLtr(text[i]) && + ((glyphs[index + i].boundingRect.left + + glyphs[index + i].boundingRect.width) - + glyphs[index + i + 1].boundingRect.left) + .abs() < + 0.001))) { + tempString += glyphs[index + i].toUnicode; + } else { + tempString += glyphs[index + i].toUnicode; + textCollection[indexValue] = tempString; + indexValue = index + i + 1; + tempString = ''; + } + } + textCollection.forEach((int key, String value) { + if (bidi.Bidi.hasAnyRtl(value)) { + boundsCollection.add( + _calculateBounds(_getRTLBounds(glyphs, value, key, page)), + ); + } else { + boundsCollection.add( + _calculateBounds(_getLTRBounds(glyphs, value, key, page)), + ); + } + }); + return boundsCollection; + } else { + textBounds = _getRTLBounds(glyphs, text, index, page); + } + } + return [_calculateBounds(textBounds)]; + } + + Rect _getLTRBounds(List glyphs, String text, int index, PdfPage page) { + final Glyph startGlyph = glyphs[index]; + double x = startGlyph.boundingRect.left; + double y = startGlyph.boundingRect.top; + double width = 0; + double height = startGlyph.boundingRect.height; + //For complex script glyph mapping + int endIndex = index + text.length - 1; + int length = text.length; + String tempString = ''; + for (int i = 0; i < text.length; i++) { + tempString += glyphs[index + i].toUnicode; + if (tempString == text) { + endIndex = index + i; + length = i + 1; + break; + } + } + final Glyph endGlyph = glyphs[endIndex]; + if (startGlyph.boundingRect.top == endGlyph.boundingRect.top || + (startGlyph.boundingRect.top - endGlyph.boundingRect.top).abs() < + 0.001) { + if (x > endGlyph.boundingRect.left) { + width = (x - endGlyph.boundingRect.left) + endGlyph.boundingRect.width; + if (page.rotation == PdfPageRotateAngle.rotateAngle0 || + page.rotation == PdfPageRotateAngle.rotateAngle180) { + width = startGlyph.boundingRect.height; + for (int i = 0; i < length; i++) { + height += glyphs[index + i].boundingRect.width; + if (glyphs[index + i].boundingRect.height > width) { + width = glyphs[index + i].boundingRect.height; + } + } + } else { + width = startGlyph.boundingRect.width; + for (int i = 0; i < length; i++) { + height += glyphs[index + i].boundingRect.height; + if (glyphs[index + i].boundingRect.width > width) { + width = glyphs[index + i].boundingRect.width; + } + } + } + x -= width; + } else { + width = (endGlyph.boundingRect.left - x) + endGlyph.boundingRect.width; + } + } else if (startGlyph.boundingRect.left == endGlyph.boundingRect.left || + (startGlyph.boundingRect.left - endGlyph.boundingRect.left).abs() < + 0.001) { + if (startGlyph.boundingRect.top != endGlyph.boundingRect.top && + !((startGlyph.boundingRect.top - endGlyph.boundingRect.top).abs() < + 0.001)) { + height = 0; + if (page.rotation == PdfPageRotateAngle.rotateAngle0 || + page.rotation == PdfPageRotateAngle.rotateAngle180) { + width = startGlyph.boundingRect.height; + for (int i = 0; i < length; i++) { + height += glyphs[index + i].boundingRect.width; + if (glyphs[index + i].boundingRect.height > 0) { + width = glyphs[index + i].boundingRect.height; + } + } + } else { + width = startGlyph.boundingRect.width; + for (int i = 0; i < length; i++) { + height += glyphs[index + i].boundingRect.height; + width = glyphs[index + i].boundingRect.width; + } + } + if (y > endGlyph.boundingRect.top || startGlyph.rotationAngle == 270) { + x = startGlyph.boundingRect.left - width + 1; + y = startGlyph.boundingRect.top - height; + } else if (y < endGlyph.boundingRect.top || + startGlyph.rotationAngle == 90) { + x = startGlyph.boundingRect.left - 1; + y = startGlyph.boundingRect.top; + } + } + } + return Rect.fromLTWH(x, y, width, height); + } + + Rect _getRTLBounds(List glyphs, String text, int index, PdfPage page) { + final Glyph startGlyph = glyphs[index]; + double x = startGlyph.boundingRect.left; + final double y = startGlyph.boundingRect.top; + double width = 0; + final double height = startGlyph.boundingRect.height; + //For complex script glyph mapping + int endIndex = index + text.length - 1; + String tempString = ''; + for (int i = 0; i < text.length; i++) { + tempString += glyphs[index + i].toUnicode; + if (tempString == text) { + endIndex = index + i; + break; + } + } + final Glyph endGlyph = glyphs[endIndex]; + if (startGlyph.boundingRect.top == endGlyph.boundingRect.top || + (startGlyph.boundingRect.top - endGlyph.boundingRect.top).abs() < + 0.001) { + width = (x - endGlyph.boundingRect.left) + startGlyph.boundingRect.width; + x = startGlyph.boundingRect.left + startGlyph.boundingRect.width - width; + } + return Rect.fromLTWH(x, y, width, height); + } + + bool _hasEscapeCharacter(String text) { + return text.contains(' ') || + text.contains(r'\u0007') || + text.contains(r'\') || + text.contains(r'\b') || + text.contains(r'\f') || + text.contains(r'\r') || + text.contains(r'\t') || + text.contains(r'\n') || + text.contains(r'\v') || + text.contains(r"\'") || + text.contains(r'\u0000'); + } + + Rect _calculateBounds(Rect bounds) { + if (_currentPage != null) { + if (!PdfPageHelper.getHelper(_currentPage!).cropBox.isEmpty && + PdfPageHelper.getHelper(_currentPage!).cropBox != + PdfPageHelper.getHelper(_currentPage!).mediaBox) { + final double x = + bounds.left - PdfPageHelper.getHelper(_currentPage!).cropBox.left; + final double y = + bounds.top + PdfPageHelper.getHelper(_currentPage!).cropBox.top; + return Rect.fromLTWH(x, y, bounds.width, bounds.height); + } else if (!PdfPageHelper.getHelper(_currentPage!).mediaBox.isEmpty && + (PdfPageHelper.getHelper(_currentPage!).mediaBox.left != 0 || + PdfPageHelper.getHelper(_currentPage!).mediaBox.top != 0)) { + final double cLeft = + PdfPageHelper.getHelper(_currentPage!).mediaBox.left; + final double ctop = PdfPageHelper.getHelper(_currentPage!).mediaBox.top; + final double x = bounds.left - cLeft; + final double y = bounds.top + ctop; + return Rect.fromLTWH(x, y, bounds.width, bounds.height); + } + } + return bounds; + } + + TextLine _prepareTextLine( + TextLine textLine, + ImageRenderer renderer, + int lineStartIndex, + int glyphIndex, + double rotation, + ) { + bool isSameFontName = true; + bool isSameFontSize = true; + bool isSameFontStyle = true; + String? fontName = ''; + double? fontSize = 0; + PdfColor? textColor; + bool isSameTextColor = true; + textLine.pageIndex = _currentPageIndex; + List? fontStyle = [PdfFontStyle.regular]; + if (rotation == 270 && + renderer.imageRenderGlyphList[lineStartIndex].isRotated) { + textLine.bounds = Rect.fromLTWH( + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left, + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.top, + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.width, + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.bottom - + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.top, + ); + } else if (rotation == 90 && + renderer.imageRenderGlyphList[lineStartIndex].isRotated) { + final double startX = + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left; + final double startY = + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.top; + final double endY = + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.top; + final double lineWidth = + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.width; + final double lineHeight = + (startY - endY).abs() + + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.height; + textLine.bounds = Rect.fromLTWH(startX, endY, lineWidth, lineHeight); + } else { + textLine.bounds = Rect.fromLTWH( + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left, + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.top, + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.right - + renderer.imageRenderGlyphList[lineStartIndex].boundingRect.left, + renderer.imageRenderGlyphList[glyphIndex - 1].boundingRect.height, + ); + } + textLine.bounds = _calculateBounds(textLine.bounds); + Rect? prevBounds; + for (int i = 0; i < textLine.wordCollection.length; i++) { + final TextWord word = textLine.wordCollection[i]; + if (i == 0) { + fontName = word.fontName; + fontSize = word.fontSize; + fontStyle = word.fontStyle; + textColor = word.textColor; + } + if (prevBounds != null && + (prevBounds.left + prevBounds.width - word.bounds.left).abs() > 1 && + !textLine.text.endsWith(' ') && + !bidi.Bidi.hasAnyRtl(textLine.text)) { + textLine.text += ' '; + } + textLine.text += word.text; + prevBounds = word.bounds; + if (fontName == word.fontName && isSameFontName) { + textLine.fontName = fontName!; + } else { + isSameFontName = false; + textLine.fontName = ''; + } + if (fontSize == word.fontSize && isSameFontSize) { + textLine.fontSize = fontSize!; + } else { + isSameFontSize = false; + textLine.fontSize = 0; + } + + if (fontStyle == word.fontStyle && isSameFontStyle) { + textLine.fontStyle = fontStyle!; + } else { + isSameFontStyle = false; + textLine.fontStyle = [PdfFontStyle.regular]; + } + if (!isSameFontName) { + isSameFontName = true; + } + if (!isSameFontSize) { + isSameFontSize = true; + } + if (!isSameFontStyle) { + isSameFontStyle = true; + } + if (textColor == word.textColor && isSameTextColor) { + textLine.textColor = textColor; + } else { + isSameTextColor = false; + textLine.textColor = null; + } + if (!isSameTextColor) { + isSameTextColor = true; + } + } + if (textLine.text.isNotEmpty && bidi.Bidi.hasAnyRtl(textLine.text)) { + textLine.text = + _bidi.getLogicalToVisualString(textLine.text, true)['rtlText'] + as String; + } + return textLine; + } + + String _renderText( + PdfRecordCollection? recordCollection, + PdfPageResources pageResources, + ) { + String resultantText = ''; + if (recordCollection != null && + recordCollection.recordCollection.isNotEmpty) { + final List records = recordCollection.recordCollection; + for (int i = 0; i < records.length; i++) { + final PdfRecord record = records[i]; + final String token = record.operatorName!; + final List? elements = record.operands; + for (int j = 0; j < _symbolChars.length; j++) { + if (token.contains(_symbolChars[j])) { + token.replaceAll(_symbolChars[j], ''); + } + } + switch (token.trim()) { + case 'T*': + { + resultantText += '\r\n'; + break; + } + case 'Tf': + { + _renderFont(elements!, pageResources); + break; + } + case 'ET': + { + resultantText += '\r\n'; + break; + } + case 'BDC': + { + if (elements != null && + elements.length > 1 && + elements[1].contains('ActualText') && + elements[1].contains('(')) { + _initializeActualText(elements[1]); + } + break; + } + case 'EMC': + _actualText = null; + break; + case 'Tj': + case 'TJ': + case "'": + { + final String? resultText = + (_actualText != null && _actualText!.isNotEmpty) + ? _actualText + : _renderTextElement( + elements!, + token, + pageResources, + null, + ); + if (resultText != null) { + resultantText += resultText; + } + if (token == "'") { + resultantText += '\r\n'; + } + break; + } + case 'Do': + { + final String? result = _getXObject( + resultantText, + elements!, + pageResources, + ); + if (result != null && result != '') { + resultantText += result; + } + break; + } + default: + break; + } + } + } + return resultantText; + } + + String _renderTextAsLayout( + PdfRecordCollection? recordCollection, + PdfPageResources pageResources, + ) { + double? currentMatrixY = 0; + double? prevMatrixY = 0; + double? currentY = 0; + double? prevY = 0; + double differenceX = 0; + String? currentText = ''; + bool hasTj = false; + bool hasTm = false; + _hasBDC = false; + String resultantText = ''; + double? textLeading = 0; + double? horizontalScaling = 100; + bool hasNoSpacing = false; + bool spaceBetweenWord = false; + bool isSpaceAdded = false; + _tempBoundingRectangle = Rect.zero; + if (recordCollection != null && + recordCollection.recordCollection.isNotEmpty) { + final List records = recordCollection.recordCollection; + for (int i = 0; i < records.length; i++) { + final PdfRecord record = records[i]; + final String token = record.operatorName!; + final List? elements = record.operands; + for (int j = 0; j < _symbolChars.length; j++) { + if (token.contains(_symbolChars[j])) { + token.replaceAll(_symbolChars[j], ''); + } + } + switch (token.trim()) { + case 'q': + { + _hasET = false; + break; + } + case 'Tw': + { + _wordSpacing = double.tryParse(elements![0])!; + break; + } + case 'Tc': + { + _characterSpacing = double.tryParse(elements![0])!; + break; + } + case 'Tm': + { + hasTm = true; + final double a = double.tryParse(elements![0])!; + final double b = double.tryParse(elements[1])!; + final double c = double.tryParse(elements[2])!; + final double d = double.tryParse(elements[3])!; + final double e = double.tryParse(elements[4])!; + final double f = double.tryParse(elements[5])!; + _textLineMatrix = MatrixHelper(a, b, c, d, e, f); + _textMatrix = MatrixHelper(a, b, c, d, e, f); + if (_textMatrix!.offsetY == _textLineMatrix!.offsetY && + _textMatrix!.offsetX != _textLineMatrix!.offsetX) { + _textLineMatrix = _textMatrix!.clone(); + } + if (_textLineMatrix!.offsetY != _currentTextMatrix!.offsetY || + ((_textLineMatrix!.offsetX != _currentTextMatrix!.offsetX) && + _hasBDC && + !hasTj)) { + _tempBoundingRectangle = Rect.zero; + _hasBDC = false; + } + break; + } + case 'TL': + { + textLeading = -double.tryParse(elements![0])!; + break; + } + case 'cm': + { + _hasET = false; + currentMatrixY = double.tryParse(elements![5]); + final int current = currentMatrixY!.toInt(); + final int prev = prevMatrixY!.toInt(); + final int locationY = (current - prev) ~/ 10; + if ((current != prev) && + hasTm && + (locationY < 0 || locationY >= 1) && + resultantText.isNotEmpty && + !resultantText.endsWith('\n')) { + resultantText += '\r\n'; + hasTm = false; + } + prevMatrixY = currentMatrixY; + break; + } + case 'BDC': + { + _hasBDC = true; + if (elements != null && + elements.length > 1 && + elements[1].contains('ActualText') && + elements[1].contains('(')) { + _initializeActualText(elements[1]); + } else { + _hasET = true; + } + break; + } + case 'EMC': + _actualText = null; + break; + case 'TD': + { + textLeading = double.tryParse(elements![1]); + _textMatrix = + MatrixHelper( + 1, + 0, + 0, + 1, + double.tryParse(elements[0])!, + double.tryParse(elements[1])!, + ) * + _textLineMatrix!; + _textLineMatrix = _textMatrix!.clone(); + if (_textLineMatrix!.offsetY != _currentTextMatrix!.offsetY || + (_hasBDC && + _textLineMatrix!.offsetX != _currentTextMatrix!.offsetX && + !hasTj)) { + _tempBoundingRectangle = Rect.zero; + _hasBDC = false; + } + break; + } + case 'Td': + { + _textMatrix = + MatrixHelper( + 1, + 0, + 0, + 1, + double.tryParse(elements![0])!, + double.tryParse(elements[1])!, + ) * + _textLineMatrix!; + _textLineMatrix = _textMatrix!.clone(); + if (_textLineMatrix!.offsetY != _currentTextMatrix!.offsetY || + (_hasBDC && + _textLineMatrix!.offsetX != + _currentTextMatrix!.offsetX)) { + _tempBoundingRectangle = Rect.zero; + _hasBDC = false; + } + if ((_textLineMatrix!.offsetX - _currentTextMatrix!.offsetX) + .abs() > + 0 && + !spaceBetweenWord && + hasTj) { + differenceX = + _textLineMatrix!.offsetX - _currentTextMatrix!.offsetX; + spaceBetweenWord = true; + } + break; + } + case 'Tz': + { + horizontalScaling = double.tryParse(elements![0]); + break; + } + case 'BT': + { + _textMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + _textLineMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + break; + } + case 'T*': + { + _textMatrix = + MatrixHelper(1, 0, 0, 1, 0, textLeading!) * _textLineMatrix!; + _textLineMatrix = _textMatrix!.clone(); + break; + } + case 'Tf': + { + _renderFont(elements!, pageResources); + break; + } + case 'ET': + { + _hasET = true; + final double endTextPosition = + (_textLineMatrix!.offsetX - _tempBoundingRectangle!.right) / + 10; + if (_hasLeading && endTextPosition == 0 && hasNoSpacing) { + resultantText += ' '; + _tempBoundingRectangle = Rect.zero; + _hasLeading = false; + isSpaceAdded = true; + } + break; + } + case 'Tj': + case 'TJ': + { + final String currentToken = token.trim(); + currentY = _textMatrix!.offsetY; + double difference = 0; + if (_fontSize! >= 10) { + difference = ((currentY - prevY!) / 10).round().toDouble(); + } else { + difference = + ((currentY - prevY!) / _fontSize!).round().toDouble(); + } + if (difference < 0) { + difference = -difference; + } + if (prevY != 0 && difference >= 1) { + if (resultantText.isNotEmpty && !resultantText.endsWith('\n')) { + resultantText += '\r\n'; + } + } else if (spaceBetweenWord) { + if (differenceX > _fontSize!) { + differenceX = 0; + } + bool isEncoded = true; + if (elements != null) { + final String text = elements.join(); + isEncoded = + text[0] != '(' || + (text[0] == '(' && _hasOctalEscape(text)); + } + if (currentToken == 'Tj' && + (_hasET || !isEncoded) && + resultantText.isNotEmpty && + !resultantText.endsWith(' ')) { + resultantText += ' '; + } + } + spaceBetweenWord = false; + hasTj = true; + currentText = + currentToken == 'TJ' + ? _renderTextElementTJ( + elements!, + token, + pageResources, + horizontalScaling, + ) + : _renderTextElement( + elements!, + token, + pageResources, + horizontalScaling, + ); + if (_actualText != null && _actualText!.isNotEmpty) { + currentText = _actualText; + _actualText = null; + } + _currentTextMatrix = _textLineMatrix!.clone(); + prevY = currentY; + resultantText += currentText!; + if (currentToken == 'TJ' && + _textLineMatrix!.m11 != 1 && + _textLineMatrix!.m22 != 1 && + _hasET && + currentText.isNotEmpty) { + resultantText += ' '; + } + _hasET = false; + _textMatrix = _textLineMatrix!.clone(); + if (currentToken == 'TJ') { + _hasBDC = false; + } + break; + } + case "'": + { + currentY = _textMatrix!.offsetY; + hasNoSpacing = false; + double difference = 0; + if (_fontSize! >= 10) { + difference = ((currentY - prevY!) / 10).round().toDouble(); + } else { + difference = + ((currentY - prevY!) / _fontSize!).round().toDouble(); + } + if (difference < 0) { + difference = -difference; + } + _hasLeading = true; + if (prevY != 0 && + (difference >= 1 || + (i > 0 && records[i - 1].operatorName! == "'")) && + resultantText.isNotEmpty && + !resultantText.endsWith('\n')) { + if (isSpaceAdded && + resultantText.isNotEmpty && + resultantText.endsWith(' ')) { + resultantText = resultantText.substring( + 0, + resultantText.length - 1, + ); + } + resultantText += '\r\n'; + } + isSpaceAdded = false; + prevY = currentY; + final int currentXPosition = _textLineMatrix!.offsetX + .toInt() + .toSigned(64); + final int prevXPosition = _currentTextMatrix!.offsetX + .toInt() + .toSigned(64); + if ((prevXPosition - currentXPosition) > 0) { + hasNoSpacing = true; + } + _textMatrix = + MatrixHelper(1, 0, 0, 1, 0, textLeading!) * _textLineMatrix!; + _textLineMatrix = _textMatrix!.clone(); + currentText = _renderTextElement( + elements!, + token, + pageResources, + horizontalScaling, + ); + _currentTextMatrix = _textLineMatrix!.clone(); + resultantText += currentText!; + break; + } + case 'Do': + { + final String? result = _getXObject( + resultantText, + elements!, + pageResources, + ); + if (result != null && result != '') { + resultantText += result; + } + break; + } + default: + break; + } + } + } + if (isSpaceAdded && + resultantText.isNotEmpty && + resultantText.endsWith(' ')) { + resultantText = resultantText.substring(0, resultantText.length - 1); + } + return resultantText + .replaceAll(RegExp(r' {2,}'), ' ') + .replaceAll(' \r\n', '\r\n'); + } + + bool _hasOctalEscape(String input) { + final RegExp octalPattern = RegExp(r'\\[0-7]{1,3}'); + return octalPattern.hasMatch(input); + } + + void _initializeActualText(String text) { + _actualText = text.substring(text.indexOf('(') + 1, text.lastIndexOf(')')); + const String bigEndianPreambleString = 'þÿ'; + if (_actualText != null && + _actualText!.startsWith(bigEndianPreambleString)) { + _actualText = null; + } + } + + String _skipEscapeSequence(String text) { + int index = -1; + do { + index = text.indexOf(r'\', index + 1); + if (text.length > index + 1) { + final String nextLiteral = text[index + 1]; + if (index >= 0 && + (nextLiteral == r'\' || nextLiteral == '(' || nextLiteral == ')')) { + text = text.replaceFirst(text[index], '', index); + } + } else { + text = text.replaceFirst(text[index], '', index); + index = -1; + } + } while (index >= 0); + return text; + } + + void _renderFont(List elements, PdfPageResources resources) { + int i = 0; + for (i = 0; i < elements.length; i++) { + if (elements[i].contains('/')) { + _currentFont = elements[i].replaceAll('/', ''); + break; + } + } + _fontSize = double.tryParse(elements[i + 1]); + if (resources.containsKey(_currentFont)) { + final FontStructure structure = resources[_currentFont!] as FontStructure; + if (structure.isStandardFont) { + structure.createStandardFont(_fontSize!); + } else if (structure.isStandardCJKFont) { + structure.createStandardCJKFont(_fontSize!); + } + } + } + + String _renderTextElementTJ( + List elements, + String tokenType, + PdfPageResources pageResources, + double? horizontalScaling, + ) { + List decodedList = []; + Map?, String> decodedListCollection = ?, String>{}; + final String text = elements.join(); + String tempText = ''; + if (pageResources.containsKey(_currentFont)) { + FontStructure? fontStructure; + final dynamic returnValue = pageResources[_currentFont!]; + if (returnValue != null && returnValue is FontStructure) { + fontStructure = returnValue; + } + fontStructure!.isTextExtraction = true; + fontStructure.isLayout = _isLayout; + fontStructure.fontSize = _fontSize; + if (!fontStructure.isEmbedded && + fontStructure.isStandardCJKFont && + fontStructure.font != null) { + decodedList = fontStructure.decodeCjkTextExtractionTJ( + text, + pageResources.isSameFont(), + ); + } else { + decodedListCollection = fontStructure.decodeTextExtractionTJ( + text, + pageResources.isSameFont(), + ); + decodedList = decodedListCollection.values.toList(); + } + fontStructure.isTextExtraction = false; + tempText = _renderTextFromTJ( + decodedList, + horizontalScaling, + fontStructure, + ); + if (bidi.Bidi.hasAnyRtl(tempText)) { + tempText = + _bidi.getLogicalToVisualString(tempText, true)['rtlText'] as String; + } + } + return tempText; + } + + String _renderTextFromTJ( + List decodedList, + double? horizontalScaling, + FontStructure? fontStructure, + ) { + String extractedText = ''; + for (String word in decodedList) { + final double? space = double.tryParse(word); + if (space != null) { + _textLineMatrix = _updateTextMatrixWithSpacing( + space, + horizontalScaling!, + ); + if ((_textLineMatrix!.offsetX - _textMatrix!.offsetX).toInt() > 1 && + !_hasBDC) { + extractedText += ' '; + } + } else { + double characterWidth = 1.0; + if (word != '' && word[word.length - 1] == 's') { + word = word.substring(0, word.length - 1); + } + if (fontStructure != null && + fontStructure.fontEncoding == 'MacRomanEncoding') { + String tempstring = ''; + for (int i = 0; i < word.length; i++) { + final int b = word[i].codeUnitAt(0).toUnsigned(8); + if (b > 126) { + final String x = fontStructure.macEncodeTable![b]!; + tempstring += x; + } else { + tempstring += word[i]; + } + } + if (tempstring != '') { + word = tempstring; + } + } + for (int i = 0; i < word.length; i++) { + final String renderedCharacter = word[i]; + MatrixHelper transform = MatrixHelper(1, 0, 0, 1, 0, 0); + if (!fontStructure!.isEmbedded && + fontStructure.isStandardFont && + fontStructure.font != null) { + final PdfStandardFont font = fontStructure.font! as PdfStandardFont; + characterWidth = + PdfStandardFontHelper.getHelper( + font, + ).getCharWidthInternal(renderedCharacter) * + PdfFontHelper.characterSizeMultiplier; + } else if (!fontStructure.isEmbedded && + fontStructure.isStandardCJKFont && + fontStructure.font != null) { + final PdfCjkStandardFont font = + fontStructure.font! as PdfCjkStandardFont; + characterWidth = + PdfCjkStandardFontHelper.getHelper( + font, + ).getCharWidthInternal(renderedCharacter) * + PdfFontHelper.characterSizeMultiplier; + } else { + characterWidth = _getCharacterWidth( + renderedCharacter, + fontStructure, + ); + } + _textMatrix = _getTextRenderingMatrix(horizontalScaling!); + final MatrixHelper identity = MatrixHelper.identity.clone(); + identity.scale(0.01, 0.01, 0.0, 0.0); + identity.translate(0.0, 1.0); + final MatrixHelper matrix = transform.clone(); + transform = matrix; + double? tempFontSize; + if (_textMatrix!.m11 > 0) { + tempFontSize = _textMatrix!.m11; + } else if (_textMatrix!.m12 != 0 && _textMatrix!.m21 != 0) { + if (_textMatrix!.m12 < 0) { + tempFontSize = -_textMatrix!.m12; + } else { + tempFontSize = _textMatrix!.m12; + } + } else { + tempFontSize = _fontSize; + } + final Rect boundingRect = Rect.fromLTWH( + matrix.offsetX / 1.3333333333333333, + (matrix.offsetY - tempFontSize!) / 1.3333333333333333, + characterWidth * tempFontSize, + tempFontSize, + ); + if (_tempBoundingRectangle != null) { + final double boundingDifference = + ((boundingRect.left - _tempBoundingRectangle!.right) / 10) + .round() + .toDouble(); + if ((_tempBoundingRectangle!.right != 0 && + boundingRect.left != 0) && + boundingDifference >= 1 && + _hasLeading) { + extractedText += ' '; + } + } + extractedText += renderedCharacter; + _textLineMatrix = _updateTextMatrix( + characterWidth, + horizontalScaling, + ); + _tempBoundingRectangle = boundingRect; + _textMatrix = _textLineMatrix!.clone(); + } + } + } + return extractedText; + } + + String? _renderTextElement( + List elements, + String tokenType, + PdfPageResources pageResources, + double? horizontalScaling, + ) { + try { + String text = elements.join(); + if (!pageResources.containsKey(_currentFont)) { + if (_currentFont != null && _currentFont!.contains('-')) { + _currentFont = _currentFont!.replaceAll('-', '#2D'); + } + } + if (pageResources.containsKey(_currentFont)) { + FontStructure? fontStructure; + final dynamic returnValue = pageResources[_currentFont!]; + if (returnValue != null && returnValue is FontStructure) { + fontStructure = returnValue; + } + fontStructure!.isTextExtraction = true; + fontStructure.fontSize = _fontSize; + text = fontStructure.decodeTextExtraction(text, true); + if (_isLayout) { + text = _renderTextFromLeading( + text, + _textLineMatrix, + fontStructure, + horizontalScaling, + ); + } + fontStructure.isTextExtraction = false; + } + if (bidi.Bidi.hasAnyRtl(text)) { + text = _bidi.getLogicalToVisualString(text, true)['rtlText'] as String; + } + return text; + } catch (e) { + return null; + } + } + + String _renderTextFromLeading( + String decodedText, + MatrixHelper? textLineMatrix, + FontStructure structure, [ + double? horizontalScaling = 100, + ]) { + String extractedText = ''; + for (int i = 0; i < decodedText.length; i++) { + final String ch = decodedText[i]; + double characterWidth; + if (structure.isStandardFont) { + final PdfStandardFont font = structure.font! as PdfStandardFont; + characterWidth = + PdfStandardFontHelper.getHelper(font).getCharWidthInternal(ch) * + PdfFontHelper.characterSizeMultiplier; + } else if (structure.isStandardCJKFont) { + final PdfCjkStandardFont font = structure.font! as PdfCjkStandardFont; + characterWidth = + PdfCjkStandardFontHelper.getHelper(font).getCharWidthInternal(ch) * + PdfFontHelper.characterSizeMultiplier; + } else { + characterWidth = _getCharacterWidth(ch, structure); + } + _textMatrix = _getTextRenderingMatrix(horizontalScaling!); + final MatrixHelper identity = MatrixHelper.identity; + identity.scale(0.01, 0.01, 0.0, 0.0); + identity.translate(0.0, 1.0); + MatrixHelper tranformation = identity * _textMatrix!; + if (_initialTransform != null) { + tranformation = tranformation * _initialTransform!; + } + MatrixHelper matrix = MatrixHelper(1, 0, 0, 1, 0, 0); + matrix = matrix * tranformation; + double? tempFontSize; + if (_textMatrix!.m11 > 0) { + tempFontSize = _textMatrix!.m11; + } else if (_textMatrix!.m12 != 0 && _textMatrix!.m21 != 0) { + if (_textMatrix!.m12 < 0) { + tempFontSize = -_textMatrix!.m12; + } else { + tempFontSize = _textMatrix!.m12; + } + } else { + tempFontSize = structure.fontSize; + } + final Rect boundingRect = Rect.fromLTWH( + matrix.offsetX / 1.3333333333333333, + (matrix.offsetY - tempFontSize!) / 1.3333333333333333, + characterWidth * tempFontSize, + tempFontSize, + ); + if (_tempBoundingRectangle != null) { + final double boundingDifference = + ((boundingRect.left - _tempBoundingRectangle!.right) / 10) + .round() + .toDouble(); + if ((_tempBoundingRectangle!.right != 0 && boundingRect.left != 0) && + boundingDifference >= 1 && + _hasLeading) { + extractedText += ' '; + } + } + extractedText += ch; + _textLineMatrix = _updateTextMatrix(characterWidth, 100); + _tempBoundingRectangle = boundingRect; + } + return extractedText; + } + + String? _getXObject( + String resultantText, + List xobjectElement, + PdfPageResources pageResources, + ) { + String? result; + final String key = xobjectElement[0].replaceAll('/', ''); + if (pageResources.containsKey(key)) { + final dynamic element = pageResources[key]; + if (element is XObjectElement) { + final PdfRecordCollection collection = element.render(pageResources)!; + final PdfDictionary xobjects = element.dictionary!; + PdfPageResources childResource = PdfPageResources(); + if (xobjects.containsKey(PdfDictionaryProperties.resources)) { + PdfDictionary? pageDictionary = PdfDictionary(); + final IPdfPrimitive? resource = + xobjects[PdfDictionaryProperties.resources]; + if (resource is PdfReferenceHolder && + resource.object is PdfDictionary) { + pageDictionary = resource.object as PdfDictionary?; + } else if (resource is PdfDictionary) { + pageDictionary = resource; + } + childResource = _resourceLoader.updatePageResources( + childResource, + _resourceLoader.getFormResources(pageDictionary), + ); + childResource = _resourceLoader.updatePageResources( + childResource, + _resourceLoader.getFontResources(pageDictionary, _currentPage), + ); + } else { + childResource = _updateFontResources(pageResources); + } + if (_isLayout) { + result = '${_renderTextAsLayout(collection, childResource)}\r\n'; + } else { + result = _renderText(collection, childResource); + } + collection.recordCollection.clear(); + } + } + return result; + } + + PdfPageResources _updateFontResources(PdfPageResources pageResources) { + final PdfPageResources resources = PdfPageResources(); + pageResources.resources.forEach((String? key, dynamic value) { + if (value is FontStructure) { + resources.resources[key] = value; + resources.fontCollection[key] = value; + } + }); + return resources; + } + + MatrixHelper? _updateTextMatrixWithSpacing( + double space, + double horizontalScaling, + ) { + final double x = -(space * 0.001 * _fontSize! * horizontalScaling / 100); + final Offset point = _textLineMatrix!.transform(Offset.zero); + final Offset point2 = _textLineMatrix!.transform(Offset(x, 0.0)); + if (point.dx != point2.dx) { + _textLineMatrix!.offsetX = point2.dx; + } else { + _textLineMatrix!.offsetY = point2.dy; + } + return _textLineMatrix; + } + + MatrixHelper _getTextRenderingMatrix(double textHorizontalScaling) { + return MatrixHelper( + _fontSize! * (textHorizontalScaling / 100), + 0, + 0, + -_fontSize!, + 0, + _fontSize!, + ) * + _textLineMatrix! * + _currentTransformationMatrix; + } + + double _getCharacterWidth(String character, FontStructure structure) { + final int charID = character.codeUnitAt(0); + return (structure.fontGlyphWidths != null && + structure.fontType!.name == 'TrueType' && + structure.fontGlyphWidths!.containsKey(charID)) + ? structure.fontGlyphWidths![charID]! * 0.001 + : 1.0; + } + + MatrixHelper _updateTextMatrix( + double characterWidth, + double horizontalScaling, + ) { + final double offsetX = + (characterWidth * _fontSize! + _characterSpacing + _wordSpacing) * + (horizontalScaling / 100); + return MatrixHelper(1.0, 0.0, 0.0, 1.0, offsetX, 0.0) * _textLineMatrix!; + } + + double _getPageRotation(PdfPage page) { + if (page.rotation == PdfPageRotateAngle.rotateAngle90) { + return 90; + } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { + return 180; + } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { + return 270; + } else { + return 0; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart index e39c82118..422ee8c56 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_element.dart @@ -1,1198 +1,1224 @@ -import 'dart:collection'; -import 'dart:ui'; - -import 'package:intl/intl.dart' as bidi; - -import '../../graphics/fonts/enums.dart'; -import '../../graphics/fonts/pdf_cjk_standard_font.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_standard_font.dart'; -import 'font_structure.dart'; -import 'glyph.dart'; -import 'graphic_object_data.dart'; -import 'matrix_helper.dart'; - -/// internal class -class TextElement { - //constructor - /// internal constructor - TextElement(this.text, MatrixHelper? transformMatrix) { - transformations = TransformationStack(transformMatrix); - _initialize(); - } - - //Fields - /// internal field - late String text; - - /// internal field - late TransformationStack transformations; - - /// internal field - late List textElementGlyphList; - - /// internal field - late bool isExtractTextData; - - /// internal field - late String fontName; - - /// internal field - late List fontStyle; - - /// internal field - double fontSize = 0; - - /// internal field - double? textScaling; - - /// internal field - double? characterSpacing; - - /// internal field - double? wordSpacing; - - /// internal field - int? renderingMode; - - /// internal field - Map? encodedTextBytes; - - /// internal field - String? fontEncoding; - - /// internal field - Map? fontGlyphWidths; - - /// internal field - double? defaultGlyphWidth; - - /// internal field - Map? unicodeCharMapTable; - - /// internal field - Map? cidToGidReverseMapTable; - - /// internal field - late Map characterMapTable; - - /// internal field - Map? reverseMapTable; - - /// internal field - late FontStructure structure; - - /// internal field - late bool isEmbeddedFont; - - /// internal field - MatrixHelper? currentTransformationMatrix; - - /// internal field - MatrixHelper? textLineMatrix; - - /// internal field - MatrixHelper? transformMatrix; - - /// internal field - int? rise; - - /// internal field - MatrixHelper? documentMatrix; - - /// internal field - String? fontId; - - /// internal field - Map? octDecMapTable; - - /// internal field - double? textHorizontalScaling; - - /// internal field - String? zapfPostScript; - - /// internal field - double? lineWidth; - - /// internal field - double? pageRotation; - - /// internal field - double? zoomFactor; - - /// internal field - Map? substitutedFontsList; - - /// internal field - PdfFont? font; - - /// internal field - String renderedText = ''; - - /// internal field - int? fontFlag; - - /// internal field - late bool isTextGlyphAdded; - - /// internal field - double? currentGlyphWidth; - - /// internal field - late double charSizeMultiplier; - - /// internal field - List? macRomanToUnicode; - - //Implementation - void _initialize() { - fontName = ''; - fontStyle = []; - charSizeMultiplier = 0.001; - currentGlyphWidth = 0; - isTextGlyphAdded = false; - textElementGlyphList = []; - isExtractTextData = false; - textScaling = 100; - textHorizontalScaling = 100; - characterSpacing = 0; - wordSpacing = 0; - defaultGlyphWidth = 0; - reverseMapTable = {}; - isEmbeddedFont = false; - documentMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - documentMatrix!.type = MatrixTypes.identity; - fontId = ''; - lineWidth = 0; - pageRotation = 0; - zoomFactor = 1; - substitutedFontsList = {}; - fontFlag = 0; - macRomanToUnicode = [ - 196, - 197, - 199, - 201, - 209, - 214, - 220, - 225, - 224, - 226, - 228, - 227, - 229, - 231, - 233, - 232, - 234, - 235, - 237, - 236, - 238, - 239, - 241, - 243, - 242, - 244, - 246, - 245, - 250, - 249, - 251, - 252, - 8224, - 176, - 162, - 163, - 167, - 8226, - 182, - 223, - 174, - 169, - 8482, - 180, - 168, - 8800, - 198, - 216, - 8734, - 177, - 8804, - 8805, - 165, - 181, - 8706, - 8721, - 8719, - 960, - 8747, - 170, - 186, - 937, - 230, - 248, - 191, - 161, - 172, - 8730, - 402, - 8776, - 8710, - 171, - 187, - 8230, - 160, - 192, - 195, - 213, - 338, - 339, - 8211, - 8212, - 8220, - 8221, - 8216, - 8217, - 247, - 9674, - 255, - 376, - 8260, - 8364, - 8249, - 8250, - 64257, - 64258, - 8225, - 183, - 8218, - 8222, - 8240, - 194, - 202, - 193, - 203, - 200, - 205, - 206, - 207, - 204, - 211, - 212, - 63743, - 210, - 218, - 219, - 217, - 305, - 710, - 732, - 175, - 728, - 729, - 730, - 184, - 733, - 731, - 711, - ]; - } - - MatrixHelper _getTextRenderingMatrix() { - return MatrixHelper( - fontSize * (textHorizontalScaling! / 100), - 0, - 0, - -fontSize, - 0, - fontSize + rise!, - ) * - textLineMatrix! * - currentTransformationMatrix!; - } - - /// internal method - Map renderTextElement( - GraphicsObject? g, - Offset currentLocation, - double? textScaling, - Map? glyphWidths, - double? type1Height, - Map differenceTable, - Map differenceMappedTable, - Map? differenceEncoding, - MatrixHelper? txtMatrix, [ - List? retrievedCharCodes, - ]) { - txtMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - txtMatrix.type = MatrixTypes.identity; - double changeInX = currentLocation.dx; - Offset location = Offset(currentLocation.dx, currentLocation.dy); - if (!isEmbeddedFont && - (structure.isStandardFont || structure.isStandardCJKFont) && - structure.font != null) { - final MatrixHelper defaultTransformations = g!.transformMatrix!.clone(); - for (int i = 0; i < text.length; i++) { - final String character = text[i]; - g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - final Glyph glyph = Glyph(); - glyph.fontSize = fontSize; - glyph.fontFamily = fontName; - glyph.fontStyle = fontStyle; - glyph.transformMatrix = _getTextRenderingMatrix(); - glyph.name = character; - glyph.horizontalScaling = textHorizontalScaling!; - glyph.charId = character.codeUnitAt(0); - glyph.toUnicode = character; - glyph.charSpacing = characterSpacing!; - if (structure.isStandardFont) { - final PdfStandardFont font = structure.font! as PdfStandardFont; - glyph.width = - PdfStandardFontHelper.getHelper( - font, - ).getCharWidthInternal(character) * - PdfFontHelper.characterSizeMultiplier; - } else if (structure.isStandardCJKFont) { - final PdfCjkStandardFont font = structure.font! as PdfCjkStandardFont; - glyph.width = - PdfCjkStandardFontHelper.getHelper( - font, - ).getCharWidthInternal(character) * - PdfFontHelper.characterSizeMultiplier; - } - final MatrixHelper identity = MatrixHelper.identity.clone(); - identity.scale(0.01, 0.01, 0.0, 0.0); - identity.translate(0.0, 1.0); - transformations._pushTransform(identity * glyph.transformMatrix); - final MatrixHelper transform = g.transformMatrix!; - MatrixHelper matrix = transform.clone(); - matrix = matrix * transformations.currentTransform!.clone(); - g.transformMatrix = matrix; - double? tempFontSize = 0; - if (glyph.transformMatrix.m11 > 0) { - tempFontSize = glyph.transformMatrix.m11; - } else if (glyph.transformMatrix.m12 != 0 && - glyph.transformMatrix.m21 != 0) { - if (glyph.transformMatrix.m12 < 0) { - tempFontSize = -glyph.transformMatrix.m12; - } else { - tempFontSize = glyph.transformMatrix.m12; - } - } else { - tempFontSize = glyph.fontSize; - } - if (tempFontSize.toInt() == 0) { - tempFontSize = glyph.fontSize; - } - glyph.boundingRect = Rect.fromLTWH( - (matrix.offsetX / 1.3333333333333333) / zoomFactor!, - ((matrix.offsetY - (tempFontSize * zoomFactor!)) / - 1.3333333333333333) / - zoomFactor!, - glyph.width * tempFontSize, - tempFontSize, - ); - textElementGlyphList.add(glyph); - _updateTextMatrix(glyph); - transformations._popTransform(); - renderedText += character; - } - g.transformMatrix = defaultTransformations; - txtMatrix = textLineMatrix; - } else { - int letterCount = 0; - if ((retrievedCharCodes != null && - text.length != retrievedCharCodes.length) || - !bidi.Bidi.hasAnyRtl(text)) { - retrievedCharCodes = null; - } - for (int i = 0; i < text.length; i++) { - final String letter = text[i]; - final dynamic retrievedCharCode = - (retrievedCharCodes != null && - i < retrievedCharCodes.length && - retrievedCharCodes[i] != null && - retrievedCharCodes[i] != 0) - ? retrievedCharCodes[i] - : null; - letterCount += 1; - final int charCode = letter.codeUnitAt(0); - isTextGlyphAdded = false; - if (charCode.toUnsigned(8) > 126 && - fontEncoding == 'MacRomanEncoding' && - !isEmbeddedFont) { - isTextGlyphAdded = true; - final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( - letter, - g!, - txtMatrix, - retrievedCharCode, - ); - if (tempMatrix != null) { - txtMatrix = tempMatrix; - } else { - isTextGlyphAdded = false; - } - } else { - if (renderingMode == 1) { - isTextGlyphAdded = true; - final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( - letter, - g!, - txtMatrix, - retrievedCharCode, - ); - if (tempMatrix != null) { - txtMatrix = tempMatrix; - } else { - isTextGlyphAdded = false; - } - } else if (reverseMapTable!.isNotEmpty && - reverseMapTable!.containsKey(letter)) { - final int tempCharCode = reverseMapTable![letter]!.toInt(); - if (fontGlyphWidths != null) { - currentGlyphWidth = - (fontGlyphWidths!.containsKey( - retrievedCharCode ?? tempCharCode, - ) - ? fontGlyphWidths![retrievedCharCode ?? tempCharCode] - : defaultGlyphWidth)! * - charSizeMultiplier; - } else { - currentGlyphWidth = defaultGlyphWidth! * charSizeMultiplier; - } - txtMatrix = drawGlyphs( - currentGlyphWidth, - g!, - txtMatrix, - letter, - false, - ); - isTextGlyphAdded = true; - } else { - if (characterMapTable.isNotEmpty && - characterMapTable.containsKey(charCode)) { - final String tempLetter = characterMapTable[charCode]![0]; - isTextGlyphAdded = true; - final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( - tempLetter, - g!, - txtMatrix, - retrievedCharCode, - ); - if (tempMatrix != null) { - txtMatrix = tempMatrix; - } else { - isTextGlyphAdded = false; - } - } - } - if (!isTextGlyphAdded) { - if (characterMapTable.isNotEmpty && - characterMapTable.containsKey(charCode)) { - final String unicode = characterMapTable[charCode]![0]; - if (fontGlyphWidths == null) { - currentGlyphWidth = defaultGlyphWidth! * charSizeMultiplier; - } else { - if (structure.fontType!.name == 'Type0') { - if (cidToGidReverseMapTable != null && - cidToGidReverseMapTable!.containsKey(charCode) && - !structure.isMappingDone) { - currentGlyphWidth = - fontGlyphWidths![cidToGidReverseMapTable![charCode]!]! * - charSizeMultiplier; - } else if (fontGlyphWidths!.containsKey(charCode)) { - currentGlyphWidth = - fontGlyphWidths![charCode]! * charSizeMultiplier; - } else { - if (reverseMapTable!.containsKey(unicode) && - !fontGlyphWidths!.containsKey( - reverseMapTable![unicode]!.toInt(), - )) { - currentGlyphWidth = - defaultGlyphWidth! * charSizeMultiplier; - } - } - } else if (structure.fontType!.name == 'TrueType' && - fontGlyphWidths!.containsKey(charCode)) { - currentGlyphWidth = - fontGlyphWidths![charCode]! * charSizeMultiplier; - } - } - } else if (cidToGidReverseMapTable != null && - cidToGidReverseMapTable!.isNotEmpty) { - if (cidToGidReverseMapTable!.containsKey(charCode)) { - final int? cidGidKey = cidToGidReverseMapTable![charCode]; - if (fontGlyphWidths != null && - fontGlyphWidths!.containsKey(cidGidKey)) { - currentGlyphWidth = - fontGlyphWidths![cidGidKey!]! * charSizeMultiplier; - } - } - } else if (fontGlyphWidths != null) { - currentGlyphWidth = - (fontGlyphWidths!.containsKey(charCode) - ? fontGlyphWidths![charCode] - : defaultGlyphWidth)! * - charSizeMultiplier; - } - } - } - if (letterCount < text.length) { - location = Offset(location.dx + characterSpacing!, location.dy); - } - if (!isTextGlyphAdded) { - txtMatrix = drawGlyphs( - currentGlyphWidth, - g!, - txtMatrix, - letter, - false, - ); - } - } - } - changeInX = location.dx - changeInX; - return { - 'textElementWidth': changeInX, - 'tempTextMatrix': txtMatrix, - }; - } - - /// internal method - Map renderWithSpacing( - GraphicsObject? g, - Offset currentLocation, - Map?, String> decodedList, - List? characterSpacing, - double? textScaling, - Map? glyphWidths, - double? type1Height, - Map differenceTable, - Map differenceMappedTable, - Map? differenceEncoding, - MatrixHelper? txtMatrix, - ) { - txtMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); - txtMatrix.type = MatrixTypes.identity; - double changeInX = currentLocation.dx; - Offset location = Offset(currentLocation.dx, currentLocation.dy); - // ignore: avoid_function_literals_in_foreach_calls - decodedList.forEach((List? keys, String word) { - final double? space = double.tryParse(word); - if (space != null) { - _updateTextMatrixWithSpacing(space); - } else { - if (!isEmbeddedFont && - structure.font != null && - (structure.isStandardFont || structure.isStandardCJKFont)) { - final MatrixHelper defaultTransformations = - g!.transformMatrix!.clone(); - if (word != '' && word[word.length - 1] == 's') { - word = word.substring(0, word.length - 1); - } - for (int i = 0; i < word.length; i++) { - final String character = word[i]; - g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - final Glyph glyph = Glyph(); - glyph.fontSize = fontSize; - glyph.fontFamily = fontName; - glyph.fontStyle = fontStyle; - glyph.transformMatrix = _getTextRenderingMatrix(); - glyph.name = character; - glyph.horizontalScaling = textHorizontalScaling!; - glyph.charId = character.codeUnitAt(0); - glyph.toUnicode = character; - glyph.charSpacing = this.characterSpacing!; - if (structure.isStandardFont) { - final PdfStandardFont font = structure.font! as PdfStandardFont; - glyph.width = - PdfStandardFontHelper.getHelper( - font, - ).getCharWidthInternal(character) * - PdfFontHelper.characterSizeMultiplier; - } else if (structure.isStandardCJKFont) { - final PdfCjkStandardFont font = - structure.font! as PdfCjkStandardFont; - glyph.width = - PdfCjkStandardFontHelper.getHelper( - font, - ).getCharWidthInternal(character) * - PdfFontHelper.characterSizeMultiplier; - } - final MatrixHelper identity = MatrixHelper.identity.clone(); - identity.scale(0.01, 0.01, 0.0, 0.0); - identity.translate(0.0, 1.0); - transformations._pushTransform(identity * glyph.transformMatrix); - final MatrixHelper transform = g.transformMatrix!; - MatrixHelper matrix = transform.clone(); - matrix = matrix * transformations.currentTransform!.clone(); - g.transformMatrix = matrix; - double? tempFontSize = 0; - if (glyph.transformMatrix.m11 > 0) { - tempFontSize = glyph.transformMatrix.m11; - } else if (glyph.transformMatrix.m12 != 0 && - glyph.transformMatrix.m21 != 0) { - if (glyph.transformMatrix.m12 < 0) { - tempFontSize = -glyph.transformMatrix.m12; - } else { - tempFontSize = glyph.transformMatrix.m12; - } - } else { - tempFontSize = glyph.fontSize; - } - glyph.boundingRect = Rect.fromLTWH( - (matrix.offsetX / 1.3333333333333333) / zoomFactor!, - ((matrix.offsetY - (tempFontSize * zoomFactor!)) / - 1.3333333333333333) / - zoomFactor!, - glyph.width * tempFontSize, - tempFontSize, - ); - textElementGlyphList.add(glyph); - _updateTextMatrix(glyph); - transformations._popTransform(); - renderedText += character; - } - g.transformMatrix = defaultTransformations; - txtMatrix = textLineMatrix; - } else { - if (word != '' && word[word.length - 1] == 's') { - word = word.substring(0, word.length - 1); - } - final bool containsRTL = bidi.Bidi.hasAnyRtl(word); - if ((keys != null && - word.length > keys.length && - keys.length > word.length + 2) || - !containsRTL) { - keys = null; - } - if (word != '') { - int letterCount = 0; - bool isComplexScript = false; - if ((!containsRTL || (containsRTL && word.length <= 1)) && - reverseMapTable!.isNotEmpty && - reverseMapTable!.containsKey(word)) { - final int charCode = reverseMapTable![word]!.toInt(); - final dynamic retrievedCharCode = - (keys != null && - keys.isNotEmpty && - keys[0] != null && - keys[0] != 0) - ? keys[0] - : null; - if (characterMapTable.isNotEmpty && - characterMapTable.containsKey(charCode)) { - final String tempLetter = characterMapTable[charCode]!; - isTextGlyphAdded = true; - isComplexScript = true; - final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( - tempLetter, - g!, - txtMatrix, - retrievedCharCode, - ); - if (tempMatrix != null) { - txtMatrix = tempMatrix; - } else { - isTextGlyphAdded = false; - isComplexScript = false; - } - } - } - if (!isComplexScript) { - for (int i = 0; i < word.length; i++) { - final String letter = word[i]; - letterCount += 1; - int charCode = letter.codeUnitAt(0); - final dynamic retrievedCharCode = - (keys != null && - i < keys.length && - keys[i] != null && - keys[i] != 0) - ? keys[i] - : null; - isTextGlyphAdded = false; - if (charCode.toUnsigned(8) > 126 && - fontEncoding == 'MacRomanEncoding' && - !isEmbeddedFont) { - isTextGlyphAdded = true; - final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( - letter, - g!, - txtMatrix, - retrievedCharCode, - ); - if (tempMatrix != null) { - txtMatrix = tempMatrix; - } else { - isTextGlyphAdded = false; - } - } else { - if (renderingMode == 1) { - isTextGlyphAdded = true; - final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( - letter, - g!, - txtMatrix, - retrievedCharCode, - ); - if (tempMatrix != null) { - txtMatrix = tempMatrix; - } else { - isTextGlyphAdded = false; - } - } else { - if (reverseMapTable!.isNotEmpty && - reverseMapTable!.containsKey(letter)) { - charCode = reverseMapTable![letter]!.toInt(); - } - if (characterMapTable.isNotEmpty && - characterMapTable.containsKey(charCode)) { - final String tempLetter = characterMapTable[charCode]![0]; - isTextGlyphAdded = true; - final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( - tempLetter, - g!, - txtMatrix, - retrievedCharCode, - ); - if (tempMatrix != null) { - txtMatrix = tempMatrix; - } else { - isTextGlyphAdded = false; - } - } - } - if (characterMapTable.isNotEmpty && - characterMapTable.containsKey(charCode)) { - final String unicode = characterMapTable[charCode]![0]; - if (fontGlyphWidths == null) { - currentGlyphWidth = - defaultGlyphWidth! * charSizeMultiplier; - } else { - if (structure.fontType!.name == 'Type0') { - if (cidToGidReverseMapTable != null && - cidToGidReverseMapTable!.containsKey(charCode) && - !structure.isMappingDone) { - currentGlyphWidth = - fontGlyphWidths![cidToGidReverseMapTable![charCode]!]! * - charSizeMultiplier; - } else if (fontGlyphWidths!.containsKey(charCode)) { - currentGlyphWidth = - fontGlyphWidths![charCode]! * charSizeMultiplier; - } else { - if (reverseMapTable!.containsKey(unicode) && - !fontGlyphWidths!.containsKey( - reverseMapTable![unicode]!.toInt(), - )) { - currentGlyphWidth = - defaultGlyphWidth! * charSizeMultiplier; - } - } - } else if (structure.fontType!.name == 'TrueType' && - fontGlyphWidths!.containsKey(charCode)) { - currentGlyphWidth = - fontGlyphWidths![charCode]! * charSizeMultiplier; - } - } - } else if (cidToGidReverseMapTable != null && - cidToGidReverseMapTable!.isNotEmpty) { - if (cidToGidReverseMapTable!.containsKey(charCode)) { - final int? cidGidKey = cidToGidReverseMapTable![charCode]; - if (fontGlyphWidths != null && - fontGlyphWidths!.containsKey(cidGidKey)) { - currentGlyphWidth = - fontGlyphWidths![cidGidKey!]! * charSizeMultiplier; - } - } - } else if (fontGlyphWidths != null) { - currentGlyphWidth = - (fontGlyphWidths!.containsKey(charCode) - ? fontGlyphWidths![charCode] - : defaultGlyphWidth)! * - charSizeMultiplier; - } - } - if (letterCount < word.length) { - location = Offset( - location.dx + this.characterSpacing!, - location.dy, - ); - } - if (!isTextGlyphAdded && - (retrievedCharCode == null || - (retrievedCharCode != null && - retrievedCharCode is! String))) { - txtMatrix = drawGlyphs( - currentGlyphWidth, - g!, - txtMatrix, - letter, - i == 0, - ); - } - } - } - } - } - } - }); - changeInX = location.dx - changeInX; - return { - 'textElementWidth': changeInX, - 'tempTextMatrix': txtMatrix, - }; - } - - /// internal method - MatrixHelper? drawGlyphs( - double? glyphwidth, - GraphicsObject g, - MatrixHelper? temptextmatrix, - String? glyphChar, - bool renderWithSpace, - ) { - final MatrixHelper defaultTransformations = g.transformMatrix!.clone(); - g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - final Glyph glyph = Glyph(); - glyph.fontSize = fontSize; - glyph.fontFamily = fontName; - glyph.fontStyle = fontStyle; - glyph.transformMatrix = _getTextRenderingMatrix(); - glyph.horizontalScaling = textHorizontalScaling!; - glyph.width = glyphwidth!; - glyph.charSpacing = characterSpacing!; - if (glyphChar == ' ') { - glyph.wordSpacing = wordSpacing!; - } - final MatrixHelper identity = MatrixHelper(1, 0, 0, 1, 0, 0); - identity.scale(0.01, 0.01, 0.0, 0.0); - identity.translate(0.0, 1.0); - transformations._pushTransform(identity * glyph.transformMatrix); - final MatrixHelper transform = g.transformMatrix!; - MatrixHelper matrix = transform.clone(); - matrix *= transformations.currentTransform!.clone(); - g.transformMatrix = matrix; - if (!structure.isMappingDone) { - if (cidToGidReverseMapTable != null && - cidToGidReverseMapTable!.containsKey(glyphChar!.codeUnitAt(0)) && - (structure.characterMapTable.isNotEmpty)) { - glyphChar = - characterMapTable[cidToGidReverseMapTable![glyphChar.codeUnitAt( - 0, - )]]; - } else if (structure.characterMapTable.isNotEmpty) { - glyphChar = structure.mapCharactersFromTable(glyphChar!); - } else if (structure.differencesDictionary.isNotEmpty) { - glyphChar = structure.mapDifferences(glyphChar); - } else if (structure.cidToGidReverseMapTable.containsKey( - glyphChar!.codeUnitAt(0), - )) { - glyphChar = String.fromCharCode( - structure.cidToGidReverseMapTable[glyphChar.codeUnitAt(0)]!, - ); - } - if (glyphChar!.contains('\u0092')) { - glyphChar = glyphChar.replaceAll('\u0092', '’'); - } - } - double? tempFontSize; - if (glyph.transformMatrix.m11 > 0) { - tempFontSize = glyph.transformMatrix.m11; - } else if (glyph.transformMatrix.m12 != 0 && - glyph.transformMatrix.m21 != 0) { - tempFontSize = - glyph.transformMatrix.m12 < 0 - ? -glyph.transformMatrix.m12 - : glyph.transformMatrix.m12; - } else { - tempFontSize = glyph.fontSize; - } - final String glyphText = glyphChar!; - if (!structure.macRomanEncoded && - structure.fontEncoding == 'MacRomanEncoding') { - String tempstring = ''; - for (int i = 0; i < glyphText.length; i++) { - final int b = glyphText[i].codeUnitAt(0).toUnsigned(8); - if (b > 126) { - final String x = structure.macEncodeTable![b]!; - tempstring += x; - } else { - tempstring += glyphText[i]; - } - } - if (tempstring != '') { - glyphChar = tempstring; - } - } else { - structure.macRomanEncoded = false; - } - glyph.toUnicode = glyphChar; - if (matrix.m12 != 0 && matrix.m21 != 0) { - glyph.isRotated = true; - if (matrix.m12 < 0 && matrix.m21 > 0) { - glyph.rotationAngle = 270; - } else if (matrix.m12 > 0 && matrix.m21 < 0) { - glyph.rotationAngle = 90; - } else if (matrix.m12 < 0 && matrix.m21 < 0) { - glyph.rotationAngle = 180; - } - final double x = - ((matrix.offsetX + - ((tempFontSize + (glyph.ascent / 1000.0)) * matrix.m21)) / - 1.3333333333333333) / - zoomFactor!; - double y = - ((matrix.offsetY - - ((pageRotation == 270 - ? tempFontSize - : (glyph.width * tempFontSize)) * - zoomFactor!)) / - 1.3333333333333333) / - zoomFactor!; - double width = glyph.width * tempFontSize; - double height = tempFontSize; - if (pageRotation == 270) { - if (textElementGlyphList.isEmpty || renderWithSpace) { - y += width; - } else { - final Glyph tempGlyph = - textElementGlyphList[textElementGlyphList.length - 1]; - if (textElementGlyphList.length == 1 && tempGlyph.toUnicode == ' ') { - y += width; - } else { - y = tempGlyph.boundingRect.top + tempGlyph.boundingRect.height; - } - } - height = width; - width = tempFontSize; - } - glyph.boundingRect = Rect.fromLTWH(x, y, width, height); - } else { - glyph.boundingRect = Rect.fromLTWH( - (matrix.offsetX / 1.3333333333333333) / zoomFactor!, - ((matrix.offsetY - (tempFontSize * zoomFactor!)) / 1.3333333333333333) / - zoomFactor!, - glyph.width * tempFontSize, - tempFontSize, - ); - } - if (glyph.toUnicode.length != 1) { - textElementGlyphList.add(glyph); - for (int i = 0; i < glyph.toUnicode.length - 1; i++) { - final Glyph emptyGlyph = Glyph(); - textElementGlyphList.add(emptyGlyph); - } - } else { - textElementGlyphList.add(glyph); - } - _updateTextMatrix(glyph); - transformations._popTransform(); - g.transformMatrix = defaultTransformations; - temptextmatrix = textLineMatrix; - renderedText += glyphChar; - return temptextmatrix; - } - - /// internal method - MatrixHelper? drawSystemFontGlyphShape( - String letter, - GraphicsObject g, - MatrixHelper? temptextmatrix, [ - dynamic charCode, - ]) { - final MatrixHelper? defaultTransformations = g.transformMatrix; - g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); - final Glyph gly = Glyph(); - gly.horizontalScaling = textHorizontalScaling!; - gly.charSpacing = characterSpacing!; - gly.fontSize = fontSize; - gly.name = letter; - gly.charId = letter.codeUnitAt(0).toUnsigned(8); - gly.transformMatrix = _getTextRenderingMatrix(); - if (letter == ' ') { - gly.wordSpacing = wordSpacing!; - } - double? systemFontGlyph; - if (fontGlyphWidths != null && fontGlyphWidths!.isNotEmpty) { - if (reverseMapTable != null && reverseMapTable!.containsKey(letter)) { - if (charCode != null && charCode is String) { - systemFontGlyph = 0; - } else { - charCode ??= reverseMapTable![letter]!.toInt(); - if (fontGlyphWidths!.containsKey(charCode)) { - systemFontGlyph = fontGlyphWidths![charCode]! * charSizeMultiplier; - } else { - return null; - } - } - } else if (fontGlyphWidths!.containsKey(letter.codeUnitAt(0))) { - systemFontGlyph = - fontGlyphWidths![letter.codeUnitAt(0)]! * charSizeMultiplier; - } - } else if (defaultGlyphWidth != null && defaultGlyphWidth! > 0) { - systemFontGlyph = defaultGlyphWidth! * charSizeMultiplier; - } - gly.width = (systemFontGlyph == null) ? 0 : systemFontGlyph; - final MatrixHelper identity = MatrixHelper(1, 0, 0, 1, 0, 0); - identity.scale(0.01, 0.01, 0.0, 0.0); - identity.translate(0.0, 1.0); - transformations._pushTransform(identity * gly.transformMatrix); - final MatrixHelper transform = g.transformMatrix!; - MatrixHelper matrix = transform.clone(); - matrix = matrix * transformations.currentTransform!.clone(); - g.transformMatrix = matrix; - double? tempFontSize = 0; - if (gly.transformMatrix.m11 > 0) { - tempFontSize = gly.transformMatrix.m11; - } else if (gly.transformMatrix.m12 != 0 && gly.transformMatrix.m21 != 0) { - tempFontSize = - gly.transformMatrix.m12 < 0 - ? -gly.transformMatrix.m12 - : gly.transformMatrix.m12; - } else { - tempFontSize = gly.fontSize; - } - String? glyphName = letter; - if (!structure.isMappingDone) { - if (cidToGidReverseMapTable != null && - cidToGidReverseMapTable!.containsKey(glyphName.codeUnitAt(0)) && - (structure.characterMapTable.isNotEmpty)) { - glyphName = - characterMapTable[cidToGidReverseMapTable![glyphName.codeUnitAt( - 0, - )]]; - } else if (structure.characterMapTable.isNotEmpty) { - glyphName = structure.mapCharactersFromTable(glyphName); - } else if (structure.differencesDictionary.isNotEmpty) { - glyphName = structure.mapDifferences(glyphName); - } else if (structure.cidToGidReverseMapTable.containsKey( - glyphName.codeUnitAt(0), - )) { - glyphName = String.fromCharCode( - structure.cidToGidReverseMapTable[glyphName.codeUnitAt(0)]!, - ); - } - if (glyphName!.contains('\u0092')) { - glyphName = glyphName.replaceAll('\u0092', '’'); - } - } - if (!structure.macRomanEncoded && - structure.fontEncoding == 'MacRomanEncoding') { - String tempstring = ''; - for (int i = 0; i < glyphName.length; i++) { - final int b = glyphName[i].codeUnitAt(0).toUnsigned(8); - if (b > 126) { - final String x = structure.macEncodeTable![b]!; - tempstring += x; - } else { - tempstring += glyphName[i]; - } - } - if (tempstring != '') { - glyphName = tempstring; - } - } else { - structure.macRomanEncoded = false; - } - gly.toUnicode = glyphName; - gly.boundingRect = Rect.fromLTWH( - (matrix.offsetX / 1.3333333333333333) / zoomFactor!, - ((matrix.offsetY - (tempFontSize * zoomFactor!)) / 1.3333333333333333) / - zoomFactor!, - gly.width * tempFontSize, - tempFontSize, - ); - textElementGlyphList.add(gly); - if (isExtractTextData && gly.toUnicode.length != 1) { - for (int i = 0; i < gly.toUnicode.length - 1; i++) { - final Glyph emptyGlyph = Glyph(); - emptyGlyph.boundingRect = Rect.fromLTWH( - gly.boundingRect.right, - gly.boundingRect.top, - 0, - 0, - ); - textElementGlyphList.add(emptyGlyph); - } - } - _updateTextMatrix(gly); - transformations._popTransform(); - g.transformMatrix = defaultTransformations; - temptextmatrix = textLineMatrix; - renderedText += glyphName; - return temptextmatrix; - } - - void _updateTextMatrixWithSpacing(double space) { - final double x = -(space * 0.001 * fontSize * textHorizontalScaling! / 100); - final Offset point = textLineMatrix!.transform(Offset.zero); - final Offset point2 = textLineMatrix!.transform(Offset(x, 0.0)); - if (point.dx != point2.dx) { - textLineMatrix!.offsetX = point2.dx; - } else { - textLineMatrix!.offsetY = point2.dy; - } - } - - void _updateTextMatrix(Glyph glyph) { - textLineMatrix = _calculateTextMatrix(textLineMatrix!, glyph); - } - - MatrixHelper _calculateTextMatrix(MatrixHelper m, Glyph glyph) { - if (glyph.charId == 32) { - glyph.wordSpacing = wordSpacing!; - } - final double width = glyph.width; - final double offsetX = - (width * glyph.fontSize + glyph.charSpacing + glyph.wordSpacing) * - (glyph.horizontalScaling / 100); - return MatrixHelper(1.0, 0.0, 0.0, 1.0, offsetX, 0.0) * m; - } -} - -class TransformationStack { - TransformationStack([MatrixHelper? transformMatrix]) { - _initialTransform = - (transformMatrix != null) - ? transformMatrix - : MatrixHelper(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); - transformStack = Queue(); - } - - //Fields - late MatrixHelper _currentTransform; - MatrixHelper? _initialTransform; - late Queue transformStack; - - //Properties - MatrixHelper? get currentTransform { - if (transformStack.isEmpty) { - return _initialTransform; - } - return _currentTransform * _initialTransform!; - } - - //Implementation - void _pushTransform(MatrixHelper transformMatrix) { - transformStack.addLast(transformMatrix); - MatrixHelper matrix = MatrixHelper.identity.clone(); - for (final MatrixHelper current in transformStack) { - matrix *= current; - } - _currentTransform = matrix; - } - - void _popTransform() { - transformStack.removeLast(); - MatrixHelper matrix = MatrixHelper.identity.clone(); - for (final MatrixHelper current in transformStack) { - matrix *= current; - } - _currentTransform = matrix; - } -} +import 'dart:collection'; +import 'dart:ui'; + +import 'package:intl/intl.dart' as bidi; + +import '../../graphics/fonts/enums.dart'; +import '../../graphics/fonts/pdf_cjk_standard_font.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_standard_font.dart'; +import '../../graphics/pdf_color.dart'; +import 'font_structure.dart'; +import 'glyph.dart'; +import 'graphic_object_data.dart'; +import 'matrix_helper.dart'; + +/// internal class +class TextElement { + //constructor + /// internal constructor + TextElement(this.text, MatrixHelper? transformMatrix) { + transformations = TransformationStack(transformMatrix); + _initialize(); + } + + //Fields + /// internal field + late String text; + + /// internal field + late TransformationStack transformations; + + /// internal field + late List textElementGlyphList; + + /// internal field + late bool isExtractTextData; + + /// internal field + late String fontName; + + /// internal field + late List fontStyle; + + /// internal field + double fontSize = 0; + + /// internal field + double? textScaling; + + /// internal field + double? characterSpacing; + + /// internal field + double? wordSpacing; + + /// internal field + int? renderingMode; + + /// internal field + Map? encodedTextBytes; + + /// internal field + String? fontEncoding; + + /// internal field + Map? fontGlyphWidths; + + /// internal field + double? defaultGlyphWidth; + + /// internal field + Map? unicodeCharMapTable; + + /// internal field + Map? cidToGidReverseMapTable; + + /// internal field + late Map characterMapTable; + + /// internal field + Map? reverseMapTable; + + /// internal field + late FontStructure structure; + + /// internal field + late bool isEmbeddedFont; + + /// internal field + MatrixHelper? currentTransformationMatrix; + + /// internal field + MatrixHelper? textLineMatrix; + + /// internal field + MatrixHelper? transformMatrix; + + /// internal field + int? rise; + + /// internal field + MatrixHelper? documentMatrix; + + /// internal field + String? fontId; + + /// internal field + Map? octDecMapTable; + + /// internal field + double? textHorizontalScaling; + + /// internal field + String? zapfPostScript; + + /// internal field + double? lineWidth; + + /// internal field + double? pageRotation; + + /// internal field + double? zoomFactor; + + /// internal field + Map? substitutedFontsList; + + /// internal field + PdfFont? font; + + /// internal field + String renderedText = ''; + + /// internal field + int? fontFlag; + + /// internal field + late bool isTextGlyphAdded; + + /// internal field + double? currentGlyphWidth; + + /// internal field + late double charSizeMultiplier; + + /// internal field + List? macRomanToUnicode; + + /// internal field + PdfColor? textColor; + + //Implementation + void _initialize() { + fontName = ''; + fontStyle = []; + charSizeMultiplier = 0.001; + currentGlyphWidth = 0; + isTextGlyphAdded = false; + textElementGlyphList = []; + isExtractTextData = false; + textScaling = 100; + textHorizontalScaling = 100; + characterSpacing = 0; + wordSpacing = 0; + defaultGlyphWidth = 0; + reverseMapTable = {}; + isEmbeddedFont = false; + documentMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + documentMatrix!.type = MatrixTypes.identity; + fontId = ''; + lineWidth = 0; + pageRotation = 0; + zoomFactor = 1; + substitutedFontsList = {}; + fontFlag = 0; + macRomanToUnicode = [ + 196, + 197, + 199, + 201, + 209, + 214, + 220, + 225, + 224, + 226, + 228, + 227, + 229, + 231, + 233, + 232, + 234, + 235, + 237, + 236, + 238, + 239, + 241, + 243, + 242, + 244, + 246, + 245, + 250, + 249, + 251, + 252, + 8224, + 176, + 162, + 163, + 167, + 8226, + 182, + 223, + 174, + 169, + 8482, + 180, + 168, + 8800, + 198, + 216, + 8734, + 177, + 8804, + 8805, + 165, + 181, + 8706, + 8721, + 8719, + 960, + 8747, + 170, + 186, + 937, + 230, + 248, + 191, + 161, + 172, + 8730, + 402, + 8776, + 8710, + 171, + 187, + 8230, + 160, + 192, + 195, + 213, + 338, + 339, + 8211, + 8212, + 8220, + 8221, + 8216, + 8217, + 247, + 9674, + 255, + 376, + 8260, + 8364, + 8249, + 8250, + 64257, + 64258, + 8225, + 183, + 8218, + 8222, + 8240, + 194, + 202, + 193, + 203, + 200, + 205, + 206, + 207, + 204, + 211, + 212, + 63743, + 210, + 218, + 219, + 217, + 305, + 710, + 732, + 175, + 728, + 729, + 730, + 184, + 733, + 731, + 711, + ]; + } + + MatrixHelper _getTextRenderingMatrix() { + return MatrixHelper( + fontSize * (textHorizontalScaling! / 100), + 0, + 0, + -fontSize, + 0, + fontSize + rise!, + ) * + textLineMatrix! * + currentTransformationMatrix!; + } + + /// internal method + Map renderTextElement( + GraphicsObject? g, + Offset currentLocation, + double? textScaling, + Map? glyphWidths, + double? type1Height, + Map differenceTable, + Map differenceMappedTable, + Map? differenceEncoding, + MatrixHelper? txtMatrix, [ + List? retrievedCharCodes, + ]) { + txtMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + txtMatrix.type = MatrixTypes.identity; + double changeInX = currentLocation.dx; + Offset location = Offset(currentLocation.dx, currentLocation.dy); + if (!isEmbeddedFont && + (structure.isStandardFont || structure.isStandardCJKFont) && + structure.font != null) { + final MatrixHelper defaultTransformations = g!.transformMatrix!.clone(); + for (int i = 0; i < text.length; i++) { + final String character = text[i]; + g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + final Glyph glyph = Glyph(); + glyph.fontSize = fontSize; + glyph.fontFamily = fontName; + glyph.fontStyle = fontStyle; + glyph.transformMatrix = _getTextRenderingMatrix(); + glyph.name = character; + glyph.horizontalScaling = textHorizontalScaling!; + glyph.charId = character.codeUnitAt(0); + glyph.toUnicode = character; + glyph.charSpacing = characterSpacing!; + glyph.textColor = textColor; + if (structure.isStandardFont) { + final PdfStandardFont font = structure.font! as PdfStandardFont; + glyph.width = + PdfStandardFontHelper.getHelper( + font, + ).getCharWidthInternal(character) * + PdfFontHelper.characterSizeMultiplier; + } else if (structure.isStandardCJKFont) { + final PdfCjkStandardFont font = structure.font! as PdfCjkStandardFont; + glyph.width = + PdfCjkStandardFontHelper.getHelper( + font, + ).getCharWidthInternal(character) * + PdfFontHelper.characterSizeMultiplier; + } + final MatrixHelper identity = MatrixHelper.identity.clone(); + identity.scale(0.01, 0.01, 0.0, 0.0); + identity.translate(0.0, 1.0); + transformations._pushTransform(identity * glyph.transformMatrix); + final MatrixHelper transform = g.transformMatrix!; + MatrixHelper matrix = transform.clone(); + matrix = matrix * transformations.currentTransform!.clone(); + g.transformMatrix = matrix; + double? tempFontSize = 0; + if (glyph.transformMatrix.m11 > 0) { + tempFontSize = glyph.transformMatrix.m11; + } else if (glyph.transformMatrix.m12 != 0 && + glyph.transformMatrix.m21 != 0) { + if (glyph.transformMatrix.m12 < 0) { + tempFontSize = -glyph.transformMatrix.m12; + } else { + tempFontSize = glyph.transformMatrix.m12; + } + } else { + tempFontSize = glyph.fontSize; + } + if (tempFontSize.toInt() == 0) { + tempFontSize = glyph.fontSize; + } + glyph.boundingRect = Rect.fromLTWH( + (matrix.offsetX / 1.3333333333333333) / zoomFactor!, + ((matrix.offsetY - (tempFontSize * zoomFactor!)) / + 1.3333333333333333) / + zoomFactor!, + glyph.width * tempFontSize, + tempFontSize, + ); + textElementGlyphList.add(glyph); + _updateTextMatrix(glyph); + transformations._popTransform(); + renderedText += character; + } + g.transformMatrix = defaultTransformations; + txtMatrix = textLineMatrix; + } else { + int letterCount = 0; + if ((retrievedCharCodes != null && + text.length != retrievedCharCodes.length) || + !bidi.Bidi.hasAnyRtl(text)) { + retrievedCharCodes = null; + } + for (int i = 0; i < text.length; i++) { + final String letter = text[i]; + final dynamic retrievedCharCode = + (retrievedCharCodes != null && + i < retrievedCharCodes.length && + retrievedCharCodes[i] != null && + retrievedCharCodes[i] != 0) + ? retrievedCharCodes[i] + : null; + letterCount += 1; + final int charCode = letter.codeUnitAt(0); + isTextGlyphAdded = false; + if (charCode.toUnsigned(8) > 126 && + fontEncoding == 'MacRomanEncoding' && + !isEmbeddedFont) { + isTextGlyphAdded = true; + final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( + letter, + g!, + txtMatrix, + retrievedCharCode, + ); + if (tempMatrix != null) { + txtMatrix = tempMatrix; + } else { + isTextGlyphAdded = false; + } + } else { + if (renderingMode == 1) { + isTextGlyphAdded = true; + final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( + letter, + g!, + txtMatrix, + retrievedCharCode, + ); + if (tempMatrix != null) { + txtMatrix = tempMatrix; + } else { + isTextGlyphAdded = false; + } + } else if (reverseMapTable!.isNotEmpty && + reverseMapTable!.containsKey(letter)) { + final int tempCharCode = reverseMapTable![letter]!.toInt(); + if (fontGlyphWidths != null) { + currentGlyphWidth = + (fontGlyphWidths!.containsKey( + retrievedCharCode ?? tempCharCode, + ) + ? fontGlyphWidths![retrievedCharCode ?? tempCharCode] + : defaultGlyphWidth)! * + charSizeMultiplier; + } else { + currentGlyphWidth = defaultGlyphWidth! * charSizeMultiplier; + } + txtMatrix = drawGlyphs( + currentGlyphWidth, + g!, + txtMatrix, + letter, + false, + ); + isTextGlyphAdded = true; + } else { + if (characterMapTable.isNotEmpty && + characterMapTable.containsKey(charCode)) { + final String tempLetter = characterMapTable[charCode]![0]; + isTextGlyphAdded = true; + final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( + tempLetter, + g!, + txtMatrix, + retrievedCharCode, + ); + if (tempMatrix != null) { + txtMatrix = tempMatrix; + } else { + isTextGlyphAdded = false; + } + } + } + if (!isTextGlyphAdded) { + if (characterMapTable.isNotEmpty && + characterMapTable.containsKey(charCode)) { + final String unicode = characterMapTable[charCode]![0]; + if (fontGlyphWidths == null) { + currentGlyphWidth = defaultGlyphWidth! * charSizeMultiplier; + } else { + if (structure.fontType!.name == 'Type0') { + if (cidToGidReverseMapTable != null && + cidToGidReverseMapTable!.containsKey(charCode) && + !structure.isMappingDone) { + currentGlyphWidth = + fontGlyphWidths![cidToGidReverseMapTable![charCode]!]! * + charSizeMultiplier; + } else if (fontGlyphWidths!.containsKey(charCode)) { + currentGlyphWidth = + fontGlyphWidths![charCode]! * charSizeMultiplier; + } else { + if (reverseMapTable!.containsKey(unicode) && + !fontGlyphWidths!.containsKey( + reverseMapTable![unicode]!.toInt(), + )) { + currentGlyphWidth = + defaultGlyphWidth! * charSizeMultiplier; + } + } + } else if (structure.fontType!.name == 'TrueType' && + fontGlyphWidths!.containsKey(charCode)) { + currentGlyphWidth = + fontGlyphWidths![charCode]! * charSizeMultiplier; + } + } + } else if (cidToGidReverseMapTable != null && + cidToGidReverseMapTable!.isNotEmpty) { + if (cidToGidReverseMapTable!.containsKey(charCode)) { + final int? cidGidKey = cidToGidReverseMapTable![charCode]; + if (fontGlyphWidths != null && + fontGlyphWidths!.containsKey(cidGidKey)) { + currentGlyphWidth = + fontGlyphWidths![cidGidKey!]! * charSizeMultiplier; + } + } + } else if (fontGlyphWidths != null) { + currentGlyphWidth = + (fontGlyphWidths!.containsKey(charCode) + ? fontGlyphWidths![charCode] + : defaultGlyphWidth)! * + charSizeMultiplier; + } + } + } + if (letterCount < text.length) { + location = Offset(location.dx + characterSpacing!, location.dy); + } + if (!isTextGlyphAdded) { + txtMatrix = drawGlyphs( + currentGlyphWidth, + g!, + txtMatrix, + letter, + false, + ); + } + } + } + changeInX = location.dx - changeInX; + return { + 'textElementWidth': changeInX, + 'tempTextMatrix': txtMatrix, + }; + } + + /// internal method + Map renderWithSpacing( + GraphicsObject? g, + Offset currentLocation, + Map?, String> decodedList, + List? characterSpacing, + double? textScaling, + Map? glyphWidths, + double? type1Height, + Map differenceTable, + Map differenceMappedTable, + Map? differenceEncoding, + MatrixHelper? txtMatrix, + ) { + txtMatrix = MatrixHelper(0, 0, 0, 0, 0, 0); + txtMatrix.type = MatrixTypes.identity; + double changeInX = currentLocation.dx; + Offset location = Offset(currentLocation.dx, currentLocation.dy); + final reverseMap = { + for (final entry in differenceMappedTable.entries) entry.value: entry.key, + }; + // ignore: avoid_function_literals_in_foreach_calls + decodedList.forEach((List? keys, String word) { + final double? space = double.tryParse(word); + if (space != null) { + _updateTextMatrixWithSpacing(space); + } else { + if (!isEmbeddedFont && + structure.font != null && + (structure.isStandardFont || structure.isStandardCJKFont)) { + final MatrixHelper defaultTransformations = + g!.transformMatrix!.clone(); + if (word != '' && word[word.length - 1] == 's') { + word = word.substring(0, word.length - 1); + } + for (int i = 0; i < word.length; i++) { + final String character = word[i]; + g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + final Glyph glyph = Glyph(); + glyph.fontSize = fontSize; + glyph.fontFamily = fontName; + glyph.fontStyle = fontStyle; + glyph.transformMatrix = _getTextRenderingMatrix(); + glyph.name = character; + glyph.horizontalScaling = textHorizontalScaling!; + glyph.charId = character.codeUnitAt(0); + glyph.toUnicode = character; + glyph.charSpacing = this.characterSpacing!; + glyph.textColor = textColor; + if (structure.isStandardFont) { + final PdfStandardFont font = structure.font! as PdfStandardFont; + glyph.width = + PdfStandardFontHelper.getHelper( + font, + ).getCharWidthInternal(character) * + PdfFontHelper.characterSizeMultiplier; + } else if (structure.isStandardCJKFont) { + final PdfCjkStandardFont font = + structure.font! as PdfCjkStandardFont; + glyph.width = + PdfCjkStandardFontHelper.getHelper( + font, + ).getCharWidthInternal(character) * + PdfFontHelper.characterSizeMultiplier; + } + final MatrixHelper identity = MatrixHelper.identity.clone(); + identity.scale(0.01, 0.01, 0.0, 0.0); + identity.translate(0.0, 1.0); + transformations._pushTransform(identity * glyph.transformMatrix); + final MatrixHelper transform = g.transformMatrix!; + MatrixHelper matrix = transform.clone(); + matrix = matrix * transformations.currentTransform!.clone(); + g.transformMatrix = matrix; + double? tempFontSize = 0; + if (glyph.transformMatrix.m11 > 0) { + tempFontSize = glyph.transformMatrix.m11; + } else if (glyph.transformMatrix.m12 != 0 && + glyph.transformMatrix.m21 != 0) { + if (glyph.transformMatrix.m12 < 0) { + tempFontSize = -glyph.transformMatrix.m12; + } else { + tempFontSize = glyph.transformMatrix.m12; + } + } else { + tempFontSize = glyph.fontSize; + } + glyph.boundingRect = Rect.fromLTWH( + (matrix.offsetX / 1.3333333333333333) / zoomFactor!, + ((matrix.offsetY - (tempFontSize * zoomFactor!)) / + 1.3333333333333333) / + zoomFactor!, + glyph.width * tempFontSize, + tempFontSize, + ); + textElementGlyphList.add(glyph); + _updateTextMatrix(glyph); + transformations._popTransform(); + renderedText += character; + } + g.transformMatrix = defaultTransformations; + txtMatrix = textLineMatrix; + } else { + if (word != '' && word[word.length - 1] == 's') { + word = word.substring(0, word.length - 1); + } + final bool containsRTL = bidi.Bidi.hasAnyRtl(word); + if ((keys != null && + word.length > keys.length && + keys.length > word.length + 2) || + !containsRTL) { + keys = null; + } + if (word != '') { + int letterCount = 0; + bool isComplexScript = false; + if ((!containsRTL || (containsRTL && word.length <= 1)) && + reverseMapTable!.isNotEmpty && + reverseMapTable!.containsKey(word)) { + final int charCode = reverseMapTable![word]!.toInt(); + final dynamic retrievedCharCode = + (keys != null && + keys.isNotEmpty && + keys[0] != null && + keys[0] != 0) + ? keys[0] + : null; + if (characterMapTable.isNotEmpty && + characterMapTable.containsKey(charCode)) { + final String tempLetter = characterMapTable[charCode]!; + isTextGlyphAdded = true; + isComplexScript = true; + final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( + tempLetter, + g!, + txtMatrix, + retrievedCharCode, + ); + if (tempMatrix != null) { + txtMatrix = tempMatrix; + } else { + isTextGlyphAdded = false; + isComplexScript = false; + } + } + } + if (!isComplexScript) { + for (int i = 0; i < word.length; i++) { + final String letter = word[i]; + letterCount += 1; + int charCode = letter.codeUnitAt(0); + final dynamic retrievedCharCode = + (keys != null && + i < keys.length && + keys[i] != null && + keys[i] != 0) + ? keys[i] + : null; + isTextGlyphAdded = false; + if (charCode.toUnsigned(8) > 126 && + fontEncoding == 'MacRomanEncoding' && + !isEmbeddedFont) { + isTextGlyphAdded = true; + final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( + letter, + g!, + txtMatrix, + retrievedCharCode, + ); + if (tempMatrix != null) { + txtMatrix = tempMatrix; + } else { + isTextGlyphAdded = false; + } + } else { + if (renderingMode == 1) { + isTextGlyphAdded = true; + final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( + letter, + g!, + txtMatrix, + retrievedCharCode, + ); + if (tempMatrix != null) { + txtMatrix = tempMatrix; + } else { + isTextGlyphAdded = false; + } + } else { + if (reverseMapTable!.isNotEmpty && + reverseMapTable!.containsKey(letter)) { + charCode = reverseMapTable![letter]!.toInt(); + } + if (characterMapTable.isNotEmpty && + characterMapTable.containsKey(charCode)) { + final String tempLetter = characterMapTable[charCode]![0]; + isTextGlyphAdded = true; + final MatrixHelper? tempMatrix = drawSystemFontGlyphShape( + tempLetter, + g!, + txtMatrix, + retrievedCharCode, + ); + if (tempMatrix != null) { + txtMatrix = tempMatrix; + } else { + isTextGlyphAdded = false; + } + } + } + if (characterMapTable.isNotEmpty && + characterMapTable.containsKey(charCode)) { + final String unicode = characterMapTable[charCode]![0]; + if (fontGlyphWidths == null) { + currentGlyphWidth = + defaultGlyphWidth! * charSizeMultiplier; + } else { + if (structure.fontType!.name == 'Type0') { + if (cidToGidReverseMapTable != null && + cidToGidReverseMapTable!.containsKey(charCode) && + !structure.isMappingDone) { + currentGlyphWidth = + fontGlyphWidths![cidToGidReverseMapTable![charCode]!]! * + charSizeMultiplier; + } else if (fontGlyphWidths!.containsKey(charCode)) { + currentGlyphWidth = + fontGlyphWidths![charCode]! * charSizeMultiplier; + } else { + if (reverseMapTable!.containsKey(unicode) && + !fontGlyphWidths!.containsKey( + reverseMapTable![unicode]!.toInt(), + )) { + currentGlyphWidth = + defaultGlyphWidth! * charSizeMultiplier; + } + } + } else if (structure.fontType!.name == 'TrueType' && + fontGlyphWidths!.containsKey(charCode)) { + currentGlyphWidth = + fontGlyphWidths![charCode]! * charSizeMultiplier; + } + } + } else if (cidToGidReverseMapTable != null && + cidToGidReverseMapTable!.isNotEmpty) { + if (cidToGidReverseMapTable!.containsKey(charCode)) { + final int? cidGidKey = cidToGidReverseMapTable![charCode]; + if (fontGlyphWidths != null && + fontGlyphWidths!.containsKey(cidGidKey)) { + currentGlyphWidth = + fontGlyphWidths![cidGidKey!]! * charSizeMultiplier; + } + } + } else if (differenceMappedTable.containsValue(letter)) { + final key = reverseMap[letter]; + final int? mappedValue = int.tryParse(key ?? ''); + if (mappedValue != null && + glyphWidths!.containsKey(mappedValue)) { + currentGlyphWidth = + glyphWidths[mappedValue]!.toDouble() * + charSizeMultiplier; + } + } else if (fontGlyphWidths != null) { + currentGlyphWidth = + (fontGlyphWidths!.containsKey(charCode) + ? fontGlyphWidths![charCode] + : defaultGlyphWidth)! * + charSizeMultiplier; + } + } + if (letterCount < word.length) { + location = Offset( + location.dx + this.characterSpacing!, + location.dy, + ); + } + if (!isTextGlyphAdded && + (retrievedCharCode == null || + (retrievedCharCode != null && + retrievedCharCode is! String))) { + txtMatrix = drawGlyphs( + currentGlyphWidth, + g!, + txtMatrix, + letter, + i == 0, + ); + } + } + } + } + } + } + }); + changeInX = location.dx - changeInX; + return { + 'textElementWidth': changeInX, + 'tempTextMatrix': txtMatrix, + }; + } + + /// internal method + MatrixHelper? drawGlyphs( + double? glyphwidth, + GraphicsObject g, + MatrixHelper? temptextmatrix, + String? glyphChar, + bool renderWithSpace, + ) { + final MatrixHelper defaultTransformations = g.transformMatrix!.clone(); + g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + final Glyph glyph = Glyph(); + glyph.fontSize = fontSize; + glyph.fontFamily = fontName; + glyph.fontStyle = fontStyle; + glyph.transformMatrix = _getTextRenderingMatrix(); + glyph.horizontalScaling = textHorizontalScaling!; + glyph.width = glyphwidth!; + glyph.charSpacing = characterSpacing!; + glyph.textColor = textColor; + if (glyphChar == ' ') { + glyph.wordSpacing = wordSpacing!; + } + final MatrixHelper identity = MatrixHelper(1, 0, 0, 1, 0, 0); + identity.scale(0.01, 0.01, 0.0, 0.0); + identity.translate(0.0, 1.0); + transformations._pushTransform(identity * glyph.transformMatrix); + final MatrixHelper transform = g.transformMatrix!; + MatrixHelper matrix = transform.clone(); + matrix *= transformations.currentTransform!.clone(); + g.transformMatrix = matrix; + if (!structure.isMappingDone) { + if (cidToGidReverseMapTable != null && + cidToGidReverseMapTable!.containsKey(glyphChar!.codeUnitAt(0)) && + (structure.characterMapTable.isNotEmpty)) { + glyphChar = + characterMapTable[cidToGidReverseMapTable![glyphChar.codeUnitAt( + 0, + )]]; + } else if (structure.characterMapTable.isNotEmpty) { + glyphChar = structure.mapCharactersFromTable(glyphChar!); + } else if (structure.differencesDictionary.isNotEmpty) { + glyphChar = structure.mapDifferences(glyphChar); + } else if (structure.cidToGidReverseMapTable.containsKey( + glyphChar!.codeUnitAt(0), + )) { + glyphChar = String.fromCharCode( + structure.cidToGidReverseMapTable[glyphChar.codeUnitAt(0)]!, + ); + } + if (glyphChar!.contains('\u0092')) { + glyphChar = glyphChar.replaceAll('\u0092', '’'); + } + } + double? tempFontSize; + if (glyph.transformMatrix.m11 > 0) { + tempFontSize = glyph.transformMatrix.m11; + } else if (glyph.transformMatrix.m12 != 0 && + glyph.transformMatrix.m21 != 0) { + tempFontSize = + glyph.transformMatrix.m12 < 0 + ? -glyph.transformMatrix.m12 + : glyph.transformMatrix.m12; + } else { + tempFontSize = glyph.fontSize; + } + final String glyphText = glyphChar!; + if (!structure.macRomanEncoded && + structure.fontEncoding == 'MacRomanEncoding') { + String tempstring = ''; + for (int i = 0; i < glyphText.length; i++) { + final int b = glyphText[i].codeUnitAt(0).toUnsigned(8); + if (b > 126) { + final String x = structure.macEncodeTable![b]!; + tempstring += x; + } else { + tempstring += glyphText[i]; + } + } + if (tempstring != '') { + glyphChar = tempstring; + } + } else { + structure.macRomanEncoded = false; + } + glyph.toUnicode = glyphChar; + if (matrix.m12 != 0 && matrix.m21 != 0) { + glyph.isRotated = true; + if (matrix.m12 < 0 && matrix.m21 > 0) { + glyph.rotationAngle = 270; + } else if (matrix.m12 > 0 && matrix.m21 < 0) { + glyph.rotationAngle = 90; + } else if (matrix.m12 < 0 && matrix.m21 < 0) { + glyph.rotationAngle = 180; + } + double x = + ((matrix.offsetX + + ((tempFontSize + (glyph.ascent / 1000.0)) * matrix.m21)) / + 1.3333333333333333) / + zoomFactor!; + double y = + ((matrix.offsetY - + ((pageRotation == 270 + ? tempFontSize + : (glyph.width * tempFontSize)) * + zoomFactor!)) / + 1.3333333333333333) / + zoomFactor!; + double width = glyph.width * tempFontSize; + double height = tempFontSize; + if (pageRotation == 90 && glyph.rotationAngle == 270) { + height = glyph.width * tempFontSize; + width = tempFontSize; + x -= tempFontSize; + } else if (pageRotation == 270) { + if (textElementGlyphList.isEmpty || renderWithSpace) { + y += width; + } else { + final Glyph tempGlyph = + textElementGlyphList[textElementGlyphList.length - 1]; + if (textElementGlyphList.length == 1 && tempGlyph.toUnicode == ' ') { + y += width; + } else { + y = tempGlyph.boundingRect.top + tempGlyph.boundingRect.height; + } + } + height = width; + width = tempFontSize; + } + glyph.boundingRect = Rect.fromLTWH(x, y, width, height); + } else { + glyph.boundingRect = Rect.fromLTWH( + (matrix.offsetX / 1.3333333333333333) / zoomFactor!, + ((matrix.offsetY - (tempFontSize * zoomFactor!)) / 1.3333333333333333) / + zoomFactor!, + glyph.width * tempFontSize, + tempFontSize, + ); + } + if (glyph.toUnicode.length != 1) { + textElementGlyphList.add(glyph); + for (int i = 0; i < glyph.toUnicode.length - 1; i++) { + final Glyph emptyGlyph = Glyph(); + emptyGlyph.textColor = textColor; + textElementGlyphList.add(emptyGlyph); + } + } else { + textElementGlyphList.add(glyph); + } + _updateTextMatrix(glyph); + transformations._popTransform(); + g.transformMatrix = defaultTransformations; + temptextmatrix = textLineMatrix; + renderedText += glyphChar; + return temptextmatrix; + } + + /// internal method + MatrixHelper? drawSystemFontGlyphShape( + String letter, + GraphicsObject g, + MatrixHelper? temptextmatrix, [ + dynamic charCode, + ]) { + final MatrixHelper? defaultTransformations = g.transformMatrix; + g.transformMatrix = MatrixHelper(1, 0, 0, 1, 0, 0); + final Glyph gly = Glyph(); + gly.horizontalScaling = textHorizontalScaling!; + gly.charSpacing = characterSpacing!; + gly.fontSize = fontSize; + gly.name = letter; + gly.charId = letter.codeUnitAt(0).toUnsigned(8); + gly.transformMatrix = _getTextRenderingMatrix(); + gly.textColor = textColor; + if (letter == ' ') { + gly.wordSpacing = wordSpacing!; + } + double? systemFontGlyph; + if (fontGlyphWidths != null && fontGlyphWidths!.isNotEmpty) { + if (reverseMapTable != null && reverseMapTable!.containsKey(letter)) { + if (charCode != null && charCode is String) { + systemFontGlyph = 0; + } else { + charCode ??= reverseMapTable![letter]!.toInt(); + if (fontGlyphWidths!.containsKey(charCode)) { + systemFontGlyph = fontGlyphWidths![charCode]! * charSizeMultiplier; + } else { + return null; + } + } + } else if (fontGlyphWidths!.containsKey(letter.codeUnitAt(0))) { + systemFontGlyph = + fontGlyphWidths![letter.codeUnitAt(0)]! * charSizeMultiplier; + } + } else if (defaultGlyphWidth != null && defaultGlyphWidth! > 0) { + systemFontGlyph = defaultGlyphWidth! * charSizeMultiplier; + } + gly.width = (systemFontGlyph == null) ? 0 : systemFontGlyph; + final MatrixHelper identity = MatrixHelper(1, 0, 0, 1, 0, 0); + identity.scale(0.01, 0.01, 0.0, 0.0); + identity.translate(0.0, 1.0); + transformations._pushTransform(identity * gly.transformMatrix); + final MatrixHelper transform = g.transformMatrix!; + MatrixHelper matrix = transform.clone(); + matrix = matrix * transformations.currentTransform!.clone(); + g.transformMatrix = matrix; + double? tempFontSize = 0; + if (gly.transformMatrix.m11 > 0) { + tempFontSize = gly.transformMatrix.m11; + } else if (gly.transformMatrix.m12 != 0 && gly.transformMatrix.m21 != 0) { + tempFontSize = + gly.transformMatrix.m12 < 0 + ? -gly.transformMatrix.m12 + : gly.transformMatrix.m12; + } else { + tempFontSize = gly.fontSize; + } + String? glyphName = letter; + if (!structure.isMappingDone) { + if (cidToGidReverseMapTable != null && + cidToGidReverseMapTable!.containsKey(glyphName.codeUnitAt(0)) && + (structure.characterMapTable.isNotEmpty)) { + glyphName = + characterMapTable[cidToGidReverseMapTable![glyphName.codeUnitAt( + 0, + )]]; + } else if (structure.characterMapTable.isNotEmpty) { + glyphName = structure.mapCharactersFromTable(glyphName); + } else if (structure.differencesDictionary.isNotEmpty) { + glyphName = structure.mapDifferences(glyphName); + } else if (structure.cidToGidReverseMapTable.containsKey( + glyphName.codeUnitAt(0), + )) { + glyphName = String.fromCharCode( + structure.cidToGidReverseMapTable[glyphName.codeUnitAt(0)]!, + ); + } + if (glyphName!.contains('\u0092')) { + glyphName = glyphName.replaceAll('\u0092', '’'); + } + } + if (!structure.macRomanEncoded && + structure.fontEncoding == 'MacRomanEncoding') { + String tempstring = ''; + for (int i = 0; i < glyphName.length; i++) { + final int b = glyphName[i].codeUnitAt(0).toUnsigned(8); + if (b > 126) { + final String x = structure.macEncodeTable![b]!; + tempstring += x; + } else { + tempstring += glyphName[i]; + } + } + if (tempstring != '') { + glyphName = tempstring; + } + } else { + structure.macRomanEncoded = false; + } + gly.toUnicode = glyphName; + gly.boundingRect = Rect.fromLTWH( + (matrix.offsetX / 1.3333333333333333) / zoomFactor!, + ((matrix.offsetY - (tempFontSize * zoomFactor!)) / 1.3333333333333333) / + zoomFactor!, + gly.width * tempFontSize, + tempFontSize, + ); + textElementGlyphList.add(gly); + if (isExtractTextData && gly.toUnicode.length != 1) { + for (int i = 0; i < gly.toUnicode.length - 1; i++) { + final Glyph emptyGlyph = Glyph(); + emptyGlyph.textColor = textColor; + emptyGlyph.boundingRect = Rect.fromLTWH( + gly.boundingRect.right, + gly.boundingRect.top, + 0, + 0, + ); + textElementGlyphList.add(emptyGlyph); + } + } + _updateTextMatrix(gly); + transformations._popTransform(); + g.transformMatrix = defaultTransformations; + temptextmatrix = textLineMatrix; + renderedText += glyphName; + return temptextmatrix; + } + + void _updateTextMatrixWithSpacing(double space) { + final double x = -(space * 0.001 * fontSize * textHorizontalScaling! / 100); + final Offset point = textLineMatrix!.transform(Offset.zero); + final Offset point2 = textLineMatrix!.transform(Offset(x, 0.0)); + if (point.dx != point2.dx) { + textLineMatrix!.offsetX = point2.dx; + } else { + textLineMatrix!.offsetY = point2.dy; + } + } + + void _updateTextMatrix(Glyph glyph) { + textLineMatrix = _calculateTextMatrix(textLineMatrix!, glyph); + } + + MatrixHelper _calculateTextMatrix(MatrixHelper m, Glyph glyph) { + if (glyph.charId == 32) { + glyph.wordSpacing = wordSpacing!; + } + final double width = glyph.width; + final double offsetX = + (width * glyph.fontSize + glyph.charSpacing + glyph.wordSpacing) * + (glyph.horizontalScaling / 100); + return MatrixHelper(1.0, 0.0, 0.0, 1.0, offsetX, 0.0) * m; + } +} + +class TransformationStack { + TransformationStack([MatrixHelper? transformMatrix]) { + _initialTransform = + (transformMatrix != null) + ? transformMatrix + : MatrixHelper(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + transformStack = Queue(); + } + + //Fields + late MatrixHelper _currentTransform; + MatrixHelper? _initialTransform; + late Queue transformStack; + + //Properties + MatrixHelper? get currentTransform { + if (transformStack.isEmpty) { + return _initialTransform; + } + return _currentTransform * _initialTransform!; + } + + //Implementation + void _pushTransform(MatrixHelper transformMatrix) { + transformStack.addLast(transformMatrix); + MatrixHelper matrix = MatrixHelper.identity.clone(); + for (final MatrixHelper current in transformStack) { + matrix *= current; + } + _currentTransform = matrix; + } + + void _popTransform() { + transformStack.removeLast(); + MatrixHelper matrix = MatrixHelper.identity.clone(); + for (final MatrixHelper current in transformStack) { + matrix *= current; + } + _currentTransform = matrix; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_glyph.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_glyph.dart index e7631c63e..2baa53e39 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_glyph.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_glyph.dart @@ -1,49 +1,49 @@ -import 'dart:ui'; -import '../../graphics/fonts/enums.dart'; - -/// Gets the details of character in the word. -class TextGlyph { - TextGlyph._( - this.text, - this.fontName, - this.fontStyle, - this.bounds, - this.fontSize, - this.isRotated, - ); - - //Fields - /// Gets the bounds of glyph. - late Rect bounds; - - /// Gets the text of glyph. - late String text; - - /// Gets the font size of glyph. - late double fontSize; - - /// Gets the font name of glyph. - late String fontName; - - /// Gets the font style of glyph. - late List fontStyle; - - /// Gets or sets a value indicating whether the glyph is rotated or not. - late bool isRotated; -} - -// ignore: avoid_classes_with_only_static_members -/// [TextGlyph] helper -class TextGlyphHelper { - /// internal method - static TextGlyph initialize( - String text, - String fontName, - List fontStyle, [ - Rect bounds = Rect.zero, - double fontSize = 0, - bool isRotated = false, - ]) { - return TextGlyph._(text, fontName, fontStyle, bounds, fontSize, isRotated); - } -} +import 'dart:ui'; +import '../../graphics/fonts/enums.dart'; + +/// Gets the details of character in the word. +class TextGlyph { + TextGlyph._( + this.text, + this.fontName, + this.fontStyle, + this.bounds, + this.fontSize, + this.isRotated, + ); + + //Fields + /// Gets the bounds of glyph. + late Rect bounds; + + /// Gets the text of glyph. + late String text; + + /// Gets the font size of glyph. + late double fontSize; + + /// Gets the font name of glyph. + late String fontName; + + /// Gets the font style of glyph. + late List fontStyle; + + /// Gets or sets a value indicating whether the glyph is rotated or not. + late bool isRotated; +} + +// ignore: avoid_classes_with_only_static_members +/// [TextGlyph] helper +class TextGlyphHelper { + /// internal method + static TextGlyph initialize( + String text, + String fontName, + List fontStyle, [ + Rect bounds = Rect.zero, + double fontSize = 0, + bool isRotated = false, + ]) { + return TextGlyph._(text, fontName, fontStyle, bounds, fontSize, isRotated); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_line.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_line.dart index 47f5f3ad1..79687ce3b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_line.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_line.dart @@ -1,49 +1,53 @@ -import 'dart:ui'; - -import '../../graphics/fonts/enums.dart'; -import 'text_word.dart'; - -/// Details of the text present in a line -class TextLine { - //constructor - TextLine._() { - wordCollection = []; - bounds = Rect.zero; - fontSize = 0; - text = ''; - pageIndex = 0; - fontName = ''; - fontStyle = []; - } - - //Fields - /// Gets the collection of words present in the line. - late List wordCollection; - - /// Gets the bounds of the text. - late Rect bounds; - - /// Gets the font name of the text. - late String fontName; - - /// Gets the font style of the text. - late List fontStyle; - - /// Gets the font size of the text. - late double fontSize; - - /// Gets the page index. - late int pageIndex; - - /// Gets the text. - late String text; -} - -// ignore: avoid_classes_with_only_static_members -/// [TextLine] helper -class TextLineHelper { - /// internal method - static TextLine initialize() { - return TextLine._(); - } -} +import 'dart:ui'; + +import '../../graphics/fonts/enums.dart'; +import '../../graphics/pdf_color.dart'; +import 'text_word.dart'; + +/// Details of the text present in a line +class TextLine { + //constructor + TextLine._() { + wordCollection = []; + bounds = Rect.zero; + fontSize = 0; + text = ''; + pageIndex = 0; + fontName = ''; + fontStyle = []; + } + + //Fields + /// Gets the collection of words present in the line. + late List wordCollection; + + /// Gets the bounds of the text. + late Rect bounds; + + /// Gets the font name of the text. + late String fontName; + + /// Gets the font style of the text. + late List fontStyle; + + /// Gets the font size of the text. + late double fontSize; + + /// Gets the page index. + late int pageIndex; + + /// Gets the text. + late String text; + + /// Gets the color of the text. + PdfColor? textColor; +} + +// ignore: avoid_classes_with_only_static_members +/// [TextLine] helper +class TextLineHelper { + /// internal method + static TextLine initialize() { + return TextLine._(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_word.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_word.dart index 0f6555edd..6cb07c0b7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_word.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/text_word.dart @@ -1,56 +1,71 @@ -import 'dart:ui'; - -import '../../graphics/fonts/enums.dart'; -import 'text_glyph.dart'; - -/// Details of a word present in the line. -class TextWord { - //constructor - TextWord._( - this.text, - this.fontName, - this.fontStyle, - List glyphs, - this.bounds, - this.fontSize, - ) { - _glyphs = glyphs; - } - - //Fields - /// Gets the text. - late String text; - - /// Gets the bounds of the word. - late Rect bounds; - - /// Gets the font size of the word. - late double fontSize; - - /// Gets the font name of the word. - late String fontName; - - /// Gets the font style of the word. - late List fontStyle; - List _glyphs = []; - - //Properties - /// Gets the text glyph with bounds in the word. - List get glyphs => _glyphs; -} - -// ignore: avoid_classes_with_only_static_members -/// [TextWord] helper -class TextWordHelper { - /// internal method - static TextWord initialize( - String text, - String fontName, - List fontStyle, - List glyphs, [ - Rect bounds = Rect.zero, - double fontSize = 0, - ]) { - return TextWord._(text, fontName, fontStyle, glyphs, bounds, fontSize); - } -} +import 'dart:ui'; + +import '../../graphics/fonts/enums.dart'; +import '../../graphics/pdf_color.dart'; +import 'text_glyph.dart'; + +/// Details of a word present in the line. +class TextWord { + //constructor + TextWord._( + this.text, + this.fontName, + this.fontStyle, + List glyphs, + this.bounds, + this.fontSize, + this.textColor, + ) { + _glyphs = glyphs; + } + + //Fields + /// Gets the text. + late String text; + + /// Gets the bounds of the word. + late Rect bounds; + + /// Gets the font size of the word. + late double fontSize; + + /// Gets the font name of the word. + late String fontName; + + /// Gets the font style of the word. + late List fontStyle; + + /// Gets the color of the word text. + PdfColor? textColor; + + List _glyphs = []; + + //Properties + /// Gets the text glyph with bounds in the word. + List get glyphs => _glyphs; +} + +// ignore: avoid_classes_with_only_static_members +/// [TextWord] helper +class TextWordHelper { + /// internal method + static TextWord initialize( + String text, + String fontName, + List fontStyle, + List glyphs, [ + Rect bounds = Rect.zero, + double fontSize = 0, + PdfColor? textColor, + ]) { + return TextWord._( + text, + fontName, + fontStyle, + glyphs, + bounds, + fontSize, + textColor, + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/xobject_element.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/xobject_element.dart index cd9eb22be..31d238dfb 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/xobject_element.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/exporting/pdf_text_extractor/xobject_element.dart @@ -1,277 +1,277 @@ -import 'dart:math'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_number.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_stream.dart'; -import 'glyph.dart'; -import 'graphic_object_data.dart'; -import 'graphic_object_data_collection.dart'; -import 'image_renderer.dart'; -import 'matrix_helper.dart'; -import 'page_resource_loader.dart'; -import 'parser/content_parser.dart'; -import 'text_element.dart'; - -/// internal class -class XObjectElement { - /// internal constructor - XObjectElement(this.dictionary, String? name) { - _objectName = name; - getObjectType(); - isPrintSelected = false; - pageHeight = 0; - } - - //Fields - // ignore: unused_field - String? _objectName; - String? _objectType; - - /// internal field - PdfDictionary? dictionary; - - /// internal field - bool? isPrintSelected; - - /// internal field - double? pageHeight; - - /// internal field - bool? isExtractTextLine; - - //Implementation - /// internal method - void getObjectType() { - if (dictionary!.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? primitive = - dictionary![PdfDictionaryProperties.subtype]; - if (primitive is PdfName) { - _objectType = primitive.name; - } - } - } - - /// internal method - PdfRecordCollection? render(PdfPageResources? resources) { - if (_objectType != null && - _objectType == 'Form' && - dictionary is PdfStream) { - final PdfStream stream = dictionary! as PdfStream; - stream.decompress(); - return ContentParser(stream.dataStream).readContent(); - } else { - return null; - } - } - - /// internal method - Map renderTextElement( - GraphicsObject? g, - PdfPageResources? resources, - GraphicStateCollection? graphicsStates, - GraphicObjectDataCollection? objects, - double? currentPageHeight, - List? glyphList, - ) { - glyphList = []; - List? extractTextElement; - if (_objectType != null && - _objectType == 'Form' && - dictionary != null && - dictionary is PdfStream) { - final PdfStream stream = dictionary! as PdfStream; - stream.decompress(); - final ContentParser parser = ContentParser(stream.dataStream); - final PdfRecordCollection? contentTree = parser.readContent(); - final PageResourceLoader resourceLoader = PageResourceLoader(); - PdfDictionary pageDictionary = PdfDictionary(); - final PdfDictionary xobjects = dictionary!; - PdfPageResources childResource = PdfPageResources(); - if (xobjects.containsKey(PdfDictionaryProperties.resources)) { - IPdfPrimitive? primitive = xobjects[PdfDictionaryProperties.resources]; - if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfDictionary) { - pageDictionary = primitive; - } - } else if (primitive is PdfDictionary) { - pageDictionary = primitive; - } - childResource = resourceLoader.updatePageResources( - childResource, - resourceLoader.getFontResources(pageDictionary), - ); - childResource = resourceLoader.updatePageResources( - childResource, - resourceLoader.getFormResources(pageDictionary), - ); - } - MatrixHelper xFormsMatrix = MatrixHelper(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); - if (xobjects.containsKey(PdfDictionaryProperties.matrix)) { - final IPdfPrimitive? arrayReference = - xobjects[PdfDictionaryProperties.matrix]; - if (arrayReference is PdfArray) { - final PdfArray matrixArray = arrayReference; - final double a = (matrixArray[0]! as PdfNumber).value!.toDouble(); - final double b = (matrixArray[1]! as PdfNumber).value!.toDouble(); - final double c = (matrixArray[2]! as PdfNumber).value!.toDouble(); - final double d = (matrixArray[3]! as PdfNumber).value!.toDouble(); - final double e = (matrixArray[4]! as PdfNumber).value!.toDouble(); - final double f = (matrixArray[5]! as PdfNumber).value!.toDouble(); - xFormsMatrix = MatrixHelper(a, b, c, d, e, f); - if (e != 0 || f != 0) { - g!.translateTransform(e, -f); - } - if (a != 0 || d != 0) { - g!.scaleTransform(a, d); - } - //check for rotate transform - if (!a.isNaN && !b.isNaN && a >= -1 && a <= 1 && b >= -1 && b <= 1) { - final double degree = ((180 / pi) * acos(a)).round().toDouble(); - final double checkDegree = - ((180 / pi) * asin(b)).round().toDouble(); - if (degree == checkDegree) { - g!.rotateTransform(-degree); - } else { - if (!checkDegree.isNaN) { - g!.rotateTransform(-checkDegree); - } else if (!degree.isNaN) { - g!.rotateTransform(-degree); - } - } - } - } - } - final ImageRenderer renderer = ImageRenderer( - contentTree, - childResource, - currentPageHeight, - g, - ); - renderer.isExtractLineCollection = isExtractTextLine!; - renderer.graphicsObjects = objects; - final MatrixHelper parentMatrix = - objects!.last.currentTransformationMatrix!; - final MatrixHelper newMatrix = xFormsMatrix * parentMatrix; - objects.last.drawing2dMatrixCTM = MatrixHelper( - newMatrix.m11, - newMatrix.m12, - newMatrix.m21, - newMatrix.m22, - newMatrix.offsetX, - newMatrix.offsetY, - ); - objects.last.currentTransformationMatrix = newMatrix; - renderer.selectablePrintDocument = isPrintSelected; - renderer.pageHeight = pageHeight; - renderer.isXGraphics = true; - renderer.renderAsImage(); - renderer.isXGraphics = false; - while (renderer.xobjectGraphicsCount > 0) { - objects.pop(); - renderer.xobjectGraphicsCount--; - } - glyphList = renderer.imageRenderGlyphList; - objects.last.currentTransformationMatrix = parentMatrix; - extractTextElement = renderer.extractTextElement; - } - return { - 'graphicStates': graphicsStates, - 'glyphList': glyphList, - 'objects': objects, - 'extractTextElement': extractTextElement, - }; - } -} - -/// internal method -String unescape(String str) { - final StringBuffer buffer = StringBuffer(); - while (str.isNotEmpty) { - final int index = str.indexOf(r'\'); - if (index != -1) { - buffer.write(str.substring(0, index)); - if (index == str.length - 1) { - break; - } - final String next = String.fromCharCode(str.codeUnitAt(index + 1)); - str = str.substring(index + 2); - switch (next) { - case r'\': - buffer.write(r'\'); - break; - case 't': - buffer.write('\t'); - break; - case 'r': - buffer.write('\r'); - break; - case 'n': - buffer.write('\n'); - break; - case 'f': - buffer.write('\f'); - break; - case 'b': - buffer.write('\b'); - break; - case 'v': - buffer.write('\v'); - break; - case 'u': - if (str.length < 4) { - str = ''; - break; - } - if (str[0] != '{') { - final String str1 = str.substring(0, 4); - final int? intValue = int.tryParse(str1, radix: 16); - if (intValue == null || intValue < 0) { - break; - } - str = str.substring(4); - buffer.writeCharCode(intValue); - } else { - final Match? match = RegExp(r'{([a-zA-Z0-9]+)}').matchAsPrefix(str); - if (match == null) { - break; - } else { - str = str.substring(match.end); - final String str1 = match[1]!; - final int? intValue = int.tryParse(str1, radix: 16); - if (intValue == null || intValue < 0) { - break; - } - buffer.writeCharCode(intValue); - } - } - break; - case 'x': - if (str.length < 2) { - str = ''; - break; - } - final String subStr = str.substring(0, 2); - str = str.substring(2); - final int? intValue = int.tryParse(subStr, radix: 16); - if (intValue == null || intValue < 0) { - break; - } - buffer.writeCharCode(intValue); - break; - default: - buffer.write(next); - break; - } - } else { - buffer.write(str); - break; - } - } - return buffer.toString(); -} +import 'dart:math'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_number.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_stream.dart'; +import 'glyph.dart'; +import 'graphic_object_data.dart'; +import 'graphic_object_data_collection.dart'; +import 'image_renderer.dart'; +import 'matrix_helper.dart'; +import 'page_resource_loader.dart'; +import 'parser/content_parser.dart'; +import 'text_element.dart'; + +/// internal class +class XObjectElement { + /// internal constructor + XObjectElement(this.dictionary, String? name) { + _objectName = name; + getObjectType(); + isPrintSelected = false; + pageHeight = 0; + } + + //Fields + // ignore: unused_field + String? _objectName; + String? _objectType; + + /// internal field + PdfDictionary? dictionary; + + /// internal field + bool? isPrintSelected; + + /// internal field + double? pageHeight; + + /// internal field + bool? isExtractTextLine; + + //Implementation + /// internal method + void getObjectType() { + if (dictionary!.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? primitive = + dictionary![PdfDictionaryProperties.subtype]; + if (primitive is PdfName) { + _objectType = primitive.name; + } + } + } + + /// internal method + PdfRecordCollection? render(PdfPageResources? resources) { + if (_objectType != null && + _objectType == 'Form' && + dictionary is PdfStream) { + final PdfStream stream = dictionary! as PdfStream; + stream.decompress(); + return ContentParser(stream.dataStream).readContent(); + } else { + return null; + } + } + + /// internal method + Map renderTextElement( + GraphicsObject? g, + PdfPageResources? resources, + GraphicStateCollection? graphicsStates, + GraphicObjectDataCollection? objects, + double? currentPageHeight, + List? glyphList, + ) { + glyphList = []; + List? extractTextElement; + if (_objectType != null && + _objectType == 'Form' && + dictionary != null && + dictionary is PdfStream) { + final PdfStream stream = dictionary! as PdfStream; + stream.decompress(); + final ContentParser parser = ContentParser(stream.dataStream); + final PdfRecordCollection? contentTree = parser.readContent(); + final PageResourceLoader resourceLoader = PageResourceLoader(); + PdfDictionary pageDictionary = PdfDictionary(); + final PdfDictionary xobjects = dictionary!; + PdfPageResources childResource = PdfPageResources(); + if (xobjects.containsKey(PdfDictionaryProperties.resources)) { + IPdfPrimitive? primitive = xobjects[PdfDictionaryProperties.resources]; + if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfDictionary) { + pageDictionary = primitive; + } + } else if (primitive is PdfDictionary) { + pageDictionary = primitive; + } + childResource = resourceLoader.updatePageResources( + childResource, + resourceLoader.getFontResources(pageDictionary), + ); + childResource = resourceLoader.updatePageResources( + childResource, + resourceLoader.getFormResources(pageDictionary), + ); + } + MatrixHelper xFormsMatrix = MatrixHelper(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); + if (xobjects.containsKey(PdfDictionaryProperties.matrix)) { + final IPdfPrimitive? arrayReference = + xobjects[PdfDictionaryProperties.matrix]; + if (arrayReference is PdfArray) { + final PdfArray matrixArray = arrayReference; + final double a = (matrixArray[0]! as PdfNumber).value!.toDouble(); + final double b = (matrixArray[1]! as PdfNumber).value!.toDouble(); + final double c = (matrixArray[2]! as PdfNumber).value!.toDouble(); + final double d = (matrixArray[3]! as PdfNumber).value!.toDouble(); + final double e = (matrixArray[4]! as PdfNumber).value!.toDouble(); + final double f = (matrixArray[5]! as PdfNumber).value!.toDouble(); + xFormsMatrix = MatrixHelper(a, b, c, d, e, f); + if (e != 0 || f != 0) { + g!.translateTransform(e, -f); + } + if (a != 0 || d != 0) { + g!.scaleTransform(a, d); + } + //check for rotate transform + if (!a.isNaN && !b.isNaN && a >= -1 && a <= 1 && b >= -1 && b <= 1) { + final double degree = ((180 / pi) * acos(a)).round().toDouble(); + final double checkDegree = + ((180 / pi) * asin(b)).round().toDouble(); + if (degree == checkDegree) { + g!.rotateTransform(-degree); + } else { + if (!checkDegree.isNaN) { + g!.rotateTransform(-checkDegree); + } else if (!degree.isNaN) { + g!.rotateTransform(-degree); + } + } + } + } + } + final ImageRenderer renderer = ImageRenderer( + contentTree, + childResource, + currentPageHeight, + g, + ); + renderer.isExtractLineCollection = isExtractTextLine!; + renderer.graphicsObjects = objects; + final MatrixHelper parentMatrix = + objects!.last.currentTransformationMatrix!; + final MatrixHelper newMatrix = xFormsMatrix * parentMatrix; + objects.last.drawing2dMatrixCTM = MatrixHelper( + newMatrix.m11, + newMatrix.m12, + newMatrix.m21, + newMatrix.m22, + newMatrix.offsetX, + newMatrix.offsetY, + ); + objects.last.currentTransformationMatrix = newMatrix; + renderer.selectablePrintDocument = isPrintSelected; + renderer.pageHeight = pageHeight; + renderer.isXGraphics = true; + renderer.renderAsImage(); + renderer.isXGraphics = false; + while (renderer.xobjectGraphicsCount > 0) { + objects.pop(); + renderer.xobjectGraphicsCount--; + } + glyphList = renderer.imageRenderGlyphList; + objects.last.currentTransformationMatrix = parentMatrix; + extractTextElement = renderer.extractTextElement; + } + return { + 'graphicStates': graphicsStates, + 'glyphList': glyphList, + 'objects': objects, + 'extractTextElement': extractTextElement, + }; + } +} + +/// internal method +String unescape(String str) { + final StringBuffer buffer = StringBuffer(); + while (str.isNotEmpty) { + final int index = str.indexOf(r'\'); + if (index != -1) { + buffer.write(str.substring(0, index)); + if (index == str.length - 1) { + break; + } + final String next = String.fromCharCode(str.codeUnitAt(index + 1)); + str = str.substring(index + 2); + switch (next) { + case r'\': + buffer.write(r'\'); + break; + case 't': + buffer.write('\t'); + break; + case 'r': + buffer.write('\r'); + break; + case 'n': + buffer.write('\n'); + break; + case 'f': + buffer.write('\f'); + break; + case 'b': + buffer.write('\b'); + break; + case 'v': + buffer.write('\v'); + break; + case 'u': + if (str.length < 4) { + str = ''; + break; + } + if (str[0] != '{') { + final String str1 = str.substring(0, 4); + final int? intValue = int.tryParse(str1, radix: 16); + if (intValue == null || intValue < 0) { + break; + } + str = str.substring(4); + buffer.writeCharCode(intValue); + } else { + final Match? match = RegExp(r'{([a-zA-Z0-9]+)}').matchAsPrefix(str); + if (match == null) { + break; + } else { + str = str.substring(match.end); + final String str1 = match[1]!; + final int? intValue = int.tryParse(str1, radix: 16); + if (intValue == null || intValue < 0) { + break; + } + buffer.writeCharCode(intValue); + } + } + break; + case 'x': + if (str.length < 2) { + str = ''; + break; + } + final String subStr = str.substring(0, 2); + str = str.substring(2); + final int? intValue = int.tryParse(subStr, radix: 16); + if (intValue == null || intValue < 0) { + break; + } + buffer.writeCharCode(intValue); + break; + default: + buffer.write(next); + break; + } + } else { + buffer.write(str); + break; + } + } + return buffer.toString(); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/enum.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/enum.dart index 4eed9f30a..55f3ff5b0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/enum.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/enum.dart @@ -1,190 +1,190 @@ -/// Represents fields flags enum. -enum FieldFlags { - //Common flags - /// Default field flag. - defaultFieldFlag, - - /// If set, the user may not change the value of the field. Any associated widget annotations - /// will not interact with the user; that is, they will not respond to mouse clicks or - /// change their appearance in response to mouse motions. This flag is useful - /// for fields whose values are computed or imported from a database. - readOnly, - - /// If set, the field must have a value at the time it is exported by a submit-form action. - requiredFieldFlag, - - /// If set, the field must not be exported by a submit-form action - noExport, - - //Text field flags - /// If set, the field can contain multiple lines of text; - /// if clear, the field’s text is restricted to a single line. - multiline, - - /// If set, the field is intended for entering a secure password that should not be - /// echoed visibly to the screen. Characters typed from the keyboard should instead - /// be echoed in some unreadable form, such as asterisks or bullet characters. - password, - - /// If set, the text entered in the field represents the pathname of a file whose - /// contents are to be submitted as the value of the field. - fileSelect, - - /// If set, text entered in the field is not spell-checked. - doNotSpellCheck, - - /// If set, the field does not scroll (horizontally for single-line fields, vertically - /// for multiple-line fields) to accommodate more text than fits within its annotation - /// rectangle. Once the field is full, no further text is accepted. - doNotScroll, - - /// Meaningful only if the MaxLen entry is present in the text field dictionary and if - /// the Multiline, Password, and FileSelect flags are clear. If set, the field is - /// automatically divided into as many equally spaced positions, or combs, as the - /// value of MaxLen, and the text is laid out into those combs. - comb, - - /// If set, the value of this field should be represented as a rich text string. - /// If the field has a value, the RVentry of the field dictionary specifies - /// the rich text string. - richText, - - //Button field flags - /// If set, exactly one radio button must be selected at all times; clicking - /// the currently selected button has no effect. If clear, clicking the selected - /// button reselects it, leaving no button selected. - noToggleToOff, - - /// If set, the field is a set of radio buttons; if clear, the field is a check box. - /// This flag is meaningful only if the Pushbutton flag is clear. - radio, - - /// If set, the field is a pushbutton that does not retain a permanent value. - pushButton, - - /// If set, a group of radio buttons within a radio button field that use the same value - /// for the on state will turn on and off in unison; that is if one is checked, they - /// are all checked. If clear, the buttons are mutually exclusive. - radiosInUnison, - - //Choise field flags - /// If set, the field is a combo box; if clear, the field is a list box. - combo, - - /// If set, the combo box includes an editable text box as well as a drop-down - /// list; if clear, it includes only a drop-down list. This flag is meaningful only - /// if the Combo flag is set. - edit, - - /// If set, the field’s option items should be sorted alphabetically. This flag - /// is intended for use by form authoring tools, not by PDF viewer applications. - sort, - - /// If set, more than one of the field’s option items may be selected simultaneously; - /// if clear, no more than one item at a time may be selected. - multiSelect, - - /// If set, the new value is committed as soon as a selection is made with the pointing - /// device. This option enables applications to perform an action once a selection is - /// made, without requiring the user to exit the field. If clear, the new value is not - /// committed until the user exits the field. - commitOnSelChange, -} - -/// Specifies the style for a check box field. -enum PdfCheckBoxStyle { - /// A tick mark is used for the checked state. - check, - - /// A circle is used for the checked state. - circle, - - /// A cross is used for the checked state. - cross, - - /// A diamond symbol is used for the checked state. - diamond, - - /// A square is used for the checked state. - square, - - /// A star is used for the checked state. - star, -} - -/// internal enumerator -enum PdfCheckFieldState { - /// Indicated unchecked/unpressed state. - unchecked, - - /// Indicated checked unpressed state. - checked, - - /// Indicated pressed unchecked state. - pressedUnchecked, - - /// Indicated pressed checked state. - pressedChecked, -} - -/// internal enumerator -enum PdfFieldTypes { - /// Identify text field. - textField, - - /// Identify push button field. - pushButton, - - /// Identify check box field. - checkBox, - - /// Identify radio button field. - radioButton, - - /// Identify signature field. - signatureField, - - /// Identify listbox field. - listBox, - - /// Identify combobox field. - comboBox, - - /// Identify that field has no type. - none, -} - -/// internal enumerator -enum SignatureFlags { - /// No flags specified. - none, - - /// If set, the document contains at least one signature field. This flag allows a viewer - /// application to enable user interface items (such as menu items or pushbuttons) related - /// to signature processing without having to scan the entire document for the presence - /// of signature fields. - signaturesExists, - - /// If set, the document contains signatures that may be invalidated if the file is saved - /// (written) in a way that alters its previous contents, as opposed to an incremental - /// update. Merely updating the file by appending new information to the end of the - /// previous version is safe. Viewer applications can use this flag to present - /// a user requesting a full save with an additional alert box warning that signatures - /// will be invalidated and requiring explicit confirmation before continuing with the operation. - appendOnly, -} - -/// Specifies the format of Export or Import data. -enum DataFormat { - /// Specifies Forms Data Format file format. - fdf, - - /// Specifies XFDF file format. - xfdf, - - /// Specifies JSON file format. - json, - - /// Specifies XML file format - xml, -} +/// Represents fields flags enum. +enum FieldFlags { + //Common flags + /// Default field flag. + defaultFieldFlag, + + /// If set, the user may not change the value of the field. Any associated widget annotations + /// will not interact with the user; that is, they will not respond to mouse clicks or + /// change their appearance in response to mouse motions. This flag is useful + /// for fields whose values are computed or imported from a database. + readOnly, + + /// If set, the field must have a value at the time it is exported by a submit-form action. + requiredFieldFlag, + + /// If set, the field must not be exported by a submit-form action + noExport, + + //Text field flags + /// If set, the field can contain multiple lines of text; + /// if clear, the field’s text is restricted to a single line. + multiline, + + /// If set, the field is intended for entering a secure password that should not be + /// echoed visibly to the screen. Characters typed from the keyboard should instead + /// be echoed in some unreadable form, such as asterisks or bullet characters. + password, + + /// If set, the text entered in the field represents the pathname of a file whose + /// contents are to be submitted as the value of the field. + fileSelect, + + /// If set, text entered in the field is not spell-checked. + doNotSpellCheck, + + /// If set, the field does not scroll (horizontally for single-line fields, vertically + /// for multiple-line fields) to accommodate more text than fits within its annotation + /// rectangle. Once the field is full, no further text is accepted. + doNotScroll, + + /// Meaningful only if the MaxLen entry is present in the text field dictionary and if + /// the Multiline, Password, and FileSelect flags are clear. If set, the field is + /// automatically divided into as many equally spaced positions, or combs, as the + /// value of MaxLen, and the text is laid out into those combs. + comb, + + /// If set, the value of this field should be represented as a rich text string. + /// If the field has a value, the RVentry of the field dictionary specifies + /// the rich text string. + richText, + + //Button field flags + /// If set, exactly one radio button must be selected at all times; clicking + /// the currently selected button has no effect. If clear, clicking the selected + /// button reselects it, leaving no button selected. + noToggleToOff, + + /// If set, the field is a set of radio buttons; if clear, the field is a check box. + /// This flag is meaningful only if the Pushbutton flag is clear. + radio, + + /// If set, the field is a pushbutton that does not retain a permanent value. + pushButton, + + /// If set, a group of radio buttons within a radio button field that use the same value + /// for the on state will turn on and off in unison; that is if one is checked, they + /// are all checked. If clear, the buttons are mutually exclusive. + radiosInUnison, + + //Choise field flags + /// If set, the field is a combo box; if clear, the field is a list box. + combo, + + /// If set, the combo box includes an editable text box as well as a drop-down + /// list; if clear, it includes only a drop-down list. This flag is meaningful only + /// if the Combo flag is set. + edit, + + /// If set, the field’s option items should be sorted alphabetically. This flag + /// is intended for use by form authoring tools, not by PDF viewer applications. + sort, + + /// If set, more than one of the field’s option items may be selected simultaneously; + /// if clear, no more than one item at a time may be selected. + multiSelect, + + /// If set, the new value is committed as soon as a selection is made with the pointing + /// device. This option enables applications to perform an action once a selection is + /// made, without requiring the user to exit the field. If clear, the new value is not + /// committed until the user exits the field. + commitOnSelChange, +} + +/// Specifies the style for a check box field. +enum PdfCheckBoxStyle { + /// A tick mark is used for the checked state. + check, + + /// A circle is used for the checked state. + circle, + + /// A cross is used for the checked state. + cross, + + /// A diamond symbol is used for the checked state. + diamond, + + /// A square is used for the checked state. + square, + + /// A star is used for the checked state. + star, +} + +/// internal enumerator +enum PdfCheckFieldState { + /// Indicated unchecked/unpressed state. + unchecked, + + /// Indicated checked unpressed state. + checked, + + /// Indicated pressed unchecked state. + pressedUnchecked, + + /// Indicated pressed checked state. + pressedChecked, +} + +/// internal enumerator +enum PdfFieldTypes { + /// Identify text field. + textField, + + /// Identify push button field. + pushButton, + + /// Identify check box field. + checkBox, + + /// Identify radio button field. + radioButton, + + /// Identify signature field. + signatureField, + + /// Identify listbox field. + listBox, + + /// Identify combobox field. + comboBox, + + /// Identify that field has no type. + none, +} + +/// internal enumerator +enum SignatureFlags { + /// No flags specified. + none, + + /// If set, the document contains at least one signature field. This flag allows a viewer + /// application to enable user interface items (such as menu items or pushbuttons) related + /// to signature processing without having to scan the entire document for the presence + /// of signature fields. + signaturesExists, + + /// If set, the document contains signatures that may be invalidated if the file is saved + /// (written) in a way that alters its previous contents, as opposed to an incremental + /// update. Merely updating the file by appending new information to the end of the + /// previous version is safe. Viewer applications can use this flag to present + /// a user requesting a full save with an additional alert box warning that signatures + /// will be invalidated and requiring explicit confirmation before continuing with the operation. + appendOnly, +} + +/// Specifies the format of Export or Import data. +enum DataFormat { + /// Specifies Forms Data Format file format. + fdf, + + /// Specifies XFDF file format. + xfdf, + + /// Specifies JSON file format. + json, + + /// Specifies XML file format + xml, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_button_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_button_field.dart index efa853ada..249c8d7a7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_button_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_button_field.dart @@ -1,680 +1,680 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../actions/pdf_field_actions.dart'; -import '../annotations/enum.dart'; -import '../annotations/pdf_annotation.dart'; -import '../annotations/pdf_annotation_collection.dart'; -import '../annotations/pdf_appearance.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../annotations/widget_annotation.dart'; -import '../general/pdf_collection.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/enum.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_field.dart'; -import 'pdf_field_painter.dart'; -import 'pdf_form.dart'; - -/// Represents button field in the PDF form. -class PdfButtonField extends PdfField { - //Constructor - /// Initializes an instance of the [PdfButtonField] class with the specific - /// page, name, and bounds. - PdfButtonField( - PdfPage page, - String name, - Rect bounds, { - String? text, - PdfFont? font, - PdfColor? borderColor, - PdfColor? backColor, - PdfColor? foreColor, - int? borderWidth, - PdfHighlightMode highlightMode = PdfHighlightMode.invert, - PdfBorderStyle borderStyle = PdfBorderStyle.solid, - PdfFieldActions? actions, - String? tooltip, - }) { - _helper = PdfButtonFieldHelper(this); - _helper.internal( - page, - name, - bounds, - tooltip: tooltip, - font: font, - borderColor: borderColor, - backColor: backColor, - foreColor: foreColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - ); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.ft, - PdfName(PdfDictionaryProperties.btn), - ); - if (backColor == null) { - _helper.backColor = PdfColor(211, 211, 211); - } - _helper.flags.add(FieldFlags.pushButton); - _helper.initValues(text, actions); - } - - PdfButtonField._loaded(PdfDictionary dictionary, PdfCrossTable crossTable) { - _helper = PdfButtonFieldHelper(this); - _helper.load(dictionary, crossTable); - } - - //Fields - late PdfButtonFieldHelper _helper; - String _text = ''; - - // Properties - /// Gets or sets the caption text. - String get text => _helper.isLoadedField ? _helper._obtainText() : _text; - set text(String value) { - if (_helper.isLoadedField) { - final bool readOnly = 1 & (_helper.flagValues ?? 65536) != 0; - if (!readOnly) { - PdfFormHelper.getHelper(form!).setAppearanceDictionary = true; - _helper._assignText(value); - } - } else { - if (_text != value) { - _text = value; - WidgetAnnotationHelper.getHelper(_helper.widget!) - .widgetAppearance! - .normalCaption = _text; - } - } - } - - /// Gets or sets the font. - PdfFont get font => _helper.font!; - set font(PdfFont? value) => _helper.font = value; - - /// Gets or sets the border style. - /// - /// The default style is solid. - PdfBorderStyle get borderStyle => _helper.borderStyle; - set borderStyle(PdfBorderStyle value) { - _helper.borderStyle = value; - } - - /// Gets or sets the color of the border. - /// - /// The default color is black. - PdfColor get borderColor => _helper.borderColor; - set borderColor(PdfColor value) { - _helper.borderColor = value; - } - - /// Gets or sets the color of the background. - /// - /// The default color is empty. - PdfColor get backColor => _helper.backColor; - set backColor(PdfColor value) { - _helper.backColor = value; - } - - /// Gets or sets the color of the text. - /// - /// The default color is black. - PdfColor get foreColor => _helper.foreColor; - set foreColor(PdfColor value) { - _helper.foreColor = value; - } - - /// Gets or sets the width of the border. - /// - /// The default value is 1. - int get borderWidth => _helper.borderWidth; - set borderWidth(int value) { - _helper.borderWidth = value; - } - - /// Gets or sets the highlighting mode. - /// - /// The default mode is invert. - PdfHighlightMode get highlightMode => _helper.highlightMode; - set highlightMode(PdfHighlightMode value) { - _helper.highlightMode = value; - } - - /// Gets the actions of the field.{Read-Only} - PdfFieldActions get actions { - if (_helper.isLoadedField && _helper.actions == null) { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.aa)) { - final PdfDictionary actionDict = - _helper.crossTable!.getObject( - _helper.dictionary![PdfDictionaryProperties.aa], - )! - as PdfDictionary; - _helper.actions = PdfFieldActionsHelper.load(actionDict); - _helper.widget!.actions = - PdfFieldActionsHelper.getHelper(_helper.actions!).annotationActions; - } else { - _helper.actions = PdfFieldActionsHelper.load(PdfDictionary()); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.aa, - _helper.actions, - ); - } - _helper.changed = true; - } else { - if (_helper.actions == null) { - _helper.actions = PdfFieldActions(_helper.widget!.actions!); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.aa, - _helper.actions, - ); - } - } - return _helper.actions!; - } - - /// Adds Print action to current button field. - void addPrintAction() { - _helper.addPrintAction(); - } -} - -/// [PdfButtonField] helper -class PdfButtonFieldHelper extends PdfFieldHelper { - /// internal constructor - PdfButtonFieldHelper(this.buttonField) : super(buttonField); - - /// internal field - PdfButtonField buttonField; - - /// internal field - PdfFieldActions? actions; - - /// internal method - static PdfButtonFieldHelper getHelper(PdfButtonField buttonField) { - return buttonField._helper; - } - - /// internal method - void initValues(String? txt, PdfFieldActions? action) { - format!.alignment = PdfTextAlignment.center; - widget!.textAlignment = PdfTextAlignment.center; - buttonField.text = txt ?? buttonField.name!; - if (action != null) { - actions = action; - widget!.actions = - PdfFieldActionsHelper.getHelper(action).annotationActions; - dictionary!.setProperty(PdfDictionaryProperties.aa, actions); - } - } - - /// Adds Print action to current button field. - void addPrintAction() { - final PdfDictionary actionDictionary = PdfDictionary(); - actionDictionary.setProperty( - PdfDictionaryProperties.n, - PdfName(PdfDictionaryProperties.print), - ); - actionDictionary.setProperty(PdfDictionaryProperties.s, PdfName('Named')); - if (isLoadedField) { - final PdfArray? kidsArray = - crossTable!.getObject(dictionary![PdfDictionaryProperties.kids]) - as PdfArray?; - if (kidsArray != null) { - final PdfReferenceHolder buttonObject = - kidsArray[0]! as PdfReferenceHolder; - final PdfDictionary buttonDictionary = - buttonObject.object! as PdfDictionary; - buttonDictionary.setProperty( - PdfDictionaryProperties.a, - actionDictionary, - ); - } else { - dictionary!.setProperty(PdfDictionaryProperties.a, actionDictionary); - } - } else { - final PdfArray kidsArray = - dictionary![PdfDictionaryProperties.kids]! as PdfArray; - final PdfReferenceHolder buttonObject = - kidsArray[0]! as PdfReferenceHolder; - final PdfDictionary buttonDictionary = - buttonObject.object! as PdfDictionary; - buttonDictionary.setProperty(PdfDictionaryProperties.a, actionDictionary); - } - } - - /// internal method - @override - void save() { - super.save(); - if (buttonField.page != null && - buttonField.page!.formFieldsTabOrder == PdfFormFieldsTabOrder.manual && - !PdfPageHelper.getHelper(buttonField.page!).isLoadedPage) { - final PdfPage? page = buttonField.page; - if (widget != null) { - page!.annotations.remove(widget!); - PdfAnnotationCollectionHelper.getHelper( - page.annotations, - ).annotations.insert(buttonField.tabIndex, PdfReferenceHolder(widget)); - PdfObjectCollectionHelper.getHelper( - page.annotations, - ).list.insert(buttonField.tabIndex, widget!); - } - } - if (buttonField.form != null && - !PdfFormHelper.getHelper(buttonField.form!).needAppearances!) { - if (PdfAnnotationHelper.getHelper(widget!).appearance == null) { - drawAppearance(widget!.appearance.normal); - } - } - if (buttonField.form != null && - !PdfFormHelper.getHelper(buttonField.form!).needAppearances!) { - if (PdfAppearanceHelper.getHelper(widget!.appearance).templatePressed == - null) { - _drawPressedAppearance(widget!.appearance.pressed); - } - } - } - - /// internal method - @override - void drawAppearance(PdfTemplate template) { - super.drawAppearance(template); - if (buttonField.text.isEmpty) { - buttonField.text = buttonField.name!; - } - final PaintParams paintParams = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - widget!.bounds.size.width, - widget!.bounds.size.height, - ), - backBrush: PdfSolidBrush(buttonField.backColor), - foreBrush: PdfSolidBrush(buttonField.foreColor), - borderPen: borderPen, - style: buttonField.borderStyle, - borderWidth: borderWidth, - shadowBrush: PdfSolidBrush(buttonField.backColor), - ); - FieldPainter().drawButton( - template.graphics!, - paintParams, - buttonField.text, - (font == null) ? PdfStandardFont(PdfFontFamily.helvetica, 8) : font!, - format, - ); - } - - void _drawPressedAppearance(PdfTemplate template) { - if (buttonField.text.isEmpty) { - buttonField.text = buttonField.name!; - } - final PaintParams paintParams = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - widget!.bounds.size.width, - widget!.bounds.size.height, - ), - backBrush: PdfSolidBrush(buttonField.backColor), - foreBrush: PdfSolidBrush(buttonField.foreColor), - borderPen: borderPen, - style: buttonField.borderStyle, - borderWidth: borderWidth, - shadowBrush: PdfSolidBrush(buttonField.backColor), - ); - FieldPainter().drawPressedButton( - template.graphics!, - paintParams, - buttonField.text, - (font == null) ? PdfStandardFont(PdfFontFamily.helvetica, 8) : font!, - format, - ); - } - - String _obtainText() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - String? str; - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final PdfDictionary appearance = - crossTable!.getObject(widget[PdfDictionaryProperties.mk])! - as PdfDictionary; - if (appearance.containsKey(PdfDictionaryProperties.ca)) { - final PdfString text = - crossTable!.getObject(appearance[PdfDictionaryProperties.ca])! - as PdfString; - str = text.value; - } - } - if (str == null) { - PdfString? val = - crossTable!.getObject(dictionary![PdfDictionaryProperties.v]) - as PdfString?; - val ??= - PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.v, - true, - ) - as PdfString?; - if (val != null) { - str = val.value; - } else { - str = ''; - } - } - return str!; - } - - void _assignText(String value) { - final String text = value; - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final PdfDictionary appearance = - crossTable!.getObject(widget[PdfDictionaryProperties.mk])! - as PdfDictionary; - appearance.setString(PdfDictionaryProperties.ca, text); - widget.setProperty( - PdfDictionaryProperties.mk, - PdfReferenceHolder(appearance), - ); - } else { - final PdfDictionary appearance = PdfDictionary(); - appearance.setString(PdfDictionaryProperties.ca, text); - widget.setProperty( - PdfDictionaryProperties.mk, - PdfReferenceHolder(appearance), - ); - } - if (widget.containsKey(PdfDictionaryProperties.ap)) { - _applyAppearance(widget, null); - } - changed = true; - } - - /// internal method - @override - void beginSave() { - super.beginSave(); - final PdfArray? kids = obtainKids(); - if (kids != null) { - for (int i = 0; i < kids.count; ++i) { - final PdfDictionary? widget = - crossTable!.getObject(kids[i]) as PdfDictionary?; - _applyAppearance(widget, buttonField); - } - } - } - - /// internal method - @override - void draw() { - super.draw(); - if (isLoadedField) { - final PdfArray? kids = obtainKids(); - if ((kids != null) && (kids.count > 1)) { - for (int i = 0; i < kids.count; ++i) { - if (buttonField.page != null) { - final PdfDictionary? widget = - crossTable!.getObject(kids[i]) as PdfDictionary?; - _drawButton(buttonField.page!.graphics, buttonField, widget); - } - } - } else { - _drawButton(buttonField.page!.graphics, null); - } - } else { - final PdfAppearance? appearance = - PdfAnnotationHelper.getHelper(widget!).appearance; - if (appearance != null) { - buttonField.page!.graphics.drawPdfTemplate( - appearance.normal, - Offset(widget!.bounds.left, widget!.bounds.top), - ); - } else { - Rect rect = buttonField.bounds; - rect = Rect.fromLTWH( - 0, - 0, - buttonField.bounds.width, - buttonField.bounds.height, - ); - final PdfFont tempFont = - font ?? PdfStandardFont(PdfFontFamily.helvetica, 8); - final PaintParams params = PaintParams( - bounds: rect, - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: buttonField.borderStyle, - borderWidth: buttonField.borderWidth, - shadowBrush: shadowBrush, - ); - final PdfTemplate template = PdfTemplate(rect.width, rect.height); - FieldPainter().drawButton( - template.graphics!, - params, - buttonField.text, - tempFont, - stringFormat, - ); - buttonField.page!.graphics.drawPdfTemplate( - template, - Offset(buttonField.bounds.left, buttonField.bounds.top), - rect.size, - ); - buttonField.page!.graphics.drawString( - (buttonField.text.isEmpty) ? buttonField.name! : buttonField.text, - tempFont, - brush: params.foreBrush, - bounds: buttonField.bounds, - format: stringFormat, - ); - } - } - } - - void _applyAppearance(PdfDictionary? widget, PdfButtonField? item) { - if ((actions != null) && - PdfFieldActionsHelper.getHelper(actions!).changed) { - widget!.setProperty(PdfDictionaryProperties.aa, actions); - } - if ((widget != null) && (widget.containsKey(PdfDictionaryProperties.ap))) { - final PdfDictionary? appearance = - crossTable!.getObject(widget[PdfDictionaryProperties.ap]) - as PdfDictionary?; - if ((appearance != null) && - (appearance.containsKey(PdfDictionaryProperties.n))) { - final Rect bounds = (item == null) ? buttonField.bounds : item.bounds; - PdfTemplate template = PdfTemplate(bounds.width, bounds.height); - final PdfTemplate pressedTemplate = PdfTemplate( - bounds.width, - bounds.height, - ); - if (widget.containsKey(PdfDictionaryProperties.mk)) { - PdfDictionary? mkDic; - if (widget[PdfDictionaryProperties.mk] is PdfReferenceHolder) { - mkDic = - crossTable!.getObject(widget[PdfDictionaryProperties.mk]) - as PdfDictionary?; - } else { - mkDic = widget[PdfDictionaryProperties.mk] as PdfDictionary?; - } - if (mkDic != null && mkDic.containsKey(PdfDictionaryProperties.r)) { - final PdfNumber? angle = - mkDic[PdfDictionaryProperties.r] as PdfNumber?; - if (angle != null) { - if (angle.value == 90) { - template = PdfTemplate(bounds.size.height, bounds.size.width); - PdfTemplateHelper.getHelper(template).writeTransformation = - false; - PdfTemplateHelper.getHelper( - template, - ).content[PdfDictionaryProperties.matrix] = PdfArray([ - 0, - 1, - -1, - 0, - bounds.size.width, - 0, - ]); - } else if (angle.value == 180) { - template = PdfTemplate(bounds.size.width, bounds.size.height); - PdfTemplateHelper.getHelper(template).writeTransformation = - false; - PdfTemplateHelper.getHelper( - template, - ).content[PdfDictionaryProperties.matrix] = PdfArray([ - -1, - 0, - 0, - -1, - bounds.size.width, - bounds.size.height, - ]); - } else if (angle.value == 270) { - template = PdfTemplate(bounds.size.height, bounds.size.width); - PdfTemplateHelper.getHelper(template).writeTransformation = - false; - PdfTemplateHelper.getHelper( - template, - ).content[PdfDictionaryProperties.matrix] = PdfArray([ - 0, - -1, - 1, - 0, - 0, - bounds.size.height, - ]); - } - } - } - } - _drawButton(template.graphics, item, widget); - _drawButton(pressedTemplate.graphics, item, widget); - appearance.setProperty( - PdfDictionaryProperties.n, - PdfReferenceHolder(template), - ); - appearance.setProperty( - PdfDictionaryProperties.d, - PdfReferenceHolder(pressedTemplate), - ); - widget.setProperty(PdfDictionaryProperties.ap, appearance); - } - } else if (PdfFormHelper.getHelper( - buttonField.form!, - ).setAppearanceDictionary) { - PdfFormHelper.getHelper(buttonField.form!).needAppearances = true; - } - } - - void _drawButton( - PdfGraphics? graphics, - PdfButtonField? item, [ - PdfDictionary? widget, - ]) { - final GraphicsProperties gp = GraphicsProperties(buttonField); - if (!flattenField) { - gp.bounds = Rect.fromLTWH(0, 0, gp.bounds!.width, gp.bounds!.height); - } - final PaintParams prms = PaintParams( - bounds: gp.bounds, - backBrush: gp.backBrush, - foreBrush: gp.foreBrush, - borderPen: gp.borderPen, - style: gp.style, - borderWidth: gp.borderWidth, - shadowBrush: gp.shadowBrush, - ); - if (dictionary!.containsKey(PdfDictionaryProperties.ap) && - !(PdfGraphicsHelper.getHelper(graphics!).layer != null && - PdfGraphicsHelper.getHelper(graphics).page!.rotation != - PdfPageRotateAngle.rotateAngle0)) { - IPdfPrimitive? buttonAppearance = dictionary![PdfDictionaryProperties.ap]; - buttonAppearance ??= widget![PdfDictionaryProperties.ap]; - PdfDictionary? buttonResource = - PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; - if (buttonResource != null) { - buttonAppearance = buttonResource[PdfDictionaryProperties.n]; - buttonResource = - PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; - if (buttonResource != null) { - final PdfStream? stream = buttonResource as PdfStream?; - if (stream != null) { - final PdfTemplate buttonShape = PdfTemplateHelper.fromPdfStream( - stream, - ); - buttonField.page!.graphics.drawPdfTemplate( - buttonShape, - Offset(buttonField.bounds.left, buttonField.bounds.top), - ); - } - } - } - } else if (dictionary!.containsKey(PdfDictionaryProperties.kids) && - item != null && - !(PdfGraphicsHelper.getHelper(graphics!).layer != null && - PdfGraphicsHelper.getHelper(graphics).page!.rotation != - PdfPageRotateAngle.rotateAngle0)) { - IPdfPrimitive? buttonAppearance = - item._helper.dictionary![PdfDictionaryProperties.ap]; - buttonAppearance ??= widget![PdfDictionaryProperties.ap]; - PdfDictionary? buttonResource = - PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; - if (buttonResource != null) { - buttonAppearance = buttonResource[PdfDictionaryProperties.n]; - buttonResource = - PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; - if (buttonResource != null) { - final PdfStream? stream = buttonResource as PdfStream?; - if (stream != null) { - final PdfTemplate buttonShape = PdfTemplateHelper.fromPdfStream( - stream, - ); - buttonField.page!.graphics.drawPdfTemplate( - buttonShape, - Offset(buttonField.bounds.left, buttonField.bounds.top), - ); - } - } - } - } else { - FieldPainter().drawButton( - graphics!, - prms, - buttonField.text, - gp.font!, - gp.stringFormat, - ); - } - } - - /// internal method - static PdfButtonField loadButtonField( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfButtonField._loaded(dictionary, crossTable); - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../actions/pdf_field_actions.dart'; +import '../annotations/enum.dart'; +import '../annotations/pdf_annotation.dart'; +import '../annotations/pdf_annotation_collection.dart'; +import '../annotations/pdf_appearance.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../annotations/widget_annotation.dart'; +import '../general/pdf_collection.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/enum.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_field.dart'; +import 'pdf_field_painter.dart'; +import 'pdf_form.dart'; + +/// Represents button field in the PDF form. +class PdfButtonField extends PdfField { + //Constructor + /// Initializes an instance of the [PdfButtonField] class with the specific + /// page, name, and bounds. + PdfButtonField( + PdfPage page, + String name, + Rect bounds, { + String? text, + PdfFont? font, + PdfColor? borderColor, + PdfColor? backColor, + PdfColor? foreColor, + int? borderWidth, + PdfHighlightMode highlightMode = PdfHighlightMode.invert, + PdfBorderStyle borderStyle = PdfBorderStyle.solid, + PdfFieldActions? actions, + String? tooltip, + }) { + _helper = PdfButtonFieldHelper(this); + _helper.internal( + page, + name, + bounds, + tooltip: tooltip, + font: font, + borderColor: borderColor, + backColor: backColor, + foreColor: foreColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + ); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.ft, + PdfName(PdfDictionaryProperties.btn), + ); + if (backColor == null) { + _helper.backColor = PdfColor(211, 211, 211); + } + _helper.flags.add(FieldFlags.pushButton); + _helper.initValues(text, actions); + } + + PdfButtonField._loaded(PdfDictionary dictionary, PdfCrossTable crossTable) { + _helper = PdfButtonFieldHelper(this); + _helper.load(dictionary, crossTable); + } + + //Fields + late PdfButtonFieldHelper _helper; + String _text = ''; + + // Properties + /// Gets or sets the caption text. + String get text => _helper.isLoadedField ? _helper._obtainText() : _text; + set text(String value) { + if (_helper.isLoadedField) { + final bool readOnly = 1 & (_helper.flagValues ?? 65536) != 0; + if (!readOnly) { + PdfFormHelper.getHelper(form!).setAppearanceDictionary = true; + _helper._assignText(value); + } + } else { + if (_text != value) { + _text = value; + WidgetAnnotationHelper.getHelper(_helper.widget!) + .widgetAppearance! + .normalCaption = _text; + } + } + } + + /// Gets or sets the font. + PdfFont get font => _helper.font!; + set font(PdfFont? value) => _helper.font = value; + + /// Gets or sets the border style. + /// + /// The default style is solid. + PdfBorderStyle get borderStyle => _helper.borderStyle; + set borderStyle(PdfBorderStyle value) { + _helper.borderStyle = value; + } + + /// Gets or sets the color of the border. + /// + /// The default color is black. + PdfColor get borderColor => _helper.borderColor; + set borderColor(PdfColor value) { + _helper.borderColor = value; + } + + /// Gets or sets the color of the background. + /// + /// The default color is empty. + PdfColor get backColor => _helper.backColor; + set backColor(PdfColor value) { + _helper.backColor = value; + } + + /// Gets or sets the color of the text. + /// + /// The default color is black. + PdfColor get foreColor => _helper.foreColor; + set foreColor(PdfColor value) { + _helper.foreColor = value; + } + + /// Gets or sets the width of the border. + /// + /// The default value is 1. + int get borderWidth => _helper.borderWidth; + set borderWidth(int value) { + _helper.borderWidth = value; + } + + /// Gets or sets the highlighting mode. + /// + /// The default mode is invert. + PdfHighlightMode get highlightMode => _helper.highlightMode; + set highlightMode(PdfHighlightMode value) { + _helper.highlightMode = value; + } + + /// Gets the actions of the field.{Read-Only} + PdfFieldActions get actions { + if (_helper.isLoadedField && _helper.actions == null) { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.aa)) { + final PdfDictionary actionDict = + _helper.crossTable!.getObject( + _helper.dictionary![PdfDictionaryProperties.aa], + )! + as PdfDictionary; + _helper.actions = PdfFieldActionsHelper.load(actionDict); + _helper.widget!.actions = + PdfFieldActionsHelper.getHelper(_helper.actions!).annotationActions; + } else { + _helper.actions = PdfFieldActionsHelper.load(PdfDictionary()); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.aa, + _helper.actions, + ); + } + _helper.changed = true; + } else { + if (_helper.actions == null) { + _helper.actions = PdfFieldActions(_helper.widget!.actions!); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.aa, + _helper.actions, + ); + } + } + return _helper.actions!; + } + + /// Adds Print action to current button field. + void addPrintAction() { + _helper.addPrintAction(); + } +} + +/// [PdfButtonField] helper +class PdfButtonFieldHelper extends PdfFieldHelper { + /// internal constructor + PdfButtonFieldHelper(this.buttonField) : super(buttonField); + + /// internal field + PdfButtonField buttonField; + + /// internal field + PdfFieldActions? actions; + + /// internal method + static PdfButtonFieldHelper getHelper(PdfButtonField buttonField) { + return buttonField._helper; + } + + /// internal method + void initValues(String? txt, PdfFieldActions? action) { + format!.alignment = PdfTextAlignment.center; + widget!.textAlignment = PdfTextAlignment.center; + buttonField.text = txt ?? buttonField.name!; + if (action != null) { + actions = action; + widget!.actions = + PdfFieldActionsHelper.getHelper(action).annotationActions; + dictionary!.setProperty(PdfDictionaryProperties.aa, actions); + } + } + + /// Adds Print action to current button field. + void addPrintAction() { + final PdfDictionary actionDictionary = PdfDictionary(); + actionDictionary.setProperty( + PdfDictionaryProperties.n, + PdfName(PdfDictionaryProperties.print), + ); + actionDictionary.setProperty(PdfDictionaryProperties.s, PdfName('Named')); + if (isLoadedField) { + final PdfArray? kidsArray = + crossTable!.getObject(dictionary![PdfDictionaryProperties.kids]) + as PdfArray?; + if (kidsArray != null) { + final PdfReferenceHolder buttonObject = + kidsArray[0]! as PdfReferenceHolder; + final PdfDictionary buttonDictionary = + buttonObject.object! as PdfDictionary; + buttonDictionary.setProperty( + PdfDictionaryProperties.a, + actionDictionary, + ); + } else { + dictionary!.setProperty(PdfDictionaryProperties.a, actionDictionary); + } + } else { + final PdfArray kidsArray = + dictionary![PdfDictionaryProperties.kids]! as PdfArray; + final PdfReferenceHolder buttonObject = + kidsArray[0]! as PdfReferenceHolder; + final PdfDictionary buttonDictionary = + buttonObject.object! as PdfDictionary; + buttonDictionary.setProperty(PdfDictionaryProperties.a, actionDictionary); + } + } + + /// internal method + @override + void save() { + super.save(); + if (buttonField.page != null && + buttonField.page!.formFieldsTabOrder == PdfFormFieldsTabOrder.manual && + !PdfPageHelper.getHelper(buttonField.page!).isLoadedPage) { + final PdfPage? page = buttonField.page; + if (widget != null) { + page!.annotations.remove(widget!); + PdfAnnotationCollectionHelper.getHelper( + page.annotations, + ).annotations.insert(buttonField.tabIndex, PdfReferenceHolder(widget)); + PdfObjectCollectionHelper.getHelper( + page.annotations, + ).list.insert(buttonField.tabIndex, widget!); + } + } + if (buttonField.form != null && + !PdfFormHelper.getHelper(buttonField.form!).needAppearances!) { + if (PdfAnnotationHelper.getHelper(widget!).appearance == null) { + drawAppearance(widget!.appearance.normal); + } + } + if (buttonField.form != null && + !PdfFormHelper.getHelper(buttonField.form!).needAppearances!) { + if (PdfAppearanceHelper.getHelper(widget!.appearance).templatePressed == + null) { + _drawPressedAppearance(widget!.appearance.pressed); + } + } + } + + /// internal method + @override + void drawAppearance(PdfTemplate template) { + super.drawAppearance(template); + if (buttonField.text.isEmpty) { + buttonField.text = buttonField.name!; + } + final PaintParams paintParams = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + widget!.bounds.size.width, + widget!.bounds.size.height, + ), + backBrush: PdfSolidBrush(buttonField.backColor), + foreBrush: PdfSolidBrush(buttonField.foreColor), + borderPen: borderPen, + style: buttonField.borderStyle, + borderWidth: borderWidth, + shadowBrush: PdfSolidBrush(buttonField.backColor), + ); + FieldPainter().drawButton( + template.graphics!, + paintParams, + buttonField.text, + (font == null) ? PdfStandardFont(PdfFontFamily.helvetica, 8) : font!, + format, + ); + } + + void _drawPressedAppearance(PdfTemplate template) { + if (buttonField.text.isEmpty) { + buttonField.text = buttonField.name!; + } + final PaintParams paintParams = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + widget!.bounds.size.width, + widget!.bounds.size.height, + ), + backBrush: PdfSolidBrush(buttonField.backColor), + foreBrush: PdfSolidBrush(buttonField.foreColor), + borderPen: borderPen, + style: buttonField.borderStyle, + borderWidth: borderWidth, + shadowBrush: PdfSolidBrush(buttonField.backColor), + ); + FieldPainter().drawPressedButton( + template.graphics!, + paintParams, + buttonField.text, + (font == null) ? PdfStandardFont(PdfFontFamily.helvetica, 8) : font!, + format, + ); + } + + String _obtainText() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + String? str; + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final PdfDictionary appearance = + crossTable!.getObject(widget[PdfDictionaryProperties.mk])! + as PdfDictionary; + if (appearance.containsKey(PdfDictionaryProperties.ca)) { + final PdfString text = + crossTable!.getObject(appearance[PdfDictionaryProperties.ca])! + as PdfString; + str = text.value; + } + } + if (str == null) { + PdfString? val = + crossTable!.getObject(dictionary![PdfDictionaryProperties.v]) + as PdfString?; + val ??= + PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.v, + true, + ) + as PdfString?; + if (val != null) { + str = val.value; + } else { + str = ''; + } + } + return str!; + } + + void _assignText(String value) { + final String text = value; + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final PdfDictionary appearance = + crossTable!.getObject(widget[PdfDictionaryProperties.mk])! + as PdfDictionary; + appearance.setString(PdfDictionaryProperties.ca, text); + widget.setProperty( + PdfDictionaryProperties.mk, + PdfReferenceHolder(appearance), + ); + } else { + final PdfDictionary appearance = PdfDictionary(); + appearance.setString(PdfDictionaryProperties.ca, text); + widget.setProperty( + PdfDictionaryProperties.mk, + PdfReferenceHolder(appearance), + ); + } + if (widget.containsKey(PdfDictionaryProperties.ap)) { + _applyAppearance(widget, null); + } + changed = true; + } + + /// internal method + @override + void beginSave() { + super.beginSave(); + final PdfArray? kids = obtainKids(); + if (kids != null) { + for (int i = 0; i < kids.count; ++i) { + final PdfDictionary? widget = + crossTable!.getObject(kids[i]) as PdfDictionary?; + _applyAppearance(widget, buttonField); + } + } + } + + /// internal method + @override + void draw() { + super.draw(); + if (isLoadedField) { + final PdfArray? kids = obtainKids(); + if ((kids != null) && (kids.count > 1)) { + for (int i = 0; i < kids.count; ++i) { + if (buttonField.page != null) { + final PdfDictionary? widget = + crossTable!.getObject(kids[i]) as PdfDictionary?; + _drawButton(buttonField.page!.graphics, buttonField, widget); + } + } + } else { + _drawButton(buttonField.page!.graphics, null); + } + } else { + final PdfAppearance? appearance = + PdfAnnotationHelper.getHelper(widget!).appearance; + if (appearance != null) { + buttonField.page!.graphics.drawPdfTemplate( + appearance.normal, + Offset(widget!.bounds.left, widget!.bounds.top), + ); + } else { + Rect rect = buttonField.bounds; + rect = Rect.fromLTWH( + 0, + 0, + buttonField.bounds.width, + buttonField.bounds.height, + ); + final PdfFont tempFont = + font ?? PdfStandardFont(PdfFontFamily.helvetica, 8); + final PaintParams params = PaintParams( + bounds: rect, + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: buttonField.borderStyle, + borderWidth: buttonField.borderWidth, + shadowBrush: shadowBrush, + ); + final PdfTemplate template = PdfTemplate(rect.width, rect.height); + FieldPainter().drawButton( + template.graphics!, + params, + buttonField.text, + tempFont, + stringFormat, + ); + buttonField.page!.graphics.drawPdfTemplate( + template, + Offset(buttonField.bounds.left, buttonField.bounds.top), + rect.size, + ); + buttonField.page!.graphics.drawString( + (buttonField.text.isEmpty) ? buttonField.name! : buttonField.text, + tempFont, + brush: params.foreBrush, + bounds: buttonField.bounds, + format: stringFormat, + ); + } + } + } + + void _applyAppearance(PdfDictionary? widget, PdfButtonField? item) { + if ((actions != null) && + PdfFieldActionsHelper.getHelper(actions!).changed) { + widget!.setProperty(PdfDictionaryProperties.aa, actions); + } + if ((widget != null) && (widget.containsKey(PdfDictionaryProperties.ap))) { + final PdfDictionary? appearance = + crossTable!.getObject(widget[PdfDictionaryProperties.ap]) + as PdfDictionary?; + if ((appearance != null) && + (appearance.containsKey(PdfDictionaryProperties.n))) { + final Rect bounds = (item == null) ? buttonField.bounds : item.bounds; + PdfTemplate template = PdfTemplate(bounds.width, bounds.height); + final PdfTemplate pressedTemplate = PdfTemplate( + bounds.width, + bounds.height, + ); + if (widget.containsKey(PdfDictionaryProperties.mk)) { + PdfDictionary? mkDic; + if (widget[PdfDictionaryProperties.mk] is PdfReferenceHolder) { + mkDic = + crossTable!.getObject(widget[PdfDictionaryProperties.mk]) + as PdfDictionary?; + } else { + mkDic = widget[PdfDictionaryProperties.mk] as PdfDictionary?; + } + if (mkDic != null && mkDic.containsKey(PdfDictionaryProperties.r)) { + final PdfNumber? angle = + mkDic[PdfDictionaryProperties.r] as PdfNumber?; + if (angle != null) { + if (angle.value == 90) { + template = PdfTemplate(bounds.size.height, bounds.size.width); + PdfTemplateHelper.getHelper(template).writeTransformation = + false; + PdfTemplateHelper.getHelper( + template, + ).content[PdfDictionaryProperties.matrix] = PdfArray([ + 0, + 1, + -1, + 0, + bounds.size.width, + 0, + ]); + } else if (angle.value == 180) { + template = PdfTemplate(bounds.size.width, bounds.size.height); + PdfTemplateHelper.getHelper(template).writeTransformation = + false; + PdfTemplateHelper.getHelper( + template, + ).content[PdfDictionaryProperties.matrix] = PdfArray([ + -1, + 0, + 0, + -1, + bounds.size.width, + bounds.size.height, + ]); + } else if (angle.value == 270) { + template = PdfTemplate(bounds.size.height, bounds.size.width); + PdfTemplateHelper.getHelper(template).writeTransformation = + false; + PdfTemplateHelper.getHelper( + template, + ).content[PdfDictionaryProperties.matrix] = PdfArray([ + 0, + -1, + 1, + 0, + 0, + bounds.size.height, + ]); + } + } + } + } + _drawButton(template.graphics, item, widget); + _drawButton(pressedTemplate.graphics, item, widget); + appearance.setProperty( + PdfDictionaryProperties.n, + PdfReferenceHolder(template), + ); + appearance.setProperty( + PdfDictionaryProperties.d, + PdfReferenceHolder(pressedTemplate), + ); + widget.setProperty(PdfDictionaryProperties.ap, appearance); + } + } else if (PdfFormHelper.getHelper( + buttonField.form!, + ).setAppearanceDictionary) { + PdfFormHelper.getHelper(buttonField.form!).needAppearances = true; + } + } + + void _drawButton( + PdfGraphics? graphics, + PdfButtonField? item, [ + PdfDictionary? widget, + ]) { + final GraphicsProperties gp = GraphicsProperties(buttonField); + if (!flattenField) { + gp.bounds = Rect.fromLTWH(0, 0, gp.bounds!.width, gp.bounds!.height); + } + final PaintParams prms = PaintParams( + bounds: gp.bounds, + backBrush: gp.backBrush, + foreBrush: gp.foreBrush, + borderPen: gp.borderPen, + style: gp.style, + borderWidth: gp.borderWidth, + shadowBrush: gp.shadowBrush, + ); + if (dictionary!.containsKey(PdfDictionaryProperties.ap) && + !(PdfGraphicsHelper.getHelper(graphics!).layer != null && + PdfGraphicsHelper.getHelper(graphics).page!.rotation != + PdfPageRotateAngle.rotateAngle0)) { + IPdfPrimitive? buttonAppearance = dictionary![PdfDictionaryProperties.ap]; + buttonAppearance ??= widget![PdfDictionaryProperties.ap]; + PdfDictionary? buttonResource = + PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; + if (buttonResource != null) { + buttonAppearance = buttonResource[PdfDictionaryProperties.n]; + buttonResource = + PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; + if (buttonResource != null) { + final PdfStream? stream = buttonResource as PdfStream?; + if (stream != null) { + final PdfTemplate buttonShape = PdfTemplateHelper.fromPdfStream( + stream, + ); + buttonField.page!.graphics.drawPdfTemplate( + buttonShape, + Offset(buttonField.bounds.left, buttonField.bounds.top), + ); + } + } + } + } else if (dictionary!.containsKey(PdfDictionaryProperties.kids) && + item != null && + !(PdfGraphicsHelper.getHelper(graphics!).layer != null && + PdfGraphicsHelper.getHelper(graphics).page!.rotation != + PdfPageRotateAngle.rotateAngle0)) { + IPdfPrimitive? buttonAppearance = + item._helper.dictionary![PdfDictionaryProperties.ap]; + buttonAppearance ??= widget![PdfDictionaryProperties.ap]; + PdfDictionary? buttonResource = + PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; + if (buttonResource != null) { + buttonAppearance = buttonResource[PdfDictionaryProperties.n]; + buttonResource = + PdfCrossTable.dereference(buttonAppearance) as PdfDictionary?; + if (buttonResource != null) { + final PdfStream? stream = buttonResource as PdfStream?; + if (stream != null) { + final PdfTemplate buttonShape = PdfTemplateHelper.fromPdfStream( + stream, + ); + buttonField.page!.graphics.drawPdfTemplate( + buttonShape, + Offset(buttonField.bounds.left, buttonField.bounds.top), + ); + } + } + } + } else { + FieldPainter().drawButton( + graphics!, + prms, + buttonField.text, + gp.font!, + gp.stringFormat, + ); + } + } + + /// internal method + static PdfButtonField loadButtonField( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfButtonField._loaded(dictionary, crossTable); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_check_box_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_check_box_field.dart index 33383b456..0192d9c21 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_check_box_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_check_box_field.dart @@ -1,1226 +1,1226 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../annotations/widget_annotation.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_color.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_field.dart'; -import 'pdf_field_item.dart'; -import 'pdf_field_item_collection.dart'; -import 'pdf_field_painter.dart'; -import 'pdf_form.dart'; -import 'pdf_radio_button_list_field.dart'; - -/// Represents check box field in the PDF form. -class PdfCheckBoxField extends PdfCheckFieldBase { - //Constructor - /// Initializes a new instance of the [PdfCheckBoxField] class with - /// the specific page, name and bounds. - PdfCheckBoxField( - PdfPage page, - String name, - Rect bounds, { - bool isChecked = false, - PdfCheckBoxStyle style = PdfCheckBoxStyle.check, - PdfColor? borderColor, - PdfColor? backColor, - PdfColor? foreColor, - int? borderWidth, - PdfHighlightMode highlightMode = PdfHighlightMode.invert, - PdfBorderStyle borderStyle = PdfBorderStyle.solid, - String? tooltip, - }) { - _helper = PdfCheckBoxFieldHelper(this); - _helper.initialize( - page, - name, - bounds, - style: style, - borderColor: borderColor, - backColor: backColor, - foreColor: foreColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - ); - _setCheckBoxValue(isChecked); - } - - PdfCheckBoxField._loaded(PdfDictionary dictionary, PdfCrossTable crossTable) { - _helper = PdfCheckBoxFieldHelper(this); - _helper.load(dictionary, crossTable); - _items = PdfFieldItemCollectionHelper.load(this); - final PdfArray? kids = _helper.kids; - if (kids != null) { - for (int i = 0; i < kids.count; ++i) { - final PdfDictionary? itemDictionary = - crossTable.getObject(kids[i]) as PdfDictionary?; - PdfFieldItemCollectionHelper.getHelper( - _items!, - ).add(PdfCheckBoxItemHelper.getItem(this, i, itemDictionary)); - } - _helper.array = kids; - } - } - - //Fields - late PdfCheckBoxFieldHelper _helper; - bool _checked = false; - PdfFieldItemCollection? _items; - - //Properties - /// Gets or sets a value indicating whether this [PdfCheckBoxField] is checked. - /// - /// The default value is false. - bool get isChecked { - if (_helper.isLoadedField) { - if (items != null && items!.count > 0) { - final IPdfPrimitive? state = PdfCrossTable.dereference( - PdfFieldItemHelper.getHelper( - items![_helper.defaultIndex], - ).dictionary![PdfDictionaryProperties.usageApplication], - ); - if (state == null) { - final IPdfPrimitive? name = PdfFieldHelper.getValue( - _helper.dictionary!, - _helper.crossTable, - PdfDictionaryProperties.v, - false, - ); - if (name != null && name is PdfName) { - _checked = - name.name == - _helper.getItemValue( - PdfFieldItemHelper.getHelper( - items![_helper.defaultIndex], - ).dictionary!, - _helper.crossTable, - ); - } - } else if (state is PdfName) { - _checked = state.name != PdfDictionaryProperties.off; - } - return _checked; - } - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - if (_helper.dictionary![PdfDictionaryProperties.v]! is PdfName) { - final PdfName chk = - _helper.dictionary![PdfDictionaryProperties.v]! as PdfName; - _checked = chk.name != 'Off'; - } else if (_helper.dictionary![PdfDictionaryProperties.v]! - is PdfString) { - final PdfString chk = - _helper.dictionary![PdfDictionaryProperties.v]! as PdfString; - _checked = chk.value != 'Off'; - } - } - } - return _checked; - } - - set isChecked(bool value) { - if (_helper.isLoadedField) { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - if (_helper.dictionary![PdfDictionaryProperties.v]! is PdfName) { - final PdfName chk = - _helper.dictionary![PdfDictionaryProperties.v]! as PdfName; - if (chk.name!.isNotEmpty) { - _checked = chk.name != 'Off'; - } else { - _helper.dictionary!.remove(PdfDictionaryProperties.v); - } - } else if (_helper.dictionary![PdfDictionaryProperties.v]! - is PdfString) { - final PdfString chk = - _helper.dictionary![PdfDictionaryProperties.v]! as PdfString; - if (chk.value!.isNotEmpty) { - _checked = chk.value != 'Off'; - } else { - _helper.dictionary!.remove(PdfDictionaryProperties.v); - } - } - } - PdfFormHelper.getHelper(form!).setAppearanceDictionary = true; - if (PdfFormHelper.getHelper(super.form!).needAppearances == false) { - _helper.changed = true; - } - } - if (_checked != value) { - _checked = value; - String? val; - if (_helper.isLoadedField) { - val = _helper._enableCheckBox(value); - val = _helper._enableItems(value, val); - } - if (_checked) { - _helper.dictionary!.setName( - PdfName(PdfDictionaryProperties.v), - val ?? PdfDictionaryProperties.yes, - ); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.usageApplication, - PdfName(val ?? PdfDictionaryProperties.yes), - ); - } else { - _helper.dictionary!.remove(PdfDictionaryProperties.v); - if (_helper.dictionary!.containsKey( - PdfDictionaryProperties.usageApplication, - )) { - _helper.dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - PdfDictionaryProperties.off, - ); - } - } - } - } - - /// Gets the collection of check box field items. - PdfFieldItemCollection? get items => _items; - - // ignore: use_setters_to_change_properties - void _setCheckBoxValue(bool isChecked) { - this.isChecked = isChecked; - } -} - -/// [PdfCheckBoxField] helper -class PdfCheckBoxFieldHelper extends PdfCheckFieldBaseHelper { - /// internal constructor - PdfCheckBoxFieldHelper(this.checkBoxField) : super(checkBoxField); - - /// internal field - PdfCheckBoxField checkBoxField; - - /// internal field - // ignore: avoid_setters_without_getters - set items(PdfFieldItemCollection? value) { - checkBoxField._items = value; - } - - /// internal method - static PdfCheckBoxField loadCheckBoxField( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfCheckBoxField._loaded(dictionary, crossTable); - } - - /// internal method - static PdfCheckBoxFieldHelper getHelper(PdfCheckBoxField checkBoxField) { - return checkBoxField._helper; - } - - /// internal method - @override - void save() { - super.save(); - if (checkBoxField.form != null) { - if (!checkBoxField.isChecked) { - widget!.appearanceState = PdfDictionaryProperties.off; - } else { - widget!.appearanceState = PdfDictionaryProperties.yes; - } - } - if (fieldItems != null && fieldItems!.length > 1) { - for (int i = 1; i < fieldItems!.length; i++) { - final PdfCheckBoxField tempField = fieldItems![i] as PdfCheckBoxField; - tempField.isChecked = checkBoxField.isChecked; - tempField._helper.save(); - } - } - } - - String? _enableCheckBox(bool value) { - bool isChecked = false; - String? val; - if (dictionary!.containsKey(PdfDictionaryProperties.usageApplication)) { - final IPdfPrimitive? state = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.usageApplication], - ); - if (state != null && state is PdfName) { - isChecked = state.name != PdfDictionaryProperties.off; - } - } - if (value != isChecked) { - val = getItemValue(dictionary!, crossTable); - if (value) { - if (val == null || val == '') { - val = PdfDictionaryProperties.yes; - } - changed = true; - } - } - return val; - } - - String? _enableItems(bool check, String? value) { - if (checkBoxField.items != null && checkBoxField.items!.count > 0) { - (checkBoxField.items![defaultIndex] as PdfCheckBoxItem).checked = check; - final PdfDictionary? dic = - PdfFieldItemHelper.getHelper( - checkBoxField.items![defaultIndex], - ).dictionary; - if (dic != null) { - value = getItemValue(dic, crossTable); - } - } - return value; - } - - /// internal method - void drawCheckAppearance() { - final PaintParams paintParams = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - widget!.bounds.size.width, - widget!.bounds.size.height, - ), - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: checkBoxField.borderStyle, - borderWidth: checkBoxField.borderWidth, - shadowBrush: shadowBrush, - ); - PdfTemplate template = widget!.extendedAppearance!.normal.activate!; - FieldPainter().drawCheckBox( - template.graphics!, - paintParams, - styleToString(checkBoxField.style), - PdfCheckFieldState.checked, - font, - ); - template = widget!.extendedAppearance!.normal.off!; - FieldPainter().drawCheckBox( - template.graphics!, - paintParams, - styleToString(checkBoxField.style), - PdfCheckFieldState.unchecked, - font, - ); - template = widget!.extendedAppearance!.pressed.activate!; - FieldPainter().drawCheckBox( - template.graphics!, - paintParams, - styleToString(checkBoxField.style), - PdfCheckFieldState.pressedChecked, - font, - ); - template = widget!.extendedAppearance!.pressed.off!; - FieldPainter().drawCheckBox( - template.graphics!, - paintParams, - styleToString(checkBoxField.style), - PdfCheckFieldState.pressedUnchecked, - font, - ); - } - - /// internal method - @override - void beginSave() { - final PdfArray? kids = obtainKids(); - if (kids != null) { - for (int i = 0; i < kids.count; ++i) { - final PdfDictionary? widget = - crossTable!.getObject(kids[i]) as PdfDictionary?; - applyAppearance(widget, null, checkBoxField._items![i]); - } - } else { - applyAppearance(null, checkBoxField); - } - } - - /// internal method - @override - void draw() { - super.draw(); - PdfCheckFieldState state = - checkBoxField.isChecked - ? PdfCheckFieldState.checked - : PdfCheckFieldState.unchecked; - if (!isLoadedField) { - final PaintParams params = PaintParams( - bounds: checkBoxField.bounds, - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: checkBoxField.borderStyle, - borderWidth: checkBoxField.borderWidth, - shadowBrush: shadowBrush, - ); - if (fieldItems != null && fieldItems!.isNotEmpty) { - for (int i = 0; i < array.count; i++) { - final PdfCheckBoxField item = fieldItems![i] as PdfCheckBoxField; - params.bounds = item.bounds; - params.backBrush = item._helper.backBrush; - params.foreBrush = item._helper.foreBrush; - params.borderPen = item._helper.borderPen; - params.style = item.borderStyle; - params.borderWidth = item.borderWidth; - params.shadowBrush = item._helper.shadowBrush; - FieldPainter().drawCheckBox( - item.page!.graphics, - params, - styleToString(item.style), - state, - ); - } - } else { - FieldPainter().drawCheckBox( - checkBoxField.page!.graphics, - params, - styleToString(checkBoxField.style), - state, - ); - } - } else { - if (kids != null) { - for (int i = 0; i < kids!.count; ++i) { - final PdfCheckBoxItem item = - checkBoxField._items![i] as PdfCheckBoxItem; - state = - item.checked - ? PdfCheckFieldState.checked - : PdfCheckFieldState.unchecked; - if (item.page != null) { - drawStateItem(item.page!.graphics, state, null, item); - } - } - } else { - drawStateItem(checkBoxField.page!.graphics, state, checkBoxField); - } - } - } -} - -/// Represents base class for field which can be checked and unchecked states. -abstract class PdfCheckFieldBase extends PdfField { - //Fields - late PdfCheckFieldBaseHelper _checkBaseHelper; - PdfCheckBoxStyle _style = PdfCheckBoxStyle.check; - - //Properties - /// Gets or sets the style. - /// - /// The default style is check. - PdfCheckBoxStyle get style => - _checkBaseHelper.isLoadedField ? _checkBaseHelper._obtainStyle() : _style; - set style(PdfCheckBoxStyle value) { - if (_checkBaseHelper.isLoadedField) { - _checkBaseHelper.assignStyle(value); - if (this is PdfCheckBoxField && - (this as PdfCheckBoxField).items != null) { - final PdfFieldItemCollection items = (this as PdfCheckBoxField).items!; - for (int i = 0; i < items.count; i++) { - PdfCheckBoxItemHelper.setStyle(items[i] as PdfCheckBoxItem, value); - } - } - if (PdfFormHelper.getHelper(form!).needAppearances == false) { - _checkBaseHelper.changed = true; - _checkBaseHelper.fieldChanged = true; - } - } else { - if (_style != value) { - _style = value; - WidgetAnnotationHelper.getHelper(_checkBaseHelper.widget!) - .widgetAppearance! - .normalCaption = _checkBaseHelper.styleToString(_style); - } - } - } - - /// Gets or sets the color of the border. - /// - /// The default color is black. - PdfColor get borderColor => _checkBaseHelper.borderColor; - set borderColor(PdfColor value) { - _checkBaseHelper.borderColor = value; - } - - /// Gets or sets the color of the background. - /// - /// The default color is empty. - PdfColor get backColor => _checkBaseHelper.backColor; - set backColor(PdfColor value) { - _checkBaseHelper.backColor = value; - } - - /// Gets or sets the color of the text. - /// - /// The default color is black. - PdfColor get foreColor => _checkBaseHelper.foreColor; - set foreColor(PdfColor value) { - _checkBaseHelper.foreColor = value; - } - - /// Gets or sets the width of the border. - /// - /// The default value is 1. - int get borderWidth => _checkBaseHelper.borderWidth; - set borderWidth(int value) { - _checkBaseHelper.borderWidth = value; - } - - /// Gets or sets the highlighting mode. - /// - /// The default mode is invert. - PdfHighlightMode get highlightMode => _checkBaseHelper.highlightMode; - set highlightMode(PdfHighlightMode value) { - _checkBaseHelper.highlightMode = value; - } - - /// Gets or sets the border style. - /// - /// The default style is solid. - PdfBorderStyle get borderStyle => _checkBaseHelper.borderStyle; - set borderStyle(PdfBorderStyle value) { - _checkBaseHelper.borderStyle = value; - } - - //Implementation - void _initValues(PdfCheckBoxStyle? boxStyle) { - if (boxStyle != null) { - style = boxStyle; - } - } -} - -/// [PdfCheckFieldBase] herlper -class PdfCheckFieldBaseHelper extends PdfFieldHelper { - /// internal constructor - PdfCheckFieldBaseHelper(this.checkField) : super(checkField); - - /// Initializes a instance of the [PdfCheckFieldBase] class with - /// the specific page, name and bounds. - void initialize( - PdfPage? page, - String? name, - Rect bounds, { - PdfCheckBoxStyle? style, - PdfColor? borderColor, - PdfColor? backColor, - PdfColor? foreColor, - int? borderWidth, - PdfHighlightMode? highlightMode, - PdfBorderStyle? borderStyle, - String? tooltip, - }) { - checkField._checkBaseHelper = this; - internal( - page, - name, - bounds, - borderColor: borderColor, - backColor: backColor, - foreColor: foreColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - ); - dictionary!.setProperty( - PdfDictionaryProperties.ft, - PdfName(PdfDictionaryProperties.btn), - ); - checkField._initValues(style); - } - - /// internal constructor - @override - void load(PdfDictionary dictionary, PdfCrossTable crossTable) { - checkField._checkBaseHelper = this; - super.load(dictionary, crossTable); - } - - /// internal field - PdfCheckFieldBase checkField; - PdfTemplate? _checkedTemplate; - PdfTemplate? _uncheckedTemplate; - PdfTemplate? _pressedCheckedTemplate; - PdfTemplate? _pressedUncheckedTemplate; - - /// internal method - static PdfCheckFieldBaseHelper getHelper(PdfCheckFieldBase checkField) { - return checkField._checkBaseHelper; - } - - /// internal method - @override - void save() { - super.save(); - if (checkField.form != null) { - final Map checkValue = _createTemplate( - _checkedTemplate, - ); - _checkedTemplate = checkValue['template']; - final Map unCheckValue = _createTemplate( - _uncheckedTemplate, - ); - _uncheckedTemplate = unCheckValue['template']; - final Map pressedValue = _createTemplate( - _pressedCheckedTemplate, - ); - _pressedCheckedTemplate = pressedValue['template']; - final Map unPressedValue = _createTemplate( - _pressedUncheckedTemplate, - ); - _pressedUncheckedTemplate = unPressedValue['template']; - widget!.extendedAppearance!.normal.activate = _checkedTemplate; - widget!.extendedAppearance!.normal.off = _uncheckedTemplate; - widget!.extendedAppearance!.pressed.activate = _pressedCheckedTemplate; - widget!.extendedAppearance!.pressed.off = _pressedUncheckedTemplate; - _drawCheckAppearance(); - } else { - _releaseTemplate(_checkedTemplate); - _releaseTemplate(_uncheckedTemplate); - _releaseTemplate(_pressedCheckedTemplate); - _releaseTemplate(_pressedUncheckedTemplate); - } - } - - Map _createTemplate(PdfTemplate? template) { - if (template == null) { - template = PdfTemplate( - widget!.bounds.size.width, - widget!.bounds.size.height, - ); - } else { - template.reset(widget!.bounds.size.width, widget!.bounds.size.height); - } - return {'template': template}; - } - - void _releaseTemplate(PdfTemplate? template) { - if (template != null) { - template.reset(); - widget!.extendedAppearance = null; - } - } - - void _drawCheckAppearance() { - if (checkField is PdfCheckBoxField) { - (checkField as PdfCheckBoxField)._helper.drawCheckAppearance(); - } else if (checkField is PdfRadioButtonListItem) { - PdfRadioButtonListItemHelper.getHelper( - checkField as PdfRadioButtonListItem, - ).drawCheckAppearance(); - } - } - - /// internal method - void applyAppearance( - PdfDictionary? widget, - PdfCheckFieldBase? item, [ - PdfFieldItem? fieldItem, - ]) { - if (widget != null && item != null) { - if (item._checkBaseHelper.dictionary!.containsKey( - PdfDictionaryProperties.v, - ) && - item is! PdfRadioButtonListItem) { - widget.setName( - PdfName(PdfDictionaryProperties.v), - PdfDictionaryProperties.yes, - ); - widget.setName( - PdfName(PdfDictionaryProperties.usageApplication), - PdfDictionaryProperties.yes, - ); - } else if (!item._checkBaseHelper.dictionary!.containsKey( - PdfDictionaryProperties.v, - ) && - item is! PdfRadioButtonListItem) { - widget.remove(PdfDictionaryProperties.v); - widget.setName( - PdfName(PdfDictionaryProperties.usageApplication), - PdfDictionaryProperties.off, - ); - } - } else if (widget != null && fieldItem != null) { - widget = PdfFieldItemHelper.getHelper(fieldItem).dictionary; - } else { - widget = item!._checkBaseHelper.dictionary; - } - if ((widget != null) && (widget.containsKey(PdfDictionaryProperties.ap))) { - final PdfDictionary? appearance = - crossTable!.getObject(widget[PdfDictionaryProperties.ap]) - as PdfDictionary?; - if ((appearance != null) && - (appearance.containsKey(PdfDictionaryProperties.n))) { - String? value = ''; - Rect rect; - if (item != null) { - value = getItemValue(widget, item._checkBaseHelper.crossTable); - rect = item.bounds; - } else if (fieldItem != null) { - value = getItemValue( - widget, - PdfFieldHelper.getHelper( - PdfFieldItemHelper.getHelper(fieldItem).field, - ).crossTable, - ); - rect = fieldItem.bounds; - } else { - value = getItemValue(widget, crossTable); - rect = checkField.bounds; - } - IPdfPrimitive? holder = PdfCrossTable.dereference( - appearance[PdfDictionaryProperties.n], - ); - PdfDictionary? normal = holder as PdfDictionary?; - if (fieldChanged == true && normal != null) { - normal = PdfDictionary(); - final PdfTemplate checkedTemplate = PdfTemplate( - rect.width, - rect.height, - ); - final PdfTemplate unchekedTemplate = PdfTemplate( - rect.width, - rect.height, - ); - drawStateItem( - checkedTemplate.graphics!, - PdfCheckFieldState.checked, - item, - fieldItem, - ); - drawStateItem( - unchekedTemplate.graphics!, - PdfCheckFieldState.unchecked, - item, - fieldItem, - ); - normal.setProperty(value, PdfReferenceHolder(checkedTemplate)); - normal.setProperty( - PdfDictionaryProperties.off, - PdfReferenceHolder(unchekedTemplate), - ); - appearance.remove(PdfDictionaryProperties.n); - appearance[PdfDictionaryProperties.n] = PdfReferenceHolder(normal); - } - holder = PdfCrossTable.dereference( - appearance[PdfDictionaryProperties.d], - ); - PdfDictionary? pressed = holder as PdfDictionary?; - if (fieldChanged == true && pressed != null) { - pressed = PdfDictionary(); - final PdfTemplate checkedTemplate = PdfTemplate( - rect.width, - rect.height, - ); - final PdfTemplate unchekedTemplate = PdfTemplate( - rect.width, - rect.height, - ); - drawStateItem( - checkedTemplate.graphics!, - PdfCheckFieldState.pressedChecked, - item, - fieldItem, - ); - drawStateItem( - unchekedTemplate.graphics!, - PdfCheckFieldState.pressedUnchecked, - item, - fieldItem, - ); - pressed.setProperty( - PdfDictionaryProperties.off, - PdfReferenceHolder(unchekedTemplate), - ); - pressed.setProperty(value, PdfReferenceHolder(checkedTemplate)); - appearance.remove(PdfDictionaryProperties.d); - appearance[PdfDictionaryProperties.d] = PdfReferenceHolder(pressed); - } - } - widget.setProperty(PdfDictionaryProperties.ap, appearance); - } else if (PdfFormHelper.getHelper( - checkField.form!, - ).setAppearanceDictionary) { - PdfFormHelper.getHelper(checkField.form!).needAppearances = true; - } else if (PdfFormHelper.getHelper(form!).setAppearanceDictionary && - !PdfFormHelper.getHelper(form!).needAppearances!) { - final PdfDictionary dic = PdfDictionary(); - final PdfTemplate template = PdfTemplate( - checkField.bounds.width, - checkField.bounds.height, - ); - drawAppearance(template); - dic.setProperty(PdfDictionaryProperties.n, PdfReferenceHolder(template)); - widget!.setProperty(PdfDictionaryProperties.ap, dic); - } - } - - PdfCheckBoxStyle _obtainStyle() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfCheckBoxStyle style = PdfCheckBoxStyle.check; - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final PdfDictionary bs = - crossTable!.getObject(widget[PdfDictionaryProperties.mk])! - as PdfDictionary; - style = _createStyle(bs); - } - return style; - } - - PdfCheckBoxStyle _createStyle(PdfDictionary bs) { - PdfCheckBoxStyle style = PdfCheckBoxStyle.check; - if (bs.containsKey(PdfDictionaryProperties.ca)) { - final PdfString? name = - crossTable!.getObject(bs[PdfDictionaryProperties.ca]) as PdfString?; - if (name != null) { - final String ch = name.value!.toLowerCase(); - switch (ch) { - case '4': - style = PdfCheckBoxStyle.check; - break; - case 'l': - style = PdfCheckBoxStyle.circle; - break; - case '8': - style = PdfCheckBoxStyle.cross; - break; - case 'u': - style = PdfCheckBoxStyle.diamond; - break; - case 'n': - style = PdfCheckBoxStyle.square; - break; - case 'h': - style = PdfCheckBoxStyle.star; - break; - } - } - } - return style; - } - - /// internal method - void assignStyle(PdfCheckBoxStyle checkStyle) { - String style = ''; - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.mk)) { - switch (checkStyle) { - case PdfCheckBoxStyle.check: - style = '4'; - break; - case PdfCheckBoxStyle.circle: - style = 'l'; - break; - case PdfCheckBoxStyle.cross: - style = '8'; - break; - case PdfCheckBoxStyle.diamond: - style = 'u'; - break; - case PdfCheckBoxStyle.square: - style = 'n'; - break; - case PdfCheckBoxStyle.star: - style = 'H'; - break; - } - if (widget[PdfDictionaryProperties.mk] is PdfReferenceHolder) { - final PdfDictionary widgetDict = - crossTable!.getObject(widget[PdfDictionaryProperties.mk])! - as PdfDictionary; - if (widgetDict.containsKey(PdfDictionaryProperties.ca)) { - widgetDict[PdfDictionaryProperties.ca] = PdfString(style); - } else { - widgetDict.setProperty(PdfDictionaryProperties.ca, PdfString(style)); - } - } else { - (widget[PdfDictionaryProperties.mk]! - as PdfDictionary)[PdfDictionaryProperties.ca] = PdfString(style); - } - WidgetAnnotationHelper.getHelper(checkField._checkBaseHelper.widget!) - .widgetAppearance! - .normalCaption = style; - } - } - - /// internal method - String styleToString(PdfCheckBoxStyle style) { - switch (style) { - case PdfCheckBoxStyle.circle: - return 'l'; - case PdfCheckBoxStyle.cross: - return '8'; - case PdfCheckBoxStyle.diamond: - return 'u'; - case PdfCheckBoxStyle.square: - return 'n'; - case PdfCheckBoxStyle.star: - return 'H'; - case PdfCheckBoxStyle.check: - return '4'; - } - } -} - -/// Represents an item of a radio button list. -class PdfRadioButtonListItem extends PdfCheckFieldBase { - //Constructor - /// Initializes a instance of the [PdfRadioButtonListItem] class with - /// the specific value and bounds. - PdfRadioButtonListItem( - String value, - Rect bounds, { - PdfCheckBoxStyle style = PdfCheckBoxStyle.circle, - PdfColor? borderColor, - PdfColor? backColor, - PdfColor? foreColor, - int? borderWidth, - PdfHighlightMode highlightMode = PdfHighlightMode.invert, - PdfBorderStyle borderStyle = PdfBorderStyle.solid, - String? tooltip, - }) { - _radioButtonListItemHelper = PdfRadioButtonListItemHelper(this); - _radioButtonListItemHelper.initialize( - null, - null, - bounds, - style: style, - borderColor: borderColor, - backColor: backColor, - foreColor: foreColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - ); - this.value = value; - _radioButtonListItemHelper.dictionary!.beginSave = - _radioButtonListItemHelper.dictionaryBeginSave; - WidgetAnnotationHelper.getHelper(_radioButtonListItemHelper.widget!) - .beginSave = _radioButtonListItemHelper._widgetSave; - style = PdfCheckBoxStyle.circle; - } - - PdfRadioButtonListItem._loaded( - PdfDictionary dictionary, - PdfCrossTable crossTable, - PdfRadioButtonListField field, - ) { - _radioButtonListItemHelper = PdfRadioButtonListItemHelper(this); - _radioButtonListItemHelper.load(dictionary, crossTable); - _radioButtonListItemHelper._field = field; - } - late PdfRadioButtonListItemHelper _radioButtonListItemHelper; - - //Properties - ///Gets or sets the value. - String get value { - if (_radioButtonListItemHelper.isLoadedField) { - _radioButtonListItemHelper._value = _radioButtonListItemHelper - .getItemValue( - _radioButtonListItemHelper.dictionary!, - _radioButtonListItemHelper.crossTable, - ); - } - return _radioButtonListItemHelper._value!; - } - - set value(String value) { - if (value.isEmpty) { - ArgumentError.value('value should not be empty'); - } - if (_radioButtonListItemHelper.isLoadedField) { - _radioButtonListItemHelper._setItemValue(value); - } - _radioButtonListItemHelper._value = value; - } - - /// Gets the form of the field.{Read-Only} - @override - PdfForm? get form => - (_radioButtonListItemHelper._field != null) - ? _radioButtonListItemHelper._field!.form - : null; - - @override - set style(PdfCheckBoxStyle value) { - if (_radioButtonListItemHelper.isLoadedField) { - _radioButtonListItemHelper.assignStyle(value); - if (PdfFormHelper.getHelper(form!).needAppearances == false) { - PdfFieldHelper.getHelper(_radioButtonListItemHelper._field!).changed = - true; - PdfFieldHelper.getHelper(_radioButtonListItemHelper._field!) - .fieldChanged = true; - } - } else { - if (super.style != value) { - super.style = value; - WidgetAnnotationHelper.getHelper( - _radioButtonListItemHelper.widget!, - ).widgetAppearance!.normalCaption = _radioButtonListItemHelper - .styleToString(super.style); - } - } - } -} - -/// [PdfRadioButtonListItem] helper -class PdfRadioButtonListItemHelper extends PdfCheckFieldBaseHelper { - /// internal constructor - PdfRadioButtonListItemHelper(this.base) : super(base); - - /// internal field - PdfRadioButtonListItem base; - String? _value = ''; - PdfRadioButtonListField? _field; - - /// internal field - String? optionValue; - - /// internal method - static PdfRadioButtonListItem loaded( - PdfDictionary dictionary, - PdfCrossTable crossTable, - PdfRadioButtonListField field, - ) { - return PdfRadioButtonListItem._loaded(dictionary, crossTable, field); - } - - /// internal method - static PdfRadioButtonListItemHelper getHelper(PdfRadioButtonListItem base) { - return base._radioButtonListItemHelper; - } - - void _widgetSave(Object sender, SavePdfPrimitiveArgs? e) { - save(); - } - - /// internal method - @override - void save() { - super.save(); - if (base.form != null) { - final String value = _obtainValue(); - widget!.extendedAppearance!.normal.onMappingName = value; - widget!.extendedAppearance!.pressed.onMappingName = value; - if (_field!.selectedItem == base) { - widget!.appearanceState = _obtainValue(); - } else { - widget!.appearanceState = PdfDictionaryProperties.off; - } - } - } - - String _obtainValue() { - String? returnValue; - if (_value!.isEmpty) { - final int index = _field!.items.indexOf(base); - returnValue = index.toString(); - } else { - returnValue = _value; - } - return PdfName.normalizeValue(returnValue)!; - } - - /// internal method - void setField(PdfRadioButtonListField? field, [bool? isItem]) { - widget!.parent = field; - final PdfPage page = (field != null) ? field.page! : _field!.page!; - if (!PdfPageHelper.getHelper(page).isLoadedPage) { - if (field == null) { - page.annotations.remove(widget!); - } else { - page.annotations.add(widget!); - } - } else if (PdfPageHelper.getHelper(page).isLoadedPage && !isItem!) { - final PdfDictionary pageDic = PdfPageHelper.getHelper(page).dictionary!; - PdfArray? annots; - if (pageDic.containsKey(PdfDictionaryProperties.annots)) { - annots = - PdfPageHelper.getHelper( - page, - ).crossTable!.getObject(pageDic[PdfDictionaryProperties.annots]) - as PdfArray?; - } else { - annots = PdfArray(); - } - final PdfReferenceHolder reference = PdfReferenceHolder(widget); - if (field == null) { - final int index = annots!.indexOf(reference); - if (index >= 0) { - annots.removeAt(index); - } - } else { - annots!.add(reference); - if (!field.page!.annotations.contains(widget!)) { - field.page!.annotations.add(widget!); - } - PdfPageHelper.getHelper( - field.page!, - ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); - } - } - if (field != null) { - _field = field; - } - } - - void _setItemValue(String value) { - final String str = value; - if (dictionary!.containsKey(PdfDictionaryProperties.ap)) { - PdfDictionary dic = - crossTable!.getObject(dictionary![PdfDictionaryProperties.ap])! - as PdfDictionary; - if (dic.containsKey(PdfDictionaryProperties.n)) { - final PdfReference normal = crossTable!.getReference( - dic[PdfDictionaryProperties.n], - ); - dic = crossTable!.getObject(normal)! as PdfDictionary; - final String? dicValue = getItemValue(dictionary!, crossTable); - if (dic.containsKey(dicValue)) { - final PdfReference valRef = crossTable!.getReference(dic[dicValue]); - dic.remove(base.value); - dic.setProperty( - str, - PdfReferenceHolder.fromReference(valRef, crossTable), - ); - } - } - } - if (str == _field!.selectedValue) { - dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - str, - ); - } else { - dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - PdfDictionaryProperties.off, - ); - } - } - - /// internal method - @override - void draw() { - removeAnnotationFromPage(_field!.page); - final PaintParams params = PaintParams( - bounds: base.bounds, - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: base.borderStyle, - borderWidth: base.borderWidth, - shadowBrush: shadowBrush, - ); - if (params.borderPen != null && params.borderWidth == 0) { - params.borderWidth = 1; - } - PdfCheckFieldState state = PdfCheckFieldState.unchecked; - if ((_field!.selectedIndex >= 0) && (_field!.selectedValue == base.value)) { - state = PdfCheckFieldState.checked; - } - FieldPainter().drawRadioButton( - _field!.page!.graphics, - params, - styleToString(base.style), - state, - ); - } - - /// internal method - @override - Rect getBounds() { - IPdfPrimitive? array; - if (dictionary!.containsKey(PdfDictionaryProperties.rect)) { - array = crossTable!.getObject(dictionary![PdfDictionaryProperties.rect]); - } - Rect bounds; - if (array != null && array is PdfArray) { - bounds = array.toRectangle().rect; - double? y = 0; - if ((PdfCrossTable.dereference(array[1])! as PdfNumber).value! < 0) { - y = - (PdfCrossTable.dereference(array[1])! as PdfNumber).value - as double?; - if ((PdfCrossTable.dereference(array[1])! as PdfNumber).value! > - (PdfCrossTable.dereference(array[3])! as PdfNumber).value!) { - y = y! - bounds.height; - } - } - bounds = Rect.fromLTWH( - bounds.left, - y! <= 0 ? bounds.top : y, - bounds.width, - bounds.height, - ); - } else { - bounds = Rect.zero; - } - return bounds; - } - - /// internal method - void drawCheckAppearance() { - final PaintParams paintParams = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - widget!.bounds.size.width, - widget!.bounds.size.height, - ), - backBrush: PdfSolidBrush(base.backColor), - foreBrush: PdfSolidBrush(base.foreColor), - borderPen: borderPen, - style: base.borderStyle, - borderWidth: base.borderWidth, - shadowBrush: PdfSolidBrush(base.backColor), - ); - - PdfTemplate template = widget!.extendedAppearance!.normal.activate!; - FieldPainter().drawRadioButton( - template.graphics, - paintParams, - styleToString(base.style), - PdfCheckFieldState.checked, - ); - - template = widget!.extendedAppearance!.normal.off!; - FieldPainter().drawRadioButton( - template.graphics, - paintParams, - styleToString(base.style), - PdfCheckFieldState.unchecked, - ); - - template = widget!.extendedAppearance!.pressed.activate!; - FieldPainter().drawRadioButton( - template.graphics, - paintParams, - styleToString(base.style), - PdfCheckFieldState.pressedChecked, - ); - - template = widget!.extendedAppearance!.pressed.off!; - FieldPainter().drawRadioButton( - template.graphics, - paintParams, - styleToString(base.style), - PdfCheckFieldState.pressedUnchecked, - ); - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../annotations/widget_annotation.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_color.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_field.dart'; +import 'pdf_field_item.dart'; +import 'pdf_field_item_collection.dart'; +import 'pdf_field_painter.dart'; +import 'pdf_form.dart'; +import 'pdf_radio_button_list_field.dart'; + +/// Represents check box field in the PDF form. +class PdfCheckBoxField extends PdfCheckFieldBase { + //Constructor + /// Initializes a new instance of the [PdfCheckBoxField] class with + /// the specific page, name and bounds. + PdfCheckBoxField( + PdfPage page, + String name, + Rect bounds, { + bool isChecked = false, + PdfCheckBoxStyle style = PdfCheckBoxStyle.check, + PdfColor? borderColor, + PdfColor? backColor, + PdfColor? foreColor, + int? borderWidth, + PdfHighlightMode highlightMode = PdfHighlightMode.invert, + PdfBorderStyle borderStyle = PdfBorderStyle.solid, + String? tooltip, + }) { + _helper = PdfCheckBoxFieldHelper(this); + _helper.initialize( + page, + name, + bounds, + style: style, + borderColor: borderColor, + backColor: backColor, + foreColor: foreColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + ); + _setCheckBoxValue(isChecked); + } + + PdfCheckBoxField._loaded(PdfDictionary dictionary, PdfCrossTable crossTable) { + _helper = PdfCheckBoxFieldHelper(this); + _helper.load(dictionary, crossTable); + _items = PdfFieldItemCollectionHelper.load(this); + final PdfArray? kids = _helper.kids; + if (kids != null) { + for (int i = 0; i < kids.count; ++i) { + final PdfDictionary? itemDictionary = + crossTable.getObject(kids[i]) as PdfDictionary?; + PdfFieldItemCollectionHelper.getHelper( + _items!, + ).add(PdfCheckBoxItemHelper.getItem(this, i, itemDictionary)); + } + _helper.array = kids; + } + } + + //Fields + late PdfCheckBoxFieldHelper _helper; + bool _checked = false; + PdfFieldItemCollection? _items; + + //Properties + /// Gets or sets a value indicating whether this [PdfCheckBoxField] is checked. + /// + /// The default value is false. + bool get isChecked { + if (_helper.isLoadedField) { + if (items != null && items!.count > 0) { + final IPdfPrimitive? state = PdfCrossTable.dereference( + PdfFieldItemHelper.getHelper( + items![_helper.defaultIndex], + ).dictionary![PdfDictionaryProperties.usageApplication], + ); + if (state == null) { + final IPdfPrimitive? name = PdfFieldHelper.getValue( + _helper.dictionary!, + _helper.crossTable, + PdfDictionaryProperties.v, + false, + ); + if (name != null && name is PdfName) { + _checked = + name.name == + _helper.getItemValue( + PdfFieldItemHelper.getHelper( + items![_helper.defaultIndex], + ).dictionary!, + _helper.crossTable, + ); + } + } else if (state is PdfName) { + _checked = state.name != PdfDictionaryProperties.off; + } + return _checked; + } + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + if (_helper.dictionary![PdfDictionaryProperties.v]! is PdfName) { + final PdfName chk = + _helper.dictionary![PdfDictionaryProperties.v]! as PdfName; + _checked = chk.name != 'Off'; + } else if (_helper.dictionary![PdfDictionaryProperties.v]! + is PdfString) { + final PdfString chk = + _helper.dictionary![PdfDictionaryProperties.v]! as PdfString; + _checked = chk.value != 'Off'; + } + } + } + return _checked; + } + + set isChecked(bool value) { + if (_helper.isLoadedField) { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + if (_helper.dictionary![PdfDictionaryProperties.v]! is PdfName) { + final PdfName chk = + _helper.dictionary![PdfDictionaryProperties.v]! as PdfName; + if (chk.name!.isNotEmpty) { + _checked = chk.name != 'Off'; + } else { + _helper.dictionary!.remove(PdfDictionaryProperties.v); + } + } else if (_helper.dictionary![PdfDictionaryProperties.v]! + is PdfString) { + final PdfString chk = + _helper.dictionary![PdfDictionaryProperties.v]! as PdfString; + if (chk.value!.isNotEmpty) { + _checked = chk.value != 'Off'; + } else { + _helper.dictionary!.remove(PdfDictionaryProperties.v); + } + } + } + PdfFormHelper.getHelper(form!).setAppearanceDictionary = true; + if (PdfFormHelper.getHelper(super.form!).needAppearances == false) { + _helper.changed = true; + } + } + if (_checked != value) { + _checked = value; + String? val; + if (_helper.isLoadedField) { + val = _helper._enableCheckBox(value); + val = _helper._enableItems(value, val); + } + if (_checked) { + _helper.dictionary!.setName( + PdfName(PdfDictionaryProperties.v), + val ?? PdfDictionaryProperties.yes, + ); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.usageApplication, + PdfName(val ?? PdfDictionaryProperties.yes), + ); + } else { + _helper.dictionary!.remove(PdfDictionaryProperties.v); + if (_helper.dictionary!.containsKey( + PdfDictionaryProperties.usageApplication, + )) { + _helper.dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + PdfDictionaryProperties.off, + ); + } + } + } + } + + /// Gets the collection of check box field items. + PdfFieldItemCollection? get items => _items; + + // ignore: use_setters_to_change_properties + void _setCheckBoxValue(bool isChecked) { + this.isChecked = isChecked; + } +} + +/// [PdfCheckBoxField] helper +class PdfCheckBoxFieldHelper extends PdfCheckFieldBaseHelper { + /// internal constructor + PdfCheckBoxFieldHelper(this.checkBoxField) : super(checkBoxField); + + /// internal field + PdfCheckBoxField checkBoxField; + + /// internal field + // ignore: avoid_setters_without_getters + set items(PdfFieldItemCollection? value) { + checkBoxField._items = value; + } + + /// internal method + static PdfCheckBoxField loadCheckBoxField( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfCheckBoxField._loaded(dictionary, crossTable); + } + + /// internal method + static PdfCheckBoxFieldHelper getHelper(PdfCheckBoxField checkBoxField) { + return checkBoxField._helper; + } + + /// internal method + @override + void save() { + super.save(); + if (checkBoxField.form != null) { + if (!checkBoxField.isChecked) { + widget!.appearanceState = PdfDictionaryProperties.off; + } else { + widget!.appearanceState = PdfDictionaryProperties.yes; + } + } + if (fieldItems != null && fieldItems!.length > 1) { + for (int i = 1; i < fieldItems!.length; i++) { + final PdfCheckBoxField tempField = fieldItems![i] as PdfCheckBoxField; + tempField.isChecked = checkBoxField.isChecked; + tempField._helper.save(); + } + } + } + + String? _enableCheckBox(bool value) { + bool isChecked = false; + String? val; + if (dictionary!.containsKey(PdfDictionaryProperties.usageApplication)) { + final IPdfPrimitive? state = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.usageApplication], + ); + if (state != null && state is PdfName) { + isChecked = state.name != PdfDictionaryProperties.off; + } + } + if (value != isChecked) { + val = getItemValue(dictionary!, crossTable); + if (value) { + if (val == null || val == '') { + val = PdfDictionaryProperties.yes; + } + changed = true; + } + } + return val; + } + + String? _enableItems(bool check, String? value) { + if (checkBoxField.items != null && checkBoxField.items!.count > 0) { + (checkBoxField.items![defaultIndex] as PdfCheckBoxItem).checked = check; + final PdfDictionary? dic = + PdfFieldItemHelper.getHelper( + checkBoxField.items![defaultIndex], + ).dictionary; + if (dic != null) { + value = getItemValue(dic, crossTable); + } + } + return value; + } + + /// internal method + void drawCheckAppearance() { + final PaintParams paintParams = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + widget!.bounds.size.width, + widget!.bounds.size.height, + ), + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: checkBoxField.borderStyle, + borderWidth: checkBoxField.borderWidth, + shadowBrush: shadowBrush, + ); + PdfTemplate template = widget!.extendedAppearance!.normal.activate!; + FieldPainter().drawCheckBox( + template.graphics!, + paintParams, + styleToString(checkBoxField.style), + PdfCheckFieldState.checked, + font, + ); + template = widget!.extendedAppearance!.normal.off!; + FieldPainter().drawCheckBox( + template.graphics!, + paintParams, + styleToString(checkBoxField.style), + PdfCheckFieldState.unchecked, + font, + ); + template = widget!.extendedAppearance!.pressed.activate!; + FieldPainter().drawCheckBox( + template.graphics!, + paintParams, + styleToString(checkBoxField.style), + PdfCheckFieldState.pressedChecked, + font, + ); + template = widget!.extendedAppearance!.pressed.off!; + FieldPainter().drawCheckBox( + template.graphics!, + paintParams, + styleToString(checkBoxField.style), + PdfCheckFieldState.pressedUnchecked, + font, + ); + } + + /// internal method + @override + void beginSave() { + final PdfArray? kids = obtainKids(); + if (kids != null) { + for (int i = 0; i < kids.count; ++i) { + final PdfDictionary? widget = + crossTable!.getObject(kids[i]) as PdfDictionary?; + applyAppearance(widget, null, checkBoxField._items![i]); + } + } else { + applyAppearance(null, checkBoxField); + } + } + + /// internal method + @override + void draw() { + super.draw(); + PdfCheckFieldState state = + checkBoxField.isChecked + ? PdfCheckFieldState.checked + : PdfCheckFieldState.unchecked; + if (!isLoadedField) { + final PaintParams params = PaintParams( + bounds: checkBoxField.bounds, + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: checkBoxField.borderStyle, + borderWidth: checkBoxField.borderWidth, + shadowBrush: shadowBrush, + ); + if (fieldItems != null && fieldItems!.isNotEmpty) { + for (int i = 0; i < array.count; i++) { + final PdfCheckBoxField item = fieldItems![i] as PdfCheckBoxField; + params.bounds = item.bounds; + params.backBrush = item._helper.backBrush; + params.foreBrush = item._helper.foreBrush; + params.borderPen = item._helper.borderPen; + params.style = item.borderStyle; + params.borderWidth = item.borderWidth; + params.shadowBrush = item._helper.shadowBrush; + FieldPainter().drawCheckBox( + item.page!.graphics, + params, + styleToString(item.style), + state, + ); + } + } else { + FieldPainter().drawCheckBox( + checkBoxField.page!.graphics, + params, + styleToString(checkBoxField.style), + state, + ); + } + } else { + if (kids != null) { + for (int i = 0; i < kids!.count; ++i) { + final PdfCheckBoxItem item = + checkBoxField._items![i] as PdfCheckBoxItem; + state = + item.checked + ? PdfCheckFieldState.checked + : PdfCheckFieldState.unchecked; + if (item.page != null) { + drawStateItem(item.page!.graphics, state, null, item); + } + } + } else { + drawStateItem(checkBoxField.page!.graphics, state, checkBoxField); + } + } + } +} + +/// Represents base class for field which can be checked and unchecked states. +abstract class PdfCheckFieldBase extends PdfField { + //Fields + late PdfCheckFieldBaseHelper _checkBaseHelper; + PdfCheckBoxStyle _style = PdfCheckBoxStyle.check; + + //Properties + /// Gets or sets the style. + /// + /// The default style is check. + PdfCheckBoxStyle get style => + _checkBaseHelper.isLoadedField ? _checkBaseHelper._obtainStyle() : _style; + set style(PdfCheckBoxStyle value) { + if (_checkBaseHelper.isLoadedField) { + _checkBaseHelper.assignStyle(value); + if (this is PdfCheckBoxField && + (this as PdfCheckBoxField).items != null) { + final PdfFieldItemCollection items = (this as PdfCheckBoxField).items!; + for (int i = 0; i < items.count; i++) { + PdfCheckBoxItemHelper.setStyle(items[i] as PdfCheckBoxItem, value); + } + } + if (PdfFormHelper.getHelper(form!).needAppearances == false) { + _checkBaseHelper.changed = true; + _checkBaseHelper.fieldChanged = true; + } + } else { + if (_style != value) { + _style = value; + WidgetAnnotationHelper.getHelper(_checkBaseHelper.widget!) + .widgetAppearance! + .normalCaption = _checkBaseHelper.styleToString(_style); + } + } + } + + /// Gets or sets the color of the border. + /// + /// The default color is black. + PdfColor get borderColor => _checkBaseHelper.borderColor; + set borderColor(PdfColor value) { + _checkBaseHelper.borderColor = value; + } + + /// Gets or sets the color of the background. + /// + /// The default color is empty. + PdfColor get backColor => _checkBaseHelper.backColor; + set backColor(PdfColor value) { + _checkBaseHelper.backColor = value; + } + + /// Gets or sets the color of the text. + /// + /// The default color is black. + PdfColor get foreColor => _checkBaseHelper.foreColor; + set foreColor(PdfColor value) { + _checkBaseHelper.foreColor = value; + } + + /// Gets or sets the width of the border. + /// + /// The default value is 1. + int get borderWidth => _checkBaseHelper.borderWidth; + set borderWidth(int value) { + _checkBaseHelper.borderWidth = value; + } + + /// Gets or sets the highlighting mode. + /// + /// The default mode is invert. + PdfHighlightMode get highlightMode => _checkBaseHelper.highlightMode; + set highlightMode(PdfHighlightMode value) { + _checkBaseHelper.highlightMode = value; + } + + /// Gets or sets the border style. + /// + /// The default style is solid. + PdfBorderStyle get borderStyle => _checkBaseHelper.borderStyle; + set borderStyle(PdfBorderStyle value) { + _checkBaseHelper.borderStyle = value; + } + + //Implementation + void _initValues(PdfCheckBoxStyle? boxStyle) { + if (boxStyle != null) { + style = boxStyle; + } + } +} + +/// [PdfCheckFieldBase] herlper +class PdfCheckFieldBaseHelper extends PdfFieldHelper { + /// internal constructor + PdfCheckFieldBaseHelper(this.checkField) : super(checkField); + + /// Initializes a instance of the [PdfCheckFieldBase] class with + /// the specific page, name and bounds. + void initialize( + PdfPage? page, + String? name, + Rect bounds, { + PdfCheckBoxStyle? style, + PdfColor? borderColor, + PdfColor? backColor, + PdfColor? foreColor, + int? borderWidth, + PdfHighlightMode? highlightMode, + PdfBorderStyle? borderStyle, + String? tooltip, + }) { + checkField._checkBaseHelper = this; + internal( + page, + name, + bounds, + borderColor: borderColor, + backColor: backColor, + foreColor: foreColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + ); + dictionary!.setProperty( + PdfDictionaryProperties.ft, + PdfName(PdfDictionaryProperties.btn), + ); + checkField._initValues(style); + } + + /// internal constructor + @override + void load(PdfDictionary dictionary, PdfCrossTable crossTable) { + checkField._checkBaseHelper = this; + super.load(dictionary, crossTable); + } + + /// internal field + PdfCheckFieldBase checkField; + PdfTemplate? _checkedTemplate; + PdfTemplate? _uncheckedTemplate; + PdfTemplate? _pressedCheckedTemplate; + PdfTemplate? _pressedUncheckedTemplate; + + /// internal method + static PdfCheckFieldBaseHelper getHelper(PdfCheckFieldBase checkField) { + return checkField._checkBaseHelper; + } + + /// internal method + @override + void save() { + super.save(); + if (checkField.form != null) { + final Map checkValue = _createTemplate( + _checkedTemplate, + ); + _checkedTemplate = checkValue['template']; + final Map unCheckValue = _createTemplate( + _uncheckedTemplate, + ); + _uncheckedTemplate = unCheckValue['template']; + final Map pressedValue = _createTemplate( + _pressedCheckedTemplate, + ); + _pressedCheckedTemplate = pressedValue['template']; + final Map unPressedValue = _createTemplate( + _pressedUncheckedTemplate, + ); + _pressedUncheckedTemplate = unPressedValue['template']; + widget!.extendedAppearance!.normal.activate = _checkedTemplate; + widget!.extendedAppearance!.normal.off = _uncheckedTemplate; + widget!.extendedAppearance!.pressed.activate = _pressedCheckedTemplate; + widget!.extendedAppearance!.pressed.off = _pressedUncheckedTemplate; + _drawCheckAppearance(); + } else { + _releaseTemplate(_checkedTemplate); + _releaseTemplate(_uncheckedTemplate); + _releaseTemplate(_pressedCheckedTemplate); + _releaseTemplate(_pressedUncheckedTemplate); + } + } + + Map _createTemplate(PdfTemplate? template) { + if (template == null) { + template = PdfTemplate( + widget!.bounds.size.width, + widget!.bounds.size.height, + ); + } else { + template.reset(widget!.bounds.size.width, widget!.bounds.size.height); + } + return {'template': template}; + } + + void _releaseTemplate(PdfTemplate? template) { + if (template != null) { + template.reset(); + widget!.extendedAppearance = null; + } + } + + void _drawCheckAppearance() { + if (checkField is PdfCheckBoxField) { + (checkField as PdfCheckBoxField)._helper.drawCheckAppearance(); + } else if (checkField is PdfRadioButtonListItem) { + PdfRadioButtonListItemHelper.getHelper( + checkField as PdfRadioButtonListItem, + ).drawCheckAppearance(); + } + } + + /// internal method + void applyAppearance( + PdfDictionary? widget, + PdfCheckFieldBase? item, [ + PdfFieldItem? fieldItem, + ]) { + if (widget != null && item != null) { + if (item._checkBaseHelper.dictionary!.containsKey( + PdfDictionaryProperties.v, + ) && + item is! PdfRadioButtonListItem) { + widget.setName( + PdfName(PdfDictionaryProperties.v), + PdfDictionaryProperties.yes, + ); + widget.setName( + PdfName(PdfDictionaryProperties.usageApplication), + PdfDictionaryProperties.yes, + ); + } else if (!item._checkBaseHelper.dictionary!.containsKey( + PdfDictionaryProperties.v, + ) && + item is! PdfRadioButtonListItem) { + widget.remove(PdfDictionaryProperties.v); + widget.setName( + PdfName(PdfDictionaryProperties.usageApplication), + PdfDictionaryProperties.off, + ); + } + } else if (widget != null && fieldItem != null) { + widget = PdfFieldItemHelper.getHelper(fieldItem).dictionary; + } else { + widget = item!._checkBaseHelper.dictionary; + } + if ((widget != null) && (widget.containsKey(PdfDictionaryProperties.ap))) { + final PdfDictionary? appearance = + crossTable!.getObject(widget[PdfDictionaryProperties.ap]) + as PdfDictionary?; + if ((appearance != null) && + (appearance.containsKey(PdfDictionaryProperties.n))) { + String? value = ''; + Rect rect; + if (item != null) { + value = getItemValue(widget, item._checkBaseHelper.crossTable); + rect = item.bounds; + } else if (fieldItem != null) { + value = getItemValue( + widget, + PdfFieldHelper.getHelper( + PdfFieldItemHelper.getHelper(fieldItem).field, + ).crossTable, + ); + rect = fieldItem.bounds; + } else { + value = getItemValue(widget, crossTable); + rect = checkField.bounds; + } + IPdfPrimitive? holder = PdfCrossTable.dereference( + appearance[PdfDictionaryProperties.n], + ); + PdfDictionary? normal = holder as PdfDictionary?; + if (fieldChanged == true && normal != null) { + normal = PdfDictionary(); + final PdfTemplate checkedTemplate = PdfTemplate( + rect.width, + rect.height, + ); + final PdfTemplate unchekedTemplate = PdfTemplate( + rect.width, + rect.height, + ); + drawStateItem( + checkedTemplate.graphics!, + PdfCheckFieldState.checked, + item, + fieldItem, + ); + drawStateItem( + unchekedTemplate.graphics!, + PdfCheckFieldState.unchecked, + item, + fieldItem, + ); + normal.setProperty(value, PdfReferenceHolder(checkedTemplate)); + normal.setProperty( + PdfDictionaryProperties.off, + PdfReferenceHolder(unchekedTemplate), + ); + appearance.remove(PdfDictionaryProperties.n); + appearance[PdfDictionaryProperties.n] = PdfReferenceHolder(normal); + } + holder = PdfCrossTable.dereference( + appearance[PdfDictionaryProperties.d], + ); + PdfDictionary? pressed = holder as PdfDictionary?; + if (fieldChanged == true && pressed != null) { + pressed = PdfDictionary(); + final PdfTemplate checkedTemplate = PdfTemplate( + rect.width, + rect.height, + ); + final PdfTemplate unchekedTemplate = PdfTemplate( + rect.width, + rect.height, + ); + drawStateItem( + checkedTemplate.graphics!, + PdfCheckFieldState.pressedChecked, + item, + fieldItem, + ); + drawStateItem( + unchekedTemplate.graphics!, + PdfCheckFieldState.pressedUnchecked, + item, + fieldItem, + ); + pressed.setProperty( + PdfDictionaryProperties.off, + PdfReferenceHolder(unchekedTemplate), + ); + pressed.setProperty(value, PdfReferenceHolder(checkedTemplate)); + appearance.remove(PdfDictionaryProperties.d); + appearance[PdfDictionaryProperties.d] = PdfReferenceHolder(pressed); + } + } + widget.setProperty(PdfDictionaryProperties.ap, appearance); + } else if (PdfFormHelper.getHelper( + checkField.form!, + ).setAppearanceDictionary) { + PdfFormHelper.getHelper(checkField.form!).needAppearances = true; + } else if (PdfFormHelper.getHelper(form!).setAppearanceDictionary && + !PdfFormHelper.getHelper(form!).needAppearances!) { + final PdfDictionary dic = PdfDictionary(); + final PdfTemplate template = PdfTemplate( + checkField.bounds.width, + checkField.bounds.height, + ); + drawAppearance(template); + dic.setProperty(PdfDictionaryProperties.n, PdfReferenceHolder(template)); + widget!.setProperty(PdfDictionaryProperties.ap, dic); + } + } + + PdfCheckBoxStyle _obtainStyle() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfCheckBoxStyle style = PdfCheckBoxStyle.check; + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final PdfDictionary bs = + crossTable!.getObject(widget[PdfDictionaryProperties.mk])! + as PdfDictionary; + style = _createStyle(bs); + } + return style; + } + + PdfCheckBoxStyle _createStyle(PdfDictionary bs) { + PdfCheckBoxStyle style = PdfCheckBoxStyle.check; + if (bs.containsKey(PdfDictionaryProperties.ca)) { + final PdfString? name = + crossTable!.getObject(bs[PdfDictionaryProperties.ca]) as PdfString?; + if (name != null) { + final String ch = name.value!.toLowerCase(); + switch (ch) { + case '4': + style = PdfCheckBoxStyle.check; + break; + case 'l': + style = PdfCheckBoxStyle.circle; + break; + case '8': + style = PdfCheckBoxStyle.cross; + break; + case 'u': + style = PdfCheckBoxStyle.diamond; + break; + case 'n': + style = PdfCheckBoxStyle.square; + break; + case 'h': + style = PdfCheckBoxStyle.star; + break; + } + } + } + return style; + } + + /// internal method + void assignStyle(PdfCheckBoxStyle checkStyle) { + String style = ''; + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.mk)) { + switch (checkStyle) { + case PdfCheckBoxStyle.check: + style = '4'; + break; + case PdfCheckBoxStyle.circle: + style = 'l'; + break; + case PdfCheckBoxStyle.cross: + style = '8'; + break; + case PdfCheckBoxStyle.diamond: + style = 'u'; + break; + case PdfCheckBoxStyle.square: + style = 'n'; + break; + case PdfCheckBoxStyle.star: + style = 'H'; + break; + } + if (widget[PdfDictionaryProperties.mk] is PdfReferenceHolder) { + final PdfDictionary widgetDict = + crossTable!.getObject(widget[PdfDictionaryProperties.mk])! + as PdfDictionary; + if (widgetDict.containsKey(PdfDictionaryProperties.ca)) { + widgetDict[PdfDictionaryProperties.ca] = PdfString(style); + } else { + widgetDict.setProperty(PdfDictionaryProperties.ca, PdfString(style)); + } + } else { + (widget[PdfDictionaryProperties.mk]! + as PdfDictionary)[PdfDictionaryProperties.ca] = PdfString(style); + } + WidgetAnnotationHelper.getHelper(checkField._checkBaseHelper.widget!) + .widgetAppearance! + .normalCaption = style; + } + } + + /// internal method + String styleToString(PdfCheckBoxStyle style) { + switch (style) { + case PdfCheckBoxStyle.circle: + return 'l'; + case PdfCheckBoxStyle.cross: + return '8'; + case PdfCheckBoxStyle.diamond: + return 'u'; + case PdfCheckBoxStyle.square: + return 'n'; + case PdfCheckBoxStyle.star: + return 'H'; + case PdfCheckBoxStyle.check: + return '4'; + } + } +} + +/// Represents an item of a radio button list. +class PdfRadioButtonListItem extends PdfCheckFieldBase { + //Constructor + /// Initializes a instance of the [PdfRadioButtonListItem] class with + /// the specific value and bounds. + PdfRadioButtonListItem( + String value, + Rect bounds, { + PdfCheckBoxStyle style = PdfCheckBoxStyle.circle, + PdfColor? borderColor, + PdfColor? backColor, + PdfColor? foreColor, + int? borderWidth, + PdfHighlightMode highlightMode = PdfHighlightMode.invert, + PdfBorderStyle borderStyle = PdfBorderStyle.solid, + String? tooltip, + }) { + _radioButtonListItemHelper = PdfRadioButtonListItemHelper(this); + _radioButtonListItemHelper.initialize( + null, + null, + bounds, + style: style, + borderColor: borderColor, + backColor: backColor, + foreColor: foreColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + ); + this.value = value; + _radioButtonListItemHelper.dictionary!.beginSave = + _radioButtonListItemHelper.dictionaryBeginSave; + WidgetAnnotationHelper.getHelper(_radioButtonListItemHelper.widget!) + .beginSave = _radioButtonListItemHelper._widgetSave; + style = PdfCheckBoxStyle.circle; + } + + PdfRadioButtonListItem._loaded( + PdfDictionary dictionary, + PdfCrossTable crossTable, + PdfRadioButtonListField field, + ) { + _radioButtonListItemHelper = PdfRadioButtonListItemHelper(this); + _radioButtonListItemHelper.load(dictionary, crossTable); + _radioButtonListItemHelper._field = field; + } + late PdfRadioButtonListItemHelper _radioButtonListItemHelper; + + //Properties + ///Gets or sets the value. + String get value { + if (_radioButtonListItemHelper.isLoadedField) { + _radioButtonListItemHelper._value = _radioButtonListItemHelper + .getItemValue( + _radioButtonListItemHelper.dictionary!, + _radioButtonListItemHelper.crossTable, + ); + } + return _radioButtonListItemHelper._value!; + } + + set value(String value) { + if (value.isEmpty) { + ArgumentError.value('value should not be empty'); + } + if (_radioButtonListItemHelper.isLoadedField) { + _radioButtonListItemHelper._setItemValue(value); + } + _radioButtonListItemHelper._value = value; + } + + /// Gets the form of the field.{Read-Only} + @override + PdfForm? get form => + (_radioButtonListItemHelper._field != null) + ? _radioButtonListItemHelper._field!.form + : null; + + @override + set style(PdfCheckBoxStyle value) { + if (_radioButtonListItemHelper.isLoadedField) { + _radioButtonListItemHelper.assignStyle(value); + if (PdfFormHelper.getHelper(form!).needAppearances == false) { + PdfFieldHelper.getHelper(_radioButtonListItemHelper._field!).changed = + true; + PdfFieldHelper.getHelper(_radioButtonListItemHelper._field!) + .fieldChanged = true; + } + } else { + if (super.style != value) { + super.style = value; + WidgetAnnotationHelper.getHelper( + _radioButtonListItemHelper.widget!, + ).widgetAppearance!.normalCaption = _radioButtonListItemHelper + .styleToString(super.style); + } + } + } +} + +/// [PdfRadioButtonListItem] helper +class PdfRadioButtonListItemHelper extends PdfCheckFieldBaseHelper { + /// internal constructor + PdfRadioButtonListItemHelper(this.base) : super(base); + + /// internal field + PdfRadioButtonListItem base; + String? _value = ''; + PdfRadioButtonListField? _field; + + /// internal field + String? optionValue; + + /// internal method + static PdfRadioButtonListItem loaded( + PdfDictionary dictionary, + PdfCrossTable crossTable, + PdfRadioButtonListField field, + ) { + return PdfRadioButtonListItem._loaded(dictionary, crossTable, field); + } + + /// internal method + static PdfRadioButtonListItemHelper getHelper(PdfRadioButtonListItem base) { + return base._radioButtonListItemHelper; + } + + void _widgetSave(Object sender, SavePdfPrimitiveArgs? e) { + save(); + } + + /// internal method + @override + void save() { + super.save(); + if (base.form != null) { + final String value = _obtainValue(); + widget!.extendedAppearance!.normal.onMappingName = value; + widget!.extendedAppearance!.pressed.onMappingName = value; + if (_field!.selectedItem == base) { + widget!.appearanceState = _obtainValue(); + } else { + widget!.appearanceState = PdfDictionaryProperties.off; + } + } + } + + String _obtainValue() { + String? returnValue; + if (_value!.isEmpty) { + final int index = _field!.items.indexOf(base); + returnValue = index.toString(); + } else { + returnValue = _value; + } + return PdfName.normalizeValue(returnValue)!; + } + + /// internal method + void setField(PdfRadioButtonListField? field, [bool? isItem]) { + widget!.parent = field; + final PdfPage page = (field != null) ? field.page! : _field!.page!; + if (!PdfPageHelper.getHelper(page).isLoadedPage) { + if (field == null) { + page.annotations.remove(widget!); + } else { + page.annotations.add(widget!); + } + } else if (PdfPageHelper.getHelper(page).isLoadedPage && !isItem!) { + final PdfDictionary pageDic = PdfPageHelper.getHelper(page).dictionary!; + PdfArray? annots; + if (pageDic.containsKey(PdfDictionaryProperties.annots)) { + annots = + PdfPageHelper.getHelper( + page, + ).crossTable!.getObject(pageDic[PdfDictionaryProperties.annots]) + as PdfArray?; + } else { + annots = PdfArray(); + } + final PdfReferenceHolder reference = PdfReferenceHolder(widget); + if (field == null) { + final int index = annots!.indexOf(reference); + if (index >= 0) { + annots.removeAt(index); + } + } else { + annots!.add(reference); + if (!field.page!.annotations.contains(widget!)) { + field.page!.annotations.add(widget!); + } + PdfPageHelper.getHelper( + field.page!, + ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); + } + } + if (field != null) { + _field = field; + } + } + + void _setItemValue(String value) { + final String str = value; + if (dictionary!.containsKey(PdfDictionaryProperties.ap)) { + PdfDictionary dic = + crossTable!.getObject(dictionary![PdfDictionaryProperties.ap])! + as PdfDictionary; + if (dic.containsKey(PdfDictionaryProperties.n)) { + final PdfReference normal = crossTable!.getReference( + dic[PdfDictionaryProperties.n], + ); + dic = crossTable!.getObject(normal)! as PdfDictionary; + final String? dicValue = getItemValue(dictionary!, crossTable); + if (dic.containsKey(dicValue)) { + final PdfReference valRef = crossTable!.getReference(dic[dicValue]); + dic.remove(base.value); + dic.setProperty( + str, + PdfReferenceHolder.fromReference(valRef, crossTable), + ); + } + } + } + if (str == _field!.selectedValue) { + dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + str, + ); + } else { + dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + PdfDictionaryProperties.off, + ); + } + } + + /// internal method + @override + void draw() { + removeAnnotationFromPage(_field!.page); + final PaintParams params = PaintParams( + bounds: base.bounds, + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: base.borderStyle, + borderWidth: base.borderWidth, + shadowBrush: shadowBrush, + ); + if (params.borderPen != null && params.borderWidth == 0) { + params.borderWidth = 1; + } + PdfCheckFieldState state = PdfCheckFieldState.unchecked; + if ((_field!.selectedIndex >= 0) && (_field!.selectedValue == base.value)) { + state = PdfCheckFieldState.checked; + } + FieldPainter().drawRadioButton( + _field!.page!.graphics, + params, + styleToString(base.style), + state, + ); + } + + /// internal method + @override + Rect getBounds() { + IPdfPrimitive? array; + if (dictionary!.containsKey(PdfDictionaryProperties.rect)) { + array = crossTable!.getObject(dictionary![PdfDictionaryProperties.rect]); + } + Rect bounds; + if (array != null && array is PdfArray) { + bounds = array.toRectangle().rect; + double? y = 0; + if ((PdfCrossTable.dereference(array[1])! as PdfNumber).value! < 0) { + y = + (PdfCrossTable.dereference(array[1])! as PdfNumber).value + as double?; + if ((PdfCrossTable.dereference(array[1])! as PdfNumber).value! > + (PdfCrossTable.dereference(array[3])! as PdfNumber).value!) { + y = y! - bounds.height; + } + } + bounds = Rect.fromLTWH( + bounds.left, + y! <= 0 ? bounds.top : y, + bounds.width, + bounds.height, + ); + } else { + bounds = Rect.zero; + } + return bounds; + } + + /// internal method + void drawCheckAppearance() { + final PaintParams paintParams = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + widget!.bounds.size.width, + widget!.bounds.size.height, + ), + backBrush: PdfSolidBrush(base.backColor), + foreBrush: PdfSolidBrush(base.foreColor), + borderPen: borderPen, + style: base.borderStyle, + borderWidth: base.borderWidth, + shadowBrush: PdfSolidBrush(base.backColor), + ); + + PdfTemplate template = widget!.extendedAppearance!.normal.activate!; + FieldPainter().drawRadioButton( + template.graphics, + paintParams, + styleToString(base.style), + PdfCheckFieldState.checked, + ); + + template = widget!.extendedAppearance!.normal.off!; + FieldPainter().drawRadioButton( + template.graphics, + paintParams, + styleToString(base.style), + PdfCheckFieldState.unchecked, + ); + + template = widget!.extendedAppearance!.pressed.activate!; + FieldPainter().drawRadioButton( + template.graphics, + paintParams, + styleToString(base.style), + PdfCheckFieldState.pressedChecked, + ); + + template = widget!.extendedAppearance!.pressed.off!; + FieldPainter().drawRadioButton( + template.graphics, + paintParams, + styleToString(base.style), + PdfCheckFieldState.pressedUnchecked, + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_combo_box_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_combo_box_field.dart index 183ce06bf..f53b245e2 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_combo_box_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_combo_box_field.dart @@ -1,486 +1,486 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/pdf_annotation.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_field.dart'; -import 'pdf_field_painter.dart'; -import 'pdf_form.dart'; -import 'pdf_list_field.dart'; -import 'pdf_list_field_item.dart'; - -/// Represents combo box field in the PDF Form. -class PdfComboBoxField extends PdfListField { - /// Initializes a new instance of the [PdfComboBoxField] class with - /// the specific page, name and bounds. - PdfComboBoxField( - PdfPage page, - String name, - Rect bounds, { - List? items, - bool editable = false, - int? selectedIndex, - String? selectedValue, - PdfFont? font, - PdfTextAlignment alignment = PdfTextAlignment.left, - PdfColor? borderColor, - PdfColor? foreColor, - PdfColor? backColor, - int? borderWidth, - PdfHighlightMode highlightMode = PdfHighlightMode.invert, - PdfBorderStyle borderStyle = PdfBorderStyle.solid, - String? tooltip, - }) { - _helper = PdfComboBoxFieldHelper(this); - _helper.initializeInternal( - page, - name, - bounds, - font: font, - alignment: alignment, - items: items, - borderColor: borderColor, - foreColor: foreColor, - backColor: backColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - ); - _helper.flags.add(FieldFlags.combo); - this.editable = editable; - if (selectedIndex != null) { - this.selectedIndex = selectedIndex; - } - if (selectedValue != null) { - this.selectedValue = selectedValue; - } - } - - /// Initializes a new instance of the [PdfComboBoxField] class. - PdfComboBoxField._load(PdfDictionary dictionary, PdfCrossTable crossTable) { - _helper = PdfComboBoxFieldHelper(this); - _helper.loadListField(dictionary, crossTable); - } - - //Fields - late PdfComboBoxFieldHelper _helper; - bool _editable = false; - - //Properties - /// Gets or sets a value indicating whether this [PdfComboBoxField] is editable. - /// - /// The default value is false. - bool get editable { - if (_helper.isLoadedField) { - _editable = - _helper.isFlagPresent(FieldFlags.edit) || - _helper.flags.contains(FieldFlags.edit); - } - return _editable; - } - - set editable(bool value) { - if (_editable != value || _helper.isLoadedField) { - _editable = value; - _editable - ? _helper.flags.add(FieldFlags.edit) - : _helper.isLoadedField - ? _helper.removeFlag(FieldFlags.edit) - : _helper.flags.remove(FieldFlags.edit); - } - } - - /// Gets or sets the selected index in the list. - int get selectedIndex => - _helper.selectedIndexes.isEmpty ? -1 : _helper.selectedIndexes[0]; - set selectedIndex(int value) { - _helper.selectedIndexes = [value]; - } - - /// Gets or sets the selected value in the list. - String get selectedValue => - _helper.selectedValues.isEmpty ? '' : _helper.selectedValues[0]; - set selectedValue(String value) { - _helper.selectedValues = [value]; - } - - /// Gets the selected item in the list. - PdfListFieldItem? get selectedItem => - _helper.selectedItems.count > 0 ? _helper.selectedItems[0] : null; -} - -/// [PdfComboBoxField] helper -class PdfComboBoxFieldHelper extends PdfListFieldHelper { - /// internal constructor - PdfComboBoxFieldHelper(this.comboBoxField) : super(comboBoxField); - - /// internal field - PdfComboBoxField comboBoxField; - - /// internal method - static PdfComboBoxField loadComboBox( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfComboBoxField._load(dictionary, crossTable); - } - - /// internal method - static PdfComboBoxFieldHelper getHelper(PdfComboBoxField comboBoxField) { - return comboBoxField._helper; - } - - /// internal method - @override - void drawAppearance(PdfTemplate template) { - super.drawAppearance(template); - final PaintParams params = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - comboBoxField.bounds.width, - comboBoxField.bounds.height, - ), - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: comboBoxField.borderStyle, - borderWidth: comboBoxField.borderWidth, - shadowBrush: shadowBrush, - ); - FieldPainter().drawRectangularControl(template.graphics!, params); - if (comboBoxField.selectedIndex != -1 && - comboBoxField.items[comboBoxField.selectedIndex].text != '' && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(comboBoxField.page!).document!, - ).conformanceLevel == - PdfConformanceLevel.none) { - final int multiplier = - params.style == PdfBorderStyle.beveled || - params.style == PdfBorderStyle.inset - ? 2 - : 1; - final Rect rectangle = Rect.fromLTWH( - params.bounds!.left + (2 * multiplier) * params.borderWidth!, - params.bounds!.top + (2 * multiplier) * params.borderWidth!, - params.bounds!.width - (4 * multiplier) * params.borderWidth!, - params.bounds!.height - (4 * multiplier) * params.borderWidth!, - ); - template.graphics!.drawString( - comboBoxField.items[comboBoxField.selectedIndex].text, - comboBoxField.font ?? PdfStandardFont(PdfFontFamily.timesRoman, 12), - brush: params.foreBrush, - bounds: rectangle, - format: format, - ); - } - } - - /// internal method - @override - void beginSave() { - super.beginSave(); - _applyAppearance(getWidgetAnnotation(dictionary!, crossTable)); - } - - void _applyAppearance(PdfDictionary widget) { - if (widget.containsKey(PdfDictionaryProperties.ap) && - !PdfFormHelper.getHelper(comboBoxField.form!).needAppearances!) { - final IPdfPrimitive? appearance = crossTable!.getObject( - widget[PdfDictionaryProperties.ap], - ); - if ((appearance != null) && - appearance is PdfDictionary && - (appearance.containsKey(PdfDictionaryProperties.n))) { - final PdfTemplate template = PdfTemplate( - comboBoxField.bounds.width, - comboBoxField.bounds.height, - ); - _drawComboBox(template.graphics); - appearance.remove(PdfDictionaryProperties.n); - appearance.setProperty( - PdfDictionaryProperties.n, - PdfReferenceHolder(template), - ); - widget.setProperty(PdfDictionaryProperties.ap, appearance); - } - } else if (comboBoxField.form!.readOnly == true || - comboBoxField.readOnly == true) { - PdfFormHelper.getHelper(comboBoxField.form!).setAppearanceDictionary = - true; - } else if (PdfFormHelper.getHelper( - comboBoxField.form!, - ).setAppearanceDictionary && - !PdfFormHelper.getHelper(comboBoxField.form!).needAppearances!) { - final PdfDictionary dic = PdfDictionary(); - final PdfTemplate template = PdfTemplate( - comboBoxField.bounds.width, - comboBoxField.bounds.height, - ); - drawAppearance(template); - dic.setProperty(PdfDictionaryProperties.n, PdfReferenceHolder(template)); - widget.setProperty(PdfDictionaryProperties.ap, dic); - } - } - - /// internal method - @override - void draw() { - super.draw(); - if (!isLoadedField && - PdfAnnotationHelper.getHelper(widget!).appearance != null) { - comboBoxField.page!.graphics.drawPdfTemplate( - widget!.appearance.normal, - comboBoxField.bounds.topLeft, - ); - } else { - final Rect rect = Rect.fromLTWH( - 0, - 0, - comboBoxField.bounds.width, - comboBoxField.bounds.height, - ); - final PdfFont font = - comboBoxField.font ?? - PdfStandardFont( - PdfFontFamily.helvetica, - getFontHeight(PdfFontFamily.helvetica), - ); - final PaintParams parameters = PaintParams( - bounds: rect, - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: comboBoxField.borderStyle, - borderWidth: comboBoxField.borderWidth, - shadowBrush: shadowBrush, - ); - final PdfTemplate template = PdfTemplate(rect.width, rect.height); - String? text = ''; - if (comboBoxField.selectedIndex != -1) { - text = comboBoxField.selectedItem!.text; - } else if (isLoadedField) { - if (comboBoxField.selectedIndex == -1 && - dictionary!.containsKey(PdfDictionaryProperties.v) && - dictionary!.containsKey(PdfDictionaryProperties.ap) && - !dictionary!.containsKey(PdfDictionaryProperties.parent)) { - final IPdfPrimitive? value = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.v], - ); - if (value != null && value is PdfString) { - text = value.value; - } - } else if (dictionary!.containsKey(PdfDictionaryProperties.dv)) { - if (dictionary![PdfDictionaryProperties.dv] is PdfString) { - text = - (dictionary![PdfDictionaryProperties.dv]! as PdfString).value; - } else { - final IPdfPrimitive? str = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.dv], - ); - if (str != null && str is PdfString) { - text = str.value; - } - } - } - } - if (!isLoadedField) { - FieldPainter().drawRectangularControl(template.graphics!, parameters); - final double borderWidth = parameters.borderWidth!.toDouble(); - final double doubleBorderWidth = 2 * borderWidth; - final bool padding = - parameters.style == PdfBorderStyle.inset || - parameters.style == PdfBorderStyle.beveled; - final Offset point = - padding - ? Offset(2 * doubleBorderWidth, 2 * borderWidth) - : Offset(doubleBorderWidth, borderWidth); - final double width = parameters.bounds!.width - doubleBorderWidth; - final Rect itemTextBound = Rect.fromLTWH( - point.dx, - point.dy, - width - point.dx, - parameters.bounds!.height - - (padding ? doubleBorderWidth : borderWidth), - ); - template.graphics!.drawString( - text!, - font, - brush: foreBrush, - bounds: itemTextBound, - format: format, - ); - comboBoxField.page!.graphics.drawPdfTemplate( - template, - comboBoxField.bounds.topLeft, - rect.size, - ); - } else { - final GraphicsProperties gp = GraphicsProperties(comboBoxField); - final PaintParams prms = PaintParams( - bounds: gp.bounds, - backBrush: gp.backBrush, - foreBrush: gp.foreBrush, - borderPen: gp.borderPen, - style: gp.style, - borderWidth: gp.borderWidth, - shadowBrush: gp.shadowBrush, - ); - if (gp.font!.height > comboBoxField.bounds.height) { - setFittingFontSize(gp, prms, text!); - } - FieldPainter().drawComboBox( - comboBoxField.page!.graphics, - prms, - text, - gp.font, - gp.stringFormat, - ); - } - } - } - - void _drawComboBox(PdfGraphics? graphics) { - final GraphicsProperties gp = GraphicsProperties(comboBoxField); - gp.bounds = Rect.fromLTWH( - 0, - 0, - comboBoxField.bounds.width, - comboBoxField.bounds.height, - ); - final PaintParams prms = PaintParams( - bounds: gp.bounds, - backBrush: gp.backBrush, - foreBrush: gp.foreBrush, - borderPen: gp.borderPen, - style: gp.style, - borderWidth: gp.borderWidth, - shadowBrush: gp.shadowBrush, - ); - String? text; - if (selectedItems.count > 0 && - comboBoxField.selectedIndex != -1 && - !flattenField) { - text = selectedItems[0].text; - } else if (dictionary!.containsKey(PdfDictionaryProperties.dv) && - !flattenField) { - final IPdfPrimitive? defaultValue = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.dv], - ); - if (defaultValue != null && defaultValue is PdfString) { - text = defaultValue.value; - } - } - if (selectedItems.count == 0) { - FieldPainter().drawComboBox( - graphics!, - prms, - comboBoxField.selectedValue, - gp.font, - gp.stringFormat, - ); - } else if (text != null && !flattenField) { - FieldPainter().drawComboBox( - graphics!, - prms, - text, - gp.font, - gp.stringFormat, - ); - } else { - FieldPainter().drawRectangularControl(graphics!, prms); - } - } - - /// internal method - @override - double getFontHeight(PdfFontFamily family) { - double fontSize = 0; - final List widths = []; - if (comboBoxField.selectedIndex != -1) { - final PdfFont itemFont = PdfStandardFont(family, 12); - widths.add( - itemFont.measureString(comboBoxField.selectedItem!.text).width, - ); - } else { - final PdfFont sfont = PdfStandardFont(family, 12); - double max = sfont.measureString(comboBoxField.items[0].text).width; - for (int i = 1; i < comboBoxField.items.count; ++i) { - final double value = - sfont.measureString(comboBoxField.items[i].text).width; - max = (max > value) ? max : value; - widths.add(max); - } - } - widths.sort(); - double s = - widths.isNotEmpty - ? ((12 * - (comboBoxField.bounds.size.width - - 4 * comboBoxField.borderWidth)) / - widths[widths.length - 1]) - : 12; - if (comboBoxField.selectedIndex != -1) { - final PdfFont font = PdfStandardFont(family, s); - final String text = comboBoxField.selectedValue; - final Size textSize = font.measureString(text); - if (textSize.width > comboBoxField.bounds.width || - textSize.height > comboBoxField.bounds.height) { - final double width = - comboBoxField.bounds.width - 4 * comboBoxField.borderWidth; - final double h = - comboBoxField.bounds.height - 4 * comboBoxField.borderWidth; - const double minimumFontSize = 0.248; - for (double i = 1; i <= comboBoxField.bounds.height; i++) { - PdfFontHelper.getHelper(font).setSize(i); - Size textSize = font.measureString(text); - if (textSize.width > comboBoxField.bounds.width || - textSize.height > h) { - fontSize = i; - do { - fontSize = fontSize - 0.001; - PdfFontHelper.getHelper(font).setSize(fontSize); - final double textWidth = PdfFontHelper.getLineWidth( - font, - text, - format, - ); - if (fontSize < minimumFontSize) { - PdfFontHelper.getHelper(font).setSize(minimumFontSize); - break; - } - textSize = font.measureString(text, format: format); - if (textWidth < width && textSize.height < h) { - PdfFontHelper.getHelper(font).setSize(fontSize); - break; - } - } while (fontSize > minimumFontSize); - s = fontSize; - break; - } - } - } - } else if (s > 12) { - s = 12; - } - return s; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/pdf_annotation.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_field.dart'; +import 'pdf_field_painter.dart'; +import 'pdf_form.dart'; +import 'pdf_list_field.dart'; +import 'pdf_list_field_item.dart'; + +/// Represents combo box field in the PDF Form. +class PdfComboBoxField extends PdfListField { + /// Initializes a new instance of the [PdfComboBoxField] class with + /// the specific page, name and bounds. + PdfComboBoxField( + PdfPage page, + String name, + Rect bounds, { + List? items, + bool editable = false, + int? selectedIndex, + String? selectedValue, + PdfFont? font, + PdfTextAlignment alignment = PdfTextAlignment.left, + PdfColor? borderColor, + PdfColor? foreColor, + PdfColor? backColor, + int? borderWidth, + PdfHighlightMode highlightMode = PdfHighlightMode.invert, + PdfBorderStyle borderStyle = PdfBorderStyle.solid, + String? tooltip, + }) { + _helper = PdfComboBoxFieldHelper(this); + _helper.initializeInternal( + page, + name, + bounds, + font: font, + alignment: alignment, + items: items, + borderColor: borderColor, + foreColor: foreColor, + backColor: backColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + ); + _helper.flags.add(FieldFlags.combo); + this.editable = editable; + if (selectedIndex != null) { + this.selectedIndex = selectedIndex; + } + if (selectedValue != null) { + this.selectedValue = selectedValue; + } + } + + /// Initializes a new instance of the [PdfComboBoxField] class. + PdfComboBoxField._load(PdfDictionary dictionary, PdfCrossTable crossTable) { + _helper = PdfComboBoxFieldHelper(this); + _helper.loadListField(dictionary, crossTable); + } + + //Fields + late PdfComboBoxFieldHelper _helper; + bool _editable = false; + + //Properties + /// Gets or sets a value indicating whether this [PdfComboBoxField] is editable. + /// + /// The default value is false. + bool get editable { + if (_helper.isLoadedField) { + _editable = + _helper.isFlagPresent(FieldFlags.edit) || + _helper.flags.contains(FieldFlags.edit); + } + return _editable; + } + + set editable(bool value) { + if (_editable != value || _helper.isLoadedField) { + _editable = value; + _editable + ? _helper.flags.add(FieldFlags.edit) + : _helper.isLoadedField + ? _helper.removeFlag(FieldFlags.edit) + : _helper.flags.remove(FieldFlags.edit); + } + } + + /// Gets or sets the selected index in the list. + int get selectedIndex => + _helper.selectedIndexes.isEmpty ? -1 : _helper.selectedIndexes[0]; + set selectedIndex(int value) { + _helper.selectedIndexes = [value]; + } + + /// Gets or sets the selected value in the list. + String get selectedValue => + _helper.selectedValues.isEmpty ? '' : _helper.selectedValues[0]; + set selectedValue(String value) { + _helper.selectedValues = [value]; + } + + /// Gets the selected item in the list. + PdfListFieldItem? get selectedItem => + _helper.selectedItems.count > 0 ? _helper.selectedItems[0] : null; +} + +/// [PdfComboBoxField] helper +class PdfComboBoxFieldHelper extends PdfListFieldHelper { + /// internal constructor + PdfComboBoxFieldHelper(this.comboBoxField) : super(comboBoxField); + + /// internal field + PdfComboBoxField comboBoxField; + + /// internal method + static PdfComboBoxField loadComboBox( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfComboBoxField._load(dictionary, crossTable); + } + + /// internal method + static PdfComboBoxFieldHelper getHelper(PdfComboBoxField comboBoxField) { + return comboBoxField._helper; + } + + /// internal method + @override + void drawAppearance(PdfTemplate template) { + super.drawAppearance(template); + final PaintParams params = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + comboBoxField.bounds.width, + comboBoxField.bounds.height, + ), + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: comboBoxField.borderStyle, + borderWidth: comboBoxField.borderWidth, + shadowBrush: shadowBrush, + ); + FieldPainter().drawRectangularControl(template.graphics!, params); + if (comboBoxField.selectedIndex != -1 && + comboBoxField.items[comboBoxField.selectedIndex].text != '' && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(comboBoxField.page!).document!, + ).conformanceLevel == + PdfConformanceLevel.none) { + final int multiplier = + params.style == PdfBorderStyle.beveled || + params.style == PdfBorderStyle.inset + ? 2 + : 1; + final Rect rectangle = Rect.fromLTWH( + params.bounds!.left + (2 * multiplier) * params.borderWidth!, + params.bounds!.top + (2 * multiplier) * params.borderWidth!, + params.bounds!.width - (4 * multiplier) * params.borderWidth!, + params.bounds!.height - (4 * multiplier) * params.borderWidth!, + ); + template.graphics!.drawString( + comboBoxField.items[comboBoxField.selectedIndex].text, + comboBoxField.font ?? PdfStandardFont(PdfFontFamily.timesRoman, 12), + brush: params.foreBrush, + bounds: rectangle, + format: format, + ); + } + } + + /// internal method + @override + void beginSave() { + super.beginSave(); + _applyAppearance(getWidgetAnnotation(dictionary!, crossTable)); + } + + void _applyAppearance(PdfDictionary widget) { + if (widget.containsKey(PdfDictionaryProperties.ap) && + !PdfFormHelper.getHelper(comboBoxField.form!).needAppearances!) { + final IPdfPrimitive? appearance = crossTable!.getObject( + widget[PdfDictionaryProperties.ap], + ); + if ((appearance != null) && + appearance is PdfDictionary && + (appearance.containsKey(PdfDictionaryProperties.n))) { + final PdfTemplate template = PdfTemplate( + comboBoxField.bounds.width, + comboBoxField.bounds.height, + ); + _drawComboBox(template.graphics); + appearance.remove(PdfDictionaryProperties.n); + appearance.setProperty( + PdfDictionaryProperties.n, + PdfReferenceHolder(template), + ); + widget.setProperty(PdfDictionaryProperties.ap, appearance); + } + } else if (comboBoxField.form!.readOnly == true || + comboBoxField.readOnly == true) { + PdfFormHelper.getHelper(comboBoxField.form!).setAppearanceDictionary = + true; + } else if (PdfFormHelper.getHelper( + comboBoxField.form!, + ).setAppearanceDictionary && + !PdfFormHelper.getHelper(comboBoxField.form!).needAppearances!) { + final PdfDictionary dic = PdfDictionary(); + final PdfTemplate template = PdfTemplate( + comboBoxField.bounds.width, + comboBoxField.bounds.height, + ); + drawAppearance(template); + dic.setProperty(PdfDictionaryProperties.n, PdfReferenceHolder(template)); + widget.setProperty(PdfDictionaryProperties.ap, dic); + } + } + + /// internal method + @override + void draw() { + super.draw(); + if (!isLoadedField && + PdfAnnotationHelper.getHelper(widget!).appearance != null) { + comboBoxField.page!.graphics.drawPdfTemplate( + widget!.appearance.normal, + comboBoxField.bounds.topLeft, + ); + } else { + final Rect rect = Rect.fromLTWH( + 0, + 0, + comboBoxField.bounds.width, + comboBoxField.bounds.height, + ); + final PdfFont font = + comboBoxField.font ?? + PdfStandardFont( + PdfFontFamily.helvetica, + getFontHeight(PdfFontFamily.helvetica), + ); + final PaintParams parameters = PaintParams( + bounds: rect, + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: comboBoxField.borderStyle, + borderWidth: comboBoxField.borderWidth, + shadowBrush: shadowBrush, + ); + final PdfTemplate template = PdfTemplate(rect.width, rect.height); + String? text = ''; + if (comboBoxField.selectedIndex != -1) { + text = comboBoxField.selectedItem!.text; + } else if (isLoadedField) { + if (comboBoxField.selectedIndex == -1 && + dictionary!.containsKey(PdfDictionaryProperties.v) && + dictionary!.containsKey(PdfDictionaryProperties.ap) && + !dictionary!.containsKey(PdfDictionaryProperties.parent)) { + final IPdfPrimitive? value = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.v], + ); + if (value != null && value is PdfString) { + text = value.value; + } + } else if (dictionary!.containsKey(PdfDictionaryProperties.dv)) { + if (dictionary![PdfDictionaryProperties.dv] is PdfString) { + text = + (dictionary![PdfDictionaryProperties.dv]! as PdfString).value; + } else { + final IPdfPrimitive? str = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.dv], + ); + if (str != null && str is PdfString) { + text = str.value; + } + } + } + } + if (!isLoadedField) { + FieldPainter().drawRectangularControl(template.graphics!, parameters); + final double borderWidth = parameters.borderWidth!.toDouble(); + final double doubleBorderWidth = 2 * borderWidth; + final bool padding = + parameters.style == PdfBorderStyle.inset || + parameters.style == PdfBorderStyle.beveled; + final Offset point = + padding + ? Offset(2 * doubleBorderWidth, 2 * borderWidth) + : Offset(doubleBorderWidth, borderWidth); + final double width = parameters.bounds!.width - doubleBorderWidth; + final Rect itemTextBound = Rect.fromLTWH( + point.dx, + point.dy, + width - point.dx, + parameters.bounds!.height - + (padding ? doubleBorderWidth : borderWidth), + ); + template.graphics!.drawString( + text!, + font, + brush: foreBrush, + bounds: itemTextBound, + format: format, + ); + comboBoxField.page!.graphics.drawPdfTemplate( + template, + comboBoxField.bounds.topLeft, + rect.size, + ); + } else { + final GraphicsProperties gp = GraphicsProperties(comboBoxField); + final PaintParams prms = PaintParams( + bounds: gp.bounds, + backBrush: gp.backBrush, + foreBrush: gp.foreBrush, + borderPen: gp.borderPen, + style: gp.style, + borderWidth: gp.borderWidth, + shadowBrush: gp.shadowBrush, + ); + if (gp.font!.height > comboBoxField.bounds.height) { + setFittingFontSize(gp, prms, text!); + } + FieldPainter().drawComboBox( + comboBoxField.page!.graphics, + prms, + text, + gp.font, + gp.stringFormat, + ); + } + } + } + + void _drawComboBox(PdfGraphics? graphics) { + final GraphicsProperties gp = GraphicsProperties(comboBoxField); + gp.bounds = Rect.fromLTWH( + 0, + 0, + comboBoxField.bounds.width, + comboBoxField.bounds.height, + ); + final PaintParams prms = PaintParams( + bounds: gp.bounds, + backBrush: gp.backBrush, + foreBrush: gp.foreBrush, + borderPen: gp.borderPen, + style: gp.style, + borderWidth: gp.borderWidth, + shadowBrush: gp.shadowBrush, + ); + String? text; + if (selectedItems.count > 0 && + comboBoxField.selectedIndex != -1 && + !flattenField) { + text = selectedItems[0].text; + } else if (dictionary!.containsKey(PdfDictionaryProperties.dv) && + !flattenField) { + final IPdfPrimitive? defaultValue = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.dv], + ); + if (defaultValue != null && defaultValue is PdfString) { + text = defaultValue.value; + } + } + if (selectedItems.count == 0) { + FieldPainter().drawComboBox( + graphics!, + prms, + comboBoxField.selectedValue, + gp.font, + gp.stringFormat, + ); + } else if (text != null && !flattenField) { + FieldPainter().drawComboBox( + graphics!, + prms, + text, + gp.font, + gp.stringFormat, + ); + } else { + FieldPainter().drawRectangularControl(graphics!, prms); + } + } + + /// internal method + @override + double getFontHeight(PdfFontFamily family) { + double fontSize = 0; + final List widths = []; + if (comboBoxField.selectedIndex != -1) { + final PdfFont itemFont = PdfStandardFont(family, 12); + widths.add( + itemFont.measureString(comboBoxField.selectedItem!.text).width, + ); + } else { + final PdfFont sfont = PdfStandardFont(family, 12); + double max = sfont.measureString(comboBoxField.items[0].text).width; + for (int i = 1; i < comboBoxField.items.count; ++i) { + final double value = + sfont.measureString(comboBoxField.items[i].text).width; + max = (max > value) ? max : value; + widths.add(max); + } + } + widths.sort(); + double s = + widths.isNotEmpty + ? ((12 * + (comboBoxField.bounds.size.width - + 4 * comboBoxField.borderWidth)) / + widths[widths.length - 1]) + : 12; + if (comboBoxField.selectedIndex != -1) { + final PdfFont font = PdfStandardFont(family, s); + final String text = comboBoxField.selectedValue; + final Size textSize = font.measureString(text); + if (textSize.width > comboBoxField.bounds.width || + textSize.height > comboBoxField.bounds.height) { + final double width = + comboBoxField.bounds.width - 4 * comboBoxField.borderWidth; + final double h = + comboBoxField.bounds.height - 4 * comboBoxField.borderWidth; + const double minimumFontSize = 0.248; + for (double i = 1; i <= comboBoxField.bounds.height; i++) { + PdfFontHelper.getHelper(font).setSize(i); + Size textSize = font.measureString(text); + if (textSize.width > comboBoxField.bounds.width || + textSize.height > h) { + fontSize = i; + do { + fontSize = fontSize - 0.001; + PdfFontHelper.getHelper(font).setSize(fontSize); + final double textWidth = PdfFontHelper.getLineWidth( + font, + text, + format, + ); + if (fontSize < minimumFontSize) { + PdfFontHelper.getHelper(font).setSize(minimumFontSize); + break; + } + textSize = font.measureString(text, format: format); + if (textWidth < width && textSize.height < h) { + PdfFontHelper.getHelper(font).setSize(fontSize); + break; + } + } while (fontSize > minimumFontSize); + s = fontSize; + break; + } + } + } + } else if (s > 12) { + s = 12; + } + return s; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field.dart index 2a1a8b9a6..51c017c01 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field.dart @@ -1,3571 +1,3571 @@ -import 'dart:convert'; -import 'dart:ui'; -import 'package:xml/xml.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/json_parser.dart'; -import '../annotations/pdf_annotation.dart'; -import '../annotations/pdf_annotation_border.dart'; -import '../annotations/pdf_annotation_collection.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../annotations/widget_annotation.dart'; -import '../general/pdf_collection.dart'; -import '../general/pdf_default_appearance.dart'; -import '../graphics/brushes/pdf_brush.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_cjk_standard_font.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_font_metrics.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/fonts/pdf_string_format.dart'; -import '../graphics/fonts/pdf_true_type_font.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_reader.dart'; -import '../pages/enum.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_collection.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import '../security/enum.dart'; -import '../security/pdf_security.dart'; -import 'enum.dart'; -import 'pdf_check_box_field.dart'; -import 'pdf_combo_box_field.dart'; -import 'pdf_field_item.dart'; -import 'pdf_field_painter.dart'; -import 'pdf_form.dart'; -import 'pdf_list_box_field.dart'; -import 'pdf_radio_button_list_field.dart'; -import 'pdf_signature_field.dart'; -import 'pdf_text_box_field.dart'; - -/// Represents field of the PDF document's interactive form. -abstract class PdfField implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfField] class with the specific page and name. - void _internal( - PdfPage? page, - String? name, - Rect bounds, { - PdfFont? font, - PdfTextAlignment? alignment, - PdfColor? borderColor, - PdfColor? foreColor, - PdfColor? backColor, - int? borderWidth, - PdfHighlightMode? highlightMode, - PdfBorderStyle? borderStyle, - String? tooltip, - PdfFieldHelper? helper, - }) { - _fieldHelper = helper!; - if (this is PdfSignatureField) { - if (page != null && PdfPageHelper.getHelper(page).document != null) { - _fieldHelper.form = PdfPageHelper.getHelper(page).document!.form; - } - } - _initialize(); - if (page != null) { - _fieldHelper.page = page; - } - this.bounds = bounds; - if (name != null) { - _fieldHelper.name = name; - _fieldHelper.dictionary!.setProperty( - PdfDictionaryProperties.t, - PdfString(name), - ); - } - if (font != null) { - _fieldHelper.font = font; - } - if (alignment != null) { - _fieldHelper.textAlignment = alignment; - } - if (borderColor != null) { - _fieldHelper.borderColor = borderColor; - } - if (foreColor != null) { - _fieldHelper.foreColor = foreColor; - } - if (backColor != null) { - _fieldHelper.backColor = backColor; - } - if (borderWidth != null) { - _fieldHelper.borderWidth = borderWidth; - } - if (highlightMode != null) { - _fieldHelper.highlightMode = highlightMode; - } - if (borderStyle != null) { - _fieldHelper.borderStyle = borderStyle; - } - if (tooltip != null) { - this.tooltip = tooltip; - } - if (this is PdfSignatureField) { - _addAnnotationToPage(page, _fieldHelper.widget); - } - } - - /// internal constructor - void _load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - PdfFieldHelper helper, - ) { - _fieldHelper = helper; - _fieldHelper.dictionary = dictionary; - _fieldHelper.crossTable = crossTable; - _fieldHelper.widget = WidgetAnnotation(); - _fieldHelper.isLoadedField = true; - } - - //Fields - late PdfFieldHelper _fieldHelper; - String? _mappingName = ''; - String? _tooltip = ''; - int _tabIndex = 0; - bool _export = false; - - //Properties - /// Gets the form of the [PdfField]. - PdfForm? get form => _fieldHelper.form; - - /// Gets the page of the field. - PdfPage? get page { - if (_fieldHelper.isLoadedField && _fieldHelper.page == null) { - _fieldHelper.page = _getLoadedPage(); - } else if (_fieldHelper.page != null && - PdfPageHelper.getHelper(_fieldHelper.page!).isLoadedPage && - _fieldHelper.changed || - (_fieldHelper.form != null && - PdfFormHelper.getHelper(_fieldHelper.form!).flatten) || - _fieldHelper.flattenField) { - _fieldHelper.page = _getLoadedPage(); - } - return _fieldHelper.page; - } - - /// Gets or sets the name of the [PdfField]. - String? get name { - if (_fieldHelper.isLoadedField && - (_fieldHelper.name == null || _fieldHelper.name!.isEmpty)) { - _fieldHelper.name = _getFieldName(); - } - return _fieldHelper.name; - } - - set name(String? value) => _fieldHelper._setName(value); - - /// Gets or sets a value indicating whether this [PdfField] field is read-only. - /// - /// The default value is false. - bool get readOnly { - if (_fieldHelper.isLoadedField) { - _fieldHelper._readOnly = _fieldHelper.isFlagPresent(FieldFlags.readOnly); - return _fieldHelper._readOnly || form!.readOnly; - } - return _fieldHelper._readOnly; - } - - set readOnly(bool value) { - if (_fieldHelper.isLoadedField) { - value || form!.readOnly - ? _fieldHelper.setFlags([FieldFlags.readOnly]) - : _fieldHelper.removeFlag(FieldFlags.readOnly); - } - _fieldHelper._readOnly = value; - } - - /// Gets or sets the mapping name to be used when exporting interactive form - /// field data from the document. - String get mappingName { - if (_fieldHelper.isLoadedField && - (_mappingName == null || _mappingName!.isEmpty)) { - final IPdfPrimitive? str = PdfFieldHelper.getValue( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - PdfDictionaryProperties.tm, - false, - ); - if (str != null && str is PdfString) { - _mappingName = str.value; - } - } - return _mappingName!; - } - - set mappingName(String value) { - if (_mappingName != value) { - _mappingName = value; - _fieldHelper.dictionary!.setString( - PdfDictionaryProperties.tm, - _mappingName, - ); - } - if (_fieldHelper.isLoadedField) { - _fieldHelper.changed = true; - } - } - - /// Gets or sets the tool tip. - String get tooltip { - if (_fieldHelper.isLoadedField && (_tooltip == null || _tooltip!.isEmpty)) { - final IPdfPrimitive? str = PdfFieldHelper.getValue( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - PdfDictionaryProperties.tu, - false, - ); - if (str != null && str is PdfString) { - _tooltip = str.value; - } - } - return _tooltip!; - } - - set tooltip(String value) { - if (_tooltip != value) { - _tooltip = value; - _fieldHelper.dictionary!.setString(PdfDictionaryProperties.tu, _tooltip); - } - if (_fieldHelper.isLoadedField) { - _fieldHelper.changed = true; - } - } - - /// Gets or sets a value indicating whether the [PdfField] is exportable or not. - /// - /// The default value is true. - bool get canExport { - if (_fieldHelper.isLoadedField) { - _export = - !(_fieldHelper.isFlagPresent(FieldFlags.noExport) || - _fieldHelper.flags.contains(FieldFlags.noExport)); - } - return _export; - } - - set canExport(bool value) { - if (canExport != value) { - _export = value; - _export - ? _fieldHelper.isLoadedField - ? _fieldHelper.removeFlag(FieldFlags.noExport) - : _fieldHelper.flags.remove(FieldFlags.noExport) - : _fieldHelper.flags.add(FieldFlags.noExport); - } - } - - /// Gets or sets the bounds. - Rect get bounds { - if (_fieldHelper.isLoadedField) { - final Rect rect = _fieldHelper.getBounds(); - double x = 0; - double y = 0; - if (page != null) { - final PdfDictionary dictionary = - PdfPageHelper.getHelper(page!).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.cropBox)) { - PdfArray? cropBox; - if (dictionary[PdfDictionaryProperties.cropBox] is PdfArray) { - cropBox = dictionary[PdfDictionaryProperties.cropBox] as PdfArray?; - } else { - final PdfReferenceHolder cropBoxHolder = - dictionary[PdfDictionaryProperties.cropBox]! - as PdfReferenceHolder; - cropBox = cropBoxHolder.object as PdfArray?; - } - if ((cropBox![0]! as PdfNumber).value != 0 || - (cropBox[1]! as PdfNumber).value != 0 || - page!.size.width == (cropBox[2]! as PdfNumber).value || - page!.size.height == (cropBox[3]! as PdfNumber).value) { - x = rect.left - (cropBox[0]! as PdfNumber).value!; - y = (cropBox[3]! as PdfNumber).value! - (rect.top + rect.height); - } else { - y = page!.size.height - (rect.top + rect.height); - } - } else if (dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { - PdfArray? mediaBox; - if (PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.mediaBox], - ) - is PdfArray) { - mediaBox = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.mediaBox], - ) - as PdfArray?; - } - if ((mediaBox![0]! as PdfNumber).value! > 0 || - (mediaBox[1]! as PdfNumber).value! > 0 || - page!.size.width == (mediaBox[2]! as PdfNumber).value || - page!.size.height == (mediaBox[3]! as PdfNumber).value) { - x = rect.left - (mediaBox[0]! as PdfNumber).value!; - y = (mediaBox[3]! as PdfNumber).value! - (rect.top + rect.height); - } else { - y = page!.size.height - (rect.top + rect.height); - } - } else { - y = page!.size.height - (rect.top + rect.height); - } - } else { - y = rect.top + rect.height; - } - return Rect.fromLTWH( - x == 0 ? rect.left : x, - y == 0 ? rect.top : y, - rect.width, - rect.height, - ); - } else { - return _fieldHelper.widget!.bounds; - } - } - - set bounds(Rect value) { - if (value.isEmpty && this is! PdfSignatureField) { - ArgumentError("bounds can't be empty."); - } - if (_fieldHelper.isLoadedField) { - final Rect rect = value; - final double height = page!.size.height; - final List values = [ - PdfNumber(rect.left), - PdfNumber(height - (rect.top + rect.height)), - PdfNumber(rect.left + rect.width), - PdfNumber(height - rect.top), - ]; - PdfDictionary dic = _fieldHelper.dictionary!; - if (!dic.containsKey(PdfDictionaryProperties.rect)) { - dic = _fieldHelper.getWidgetAnnotation( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - ); - } - dic.setArray(PdfDictionaryProperties.rect, values); - _fieldHelper.changed = true; - } else { - _fieldHelper.widget!.bounds = value; - } - } - - /// Gets or sets the tab index for form fields. - /// - /// The default value is 0. - int get tabIndex { - if (_fieldHelper.isLoadedField) { - if (page != null) { - final PdfDictionary annotDic = _fieldHelper.getWidgetAnnotation( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - ); - final PdfReference reference = PdfPageHelper.getHelper( - page!, - ).crossTable!.getReference(annotDic); - _tabIndex = PdfPageHelper.getHelper( - page!, - ).annotsReference.indexOf(reference); - } - } - return _tabIndex; - } - - set tabIndex(int value) { - _tabIndex = value; - if (_fieldHelper.isLoadedField && - page != null && - page!.formFieldsTabOrder == PdfFormFieldsTabOrder.manual) { - final PdfAnnotation annotationReference = WidgetAnnotationHelper.load( - _fieldHelper.dictionary!, - _fieldHelper.crossTable!, - ); - final PdfReference reference = PdfPageHelper.getHelper( - page!, - ).crossTable!.getReference(IPdfWrapper.getElement(annotationReference)); - int index = PdfPageHelper.getHelper( - page!, - ).annotsReference.indexOf(reference); - if (index < 0) { - index = _fieldHelper.annotationIndex; - } - final PdfArray? annots = PdfAnnotationCollectionHelper.getHelper( - page!.annotations, - ).rearrange(reference, _tabIndex, index); - PdfPageHelper.getHelper( - page!, - ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); - } - } - - //Public methods - /// Flattens the field. - void flatten() { - _fieldHelper.flattenField = true; - } - - //Implementations - void _initialize() { - _fieldHelper.dictionary!.beginSave = - this is PdfSignatureField - ? _fieldHelper.dictionaryBeginSave - : _dictBeginSave; - _fieldHelper.widget = WidgetAnnotation(); - if (this is PdfSignatureField && form!.fieldAutoNaming) { - _fieldHelper._createBorderPen(); - _fieldHelper._createBackBrush(); - _fieldHelper.dictionary = - PdfAnnotationHelper.getHelper(_fieldHelper.widget!).dictionary; - } else { - _fieldHelper.widget!.parent = this; - if (this is! PdfSignatureField) { - _fieldHelper.format = PdfStringFormat( - alignment: _fieldHelper.widget!.alignment!, - lineAlignment: PdfVerticalAlignment.middle, - ); - _fieldHelper._createBorderPen(); - _fieldHelper._createBackBrush(); - } - final PdfArray array = PdfArray(); - array.add(PdfReferenceHolder(_fieldHelper.widget)); - _fieldHelper.dictionary!.setProperty( - PdfDictionaryProperties.kids, - PdfArray(array), - ); - } - _fieldHelper.widget!.defaultAppearance.fontName = 'TiRo'; - } - - void _dictBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - _fieldHelper.save(); - } - - String? _getFieldName() { - String? name; - PdfString? str; - if (!_fieldHelper.dictionary!.containsKey(PdfDictionaryProperties.parent)) { - str = - PdfFieldHelper.getValue( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - PdfDictionaryProperties.t, - false, - ) - as PdfString?; - } else { - IPdfPrimitive? dic = _fieldHelper.crossTable!.getObject( - _fieldHelper.dictionary![PdfDictionaryProperties.parent], - ); - while (dic != null && - dic is PdfDictionary && - dic.containsKey(PdfDictionaryProperties.parent)) { - if (dic.containsKey(PdfDictionaryProperties.t)) { - name = - name == null - ? (PdfFieldHelper.getValue( - dic, - _fieldHelper.crossTable, - PdfDictionaryProperties.t, - false, - )! - as PdfString) - .value - : '${(PdfFieldHelper.getValue(dic, _fieldHelper.crossTable, PdfDictionaryProperties.t, false)! as PdfString).value!}.$name'; - } - dic = - _fieldHelper.crossTable!.getObject( - dic[PdfDictionaryProperties.parent], - ) - as PdfDictionary?; - } - if (dic != null && - dic is PdfDictionary && - dic.containsKey(PdfDictionaryProperties.t)) { - name = - name == null - ? (PdfFieldHelper.getValue( - dic, - _fieldHelper.crossTable, - PdfDictionaryProperties.t, - false, - )! - as PdfString) - .value - : '${(PdfFieldHelper.getValue(dic, _fieldHelper.crossTable, PdfDictionaryProperties.t, false)! as PdfString).value!}.$name'; - final IPdfPrimitive? strName = PdfFieldHelper.getValue( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - PdfDictionaryProperties.t, - false, - ); - if (strName != null && strName is PdfString) { - name = '${name!}.${strName.value!}'; - } - } else if (_fieldHelper.dictionary!.containsKey( - PdfDictionaryProperties.t, - )) { - str = - PdfFieldHelper.getValue( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - PdfDictionaryProperties.t, - false, - ) - as PdfString?; - } - } - if (str != null) { - name = str.value; - } - return name; - } - - PdfPage? _getLoadedPage() { - PdfPage? page = _fieldHelper.page; - if (page == null || - (PdfPageHelper.getHelper(page).isLoadedPage) && - _fieldHelper.crossTable != null) { - final PdfDocument? doc = _fieldHelper.crossTable!.document; - final PdfDictionary widget = _fieldHelper.getWidgetAnnotation( - _fieldHelper.dictionary!, - _fieldHelper.crossTable, - ); - if (widget.containsKey(PdfDictionaryProperties.p) && - PdfCrossTable.dereference(widget[PdfDictionaryProperties.p]) - is! PdfNull) { - final IPdfPrimitive? pageRef = _fieldHelper.crossTable!.getObject( - widget[PdfDictionaryProperties.p], - ); - if (pageRef != null && pageRef is PdfDictionary) { - page = PdfPageCollectionHelper.getHelper(doc!.pages).getPage(pageRef); - } - } else { - final PdfReference widgetReference = _fieldHelper.crossTable! - .getReference(widget); - for (int j = 0; j < doc!.pages.count; j++) { - final PdfPage loadedPage = doc.pages[j]; - final PdfArray? lAnnots = - PdfPageHelper.getHelper(loadedPage).obtainAnnotations(); - if (lAnnots != null) { - for (int i = 0; i < lAnnots.count; i++) { - final IPdfPrimitive? holder = lAnnots[i]; - if (holder != null && - holder is PdfReferenceHolder && - holder.reference != null) { - if (holder.reference!.objNum == widgetReference.objNum && - holder.reference!.genNum == widgetReference.genNum) { - page = loadedPage; - return page; - } else if (_fieldHelper.requiredReference != null && - _fieldHelper.requiredReference!.reference != null && - _fieldHelper.requiredReference!.reference!.objNum == - holder.reference!.objNum && - _fieldHelper.requiredReference!.reference!.genNum == - holder.reference!.genNum) { - page = loadedPage; - return page; - } - } - } - } - } - } - } - if (page != null && - PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.tabs)) { - final IPdfPrimitive? tabName = PdfCrossTable.dereference( - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties.tabs], - ); - if (tabName != null && - ((tabName is PdfName && tabName.name == '') || - (tabName is PdfString && tabName.value == ''))) { - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .tabs] = PdfName(' '); - } - } - return page; - } - - void _addAnnotationToPage(PdfPage? page, PdfAnnotation? widget) { - if (page != null && !PdfPageHelper.getHelper(page).isLoadedPage) { - PdfAnnotationHelper.getHelper(widget!).dictionary!.setProperty( - PdfDictionaryProperties.t, - PdfString(_fieldHelper.name!), - ); - } else { - final PdfDictionary pageDic = PdfPageHelper.getHelper(page!).dictionary!; - PdfArray? annots; - if (pageDic.containsKey(PdfDictionaryProperties.annots)) { - final IPdfPrimitive? obj = PdfPageHelper.getHelper( - page, - ).crossTable!.getObject(pageDic[PdfDictionaryProperties.annots]); - if (obj != null && obj is PdfArray) { - annots = obj; - } - } - annots ??= PdfArray(); - PdfAnnotationHelper.getHelper(widget!).dictionary!.setProperty( - PdfDictionaryProperties.p, - PdfReferenceHolder(page), - ); - form!.fieldAutoNaming - ? PdfAnnotationHelper.getHelper(widget).dictionary!.setProperty( - PdfDictionaryProperties.t, - PdfString(_fieldHelper.name!), - ) - : _fieldHelper.dictionary!.setProperty( - PdfDictionaryProperties.t, - PdfString(_fieldHelper.name!), - ); - annots.add(PdfReferenceHolder(widget)); - PdfPageHelper.getHelper( - page, - ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); - } - } - - List _getWidgetAnnotations( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final List widgetAnnotationCollection = []; - if (dictionary.containsKey(PdfDictionaryProperties.kids)) { - final IPdfPrimitive? array = crossTable.getObject( - dictionary[PdfDictionaryProperties.kids], - ); - if (array != null && array is PdfArray && array.count > 0) { - for (int i = 0; i < array.count; i++) { - final IPdfPrimitive item = array[i]!; - final PdfReference reference = crossTable.getReference(item); - final IPdfPrimitive? widgetDic = crossTable.getObject(reference); - if (widgetDic != null && widgetDic is PdfDictionary) { - widgetAnnotationCollection.add(widgetDic); - } - } - } - } else if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? type = crossTable.getObject( - dictionary[PdfDictionaryProperties.subtype], - ); - if (type != null && - type is PdfName && - type.name == PdfDictionaryProperties.widget) { - widgetAnnotationCollection.add(dictionary); - } - } - if (widgetAnnotationCollection.isEmpty) { - widgetAnnotationCollection.add(dictionary); - } - return widgetAnnotationCollection; - } -} - -/// [PdfField] helper -class PdfFieldHelper { - /// internal constructor - PdfFieldHelper(this.field); - - /// internal field - late PdfField field; - - /// internal method - void load(PdfDictionary dictionary, PdfCrossTable crossTable) { - field._load(dictionary, crossTable, this); - } - - /// internal method - void internal( - PdfPage? page, - String? name, - Rect bounds, { - PdfFont? font, - PdfTextAlignment? alignment, - PdfColor? borderColor, - PdfColor? foreColor, - PdfColor? backColor, - int? borderWidth, - PdfHighlightMode? highlightMode, - PdfBorderStyle? borderStyle, - String? tooltip, - }) { - field._internal( - page, - name, - bounds, - font: font, - alignment: alignment, - borderColor: borderColor, - foreColor: foreColor, - backColor: backColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - helper: this, - ); - } - - /// internal field - PdfPage? page; - - /// internal field - PdfForm? form; - - /// internal field - WidgetAnnotation? widget; - - /// internal field - PdfStringFormat? stringFormat; - - /// internal field - // ignore: prefer_final_fields - PdfArray array = PdfArray(); - - /// internal field - bool changed = false; - - /// internal field - bool isLoadedField = false; - - /// internal field - // ignore: prefer_final_fields - int defaultIndex = 0; - - /// internal field - PdfCrossTable? crossTable; - - /// internal field - PdfReferenceHolder? requiredReference; - - /// internal field - int? flagValues; - - /// internal field - // ignore: prefer_final_fields - int annotationIndex = 0; - - /// internal field - List? fieldItems; - - /// internal field - // ignore: prefer_final_fields - bool exportEmptyField = false; - - /// internal field - int objID = 0; - - /// internal field - bool flatten = false; - //// ignore: prefer_final_fields - List flags = [FieldFlags.defaultFieldFlag]; - - /// internal field - PdfArray? get kids => obtainKids(); - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal field - // ignore: prefer_final_fields - bool isTextChanged = false; - - /// internal field - bool fieldChanged = false; - - PdfFont? _internalFont; - - /// internal field - PdfBrush? bBrush; - - /// internal field - PdfBrush? fBrush; - - /// internal field - PdfBrush? sBrush; - - /// internal field - PdfPen? bPen; - - /// internal field - String? name = ''; - bool _readOnly = false; - - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal field - late BeforeNameChangesEventHandler beforeNameChanges; - - /// Gets or sets a value indicating whether to flatten this [PdfField]. - bool get flattenField { - if (form != null) { - flatten |= PdfFormHelper.getHelper(form!).flatten; - } - return flatten; - } - - set flattenField(bool value) { - flatten = value; - } - - /// internal method - /// Gets or sets the color of the border. - PdfColor get borderColor { - if (isLoadedField) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfColor bc = PdfColor.empty; - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final IPdfPrimitive? getObject = crossTable!.getObject( - widget[PdfDictionaryProperties.mk], - ); - if (getObject != null && - getObject is PdfDictionary && - getObject.containsKey(PdfDictionaryProperties.bc)) { - final PdfArray array = - getObject[PdfDictionaryProperties.bc]! as PdfArray; - bc = _createColor(array); - } - } - return bc; - } else { - return WidgetAnnotationHelper.getHelper( - widget!, - ).widgetAppearance!.borderColor; - } - } - - set borderColor(PdfColor value) { - WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.borderColor = - value; - if (isLoadedField) { - PdfFormHelper.getHelper(field.form!).setAppearanceDictionary = true; - assignBorderColor(value); - if (PdfFormHelper.getHelper(field.form!).needAppearances == false) { - changed = true; - fieldChanged = true; - } - } - _createBorderPen(); - } - - /// Gets or sets the color of the background. - PdfColor get backColor => - isLoadedField - ? getBackColor() - : WidgetAnnotationHelper.getHelper( - widget!, - ).widgetAppearance!.backColor; - - set backColor(PdfColor value) { - if (isLoadedField) { - assignBackColor(value); - if (PdfFormHelper.getHelper(field.form!).needAppearances == false) { - changed = true; - fieldChanged = true; - } - } else { - WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.backColor = - value; - _createBackBrush(); - } - } - - //Creates the back brush. - void _createBackBrush() { - final PdfColor bc = - WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.backColor; - backBrush = PdfSolidBrush(bc); - final PdfColor color = PdfColor(bc.r, bc.g, bc.b); - color.r = (color.r - 64 >= 0 ? color.r - 64 : 0).toUnsigned(8); - color.g = (color.g - 64 >= 0 ? color.g - 64 : 0).toUnsigned(8); - color.b = (color.b - 64 >= 0 ? color.b - 64 : 0).toUnsigned(8); - shadowBrush = PdfSolidBrush(color); - } - - /// Gets or sets the color of the text. - PdfColor get foreColor { - if (isLoadedField) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfColor color = PdfColor(0, 0, 0); - if (widget.containsKey(PdfDictionaryProperties.da)) { - final PdfString defaultAppearance = - crossTable!.getObject(widget[PdfDictionaryProperties.da])! - as PdfString; - color = _getForeColor(defaultAppearance.value); - } else { - final IPdfPrimitive? defaultAppearance = widget.getValue( - PdfDictionaryProperties.da, - PdfDictionaryProperties.parent, - ); - if (defaultAppearance != null && defaultAppearance is PdfString) { - color = _getForeColor(defaultAppearance.value); - } - } - return color; - } else { - return widget!.defaultAppearance.foreColor; - } - } - - set foreColor(PdfColor value) { - if (isLoadedField) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - double? height = 0; - String? name; - if (widget.containsKey(PdfDictionaryProperties.da)) { - final PdfString str = widget[PdfDictionaryProperties.da]! as PdfString; - final dynamic fontName = _fontName(str.value!); - name = fontName['name'] as String?; - height = fontName['height'] as double?; - } else if (dictionary!.containsKey(PdfDictionaryProperties.da)) { - final PdfString str = - dictionary![PdfDictionaryProperties.da]! as PdfString; - final dynamic fontName = _fontName(str.value!); - name = fontName['name'] as String?; - height = fontName['height'] as double?; - } - if (name != null) { - final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); - defaultAppearance.fontName = name; - defaultAppearance.fontSize = height; - defaultAppearance.foreColor = value; - widget[PdfDictionaryProperties.da] = PdfString( - defaultAppearance.getString(), - ); - } else if (font != null) { - final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); - defaultAppearance.fontName = font!.name; - defaultAppearance.fontSize = font!.size; - defaultAppearance.foreColor = value; - widget[PdfDictionaryProperties.da] = PdfString( - defaultAppearance.getString(), - ); - } - PdfFormHelper.getHelper(field.form!).setAppearanceDictionary = true; - } else { - WidgetAnnotationHelper.getHelper(widget!) - .pdfDefaultAppearance! - .foreColor = value; - foreBrush = PdfSolidBrush(value); - } - } - - /// Gets or sets the width of the border. - int get borderWidth => - isLoadedField - ? _obtainBorderWidth() - : widget!.widgetBorder!.width.toInt(); - set borderWidth(int value) { - if (widget!.widgetBorder!.width != value) { - widget!.widgetBorder!.width = value.toDouble(); - if (isLoadedField) { - _assignBorderWidth(value); - } else { - value == 0 - ? WidgetAnnotationHelper.getHelper( - widget!, - ).widgetAppearance!.borderColor = PdfColor(255, 255, 255) - : _createBorderPen(); - } - } - } - - /// Gets or sets the highlighting mode. - PdfHighlightMode get highlightMode => - isLoadedField ? _obtainHighlightMode() : widget!.highlightMode!; - set highlightMode(PdfHighlightMode value) => - isLoadedField - ? _assignHighlightMode(value) - : widget!.highlightMode = value; - - /// Gets or sets the border style. - PdfBorderStyle get borderStyle => - isLoadedField ? _obtainBorderStyle() : widget!.widgetBorder!.borderStyle; - set borderStyle(PdfBorderStyle value) { - if (isLoadedField) { - _assignBorderStyle(value); - if (PdfFormHelper.getHelper(field.form!).needAppearances == false) { - changed = true; - fieldChanged = true; - } - } else { - widget!.widgetBorder!.borderStyle = value; - } - _createBorderPen(); - } - - PdfBorderStyle _obtainBorderStyle() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfBorderStyle style = PdfBorderStyle.solid; - if (widget.containsKey(PdfDictionaryProperties.bs)) { - final PdfDictionary bs = - crossTable!.getObject(widget[PdfDictionaryProperties.bs])! - as PdfDictionary; - style = _createBorderStyle(bs); - } - return style; - } - - PdfBorderStyle _createBorderStyle(PdfDictionary bs) { - PdfBorderStyle style = PdfBorderStyle.solid; - if (bs.containsKey(PdfDictionaryProperties.s)) { - final IPdfPrimitive? name = crossTable!.getObject( - bs[PdfDictionaryProperties.s], - ); - if (name != null && name is PdfName) { - switch (name.name!.toLowerCase()) { - case 'd': - style = PdfBorderStyle.dashed; - break; - case 'b': - style = PdfBorderStyle.beveled; - break; - case 'i': - style = PdfBorderStyle.inset; - break; - case 'u': - style = PdfBorderStyle.underline; - break; - } - } - } - return style; - } - - /// Gets or sets the font. - PdfFont? get font { - if (isLoadedField) { - if (_internalFont != null) { - return _internalFont!; - } - bool? isCorrectFont = false; - PdfFont tempFont = PdfStandardFont(PdfFontFamily.helvetica, 8); - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.da) || - dictionary!.containsKey(PdfDictionaryProperties.da)) { - IPdfPrimitive? defaultAppearance = crossTable!.getObject( - widget[PdfDictionaryProperties.da], - ); - defaultAppearance ??= crossTable!.getObject( - dictionary![PdfDictionaryProperties.da], - ); - String? fontName; - if (defaultAppearance != null && defaultAppearance is PdfString) { - final Map value = _getFont(defaultAppearance.value!); - tempFont = value['font'] as PdfFont; - isCorrectFont = value['isCorrectFont'] as bool?; - fontName = value['fontName'] as String?; - if (!isCorrectFont! && fontName != null) { - widget.setProperty( - PdfDictionaryProperties.da, - PdfString(defaultAppearance.value!.replaceAll(fontName, '/Helv')), - ); - } - } - } - return tempFont; - } - return _internalFont; - } - - set font(PdfFont? value) { - if (value != null && _internalFont != value) { - _internalFont = value; - if (isLoadedField) { - if (form != null) { - PdfFormHelper.getHelper(form!).setAppearanceDictionary = true; - } - final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); - defaultAppearance.fontName = _internalFont!.name.replaceAll(' ', ''); - defaultAppearance.fontSize = _internalFont!.size; - defaultAppearance.foreColor = foreColor; - final IPdfPrimitive? fontDictionary = PdfCrossTable.dereference( - PdfFormHelper.getHelper(form!).resources[PdfDictionaryProperties - .font], - ); - if (fontDictionary != null && - fontDictionary is PdfDictionary && - !fontDictionary.containsKey(defaultAppearance.fontName)) { - final IPdfWrapper fontWrapper = _internalFont!; - final PdfDictionary? fontElement = - IPdfWrapper.getElement(fontWrapper) as PdfDictionary?; - fontDictionary.items![PdfName( - defaultAppearance.fontName, - )] = PdfReferenceHolder(fontElement); - } - final PdfDictionary widget = getWidgetAnnotation( - dictionary!, - crossTable, - ); - widget[PdfDictionaryProperties.da] = PdfString( - defaultAppearance.getString(), - ); - } else { - _defineDefaultAppearance(); - } - } - } - - /// Gets or sets the text alignment. - PdfTextAlignment get textAlignment => - isLoadedField ? format!.alignment : widget!.textAlignment!; - set textAlignment(PdfTextAlignment value) { - if (isLoadedField) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - widget.setProperty(PdfDictionaryProperties.q, PdfNumber(value.index)); - changed = true; - } else if (widget!.textAlignment != value) { - widget!.textAlignment = value; - format = PdfStringFormat( - alignment: value, - lineAlignment: PdfVerticalAlignment.middle, - ); - } - } - - /// internal property - int get flagValue => flagValues ??= getFlagValue(); - - /// internal method - bool isFlagPresent(FieldFlags flag) { - return _getFieldFlagsValue(flag) & flagValue != 0; - } - - int _getFieldFlagsValue(FieldFlags value) { - switch (value) { - case FieldFlags.readOnly: - return 1; - case FieldFlags.requiredFieldFlag: - return 1 << 1; - case FieldFlags.noExport: - return 1 << 2; - case FieldFlags.multiline: - return 1 << 12; - case FieldFlags.password: - return 1 << 13; - case FieldFlags.fileSelect: - return 1 << 20; - case FieldFlags.doNotSpellCheck: - return 1 << 22; - case FieldFlags.doNotScroll: - return 1 << 23; - case FieldFlags.comb: - return 1 << 24; - case FieldFlags.richText: - return 1 << 25; - case FieldFlags.noToggleToOff: - return 1 << 14; - case FieldFlags.radio: - return 1 << 15; - case FieldFlags.pushButton: - return 1 << 16; - case FieldFlags.radiosInUnison: - return 1 << 25; - case FieldFlags.combo: - return 1 << 17; - case FieldFlags.edit: - return 1 << 18; - case FieldFlags.sort: - return 1 << 19; - case FieldFlags.multiSelect: - return 1 << 21; - case FieldFlags.commitOnSelChange: - return 1 << 26; - case FieldFlags.defaultFieldFlag: - return 0; - } - } - - /// internal property - PdfStringFormat? get format => - isLoadedField ? _assignStringFormat() : stringFormat; - set format(PdfStringFormat? value) => stringFormat = value; - - /// internal property - PdfBrush? get backBrush { - if (isLoadedField) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfColor c = PdfColor.empty; - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final IPdfPrimitive? bs = crossTable!.getObject( - widget[PdfDictionaryProperties.mk], - ); - if (bs is PdfDictionary) { - IPdfPrimitive? array; - if (bs.containsKey(PdfDictionaryProperties.bg)) { - array = bs[PdfDictionaryProperties.bg]; - } else if (bs.containsKey(PdfDictionaryProperties.bs)) { - array = bs[PdfDictionaryProperties.bs]; - } - if (array != null && array is PdfArray) { - c = _createColor(array); - } - } - } - return c.isEmpty ? null : PdfSolidBrush(c); - } else { - return bBrush; - } - } - - set backBrush(PdfBrush? value) { - if (isLoadedField && value is PdfSolidBrush) { - assignBackColor(value.color); - } else { - bBrush = value; - } - } - - /// internal property - PdfBrush? get foreBrush => isLoadedField ? PdfSolidBrush(foreColor) : fBrush; - set foreBrush(PdfBrush? value) => fBrush = value; - - /// internal property - PdfBrush? get shadowBrush => isLoadedField ? _obtainShadowBrush() : sBrush; - set shadowBrush(PdfBrush? value) => sBrush = value; - - /// internal property - PdfPen? get borderPen => isLoadedField ? _obtainBorderPen() : bPen; - set borderPen(PdfPen? value) => bPen = value; - - /// internal method - void beginSave() { - if (backBrush != null && - backBrush is PdfSolidBrush && - (backBrush! as PdfSolidBrush).color.isEmpty) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - final PdfDictionary mk = PdfDictionary(); - final PdfArray arr = PdfArray([1, 1, 1]); - mk.setProperty(PdfDictionaryProperties.bg, arr); - widget.setProperty(PdfDictionaryProperties.mk, mk); - } - } - - /// internal method - void setForm(PdfForm? pdfForm) { - form = pdfForm; - _defineDefaultAppearance(); - } - - /// internal method - void setFlags(List value) { - int flagValue = isLoadedField ? this.flagValue : 0; - // ignore: avoid_function_literals_in_foreach_calls - value.forEach( - (FieldFlags element) => flagValue |= _getFieldFlagsValue(element), - ); - flagValues = flagValue; - dictionary!.setNumber(PdfDictionaryProperties.fieldFlags, flagValues); - } - - /// internal method - void removeFlag(FieldFlags flag) { - flagValues = flagValue & ~_getFieldFlagsValue(flag); - } - - /// internal method - int getFlagValue() { - final IPdfPrimitive? number = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.fieldFlags, - true, - ); - return number != null && number is PdfNumber ? number.value!.toInt() : 0; - } - - void _defineDefaultAppearance() { - if (field.form != null && _internalFont != null) { - if (isLoadedField) { - final PdfDictionary widget = getWidgetAnnotation( - dictionary!, - crossTable, - ); - final PdfName name = PdfFormHelper.getHelper( - form!, - ).resources.getName(font!); - PdfFormHelper.getHelper(form!).resources.add(_internalFont, name); - PdfFormHelper.getHelper(form!).needAppearances = true; - final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); - defaultAppearance.fontName = name.name; - defaultAppearance.fontSize = _internalFont!.size; - defaultAppearance.foreColor = foreColor; - widget[PdfDictionaryProperties.da] = PdfString( - defaultAppearance.getString(), - ); - if (field is PdfRadioButtonListField) { - final PdfRadioButtonListField radioButtonListField = - field as PdfRadioButtonListField; - for (int i = 0; i < radioButtonListField.items.count; i++) { - final PdfRadioButtonListItem item = radioButtonListField.items[i]; - if (PdfFieldHelper.getHelper(item).font != null) { - PdfFormHelper.getHelper(field.form!).resources.add( - PdfFieldHelper.getHelper(radioButtonListField.items[i]).font, - PdfName( - WidgetAnnotationHelper.getHelper( - PdfFieldHelper.getHelper(item).widget!, - ).pdfDefaultAppearance!.fontName, - ), - ); - } - } - } - } else { - final PdfName name = PdfFormHelper.getHelper( - field.form!, - ).resources.getName(_internalFont!); - widget!.defaultAppearance.fontName = name.name; - widget!.defaultAppearance.fontSize = _internalFont!.size; - } - } else if (!isLoadedField && _internalFont != null) { - widget!.defaultAppearance.fontName = _internalFont!.name; - widget!.defaultAppearance.fontSize = _internalFont!.size; - } - } - - /// Sets the name of the field. - void _setName(String? name) { - if (name == null || name.isEmpty) { - throw ArgumentError('Field name cannot be null/empty.'); - } - if (isLoadedField) { - if (field.name != null && field.name != name) { - final List nameParts = field.name!.split('.'); - if (nameParts[nameParts.length - 1] == name) { - return; - } else { - if (form != null) { - beforeNameChanges(name); - } - this.name = name; - changed = true; - } - } - } else { - this.name = name; - } - dictionary!.setProperty(PdfDictionaryProperties.t, PdfString(name)); - } - - /// internal method - void applyName(String? name) { - if (isLoadedField) { - _setName(name); - } else { - name = name; - dictionary!.setProperty(PdfDictionaryProperties.t, PdfString(name!)); - } - } - - /// Gets the widget annotation. - PdfDictionary getWidgetAnnotation( - PdfDictionary dictionary, - PdfCrossTable? crossTable, - ) { - PdfDictionary? dic; - if (dictionary.containsKey(PdfDictionaryProperties.kids)) { - final IPdfPrimitive? array = crossTable!.getObject( - dictionary[PdfDictionaryProperties.kids], - ); - if (array is PdfArray && array.count > 0) { - final IPdfPrimitive reference = crossTable.getReference( - array[defaultIndex], - ); - if (reference is PdfReference) { - dic = crossTable.getObject(reference) as PdfDictionary?; - } - } - } - return dic ?? dictionary; - } - - /// internal method - void drawAppearance(PdfTemplate template) { - if (font != null) { - if ((font is PdfStandardFont || font is PdfCjkStandardFont) && - page != null && - PdfPageHelper.getHelper(page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(page!).document!, - ).conformanceLevel != - PdfConformanceLevel.none) { - throw ArgumentError( - 'All the fonts must be embedded in ${PdfDocumentHelper.getHelper(PdfPageHelper.getHelper(page!).document!).conformanceLevel} document.', - ); - } else if (font is PdfTrueTypeFont && - PdfPageHelper.getHelper(page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(page!).document!, - ).conformanceLevel == - PdfConformanceLevel.a1b) { - PdfTrueTypeFontHelper.getHelper( - font! as PdfTrueTypeFont, - ).fontInternal.initializeCidSet(); - } - } - } - - /// internal method - void draw() { - removeAnnotationFromPage(); - } - - Map _getFont(String fontString) { - bool isCorrectFont = true; - final Map fontNameDic = _fontName(fontString); - final String? name = fontNameDic['name'] as String?; - double height = fontNameDic['height'] as double; - PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, height); - IPdfPrimitive? fontDictionary = crossTable!.getObject( - PdfFormHelper.getHelper(field.form!).resources[PdfDictionaryProperties - .font], - ); - if (height == 0) { - if (font is PdfStandardFont) { - height = getFontHeight(font.fontFamily); - if (height == 0) { - height = 12; - } - PdfFontHelper.getHelper(font).setSize(height); - } - } - if (fontDictionary != null && - name != null && - fontDictionary is PdfDictionary && - fontDictionary.containsKey(name)) { - fontDictionary = crossTable!.getObject(fontDictionary[name]); - if (fontDictionary != null && - fontDictionary is PdfDictionary && - fontDictionary.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName fontSubtype = - crossTable!.getObject( - fontDictionary[PdfDictionaryProperties.subtype], - )! - as PdfName; - if (fontSubtype.name == PdfDictionaryProperties.type1) { - final PdfName baseFont = - crossTable!.getObject( - fontDictionary[PdfDictionaryProperties.baseFont], - )! - as PdfName; - final List fontStyle = _getFontStyle( - PdfName.decodeName(baseFont.name)!, - ); - final dynamic fontFamilyDic = _getFontFamily( - PdfName.decodeName(baseFont.name)!, - ); - final PdfFontFamily? fontFamily = - fontFamilyDic['fontFamily'] as PdfFontFamily?; - final String? standardName = fontFamilyDic['standardName'] as String?; - if (standardName == null) { - font = PdfStandardFont(fontFamily!, height, multiStyle: fontStyle); - if (!isTextChanged) { - font = _updateFontEncoding(font, fontDictionary); - } - } else { - if (height == 0 && standardName != getEnumName(fontFamily)) { - PdfDictionary? appearanceDictionary = PdfDictionary(); - if (dictionary!.containsKey(PdfDictionaryProperties.ap)) { - appearanceDictionary = - dictionary![PdfDictionaryProperties.ap] as PdfDictionary?; - } else { - if (dictionary!.containsKey(PdfDictionaryProperties.kids) && - dictionary![PdfDictionaryProperties.kids] is PdfArray) { - final PdfArray kidsArray = - dictionary![PdfDictionaryProperties.kids]! as PdfArray; - for (int i = 0; i < kidsArray.count; i++) { - if (kidsArray[i] is PdfReferenceHolder) { - final PdfReferenceHolder kids = - kidsArray[i]! as PdfReferenceHolder; - final IPdfPrimitive? dictionary = kids.object; - appearanceDictionary = - dictionary != null && - dictionary is PdfDictionary && - dictionary.containsKey( - PdfDictionaryProperties.ap, - ) && - dictionary[PdfDictionaryProperties.ap] - is PdfDictionary - ? dictionary[PdfDictionaryProperties.ap] - as PdfDictionary? - : null; - break; - } - } - } - } - if (appearanceDictionary != null && - appearanceDictionary.containsKey(PdfDictionaryProperties.n)) { - final IPdfPrimitive? dic = PdfCrossTable.dereference( - appearanceDictionary[PdfDictionaryProperties.n], - ); - if (dic != null && dic is PdfStream) { - final PdfStream stream = dic; - stream.decompress(); - final dynamic fontNameDict = _fontName( - utf8.decode(stream.dataStream!.toList()), - ); - height = fontNameDict['height'] as double; - } - } - } - if (height == 0 && standardName != getEnumName(fontFamily)) { - final PdfStandardFont stdf = font as PdfStandardFont; - height = getFontHeight(stdf.fontFamily); - font = PdfStandardFont.prototype(stdf, height); - } - if (fontStyle != [PdfFontStyle.regular]) { - font = PdfStandardFont( - PdfFontFamily.helvetica, - height, - multiStyle: fontStyle, - ); - } - if (standardName != getEnumName(fontFamily)) { - font = _updateFontEncoding(font, fontDictionary); - } - PdfFontHelper.getHelper(font).metrics = _createFont( - fontDictionary, - height, - baseFont, - ); - PdfFontHelper.getHelper(font).fontInternals = fontDictionary; - } - } else if (fontSubtype.name == 'TrueType') { - final PdfName baseFont = - crossTable!.getObject( - fontDictionary[PdfDictionaryProperties.baseFont], - )! - as PdfName; - final List fontStyle = _getFontStyle(baseFont.name!); - font = PdfStandardFont.prototype( - PdfStandardFont(PdfFontFamily.helvetica, 8), - height, - multiStyle: fontStyle, - ); - font = _createFontFromFontStream( - font, - fontDictionary, - height, - fontStyle, - ); - final IPdfPrimitive? tempName = - fontDictionary[PdfDictionaryProperties.name]; - if (tempName != null && tempName is PdfName) { - if (font is PdfStandardFont && font.name != tempName.name) { - final PdfFontHelper fontHelper = PdfFontHelper.getHelper(font); - final WidthTable? widthTable = fontHelper.metrics!.widthTable; - fontHelper.metrics = _createFont( - fontDictionary, - height, - baseFont, - ); - fontHelper.metrics!.widthTable = widthTable; - } - } - } else if (fontSubtype.name == PdfDictionaryProperties.type0) { - final IPdfPrimitive? baseFont = crossTable!.getObject( - fontDictionary[PdfDictionaryProperties.baseFont], - ); - if (baseFont != null && - baseFont is PdfName && - _isCjkFont(baseFont.name)) { - font = PdfCjkStandardFont( - _getCjkFontFamily(baseFont.name)!, - height, - multiStyle: _getFontStyle(baseFont.name!), - ); - } else { - IPdfPrimitive? descendantFontsArray; - IPdfPrimitive? descendantFontsDic; - IPdfPrimitive? fontDescriptor; - IPdfPrimitive? fontDescriptorDic; - IPdfPrimitive? fontName; - descendantFontsArray = crossTable!.getObject( - fontDictionary[PdfDictionaryProperties.descendantFonts], - ); - if (descendantFontsArray != null && - descendantFontsArray is PdfArray && - descendantFontsArray.count > 0) { - descendantFontsDic = - descendantFontsArray[0] is PdfDictionary - ? descendantFontsArray[0] - : (descendantFontsArray[0]! as PdfReferenceHolder).object; - } - if (descendantFontsDic != null && - descendantFontsDic is PdfDictionary) { - fontDescriptor = - descendantFontsDic[PdfDictionaryProperties.fontDescriptor]; - } - if (fontDescriptor != null && - fontDescriptor is PdfReferenceHolder) { - fontDescriptorDic = fontDescriptor.object; - } - if (fontDescriptorDic != null && - fontDescriptorDic is PdfDictionary) { - fontName = fontDescriptorDic[PdfDictionaryProperties.fontName]; - } - if (fontName != null && fontName is PdfName) { - String fontNameStr = fontName.name!.substring( - fontName.name!.indexOf('+') + 1, - ); - final PdfFontMetrics fontMetrics = _createFont( - descendantFontsDic! as PdfDictionary, - height, - PdfName(fontNameStr), - ); - if (fontNameStr.contains('PSMT')) { - fontNameStr = fontNameStr.replaceAll('PSMT', ''); - } - if (fontNameStr.contains('PS')) { - fontNameStr = fontNameStr.replaceAll('PS', ''); - } - if (fontNameStr.contains('-')) { - fontNameStr = fontNameStr.replaceAll('-', ''); - } - if (font.name != fontNameStr) { - final WidthTable? widthTable = - PdfFontHelper.getHelper(font).metrics!.widthTable; - PdfFontHelper.getHelper(font).metrics = fontMetrics; - PdfFontHelper.getHelper(font).metrics!.widthTable = widthTable; - } - } - } - } - } - } else { - final PdfFont? usedFont = _getFontByName(name, height); - usedFont != null ? font = usedFont : isCorrectFont = false; - } - return { - 'font': font, - 'isCorrectFont': isCorrectFont, - 'FontName': name, - }; - } - - PdfFont _createFontFromFontStream( - PdfFont font, - PdfDictionary fontDictionary, - double height, - List fontStyle, - ) { - if (fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor)) { - IPdfPrimitive? fontDescriptor = PdfCrossTable.dereference( - fontDictionary[PdfDictionaryProperties.fontDescriptor], - ); - if (fontDescriptor == null && - fontDescriptor is PdfDictionary && - fontDictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { - final IPdfPrimitive? descendFonts = PdfCrossTable.dereference( - fontDictionary[PdfDictionaryProperties.descendantFonts], - ); - if (descendFonts != null && descendFonts is PdfArray) { - final IPdfPrimitive? descendDict = PdfCrossTable.dereference( - descendFonts[0], - ); - if (descendDict != null && - descendDict is PdfDictionary && - descendDict.containsKey(PdfDictionaryProperties.fontDescriptor)) { - fontDescriptor = PdfCrossTable.dereference( - descendDict[PdfDictionaryProperties.fontDescriptor], - ); - } - } - } - IPdfPrimitive? fontFile; - if (fontDescriptor != null && fontDescriptor is PdfDictionary) { - if (fontDescriptor.containsKey(PdfDictionaryProperties.fontFile2)) { - fontFile = PdfCrossTable.dereference( - fontDescriptor[PdfDictionaryProperties.fontFile2], - ); - } - if (fontDescriptor.containsKey('FontFile3')) { - fontFile = PdfCrossTable.dereference(fontDescriptor['FontFile3']); - } - } - if (fontFile != null && fontFile is PdfStream) { - fontFile.decompress(); - fontFile.freezeChanges(fontFile); - try { - fontFile.position = 0; - if (fontFile.dataStream != null) { - font = PdfTrueTypeFont( - fontFile.dataStream!, - height, - multiStyle: fontStyle, - ); - } - } catch (e) { - return font; - } - } - } - return font; - } - - PdfFontMetrics _createFont( - PdfDictionary fontDictionary, - double? height, - PdfName baseFont, - ) { - final PdfFontMetrics fontMetrics = PdfFontMetrics(); - if (fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor)) { - IPdfPrimitive? createFontDictionary; - final IPdfPrimitive? fontReferenceHolder = - fontDictionary[PdfDictionaryProperties.fontDescriptor]; - if (fontReferenceHolder != null && - fontReferenceHolder is PdfReferenceHolder) { - createFontDictionary = fontReferenceHolder.object; - } else { - createFontDictionary = - fontDictionary[PdfDictionaryProperties.fontDescriptor]; - } - if (createFontDictionary != null && - createFontDictionary is PdfDictionary) { - fontMetrics.ascent = - (createFontDictionary[PdfDictionaryProperties.ascent]! as PdfNumber) - .value! - as double; - fontMetrics.descent = - (createFontDictionary[PdfDictionaryProperties.descent]! - as PdfNumber) - .value! - as double; - fontMetrics.size = height!; - fontMetrics.height = fontMetrics.ascent - fontMetrics.descent; - fontMetrics.postScriptName = baseFont.name; - } - } - PdfArray? array; - if (fontDictionary.containsKey(PdfDictionaryProperties.widths)) { - if (fontDictionary[PdfDictionaryProperties.widths] - is PdfReferenceHolder) { - final PdfReferenceHolder tableReference = PdfReferenceHolder( - fontDictionary[PdfDictionaryProperties.widths], - ); - final PdfReferenceHolder tableArray = - tableReference.object! as PdfReferenceHolder; - array = tableArray.object as PdfArray?; - final List widthTable = []; - for (int i = 0; i < array!.count; i++) { - widthTable.add((array[i]! as PdfNumber).value! as int); - } - fontMetrics.widthTable = StandardWidthTable(widthTable); - } else { - array = fontDictionary[PdfDictionaryProperties.widths] as PdfArray?; - final List widthTable = []; - for (int i = 0; i < array!.count; i++) { - widthTable.add((array[i]! as PdfNumber).value!.toInt()); - } - fontMetrics.widthTable = StandardWidthTable(widthTable); - } - } - fontMetrics.name = baseFont.name!; - return fontMetrics; - } - - PdfFont? _getFontByName(String? name, double height) { - PdfFont? font; - switch (name) { - case 'CoBO': //"Courier-BoldOblique" - font = PdfStandardFont( - PdfFontFamily.courier, - height, - multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], - ); - break; - case 'CoBo': //"Courier-Bold" - font = PdfStandardFont( - PdfFontFamily.courier, - height, - style: PdfFontStyle.bold, - ); - break; - case 'CoOb': //"Courier-Oblique" - font = PdfStandardFont( - PdfFontFamily.courier, - height, - style: PdfFontStyle.italic, - ); - break; - case 'Courier': - case 'Cour': //"Courier" - font = PdfStandardFont( - PdfFontFamily.courier, - height, - style: PdfFontStyle.regular, - ); - break; - case 'HeBO': //"Helvetica-BoldOblique" - font = PdfStandardFont( - PdfFontFamily.helvetica, - height, - multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], - ); - break; - case 'HeBo': //"Helvetica-Bold" - font = PdfStandardFont( - PdfFontFamily.helvetica, - height, - style: PdfFontStyle.bold, - ); - break; - case 'HeOb': //"Helvetica-Oblique" - font = PdfStandardFont( - PdfFontFamily.helvetica, - height, - style: PdfFontStyle.italic, - ); - break; - case 'Helv': //"Helvetica" - font = PdfStandardFont( - PdfFontFamily.helvetica, - height, - style: PdfFontStyle.regular, - ); - break; - case 'Symb': // "Symbol" - font = PdfStandardFont(PdfFontFamily.symbol, height); - break; - case 'TiBI': // "Times-BoldItalic" - font = PdfStandardFont( - PdfFontFamily.timesRoman, - height, - multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], - ); - break; - case 'TiBo': // "Times-Bold" - font = PdfStandardFont( - PdfFontFamily.timesRoman, - height, - style: PdfFontStyle.bold, - ); - break; - case 'TiIt': // "Times-Italic" - font = PdfStandardFont( - PdfFontFamily.timesRoman, - height, - style: PdfFontStyle.italic, - ); - break; - case 'TiRo': // "Times-Roman" - font = PdfStandardFont( - PdfFontFamily.timesRoman, - height, - style: PdfFontStyle.regular, - ); - break; - case 'ZaDb': // "ZapfDingbats" - font = PdfStandardFont(PdfFontFamily.zapfDingbats, height); - break; - } - return font; - } - - //Gets the font color. - PdfColor _getForeColor(String? defaultAppearance) { - PdfColor colour = PdfColor(0, 0, 0); - if (defaultAppearance == null || defaultAppearance.isEmpty) { - colour = PdfColor(0, 0, 0); - } else { - final PdfReader reader = PdfReader(utf8.encode(defaultAppearance)); - reader.position = 0; - bool symbol = false; - final List operands = []; - String? token = reader.getNextToken(); - if (token == '/') { - symbol = true; - } - while (token != null && token.isNotEmpty) { - if (symbol == true) { - token = reader.getNextToken(); - } - symbol = true; - if (token == 'g') { - colour = PdfColorHelper.fromGray(_parseFloatColour(operands.last!)); - } else if (token == 'rg') { - colour = PdfColor( - (_parseFloatColour(operands.elementAt(operands.length - 3)!) * 255) - .toInt() - .toUnsigned(8), - (_parseFloatColour(operands.elementAt(operands.length - 2)!) * 255) - .toInt() - .toUnsigned(8), - (_parseFloatColour(operands.last!) * 255).toInt().toUnsigned(8), - ); - operands.clear(); - } else if (token == 'k') { - colour = PdfColor.fromCMYK( - _parseFloatColour(operands.elementAt(operands.length - 4)!), - _parseFloatColour(operands.elementAt(operands.length - 3)!), - _parseFloatColour(operands.elementAt(operands.length - 2)!), - _parseFloatColour(operands.last!), - ); - operands.clear(); - } else { - operands.add(token); - } - } - } - return colour; - } - - double _parseFloatColour(String text) { - double number; - try { - number = double.parse(text); - } catch (e) { - number = 0; - } - return number; - } - - PdfStringFormat _assignStringFormat() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - final PdfStringFormat stringFormat = PdfStringFormat(); - stringFormat.lineAlignment = PdfVerticalAlignment.middle; - stringFormat.lineAlignment = - ((flagValue & _getFieldFlagsValue(FieldFlags.multiline)) > 0) - ? PdfVerticalAlignment.top - : PdfVerticalAlignment.middle; - IPdfPrimitive? number; - if (widget.containsKey(PdfDictionaryProperties.q)) { - number = crossTable!.getObject(widget[PdfDictionaryProperties.q]); - } else if (dictionary!.containsKey(PdfDictionaryProperties.q)) { - number = crossTable!.getObject(dictionary![PdfDictionaryProperties.q]); - } - if (number != null && number is PdfNumber) { - stringFormat.alignment = PdfTextAlignment.values[number.value!.toInt()]; - } - return stringFormat; - } - - PdfBrush? _obtainShadowBrush() { - PdfBrush? brush = PdfBrushes.white; - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.da)) { - PdfColor? color = PdfColor(255, 255, 255); - if (backBrush is PdfSolidBrush) { - color = (backBrush! as PdfSolidBrush).color; - } - color.r = (color.r - 64 >= 0 ? color.r - 64 : 0).toUnsigned(8); - color.g = (color.g - 64 >= 0 ? color.g - 64 : 0).toUnsigned(8); - color.b = (color.b - 64 >= 0 ? color.b - 64 : 0).toUnsigned(8); - brush = PdfSolidBrush(color); - } - return brush; - } - - bool _isCjkFont(String? fontName) { - final List fontString = [ - 'STSong-Light', - 'HeiseiMin-W3', - 'HeiseiKakuGo-W5', - 'HYSMyeongJo-Medium', - 'MSung-Light', - 'MHei-Medium', - 'HYGoThic-Medium', - ]; - for (int i = 0; i < 7; i++) { - if (fontName!.contains(fontString[i])) { - return true; - } - } - return false; - } - - PdfCjkFontFamily? _getCjkFontFamily(String? fontName) { - final List fontString = [ - 'STSong-Light', - 'HeiseiMin-W3', - 'HeiseiKakuGo-W5', - 'HYSMyeongJo-Medium', - 'MSung-Light', - 'MHei-Medium', - 'HYGoThic-Medium', - ]; - String? value; - for (int i = 0; i < 7; i++) { - if (fontName!.contains(fontString[i])) { - value = fontString[i]; - break; - } - } - switch (value) { - case 'STSong-Light': - return PdfCjkFontFamily.sinoTypeSongLight; - case 'HeiseiMin-W3': - return PdfCjkFontFamily.heiseiMinchoW3; - case 'HeiseiKakuGo-W5': - return PdfCjkFontFamily.heiseiKakuGothicW5; - case 'HYSMyeongJo-Medium': - return PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium; - case 'MSung-Light': - return PdfCjkFontFamily.monotypeSungLight; - case 'MHei-Medium': - return PdfCjkFontFamily.monotypeHeiMedium; - case 'HYGoThic-Medium': - return PdfCjkFontFamily.hanyangSystemsGothicMedium; - } - return null; - } - - Map _fontName(String fontString) { - if (fontString.contains('#2C')) { - fontString = fontString.replaceAll('#2C', ','); - } - final PdfReader reader = PdfReader(utf8.encode(fontString)); - reader.position = 0; - String? prevToken = reader.getNextToken(); - String? token = reader.getNextToken(); - String? name; - double height = 0; - while (token != null && token.isNotEmpty) { - name = prevToken; - prevToken = token; - token = reader.getNextToken(); - if (token == PdfOperators.setFont) { - try { - height = double.parse(prevToken); - } catch (e) { - height = 0; - } - break; - } - } - return {'name': name, 'height': height}; - } - - //Gets the font style - List _getFontStyle(String fontFamilyString) { - String standardName = fontFamilyString; - int position = standardName.indexOf('-'); - if (position >= 0) { - standardName = standardName.substring(position + 1, standardName.length); - } - position = standardName.indexOf(','); - if (position >= 0) { - standardName = standardName.substring(position + 1, standardName.length); - } - List style = [PdfFontStyle.regular]; - if (position >= 0) { - switch (standardName) { - case 'Italic': - case 'Oblique': - case 'ItalicMT': - case 'It': - style = [PdfFontStyle.italic]; - break; - case 'Bold': - case 'BoldMT': - style = [PdfFontStyle.bold]; - break; - case 'BoldItalic': - case 'BoldOblique': - case 'BoldItalicMT': - style = [PdfFontStyle.italic, PdfFontStyle.bold]; - break; - } - } - return style; - } - - Map _getFontFamily(String fontFamilyString) { - String? standardName; - final int position = fontFamilyString.indexOf('-'); - PdfFontFamily fontFamily = PdfFontFamily.helvetica; - standardName = fontFamilyString; - if (position >= 0) { - standardName = fontFamilyString.substring(0, position); - } - if (standardName == 'Times') { - fontFamily = PdfFontFamily.timesRoman; - standardName = null; - } - final List fontFamilyList = [ - 'Helvetica', - 'Courier', - 'TimesRoman', - 'Symbol', - 'ZapfDingbats', - ]; - if (standardName != null && fontFamilyList.contains(standardName)) { - fontFamily = PdfFontFamily.values[fontFamilyList.indexOf(standardName)]; - standardName = null; - } - return { - 'fontFamily': fontFamily, - 'standardName': standardName, - }; - } - - PdfFont _updateFontEncoding(PdfFont font, PdfDictionary fontDictionary) { - final PdfDictionary? fontInternalDictionary = - PdfFontHelper.getHelper(font).fontInternals as PdfDictionary?; - if (fontDictionary.items!.containsKey( - PdfName(PdfDictionaryProperties.encoding), - )) { - final PdfName encodingName = PdfName(PdfDictionaryProperties.encoding); - final IPdfPrimitive? encodingReferenceHolder = - fontDictionary.items![PdfName(PdfDictionaryProperties.encoding)]; - if (encodingReferenceHolder != null && - encodingReferenceHolder is PdfReferenceHolder) { - final IPdfPrimitive? dictionary = encodingReferenceHolder.object; - if (dictionary != null && dictionary is PdfDictionary) { - if (fontInternalDictionary!.items!.containsKey( - PdfName(PdfDictionaryProperties.encoding), - )) { - fontInternalDictionary.items!.remove( - PdfName(PdfDictionaryProperties.encoding), - ); - } - fontInternalDictionary.items![encodingName] = dictionary; - } - } else { - final IPdfPrimitive? encodingDictionary = - fontDictionary.items![PdfName(PdfDictionaryProperties.encoding)]; - if (encodingDictionary != null && encodingDictionary is PdfDictionary) { - if (fontInternalDictionary!.items!.containsKey( - PdfName(PdfDictionaryProperties.encoding), - )) { - fontInternalDictionary.items!.remove( - PdfName(PdfDictionaryProperties.encoding), - ); - } - fontInternalDictionary.items![encodingName] = encodingDictionary; - } - } - } - return font; - } - - /// internal method - void setFittingFontSize( - GraphicsProperties gp, - PaintParams prms, - String text, - ) { - double fontSize = 0; - final double width = - prms.style == PdfBorderStyle.beveled || - prms.style == PdfBorderStyle.inset - ? gp.bounds!.width - 8 * prms.borderWidth! - : gp.bounds!.width - 4 * prms.borderWidth!; - final double height = gp.bounds!.height - 2 * gp.borderWidth!; - const double minimumFontSize = 0.248; - if (text.endsWith(' ')) { - gp.stringFormat!.measureTrailingSpaces = true; - } - for (double i = 0; i <= gp.bounds!.height; i++) { - PdfFontHelper.getHelper(gp.font!).setSize(i); - Size textSize = gp.font!.measureString(text, format: gp.stringFormat); - if (textSize.width > gp.bounds!.width || textSize.height > height) { - fontSize = i; - do { - fontSize = fontSize - 0.001; - PdfFontHelper.getHelper(gp.font!).setSize(fontSize); - final double textWidth = PdfFontHelper.getLineWidth( - gp.font!, - text, - gp.stringFormat, - ); - if (fontSize < minimumFontSize) { - PdfFontHelper.getHelper(gp.font!).setSize(minimumFontSize); - break; - } - textSize = gp.font!.measureString(text, format: gp.stringFormat); - if (textWidth < width && textSize.height < height) { - PdfFontHelper.getHelper(gp.font!).setSize(fontSize); - break; - } - } while (fontSize > minimumFontSize); - break; - } - } - } - - /// internal method - double getFontHeight(PdfFontFamily family) { - return 0; - } - - /// internal method - void beginMarkupSequence(PdfStream stream) { - stream.write('/'); - stream.write('Tx'); - stream.write(' '); - stream.write('BMC'); - stream.write('\r\n'); - } - - /// internal method - void endMarkupSequence(PdfStream stream) { - stream.write('EMC'); - stream.write('\r\n'); - } - - /// internal method - void drawStateItem( - PdfGraphics graphics, - PdfCheckFieldState state, - PdfCheckFieldBase? item, [ - PdfFieldItem? fieldItem, - ]) { - final GraphicsProperties gp = - item != null - ? GraphicsProperties(item) - : GraphicsProperties.fromFieldItem(fieldItem!); - if (!flattenField) { - gp.bounds = Rect.fromLTWH(0, 0, gp.bounds!.width, gp.bounds!.height); - } - if (gp.borderPen != null && gp.borderWidth == 0) { - gp.borderWidth = 1; - } - graphics.save(); - final PaintParams prms = PaintParams( - bounds: gp.bounds, - backBrush: gp.backBrush, - foreBrush: gp.foreBrush, - borderPen: gp.borderPen, - style: gp.style, - borderWidth: gp.borderWidth, - shadowBrush: gp.shadowBrush, - ); - if (fieldChanged == true) { - _drawFields(graphics, gp, prms, state); - } else { - PdfGraphicsHelper.getHelper( - graphics, - ).streamWriter!.setTextRenderingMode(0); - final PdfTemplate? stateTemplate = _getStateTemplate( - state, - item != null - ? PdfFieldHelper.getHelper(item).dictionary! - : PdfFieldItemHelper.getHelper(fieldItem!).dictionary!, - ); - if (stateTemplate != null) { - final Rect bounds = - item == null && fieldItem == null - ? field.bounds - : item != null - ? item.bounds - : fieldItem!.bounds; - bool encryptedContent = false; - if (crossTable != null && - crossTable!.document != null && - PdfDocumentHelper.getHelper( - crossTable!.document!, - ).isLoadedDocument) { - final PdfDocument? loadedDocument = crossTable!.document; - if (loadedDocument != null && - PdfDocumentHelper.getHelper(loadedDocument).isEncrypted) { - if (PdfSecurityHelper.getHelper( - loadedDocument.security, - ).encryptor.isEncrypt! && - loadedDocument.security.encryptionOptions == - PdfEncryptionOptions.encryptAllContents) { - encryptedContent = true; - } - } - } - final PdfStream pdfStream = - PdfTemplateHelper.getHelper(stateTemplate).content; - if (encryptedContent && - pdfStream.encrypt! && - !pdfStream.decrypted! && - field is PdfCheckBoxField) { - gp.font = null; - FieldPainter().drawCheckBox( - graphics, - prms, - PdfCheckFieldBaseHelper.getHelper( - field as PdfCheckBoxField, - ).styleToString((field as PdfCheckBoxField).style), - state, - gp.font, - ); - } else { - graphics.drawPdfTemplate(stateTemplate, bounds.topLeft, bounds.size); - } - } else { - _drawFields(graphics, gp, prms, state); - } - } - graphics.restore(); - } - - PdfTemplate? _getStateTemplate( - PdfCheckFieldState state, - PdfDictionary? itemDictionary, - ) { - final PdfDictionary dic = itemDictionary ?? dictionary!; - final String? value = - state == PdfCheckFieldState.checked - ? getItemValue(dic, crossTable) - : PdfDictionaryProperties.off; - PdfTemplate? template; - if (dic.containsKey(PdfDictionaryProperties.ap)) { - final IPdfPrimitive? appearance = PdfCrossTable.dereference( - dic[PdfDictionaryProperties.ap], - ); - if (appearance != null && appearance is PdfDictionary) { - final IPdfPrimitive? norm = PdfCrossTable.dereference( - appearance[PdfDictionaryProperties.n], - ); - if (value != null && - value.isNotEmpty && - norm != null && - norm is PdfDictionary) { - final IPdfPrimitive? xObject = PdfCrossTable.dereference(norm[value]); - if (xObject != null && xObject is PdfStream) { - template = PdfTemplateHelper.fromPdfStream(xObject); - if (value == PdfDictionaryProperties.off && - xObject.encrypt! && - xObject.decrypted!) { - //AP stream undecrypted might cause document corruption - template = null; - } - } - } - } - } - return template; - } - - void _drawFields( - PdfGraphics graphics, - GraphicsProperties gp, - PaintParams params, - PdfCheckFieldState state, - ) { - if (gp.font!.size >= 0) { - gp.font = null; - } - if (field is PdfCheckBoxField) { - FieldPainter().drawCheckBox( - graphics, - params, - PdfCheckBoxFieldHelper.getHelper( - field as PdfCheckBoxField, - ).styleToString((field as PdfCheckBoxField).style), - state, - gp.font, - ); - } else if (field is PdfRadioButtonListItem) { - FieldPainter().drawRadioButton( - graphics, - params, - PdfRadioButtonListItemHelper.getHelper( - field as PdfRadioButtonListItem, - ).styleToString((field as PdfRadioButtonListItem).style), - state, - ); - } - } - - /// internal method - void importFieldValue(Object fieldValue) { - final IPdfPrimitive? primitive = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.ft, - true, - ); - String? value; - if (fieldValue is String) { - value = fieldValue; - } - List? valueArray; - if (value == null) { - valueArray = fieldValue as List; - if (valueArray.isNotEmpty) { - value = fieldValue[0]; - } - } - if (value != null && primitive != null && primitive is PdfName) { - switch (primitive.name) { - case 'Tx': - (field as PdfTextBoxField).text = value; - break; - case 'Ch': - if (field is PdfListBoxField) { - (field as PdfListBoxField).selectedValues = - valueArray ?? [value]; - } else if (field is PdfComboBoxField) { - (field as PdfComboBoxField).selectedValue = value; - } - break; - case 'Btn': - if (field is PdfCheckBoxField) { - final PdfCheckBoxField field1 = field as PdfCheckBoxField; - if (value.toUpperCase() == 'OFF' || value.toUpperCase() == 'NO') { - field1.isChecked = false; - } else if (value.toUpperCase() == 'ON' || - value.toUpperCase() == 'YES') { - field1.isChecked = true; - } else if (_containsExportValue( - value, - field1._fieldHelper.dictionary!, - )) { - field1.isChecked = true; - } else if (field1.items != null && field1.items!.count > 0) { - bool isChecked = false; - for (int i = 0; i < field1.items!.count; i++) { - if (_containsExportValue( - value, - PdfFieldItemHelper.getHelper(field1.items![i]).dictionary!, - )) { - (field1.items![i] as PdfCheckBoxItem).checked = true; - isChecked = true; - } - } - if (!isChecked) { - field1.isChecked = false; - } - } else { - field1.isChecked = false; - } - } else if (field is PdfRadioButtonListField) { - (field as PdfRadioButtonListField).selectedValue = value; - } - break; - } - } - } - - void _assignBorderStyle(PdfBorderStyle? borderStyle) { - String style = ''; - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.bs)) { - switch (borderStyle) { - case PdfBorderStyle.dashed: - case PdfBorderStyle.dot: - style = 'D'; - break; - case PdfBorderStyle.beveled: - style = 'B'; - break; - case PdfBorderStyle.inset: - style = 'I'; - break; - case PdfBorderStyle.underline: - style = 'U'; - break; - // ignore: no_default_cases - default: - style = 'S'; - break; - } - if (widget[PdfDictionaryProperties.bs] is PdfReferenceHolder) { - final PdfDictionary widgetDict = - crossTable!.getObject(widget[PdfDictionaryProperties.bs])! - as PdfDictionary; - if (widgetDict.containsKey(PdfDictionaryProperties.s)) { - widgetDict[PdfDictionaryProperties.s] = PdfName(style); - } else { - widgetDict.setProperty(PdfDictionaryProperties.s, PdfName(style)); - } - } else { - final PdfDictionary bsDict = - widget[PdfDictionaryProperties.bs]! as PdfDictionary; - if (bsDict.containsKey(PdfDictionaryProperties.s)) { - bsDict[PdfDictionaryProperties.s] = PdfName(style); - } else { - bsDict.setProperty(PdfDictionaryProperties.s, PdfName(style)); - } - } - this.widget!.widgetBorder!.borderStyle = borderStyle!; - } else { - if (!widget.containsKey(PdfDictionaryProperties.bs)) { - this.widget!.widgetBorder!.borderStyle = borderStyle!; - widget.setProperty( - PdfDictionaryProperties.bs, - PdfAnnotationBorderHelper.getHelper( - this.widget!.widgetBorder!, - ).dictionary, - ); - } - } - if (widget.containsKey(PdfDictionaryProperties.mk) && - widget[PdfDictionaryProperties.mk] is PdfDictionary) { - final PdfDictionary mkDict = - widget[PdfDictionaryProperties.mk]! as PdfDictionary; - if (!mkDict.containsKey(PdfDictionaryProperties.bc) && - !mkDict.containsKey(PdfDictionaryProperties.bg)) { - WidgetAnnotationHelper.getHelper(this.widget!) - .widgetAppearance! - .dictionary! - .items! - .forEach((PdfName? key, IPdfPrimitive? value) { - mkDict.setProperty(key, value); - }); - } - } else { - widget.setProperty( - PdfDictionaryProperties.mk, - WidgetAnnotationHelper.getHelper(this.widget!).widgetAppearance, - ); - } - } - - PdfHighlightMode _obtainHighlightMode() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfHighlightMode mode = PdfHighlightMode.noHighlighting; - if (widget.containsKey(PdfDictionaryProperties.h)) { - final PdfName name = widget[PdfDictionaryProperties.h]! as PdfName; - switch (name.name) { - case 'I': - mode = PdfHighlightMode.invert; - break; - case 'N': - mode = PdfHighlightMode.noHighlighting; - break; - case 'O': - mode = PdfHighlightMode.outline; - break; - case 'P': - mode = PdfHighlightMode.push; - break; - } - } - return mode; - } - - bool _containsExportValue(String value, PdfDictionary dictionary) { - bool result = false; - final PdfDictionary widgetDictionary = getWidgetAnnotation( - dictionary, - crossTable, - ); - if (widgetDictionary.containsKey(PdfDictionaryProperties.ap)) { - final IPdfPrimitive? appearance = crossTable!.getObject( - widgetDictionary[PdfDictionaryProperties.ap], - ); - if (appearance != null && - appearance is PdfDictionary && - appearance.containsKey(PdfDictionaryProperties.n)) { - final IPdfPrimitive? normalTemplate = PdfCrossTable.dereference( - appearance[PdfDictionaryProperties.n], - ); - if (normalTemplate != null && - normalTemplate is PdfDictionary && - normalTemplate.containsKey(value)) { - result = true; - } - } - } - return result; - } - - /// internal methods - Map exportField(List bytes, int objectID) { - bool flag = false; - IPdfPrimitive? kids; - if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { - kids = crossTable!.getObject(dictionary![PdfDictionaryProperties.kids]); - if (kids != null && kids is PdfArray) { - for (int i = 0; i < kids.count; i++) { - flag = - flag || - (kids[i] is PdfField && - (kids[i]! as PdfField)._fieldHelper.isLoadedField); - } - } - } - final IPdfPrimitive? name = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.ft, - true, - ); - String? strValue = ''; - if (name != null && name is PdfName) { - switch (name.name) { - case 'Tx': - final IPdfPrimitive? tempName = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.v, - true, - ); - if (tempName != null && tempName is PdfString) { - strValue = tempName.value; - } - break; - case 'Ch': - final IPdfPrimitive? checkBoxPrimitive = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.v, - true, - ); - if (checkBoxPrimitive != null) { - final String? value = getExportValue(field, checkBoxPrimitive); - if (value != null && value.isNotEmpty) { - strValue = value; - } - } - break; - case 'Btn': - final IPdfPrimitive? buttonFieldPrimitive = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.v, - true, - ); - if (buttonFieldPrimitive != null) { - final String? value = getExportValue(field, buttonFieldPrimitive); - if (value != null && value.isNotEmpty) { - strValue = value; - } else if (field is PdfRadioButtonListField || - field is PdfCheckBoxField) { - if (!exportEmptyField) { - strValue = PdfDictionaryProperties.off; - } - } - } else { - if (field is PdfRadioButtonListField) { - strValue = getAppearanceStateValue(field); - } else { - final PdfDictionary holder = getWidgetAnnotation( - dictionary!, - crossTable, - ); - final IPdfPrimitive? holderName = - holder[PdfDictionaryProperties.usageApplication]; - if (holderName != null && holderName is PdfName) { - strValue = holderName.name; - } - } - } - break; - } - if ((strValue != null && strValue.isNotEmpty) || - exportEmptyField || - flag) { - if (flag && kids != null && kids is PdfArray) { - for (int i = 0; i < kids.count; i++) { - final IPdfPrimitive? field = kids[i]; - if (field != null && - field is PdfField && - (field as PdfField)._fieldHelper.isLoadedField && - (field as PdfField).canExport) { - final Map out = (field as PdfField)._fieldHelper - .exportField(bytes, objectID); - bytes = out['bytes'] as List; - objectID = out['objectID'] as int; - } - } - objID = objectID; - objectID++; - final PdfString stringValue = PdfString(strValue!) - ..encode = ForceEncoding.ascii; - final StringBuffer buffer = StringBuffer(); - buffer.write( - '$objID 0 obj< /Kids [', - ); - - for (int i = 0; i < kids.count; i++) { - final PdfField field = kids[i]! as PdfField; - if (field._fieldHelper.isLoadedField && - field.canExport && - field._fieldHelper.objID != 0) { - buffer.write('${field._fieldHelper.objID} 0 R '); - } - } - buffer.write(']>>endobj\n'); - final PdfString builderString = PdfString(buffer.toString()) - ..encode = ForceEncoding.ascii; - bytes.addAll(builderString.value!.codeUnits); - } else { - objID = objectID; - objectID++; - if (field is PdfCheckBoxField || field is PdfRadioButtonListField) { - strValue = '/${strValue!}'; - } else { - final PdfString stringFieldValue = PdfString(strValue!) - ..encode = ForceEncoding.ascii; - strValue = - '<${PdfString.bytesToHex(stringFieldValue.value!.codeUnits)}>'; - } - final PdfString stringFieldName = PdfString(this.name!) - ..encode = ForceEncoding.ascii; - final PdfString buildString = PdfString( - '$objID 0 obj< /V $strValue >>endobj\n', - )..encode = ForceEncoding.ascii; - bytes.addAll(buildString.value!.codeUnits); - } - } - } - return {'bytes': bytes, 'objectID': objectID}; - } - - /// internal method - String? getExportValue(PdfField field, IPdfPrimitive buttonFieldPrimitive) { - String? value; - if (buttonFieldPrimitive is PdfName) { - value = buttonFieldPrimitive.name; - } else if (buttonFieldPrimitive is PdfString) { - value = buttonFieldPrimitive.value; - } else if (buttonFieldPrimitive is PdfArray && - buttonFieldPrimitive.count > 0) { - for (int i = 0; i < buttonFieldPrimitive.count; i++) { - final IPdfPrimitive? primitive = buttonFieldPrimitive[i]; - if (primitive is PdfName) { - value = primitive.name; - break; - } else if (primitive is PdfString) { - value = primitive.value; - break; - } - } - } - if (value != null) { - if (field is PdfRadioButtonListField) { - final PdfRadioButtonListItem? item = field.selectedItem; - if (item != null) { - if (item.value == value || - PdfRadioButtonListItemHelper.getHelper(item).optionValue == - value) { - final String? optionValue = - PdfRadioButtonListItemHelper.getHelper(item).optionValue; - if (optionValue != null && optionValue.isNotEmpty) { - value = optionValue; - } - } - } - } - } - return value; - } - - /// internal method - String getAppearanceStateValue(PdfField field) { - final List holders = field._getWidgetAnnotations( - field._fieldHelper.dictionary!, - field._fieldHelper.crossTable!, - ); - String? value; - for (int i = 0; i < holders.length; i++) { - final IPdfPrimitive? pdfName = - holders[i][PdfDictionaryProperties.usageApplication]; - if (pdfName != null && - pdfName is PdfName && - pdfName.name != PdfDictionaryProperties.off) { - value = pdfName.name; - } - } - if (value == null && exportEmptyField) { - value = ''; - } - return value ?? PdfDictionaryProperties.off; - } - - /// internal method - XmlElement? exportFieldForXml() { - final IPdfPrimitive? name = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.ft, - true, - ); - String fieldName = this.name!.replaceAll(' ', '_x0020_'); - fieldName = fieldName - .replaceAll(r'\', '_x005C_') - .replaceAll(']', '_x005D_') - .replaceAll('[', '_x005B_') - .replaceAll(',', '_x002C_') - .replaceAll('"', '_x0022_') - .replaceAll(':', '_x003A_') - .replaceAll('{', '_x007B_') - .replaceAll('}', '_x007D_') - .replaceAll('#', '_x0023_') - .replaceAll(r'$', '_x0024_'); - XmlElement? element; - if (name != null && name is PdfName) { - switch (name.name) { - case 'Tx': - final IPdfPrimitive? str = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.v, - true, - ); - if ((str != null && str is PdfString) || exportEmptyField) { - element = XmlElement(XmlName(fieldName)); - if (str != null && str is PdfString) { - element.innerText = str.value!; - } else if (exportEmptyField) { - element.innerText = ''; - } - } - break; - case 'Ch': - final IPdfPrimitive? str = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.v, - true, - ); - if (str != null && str is PdfName) { - final XmlElement element = XmlElement(XmlName(fieldName)); - element.innerText = str.name!; - } else if ((str != null && str is PdfString) || exportEmptyField) { - element = XmlElement(XmlName(fieldName)); - if (str != null && str is PdfString) { - element.innerText = str.value!; - } else if (exportEmptyField) { - element.innerText = ''; - } - } - break; - case 'Btn': - final IPdfPrimitive? buttonFieldPrimitive = PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.v, - true, - ); - if (buttonFieldPrimitive != null) { - final String? value = getExportValue(field, buttonFieldPrimitive); - if ((value != null && value.isNotEmpty) || exportEmptyField) { - element = XmlElement(XmlName(fieldName)); - if (value != null) { - element.innerText = value; - } else if (exportEmptyField) { - element.innerText = ''; - } - } else if (field is PdfRadioButtonListField || - field is PdfCheckBoxField) { - element = XmlElement(XmlName(fieldName)); - if (exportEmptyField) { - element.innerText = ''; - } else { - element.innerText = PdfDictionaryProperties.off; - } - } - } else { - if (field is PdfRadioButtonListField) { - element = XmlElement(XmlName(fieldName)); - element.innerText = getAppearanceStateValue( - field as PdfRadioButtonListField, - ); - } else { - final PdfDictionary holder = getWidgetAnnotation( - dictionary!, - crossTable, - ); - if ((holder[PdfDictionaryProperties.usageApplication] - is PdfName) || - exportEmptyField) { - final IPdfPrimitive? holderName = - holder[PdfDictionaryProperties.usageApplication]; - element = XmlElement(XmlName(fieldName)); - if (holderName != null && holderName is PdfName) { - element.innerText = holderName.name!; - } else if (exportEmptyField) { - element.innerText = ''; - } - } - } - } - break; - } - } - return element; - } - - /// internal method - PdfArray? obtainKids() { - IPdfPrimitive? kids; - if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { - kids = crossTable!.getObject(dictionary![PdfDictionaryProperties.kids]); - } - return kids != null && kids is PdfArray ? kids : null; - } - - /// internal method - void save() { - if (field.readOnly || (field.form != null && field.form!.readOnly)) { - flags.add(FieldFlags.readOnly); - } - setFlags(flags); - if (page != null && - page!.formFieldsTabOrder == PdfFormFieldsTabOrder.manual) { - page!.annotations.remove(widget!); - PdfAnnotationCollectionHelper.getHelper( - page!.annotations, - ).annotations.insert(field.tabIndex, PdfReferenceHolder(widget)); - PdfObjectCollectionHelper.getHelper( - page!.annotations, - ).list.insert(field.tabIndex, widget!); - } - if (form != null && - !PdfFormHelper.getHelper(form!).needAppearances! && - PdfAnnotationHelper.getHelper(widget!).appearance == null) { - widget!.setAppearance = true; - drawAppearance(widget!.appearance.normal); - } - } - - /// internal method - String? getItemValue(PdfDictionary dictionary, PdfCrossTable? crossTable) { - String? value = ''; - PdfName? name; - if (dictionary.containsKey(PdfDictionaryProperties.usageApplication)) { - name = - crossTable!.getObject( - dictionary[PdfDictionaryProperties.usageApplication], - ) - as PdfName?; - if (name != null && name.name != PdfDictionaryProperties.off) { - value = PdfName.decodeName(name.name); - } - } - if (value!.isEmpty) { - if (dictionary.containsKey(PdfDictionaryProperties.ap)) { - final PdfDictionary dic = - crossTable!.getObject(dictionary[PdfDictionaryProperties.ap])! - as PdfDictionary; - if (dic.containsKey(PdfDictionaryProperties.n)) { - final PdfReference reference = crossTable.getReference( - dic[PdfDictionaryProperties.n], - ); - final PdfDictionary normalAppearance = - crossTable.getObject(reference)! as PdfDictionary; - final List list = []; - normalAppearance.items!.forEach((PdfName? key, IPdfPrimitive? value) { - list.add(key); - }); - for (int i = 0; i < list.length; ++i) { - name = list[i] as PdfName?; - if (name!.name != PdfDictionaryProperties.off) { - value = PdfName.decodeName(name.name); - break; - } - } - } - } - } - return value; - } - - /// internal method - void removeAnnotationFromPage([PdfPage? page]) { - page ??= this.page; - if (page != null) { - if (!PdfPageHelper.getHelper(page).isLoadedPage) { - page.annotations.remove(widget!); - } else { - final PdfDictionary pageDic = PdfPageHelper.getHelper(page).dictionary!; - final PdfArray annots = - pageDic.containsKey(PdfDictionaryProperties.annots) - ? PdfPageHelper.getHelper(page).crossTable!.getObject( - pageDic[PdfDictionaryProperties.annots], - )! - as PdfArray - : PdfArray(); - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - widget!, - ); - helper.dictionary!.setProperty( - PdfDictionaryProperties.p, - PdfReferenceHolder(page), - ); - for (int i = 0; i < annots.count; i++) { - final IPdfPrimitive? obj = annots[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object is PdfDictionary && - obj.object == helper.dictionary) { - annots.remove(obj); - break; - } - } - PdfPageHelper.getHelper( - page, - ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); - } - } - } - - PdfPen? _obtainBorderPen() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfPen? pen; - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final IPdfPrimitive? mk = crossTable!.getObject( - widget[PdfDictionaryProperties.mk], - ); - if (mk is PdfDictionary && mk.containsKey(PdfDictionaryProperties.bc)) { - final PdfArray array = - crossTable!.getObject(mk[PdfDictionaryProperties.bc])! as PdfArray; - pen = PdfPen(_createColor(array)); - } - } - if (pen != null) { - pen.width = borderWidth.toDouble(); - if (borderStyle == PdfBorderStyle.dashed) { - final List? dashPatern = _obtainDashPatern(); - pen.dashStyle = PdfDashStyle.custom; - if (dashPatern != null) { - pen.dashPattern = dashPatern; - } else if (borderWidth > 0) { - pen.dashPattern = [3 / borderWidth]; - } - } - } - return (pen == null) ? bPen : pen; - } - - List? _obtainDashPatern() { - List? array; - if (borderStyle == PdfBorderStyle.dashed) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.d)) { - final IPdfPrimitive? dashes = crossTable!.getObject( - widget[PdfDictionaryProperties.d], - ); - if (dashes != null && dashes is PdfArray) { - if (dashes.count == 2) { - array = [0, 0]; - IPdfPrimitive? number = dashes[0]; - if (number != null && number is PdfNumber) { - array[0] = number.value!.toDouble(); - } - number = dashes[1]; - if (number != null && number is PdfNumber) { - array[1] = number.value!.toDouble(); - } - } else { - array = [0]; - final IPdfPrimitive? number = dashes[0]; - if (number != null && number is PdfNumber) { - array[0] = number.value!.toDouble(); - } - } - } - } - } - return array; - } - - /// internal method - void _assignHighlightMode(PdfHighlightMode? highlightMode) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - widget.setName( - PdfName(PdfDictionaryProperties.h), - WidgetAnnotationHelper.getHelper( - this.widget!, - ).highlightModeToString(highlightMode), - ); - changed = true; - } - - /// internal method - Rect getBounds() { - IPdfPrimitive? array; - if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.rect)) { - array = crossTable!.getObject(widget[PdfDictionaryProperties.rect]); - } - } else { - if (dictionary!.containsKey(PdfDictionaryProperties.parent)) { - final IPdfPrimitive? parentDictionary = - (dictionary![PdfDictionaryProperties.parent]! as PdfReferenceHolder) - .object; - if (parentDictionary != null && - parentDictionary is PdfDictionary && - parentDictionary.containsKey(PdfDictionaryProperties.kids)) { - if (parentDictionary.containsKey(PdfDictionaryProperties.ft) && - (parentDictionary[PdfDictionaryProperties.ft]! as PdfName).name == - PdfDictionaryProperties.btn) { - final PdfDictionary widget = getWidgetAnnotation( - parentDictionary, - crossTable, - ); - if (widget.containsKey(PdfDictionaryProperties.rect)) { - array = crossTable!.getObject( - widget[PdfDictionaryProperties.rect], - ); - } - } - } - } - if (array == null && - dictionary!.containsKey(PdfDictionaryProperties.rect)) { - array = crossTable!.getObject( - dictionary![PdfDictionaryProperties.rect], - ); - } - } - Rect bounds; - if (array != null && array is PdfArray) { - bounds = array.toRectangle().rect; - double y = 0.0; - - final value1 = (PdfCrossTable.dereference(array[1])! as PdfNumber).value!; - final value3 = (PdfCrossTable.dereference(array[3])! as PdfNumber).value!; - - final value1Double = value1.toDouble(); - final value3Double = value3.toDouble(); - - if (value1Double < 0) { - y = value1Double; - - if (value1Double > value3Double) { - y = y - bounds.height; - } - } - bounds = Rect.fromLTWH( - bounds.left, - y <= 0 ? bounds.top : y, - bounds.width, - bounds.height, - ); - } else { - bounds = Rect.zero; - } - return bounds; - } - - /// internal method - PdfColor getBackColor() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - PdfColor c = PdfColor.empty; - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final IPdfPrimitive? bs = crossTable!.getObject( - widget[PdfDictionaryProperties.mk], - ); - if (bs is PdfDictionary) { - IPdfPrimitive? array; - if (bs.containsKey(PdfDictionaryProperties.bg)) { - array = bs[PdfDictionaryProperties.bg]; - } else if (bs.containsKey(PdfDictionaryProperties.bs)) { - array = bs[PdfDictionaryProperties.bs]; - } - if (array != null && array is PdfArray) { - c = _createColor(array); - } - } - } - return c; - } - - PdfColor _createColor(PdfArray array) { - final int dim = array.count; - PdfColor color = PdfColor.empty; - final List colors = []; - for (int i = 0; i < array.count; ++i) { - final PdfNumber number = crossTable!.getObject(array[i])! as PdfNumber; - colors.add(number.value!.toDouble()); - } - switch (dim) { - case 1: - color = - (colors[0] > 0.0) && (colors[0] <= 1.0) - ? PdfColorHelper.fromGray(colors[0]) - : PdfColorHelper.fromGray( - colors[0].toInt().toUnsigned(8).toDouble(), - ); - break; - case 3: - color = - ((colors[0] > 0.0) && (colors[0] <= 1.0)) || - ((colors[1] > 0.0) && (colors[1] <= 1.0)) || - ((colors[2] > 0.0) && (colors[2] <= 1.0)) - ? PdfColor( - (colors[0] * 255).toInt().toUnsigned(8), - (colors[1] * 255).toInt().toUnsigned(8), - (colors[2] * 255).toInt().toUnsigned(8), - ) - : PdfColor( - colors[0].toInt().toUnsigned(8), - colors[1].toInt().toUnsigned(8), - colors[2].toInt().toUnsigned(8), - ); - break; - case 4: - color = - ((colors[0] > 0.0) && (colors[0] <= 1.0)) || - ((colors[1] > 0.0) && (colors[1] <= 1.0)) || - ((colors[2] > 0.0) && (colors[2] <= 1.0)) || - ((colors[3] > 0.0) && (colors[3] <= 1.0)) - ? PdfColor.fromCMYK(colors[0], colors[1], colors[2], colors[3]) - : PdfColor.fromCMYK( - colors[0].toInt().toUnsigned(8).toDouble(), - colors[1].toInt().toUnsigned(8).toDouble(), - colors[2].toInt().toUnsigned(8).toDouble(), - colors[3].toInt().toUnsigned(8).toDouble(), - ); - break; - } - return color; - } - - /// internal method - void assignBackColor(PdfColor? value) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final PdfDictionary mk = - (crossTable != null - ? crossTable!.getObject(widget[PdfDictionaryProperties.mk]) - : PdfCrossTable.dereference( - widget[PdfDictionaryProperties.mk], - ))! - as PdfDictionary; - final PdfArray array = PdfColorHelper.toArray(value!); - mk[PdfDictionaryProperties.bg] = array; - } else { - final PdfDictionary mk = PdfDictionary(); - final PdfArray array = PdfColorHelper.toArray(value!); - mk[PdfDictionaryProperties.bg] = array; - widget[PdfDictionaryProperties.mk] = mk; - } - PdfFormHelper.getHelper(field.form!).setAppearanceDictionary = true; - } - - /// internal method - void assignBorderColor(PdfColor borderColor) { - if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { - final IPdfPrimitive? kids = crossTable!.getObject( - dictionary![PdfDictionaryProperties.kids], - ); - if (kids != null && kids is PdfArray) { - for (int i = 0; i < kids.count; i++) { - final IPdfPrimitive? widget = PdfCrossTable.dereference(kids[i]); - if (widget != null && widget is PdfDictionary) { - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final IPdfPrimitive? mk = - crossTable != null - ? crossTable!.getObject( - widget[PdfDictionaryProperties.mk], - ) - : PdfCrossTable.dereference( - widget[PdfDictionaryProperties.mk], - ); - if (mk != null && mk is PdfDictionary) { - final PdfArray array = PdfColorHelper.toArray(borderColor); - if (PdfColorHelper.getHelper(borderColor).alpha == 0) { - mk[PdfDictionaryProperties.bc] = PdfArray([]); - } else { - mk[PdfDictionaryProperties.bc] = array; - } - } - } else { - final PdfDictionary mk = PdfDictionary(); - final PdfArray array = PdfColorHelper.toArray(borderColor); - if (PdfColorHelper.getHelper(borderColor).alpha == 0) { - mk[PdfDictionaryProperties.bc] = PdfArray([]); - } else { - mk[PdfDictionaryProperties.bc] = array; - } - widget[PdfDictionaryProperties.mk] = mk; - } - } - } - } - } else { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final IPdfPrimitive? mk = - crossTable != null - ? crossTable!.getObject(widget[PdfDictionaryProperties.mk]) - : PdfCrossTable.dereference(widget[PdfDictionaryProperties.mk]); - if (mk != null && mk is PdfDictionary) { - final PdfArray array = PdfColorHelper.toArray(borderColor); - if (PdfColorHelper.getHelper(borderColor).alpha == 0) { - mk[PdfDictionaryProperties.bc] = PdfArray([]); - } else { - mk[PdfDictionaryProperties.bc] = array; - } - } - } else { - final PdfDictionary mk = PdfDictionary(); - final PdfArray array = PdfColorHelper.toArray(borderColor); - if (PdfColorHelper.getHelper(borderColor).alpha == 0) { - mk[PdfDictionaryProperties.bc] = PdfArray([]); - } else { - mk[PdfDictionaryProperties.bc] = array; - } - widget[PdfDictionaryProperties.mk] = mk; - } - } - } - - int _obtainBorderWidth() { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - int width = 0; - final IPdfPrimitive? name = crossTable!.getObject( - widget[PdfDictionaryProperties.ft], - ); - if (widget.containsKey(PdfDictionaryProperties.bs)) { - width = 1; - final PdfDictionary bs = - crossTable!.getObject(widget[PdfDictionaryProperties.bs])! - as PdfDictionary; - final IPdfPrimitive? number = crossTable!.getObject( - bs[PdfDictionaryProperties.w], - ); - if (number != null && number is PdfNumber) { - width = number.value!.toInt(); - } - } else if (name != null && name is PdfName && name.name == 'Btn') { - width = 1; - } - return width; - } - - void _assignBorderWidth(int width) { - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - if (widget.containsKey(PdfDictionaryProperties.bs)) { - if (widget[PdfDictionaryProperties.bs] is PdfReferenceHolder) { - final PdfDictionary widgetDict = - crossTable!.getObject(widget[PdfDictionaryProperties.bs])! - as PdfDictionary; - if (widgetDict.containsKey(PdfDictionaryProperties.w)) { - widgetDict[PdfDictionaryProperties.w] = PdfNumber(width); - } else { - widgetDict.setProperty(PdfDictionaryProperties.w, PdfNumber(width)); - } - } else { - (widget[PdfDictionaryProperties.bs]! - as PdfDictionary)[PdfDictionaryProperties.w] = PdfNumber(width); - } - _createBorderPen(); - } else { - if (!widget.containsKey(PdfDictionaryProperties.bs)) { - widget.setProperty( - PdfDictionaryProperties.bs, - PdfAnnotationBorderHelper.getHelper( - this.widget!.widgetBorder!, - ).dictionary, - ); - (widget[PdfDictionaryProperties.bs]! as PdfDictionary).setProperty( - PdfDictionaryProperties.w, - PdfNumber(width), - ); - _createBorderPen(); - } - } - } - - //Creates the border pen. - void _createBorderPen() { - final double width = widget!.widgetBorder!.width; - borderPen = PdfPen( - WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.borderColor, - width: width, - ); - if (widget!.widgetBorder!.borderStyle == PdfBorderStyle.dashed || - widget!.widgetBorder!.borderStyle == PdfBorderStyle.dot) { - borderPen!.dashStyle = PdfDashStyle.custom; - borderPen!.dashPattern = [3 / width]; - } - } - - /// internal method - static PdfFieldHelper getHelper(PdfField field) { - return field._fieldHelper; - } - - /// internal method - void dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (dictionary!.containsKey(PdfDictionaryProperties.kids) && - dictionary!.containsKey(PdfDictionaryProperties.tu)) { - final IPdfPrimitive? kids = dictionary![PdfDictionaryProperties.kids]; - if (kids != null && kids is PdfArray) { - for (int i = 0; i < kids.count; i++) { - final IPdfPrimitive? kidsReferenceHolder = kids.elements[i]; - if (kidsReferenceHolder != null && - kidsReferenceHolder is PdfReferenceHolder) { - final IPdfPrimitive? widgetAnnot = kidsReferenceHolder.object; - if (widgetAnnot != null && - widgetAnnot is PdfDictionary && - !widgetAnnot.containsKey(PdfDictionaryProperties.tu)) { - final IPdfPrimitive? toolTip = - dictionary![PdfDictionaryProperties.tu]; - if (toolTip != null && toolTip is PdfString) { - widgetAnnot.setString( - PdfDictionaryProperties.tu, - toolTip.value, - ); - } - } - } - } - } - } - } - - /// Gets the value. - static IPdfPrimitive? getValue( - PdfDictionary dictionary, - PdfCrossTable? crossTable, - String value, - bool inheritable, - ) { - IPdfPrimitive? primitive; - if (dictionary.containsKey(value)) { - primitive = crossTable!.getObject(dictionary[value]); - } else if (inheritable) { - primitive = searchInParents(dictionary, crossTable, value); - } - return primitive; - } - - /// Searches the in parents. - static IPdfPrimitive? searchInParents( - PdfDictionary dictionary, - PdfCrossTable? crossTable, - String value, - ) { - IPdfPrimitive? primitive; - PdfDictionary? dic = dictionary; - while (primitive == null && dic != null) { - if (dic.containsKey(value)) { - primitive = crossTable!.getObject(dic[value]); - } else { - dic = - dic.containsKey(PdfDictionaryProperties.parent) - ? (crossTable!.getObject(dic[PdfDictionaryProperties.parent]) - as PdfDictionary?)! - : null; - } - } - return primitive; - } -} - -/// Represents the graphic properties of field. -class GraphicsProperties { - /// internal constructor - GraphicsProperties(PdfField field) { - bounds = field.bounds; - borderPen = field._fieldHelper.borderPen; - style = field._fieldHelper.borderStyle; - borderWidth = field._fieldHelper.borderWidth; - backBrush = field._fieldHelper.backBrush; - foreBrush = field._fieldHelper.foreBrush; - shadowBrush = field._fieldHelper.shadowBrush; - font = field._fieldHelper.font; - stringFormat = field._fieldHelper.format; - if ((!field._fieldHelper.isLoadedField) && - field.page != null && - field.page!.rotation != PdfPageRotateAngle.rotateAngle0) { - bounds = _rotateTextbox( - field.bounds, - field.page!.size, - field.page!.rotation, - ); - } - } - - /// internal constructor - GraphicsProperties.fromFieldItem(PdfFieldItem item) { - bounds = item.bounds; - final PdfFieldItemHelper helper = PdfFieldItemHelper.getHelper(item); - borderPen = helper.borderPen; - style = helper.borderStyle; - borderWidth = helper.borderWidth; - backBrush = helper.backBrush; - foreBrush = helper.foreBrush; - shadowBrush = helper.shadowBrush; - font = helper.font; - stringFormat = helper.format; - if ((!helper.field._fieldHelper.isLoadedField) && - item.page != null && - item.page!.rotation != PdfPageRotateAngle.rotateAngle0) { - bounds = _rotateTextbox( - item.bounds, - item.page!.size, - item.page!.rotation, - ); - } - } - - //Fields - /// internal field - Rect? bounds; - - /// internal field - PdfBrush? foreBrush; - - /// internal field - PdfBrush? backBrush; - - /// internal field - PdfBrush? shadowBrush; - - /// internal field - int? borderWidth; - - /// internal field - PdfBorderStyle? style; - - /// internal field - PdfPen? borderPen; - - /// internal field - PdfFont? font; - - /// internal field - PdfStringFormat? stringFormat; - - //Implementation - Rect _rotateTextbox(Rect rect, Size? size, PdfPageRotateAngle angle) { - Rect rectangle = rect; - if (angle == PdfPageRotateAngle.rotateAngle180) { - rectangle = Rect.fromLTWH( - size!.width - rect.left - rect.width, - size.height - rect.top - rect.height, - rect.width, - rect.height, - ); - } - if (angle == PdfPageRotateAngle.rotateAngle270) { - rectangle = Rect.fromLTWH( - rect.top, - size!.width - rect.left - rect.width, - rect.height, - rect.width, - ); - } - if (angle == PdfPageRotateAngle.rotateAngle90) { - rectangle = Rect.fromLTWH( - size!.height - rect.top - rect.height, - rect.left, - rect.height, - rect.width, - ); - } - return rectangle; - } -} - -//typedef for NameChanged event handler. -typedef BeforeNameChangesEventHandler = void Function(String name); +import 'dart:convert'; +import 'dart:ui'; +import 'package:xml/xml.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/json_parser.dart'; +import '../annotations/pdf_annotation.dart'; +import '../annotations/pdf_annotation_border.dart'; +import '../annotations/pdf_annotation_collection.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../annotations/widget_annotation.dart'; +import '../general/pdf_collection.dart'; +import '../general/pdf_default_appearance.dart'; +import '../graphics/brushes/pdf_brush.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_cjk_standard_font.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_font_metrics.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/fonts/pdf_string_format.dart'; +import '../graphics/fonts/pdf_true_type_font.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_reader.dart'; +import '../pages/enum.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_collection.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import '../security/enum.dart'; +import '../security/pdf_security.dart'; +import 'enum.dart'; +import 'pdf_check_box_field.dart'; +import 'pdf_combo_box_field.dart'; +import 'pdf_field_item.dart'; +import 'pdf_field_painter.dart'; +import 'pdf_form.dart'; +import 'pdf_list_box_field.dart'; +import 'pdf_radio_button_list_field.dart'; +import 'pdf_signature_field.dart'; +import 'pdf_text_box_field.dart'; + +/// Represents field of the PDF document's interactive form. +abstract class PdfField implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfField] class with the specific page and name. + void _internal( + PdfPage? page, + String? name, + Rect bounds, { + PdfFont? font, + PdfTextAlignment? alignment, + PdfColor? borderColor, + PdfColor? foreColor, + PdfColor? backColor, + int? borderWidth, + PdfHighlightMode? highlightMode, + PdfBorderStyle? borderStyle, + String? tooltip, + PdfFieldHelper? helper, + }) { + _fieldHelper = helper!; + if (this is PdfSignatureField) { + if (page != null && PdfPageHelper.getHelper(page).document != null) { + _fieldHelper.form = PdfPageHelper.getHelper(page).document!.form; + } + } + _initialize(); + if (page != null) { + _fieldHelper.page = page; + } + this.bounds = bounds; + if (name != null) { + _fieldHelper.name = name; + _fieldHelper.dictionary!.setProperty( + PdfDictionaryProperties.t, + PdfString(name), + ); + } + if (font != null) { + _fieldHelper.font = font; + } + if (alignment != null) { + _fieldHelper.textAlignment = alignment; + } + if (borderColor != null) { + _fieldHelper.borderColor = borderColor; + } + if (foreColor != null) { + _fieldHelper.foreColor = foreColor; + } + if (backColor != null) { + _fieldHelper.backColor = backColor; + } + if (borderWidth != null) { + _fieldHelper.borderWidth = borderWidth; + } + if (highlightMode != null) { + _fieldHelper.highlightMode = highlightMode; + } + if (borderStyle != null) { + _fieldHelper.borderStyle = borderStyle; + } + if (tooltip != null) { + this.tooltip = tooltip; + } + if (this is PdfSignatureField) { + _addAnnotationToPage(page, _fieldHelper.widget); + } + } + + /// internal constructor + void _load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + PdfFieldHelper helper, + ) { + _fieldHelper = helper; + _fieldHelper.dictionary = dictionary; + _fieldHelper.crossTable = crossTable; + _fieldHelper.widget = WidgetAnnotation(); + _fieldHelper.isLoadedField = true; + } + + //Fields + late PdfFieldHelper _fieldHelper; + String? _mappingName = ''; + String? _tooltip = ''; + int _tabIndex = 0; + bool _export = false; + + //Properties + /// Gets the form of the [PdfField]. + PdfForm? get form => _fieldHelper.form; + + /// Gets the page of the field. + PdfPage? get page { + if (_fieldHelper.isLoadedField && _fieldHelper.page == null) { + _fieldHelper.page = _getLoadedPage(); + } else if (_fieldHelper.page != null && + PdfPageHelper.getHelper(_fieldHelper.page!).isLoadedPage && + _fieldHelper.changed || + (_fieldHelper.form != null && + PdfFormHelper.getHelper(_fieldHelper.form!).flatten) || + _fieldHelper.flattenField) { + _fieldHelper.page = _getLoadedPage(); + } + return _fieldHelper.page; + } + + /// Gets or sets the name of the [PdfField]. + String? get name { + if (_fieldHelper.isLoadedField && + (_fieldHelper.name == null || _fieldHelper.name!.isEmpty)) { + _fieldHelper.name = _getFieldName(); + } + return _fieldHelper.name; + } + + set name(String? value) => _fieldHelper._setName(value); + + /// Gets or sets a value indicating whether this [PdfField] field is read-only. + /// + /// The default value is false. + bool get readOnly { + if (_fieldHelper.isLoadedField) { + _fieldHelper._readOnly = _fieldHelper.isFlagPresent(FieldFlags.readOnly); + return _fieldHelper._readOnly || form!.readOnly; + } + return _fieldHelper._readOnly; + } + + set readOnly(bool value) { + if (_fieldHelper.isLoadedField) { + value || form!.readOnly + ? _fieldHelper.setFlags([FieldFlags.readOnly]) + : _fieldHelper.removeFlag(FieldFlags.readOnly); + } + _fieldHelper._readOnly = value; + } + + /// Gets or sets the mapping name to be used when exporting interactive form + /// field data from the document. + String get mappingName { + if (_fieldHelper.isLoadedField && + (_mappingName == null || _mappingName!.isEmpty)) { + final IPdfPrimitive? str = PdfFieldHelper.getValue( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + PdfDictionaryProperties.tm, + false, + ); + if (str != null && str is PdfString) { + _mappingName = str.value; + } + } + return _mappingName!; + } + + set mappingName(String value) { + if (_mappingName != value) { + _mappingName = value; + _fieldHelper.dictionary!.setString( + PdfDictionaryProperties.tm, + _mappingName, + ); + } + if (_fieldHelper.isLoadedField) { + _fieldHelper.changed = true; + } + } + + /// Gets or sets the tool tip. + String get tooltip { + if (_fieldHelper.isLoadedField && (_tooltip == null || _tooltip!.isEmpty)) { + final IPdfPrimitive? str = PdfFieldHelper.getValue( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + PdfDictionaryProperties.tu, + false, + ); + if (str != null && str is PdfString) { + _tooltip = str.value; + } + } + return _tooltip!; + } + + set tooltip(String value) { + if (_tooltip != value) { + _tooltip = value; + _fieldHelper.dictionary!.setString(PdfDictionaryProperties.tu, _tooltip); + } + if (_fieldHelper.isLoadedField) { + _fieldHelper.changed = true; + } + } + + /// Gets or sets a value indicating whether the [PdfField] is exportable or not. + /// + /// The default value is true. + bool get canExport { + if (_fieldHelper.isLoadedField) { + _export = + !(_fieldHelper.isFlagPresent(FieldFlags.noExport) || + _fieldHelper.flags.contains(FieldFlags.noExport)); + } + return _export; + } + + set canExport(bool value) { + if (canExport != value) { + _export = value; + _export + ? _fieldHelper.isLoadedField + ? _fieldHelper.removeFlag(FieldFlags.noExport) + : _fieldHelper.flags.remove(FieldFlags.noExport) + : _fieldHelper.flags.add(FieldFlags.noExport); + } + } + + /// Gets or sets the bounds. + Rect get bounds { + if (_fieldHelper.isLoadedField) { + final Rect rect = _fieldHelper.getBounds(); + double x = 0; + double y = 0; + if (page != null) { + final PdfDictionary dictionary = + PdfPageHelper.getHelper(page!).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.cropBox)) { + PdfArray? cropBox; + if (dictionary[PdfDictionaryProperties.cropBox] is PdfArray) { + cropBox = dictionary[PdfDictionaryProperties.cropBox] as PdfArray?; + } else { + final PdfReferenceHolder cropBoxHolder = + dictionary[PdfDictionaryProperties.cropBox]! + as PdfReferenceHolder; + cropBox = cropBoxHolder.object as PdfArray?; + } + if ((cropBox![0]! as PdfNumber).value != 0 || + (cropBox[1]! as PdfNumber).value != 0 || + page!.size.width == (cropBox[2]! as PdfNumber).value || + page!.size.height == (cropBox[3]! as PdfNumber).value) { + x = rect.left - (cropBox[0]! as PdfNumber).value!; + y = (cropBox[3]! as PdfNumber).value! - (rect.top + rect.height); + } else { + y = page!.size.height - (rect.top + rect.height); + } + } else if (dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { + PdfArray? mediaBox; + if (PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.mediaBox], + ) + is PdfArray) { + mediaBox = + PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.mediaBox], + ) + as PdfArray?; + } + if ((mediaBox![0]! as PdfNumber).value! > 0 || + (mediaBox[1]! as PdfNumber).value! > 0 || + page!.size.width == (mediaBox[2]! as PdfNumber).value || + page!.size.height == (mediaBox[3]! as PdfNumber).value) { + x = rect.left - (mediaBox[0]! as PdfNumber).value!; + y = (mediaBox[3]! as PdfNumber).value! - (rect.top + rect.height); + } else { + y = page!.size.height - (rect.top + rect.height); + } + } else { + y = page!.size.height - (rect.top + rect.height); + } + } else { + y = rect.top + rect.height; + } + return Rect.fromLTWH( + x == 0 ? rect.left : x, + y == 0 ? rect.top : y, + rect.width, + rect.height, + ); + } else { + return _fieldHelper.widget!.bounds; + } + } + + set bounds(Rect value) { + if (value.isEmpty && this is! PdfSignatureField) { + ArgumentError("bounds can't be empty."); + } + if (_fieldHelper.isLoadedField) { + final Rect rect = value; + final double height = page!.size.height; + final List values = [ + PdfNumber(rect.left), + PdfNumber(height - (rect.top + rect.height)), + PdfNumber(rect.left + rect.width), + PdfNumber(height - rect.top), + ]; + PdfDictionary dic = _fieldHelper.dictionary!; + if (!dic.containsKey(PdfDictionaryProperties.rect)) { + dic = _fieldHelper.getWidgetAnnotation( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + ); + } + dic.setArray(PdfDictionaryProperties.rect, values); + _fieldHelper.changed = true; + } else { + _fieldHelper.widget!.bounds = value; + } + } + + /// Gets or sets the tab index for form fields. + /// + /// The default value is 0. + int get tabIndex { + if (_fieldHelper.isLoadedField) { + if (page != null) { + final PdfDictionary annotDic = _fieldHelper.getWidgetAnnotation( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + ); + final PdfReference reference = PdfPageHelper.getHelper( + page!, + ).crossTable!.getReference(annotDic); + _tabIndex = PdfPageHelper.getHelper( + page!, + ).annotsReference.indexOf(reference); + } + } + return _tabIndex; + } + + set tabIndex(int value) { + _tabIndex = value; + if (_fieldHelper.isLoadedField && + page != null && + page!.formFieldsTabOrder == PdfFormFieldsTabOrder.manual) { + final PdfAnnotation annotationReference = WidgetAnnotationHelper.load( + _fieldHelper.dictionary!, + _fieldHelper.crossTable!, + ); + final PdfReference reference = PdfPageHelper.getHelper( + page!, + ).crossTable!.getReference(IPdfWrapper.getElement(annotationReference)); + int index = PdfPageHelper.getHelper( + page!, + ).annotsReference.indexOf(reference); + if (index < 0) { + index = _fieldHelper.annotationIndex; + } + final PdfArray? annots = PdfAnnotationCollectionHelper.getHelper( + page!.annotations, + ).rearrange(reference, _tabIndex, index); + PdfPageHelper.getHelper( + page!, + ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); + } + } + + //Public methods + /// Flattens the field. + void flatten() { + _fieldHelper.flattenField = true; + } + + //Implementations + void _initialize() { + _fieldHelper.dictionary!.beginSave = + this is PdfSignatureField + ? _fieldHelper.dictionaryBeginSave + : _dictBeginSave; + _fieldHelper.widget = WidgetAnnotation(); + if (this is PdfSignatureField && form!.fieldAutoNaming) { + _fieldHelper._createBorderPen(); + _fieldHelper._createBackBrush(); + _fieldHelper.dictionary = + PdfAnnotationHelper.getHelper(_fieldHelper.widget!).dictionary; + } else { + _fieldHelper.widget!.parent = this; + if (this is! PdfSignatureField) { + _fieldHelper.format = PdfStringFormat( + alignment: _fieldHelper.widget!.alignment!, + lineAlignment: PdfVerticalAlignment.middle, + ); + _fieldHelper._createBorderPen(); + _fieldHelper._createBackBrush(); + } + final PdfArray array = PdfArray(); + array.add(PdfReferenceHolder(_fieldHelper.widget)); + _fieldHelper.dictionary!.setProperty( + PdfDictionaryProperties.kids, + PdfArray(array), + ); + } + _fieldHelper.widget!.defaultAppearance.fontName = 'TiRo'; + } + + void _dictBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + _fieldHelper.save(); + } + + String? _getFieldName() { + String? name; + PdfString? str; + if (!_fieldHelper.dictionary!.containsKey(PdfDictionaryProperties.parent)) { + str = + PdfFieldHelper.getValue( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + PdfDictionaryProperties.t, + false, + ) + as PdfString?; + } else { + IPdfPrimitive? dic = _fieldHelper.crossTable!.getObject( + _fieldHelper.dictionary![PdfDictionaryProperties.parent], + ); + while (dic != null && + dic is PdfDictionary && + dic.containsKey(PdfDictionaryProperties.parent)) { + if (dic.containsKey(PdfDictionaryProperties.t)) { + name = + name == null + ? (PdfFieldHelper.getValue( + dic, + _fieldHelper.crossTable, + PdfDictionaryProperties.t, + false, + )! + as PdfString) + .value + : '${(PdfFieldHelper.getValue(dic, _fieldHelper.crossTable, PdfDictionaryProperties.t, false)! as PdfString).value!}.$name'; + } + dic = + _fieldHelper.crossTable!.getObject( + dic[PdfDictionaryProperties.parent], + ) + as PdfDictionary?; + } + if (dic != null && + dic is PdfDictionary && + dic.containsKey(PdfDictionaryProperties.t)) { + name = + name == null + ? (PdfFieldHelper.getValue( + dic, + _fieldHelper.crossTable, + PdfDictionaryProperties.t, + false, + )! + as PdfString) + .value + : '${(PdfFieldHelper.getValue(dic, _fieldHelper.crossTable, PdfDictionaryProperties.t, false)! as PdfString).value!}.$name'; + final IPdfPrimitive? strName = PdfFieldHelper.getValue( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + PdfDictionaryProperties.t, + false, + ); + if (strName != null && strName is PdfString) { + name = '${name!}.${strName.value!}'; + } + } else if (_fieldHelper.dictionary!.containsKey( + PdfDictionaryProperties.t, + )) { + str = + PdfFieldHelper.getValue( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + PdfDictionaryProperties.t, + false, + ) + as PdfString?; + } + } + if (str != null) { + name = str.value; + } + return name; + } + + PdfPage? _getLoadedPage() { + PdfPage? page = _fieldHelper.page; + if (page == null || + (PdfPageHelper.getHelper(page).isLoadedPage) && + _fieldHelper.crossTable != null) { + final PdfDocument? doc = _fieldHelper.crossTable!.document; + final PdfDictionary widget = _fieldHelper.getWidgetAnnotation( + _fieldHelper.dictionary!, + _fieldHelper.crossTable, + ); + if (widget.containsKey(PdfDictionaryProperties.p) && + PdfCrossTable.dereference(widget[PdfDictionaryProperties.p]) + is! PdfNull) { + final IPdfPrimitive? pageRef = _fieldHelper.crossTable!.getObject( + widget[PdfDictionaryProperties.p], + ); + if (pageRef != null && pageRef is PdfDictionary) { + page = PdfPageCollectionHelper.getHelper(doc!.pages).getPage(pageRef); + } + } else { + final PdfReference widgetReference = _fieldHelper.crossTable! + .getReference(widget); + for (int j = 0; j < doc!.pages.count; j++) { + final PdfPage loadedPage = doc.pages[j]; + final PdfArray? lAnnots = + PdfPageHelper.getHelper(loadedPage).obtainAnnotations(); + if (lAnnots != null) { + for (int i = 0; i < lAnnots.count; i++) { + final IPdfPrimitive? holder = lAnnots[i]; + if (holder != null && + holder is PdfReferenceHolder && + holder.reference != null) { + if (holder.reference!.objNum == widgetReference.objNum && + holder.reference!.genNum == widgetReference.genNum) { + page = loadedPage; + return page; + } else if (_fieldHelper.requiredReference != null && + _fieldHelper.requiredReference!.reference != null && + _fieldHelper.requiredReference!.reference!.objNum == + holder.reference!.objNum && + _fieldHelper.requiredReference!.reference!.genNum == + holder.reference!.genNum) { + page = loadedPage; + return page; + } + } + } + } + } + } + } + if (page != null && + PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.tabs)) { + final IPdfPrimitive? tabName = PdfCrossTable.dereference( + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties.tabs], + ); + if (tabName != null && + ((tabName is PdfName && tabName.name == '') || + (tabName is PdfString && tabName.value == ''))) { + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .tabs] = PdfName(' '); + } + } + return page; + } + + void _addAnnotationToPage(PdfPage? page, PdfAnnotation? widget) { + if (page != null && !PdfPageHelper.getHelper(page).isLoadedPage) { + PdfAnnotationHelper.getHelper(widget!).dictionary!.setProperty( + PdfDictionaryProperties.t, + PdfString(_fieldHelper.name!), + ); + } else { + final PdfDictionary pageDic = PdfPageHelper.getHelper(page!).dictionary!; + PdfArray? annots; + if (pageDic.containsKey(PdfDictionaryProperties.annots)) { + final IPdfPrimitive? obj = PdfPageHelper.getHelper( + page, + ).crossTable!.getObject(pageDic[PdfDictionaryProperties.annots]); + if (obj != null && obj is PdfArray) { + annots = obj; + } + } + annots ??= PdfArray(); + PdfAnnotationHelper.getHelper(widget!).dictionary!.setProperty( + PdfDictionaryProperties.p, + PdfReferenceHolder(page), + ); + form!.fieldAutoNaming + ? PdfAnnotationHelper.getHelper(widget).dictionary!.setProperty( + PdfDictionaryProperties.t, + PdfString(_fieldHelper.name!), + ) + : _fieldHelper.dictionary!.setProperty( + PdfDictionaryProperties.t, + PdfString(_fieldHelper.name!), + ); + annots.add(PdfReferenceHolder(widget)); + PdfPageHelper.getHelper( + page, + ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); + } + } + + List _getWidgetAnnotations( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final List widgetAnnotationCollection = []; + if (dictionary.containsKey(PdfDictionaryProperties.kids)) { + final IPdfPrimitive? array = crossTable.getObject( + dictionary[PdfDictionaryProperties.kids], + ); + if (array != null && array is PdfArray && array.count > 0) { + for (int i = 0; i < array.count; i++) { + final IPdfPrimitive item = array[i]!; + final PdfReference reference = crossTable.getReference(item); + final IPdfPrimitive? widgetDic = crossTable.getObject(reference); + if (widgetDic != null && widgetDic is PdfDictionary) { + widgetAnnotationCollection.add(widgetDic); + } + } + } + } else if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? type = crossTable.getObject( + dictionary[PdfDictionaryProperties.subtype], + ); + if (type != null && + type is PdfName && + type.name == PdfDictionaryProperties.widget) { + widgetAnnotationCollection.add(dictionary); + } + } + if (widgetAnnotationCollection.isEmpty) { + widgetAnnotationCollection.add(dictionary); + } + return widgetAnnotationCollection; + } +} + +/// [PdfField] helper +class PdfFieldHelper { + /// internal constructor + PdfFieldHelper(this.field); + + /// internal field + late PdfField field; + + /// internal method + void load(PdfDictionary dictionary, PdfCrossTable crossTable) { + field._load(dictionary, crossTable, this); + } + + /// internal method + void internal( + PdfPage? page, + String? name, + Rect bounds, { + PdfFont? font, + PdfTextAlignment? alignment, + PdfColor? borderColor, + PdfColor? foreColor, + PdfColor? backColor, + int? borderWidth, + PdfHighlightMode? highlightMode, + PdfBorderStyle? borderStyle, + String? tooltip, + }) { + field._internal( + page, + name, + bounds, + font: font, + alignment: alignment, + borderColor: borderColor, + foreColor: foreColor, + backColor: backColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + helper: this, + ); + } + + /// internal field + PdfPage? page; + + /// internal field + PdfForm? form; + + /// internal field + WidgetAnnotation? widget; + + /// internal field + PdfStringFormat? stringFormat; + + /// internal field + // ignore: prefer_final_fields + PdfArray array = PdfArray(); + + /// internal field + bool changed = false; + + /// internal field + bool isLoadedField = false; + + /// internal field + // ignore: prefer_final_fields + int defaultIndex = 0; + + /// internal field + PdfCrossTable? crossTable; + + /// internal field + PdfReferenceHolder? requiredReference; + + /// internal field + int? flagValues; + + /// internal field + // ignore: prefer_final_fields + int annotationIndex = 0; + + /// internal field + List? fieldItems; + + /// internal field + // ignore: prefer_final_fields + bool exportEmptyField = false; + + /// internal field + int objID = 0; + + /// internal field + bool flatten = false; + //// ignore: prefer_final_fields + List flags = [FieldFlags.defaultFieldFlag]; + + /// internal field + PdfArray? get kids => obtainKids(); + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal field + // ignore: prefer_final_fields + bool isTextChanged = false; + + /// internal field + bool fieldChanged = false; + + PdfFont? _internalFont; + + /// internal field + PdfBrush? bBrush; + + /// internal field + PdfBrush? fBrush; + + /// internal field + PdfBrush? sBrush; + + /// internal field + PdfPen? bPen; + + /// internal field + String? name = ''; + bool _readOnly = false; + + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal field + late BeforeNameChangesEventHandler beforeNameChanges; + + /// Gets or sets a value indicating whether to flatten this [PdfField]. + bool get flattenField { + if (form != null) { + flatten |= PdfFormHelper.getHelper(form!).flatten; + } + return flatten; + } + + set flattenField(bool value) { + flatten = value; + } + + /// internal method + /// Gets or sets the color of the border. + PdfColor get borderColor { + if (isLoadedField) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfColor bc = PdfColor.empty; + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final IPdfPrimitive? getObject = crossTable!.getObject( + widget[PdfDictionaryProperties.mk], + ); + if (getObject != null && + getObject is PdfDictionary && + getObject.containsKey(PdfDictionaryProperties.bc)) { + final PdfArray array = + getObject[PdfDictionaryProperties.bc]! as PdfArray; + bc = _createColor(array); + } + } + return bc; + } else { + return WidgetAnnotationHelper.getHelper( + widget!, + ).widgetAppearance!.borderColor; + } + } + + set borderColor(PdfColor value) { + WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.borderColor = + value; + if (isLoadedField) { + PdfFormHelper.getHelper(field.form!).setAppearanceDictionary = true; + assignBorderColor(value); + if (PdfFormHelper.getHelper(field.form!).needAppearances == false) { + changed = true; + fieldChanged = true; + } + } + _createBorderPen(); + } + + /// Gets or sets the color of the background. + PdfColor get backColor => + isLoadedField + ? getBackColor() + : WidgetAnnotationHelper.getHelper( + widget!, + ).widgetAppearance!.backColor; + + set backColor(PdfColor value) { + if (isLoadedField) { + assignBackColor(value); + if (PdfFormHelper.getHelper(field.form!).needAppearances == false) { + changed = true; + fieldChanged = true; + } + } else { + WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.backColor = + value; + _createBackBrush(); + } + } + + //Creates the back brush. + void _createBackBrush() { + final PdfColor bc = + WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.backColor; + backBrush = PdfSolidBrush(bc); + final PdfColor color = PdfColor(bc.r, bc.g, bc.b); + color.r = (color.r - 64 >= 0 ? color.r - 64 : 0).toUnsigned(8); + color.g = (color.g - 64 >= 0 ? color.g - 64 : 0).toUnsigned(8); + color.b = (color.b - 64 >= 0 ? color.b - 64 : 0).toUnsigned(8); + shadowBrush = PdfSolidBrush(color); + } + + /// Gets or sets the color of the text. + PdfColor get foreColor { + if (isLoadedField) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfColor color = PdfColor(0, 0, 0); + if (widget.containsKey(PdfDictionaryProperties.da)) { + final PdfString defaultAppearance = + crossTable!.getObject(widget[PdfDictionaryProperties.da])! + as PdfString; + color = _getForeColor(defaultAppearance.value); + } else { + final IPdfPrimitive? defaultAppearance = widget.getValue( + PdfDictionaryProperties.da, + PdfDictionaryProperties.parent, + ); + if (defaultAppearance != null && defaultAppearance is PdfString) { + color = _getForeColor(defaultAppearance.value); + } + } + return color; + } else { + return widget!.defaultAppearance.foreColor; + } + } + + set foreColor(PdfColor value) { + if (isLoadedField) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + double? height = 0; + String? name; + if (widget.containsKey(PdfDictionaryProperties.da)) { + final PdfString str = widget[PdfDictionaryProperties.da]! as PdfString; + final dynamic fontName = _fontName(str.value!); + name = fontName['name'] as String?; + height = fontName['height'] as double?; + } else if (dictionary!.containsKey(PdfDictionaryProperties.da)) { + final PdfString str = + dictionary![PdfDictionaryProperties.da]! as PdfString; + final dynamic fontName = _fontName(str.value!); + name = fontName['name'] as String?; + height = fontName['height'] as double?; + } + if (name != null) { + final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); + defaultAppearance.fontName = name; + defaultAppearance.fontSize = height; + defaultAppearance.foreColor = value; + widget[PdfDictionaryProperties.da] = PdfString( + defaultAppearance.getString(), + ); + } else if (font != null) { + final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); + defaultAppearance.fontName = font!.name; + defaultAppearance.fontSize = font!.size; + defaultAppearance.foreColor = value; + widget[PdfDictionaryProperties.da] = PdfString( + defaultAppearance.getString(), + ); + } + PdfFormHelper.getHelper(field.form!).setAppearanceDictionary = true; + } else { + WidgetAnnotationHelper.getHelper(widget!) + .pdfDefaultAppearance! + .foreColor = value; + foreBrush = PdfSolidBrush(value); + } + } + + /// Gets or sets the width of the border. + int get borderWidth => + isLoadedField + ? _obtainBorderWidth() + : widget!.widgetBorder!.width.toInt(); + set borderWidth(int value) { + if (widget!.widgetBorder!.width != value) { + widget!.widgetBorder!.width = value.toDouble(); + if (isLoadedField) { + _assignBorderWidth(value); + } else { + value == 0 + ? WidgetAnnotationHelper.getHelper( + widget!, + ).widgetAppearance!.borderColor = PdfColor(255, 255, 255) + : _createBorderPen(); + } + } + } + + /// Gets or sets the highlighting mode. + PdfHighlightMode get highlightMode => + isLoadedField ? _obtainHighlightMode() : widget!.highlightMode!; + set highlightMode(PdfHighlightMode value) => + isLoadedField + ? _assignHighlightMode(value) + : widget!.highlightMode = value; + + /// Gets or sets the border style. + PdfBorderStyle get borderStyle => + isLoadedField ? _obtainBorderStyle() : widget!.widgetBorder!.borderStyle; + set borderStyle(PdfBorderStyle value) { + if (isLoadedField) { + _assignBorderStyle(value); + if (PdfFormHelper.getHelper(field.form!).needAppearances == false) { + changed = true; + fieldChanged = true; + } + } else { + widget!.widgetBorder!.borderStyle = value; + } + _createBorderPen(); + } + + PdfBorderStyle _obtainBorderStyle() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfBorderStyle style = PdfBorderStyle.solid; + if (widget.containsKey(PdfDictionaryProperties.bs)) { + final PdfDictionary bs = + crossTable!.getObject(widget[PdfDictionaryProperties.bs])! + as PdfDictionary; + style = _createBorderStyle(bs); + } + return style; + } + + PdfBorderStyle _createBorderStyle(PdfDictionary bs) { + PdfBorderStyle style = PdfBorderStyle.solid; + if (bs.containsKey(PdfDictionaryProperties.s)) { + final IPdfPrimitive? name = crossTable!.getObject( + bs[PdfDictionaryProperties.s], + ); + if (name != null && name is PdfName) { + switch (name.name!.toLowerCase()) { + case 'd': + style = PdfBorderStyle.dashed; + break; + case 'b': + style = PdfBorderStyle.beveled; + break; + case 'i': + style = PdfBorderStyle.inset; + break; + case 'u': + style = PdfBorderStyle.underline; + break; + } + } + } + return style; + } + + /// Gets or sets the font. + PdfFont? get font { + if (isLoadedField) { + if (_internalFont != null) { + return _internalFont!; + } + bool? isCorrectFont = false; + PdfFont tempFont = PdfStandardFont(PdfFontFamily.helvetica, 8); + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.da) || + dictionary!.containsKey(PdfDictionaryProperties.da)) { + IPdfPrimitive? defaultAppearance = crossTable!.getObject( + widget[PdfDictionaryProperties.da], + ); + defaultAppearance ??= crossTable!.getObject( + dictionary![PdfDictionaryProperties.da], + ); + String? fontName; + if (defaultAppearance != null && defaultAppearance is PdfString) { + final Map value = _getFont(defaultAppearance.value!); + tempFont = value['font'] as PdfFont; + isCorrectFont = value['isCorrectFont'] as bool?; + fontName = value['fontName'] as String?; + if (!isCorrectFont! && fontName != null) { + widget.setProperty( + PdfDictionaryProperties.da, + PdfString(defaultAppearance.value!.replaceAll(fontName, '/Helv')), + ); + } + } + } + return tempFont; + } + return _internalFont; + } + + set font(PdfFont? value) { + if (value != null && _internalFont != value) { + _internalFont = value; + if (isLoadedField) { + if (form != null) { + PdfFormHelper.getHelper(form!).setAppearanceDictionary = true; + } + final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); + defaultAppearance.fontName = _internalFont!.name.replaceAll(' ', ''); + defaultAppearance.fontSize = _internalFont!.size; + defaultAppearance.foreColor = foreColor; + final IPdfPrimitive? fontDictionary = PdfCrossTable.dereference( + PdfFormHelper.getHelper(form!).resources[PdfDictionaryProperties + .font], + ); + if (fontDictionary != null && + fontDictionary is PdfDictionary && + !fontDictionary.containsKey(defaultAppearance.fontName)) { + final IPdfWrapper fontWrapper = _internalFont!; + final PdfDictionary? fontElement = + IPdfWrapper.getElement(fontWrapper) as PdfDictionary?; + fontDictionary.items![PdfName( + defaultAppearance.fontName, + )] = PdfReferenceHolder(fontElement); + } + final PdfDictionary widget = getWidgetAnnotation( + dictionary!, + crossTable, + ); + widget[PdfDictionaryProperties.da] = PdfString( + defaultAppearance.getString(), + ); + } else { + _defineDefaultAppearance(); + } + } + } + + /// Gets or sets the text alignment. + PdfTextAlignment get textAlignment => + isLoadedField ? format!.alignment : widget!.textAlignment!; + set textAlignment(PdfTextAlignment value) { + if (isLoadedField) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + widget.setProperty(PdfDictionaryProperties.q, PdfNumber(value.index)); + changed = true; + } else if (widget!.textAlignment != value) { + widget!.textAlignment = value; + format = PdfStringFormat( + alignment: value, + lineAlignment: PdfVerticalAlignment.middle, + ); + } + } + + /// internal property + int get flagValue => flagValues ??= getFlagValue(); + + /// internal method + bool isFlagPresent(FieldFlags flag) { + return _getFieldFlagsValue(flag) & flagValue != 0; + } + + int _getFieldFlagsValue(FieldFlags value) { + switch (value) { + case FieldFlags.readOnly: + return 1; + case FieldFlags.requiredFieldFlag: + return 1 << 1; + case FieldFlags.noExport: + return 1 << 2; + case FieldFlags.multiline: + return 1 << 12; + case FieldFlags.password: + return 1 << 13; + case FieldFlags.fileSelect: + return 1 << 20; + case FieldFlags.doNotSpellCheck: + return 1 << 22; + case FieldFlags.doNotScroll: + return 1 << 23; + case FieldFlags.comb: + return 1 << 24; + case FieldFlags.richText: + return 1 << 25; + case FieldFlags.noToggleToOff: + return 1 << 14; + case FieldFlags.radio: + return 1 << 15; + case FieldFlags.pushButton: + return 1 << 16; + case FieldFlags.radiosInUnison: + return 1 << 25; + case FieldFlags.combo: + return 1 << 17; + case FieldFlags.edit: + return 1 << 18; + case FieldFlags.sort: + return 1 << 19; + case FieldFlags.multiSelect: + return 1 << 21; + case FieldFlags.commitOnSelChange: + return 1 << 26; + case FieldFlags.defaultFieldFlag: + return 0; + } + } + + /// internal property + PdfStringFormat? get format => + isLoadedField ? _assignStringFormat() : stringFormat; + set format(PdfStringFormat? value) => stringFormat = value; + + /// internal property + PdfBrush? get backBrush { + if (isLoadedField) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfColor c = PdfColor.empty; + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final IPdfPrimitive? bs = crossTable!.getObject( + widget[PdfDictionaryProperties.mk], + ); + if (bs is PdfDictionary) { + IPdfPrimitive? array; + if (bs.containsKey(PdfDictionaryProperties.bg)) { + array = bs[PdfDictionaryProperties.bg]; + } else if (bs.containsKey(PdfDictionaryProperties.bs)) { + array = bs[PdfDictionaryProperties.bs]; + } + if (array != null && array is PdfArray) { + c = _createColor(array); + } + } + } + return c.isEmpty ? null : PdfSolidBrush(c); + } else { + return bBrush; + } + } + + set backBrush(PdfBrush? value) { + if (isLoadedField && value is PdfSolidBrush) { + assignBackColor(value.color); + } else { + bBrush = value; + } + } + + /// internal property + PdfBrush? get foreBrush => isLoadedField ? PdfSolidBrush(foreColor) : fBrush; + set foreBrush(PdfBrush? value) => fBrush = value; + + /// internal property + PdfBrush? get shadowBrush => isLoadedField ? _obtainShadowBrush() : sBrush; + set shadowBrush(PdfBrush? value) => sBrush = value; + + /// internal property + PdfPen? get borderPen => isLoadedField ? _obtainBorderPen() : bPen; + set borderPen(PdfPen? value) => bPen = value; + + /// internal method + void beginSave() { + if (backBrush != null && + backBrush is PdfSolidBrush && + (backBrush! as PdfSolidBrush).color.isEmpty) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + final PdfDictionary mk = PdfDictionary(); + final PdfArray arr = PdfArray([1, 1, 1]); + mk.setProperty(PdfDictionaryProperties.bg, arr); + widget.setProperty(PdfDictionaryProperties.mk, mk); + } + } + + /// internal method + void setForm(PdfForm? pdfForm) { + form = pdfForm; + _defineDefaultAppearance(); + } + + /// internal method + void setFlags(List value) { + int flagValue = isLoadedField ? this.flagValue : 0; + // ignore: avoid_function_literals_in_foreach_calls + value.forEach( + (FieldFlags element) => flagValue |= _getFieldFlagsValue(element), + ); + flagValues = flagValue; + dictionary!.setNumber(PdfDictionaryProperties.fieldFlags, flagValues); + } + + /// internal method + void removeFlag(FieldFlags flag) { + flagValues = flagValue & ~_getFieldFlagsValue(flag); + } + + /// internal method + int getFlagValue() { + final IPdfPrimitive? number = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.fieldFlags, + true, + ); + return number != null && number is PdfNumber ? number.value!.toInt() : 0; + } + + void _defineDefaultAppearance() { + if (field.form != null && _internalFont != null) { + if (isLoadedField) { + final PdfDictionary widget = getWidgetAnnotation( + dictionary!, + crossTable, + ); + final PdfName name = PdfFormHelper.getHelper( + form!, + ).resources.getName(font!); + PdfFormHelper.getHelper(form!).resources.add(_internalFont, name); + PdfFormHelper.getHelper(form!).needAppearances = true; + final PdfDefaultAppearance defaultAppearance = PdfDefaultAppearance(); + defaultAppearance.fontName = name.name; + defaultAppearance.fontSize = _internalFont!.size; + defaultAppearance.foreColor = foreColor; + widget[PdfDictionaryProperties.da] = PdfString( + defaultAppearance.getString(), + ); + if (field is PdfRadioButtonListField) { + final PdfRadioButtonListField radioButtonListField = + field as PdfRadioButtonListField; + for (int i = 0; i < radioButtonListField.items.count; i++) { + final PdfRadioButtonListItem item = radioButtonListField.items[i]; + if (PdfFieldHelper.getHelper(item).font != null) { + PdfFormHelper.getHelper(field.form!).resources.add( + PdfFieldHelper.getHelper(radioButtonListField.items[i]).font, + PdfName( + WidgetAnnotationHelper.getHelper( + PdfFieldHelper.getHelper(item).widget!, + ).pdfDefaultAppearance!.fontName, + ), + ); + } + } + } + } else { + final PdfName name = PdfFormHelper.getHelper( + field.form!, + ).resources.getName(_internalFont!); + widget!.defaultAppearance.fontName = name.name; + widget!.defaultAppearance.fontSize = _internalFont!.size; + } + } else if (!isLoadedField && _internalFont != null) { + widget!.defaultAppearance.fontName = _internalFont!.name; + widget!.defaultAppearance.fontSize = _internalFont!.size; + } + } + + /// Sets the name of the field. + void _setName(String? name) { + if (name == null || name.isEmpty) { + throw ArgumentError('Field name cannot be null/empty.'); + } + if (isLoadedField) { + if (field.name != null && field.name != name) { + final List nameParts = field.name!.split('.'); + if (nameParts[nameParts.length - 1] == name) { + return; + } else { + if (form != null) { + beforeNameChanges(name); + } + this.name = name; + changed = true; + } + } + } else { + this.name = name; + } + dictionary!.setProperty(PdfDictionaryProperties.t, PdfString(name)); + } + + /// internal method + void applyName(String? name) { + if (isLoadedField) { + _setName(name); + } else { + name = name; + dictionary!.setProperty(PdfDictionaryProperties.t, PdfString(name!)); + } + } + + /// Gets the widget annotation. + PdfDictionary getWidgetAnnotation( + PdfDictionary dictionary, + PdfCrossTable? crossTable, + ) { + PdfDictionary? dic; + if (dictionary.containsKey(PdfDictionaryProperties.kids)) { + final IPdfPrimitive? array = crossTable!.getObject( + dictionary[PdfDictionaryProperties.kids], + ); + if (array is PdfArray && array.count > 0) { + final IPdfPrimitive reference = crossTable.getReference( + array[defaultIndex], + ); + if (reference is PdfReference) { + dic = crossTable.getObject(reference) as PdfDictionary?; + } + } + } + return dic ?? dictionary; + } + + /// internal method + void drawAppearance(PdfTemplate template) { + if (font != null) { + if ((font is PdfStandardFont || font is PdfCjkStandardFont) && + page != null && + PdfPageHelper.getHelper(page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(page!).document!, + ).conformanceLevel != + PdfConformanceLevel.none) { + throw ArgumentError( + 'All the fonts must be embedded in ${PdfDocumentHelper.getHelper(PdfPageHelper.getHelper(page!).document!).conformanceLevel} document.', + ); + } else if (font is PdfTrueTypeFont && + PdfPageHelper.getHelper(page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(page!).document!, + ).conformanceLevel == + PdfConformanceLevel.a1b) { + PdfTrueTypeFontHelper.getHelper( + font! as PdfTrueTypeFont, + ).fontInternal.initializeCidSet(); + } + } + } + + /// internal method + void draw() { + removeAnnotationFromPage(); + } + + Map _getFont(String fontString) { + bool isCorrectFont = true; + final Map fontNameDic = _fontName(fontString); + final String? name = fontNameDic['name'] as String?; + double height = fontNameDic['height'] as double; + PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, height); + IPdfPrimitive? fontDictionary = crossTable!.getObject( + PdfFormHelper.getHelper(field.form!).resources[PdfDictionaryProperties + .font], + ); + if (height == 0) { + if (font is PdfStandardFont) { + height = getFontHeight(font.fontFamily); + if (height == 0) { + height = 12; + } + PdfFontHelper.getHelper(font).setSize(height); + } + } + if (fontDictionary != null && + name != null && + fontDictionary is PdfDictionary && + fontDictionary.containsKey(name)) { + fontDictionary = crossTable!.getObject(fontDictionary[name]); + if (fontDictionary != null && + fontDictionary is PdfDictionary && + fontDictionary.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName fontSubtype = + crossTable!.getObject( + fontDictionary[PdfDictionaryProperties.subtype], + )! + as PdfName; + if (fontSubtype.name == PdfDictionaryProperties.type1) { + final PdfName baseFont = + crossTable!.getObject( + fontDictionary[PdfDictionaryProperties.baseFont], + )! + as PdfName; + final List fontStyle = _getFontStyle( + PdfName.decodeName(baseFont.name)!, + ); + final dynamic fontFamilyDic = _getFontFamily( + PdfName.decodeName(baseFont.name)!, + ); + final PdfFontFamily? fontFamily = + fontFamilyDic['fontFamily'] as PdfFontFamily?; + final String? standardName = fontFamilyDic['standardName'] as String?; + if (standardName == null) { + font = PdfStandardFont(fontFamily!, height, multiStyle: fontStyle); + if (!isTextChanged) { + font = _updateFontEncoding(font, fontDictionary); + } + } else { + if (height == 0 && standardName != getEnumName(fontFamily)) { + PdfDictionary? appearanceDictionary = PdfDictionary(); + if (dictionary!.containsKey(PdfDictionaryProperties.ap)) { + appearanceDictionary = + dictionary![PdfDictionaryProperties.ap] as PdfDictionary?; + } else { + if (dictionary!.containsKey(PdfDictionaryProperties.kids) && + dictionary![PdfDictionaryProperties.kids] is PdfArray) { + final PdfArray kidsArray = + dictionary![PdfDictionaryProperties.kids]! as PdfArray; + for (int i = 0; i < kidsArray.count; i++) { + if (kidsArray[i] is PdfReferenceHolder) { + final PdfReferenceHolder kids = + kidsArray[i]! as PdfReferenceHolder; + final IPdfPrimitive? dictionary = kids.object; + appearanceDictionary = + dictionary != null && + dictionary is PdfDictionary && + dictionary.containsKey( + PdfDictionaryProperties.ap, + ) && + dictionary[PdfDictionaryProperties.ap] + is PdfDictionary + ? dictionary[PdfDictionaryProperties.ap] + as PdfDictionary? + : null; + break; + } + } + } + } + if (appearanceDictionary != null && + appearanceDictionary.containsKey(PdfDictionaryProperties.n)) { + final IPdfPrimitive? dic = PdfCrossTable.dereference( + appearanceDictionary[PdfDictionaryProperties.n], + ); + if (dic != null && dic is PdfStream) { + final PdfStream stream = dic; + stream.decompress(); + final dynamic fontNameDict = _fontName( + utf8.decode(stream.dataStream!.toList()), + ); + height = fontNameDict['height'] as double; + } + } + } + if (height == 0 && standardName != getEnumName(fontFamily)) { + final PdfStandardFont stdf = font as PdfStandardFont; + height = getFontHeight(stdf.fontFamily); + font = PdfStandardFont.prototype(stdf, height); + } + if (fontStyle != [PdfFontStyle.regular]) { + font = PdfStandardFont( + PdfFontFamily.helvetica, + height, + multiStyle: fontStyle, + ); + } + if (standardName != getEnumName(fontFamily)) { + font = _updateFontEncoding(font, fontDictionary); + } + PdfFontHelper.getHelper(font).metrics = _createFont( + fontDictionary, + height, + baseFont, + ); + PdfFontHelper.getHelper(font).fontInternals = fontDictionary; + } + } else if (fontSubtype.name == 'TrueType') { + final PdfName baseFont = + crossTable!.getObject( + fontDictionary[PdfDictionaryProperties.baseFont], + )! + as PdfName; + final List fontStyle = _getFontStyle(baseFont.name!); + font = PdfStandardFont.prototype( + PdfStandardFont(PdfFontFamily.helvetica, 8), + height, + multiStyle: fontStyle, + ); + font = _createFontFromFontStream( + font, + fontDictionary, + height, + fontStyle, + ); + final IPdfPrimitive? tempName = + fontDictionary[PdfDictionaryProperties.name]; + if (tempName != null && tempName is PdfName) { + if (font is PdfStandardFont && font.name != tempName.name) { + final PdfFontHelper fontHelper = PdfFontHelper.getHelper(font); + final WidthTable? widthTable = fontHelper.metrics!.widthTable; + fontHelper.metrics = _createFont( + fontDictionary, + height, + baseFont, + ); + fontHelper.metrics!.widthTable = widthTable; + } + } + } else if (fontSubtype.name == PdfDictionaryProperties.type0) { + final IPdfPrimitive? baseFont = crossTable!.getObject( + fontDictionary[PdfDictionaryProperties.baseFont], + ); + if (baseFont != null && + baseFont is PdfName && + _isCjkFont(baseFont.name)) { + font = PdfCjkStandardFont( + _getCjkFontFamily(baseFont.name)!, + height, + multiStyle: _getFontStyle(baseFont.name!), + ); + } else { + IPdfPrimitive? descendantFontsArray; + IPdfPrimitive? descendantFontsDic; + IPdfPrimitive? fontDescriptor; + IPdfPrimitive? fontDescriptorDic; + IPdfPrimitive? fontName; + descendantFontsArray = crossTable!.getObject( + fontDictionary[PdfDictionaryProperties.descendantFonts], + ); + if (descendantFontsArray != null && + descendantFontsArray is PdfArray && + descendantFontsArray.count > 0) { + descendantFontsDic = + descendantFontsArray[0] is PdfDictionary + ? descendantFontsArray[0] + : (descendantFontsArray[0]! as PdfReferenceHolder).object; + } + if (descendantFontsDic != null && + descendantFontsDic is PdfDictionary) { + fontDescriptor = + descendantFontsDic[PdfDictionaryProperties.fontDescriptor]; + } + if (fontDescriptor != null && + fontDescriptor is PdfReferenceHolder) { + fontDescriptorDic = fontDescriptor.object; + } + if (fontDescriptorDic != null && + fontDescriptorDic is PdfDictionary) { + fontName = fontDescriptorDic[PdfDictionaryProperties.fontName]; + } + if (fontName != null && fontName is PdfName) { + String fontNameStr = fontName.name!.substring( + fontName.name!.indexOf('+') + 1, + ); + final PdfFontMetrics fontMetrics = _createFont( + descendantFontsDic! as PdfDictionary, + height, + PdfName(fontNameStr), + ); + if (fontNameStr.contains('PSMT')) { + fontNameStr = fontNameStr.replaceAll('PSMT', ''); + } + if (fontNameStr.contains('PS')) { + fontNameStr = fontNameStr.replaceAll('PS', ''); + } + if (fontNameStr.contains('-')) { + fontNameStr = fontNameStr.replaceAll('-', ''); + } + if (font.name != fontNameStr) { + final WidthTable? widthTable = + PdfFontHelper.getHelper(font).metrics!.widthTable; + PdfFontHelper.getHelper(font).metrics = fontMetrics; + PdfFontHelper.getHelper(font).metrics!.widthTable = widthTable; + } + } + } + } + } + } else { + final PdfFont? usedFont = _getFontByName(name, height); + usedFont != null ? font = usedFont : isCorrectFont = false; + } + return { + 'font': font, + 'isCorrectFont': isCorrectFont, + 'FontName': name, + }; + } + + PdfFont _createFontFromFontStream( + PdfFont font, + PdfDictionary fontDictionary, + double height, + List fontStyle, + ) { + if (fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor)) { + IPdfPrimitive? fontDescriptor = PdfCrossTable.dereference( + fontDictionary[PdfDictionaryProperties.fontDescriptor], + ); + if (fontDescriptor == null && + fontDescriptor is PdfDictionary && + fontDictionary.containsKey(PdfDictionaryProperties.descendantFonts)) { + final IPdfPrimitive? descendFonts = PdfCrossTable.dereference( + fontDictionary[PdfDictionaryProperties.descendantFonts], + ); + if (descendFonts != null && descendFonts is PdfArray) { + final IPdfPrimitive? descendDict = PdfCrossTable.dereference( + descendFonts[0], + ); + if (descendDict != null && + descendDict is PdfDictionary && + descendDict.containsKey(PdfDictionaryProperties.fontDescriptor)) { + fontDescriptor = PdfCrossTable.dereference( + descendDict[PdfDictionaryProperties.fontDescriptor], + ); + } + } + } + IPdfPrimitive? fontFile; + if (fontDescriptor != null && fontDescriptor is PdfDictionary) { + if (fontDescriptor.containsKey(PdfDictionaryProperties.fontFile2)) { + fontFile = PdfCrossTable.dereference( + fontDescriptor[PdfDictionaryProperties.fontFile2], + ); + } + if (fontDescriptor.containsKey('FontFile3')) { + fontFile = PdfCrossTable.dereference(fontDescriptor['FontFile3']); + } + } + if (fontFile != null && fontFile is PdfStream) { + fontFile.decompress(); + fontFile.freezeChanges(fontFile); + try { + fontFile.position = 0; + if (fontFile.dataStream != null) { + font = PdfTrueTypeFont( + fontFile.dataStream!, + height, + multiStyle: fontStyle, + ); + } + } catch (e) { + return font; + } + } + } + return font; + } + + PdfFontMetrics _createFont( + PdfDictionary fontDictionary, + double? height, + PdfName baseFont, + ) { + final PdfFontMetrics fontMetrics = PdfFontMetrics(); + if (fontDictionary.containsKey(PdfDictionaryProperties.fontDescriptor)) { + IPdfPrimitive? createFontDictionary; + final IPdfPrimitive? fontReferenceHolder = + fontDictionary[PdfDictionaryProperties.fontDescriptor]; + if (fontReferenceHolder != null && + fontReferenceHolder is PdfReferenceHolder) { + createFontDictionary = fontReferenceHolder.object; + } else { + createFontDictionary = + fontDictionary[PdfDictionaryProperties.fontDescriptor]; + } + if (createFontDictionary != null && + createFontDictionary is PdfDictionary) { + fontMetrics.ascent = + (createFontDictionary[PdfDictionaryProperties.ascent]! as PdfNumber) + .value! + as double; + fontMetrics.descent = + (createFontDictionary[PdfDictionaryProperties.descent]! + as PdfNumber) + .value! + as double; + fontMetrics.size = height!; + fontMetrics.height = fontMetrics.ascent - fontMetrics.descent; + fontMetrics.postScriptName = baseFont.name; + } + } + PdfArray? array; + if (fontDictionary.containsKey(PdfDictionaryProperties.widths)) { + if (fontDictionary[PdfDictionaryProperties.widths] + is PdfReferenceHolder) { + final PdfReferenceHolder tableReference = PdfReferenceHolder( + fontDictionary[PdfDictionaryProperties.widths], + ); + final PdfReferenceHolder tableArray = + tableReference.object! as PdfReferenceHolder; + array = tableArray.object as PdfArray?; + final List widthTable = []; + for (int i = 0; i < array!.count; i++) { + widthTable.add((array[i]! as PdfNumber).value! as int); + } + fontMetrics.widthTable = StandardWidthTable(widthTable); + } else { + array = fontDictionary[PdfDictionaryProperties.widths] as PdfArray?; + final List widthTable = []; + for (int i = 0; i < array!.count; i++) { + widthTable.add((array[i]! as PdfNumber).value!.toInt()); + } + fontMetrics.widthTable = StandardWidthTable(widthTable); + } + } + fontMetrics.name = baseFont.name!; + return fontMetrics; + } + + PdfFont? _getFontByName(String? name, double height) { + PdfFont? font; + switch (name) { + case 'CoBO': //"Courier-BoldOblique" + font = PdfStandardFont( + PdfFontFamily.courier, + height, + multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], + ); + break; + case 'CoBo': //"Courier-Bold" + font = PdfStandardFont( + PdfFontFamily.courier, + height, + style: PdfFontStyle.bold, + ); + break; + case 'CoOb': //"Courier-Oblique" + font = PdfStandardFont( + PdfFontFamily.courier, + height, + style: PdfFontStyle.italic, + ); + break; + case 'Courier': + case 'Cour': //"Courier" + font = PdfStandardFont( + PdfFontFamily.courier, + height, + style: PdfFontStyle.regular, + ); + break; + case 'HeBO': //"Helvetica-BoldOblique" + font = PdfStandardFont( + PdfFontFamily.helvetica, + height, + multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], + ); + break; + case 'HeBo': //"Helvetica-Bold" + font = PdfStandardFont( + PdfFontFamily.helvetica, + height, + style: PdfFontStyle.bold, + ); + break; + case 'HeOb': //"Helvetica-Oblique" + font = PdfStandardFont( + PdfFontFamily.helvetica, + height, + style: PdfFontStyle.italic, + ); + break; + case 'Helv': //"Helvetica" + font = PdfStandardFont( + PdfFontFamily.helvetica, + height, + style: PdfFontStyle.regular, + ); + break; + case 'Symb': // "Symbol" + font = PdfStandardFont(PdfFontFamily.symbol, height); + break; + case 'TiBI': // "Times-BoldItalic" + font = PdfStandardFont( + PdfFontFamily.timesRoman, + height, + multiStyle: [PdfFontStyle.bold, PdfFontStyle.italic], + ); + break; + case 'TiBo': // "Times-Bold" + font = PdfStandardFont( + PdfFontFamily.timesRoman, + height, + style: PdfFontStyle.bold, + ); + break; + case 'TiIt': // "Times-Italic" + font = PdfStandardFont( + PdfFontFamily.timesRoman, + height, + style: PdfFontStyle.italic, + ); + break; + case 'TiRo': // "Times-Roman" + font = PdfStandardFont( + PdfFontFamily.timesRoman, + height, + style: PdfFontStyle.regular, + ); + break; + case 'ZaDb': // "ZapfDingbats" + font = PdfStandardFont(PdfFontFamily.zapfDingbats, height); + break; + } + return font; + } + + //Gets the font color. + PdfColor _getForeColor(String? defaultAppearance) { + PdfColor colour = PdfColor(0, 0, 0); + if (defaultAppearance == null || defaultAppearance.isEmpty) { + colour = PdfColor(0, 0, 0); + } else { + final PdfReader reader = PdfReader(utf8.encode(defaultAppearance)); + reader.position = 0; + bool symbol = false; + final List operands = []; + String? token = reader.getNextToken(); + if (token == '/') { + symbol = true; + } + while (token != null && token.isNotEmpty) { + if (symbol == true) { + token = reader.getNextToken(); + } + symbol = true; + if (token == 'g') { + colour = PdfColorHelper.fromGray(_parseFloatColour(operands.last!)); + } else if (token == 'rg') { + colour = PdfColor( + (_parseFloatColour(operands.elementAt(operands.length - 3)!) * 255) + .toInt() + .toUnsigned(8), + (_parseFloatColour(operands.elementAt(operands.length - 2)!) * 255) + .toInt() + .toUnsigned(8), + (_parseFloatColour(operands.last!) * 255).toInt().toUnsigned(8), + ); + operands.clear(); + } else if (token == 'k') { + colour = PdfColor.fromCMYK( + _parseFloatColour(operands.elementAt(operands.length - 4)!), + _parseFloatColour(operands.elementAt(operands.length - 3)!), + _parseFloatColour(operands.elementAt(operands.length - 2)!), + _parseFloatColour(operands.last!), + ); + operands.clear(); + } else { + operands.add(token); + } + } + } + return colour; + } + + double _parseFloatColour(String text) { + double number; + try { + number = double.parse(text); + } catch (e) { + number = 0; + } + return number; + } + + PdfStringFormat _assignStringFormat() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + final PdfStringFormat stringFormat = PdfStringFormat(); + stringFormat.lineAlignment = PdfVerticalAlignment.middle; + stringFormat.lineAlignment = + ((flagValue & _getFieldFlagsValue(FieldFlags.multiline)) > 0) + ? PdfVerticalAlignment.top + : PdfVerticalAlignment.middle; + IPdfPrimitive? number; + if (widget.containsKey(PdfDictionaryProperties.q)) { + number = crossTable!.getObject(widget[PdfDictionaryProperties.q]); + } else if (dictionary!.containsKey(PdfDictionaryProperties.q)) { + number = crossTable!.getObject(dictionary![PdfDictionaryProperties.q]); + } + if (number != null && number is PdfNumber) { + stringFormat.alignment = PdfTextAlignment.values[number.value!.toInt()]; + } + return stringFormat; + } + + PdfBrush? _obtainShadowBrush() { + PdfBrush? brush = PdfBrushes.white; + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.da)) { + PdfColor? color = PdfColor(255, 255, 255); + if (backBrush is PdfSolidBrush) { + color = (backBrush! as PdfSolidBrush).color; + } + color.r = (color.r - 64 >= 0 ? color.r - 64 : 0).toUnsigned(8); + color.g = (color.g - 64 >= 0 ? color.g - 64 : 0).toUnsigned(8); + color.b = (color.b - 64 >= 0 ? color.b - 64 : 0).toUnsigned(8); + brush = PdfSolidBrush(color); + } + return brush; + } + + bool _isCjkFont(String? fontName) { + final List fontString = [ + 'STSong-Light', + 'HeiseiMin-W3', + 'HeiseiKakuGo-W5', + 'HYSMyeongJo-Medium', + 'MSung-Light', + 'MHei-Medium', + 'HYGoThic-Medium', + ]; + for (int i = 0; i < 7; i++) { + if (fontName!.contains(fontString[i])) { + return true; + } + } + return false; + } + + PdfCjkFontFamily? _getCjkFontFamily(String? fontName) { + final List fontString = [ + 'STSong-Light', + 'HeiseiMin-W3', + 'HeiseiKakuGo-W5', + 'HYSMyeongJo-Medium', + 'MSung-Light', + 'MHei-Medium', + 'HYGoThic-Medium', + ]; + String? value; + for (int i = 0; i < 7; i++) { + if (fontName!.contains(fontString[i])) { + value = fontString[i]; + break; + } + } + switch (value) { + case 'STSong-Light': + return PdfCjkFontFamily.sinoTypeSongLight; + case 'HeiseiMin-W3': + return PdfCjkFontFamily.heiseiMinchoW3; + case 'HeiseiKakuGo-W5': + return PdfCjkFontFamily.heiseiKakuGothicW5; + case 'HYSMyeongJo-Medium': + return PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium; + case 'MSung-Light': + return PdfCjkFontFamily.monotypeSungLight; + case 'MHei-Medium': + return PdfCjkFontFamily.monotypeHeiMedium; + case 'HYGoThic-Medium': + return PdfCjkFontFamily.hanyangSystemsGothicMedium; + } + return null; + } + + Map _fontName(String fontString) { + if (fontString.contains('#2C')) { + fontString = fontString.replaceAll('#2C', ','); + } + final PdfReader reader = PdfReader(utf8.encode(fontString)); + reader.position = 0; + String? prevToken = reader.getNextToken(); + String? token = reader.getNextToken(); + String? name; + double height = 0; + while (token != null && token.isNotEmpty) { + name = prevToken; + prevToken = token; + token = reader.getNextToken(); + if (token == PdfOperators.setFont) { + try { + height = double.parse(prevToken); + } catch (e) { + height = 0; + } + break; + } + } + return {'name': name, 'height': height}; + } + + //Gets the font style + List _getFontStyle(String fontFamilyString) { + String standardName = fontFamilyString; + int position = standardName.indexOf('-'); + if (position >= 0) { + standardName = standardName.substring(position + 1, standardName.length); + } + position = standardName.indexOf(','); + if (position >= 0) { + standardName = standardName.substring(position + 1, standardName.length); + } + List style = [PdfFontStyle.regular]; + if (position >= 0) { + switch (standardName) { + case 'Italic': + case 'Oblique': + case 'ItalicMT': + case 'It': + style = [PdfFontStyle.italic]; + break; + case 'Bold': + case 'BoldMT': + style = [PdfFontStyle.bold]; + break; + case 'BoldItalic': + case 'BoldOblique': + case 'BoldItalicMT': + style = [PdfFontStyle.italic, PdfFontStyle.bold]; + break; + } + } + return style; + } + + Map _getFontFamily(String fontFamilyString) { + String? standardName; + final int position = fontFamilyString.indexOf('-'); + PdfFontFamily fontFamily = PdfFontFamily.helvetica; + standardName = fontFamilyString; + if (position >= 0) { + standardName = fontFamilyString.substring(0, position); + } + if (standardName == 'Times') { + fontFamily = PdfFontFamily.timesRoman; + standardName = null; + } + final List fontFamilyList = [ + 'Helvetica', + 'Courier', + 'TimesRoman', + 'Symbol', + 'ZapfDingbats', + ]; + if (standardName != null && fontFamilyList.contains(standardName)) { + fontFamily = PdfFontFamily.values[fontFamilyList.indexOf(standardName)]; + standardName = null; + } + return { + 'fontFamily': fontFamily, + 'standardName': standardName, + }; + } + + PdfFont _updateFontEncoding(PdfFont font, PdfDictionary fontDictionary) { + final PdfDictionary? fontInternalDictionary = + PdfFontHelper.getHelper(font).fontInternals as PdfDictionary?; + if (fontDictionary.items!.containsKey( + PdfName(PdfDictionaryProperties.encoding), + )) { + final PdfName encodingName = PdfName(PdfDictionaryProperties.encoding); + final IPdfPrimitive? encodingReferenceHolder = + fontDictionary.items![PdfName(PdfDictionaryProperties.encoding)]; + if (encodingReferenceHolder != null && + encodingReferenceHolder is PdfReferenceHolder) { + final IPdfPrimitive? dictionary = encodingReferenceHolder.object; + if (dictionary != null && dictionary is PdfDictionary) { + if (fontInternalDictionary!.items!.containsKey( + PdfName(PdfDictionaryProperties.encoding), + )) { + fontInternalDictionary.items!.remove( + PdfName(PdfDictionaryProperties.encoding), + ); + } + fontInternalDictionary.items![encodingName] = dictionary; + } + } else { + final IPdfPrimitive? encodingDictionary = + fontDictionary.items![PdfName(PdfDictionaryProperties.encoding)]; + if (encodingDictionary != null && encodingDictionary is PdfDictionary) { + if (fontInternalDictionary!.items!.containsKey( + PdfName(PdfDictionaryProperties.encoding), + )) { + fontInternalDictionary.items!.remove( + PdfName(PdfDictionaryProperties.encoding), + ); + } + fontInternalDictionary.items![encodingName] = encodingDictionary; + } + } + } + return font; + } + + /// internal method + void setFittingFontSize( + GraphicsProperties gp, + PaintParams prms, + String text, + ) { + double fontSize = 0; + final double width = + prms.style == PdfBorderStyle.beveled || + prms.style == PdfBorderStyle.inset + ? gp.bounds!.width - 8 * prms.borderWidth! + : gp.bounds!.width - 4 * prms.borderWidth!; + final double height = gp.bounds!.height - 2 * gp.borderWidth!; + const double minimumFontSize = 0.248; + if (text.endsWith(' ')) { + gp.stringFormat!.measureTrailingSpaces = true; + } + for (double i = 0; i <= gp.bounds!.height; i++) { + PdfFontHelper.getHelper(gp.font!).setSize(i); + Size textSize = gp.font!.measureString(text, format: gp.stringFormat); + if (textSize.width > gp.bounds!.width || textSize.height > height) { + fontSize = i; + do { + fontSize = fontSize - 0.001; + PdfFontHelper.getHelper(gp.font!).setSize(fontSize); + final double textWidth = PdfFontHelper.getLineWidth( + gp.font!, + text, + gp.stringFormat, + ); + if (fontSize < minimumFontSize) { + PdfFontHelper.getHelper(gp.font!).setSize(minimumFontSize); + break; + } + textSize = gp.font!.measureString(text, format: gp.stringFormat); + if (textWidth < width && textSize.height < height) { + PdfFontHelper.getHelper(gp.font!).setSize(fontSize); + break; + } + } while (fontSize > minimumFontSize); + break; + } + } + } + + /// internal method + double getFontHeight(PdfFontFamily family) { + return 0; + } + + /// internal method + void beginMarkupSequence(PdfStream stream) { + stream.write('/'); + stream.write('Tx'); + stream.write(' '); + stream.write('BMC'); + stream.write('\r\n'); + } + + /// internal method + void endMarkupSequence(PdfStream stream) { + stream.write('EMC'); + stream.write('\r\n'); + } + + /// internal method + void drawStateItem( + PdfGraphics graphics, + PdfCheckFieldState state, + PdfCheckFieldBase? item, [ + PdfFieldItem? fieldItem, + ]) { + final GraphicsProperties gp = + item != null + ? GraphicsProperties(item) + : GraphicsProperties.fromFieldItem(fieldItem!); + if (!flattenField) { + gp.bounds = Rect.fromLTWH(0, 0, gp.bounds!.width, gp.bounds!.height); + } + if (gp.borderPen != null && gp.borderWidth == 0) { + gp.borderWidth = 1; + } + graphics.save(); + final PaintParams prms = PaintParams( + bounds: gp.bounds, + backBrush: gp.backBrush, + foreBrush: gp.foreBrush, + borderPen: gp.borderPen, + style: gp.style, + borderWidth: gp.borderWidth, + shadowBrush: gp.shadowBrush, + ); + if (fieldChanged == true) { + _drawFields(graphics, gp, prms, state); + } else { + PdfGraphicsHelper.getHelper( + graphics, + ).streamWriter!.setTextRenderingMode(0); + final PdfTemplate? stateTemplate = _getStateTemplate( + state, + item != null + ? PdfFieldHelper.getHelper(item).dictionary! + : PdfFieldItemHelper.getHelper(fieldItem!).dictionary!, + ); + if (stateTemplate != null) { + final Rect bounds = + item == null && fieldItem == null + ? field.bounds + : item != null + ? item.bounds + : fieldItem!.bounds; + bool encryptedContent = false; + if (crossTable != null && + crossTable!.document != null && + PdfDocumentHelper.getHelper( + crossTable!.document!, + ).isLoadedDocument) { + final PdfDocument? loadedDocument = crossTable!.document; + if (loadedDocument != null && + PdfDocumentHelper.getHelper(loadedDocument).isEncrypted) { + if (PdfSecurityHelper.getHelper( + loadedDocument.security, + ).encryptor.isEncrypt! && + loadedDocument.security.encryptionOptions == + PdfEncryptionOptions.encryptAllContents) { + encryptedContent = true; + } + } + } + final PdfStream pdfStream = + PdfTemplateHelper.getHelper(stateTemplate).content; + if (encryptedContent && + pdfStream.encrypt! && + !pdfStream.decrypted! && + field is PdfCheckBoxField) { + gp.font = null; + FieldPainter().drawCheckBox( + graphics, + prms, + PdfCheckFieldBaseHelper.getHelper( + field as PdfCheckBoxField, + ).styleToString((field as PdfCheckBoxField).style), + state, + gp.font, + ); + } else { + graphics.drawPdfTemplate(stateTemplate, bounds.topLeft, bounds.size); + } + } else { + _drawFields(graphics, gp, prms, state); + } + } + graphics.restore(); + } + + PdfTemplate? _getStateTemplate( + PdfCheckFieldState state, + PdfDictionary? itemDictionary, + ) { + final PdfDictionary dic = itemDictionary ?? dictionary!; + final String? value = + state == PdfCheckFieldState.checked + ? getItemValue(dic, crossTable) + : PdfDictionaryProperties.off; + PdfTemplate? template; + if (dic.containsKey(PdfDictionaryProperties.ap)) { + final IPdfPrimitive? appearance = PdfCrossTable.dereference( + dic[PdfDictionaryProperties.ap], + ); + if (appearance != null && appearance is PdfDictionary) { + final IPdfPrimitive? norm = PdfCrossTable.dereference( + appearance[PdfDictionaryProperties.n], + ); + if (value != null && + value.isNotEmpty && + norm != null && + norm is PdfDictionary) { + final IPdfPrimitive? xObject = PdfCrossTable.dereference(norm[value]); + if (xObject != null && xObject is PdfStream) { + template = PdfTemplateHelper.fromPdfStream(xObject); + if (value == PdfDictionaryProperties.off && + xObject.encrypt! && + xObject.decrypted!) { + //AP stream undecrypted might cause document corruption + template = null; + } + } + } + } + } + return template; + } + + void _drawFields( + PdfGraphics graphics, + GraphicsProperties gp, + PaintParams params, + PdfCheckFieldState state, + ) { + if (gp.font!.size >= 0) { + gp.font = null; + } + if (field is PdfCheckBoxField) { + FieldPainter().drawCheckBox( + graphics, + params, + PdfCheckBoxFieldHelper.getHelper( + field as PdfCheckBoxField, + ).styleToString((field as PdfCheckBoxField).style), + state, + gp.font, + ); + } else if (field is PdfRadioButtonListItem) { + FieldPainter().drawRadioButton( + graphics, + params, + PdfRadioButtonListItemHelper.getHelper( + field as PdfRadioButtonListItem, + ).styleToString((field as PdfRadioButtonListItem).style), + state, + ); + } + } + + /// internal method + void importFieldValue(Object fieldValue) { + final IPdfPrimitive? primitive = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.ft, + true, + ); + String? value; + if (fieldValue is String) { + value = fieldValue; + } + List? valueArray; + if (value == null) { + valueArray = fieldValue as List; + if (valueArray.isNotEmpty) { + value = fieldValue[0]; + } + } + if (value != null && primitive != null && primitive is PdfName) { + switch (primitive.name) { + case 'Tx': + (field as PdfTextBoxField).text = value; + break; + case 'Ch': + if (field is PdfListBoxField) { + (field as PdfListBoxField).selectedValues = + valueArray ?? [value]; + } else if (field is PdfComboBoxField) { + (field as PdfComboBoxField).selectedValue = value; + } + break; + case 'Btn': + if (field is PdfCheckBoxField) { + final PdfCheckBoxField field1 = field as PdfCheckBoxField; + if (value.toUpperCase() == 'OFF' || value.toUpperCase() == 'NO') { + field1.isChecked = false; + } else if (value.toUpperCase() == 'ON' || + value.toUpperCase() == 'YES') { + field1.isChecked = true; + } else if (_containsExportValue( + value, + field1._fieldHelper.dictionary!, + )) { + field1.isChecked = true; + } else if (field1.items != null && field1.items!.count > 0) { + bool isChecked = false; + for (int i = 0; i < field1.items!.count; i++) { + if (_containsExportValue( + value, + PdfFieldItemHelper.getHelper(field1.items![i]).dictionary!, + )) { + (field1.items![i] as PdfCheckBoxItem).checked = true; + isChecked = true; + } + } + if (!isChecked) { + field1.isChecked = false; + } + } else { + field1.isChecked = false; + } + } else if (field is PdfRadioButtonListField) { + (field as PdfRadioButtonListField).selectedValue = value; + } + break; + } + } + } + + void _assignBorderStyle(PdfBorderStyle? borderStyle) { + String style = ''; + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.bs)) { + switch (borderStyle) { + case PdfBorderStyle.dashed: + case PdfBorderStyle.dot: + style = 'D'; + break; + case PdfBorderStyle.beveled: + style = 'B'; + break; + case PdfBorderStyle.inset: + style = 'I'; + break; + case PdfBorderStyle.underline: + style = 'U'; + break; + // ignore: no_default_cases + default: + style = 'S'; + break; + } + if (widget[PdfDictionaryProperties.bs] is PdfReferenceHolder) { + final PdfDictionary widgetDict = + crossTable!.getObject(widget[PdfDictionaryProperties.bs])! + as PdfDictionary; + if (widgetDict.containsKey(PdfDictionaryProperties.s)) { + widgetDict[PdfDictionaryProperties.s] = PdfName(style); + } else { + widgetDict.setProperty(PdfDictionaryProperties.s, PdfName(style)); + } + } else { + final PdfDictionary bsDict = + widget[PdfDictionaryProperties.bs]! as PdfDictionary; + if (bsDict.containsKey(PdfDictionaryProperties.s)) { + bsDict[PdfDictionaryProperties.s] = PdfName(style); + } else { + bsDict.setProperty(PdfDictionaryProperties.s, PdfName(style)); + } + } + this.widget!.widgetBorder!.borderStyle = borderStyle!; + } else { + if (!widget.containsKey(PdfDictionaryProperties.bs)) { + this.widget!.widgetBorder!.borderStyle = borderStyle!; + widget.setProperty( + PdfDictionaryProperties.bs, + PdfAnnotationBorderHelper.getHelper( + this.widget!.widgetBorder!, + ).dictionary, + ); + } + } + if (widget.containsKey(PdfDictionaryProperties.mk) && + widget[PdfDictionaryProperties.mk] is PdfDictionary) { + final PdfDictionary mkDict = + widget[PdfDictionaryProperties.mk]! as PdfDictionary; + if (!mkDict.containsKey(PdfDictionaryProperties.bc) && + !mkDict.containsKey(PdfDictionaryProperties.bg)) { + WidgetAnnotationHelper.getHelper(this.widget!) + .widgetAppearance! + .dictionary! + .items! + .forEach((PdfName? key, IPdfPrimitive? value) { + mkDict.setProperty(key, value); + }); + } + } else { + widget.setProperty( + PdfDictionaryProperties.mk, + WidgetAnnotationHelper.getHelper(this.widget!).widgetAppearance, + ); + } + } + + PdfHighlightMode _obtainHighlightMode() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfHighlightMode mode = PdfHighlightMode.noHighlighting; + if (widget.containsKey(PdfDictionaryProperties.h)) { + final PdfName name = widget[PdfDictionaryProperties.h]! as PdfName; + switch (name.name) { + case 'I': + mode = PdfHighlightMode.invert; + break; + case 'N': + mode = PdfHighlightMode.noHighlighting; + break; + case 'O': + mode = PdfHighlightMode.outline; + break; + case 'P': + mode = PdfHighlightMode.push; + break; + } + } + return mode; + } + + bool _containsExportValue(String value, PdfDictionary dictionary) { + bool result = false; + final PdfDictionary widgetDictionary = getWidgetAnnotation( + dictionary, + crossTable, + ); + if (widgetDictionary.containsKey(PdfDictionaryProperties.ap)) { + final IPdfPrimitive? appearance = crossTable!.getObject( + widgetDictionary[PdfDictionaryProperties.ap], + ); + if (appearance != null && + appearance is PdfDictionary && + appearance.containsKey(PdfDictionaryProperties.n)) { + final IPdfPrimitive? normalTemplate = PdfCrossTable.dereference( + appearance[PdfDictionaryProperties.n], + ); + if (normalTemplate != null && + normalTemplate is PdfDictionary && + normalTemplate.containsKey(value)) { + result = true; + } + } + } + return result; + } + + /// internal methods + Map exportField(List bytes, int objectID) { + bool flag = false; + IPdfPrimitive? kids; + if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { + kids = crossTable!.getObject(dictionary![PdfDictionaryProperties.kids]); + if (kids != null && kids is PdfArray) { + for (int i = 0; i < kids.count; i++) { + flag = + flag || + (kids[i] is PdfField && + (kids[i]! as PdfField)._fieldHelper.isLoadedField); + } + } + } + final IPdfPrimitive? name = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.ft, + true, + ); + String? strValue = ''; + if (name != null && name is PdfName) { + switch (name.name) { + case 'Tx': + final IPdfPrimitive? tempName = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.v, + true, + ); + if (tempName != null && tempName is PdfString) { + strValue = tempName.value; + } + break; + case 'Ch': + final IPdfPrimitive? checkBoxPrimitive = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.v, + true, + ); + if (checkBoxPrimitive != null) { + final String? value = getExportValue(field, checkBoxPrimitive); + if (value != null && value.isNotEmpty) { + strValue = value; + } + } + break; + case 'Btn': + final IPdfPrimitive? buttonFieldPrimitive = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.v, + true, + ); + if (buttonFieldPrimitive != null) { + final String? value = getExportValue(field, buttonFieldPrimitive); + if (value != null && value.isNotEmpty) { + strValue = value; + } else if (field is PdfRadioButtonListField || + field is PdfCheckBoxField) { + if (!exportEmptyField) { + strValue = PdfDictionaryProperties.off; + } + } + } else { + if (field is PdfRadioButtonListField) { + strValue = getAppearanceStateValue(field); + } else { + final PdfDictionary holder = getWidgetAnnotation( + dictionary!, + crossTable, + ); + final IPdfPrimitive? holderName = + holder[PdfDictionaryProperties.usageApplication]; + if (holderName != null && holderName is PdfName) { + strValue = holderName.name; + } + } + } + break; + } + if ((strValue != null && strValue.isNotEmpty) || + exportEmptyField || + flag) { + if (flag && kids != null && kids is PdfArray) { + for (int i = 0; i < kids.count; i++) { + final IPdfPrimitive? field = kids[i]; + if (field != null && + field is PdfField && + (field as PdfField)._fieldHelper.isLoadedField && + (field as PdfField).canExport) { + final Map out = (field as PdfField)._fieldHelper + .exportField(bytes, objectID); + bytes = out['bytes'] as List; + objectID = out['objectID'] as int; + } + } + objID = objectID; + objectID++; + final PdfString stringValue = PdfString(strValue!) + ..encode = ForceEncoding.ascii; + final StringBuffer buffer = StringBuffer(); + buffer.write( + '$objID 0 obj< /Kids [', + ); + + for (int i = 0; i < kids.count; i++) { + final PdfField field = kids[i]! as PdfField; + if (field._fieldHelper.isLoadedField && + field.canExport && + field._fieldHelper.objID != 0) { + buffer.write('${field._fieldHelper.objID} 0 R '); + } + } + buffer.write(']>>endobj\n'); + final PdfString builderString = PdfString(buffer.toString()) + ..encode = ForceEncoding.ascii; + bytes.addAll(builderString.value!.codeUnits); + } else { + objID = objectID; + objectID++; + if (field is PdfCheckBoxField || field is PdfRadioButtonListField) { + strValue = '/${strValue!}'; + } else { + final PdfString stringFieldValue = PdfString(strValue!) + ..encode = ForceEncoding.ascii; + strValue = + '<${PdfString.bytesToHex(stringFieldValue.value!.codeUnits)}>'; + } + final PdfString stringFieldName = PdfString(this.name!) + ..encode = ForceEncoding.ascii; + final PdfString buildString = PdfString( + '$objID 0 obj< /V $strValue >>endobj\n', + )..encode = ForceEncoding.ascii; + bytes.addAll(buildString.value!.codeUnits); + } + } + } + return {'bytes': bytes, 'objectID': objectID}; + } + + /// internal method + String? getExportValue(PdfField field, IPdfPrimitive buttonFieldPrimitive) { + String? value; + if (buttonFieldPrimitive is PdfName) { + value = buttonFieldPrimitive.name; + } else if (buttonFieldPrimitive is PdfString) { + value = buttonFieldPrimitive.value; + } else if (buttonFieldPrimitive is PdfArray && + buttonFieldPrimitive.count > 0) { + for (int i = 0; i < buttonFieldPrimitive.count; i++) { + final IPdfPrimitive? primitive = buttonFieldPrimitive[i]; + if (primitive is PdfName) { + value = primitive.name; + break; + } else if (primitive is PdfString) { + value = primitive.value; + break; + } + } + } + if (value != null) { + if (field is PdfRadioButtonListField) { + final PdfRadioButtonListItem? item = field.selectedItem; + if (item != null) { + if (item.value == value || + PdfRadioButtonListItemHelper.getHelper(item).optionValue == + value) { + final String? optionValue = + PdfRadioButtonListItemHelper.getHelper(item).optionValue; + if (optionValue != null && optionValue.isNotEmpty) { + value = optionValue; + } + } + } + } + } + return value; + } + + /// internal method + String getAppearanceStateValue(PdfField field) { + final List holders = field._getWidgetAnnotations( + field._fieldHelper.dictionary!, + field._fieldHelper.crossTable!, + ); + String? value; + for (int i = 0; i < holders.length; i++) { + final IPdfPrimitive? pdfName = + holders[i][PdfDictionaryProperties.usageApplication]; + if (pdfName != null && + pdfName is PdfName && + pdfName.name != PdfDictionaryProperties.off) { + value = pdfName.name; + } + } + if (value == null && exportEmptyField) { + value = ''; + } + return value ?? PdfDictionaryProperties.off; + } + + /// internal method + XmlElement? exportFieldForXml() { + final IPdfPrimitive? name = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.ft, + true, + ); + String fieldName = this.name!.replaceAll(' ', '_x0020_'); + fieldName = fieldName + .replaceAll(r'\', '_x005C_') + .replaceAll(']', '_x005D_') + .replaceAll('[', '_x005B_') + .replaceAll(',', '_x002C_') + .replaceAll('"', '_x0022_') + .replaceAll(':', '_x003A_') + .replaceAll('{', '_x007B_') + .replaceAll('}', '_x007D_') + .replaceAll('#', '_x0023_') + .replaceAll(r'$', '_x0024_'); + XmlElement? element; + if (name != null && name is PdfName) { + switch (name.name) { + case 'Tx': + final IPdfPrimitive? str = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.v, + true, + ); + if ((str != null && str is PdfString) || exportEmptyField) { + element = XmlElement(XmlName(fieldName)); + if (str != null && str is PdfString) { + element.innerText = str.value!; + } else if (exportEmptyField) { + element.innerText = ''; + } + } + break; + case 'Ch': + final IPdfPrimitive? str = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.v, + true, + ); + if (str != null && str is PdfName) { + final XmlElement element = XmlElement(XmlName(fieldName)); + element.innerText = str.name!; + } else if ((str != null && str is PdfString) || exportEmptyField) { + element = XmlElement(XmlName(fieldName)); + if (str != null && str is PdfString) { + element.innerText = str.value!; + } else if (exportEmptyField) { + element.innerText = ''; + } + } + break; + case 'Btn': + final IPdfPrimitive? buttonFieldPrimitive = PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.v, + true, + ); + if (buttonFieldPrimitive != null) { + final String? value = getExportValue(field, buttonFieldPrimitive); + if ((value != null && value.isNotEmpty) || exportEmptyField) { + element = XmlElement(XmlName(fieldName)); + if (value != null) { + element.innerText = value; + } else if (exportEmptyField) { + element.innerText = ''; + } + } else if (field is PdfRadioButtonListField || + field is PdfCheckBoxField) { + element = XmlElement(XmlName(fieldName)); + if (exportEmptyField) { + element.innerText = ''; + } else { + element.innerText = PdfDictionaryProperties.off; + } + } + } else { + if (field is PdfRadioButtonListField) { + element = XmlElement(XmlName(fieldName)); + element.innerText = getAppearanceStateValue( + field as PdfRadioButtonListField, + ); + } else { + final PdfDictionary holder = getWidgetAnnotation( + dictionary!, + crossTable, + ); + if ((holder[PdfDictionaryProperties.usageApplication] + is PdfName) || + exportEmptyField) { + final IPdfPrimitive? holderName = + holder[PdfDictionaryProperties.usageApplication]; + element = XmlElement(XmlName(fieldName)); + if (holderName != null && holderName is PdfName) { + element.innerText = holderName.name!; + } else if (exportEmptyField) { + element.innerText = ''; + } + } + } + } + break; + } + } + return element; + } + + /// internal method + PdfArray? obtainKids() { + IPdfPrimitive? kids; + if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { + kids = crossTable!.getObject(dictionary![PdfDictionaryProperties.kids]); + } + return kids != null && kids is PdfArray ? kids : null; + } + + /// internal method + void save() { + if (field.readOnly || (field.form != null && field.form!.readOnly)) { + flags.add(FieldFlags.readOnly); + } + setFlags(flags); + if (page != null && + page!.formFieldsTabOrder == PdfFormFieldsTabOrder.manual) { + page!.annotations.remove(widget!); + PdfAnnotationCollectionHelper.getHelper( + page!.annotations, + ).annotations.insert(field.tabIndex, PdfReferenceHolder(widget)); + PdfObjectCollectionHelper.getHelper( + page!.annotations, + ).list.insert(field.tabIndex, widget!); + } + if (form != null && + !PdfFormHelper.getHelper(form!).needAppearances! && + PdfAnnotationHelper.getHelper(widget!).appearance == null) { + widget!.setAppearance = true; + drawAppearance(widget!.appearance.normal); + } + } + + /// internal method + String? getItemValue(PdfDictionary dictionary, PdfCrossTable? crossTable) { + String? value = ''; + PdfName? name; + if (dictionary.containsKey(PdfDictionaryProperties.usageApplication)) { + name = + crossTable!.getObject( + dictionary[PdfDictionaryProperties.usageApplication], + ) + as PdfName?; + if (name != null && name.name != PdfDictionaryProperties.off) { + value = PdfName.decodeName(name.name); + } + } + if (value!.isEmpty) { + if (dictionary.containsKey(PdfDictionaryProperties.ap)) { + final PdfDictionary dic = + crossTable!.getObject(dictionary[PdfDictionaryProperties.ap])! + as PdfDictionary; + if (dic.containsKey(PdfDictionaryProperties.n)) { + final PdfReference reference = crossTable.getReference( + dic[PdfDictionaryProperties.n], + ); + final PdfDictionary normalAppearance = + crossTable.getObject(reference)! as PdfDictionary; + final List list = []; + normalAppearance.items!.forEach((PdfName? key, IPdfPrimitive? value) { + list.add(key); + }); + for (int i = 0; i < list.length; ++i) { + name = list[i] as PdfName?; + if (name!.name != PdfDictionaryProperties.off) { + value = PdfName.decodeName(name.name); + break; + } + } + } + } + } + return value; + } + + /// internal method + void removeAnnotationFromPage([PdfPage? page]) { + page ??= this.page; + if (page != null) { + if (!PdfPageHelper.getHelper(page).isLoadedPage) { + page.annotations.remove(widget!); + } else { + final PdfDictionary pageDic = PdfPageHelper.getHelper(page).dictionary!; + final PdfArray annots = + pageDic.containsKey(PdfDictionaryProperties.annots) + ? PdfPageHelper.getHelper(page).crossTable!.getObject( + pageDic[PdfDictionaryProperties.annots], + )! + as PdfArray + : PdfArray(); + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + widget!, + ); + helper.dictionary!.setProperty( + PdfDictionaryProperties.p, + PdfReferenceHolder(page), + ); + for (int i = 0; i < annots.count; i++) { + final IPdfPrimitive? obj = annots[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object is PdfDictionary && + obj.object == helper.dictionary) { + annots.remove(obj); + break; + } + } + PdfPageHelper.getHelper( + page, + ).dictionary!.setProperty(PdfDictionaryProperties.annots, annots); + } + } + } + + PdfPen? _obtainBorderPen() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfPen? pen; + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final IPdfPrimitive? mk = crossTable!.getObject( + widget[PdfDictionaryProperties.mk], + ); + if (mk is PdfDictionary && mk.containsKey(PdfDictionaryProperties.bc)) { + final PdfArray array = + crossTable!.getObject(mk[PdfDictionaryProperties.bc])! as PdfArray; + pen = PdfPen(_createColor(array)); + } + } + if (pen != null) { + pen.width = borderWidth.toDouble(); + if (borderStyle == PdfBorderStyle.dashed) { + final List? dashPatern = _obtainDashPatern(); + pen.dashStyle = PdfDashStyle.custom; + if (dashPatern != null) { + pen.dashPattern = dashPatern; + } else if (borderWidth > 0) { + pen.dashPattern = [3 / borderWidth]; + } + } + } + return (pen == null) ? bPen : pen; + } + + List? _obtainDashPatern() { + List? array; + if (borderStyle == PdfBorderStyle.dashed) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.d)) { + final IPdfPrimitive? dashes = crossTable!.getObject( + widget[PdfDictionaryProperties.d], + ); + if (dashes != null && dashes is PdfArray) { + if (dashes.count == 2) { + array = [0, 0]; + IPdfPrimitive? number = dashes[0]; + if (number != null && number is PdfNumber) { + array[0] = number.value!.toDouble(); + } + number = dashes[1]; + if (number != null && number is PdfNumber) { + array[1] = number.value!.toDouble(); + } + } else { + array = [0]; + final IPdfPrimitive? number = dashes[0]; + if (number != null && number is PdfNumber) { + array[0] = number.value!.toDouble(); + } + } + } + } + } + return array; + } + + /// internal method + void _assignHighlightMode(PdfHighlightMode? highlightMode) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + widget.setName( + PdfName(PdfDictionaryProperties.h), + WidgetAnnotationHelper.getHelper( + this.widget!, + ).highlightModeToString(highlightMode), + ); + changed = true; + } + + /// internal method + Rect getBounds() { + IPdfPrimitive? array; + if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.rect)) { + array = crossTable!.getObject(widget[PdfDictionaryProperties.rect]); + } + } else { + if (dictionary!.containsKey(PdfDictionaryProperties.parent)) { + final IPdfPrimitive? parentDictionary = + (dictionary![PdfDictionaryProperties.parent]! as PdfReferenceHolder) + .object; + if (parentDictionary != null && + parentDictionary is PdfDictionary && + parentDictionary.containsKey(PdfDictionaryProperties.kids)) { + if (parentDictionary.containsKey(PdfDictionaryProperties.ft) && + (parentDictionary[PdfDictionaryProperties.ft]! as PdfName).name == + PdfDictionaryProperties.btn) { + final PdfDictionary widget = getWidgetAnnotation( + parentDictionary, + crossTable, + ); + if (widget.containsKey(PdfDictionaryProperties.rect)) { + array = crossTable!.getObject( + widget[PdfDictionaryProperties.rect], + ); + } + } + } + } + if (array == null && + dictionary!.containsKey(PdfDictionaryProperties.rect)) { + array = crossTable!.getObject( + dictionary![PdfDictionaryProperties.rect], + ); + } + } + Rect bounds; + if (array != null && array is PdfArray) { + bounds = array.toRectangle().rect; + double y = 0.0; + + final value1 = (PdfCrossTable.dereference(array[1])! as PdfNumber).value!; + final value3 = (PdfCrossTable.dereference(array[3])! as PdfNumber).value!; + + final value1Double = value1.toDouble(); + final value3Double = value3.toDouble(); + + if (value1Double < 0) { + y = value1Double; + + if (value1Double > value3Double) { + y = y - bounds.height; + } + } + bounds = Rect.fromLTWH( + bounds.left, + y <= 0 ? bounds.top : y, + bounds.width, + bounds.height, + ); + } else { + bounds = Rect.zero; + } + return bounds; + } + + /// internal method + PdfColor getBackColor() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + PdfColor c = PdfColor.empty; + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final IPdfPrimitive? bs = crossTable!.getObject( + widget[PdfDictionaryProperties.mk], + ); + if (bs is PdfDictionary) { + IPdfPrimitive? array; + if (bs.containsKey(PdfDictionaryProperties.bg)) { + array = bs[PdfDictionaryProperties.bg]; + } else if (bs.containsKey(PdfDictionaryProperties.bs)) { + array = bs[PdfDictionaryProperties.bs]; + } + if (array != null && array is PdfArray) { + c = _createColor(array); + } + } + } + return c; + } + + PdfColor _createColor(PdfArray array) { + final int dim = array.count; + PdfColor color = PdfColor.empty; + final List colors = []; + for (int i = 0; i < array.count; ++i) { + final PdfNumber number = crossTable!.getObject(array[i])! as PdfNumber; + colors.add(number.value!.toDouble()); + } + switch (dim) { + case 1: + color = + (colors[0] > 0.0) && (colors[0] <= 1.0) + ? PdfColorHelper.fromGray(colors[0]) + : PdfColorHelper.fromGray( + colors[0].toInt().toUnsigned(8).toDouble(), + ); + break; + case 3: + color = + ((colors[0] > 0.0) && (colors[0] <= 1.0)) || + ((colors[1] > 0.0) && (colors[1] <= 1.0)) || + ((colors[2] > 0.0) && (colors[2] <= 1.0)) + ? PdfColor( + (colors[0] * 255).toInt().toUnsigned(8), + (colors[1] * 255).toInt().toUnsigned(8), + (colors[2] * 255).toInt().toUnsigned(8), + ) + : PdfColor( + colors[0].toInt().toUnsigned(8), + colors[1].toInt().toUnsigned(8), + colors[2].toInt().toUnsigned(8), + ); + break; + case 4: + color = + ((colors[0] > 0.0) && (colors[0] <= 1.0)) || + ((colors[1] > 0.0) && (colors[1] <= 1.0)) || + ((colors[2] > 0.0) && (colors[2] <= 1.0)) || + ((colors[3] > 0.0) && (colors[3] <= 1.0)) + ? PdfColor.fromCMYK(colors[0], colors[1], colors[2], colors[3]) + : PdfColor.fromCMYK( + colors[0].toInt().toUnsigned(8).toDouble(), + colors[1].toInt().toUnsigned(8).toDouble(), + colors[2].toInt().toUnsigned(8).toDouble(), + colors[3].toInt().toUnsigned(8).toDouble(), + ); + break; + } + return color; + } + + /// internal method + void assignBackColor(PdfColor? value) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final PdfDictionary mk = + (crossTable != null + ? crossTable!.getObject(widget[PdfDictionaryProperties.mk]) + : PdfCrossTable.dereference( + widget[PdfDictionaryProperties.mk], + ))! + as PdfDictionary; + final PdfArray array = PdfColorHelper.toArray(value!); + mk[PdfDictionaryProperties.bg] = array; + } else { + final PdfDictionary mk = PdfDictionary(); + final PdfArray array = PdfColorHelper.toArray(value!); + mk[PdfDictionaryProperties.bg] = array; + widget[PdfDictionaryProperties.mk] = mk; + } + PdfFormHelper.getHelper(field.form!).setAppearanceDictionary = true; + } + + /// internal method + void assignBorderColor(PdfColor borderColor) { + if (dictionary!.containsKey(PdfDictionaryProperties.kids)) { + final IPdfPrimitive? kids = crossTable!.getObject( + dictionary![PdfDictionaryProperties.kids], + ); + if (kids != null && kids is PdfArray) { + for (int i = 0; i < kids.count; i++) { + final IPdfPrimitive? widget = PdfCrossTable.dereference(kids[i]); + if (widget != null && widget is PdfDictionary) { + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final IPdfPrimitive? mk = + crossTable != null + ? crossTable!.getObject( + widget[PdfDictionaryProperties.mk], + ) + : PdfCrossTable.dereference( + widget[PdfDictionaryProperties.mk], + ); + if (mk != null && mk is PdfDictionary) { + final PdfArray array = PdfColorHelper.toArray(borderColor); + if (PdfColorHelper.getHelper(borderColor).alpha == 0) { + mk[PdfDictionaryProperties.bc] = PdfArray([]); + } else { + mk[PdfDictionaryProperties.bc] = array; + } + } + } else { + final PdfDictionary mk = PdfDictionary(); + final PdfArray array = PdfColorHelper.toArray(borderColor); + if (PdfColorHelper.getHelper(borderColor).alpha == 0) { + mk[PdfDictionaryProperties.bc] = PdfArray([]); + } else { + mk[PdfDictionaryProperties.bc] = array; + } + widget[PdfDictionaryProperties.mk] = mk; + } + } + } + } + } else { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final IPdfPrimitive? mk = + crossTable != null + ? crossTable!.getObject(widget[PdfDictionaryProperties.mk]) + : PdfCrossTable.dereference(widget[PdfDictionaryProperties.mk]); + if (mk != null && mk is PdfDictionary) { + final PdfArray array = PdfColorHelper.toArray(borderColor); + if (PdfColorHelper.getHelper(borderColor).alpha == 0) { + mk[PdfDictionaryProperties.bc] = PdfArray([]); + } else { + mk[PdfDictionaryProperties.bc] = array; + } + } + } else { + final PdfDictionary mk = PdfDictionary(); + final PdfArray array = PdfColorHelper.toArray(borderColor); + if (PdfColorHelper.getHelper(borderColor).alpha == 0) { + mk[PdfDictionaryProperties.bc] = PdfArray([]); + } else { + mk[PdfDictionaryProperties.bc] = array; + } + widget[PdfDictionaryProperties.mk] = mk; + } + } + } + + int _obtainBorderWidth() { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + int width = 0; + final IPdfPrimitive? name = crossTable!.getObject( + widget[PdfDictionaryProperties.ft], + ); + if (widget.containsKey(PdfDictionaryProperties.bs)) { + width = 1; + final PdfDictionary bs = + crossTable!.getObject(widget[PdfDictionaryProperties.bs])! + as PdfDictionary; + final IPdfPrimitive? number = crossTable!.getObject( + bs[PdfDictionaryProperties.w], + ); + if (number != null && number is PdfNumber) { + width = number.value!.toInt(); + } + } else if (name != null && name is PdfName && name.name == 'Btn') { + width = 1; + } + return width; + } + + void _assignBorderWidth(int width) { + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + if (widget.containsKey(PdfDictionaryProperties.bs)) { + if (widget[PdfDictionaryProperties.bs] is PdfReferenceHolder) { + final PdfDictionary widgetDict = + crossTable!.getObject(widget[PdfDictionaryProperties.bs])! + as PdfDictionary; + if (widgetDict.containsKey(PdfDictionaryProperties.w)) { + widgetDict[PdfDictionaryProperties.w] = PdfNumber(width); + } else { + widgetDict.setProperty(PdfDictionaryProperties.w, PdfNumber(width)); + } + } else { + (widget[PdfDictionaryProperties.bs]! + as PdfDictionary)[PdfDictionaryProperties.w] = PdfNumber(width); + } + _createBorderPen(); + } else { + if (!widget.containsKey(PdfDictionaryProperties.bs)) { + widget.setProperty( + PdfDictionaryProperties.bs, + PdfAnnotationBorderHelper.getHelper( + this.widget!.widgetBorder!, + ).dictionary, + ); + (widget[PdfDictionaryProperties.bs]! as PdfDictionary).setProperty( + PdfDictionaryProperties.w, + PdfNumber(width), + ); + _createBorderPen(); + } + } + } + + //Creates the border pen. + void _createBorderPen() { + final double width = widget!.widgetBorder!.width; + borderPen = PdfPen( + WidgetAnnotationHelper.getHelper(widget!).widgetAppearance!.borderColor, + width: width, + ); + if (widget!.widgetBorder!.borderStyle == PdfBorderStyle.dashed || + widget!.widgetBorder!.borderStyle == PdfBorderStyle.dot) { + borderPen!.dashStyle = PdfDashStyle.custom; + borderPen!.dashPattern = [3 / width]; + } + } + + /// internal method + static PdfFieldHelper getHelper(PdfField field) { + return field._fieldHelper; + } + + /// internal method + void dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (dictionary!.containsKey(PdfDictionaryProperties.kids) && + dictionary!.containsKey(PdfDictionaryProperties.tu)) { + final IPdfPrimitive? kids = dictionary![PdfDictionaryProperties.kids]; + if (kids != null && kids is PdfArray) { + for (int i = 0; i < kids.count; i++) { + final IPdfPrimitive? kidsReferenceHolder = kids.elements[i]; + if (kidsReferenceHolder != null && + kidsReferenceHolder is PdfReferenceHolder) { + final IPdfPrimitive? widgetAnnot = kidsReferenceHolder.object; + if (widgetAnnot != null && + widgetAnnot is PdfDictionary && + !widgetAnnot.containsKey(PdfDictionaryProperties.tu)) { + final IPdfPrimitive? toolTip = + dictionary![PdfDictionaryProperties.tu]; + if (toolTip != null && toolTip is PdfString) { + widgetAnnot.setString( + PdfDictionaryProperties.tu, + toolTip.value, + ); + } + } + } + } + } + } + } + + /// Gets the value. + static IPdfPrimitive? getValue( + PdfDictionary dictionary, + PdfCrossTable? crossTable, + String value, + bool inheritable, + ) { + IPdfPrimitive? primitive; + if (dictionary.containsKey(value)) { + primitive = crossTable!.getObject(dictionary[value]); + } else if (inheritable) { + primitive = searchInParents(dictionary, crossTable, value); + } + return primitive; + } + + /// Searches the in parents. + static IPdfPrimitive? searchInParents( + PdfDictionary dictionary, + PdfCrossTable? crossTable, + String value, + ) { + IPdfPrimitive? primitive; + PdfDictionary? dic = dictionary; + while (primitive == null && dic != null) { + if (dic.containsKey(value)) { + primitive = crossTable!.getObject(dic[value]); + } else { + dic = + dic.containsKey(PdfDictionaryProperties.parent) + ? (crossTable!.getObject(dic[PdfDictionaryProperties.parent]) + as PdfDictionary?)! + : null; + } + } + return primitive; + } +} + +/// Represents the graphic properties of field. +class GraphicsProperties { + /// internal constructor + GraphicsProperties(PdfField field) { + bounds = field.bounds; + borderPen = field._fieldHelper.borderPen; + style = field._fieldHelper.borderStyle; + borderWidth = field._fieldHelper.borderWidth; + backBrush = field._fieldHelper.backBrush; + foreBrush = field._fieldHelper.foreBrush; + shadowBrush = field._fieldHelper.shadowBrush; + font = field._fieldHelper.font; + stringFormat = field._fieldHelper.format; + if ((!field._fieldHelper.isLoadedField) && + field.page != null && + field.page!.rotation != PdfPageRotateAngle.rotateAngle0) { + bounds = _rotateTextbox( + field.bounds, + field.page!.size, + field.page!.rotation, + ); + } + } + + /// internal constructor + GraphicsProperties.fromFieldItem(PdfFieldItem item) { + bounds = item.bounds; + final PdfFieldItemHelper helper = PdfFieldItemHelper.getHelper(item); + borderPen = helper.borderPen; + style = helper.borderStyle; + borderWidth = helper.borderWidth; + backBrush = helper.backBrush; + foreBrush = helper.foreBrush; + shadowBrush = helper.shadowBrush; + font = helper.font; + stringFormat = helper.format; + if ((!helper.field._fieldHelper.isLoadedField) && + item.page != null && + item.page!.rotation != PdfPageRotateAngle.rotateAngle0) { + bounds = _rotateTextbox( + item.bounds, + item.page!.size, + item.page!.rotation, + ); + } + } + + //Fields + /// internal field + Rect? bounds; + + /// internal field + PdfBrush? foreBrush; + + /// internal field + PdfBrush? backBrush; + + /// internal field + PdfBrush? shadowBrush; + + /// internal field + int? borderWidth; + + /// internal field + PdfBorderStyle? style; + + /// internal field + PdfPen? borderPen; + + /// internal field + PdfFont? font; + + /// internal field + PdfStringFormat? stringFormat; + + //Implementation + Rect _rotateTextbox(Rect rect, Size? size, PdfPageRotateAngle angle) { + Rect rectangle = rect; + if (angle == PdfPageRotateAngle.rotateAngle180) { + rectangle = Rect.fromLTWH( + size!.width - rect.left - rect.width, + size.height - rect.top - rect.height, + rect.width, + rect.height, + ); + } + if (angle == PdfPageRotateAngle.rotateAngle270) { + rectangle = Rect.fromLTWH( + rect.top, + size!.width - rect.left - rect.width, + rect.height, + rect.width, + ); + } + if (angle == PdfPageRotateAngle.rotateAngle90) { + rectangle = Rect.fromLTWH( + size!.height - rect.top - rect.height, + rect.left, + rect.height, + rect.width, + ); + } + return rectangle; + } +} + +//typedef for NameChanged event handler. +typedef BeforeNameChangesEventHandler = void Function(String name); diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item.dart index a5bc5f56a..ef4b3e5b4 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item.dart @@ -1,442 +1,442 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_string_format.dart'; -import '../graphics/pdf_pen.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_collection.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_check_box_field.dart'; -import 'pdf_field.dart'; -import 'pdf_field_item_collection.dart'; -import 'pdf_form.dart'; - -/// Represents base class for field's group items. -class PdfFieldItem { - //Constructor - /// Initializes a new instance of the [PdfFieldItem] class. - PdfFieldItem._(PdfField field, int index, PdfDictionary? dictionary) { - _helper = PdfFieldItemHelper(this, field); - _helper._collectionIndex = index; - _helper.dictionary = dictionary; - } - - //Field - late PdfFieldItemHelper _helper; - PdfPage? _page; - - //Properties - /// Gets or sets the bounds. - Rect get bounds { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(_helper.field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _helper._collectionIndex; - final Rect rect = _helper.field.bounds; - helper.defaultIndex = backUpIndex; - return rect; - } - - set bounds(Rect value) { - if (value.isEmpty) { - ArgumentError("bounds can't be null/empty"); - } - final PdfFieldHelper helper = PdfFieldHelper.getHelper(_helper.field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _helper._collectionIndex; - _helper.field.bounds = value; - helper.defaultIndex = backUpIndex; - } - - /// Gets the page of the field. - PdfPage? get page { - if (_page == null) { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(_helper.field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _helper._collectionIndex; - _page = _helper.field.page; - final PdfName pName = PdfName(PdfDictionaryProperties.p); - final PdfArray? kids = helper.kids; - if (kids != null && kids.count > 0) { - final PdfCrossTable crosstable = helper.crossTable!; - final PdfDocument? doc = crosstable.document; - if (doc != null && PdfDocumentHelper.getHelper(doc).isLoadedDocument) { - if (_helper.dictionary!.containsKey(pName)) { - final IPdfPrimitive? pageRef = crosstable.getObject( - _helper.dictionary![PdfDictionaryProperties.p], - ); - if (pageRef != null && pageRef is PdfDictionary) { - final PdfReference widgetReference = crosstable.getReference( - _helper.dictionary, - ); - for (int i = 0; i < doc.pages.count; i++) { - final PdfPage loadedPage = doc.pages[i]; - final PdfArray? lAnnots = - PdfPageHelper.getHelper(loadedPage).obtainAnnotations(); - if (lAnnots != null) { - for (int i = 0; i < lAnnots.count; i++) { - final IPdfPrimitive? holder = lAnnots[i]; - if (holder != null && - holder is PdfReferenceHolder && - holder.reference != null && - holder.reference!.objNum == widgetReference.objNum && - holder.reference!.genNum == widgetReference.genNum) { - _page = PdfPageCollectionHelper.getHelper( - doc.pages, - ).getPage(pageRef); - helper.defaultIndex = backUpIndex; - return _page; - } - } - } - if (_helper.dictionary!.containsKey( - PdfDictionaryProperties.p, - )) { - final IPdfPrimitive? itemPageDict = PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.p], - ); - final PdfDictionary pageDict = - PdfPageHelper.getHelper(loadedPage).dictionary!; - if (itemPageDict is PdfDictionary && - itemPageDict == pageDict) { - _page = loadedPage; - helper.defaultIndex = backUpIndex; - return _page; - } - } - } - helper.defaultIndex = backUpIndex; - _page = null; - } - } else { - final PdfReference widgetReference = crosstable.getReference( - _helper.dictionary, - ); - for (int i = 0; i < doc.pages.count; i++) { - final PdfPage loadedPage = doc.pages[i]; - final PdfArray? lAnnots = - PdfPageHelper.getHelper(loadedPage).obtainAnnotations(); - if (lAnnots != null) { - for (int i = 0; i < lAnnots.count; i++) { - final IPdfPrimitive? holder = lAnnots[i]; - if (holder != null && - holder is PdfReferenceHolder && - holder.reference!.objNum == widgetReference.objNum && - holder.reference!.genNum == widgetReference.genNum) { - return _page = loadedPage; - } - } - } - } - _page = null; - } - } - } - helper.defaultIndex = backUpIndex; - } - return _page; - } -} - -/// [PdfFieldItem] helper -class PdfFieldItemHelper { - /// internal constructor - PdfFieldItemHelper(this.fieldItem, this.field); - - /// internal field - late PdfFieldItem fieldItem; - - /// internal field - late PdfField field; - - /// internal field - PdfDictionary? dictionary; - - /// internal field - int _collectionIndex = 0; - - /// internal method - PdfPen? get borderPen { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final PdfPen? pen = helper.borderPen; - helper.defaultIndex = backUpIndex; - return pen; - } - - /// internal method - PdfBorderStyle? get borderStyle { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final PdfBorderStyle bs = helper.borderStyle; - helper.defaultIndex = backUpIndex; - return bs; - } - - /// internal method - int get borderWidth { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final int borderWidth = helper.borderWidth; - helper.defaultIndex = backUpIndex; - return borderWidth; - } - - /// internal method - PdfStringFormat? get format { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final PdfStringFormat? sFormat = helper.format; - helper.defaultIndex = backUpIndex; - return sFormat; - } - - /// internal method - PdfBrush? get backBrush { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final PdfBrush? backBrush = helper.backBrush; - helper.defaultIndex = backUpIndex; - return backBrush; - } - - /// internal method - PdfBrush? get foreBrush { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final PdfBrush? foreBrush = helper.foreBrush; - helper.defaultIndex = backUpIndex; - return foreBrush; - } - - /// internal method - PdfBrush? get shadowBrush { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final PdfBrush? shadowBrush = helper.shadowBrush; - helper.defaultIndex = backUpIndex; - return shadowBrush; - } - - /// internal method - PdfFont get font { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final int backUpIndex = helper.defaultIndex; - helper.defaultIndex = _collectionIndex; - final PdfFont font = helper.font!; - helper.defaultIndex = backUpIndex; - return font; - } - - /// internal method - static PdfFieldItemHelper getHelper(PdfFieldItem item) { - return item._helper; - } - - /// internal method - bool obtainCheckedStatus() { - bool check = false; - IPdfPrimitive? state; - if (dictionary!.containsKey(PdfDictionaryProperties.usageApplication)) { - state = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.usageApplication], - ); - } - if (state == null) { - final PdfFieldHelper fieldHelper = PdfFieldHelper.getHelper(field); - final IPdfPrimitive? name = PdfFieldHelper.getValue( - fieldHelper.dictionary!, - fieldHelper.crossTable, - PdfDictionaryProperties.v, - false, - ); - if (name != null && name is PdfName) { - check = - (name.name == - fieldHelper.getItemValue(dictionary!, fieldHelper.crossTable)); - } - } else if (state is PdfName) { - check = (state.name != PdfDictionaryProperties.off); - } - return check; - } - - /// internal method - void setCheckedStatus(bool check) { - final PdfFieldHelper fieldHelper = PdfFieldHelper.getHelper(field); - String? val = fieldHelper.getItemValue(dictionary!, fieldHelper.crossTable); - if (val != null) { - _uncheckOthers(val, check, fieldHelper); - } - if (check) { - if (val == null || val.isEmpty) { - val = PdfDictionaryProperties.yes; - } - fieldHelper.dictionary!.setName(PdfName(PdfDictionaryProperties.v), val); - dictionary!.setProperty( - PdfDictionaryProperties.usageApplication, - PdfName(val), - ); - dictionary!.setProperty(PdfDictionaryProperties.v, PdfName(val)); - } else { - IPdfPrimitive? v; - if (fieldHelper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - v = PdfCrossTable.dereference( - fieldHelper.dictionary![PdfDictionaryProperties.v], - ); - } - if (v != null && v is PdfName && val == v.name) { - fieldHelper.dictionary!.remove(PdfDictionaryProperties.v); - } - dictionary!.setProperty( - PdfDictionaryProperties.usageApplication, - PdfName(PdfDictionaryProperties.off), - ); - } - fieldHelper.changed = true; - } - - /// internal method - void _uncheckOthers(String value, bool check, PdfFieldHelper fieldHelper) { - final PdfFieldItemCollection? items = (field as PdfCheckBoxField).items; - if (items != null && items.count > 0) { - final PdfFieldItemCollectionHelper fieldItemCollectionHelper = - PdfFieldItemCollectionHelper.getHelper(items); - if (fieldItemCollectionHelper.allowUncheck) { - fieldItemCollectionHelper.allowUncheck = false; - for (int i = 0; i < items.count; i++) { - final PdfFieldItem item = items[i]; - if (item != fieldItem && item is PdfCheckBoxItem) { - final String? val = fieldHelper.getItemValue( - PdfFieldItemHelper.getHelper(item).dictionary!, - fieldHelper.crossTable, - ); - final bool v = val != null && val == value; - if (v && check) { - item.checked = true; - } else { - item.checked = false; - } - } - } - } - fieldItemCollectionHelper.allowUncheck = true; - } - } -} - -/// Represents loaded check box item. -class PdfCheckBoxItem extends PdfFieldItem { - PdfCheckBoxItem._(super.field, super.index, super.dictionary) : super._(); - - //Properties - /// Gets or sets a value indicating whether the [PdfCheckBoxItem] is checked. - bool get checked => _helper.obtainCheckedStatus(); - - set checked(bool value) { - if (!_helper.field.readOnly) { - if (value != checked) { - _helper.setCheckedStatus(value); - PdfFormHelper.getHelper(_helper.field.form!).setAppearanceDictionary = - true; - } - } - } - - //Implementation - void _setStyle(PdfCheckBoxStyle value) { - String style = ''; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.mk)) { - switch (value) { - case PdfCheckBoxStyle.check: - style = '4'; - break; - case PdfCheckBoxStyle.circle: - style = 'l'; - break; - case PdfCheckBoxStyle.cross: - style = '8'; - break; - case PdfCheckBoxStyle.diamond: - style = 'u'; - break; - case PdfCheckBoxStyle.square: - style = 'n'; - break; - case PdfCheckBoxStyle.star: - style = 'H'; - break; - } - final IPdfPrimitive? mk = _helper.dictionary![PdfDictionaryProperties.mk]; - if (mk is PdfReferenceHolder) { - final IPdfPrimitive? widgetDict = mk.object; - if (widgetDict is PdfDictionary) { - if (widgetDict.containsKey(PdfDictionaryProperties.ca)) { - widgetDict[PdfDictionaryProperties.ca] = PdfString(style); - } else { - widgetDict.setProperty( - PdfDictionaryProperties.ca, - PdfString(style), - ); - } - } - } else if (mk is PdfDictionary) { - mk[PdfDictionaryProperties.ca] = PdfString(style); - } - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfCheckBoxItem] helper -class PdfCheckBoxItemHelper { - /// internal method - static void setStyle(PdfCheckBoxItem checkBoxItem, PdfCheckBoxStyle value) { - checkBoxItem._setStyle(value); - } - - /// internal method - static PdfCheckBoxItem getItem( - PdfField field, - int index, - PdfDictionary? dictionary, - ) { - return PdfCheckBoxItem._(field, index, dictionary); - } -} - -/// Represents an item in a text box field collection. -class PdfTextBoxItem extends PdfFieldItem { - PdfTextBoxItem._(super.field, super.index, super.dictionary) : super._(); -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfTextBoxItem] helper -class PdfTextBoxItemHelper { - /// internal method - static PdfTextBoxItem getItem( - PdfField field, - int index, - PdfDictionary? dictionary, - ) { - return PdfTextBoxItem._(field, index, dictionary); - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_string_format.dart'; +import '../graphics/pdf_pen.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_collection.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_check_box_field.dart'; +import 'pdf_field.dart'; +import 'pdf_field_item_collection.dart'; +import 'pdf_form.dart'; + +/// Represents base class for field's group items. +class PdfFieldItem { + //Constructor + /// Initializes a new instance of the [PdfFieldItem] class. + PdfFieldItem._(PdfField field, int index, PdfDictionary? dictionary) { + _helper = PdfFieldItemHelper(this, field); + _helper._collectionIndex = index; + _helper.dictionary = dictionary; + } + + //Field + late PdfFieldItemHelper _helper; + PdfPage? _page; + + //Properties + /// Gets or sets the bounds. + Rect get bounds { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(_helper.field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _helper._collectionIndex; + final Rect rect = _helper.field.bounds; + helper.defaultIndex = backUpIndex; + return rect; + } + + set bounds(Rect value) { + if (value.isEmpty) { + ArgumentError("bounds can't be null/empty"); + } + final PdfFieldHelper helper = PdfFieldHelper.getHelper(_helper.field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _helper._collectionIndex; + _helper.field.bounds = value; + helper.defaultIndex = backUpIndex; + } + + /// Gets the page of the field. + PdfPage? get page { + if (_page == null) { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(_helper.field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _helper._collectionIndex; + _page = _helper.field.page; + final PdfName pName = PdfName(PdfDictionaryProperties.p); + final PdfArray? kids = helper.kids; + if (kids != null && kids.count > 0) { + final PdfCrossTable crosstable = helper.crossTable!; + final PdfDocument? doc = crosstable.document; + if (doc != null && PdfDocumentHelper.getHelper(doc).isLoadedDocument) { + if (_helper.dictionary!.containsKey(pName)) { + final IPdfPrimitive? pageRef = crosstable.getObject( + _helper.dictionary![PdfDictionaryProperties.p], + ); + if (pageRef != null && pageRef is PdfDictionary) { + final PdfReference widgetReference = crosstable.getReference( + _helper.dictionary, + ); + for (int i = 0; i < doc.pages.count; i++) { + final PdfPage loadedPage = doc.pages[i]; + final PdfArray? lAnnots = + PdfPageHelper.getHelper(loadedPage).obtainAnnotations(); + if (lAnnots != null) { + for (int i = 0; i < lAnnots.count; i++) { + final IPdfPrimitive? holder = lAnnots[i]; + if (holder != null && + holder is PdfReferenceHolder && + holder.reference != null && + holder.reference!.objNum == widgetReference.objNum && + holder.reference!.genNum == widgetReference.genNum) { + _page = PdfPageCollectionHelper.getHelper( + doc.pages, + ).getPage(pageRef); + helper.defaultIndex = backUpIndex; + return _page; + } + } + } + if (_helper.dictionary!.containsKey( + PdfDictionaryProperties.p, + )) { + final IPdfPrimitive? itemPageDict = PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.p], + ); + final PdfDictionary pageDict = + PdfPageHelper.getHelper(loadedPage).dictionary!; + if (itemPageDict is PdfDictionary && + itemPageDict == pageDict) { + _page = loadedPage; + helper.defaultIndex = backUpIndex; + return _page; + } + } + } + helper.defaultIndex = backUpIndex; + _page = null; + } + } else { + final PdfReference widgetReference = crosstable.getReference( + _helper.dictionary, + ); + for (int i = 0; i < doc.pages.count; i++) { + final PdfPage loadedPage = doc.pages[i]; + final PdfArray? lAnnots = + PdfPageHelper.getHelper(loadedPage).obtainAnnotations(); + if (lAnnots != null) { + for (int i = 0; i < lAnnots.count; i++) { + final IPdfPrimitive? holder = lAnnots[i]; + if (holder != null && + holder is PdfReferenceHolder && + holder.reference!.objNum == widgetReference.objNum && + holder.reference!.genNum == widgetReference.genNum) { + return _page = loadedPage; + } + } + } + } + _page = null; + } + } + } + helper.defaultIndex = backUpIndex; + } + return _page; + } +} + +/// [PdfFieldItem] helper +class PdfFieldItemHelper { + /// internal constructor + PdfFieldItemHelper(this.fieldItem, this.field); + + /// internal field + late PdfFieldItem fieldItem; + + /// internal field + late PdfField field; + + /// internal field + PdfDictionary? dictionary; + + /// internal field + int _collectionIndex = 0; + + /// internal method + PdfPen? get borderPen { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final PdfPen? pen = helper.borderPen; + helper.defaultIndex = backUpIndex; + return pen; + } + + /// internal method + PdfBorderStyle? get borderStyle { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final PdfBorderStyle bs = helper.borderStyle; + helper.defaultIndex = backUpIndex; + return bs; + } + + /// internal method + int get borderWidth { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final int borderWidth = helper.borderWidth; + helper.defaultIndex = backUpIndex; + return borderWidth; + } + + /// internal method + PdfStringFormat? get format { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final PdfStringFormat? sFormat = helper.format; + helper.defaultIndex = backUpIndex; + return sFormat; + } + + /// internal method + PdfBrush? get backBrush { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final PdfBrush? backBrush = helper.backBrush; + helper.defaultIndex = backUpIndex; + return backBrush; + } + + /// internal method + PdfBrush? get foreBrush { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final PdfBrush? foreBrush = helper.foreBrush; + helper.defaultIndex = backUpIndex; + return foreBrush; + } + + /// internal method + PdfBrush? get shadowBrush { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final PdfBrush? shadowBrush = helper.shadowBrush; + helper.defaultIndex = backUpIndex; + return shadowBrush; + } + + /// internal method + PdfFont get font { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final int backUpIndex = helper.defaultIndex; + helper.defaultIndex = _collectionIndex; + final PdfFont font = helper.font!; + helper.defaultIndex = backUpIndex; + return font; + } + + /// internal method + static PdfFieldItemHelper getHelper(PdfFieldItem item) { + return item._helper; + } + + /// internal method + bool obtainCheckedStatus() { + bool check = false; + IPdfPrimitive? state; + if (dictionary!.containsKey(PdfDictionaryProperties.usageApplication)) { + state = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.usageApplication], + ); + } + if (state == null) { + final PdfFieldHelper fieldHelper = PdfFieldHelper.getHelper(field); + final IPdfPrimitive? name = PdfFieldHelper.getValue( + fieldHelper.dictionary!, + fieldHelper.crossTable, + PdfDictionaryProperties.v, + false, + ); + if (name != null && name is PdfName) { + check = + (name.name == + fieldHelper.getItemValue(dictionary!, fieldHelper.crossTable)); + } + } else if (state is PdfName) { + check = (state.name != PdfDictionaryProperties.off); + } + return check; + } + + /// internal method + void setCheckedStatus(bool check) { + final PdfFieldHelper fieldHelper = PdfFieldHelper.getHelper(field); + String? val = fieldHelper.getItemValue(dictionary!, fieldHelper.crossTable); + if (val != null) { + _uncheckOthers(val, check, fieldHelper); + } + if (check) { + if (val == null || val.isEmpty) { + val = PdfDictionaryProperties.yes; + } + fieldHelper.dictionary!.setName(PdfName(PdfDictionaryProperties.v), val); + dictionary!.setProperty( + PdfDictionaryProperties.usageApplication, + PdfName(val), + ); + dictionary!.setProperty(PdfDictionaryProperties.v, PdfName(val)); + } else { + IPdfPrimitive? v; + if (fieldHelper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + v = PdfCrossTable.dereference( + fieldHelper.dictionary![PdfDictionaryProperties.v], + ); + } + if (v != null && v is PdfName && val == v.name) { + fieldHelper.dictionary!.remove(PdfDictionaryProperties.v); + } + dictionary!.setProperty( + PdfDictionaryProperties.usageApplication, + PdfName(PdfDictionaryProperties.off), + ); + } + fieldHelper.changed = true; + } + + /// internal method + void _uncheckOthers(String value, bool check, PdfFieldHelper fieldHelper) { + final PdfFieldItemCollection? items = (field as PdfCheckBoxField).items; + if (items != null && items.count > 0) { + final PdfFieldItemCollectionHelper fieldItemCollectionHelper = + PdfFieldItemCollectionHelper.getHelper(items); + if (fieldItemCollectionHelper.allowUncheck) { + fieldItemCollectionHelper.allowUncheck = false; + for (int i = 0; i < items.count; i++) { + final PdfFieldItem item = items[i]; + if (item != fieldItem && item is PdfCheckBoxItem) { + final String? val = fieldHelper.getItemValue( + PdfFieldItemHelper.getHelper(item).dictionary!, + fieldHelper.crossTable, + ); + final bool v = val != null && val == value; + if (v && check) { + item.checked = true; + } else { + item.checked = false; + } + } + } + } + fieldItemCollectionHelper.allowUncheck = true; + } + } +} + +/// Represents loaded check box item. +class PdfCheckBoxItem extends PdfFieldItem { + PdfCheckBoxItem._(super.field, super.index, super.dictionary) : super._(); + + //Properties + /// Gets or sets a value indicating whether the [PdfCheckBoxItem] is checked. + bool get checked => _helper.obtainCheckedStatus(); + + set checked(bool value) { + if (!_helper.field.readOnly) { + if (value != checked) { + _helper.setCheckedStatus(value); + PdfFormHelper.getHelper(_helper.field.form!).setAppearanceDictionary = + true; + } + } + } + + //Implementation + void _setStyle(PdfCheckBoxStyle value) { + String style = ''; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.mk)) { + switch (value) { + case PdfCheckBoxStyle.check: + style = '4'; + break; + case PdfCheckBoxStyle.circle: + style = 'l'; + break; + case PdfCheckBoxStyle.cross: + style = '8'; + break; + case PdfCheckBoxStyle.diamond: + style = 'u'; + break; + case PdfCheckBoxStyle.square: + style = 'n'; + break; + case PdfCheckBoxStyle.star: + style = 'H'; + break; + } + final IPdfPrimitive? mk = _helper.dictionary![PdfDictionaryProperties.mk]; + if (mk is PdfReferenceHolder) { + final IPdfPrimitive? widgetDict = mk.object; + if (widgetDict is PdfDictionary) { + if (widgetDict.containsKey(PdfDictionaryProperties.ca)) { + widgetDict[PdfDictionaryProperties.ca] = PdfString(style); + } else { + widgetDict.setProperty( + PdfDictionaryProperties.ca, + PdfString(style), + ); + } + } + } else if (mk is PdfDictionary) { + mk[PdfDictionaryProperties.ca] = PdfString(style); + } + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfCheckBoxItem] helper +class PdfCheckBoxItemHelper { + /// internal method + static void setStyle(PdfCheckBoxItem checkBoxItem, PdfCheckBoxStyle value) { + checkBoxItem._setStyle(value); + } + + /// internal method + static PdfCheckBoxItem getItem( + PdfField field, + int index, + PdfDictionary? dictionary, + ) { + return PdfCheckBoxItem._(field, index, dictionary); + } +} + +/// Represents an item in a text box field collection. +class PdfTextBoxItem extends PdfFieldItem { + PdfTextBoxItem._(super.field, super.index, super.dictionary) : super._(); +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfTextBoxItem] helper +class PdfTextBoxItemHelper { + /// internal method + static PdfTextBoxItem getItem( + PdfField field, + int index, + PdfDictionary? dictionary, + ) { + return PdfTextBoxItem._(field, index, dictionary); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item_collection.dart index 43e5678e6..9454b3a5b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_item_collection.dart @@ -1,72 +1,72 @@ -import '../general/pdf_collection.dart'; -import '../io/pdf_constants.dart'; -import 'pdf_field.dart'; -import 'pdf_field_item.dart'; - -/// Represents collection field items. -class PdfFieldItemCollection extends PdfObjectCollection { - //Constructor - PdfFieldItemCollection._(PdfField field) { - _helper = PdfFieldItemCollectionHelper(this, field); - } - - //Fields - late PdfFieldItemCollectionHelper _helper; - - //Properties - /// Gets the Field item at the specified index. - PdfFieldItem operator [](int index) { - if (index < 0 || index >= count) { - throw RangeError('index'); - } - return _helper.list[index] as PdfFieldItem; - } - - //Implementations - /// Clears all items in the list. - void clear() { - _helper.clear(); - } -} - -/// [PdfFieldItemCollection] helper -class PdfFieldItemCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfFieldItemCollectionHelper(this.fieldItemCollection, this.field) - : super(fieldItemCollection); - - /// internal field - late PdfFieldItemCollection fieldItemCollection; - - /// internal field - late PdfField field; - - /// internal field - bool allowUncheck = true; - - /// internal method - static PdfFieldItemCollection load(PdfField field) { - return PdfFieldItemCollection._(field); - } - - /// internal method - static PdfFieldItemCollectionHelper getHelper( - PdfFieldItemCollection collection, - ) { - return collection._helper; - } - - /// internal method - void add(PdfFieldItem item) { - list.add(item); - } - - /// internal method - void clear() { - PdfFieldHelper.getHelper(field).array.clear(); - list.clear(); - PdfFieldHelper.getHelper( - field, - ).dictionary!.remove(PdfDictionaryProperties.kids); - } -} +import '../general/pdf_collection.dart'; +import '../io/pdf_constants.dart'; +import 'pdf_field.dart'; +import 'pdf_field_item.dart'; + +/// Represents collection field items. +class PdfFieldItemCollection extends PdfObjectCollection { + //Constructor + PdfFieldItemCollection._(PdfField field) { + _helper = PdfFieldItemCollectionHelper(this, field); + } + + //Fields + late PdfFieldItemCollectionHelper _helper; + + //Properties + /// Gets the Field item at the specified index. + PdfFieldItem operator [](int index) { + if (index < 0 || index >= count) { + throw RangeError('index'); + } + return _helper.list[index] as PdfFieldItem; + } + + //Implementations + /// Clears all items in the list. + void clear() { + _helper.clear(); + } +} + +/// [PdfFieldItemCollection] helper +class PdfFieldItemCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfFieldItemCollectionHelper(this.fieldItemCollection, this.field) + : super(fieldItemCollection); + + /// internal field + late PdfFieldItemCollection fieldItemCollection; + + /// internal field + late PdfField field; + + /// internal field + bool allowUncheck = true; + + /// internal method + static PdfFieldItemCollection load(PdfField field) { + return PdfFieldItemCollection._(field); + } + + /// internal method + static PdfFieldItemCollectionHelper getHelper( + PdfFieldItemCollection collection, + ) { + return collection._helper; + } + + /// internal method + void add(PdfFieldItem item) { + list.add(item); + } + + /// internal method + void clear() { + PdfFieldHelper.getHelper(field).array.clear(); + list.clear(); + PdfFieldHelper.getHelper( + field, + ).dictionary!.remove(PdfDictionaryProperties.kids); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_painter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_painter.dart index 9492eee52..089ce13f0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_painter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_field_painter.dart @@ -1,755 +1,755 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../annotations/enum.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../drawing/drawing.dart'; -import '../graphics/brushes/pdf_brush.dart'; -import '../graphics/brushes/pdf_solid_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_path.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/fonts/pdf_string_format.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_pen.dart'; -import 'enum.dart'; -import 'pdf_list_field_item.dart'; -import 'pdf_list_field_item_collection.dart'; - -/// Represents class which draws form fields. -class FieldPainter { - /// internal constructor - FieldPainter(); - - //Implementations - /// Draws a rectangular control. - void drawRectangularControl(PdfGraphics graphics, PaintParams params) { - graphics.drawRectangle( - bounds: params.bounds ?? Rect.zero, - brush: params.backBrush, - ); - drawBorder( - graphics, - params.bounds, - params.borderPen, - params.style, - params.borderWidth, - ); - switch (params.style) { - case PdfBorderStyle.inset: - drawLeftTopShadow( - graphics, - params.bounds!, - params.borderWidth!, - PdfBrushes.gray, - ); - drawRightBottomShadow( - graphics, - params.bounds!, - params.borderWidth!, - PdfBrushes.silver, - ); - break; - case PdfBorderStyle.beveled: - drawLeftTopShadow( - graphics, - params.bounds!, - params.borderWidth!, - PdfBrushes.white, - ); - drawRightBottomShadow( - graphics, - params.bounds!, - params.borderWidth!, - params.shadowBrush, - ); - break; - // ignore: no_default_cases - default: - break; - } - } - - /// internal method - void drawCheckBox( - PdfGraphics g, - PaintParams paintParams, - String checkSymbol, - PdfCheckFieldState state, [ - PdfFont? font, - ]) { - switch (state) { - case PdfCheckFieldState.unchecked: - case PdfCheckFieldState.checked: - if (paintParams.borderPen != null && - PdfColorHelper.getHelper(paintParams.borderPen!.color).alpha != 0) { - g.drawRectangle( - brush: paintParams.backBrush, - bounds: paintParams.bounds!, - ); - } - break; - - case PdfCheckFieldState.pressedChecked: - case PdfCheckFieldState.pressedUnchecked: - if ((paintParams.style == PdfBorderStyle.beveled) || - (paintParams.style == PdfBorderStyle.underline)) { - if (paintParams.borderPen != null && - PdfColorHelper.getHelper(paintParams.borderPen!.color).alpha != - 0) { - g.drawRectangle( - brush: paintParams.backBrush, - bounds: paintParams.bounds!, - ); - } - } else { - if (paintParams.borderPen != null && - PdfColorHelper.getHelper(paintParams.borderPen!.color).alpha != - 0) { - g.drawRectangle( - brush: paintParams.shadowBrush, - bounds: paintParams.bounds!, - ); - } - } - break; - } - - drawBorder( - g, - paintParams.bounds, - paintParams.borderPen, - paintParams.style, - paintParams.borderWidth, - ); - - if ((state == PdfCheckFieldState.pressedChecked) || - (state == PdfCheckFieldState.pressedUnchecked)) { - switch (paintParams.style) { - case PdfBorderStyle.inset: - drawLeftTopShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.black, - ); - drawRightBottomShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.white, - ); - break; - - case PdfBorderStyle.beveled: - drawLeftTopShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - paintParams.shadowBrush, - ); - drawRightBottomShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.white, - ); - break; - // ignore: no_default_cases - default: - } - } else { - switch (paintParams.style) { - case PdfBorderStyle.inset: - drawLeftTopShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.gray, - ); - drawRightBottomShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.silver, - ); - break; - - case PdfBorderStyle.beveled: - drawLeftTopShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.white, - ); - drawRightBottomShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - paintParams.shadowBrush, - ); - break; - // ignore: no_default_cases - default: - } - } - double yOffset = 0; - double size = 0; - switch (state) { - case PdfCheckFieldState.pressedChecked: - case PdfCheckFieldState.checked: - if (font == null) { - final bool extraBorder = - paintParams.style == PdfBorderStyle.beveled || - paintParams.style == PdfBorderStyle.inset; - - double borderWidth = paintParams.borderWidth!.toDouble(); - if (extraBorder) { - borderWidth *= 2; - } - double xPosition = - extraBorder - ? 2.0 * paintParams.borderWidth! - : paintParams.borderWidth!.toDouble(); - xPosition = max(xPosition, 1); - final double xOffset = min(borderWidth, xPosition); - - size = - (paintParams.bounds!.width > paintParams.bounds!.height) - ? paintParams.bounds!.height - : paintParams.bounds!.width; - - final double fontSize = size - 2 * xOffset; - - font = PdfStandardFont(PdfFontFamily.zapfDingbats, fontSize); - if (paintParams.bounds!.width > paintParams.bounds!.height) { - yOffset = (paintParams.bounds!.height - font.height) / 2; - } - } else { - font = PdfStandardFont(PdfFontFamily.zapfDingbats, font.size); - } - if (size == 0) { - size = paintParams.bounds!.height; - } - - if (size < font.size) { - ArgumentError.value( - 'Font size cannot be greater than CheckBox height', - ); - } - g.drawString( - checkSymbol, - font, - brush: paintParams.foreBrush, - bounds: Rect.fromLTWH( - paintParams.bounds!.left, - paintParams.bounds!.top - yOffset, - paintParams.bounds!.width, - paintParams.bounds!.height, - ), - format: PdfStringFormat( - alignment: PdfTextAlignment.center, - lineAlignment: PdfVerticalAlignment.middle, - ), - ); - break; - // ignore: no_default_cases - default: - } - } - - /// Draws a border. - void drawBorder( - PdfGraphics graphics, - Rect? bounds, - PdfPen? borderPen, - PdfBorderStyle? style, - int? borderWidth, - ) { - if (borderPen != null) { - if (borderWidth! > 0 && !borderPen.color.isEmpty) { - if (style == PdfBorderStyle.underline) { - graphics.drawLine( - borderPen, - Offset(bounds!.left, bounds.top + bounds.height - borderWidth / 2), - Offset( - bounds.left + bounds.width, - bounds.top + bounds.height - borderWidth / 2, - ), - ); - } else { - graphics.drawRectangle( - pen: borderPen, - bounds: Rect.fromLTWH( - bounds!.left + borderWidth / 2, - bounds.top + borderWidth / 2, - bounds.width - borderWidth, - bounds.height - borderWidth, - ), - ); - } - } - } - } - - /// internal method - void drawRadioButton( - PdfGraphics? g, - PaintParams paintParams, - String checkSymbol, - PdfCheckFieldState state, - ) { - //if the symbol is not a circle type ("l") then we need to draw the checkbox appearance - if (checkSymbol != 'l') { - drawCheckBox(g!, paintParams, checkSymbol, state); - } else { - switch (state) { - case PdfCheckFieldState.unchecked: - case PdfCheckFieldState.checked: - g!.drawEllipse(paintParams.bounds!, brush: paintParams.backBrush); - break; - - case PdfCheckFieldState.pressedChecked: - case PdfCheckFieldState.pressedUnchecked: - if ((paintParams.style == PdfBorderStyle.beveled) || - (paintParams.style == PdfBorderStyle.underline)) { - g!.drawEllipse(paintParams.bounds!, brush: paintParams.backBrush); - } else { - g!.drawEllipse(paintParams.bounds!, brush: paintParams.shadowBrush); - } - - break; - } - drawRoundBorder( - g, - paintParams.bounds, - paintParams.borderPen, - paintParams.borderWidth, - ); - drawRoundShadow(g, paintParams, state); - switch (state) { - case PdfCheckFieldState.checked: - case PdfCheckFieldState.pressedChecked: - final Rect outward = Rect.fromLTWH( - paintParams.bounds!.left + paintParams.borderWidth! / 2.0, - paintParams.bounds!.top + paintParams.borderWidth! / 2.0, - paintParams.bounds!.width - paintParams.borderWidth!, - paintParams.bounds!.height - paintParams.borderWidth!, - ); - Rect checkedBounds = outward; - checkedBounds = Rect.fromLTWH( - checkedBounds.left + (outward.width / 4), - checkedBounds.top + (outward.width / 4), - checkedBounds.width - (outward.width / 2), - checkedBounds.height - (outward.width / 2), - ); - g.drawEllipse( - checkedBounds, - brush: paintParams.foreBrush ?? PdfBrushes.black, - ); - break; - // ignore: no_default_cases - default: - break; - } - } - } - - /// Draws the left top shadow. - void drawLeftTopShadow( - PdfGraphics graphics, - Rect bounds, - int width, - PdfBrush? brush, - ) { - final List points = [ - Offset(bounds.left + width, bounds.top + width), - Offset(bounds.left + width, bounds.bottom - width), - Offset(bounds.left + 2 * width, bounds.bottom - 2 * width), - Offset(bounds.left + 2 * width, bounds.top + 2 * width), - Offset(bounds.right - 2 * width, bounds.top + 2 * width), - Offset(bounds.right - width, bounds.top + width), - ]; - graphics.drawPath(PdfPath()..addPolygon(points), brush: brush); - } - - /// Draws the right bottom shadow. - void drawRightBottomShadow( - PdfGraphics graphics, - Rect bounds, - int width, - PdfBrush? brush, - ) { - final List points = [ - Offset(bounds.left + width, bounds.bottom - width), - Offset(bounds.left + 2 * width, bounds.bottom - 2 * width), - Offset(bounds.right - 2 * width, bounds.bottom - 2 * width), - Offset(bounds.right - 2 * width, bounds.top + 2 * width), - Offset(bounds.left + bounds.width - width, bounds.top + width), - Offset(bounds.right - width, bounds.bottom - width), - ]; - graphics.drawPath(PdfPath()..addPolygon(points), brush: brush); - } - - /// internal method - void drawButton( - PdfGraphics g, - PaintParams paintParams, - String text, - PdfFont font, - PdfStringFormat? format, - ) { - drawRectangularControl(g, paintParams); - final Rect? rectangle = paintParams.bounds; - g.drawString( - text, - font, - brush: paintParams.foreBrush, - bounds: rectangle, - format: format, - ); - } - - /// internal method - void drawPressedButton( - PdfGraphics g, - PaintParams paintParams, - String text, - PdfFont font, - PdfStringFormat? format, - ) { - switch (paintParams.style) { - case PdfBorderStyle.inset: - g.drawRectangle( - brush: paintParams.shadowBrush, - bounds: paintParams.bounds!, - ); - break; - // ignore: no_default_cases - default: - g.drawRectangle( - brush: paintParams.backBrush, - bounds: paintParams.bounds!, - ); - break; - } - - drawBorder( - g, - paintParams.bounds, - paintParams.borderPen, - paintParams.style, - paintParams.borderWidth, - ); - - final Rect rectangle = Rect.fromLTWH( - paintParams.borderWidth!.toDouble(), - paintParams.borderWidth!.toDouble(), - paintParams.bounds!.size.width - paintParams.borderWidth!, - paintParams.bounds!.size.height - paintParams.borderWidth!, - ); - g.drawString( - text, - font, - brush: paintParams.foreBrush, - bounds: rectangle, - format: format, - ); - - switch (paintParams.style) { - case PdfBorderStyle.inset: - drawLeftTopShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.gray, - ); - drawRightBottomShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.silver, - ); - break; - - case PdfBorderStyle.beveled: - drawLeftTopShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - paintParams.shadowBrush, - ); - drawRightBottomShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - PdfBrushes.white, - ); - break; - - // ignore: no_default_cases - default: - drawLeftTopShadow( - g, - paintParams.bounds!, - paintParams.borderWidth!, - paintParams.shadowBrush, - ); - break; - } - } - - /// internal method - void drawRoundBorder( - PdfGraphics? g, - Rect? bounds, - PdfPen? borderPen, - int? borderWidth, - ) { - Rect? outward = bounds; - if (outward != Rect.zero) { - outward = Rect.fromLTWH( - bounds!.left + borderWidth! / 2.0, - bounds.top + borderWidth / 2.0, - bounds.width - borderWidth, - bounds.height - borderWidth, - ); - g!.drawEllipse(outward, pen: borderPen); - } - } - - /// internal method - void drawRoundShadow( - PdfGraphics? g, - PaintParams paintParams, - PdfCheckFieldState state, - ) { - final double borderWidth = paintParams.borderWidth!.toDouble(); - final Rect rectangle = paintParams.bounds!; - rectangle.inflate(-1.5 * borderWidth); - PdfPen? leftTopPen; - PdfPen? rightBottomPen; - final PdfSolidBrush shadowBrush = paintParams.shadowBrush! as PdfSolidBrush; - final PdfColor shadowColor = shadowBrush.color; - - switch (paintParams.style) { - case PdfBorderStyle.beveled: - switch (state) { - case PdfCheckFieldState.pressedChecked: - case PdfCheckFieldState.pressedUnchecked: - leftTopPen = PdfPen(shadowColor, width: borderWidth); - rightBottomPen = PdfPen( - PdfColor(255, 255, 255), - width: borderWidth, - ); - break; - - case PdfCheckFieldState.checked: - case PdfCheckFieldState.unchecked: - leftTopPen = PdfPen(PdfColor(255, 255, 255), width: borderWidth); - rightBottomPen = PdfPen(shadowColor, width: borderWidth); - break; - } - break; - - case PdfBorderStyle.inset: - switch (state) { - case PdfCheckFieldState.pressedChecked: - case PdfCheckFieldState.pressedUnchecked: - leftTopPen = PdfPen(PdfColor(0, 0, 0), width: borderWidth); - rightBottomPen = PdfPen(PdfColor(0, 0, 0), width: borderWidth); - break; - - case PdfCheckFieldState.checked: - case PdfCheckFieldState.unchecked: - leftTopPen = PdfPen( - PdfColor(255, 128, 128, 128), - width: borderWidth, - ); - rightBottomPen = PdfPen( - PdfColor(255, 192, 192, 192), - width: borderWidth, - ); - break; - } - break; - // ignore: no_default_cases - default: - } - if (leftTopPen != null && rightBottomPen != null) { - g!.drawArc(rectangle, 135, 180, pen: leftTopPen); - g.drawArc(rectangle, -45, 180, pen: rightBottomPen); - } - } - - /// Draws the combo box - void drawComboBox( - PdfGraphics graphics, - PaintParams paintParams, - String? text, - PdfFont? font, - PdfStringFormat? format, - ) { - drawRectangularControl(graphics, paintParams); - final Rect? rectangle = paintParams.bounds; - graphics.drawString( - text!, - font!, - brush: paintParams.foreBrush, - bounds: rectangle, - format: format, - ); - } - - /// Draws the list box - void drawListBox( - PdfGraphics graphics, - PaintParams params, - PdfListFieldItemCollection items, - List selectedItem, - PdfFont font, - PdfStringFormat? stringFormat, - ) { - FieldPainter().drawRectangularControl(graphics, params); - for (int index = 0; index < items.count; index++) { - final PdfListFieldItem item = items[index]; - final int borderWidth = params.borderWidth!; - final double doubleBorderWidth = (2 * borderWidth).toDouble(); - final bool padding = - params.style == PdfBorderStyle.inset || - params.style == PdfBorderStyle.beveled; - final Offset point = - padding - ? Offset( - 2 * doubleBorderWidth, - (index + 2) * borderWidth + font.size * index, - ) - : Offset( - doubleBorderWidth, - (index + 1) * borderWidth + font.size * index, - ); - PdfBrush? brush = params.foreBrush; - double width = params.bounds!.width - doubleBorderWidth; - final Rect rectangle = Rect.fromLTWH( - params.bounds!.left, - params.bounds!.top, - params.bounds!.width, - params.bounds!.height - (padding ? doubleBorderWidth : borderWidth), - ); - graphics.setClip(bounds: rectangle, mode: PdfFillMode.winding); - bool selected = false; - for (final int selectedIndex in selectedItem) { - if (selectedIndex == index) { - selected = true; - } - } - if (selected) { - double x = rectangle.left + borderWidth; - if (padding) { - x += borderWidth; - width -= doubleBorderWidth; - } - brush = PdfSolidBrush(PdfColor(51, 153, 255)); - graphics.drawRectangle( - brush: brush, - bounds: Rect.fromLTWH(x, point.dy, width, font.height), - ); - brush = PdfSolidBrush(PdfColor(255, 255, 255)); - } - final String value = item.text; - final PdfRectangle itemTextBound = PdfRectangle( - point.dx, - point.dy, - width - point.dx, - font.height, - ); - PdfGraphicsHelper.getHelper(graphics).layoutString( - value, - font, - brush: brush ?? PdfSolidBrush(PdfColor(0, 0, 0)), - layoutRectangle: itemTextBound, - format: stringFormat, - ); - } - } - - /// Draws the text box - void drawTextBox( - PdfGraphics graphics, - PaintParams params, - String text, - PdfFont font, - PdfStringFormat format, - bool insertSpaces, - bool multiline, - ) { - if (!insertSpaces) { - FieldPainter().drawRectangularControl(graphics, params); - } - final int multiplier = - params.style == PdfBorderStyle.beveled || - params.style == PdfBorderStyle.inset - ? 2 - : 1; - Rect rectangle = Rect.fromLTWH( - params.bounds!.left + (2 * multiplier) * params.borderWidth!, - params.bounds!.top + (2 * multiplier) * params.borderWidth!, - params.bounds!.width - (4 * multiplier) * params.borderWidth!, - params.bounds!.height - (4 * multiplier) * params.borderWidth!, - ); - // Calculate position of the text. - if (multiline) { - final double tempHeight = - format.lineSpacing == 0 ? font.height : format.lineSpacing; - final bool subScript = - format.subSuperscript == PdfSubSuperscript.subscript; - final double ascent = PdfFontHelper.getHelper( - font, - ).metrics!.getAscent(format); - final double descent = PdfFontHelper.getHelper( - font, - ).metrics!.getDescent(format); - final double shift = - subScript - ? tempHeight - (font.height + descent) - : tempHeight - ascent; - if (rectangle.left == 0 && rectangle.top == 0) { - rectangle = Rect.fromLTWH( - rectangle.left, - -(rectangle.top - shift), - rectangle.width, - rectangle.height, - ); - } - graphics.drawString( - text, - font, - brush: params.foreBrush, - bounds: rectangle, - format: PdfStringFormat( - alignment: format.alignment, - lineAlignment: format.lineAlignment, - )..lineLimit = false, - ); - } else { - graphics.drawString( - text, - font, - brush: params.foreBrush, - bounds: rectangle, - format: PdfStringFormat( - alignment: format.alignment, - lineAlignment: PdfVerticalAlignment.middle, - )..lineLimit = false, - ); - } - } - - /// internal method - void drawSignature(PdfGraphics graphics, PaintParams paintParams) { - drawRectangularControl(graphics, paintParams); - } -} +import 'dart:math'; +import 'dart:ui'; + +import '../annotations/enum.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../drawing/drawing.dart'; +import '../graphics/brushes/pdf_brush.dart'; +import '../graphics/brushes/pdf_solid_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_path.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/fonts/pdf_string_format.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_pen.dart'; +import 'enum.dart'; +import 'pdf_list_field_item.dart'; +import 'pdf_list_field_item_collection.dart'; + +/// Represents class which draws form fields. +class FieldPainter { + /// internal constructor + FieldPainter(); + + //Implementations + /// Draws a rectangular control. + void drawRectangularControl(PdfGraphics graphics, PaintParams params) { + graphics.drawRectangle( + bounds: params.bounds ?? Rect.zero, + brush: params.backBrush, + ); + drawBorder( + graphics, + params.bounds, + params.borderPen, + params.style, + params.borderWidth, + ); + switch (params.style) { + case PdfBorderStyle.inset: + drawLeftTopShadow( + graphics, + params.bounds!, + params.borderWidth!, + PdfBrushes.gray, + ); + drawRightBottomShadow( + graphics, + params.bounds!, + params.borderWidth!, + PdfBrushes.silver, + ); + break; + case PdfBorderStyle.beveled: + drawLeftTopShadow( + graphics, + params.bounds!, + params.borderWidth!, + PdfBrushes.white, + ); + drawRightBottomShadow( + graphics, + params.bounds!, + params.borderWidth!, + params.shadowBrush, + ); + break; + // ignore: no_default_cases + default: + break; + } + } + + /// internal method + void drawCheckBox( + PdfGraphics g, + PaintParams paintParams, + String checkSymbol, + PdfCheckFieldState state, [ + PdfFont? font, + ]) { + switch (state) { + case PdfCheckFieldState.unchecked: + case PdfCheckFieldState.checked: + if (paintParams.borderPen != null && + PdfColorHelper.getHelper(paintParams.borderPen!.color).alpha != 0) { + g.drawRectangle( + brush: paintParams.backBrush, + bounds: paintParams.bounds!, + ); + } + break; + + case PdfCheckFieldState.pressedChecked: + case PdfCheckFieldState.pressedUnchecked: + if ((paintParams.style == PdfBorderStyle.beveled) || + (paintParams.style == PdfBorderStyle.underline)) { + if (paintParams.borderPen != null && + PdfColorHelper.getHelper(paintParams.borderPen!.color).alpha != + 0) { + g.drawRectangle( + brush: paintParams.backBrush, + bounds: paintParams.bounds!, + ); + } + } else { + if (paintParams.borderPen != null && + PdfColorHelper.getHelper(paintParams.borderPen!.color).alpha != + 0) { + g.drawRectangle( + brush: paintParams.shadowBrush, + bounds: paintParams.bounds!, + ); + } + } + break; + } + + drawBorder( + g, + paintParams.bounds, + paintParams.borderPen, + paintParams.style, + paintParams.borderWidth, + ); + + if ((state == PdfCheckFieldState.pressedChecked) || + (state == PdfCheckFieldState.pressedUnchecked)) { + switch (paintParams.style) { + case PdfBorderStyle.inset: + drawLeftTopShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.black, + ); + drawRightBottomShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.white, + ); + break; + + case PdfBorderStyle.beveled: + drawLeftTopShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + paintParams.shadowBrush, + ); + drawRightBottomShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.white, + ); + break; + // ignore: no_default_cases + default: + } + } else { + switch (paintParams.style) { + case PdfBorderStyle.inset: + drawLeftTopShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.gray, + ); + drawRightBottomShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.silver, + ); + break; + + case PdfBorderStyle.beveled: + drawLeftTopShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.white, + ); + drawRightBottomShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + paintParams.shadowBrush, + ); + break; + // ignore: no_default_cases + default: + } + } + double yOffset = 0; + double size = 0; + switch (state) { + case PdfCheckFieldState.pressedChecked: + case PdfCheckFieldState.checked: + if (font == null) { + final bool extraBorder = + paintParams.style == PdfBorderStyle.beveled || + paintParams.style == PdfBorderStyle.inset; + + double borderWidth = paintParams.borderWidth!.toDouble(); + if (extraBorder) { + borderWidth *= 2; + } + double xPosition = + extraBorder + ? 2.0 * paintParams.borderWidth! + : paintParams.borderWidth!.toDouble(); + xPosition = max(xPosition, 1); + final double xOffset = min(borderWidth, xPosition); + + size = + (paintParams.bounds!.width > paintParams.bounds!.height) + ? paintParams.bounds!.height + : paintParams.bounds!.width; + + final double fontSize = size - 2 * xOffset; + + font = PdfStandardFont(PdfFontFamily.zapfDingbats, fontSize); + if (paintParams.bounds!.width > paintParams.bounds!.height) { + yOffset = (paintParams.bounds!.height - font.height) / 2; + } + } else { + font = PdfStandardFont(PdfFontFamily.zapfDingbats, font.size); + } + if (size == 0) { + size = paintParams.bounds!.height; + } + + if (size < font.size) { + ArgumentError.value( + 'Font size cannot be greater than CheckBox height', + ); + } + g.drawString( + checkSymbol, + font, + brush: paintParams.foreBrush, + bounds: Rect.fromLTWH( + paintParams.bounds!.left, + paintParams.bounds!.top - yOffset, + paintParams.bounds!.width, + paintParams.bounds!.height, + ), + format: PdfStringFormat( + alignment: PdfTextAlignment.center, + lineAlignment: PdfVerticalAlignment.middle, + ), + ); + break; + // ignore: no_default_cases + default: + } + } + + /// Draws a border. + void drawBorder( + PdfGraphics graphics, + Rect? bounds, + PdfPen? borderPen, + PdfBorderStyle? style, + int? borderWidth, + ) { + if (borderPen != null) { + if (borderWidth! > 0 && !borderPen.color.isEmpty) { + if (style == PdfBorderStyle.underline) { + graphics.drawLine( + borderPen, + Offset(bounds!.left, bounds.top + bounds.height - borderWidth / 2), + Offset( + bounds.left + bounds.width, + bounds.top + bounds.height - borderWidth / 2, + ), + ); + } else { + graphics.drawRectangle( + pen: borderPen, + bounds: Rect.fromLTWH( + bounds!.left + borderWidth / 2, + bounds.top + borderWidth / 2, + bounds.width - borderWidth, + bounds.height - borderWidth, + ), + ); + } + } + } + } + + /// internal method + void drawRadioButton( + PdfGraphics? g, + PaintParams paintParams, + String checkSymbol, + PdfCheckFieldState state, + ) { + //if the symbol is not a circle type ("l") then we need to draw the checkbox appearance + if (checkSymbol != 'l') { + drawCheckBox(g!, paintParams, checkSymbol, state); + } else { + switch (state) { + case PdfCheckFieldState.unchecked: + case PdfCheckFieldState.checked: + g!.drawEllipse(paintParams.bounds!, brush: paintParams.backBrush); + break; + + case PdfCheckFieldState.pressedChecked: + case PdfCheckFieldState.pressedUnchecked: + if ((paintParams.style == PdfBorderStyle.beveled) || + (paintParams.style == PdfBorderStyle.underline)) { + g!.drawEllipse(paintParams.bounds!, brush: paintParams.backBrush); + } else { + g!.drawEllipse(paintParams.bounds!, brush: paintParams.shadowBrush); + } + + break; + } + drawRoundBorder( + g, + paintParams.bounds, + paintParams.borderPen, + paintParams.borderWidth, + ); + drawRoundShadow(g, paintParams, state); + switch (state) { + case PdfCheckFieldState.checked: + case PdfCheckFieldState.pressedChecked: + final Rect outward = Rect.fromLTWH( + paintParams.bounds!.left + paintParams.borderWidth! / 2.0, + paintParams.bounds!.top + paintParams.borderWidth! / 2.0, + paintParams.bounds!.width - paintParams.borderWidth!, + paintParams.bounds!.height - paintParams.borderWidth!, + ); + Rect checkedBounds = outward; + checkedBounds = Rect.fromLTWH( + checkedBounds.left + (outward.width / 4), + checkedBounds.top + (outward.width / 4), + checkedBounds.width - (outward.width / 2), + checkedBounds.height - (outward.width / 2), + ); + g.drawEllipse( + checkedBounds, + brush: paintParams.foreBrush ?? PdfBrushes.black, + ); + break; + // ignore: no_default_cases + default: + break; + } + } + } + + /// Draws the left top shadow. + void drawLeftTopShadow( + PdfGraphics graphics, + Rect bounds, + int width, + PdfBrush? brush, + ) { + final List points = [ + Offset(bounds.left + width, bounds.top + width), + Offset(bounds.left + width, bounds.bottom - width), + Offset(bounds.left + 2 * width, bounds.bottom - 2 * width), + Offset(bounds.left + 2 * width, bounds.top + 2 * width), + Offset(bounds.right - 2 * width, bounds.top + 2 * width), + Offset(bounds.right - width, bounds.top + width), + ]; + graphics.drawPath(PdfPath()..addPolygon(points), brush: brush); + } + + /// Draws the right bottom shadow. + void drawRightBottomShadow( + PdfGraphics graphics, + Rect bounds, + int width, + PdfBrush? brush, + ) { + final List points = [ + Offset(bounds.left + width, bounds.bottom - width), + Offset(bounds.left + 2 * width, bounds.bottom - 2 * width), + Offset(bounds.right - 2 * width, bounds.bottom - 2 * width), + Offset(bounds.right - 2 * width, bounds.top + 2 * width), + Offset(bounds.left + bounds.width - width, bounds.top + width), + Offset(bounds.right - width, bounds.bottom - width), + ]; + graphics.drawPath(PdfPath()..addPolygon(points), brush: brush); + } + + /// internal method + void drawButton( + PdfGraphics g, + PaintParams paintParams, + String text, + PdfFont font, + PdfStringFormat? format, + ) { + drawRectangularControl(g, paintParams); + final Rect? rectangle = paintParams.bounds; + g.drawString( + text, + font, + brush: paintParams.foreBrush, + bounds: rectangle, + format: format, + ); + } + + /// internal method + void drawPressedButton( + PdfGraphics g, + PaintParams paintParams, + String text, + PdfFont font, + PdfStringFormat? format, + ) { + switch (paintParams.style) { + case PdfBorderStyle.inset: + g.drawRectangle( + brush: paintParams.shadowBrush, + bounds: paintParams.bounds!, + ); + break; + // ignore: no_default_cases + default: + g.drawRectangle( + brush: paintParams.backBrush, + bounds: paintParams.bounds!, + ); + break; + } + + drawBorder( + g, + paintParams.bounds, + paintParams.borderPen, + paintParams.style, + paintParams.borderWidth, + ); + + final Rect rectangle = Rect.fromLTWH( + paintParams.borderWidth!.toDouble(), + paintParams.borderWidth!.toDouble(), + paintParams.bounds!.size.width - paintParams.borderWidth!, + paintParams.bounds!.size.height - paintParams.borderWidth!, + ); + g.drawString( + text, + font, + brush: paintParams.foreBrush, + bounds: rectangle, + format: format, + ); + + switch (paintParams.style) { + case PdfBorderStyle.inset: + drawLeftTopShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.gray, + ); + drawRightBottomShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.silver, + ); + break; + + case PdfBorderStyle.beveled: + drawLeftTopShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + paintParams.shadowBrush, + ); + drawRightBottomShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + PdfBrushes.white, + ); + break; + + // ignore: no_default_cases + default: + drawLeftTopShadow( + g, + paintParams.bounds!, + paintParams.borderWidth!, + paintParams.shadowBrush, + ); + break; + } + } + + /// internal method + void drawRoundBorder( + PdfGraphics? g, + Rect? bounds, + PdfPen? borderPen, + int? borderWidth, + ) { + Rect? outward = bounds; + if (outward != Rect.zero) { + outward = Rect.fromLTWH( + bounds!.left + borderWidth! / 2.0, + bounds.top + borderWidth / 2.0, + bounds.width - borderWidth, + bounds.height - borderWidth, + ); + g!.drawEllipse(outward, pen: borderPen); + } + } + + /// internal method + void drawRoundShadow( + PdfGraphics? g, + PaintParams paintParams, + PdfCheckFieldState state, + ) { + final double borderWidth = paintParams.borderWidth!.toDouble(); + final Rect rectangle = paintParams.bounds!; + rectangle.inflate(-1.5 * borderWidth); + PdfPen? leftTopPen; + PdfPen? rightBottomPen; + final PdfSolidBrush shadowBrush = paintParams.shadowBrush! as PdfSolidBrush; + final PdfColor shadowColor = shadowBrush.color; + + switch (paintParams.style) { + case PdfBorderStyle.beveled: + switch (state) { + case PdfCheckFieldState.pressedChecked: + case PdfCheckFieldState.pressedUnchecked: + leftTopPen = PdfPen(shadowColor, width: borderWidth); + rightBottomPen = PdfPen( + PdfColor(255, 255, 255), + width: borderWidth, + ); + break; + + case PdfCheckFieldState.checked: + case PdfCheckFieldState.unchecked: + leftTopPen = PdfPen(PdfColor(255, 255, 255), width: borderWidth); + rightBottomPen = PdfPen(shadowColor, width: borderWidth); + break; + } + break; + + case PdfBorderStyle.inset: + switch (state) { + case PdfCheckFieldState.pressedChecked: + case PdfCheckFieldState.pressedUnchecked: + leftTopPen = PdfPen(PdfColor(0, 0, 0), width: borderWidth); + rightBottomPen = PdfPen(PdfColor(0, 0, 0), width: borderWidth); + break; + + case PdfCheckFieldState.checked: + case PdfCheckFieldState.unchecked: + leftTopPen = PdfPen( + PdfColor(255, 128, 128, 128), + width: borderWidth, + ); + rightBottomPen = PdfPen( + PdfColor(255, 192, 192, 192), + width: borderWidth, + ); + break; + } + break; + // ignore: no_default_cases + default: + } + if (leftTopPen != null && rightBottomPen != null) { + g!.drawArc(rectangle, 135, 180, pen: leftTopPen); + g.drawArc(rectangle, -45, 180, pen: rightBottomPen); + } + } + + /// Draws the combo box + void drawComboBox( + PdfGraphics graphics, + PaintParams paintParams, + String? text, + PdfFont? font, + PdfStringFormat? format, + ) { + drawRectangularControl(graphics, paintParams); + final Rect? rectangle = paintParams.bounds; + graphics.drawString( + text!, + font!, + brush: paintParams.foreBrush, + bounds: rectangle, + format: format, + ); + } + + /// Draws the list box + void drawListBox( + PdfGraphics graphics, + PaintParams params, + PdfListFieldItemCollection items, + List selectedItem, + PdfFont font, + PdfStringFormat? stringFormat, + ) { + FieldPainter().drawRectangularControl(graphics, params); + for (int index = 0; index < items.count; index++) { + final PdfListFieldItem item = items[index]; + final int borderWidth = params.borderWidth!; + final double doubleBorderWidth = (2 * borderWidth).toDouble(); + final bool padding = + params.style == PdfBorderStyle.inset || + params.style == PdfBorderStyle.beveled; + final Offset point = + padding + ? Offset( + 2 * doubleBorderWidth, + (index + 2) * borderWidth + font.size * index, + ) + : Offset( + doubleBorderWidth, + (index + 1) * borderWidth + font.size * index, + ); + PdfBrush? brush = params.foreBrush; + double width = params.bounds!.width - doubleBorderWidth; + final Rect rectangle = Rect.fromLTWH( + params.bounds!.left, + params.bounds!.top, + params.bounds!.width, + params.bounds!.height - (padding ? doubleBorderWidth : borderWidth), + ); + graphics.setClip(bounds: rectangle, mode: PdfFillMode.winding); + bool selected = false; + for (final int selectedIndex in selectedItem) { + if (selectedIndex == index) { + selected = true; + } + } + if (selected) { + double x = rectangle.left + borderWidth; + if (padding) { + x += borderWidth; + width -= doubleBorderWidth; + } + brush = PdfSolidBrush(PdfColor(51, 153, 255)); + graphics.drawRectangle( + brush: brush, + bounds: Rect.fromLTWH(x, point.dy, width, font.height), + ); + brush = PdfSolidBrush(PdfColor(255, 255, 255)); + } + final String value = item.text; + final PdfRectangle itemTextBound = PdfRectangle( + point.dx, + point.dy, + width - point.dx, + font.height, + ); + PdfGraphicsHelper.getHelper(graphics).layoutString( + value, + font, + brush: brush ?? PdfSolidBrush(PdfColor(0, 0, 0)), + layoutRectangle: itemTextBound, + format: stringFormat, + ); + } + } + + /// Draws the text box + void drawTextBox( + PdfGraphics graphics, + PaintParams params, + String text, + PdfFont font, + PdfStringFormat format, + bool insertSpaces, + bool multiline, + ) { + if (!insertSpaces) { + FieldPainter().drawRectangularControl(graphics, params); + } + final int multiplier = + params.style == PdfBorderStyle.beveled || + params.style == PdfBorderStyle.inset + ? 2 + : 1; + Rect rectangle = Rect.fromLTWH( + params.bounds!.left + (2 * multiplier) * params.borderWidth!, + params.bounds!.top + (2 * multiplier) * params.borderWidth!, + params.bounds!.width - (4 * multiplier) * params.borderWidth!, + params.bounds!.height - (4 * multiplier) * params.borderWidth!, + ); + // Calculate position of the text. + if (multiline) { + final double tempHeight = + format.lineSpacing == 0 ? font.height : format.lineSpacing; + final bool subScript = + format.subSuperscript == PdfSubSuperscript.subscript; + final double ascent = PdfFontHelper.getHelper( + font, + ).metrics!.getAscent(format); + final double descent = PdfFontHelper.getHelper( + font, + ).metrics!.getDescent(format); + final double shift = + subScript + ? tempHeight - (font.height + descent) + : tempHeight - ascent; + if (rectangle.left == 0 && rectangle.top == 0) { + rectangle = Rect.fromLTWH( + rectangle.left, + -(rectangle.top - shift), + rectangle.width, + rectangle.height, + ); + } + graphics.drawString( + text, + font, + brush: params.foreBrush, + bounds: rectangle, + format: PdfStringFormat( + alignment: format.alignment, + lineAlignment: format.lineAlignment, + )..lineLimit = false, + ); + } else { + graphics.drawString( + text, + font, + brush: params.foreBrush, + bounds: rectangle, + format: PdfStringFormat( + alignment: format.alignment, + lineAlignment: PdfVerticalAlignment.middle, + )..lineLimit = false, + ); + } + } + + /// internal method + void drawSignature(PdfGraphics graphics, PaintParams paintParams) { + drawRectangularControl(graphics, paintParams); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart index 2e99b3d42..336d37e15 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form.dart @@ -1,1532 +1,1532 @@ -import 'dart:collection'; -import 'dart:convert'; - -import 'package:xml/xml.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/pdf_annotation_collection.dart'; -import '../graphics/pdf_resources.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_reader.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/pdf_catalog.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_check_box_field.dart'; -import 'pdf_combo_box_field.dart'; -import 'pdf_field.dart'; -import 'pdf_form_field_collection.dart'; -import 'pdf_list_box_field.dart'; -import 'pdf_radio_button_list_field.dart'; -import 'pdf_signature_field.dart'; -import 'pdf_xfdf_document.dart'; - -/// Represents interactive form of the PDF document. -class PdfForm implements IPdfWrapper { - //Constructors - /// Initializes a new instance of the [PdfForm] class. - PdfForm() : super() { - _helper = PdfFormHelper(this); - _helper._fields = PdfFormFieldCollectionHelper.getCollection(); - PdfFormFieldCollectionHelper.getHelper(_helper._fields!).form = this; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.fields, - _helper._fields, - ); - if (!_helper.isLoadedForm) { - _helper.dictionary!.beginSave = _helper.beginSave; - } - _helper.setAppearanceDictionary = true; - } - - PdfForm._internal( - PdfCrossTable? crossTable, [ - PdfDictionary? formDictionary, - ]) { - _helper = PdfFormHelper(this); - _helper.isLoadedForm = true; - _helper.crossTable = crossTable; - _helper.dictionary!.setBoolean( - PdfDictionaryProperties.needAppearances, - _helper.needAppearances, - ); - PdfDocumentHelper.getHelper(_helper.crossTable!.document!) - .catalog - .beginSaveList ??= []; - PdfDocumentHelper.getHelper( - _helper.crossTable!.document!, - ).catalog.beginSaveList!.add(_helper.beginSave); - PdfDocumentHelper.getHelper(_helper.crossTable!.document!).catalog.modify(); - if (PdfDocumentHelper.getHelper( - _helper.crossTable!.document!, - ).catalog.containsKey(PdfDictionaryProperties.perms)) { - _checkPerms( - PdfDocumentHelper.getHelper(_helper.crossTable!.document!).catalog, - ); - } - if (formDictionary != null) { - _initialize(formDictionary, crossTable!); - } - } - - //Fields - late PdfFormHelper _helper; - bool _readOnly = false; - - /// Gets or sets a value indicating whether field auto naming. - /// - /// The default value is true. - bool fieldAutoNaming = true; - - /// Gets or sets the ExportEmptyFields property, enabling this will export - /// the empty acroform fields. - /// - /// The default value is false. - bool exportEmptyFields = false; - - //Properties - - /// Gets the fields collection. - PdfFormFieldCollection get fields { - if (_helper.isLoadedForm) { - _helper._fields ??= PdfFormFieldCollectionHelper.getCollection(this); - } - return _helper._fields!; - } - - /// Gets or sets a value indicating whether the form is read only. - /// - /// The default value is false. - bool get readOnly => _readOnly; - set readOnly(bool value) { - _readOnly = value; - if (_helper.isLoadedForm) { - for (int i = 0; i < fields.count; i++) { - fields[i].readOnly = value; - } - } - } - - //Public methods. - /// Specifies whether to set the default appearance for the form or not. - void setDefaultAppearance(bool value) { - _helper.needAppearances = value; - _helper.setAppearanceDictionary = !value; - _helper._isDefaultAppearance = value; - } - - /// Flatten all the fields available in the form. - /// - /// The flatten will add at the time of saving the current document. - void flattenAllFields() { - _helper.flatten = true; - } - - /// Imports form value from base 64 string to the file with the specific [DataFormat]. - void importDataFromBase64String( - String base64String, - DataFormat dataFormat, [ - bool continueImportOnError = false, - ]) { - importData( - base64.decode(base64String).toList(), - dataFormat, - continueImportOnError, - ); - } - - /// Imports form value to the file with the specific [DataFormat]. - void importData( - List inputBytes, - DataFormat dataFormat, [ - bool continueImportOnError = false, - ]) { - if (dataFormat == DataFormat.fdf) { - _importDataFDF(inputBytes, continueImportOnError); - } else if (dataFormat == DataFormat.json) { - _importDataJSON(inputBytes, continueImportOnError); - } else if (dataFormat == DataFormat.xfdf) { - _importDataXFDF(inputBytes); - } else if (dataFormat == DataFormat.xml) { - _importDataXml(inputBytes, continueImportOnError); - } - } - - /// Export the form data to a file with the specific [DataFormat] and form name. - List exportData(DataFormat dataFormat, [String formName = '']) { - List? data; - if (dataFormat == DataFormat.fdf) { - data = _exportDataFDF(formName); - } else if (dataFormat == DataFormat.xfdf) { - data = _exportDataXFDF(formName); - } else if (dataFormat == DataFormat.json) { - data = _exportDataJSON(); - } else if (dataFormat == DataFormat.xml) { - data = _exportDataXML(); - } - return data!; - } - - /// Imports XFDF Data from the given data. - void _importDataXFDF(List bytes) { - final String data = utf8.decode(bytes); - final XmlDocument xmlDoc = XmlDocument.parse(data); - PdfField formField; - for (final XmlNode node in xmlDoc.rootElement.firstElementChild!.children) { - if (node is XmlElement) { - final String fieldName = node.attributes.first.value; - final int index = PdfFormFieldCollectionHelper.getHelper( - fields, - ).getFieldIndex(fieldName); - if (index >= 0 && index < fields.count) { - formField = fields[index]; - String? fieldInnerValue; - final List fieldInnerValues = []; - if (node.childElements.length > 1) { - for (int i = 0; i < node.childElements.length; i++) { - fieldInnerValues.add(node.childElements.elementAt(i).innerText); - } - } else { - fieldInnerValue = node.firstElementChild!.innerText; - } - if (fieldInnerValues.isNotEmpty) { - PdfFieldHelper.getHelper( - formField, - ).importFieldValue(fieldInnerValues); - } else if (fieldInnerValue != null) { - PdfFieldHelper.getHelper( - formField, - ).importFieldValue(fieldInnerValue); - } - } - } - } - } - - //Implementation - - void _initialize(PdfDictionary formDictionary, PdfCrossTable crossTable) { - _helper.dictionary = formDictionary; - //Get terminal fields. - _createFields(); - //Gets NeedAppearance - if (_helper.dictionary!.containsKey( - PdfDictionaryProperties.needAppearances, - )) { - final PdfBoolean needAppearance = - crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.needAppearances], - )! - as PdfBoolean; - _helper.needAppearances = needAppearance.value; - _helper.setAppearanceDictionary = true; - } else { - _helper.setAppearanceDictionary = false; - } - //Gets resource dictionary - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.dr)) { - final IPdfPrimitive? resourceDictionary = PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.dr], - ); - if (resourceDictionary != null && resourceDictionary is PdfDictionary) { - _helper.resources = PdfResources(resourceDictionary); - } - } - } - - //Retrieves the terminal fields. - void _createFields() { - PdfArray? fields; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.fields)) { - final IPdfPrimitive? obj = _helper.crossTable!.getObject( - _helper.dictionary![PdfDictionaryProperties.fields], - ); - if (obj != null) { - fields = obj as PdfArray; - } - } - int count = 0; - final Queue<_NodeInfo> nodes = Queue<_NodeInfo>(); - while (true && fields != null) { - for (; count < fields!.count; ++count) { - final IPdfPrimitive? fieldDictionary = _helper.crossTable!.getObject( - fields[count], - ); - PdfArray? fieldKids; - if (fieldDictionary != null && - fieldDictionary is PdfDictionary && - fieldDictionary.containsKey(PdfDictionaryProperties.kids)) { - final IPdfPrimitive? fieldKid = _helper.crossTable!.getObject( - fieldDictionary[PdfDictionaryProperties.kids], - ); - if (fieldKid != null && fieldKid is PdfArray) { - fieldKids = fieldKid; - for (int i = 0; i < fieldKids.count; i++) { - final IPdfPrimitive? kidsDict = PdfCrossTable.dereference( - fieldKids[i], - ); - if (kidsDict != null && - kidsDict is PdfDictionary && - !kidsDict.containsKey(PdfDictionaryProperties.parent)) { - kidsDict[PdfDictionaryProperties.parent] = PdfReferenceHolder( - fieldDictionary, - ); - } - } - } - } - if (fieldKids == null) { - if (fieldDictionary != null) { - if (!_helper.terminalFields.contains(fieldDictionary)) { - _helper.terminalFields.add(fieldDictionary as PdfDictionary); - } - } - } else { - if (!(fieldDictionary! as PdfDictionary).containsKey( - PdfDictionaryProperties.ft, - ) || - _isNode(fieldKids)) { - nodes.addFirst(_NodeInfo(fields, count)); - _helper.formHasKids = true; - count = -1; - fields = fieldKids; - } else { - _helper.terminalFields.add(fieldDictionary as PdfDictionary); - } - } - } - if (nodes.isEmpty) { - break; - } - final _NodeInfo nInfo = nodes.elementAt(0); - nodes.removeFirst(); - fields = nInfo._fields; - count = nInfo._count + 1; - } - } - - //Determines whether the specified kids is node. - bool _isNode(PdfArray kids) { - bool isNode = false; - if (kids.count >= 1) { - final PdfDictionary dictionary = - _helper.crossTable!.getObject(kids[0])! as PdfDictionary; - if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName name = - _helper.crossTable!.getObject( - dictionary[PdfDictionaryProperties.subtype], - )! - as PdfName; - if (name.name != PdfDictionaryProperties.widget) { - isNode = true; - } - } - } - return isNode; - } - - void _checkPerms(PdfCatalog catalog) { - IPdfPrimitive? permission = catalog[PdfDictionaryProperties.perms]; - if (permission is PdfReferenceHolder) { - permission = - (catalog[PdfDictionaryProperties.perms]! as PdfReferenceHolder) - .object; - } - if (permission != null && - permission is PdfDictionary && - permission.containsKey('UR3')) { - _helper.isUR3 = true; - } - } - - /// Imports form value from FDF file. - void _importDataFDF(List inputBytes, bool continueImportOnError) { - final PdfReader reader = PdfReader(inputBytes); - reader.position = 0; - String? token = reader.getNextToken(); - if (token != null && token.startsWith('%')) { - token = reader.getNextToken(); - if (token != null && !token.startsWith('FDF-')) { - throw ArgumentError( - 'The source is not a valid FDF file because it does not start with"%FDF-"', - ); - } - } - final Map> table = >{}; - String? fieldName = ''; - token = reader.getNextToken(); - while (token != null && token.isNotEmpty) { - if (token.toUpperCase() == 'T') { - final List out = _getFieldName(reader, token); - fieldName = out[0]; - token = out[1]; - } - if (token != null && token.toUpperCase() == 'V') { - _getFieldValue(reader, token, fieldName!, table); - } - token = reader.getNextToken(); - } - PdfField? field; - table.forEach((String k, List v) { - try { - final int index = PdfFormFieldCollectionHelper.getHelper( - fields, - ).getFieldIndex(k); - if (index == -1) { - throw ArgumentError('Incorrect field name.'); - } - field = fields[index]; - if (field != null) { - PdfFieldHelper.getHelper(field!).importFieldValue(v); - } - } catch (e) { - if (!continueImportOnError) { - rethrow; - } - } - }); - } - - /// Export the form data in FDF file format. - List _exportDataFDF(String formName) { - List bytes = []; - final PdfString headerString = PdfString('%FDF-1.2\n') - ..encode = ForceEncoding.ascii; - bytes.addAll(headerString.value!.codeUnits); - int count = 1; - for (int i = 0; i < fields.count; i++) { - final PdfField field = fields[i]; - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - helper.exportEmptyField = exportEmptyFields; - if (field.canExport && helper.isLoadedField) { - final Map out = helper.exportField(bytes, count); - bytes = out['bytes'] as List; - count = out['objectID'] as int; - } - } - final PdfString formNameEncodedString = PdfString(formName) - ..encode = ForceEncoding.ascii; - final StringBuffer buffer = StringBuffer(); - buffer.write( - '$count 0 obj< /Fields [', - ); - for (int i = 0; i < fields.count; i++) { - final PdfField field = fields[i]; - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if (helper.isLoadedField && field.canExport && helper.objID != 0) { - buffer.write('${helper.objID} 0 R '); - } - } - buffer.write(']>>endobj\n'); - buffer.write('${count + 1} 0 obj<>endobj\n'); - buffer.write('trailer\n<>\n'); - final PdfString fdfString = PdfString(buffer.toString()) - ..encode = ForceEncoding.ascii; - bytes.addAll(fdfString.value!.codeUnits); - return bytes; - } - - List _getFieldName(PdfReader reader, String? token) { - String? fieldname = ''; - token = reader.getNextToken(); - if (token != null && token.isNotEmpty) { - if (token == '<') { - token = reader.getNextToken(); - if (token != null && token.isNotEmpty && token != '>') { - final PdfString str = PdfString(''); - final List buffer = str.hexToBytes(token); - token = PdfString.byteToString(buffer); - fieldname = token; - } - } else { - token = reader.getNextToken(); - if (token != null && token.isNotEmpty) { - String? str = ' '; - while (str != ')') { - str = reader.getNextToken(); - if (str != null && str.isNotEmpty && str != ')') { - token = '${token!} $str'; - } - } - fieldname = token; - token = str; - } - } - } - return [fieldname, token]; - } - - void _getFieldValue( - PdfReader reader, - String? token, - String fieldName, - Map> table, - ) { - token = reader.getNextToken(); - if (token != null && token.isNotEmpty) { - if (token == '[') { - token = reader.getNextToken(); - if (token != null && token.isNotEmpty) { - final List fieldValues = []; - while (token != ']') { - token = _fieldValue( - reader, - token, - true, - table, - fieldName, - fieldValues, - ); - } - if (!table.containsKey(fieldName) && fieldValues.isNotEmpty) { - table[fieldName] = fieldValues; - } - } - } else { - _fieldValue(reader, token, false, table, fieldName, null); - } - } - } - - String? _fieldValue( - PdfReader reader, - String? token, - bool isMultiSelect, - Map> table, - String fieldName, - List? fieldValues, - ) { - if (token == '<') { - token = reader.getNextToken(); - if (token != null && token.isNotEmpty && token != '>') { - final PdfString str = PdfString(''); - final List buffer = str.hexToBytes(token); - token = PdfString.byteToString(buffer); - if (isMultiSelect && fieldValues != null) { - fieldValues.add(token); - } else if (!table.containsKey(fieldName)) { - table[fieldName] = [token]; - } - } - } else { - if (isMultiSelect && fieldValues != null) { - while (token != '>' && token != ')' && token != ']') { - if (token != null && - token.isNotEmpty && - (token == '/' || token != ')')) { - token = reader.getNextToken(); - if (token != null && - token.isNotEmpty && - token != '>' && - token != ')') { - String? str = ' '; - while (str != ')' && str != '>') { - str = reader.getNextToken(); - if (str != null && - str.isNotEmpty && - str != '>' && - str != ')' && - str != '/') { - token = '${token!} $str'; - } - fieldValues.add(token!); - } - } - } - token = reader.getNextToken(); - } - } else { - while (token != '>' && token != ')') { - if (token != null && - token.isNotEmpty && - (token == '/' || token != ')')) { - token = reader.getNextToken(); - if (token != null && - token.isNotEmpty && - token != '>' && - token != ')') { - String? str = ' '; - while (str != ')' && str != '>') { - str = reader.getNextToken(); - if (str != null && - str.isNotEmpty && - str != '>' && - str != ')' && - str != '/') { - token = '${token!} $str'; - } - } - if (!table.containsKey(fieldName)) { - table[fieldName] = [token!]; - } - } - } - token = reader.getNextToken(); - } - } - } - return token; - } - - List _exportDataXFDF(String formName) { - final XFdfDocument xfdf = XFdfDocument(formName); - for (int i = 0; i < fields.count; i++) { - final PdfField field = fields[i]; - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if (field.canExport) { - helper.exportEmptyField = exportEmptyFields; - final IPdfPrimitive? name = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.ft, - true, - ); - if (name != null && name is PdfName) { - switch (name.name) { - case 'Tx': - final IPdfPrimitive? fieldValue = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (fieldValue is PdfString) { - xfdf.setFields(field.name!, fieldValue.value!); - } else if (exportEmptyFields) { - xfdf.setFields(field.name!, ''); - } - break; - case 'Ch': - if (field is PdfListBoxField) { - final IPdfPrimitive? primitive = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (primitive is PdfArray) { - xfdf.setFields(field.name!, primitive); - } else if (primitive is PdfString) { - xfdf.setFields(field.name!, primitive.value!); - } else if (exportEmptyFields) { - xfdf.setFields(field.name!, ''); - } - } else { - final IPdfPrimitive? listField = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (listField is PdfName) { - xfdf.setFields(field.name!, listField.name!); - } else { - final IPdfPrimitive? comboValue = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (comboValue is PdfString) { - xfdf.setFields(field.name!, comboValue.value!); - } else if (exportEmptyFields) { - xfdf.setFields(field.name!, ''); - } - } - } - break; - case 'Btn': - final IPdfPrimitive? buttonFieldPrimitive = - PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (buttonFieldPrimitive != null) { - final String? value = helper.getExportValue( - field, - buttonFieldPrimitive, - ); - if (value != null && value.isNotEmpty) { - xfdf.setFields(field.name!, value); - } else if (field is PdfRadioButtonListField || - field is PdfCheckBoxField) { - if (exportEmptyFields) { - xfdf.setFields(field.name!, ''); - } else { - xfdf.setFields(field.name!, PdfDictionaryProperties.off); - } - } - } else { - if (field is PdfRadioButtonListField) { - xfdf.setFields( - field.name!, - helper.getAppearanceStateValue(field), - ); - } else { - final PdfDictionary holder = helper.getWidgetAnnotation( - helper.dictionary!, - helper.crossTable, - ); - final IPdfPrimitive? holderName = - holder[PdfDictionaryProperties.usageApplication]; - if (holderName is PdfName) { - xfdf.setFields(field.name!, holderName.name!); - } else if (exportEmptyFields) { - xfdf.setFields(field.name!, ''); - } - } - } - break; - } - } - } - } - return xfdf.save(); - } - - void _importDataJSON(List bytes, bool continueImportOnError) { - String? fieldKey, fieldValue; - final Map table = {}; - final PdfReader reader = PdfReader(bytes); - String? token = reader.getNextJsonToken(); - reader.position = 0; - while (token != null && token.isNotEmpty) { - if (token != '{' && token != '}' && token != '"' && token != ',') { - fieldKey = token; - do { - token = reader.getNextJsonToken(); - } while (token != ':'); - do { - token = reader.getNextJsonToken(); - } while (token != '"'); - token = reader.getNextJsonToken(); - if (token != '"') { - fieldValue = token; - } - } - if (fieldKey != null && fieldValue != null) { - table[PdfFormHelper.decodeXMLConversion( - fieldKey, - )] = PdfFormHelper.decodeXMLConversion(fieldValue); - fieldKey = fieldValue = null; - } - token = reader.getNextJsonToken(); - } - PdfField? field; - table.forEach((String k, String v) { - try { - final int index = PdfFormFieldCollectionHelper.getHelper( - fields, - ).getFieldIndex(k); - if (index == -1) { - throw ArgumentError('Incorrect field name.'); - } - field = fields[index]; - if (field != null) { - PdfFieldHelper.getHelper(field!).importFieldValue(v); - } - } catch (e) { - if (!continueImportOnError) { - rethrow; - } - } - }); - } - - List _exportDataJSON() { - final List bytes = []; - final Map table = {}; - for (int i = 0; i < fields.count; i++) { - final PdfField field = fields[i]; - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if (helper.isLoadedField && field.canExport) { - final IPdfPrimitive? name = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.ft, - true, - ); - if (name != null && name is PdfName) { - switch (name.name) { - case 'Tx': - final IPdfPrimitive? textField = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (textField != null && textField is PdfString) { - table[field.name!] = textField.value!; - } - break; - case 'Ch': - if (field is PdfListBoxField || field is PdfComboBoxField) { - final IPdfPrimitive? listValue = PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (listValue != null) { - final String? value = helper.getExportValue(field, listValue); - if (value != null && value.isNotEmpty) { - table[field.name!] = value; - } - } - } - break; - case 'Btn': - final IPdfPrimitive? buttonFieldPrimitive = - PdfFieldHelper.getValue( - helper.dictionary!, - helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - if (buttonFieldPrimitive != null) { - final String? value = helper.getExportValue( - field, - buttonFieldPrimitive, - ); - if (value != null && value.isNotEmpty) { - table[field.name!] = value; - } else if (field is PdfRadioButtonListField || - field is PdfCheckBoxField) { - table[field.name!] = 'Off'; - } - } else { - if (field is PdfRadioButtonListField) { - table[field.name!] = helper.getAppearanceStateValue(field); - } else { - final PdfDictionary holder = helper.getWidgetAnnotation( - helper.dictionary!, - helper.crossTable, - ); - final IPdfPrimitive? holderName = - holder[PdfDictionaryProperties.usageApplication]; - if (holderName != null && holderName is PdfName) { - table[field.name!] = holderName.name!; - } - } - } - break; - } - } - } - } - bytes.addAll(utf8.encode('{')); - String json; - int j = 0; - table.forEach((String k, String v) { - json = '"${_replaceJsonDelimiters(k)}":"${_replaceJsonDelimiters(v)}"'; - bytes.addAll(utf8.encode(j > 0 ? ',$json' : json)); - j++; - }); - bytes.addAll(utf8.encode('}')); - return bytes; - } - - String _replaceJsonDelimiters(String value) { - // ignore: unnecessary_string_escapes - return value.contains(RegExp('[":,{}]|[\[]|]')) - ? value - .replaceAll(',', '_x002C_') - .replaceAll('"', '_x0022_') - .replaceAll(':', '_x003A_') - .replaceAll('{', '_x007B_') - .replaceAll('}', '_x007D_') - .replaceAll('[', '_x005B_') - .replaceAll(']', '_x005D_') - : value; - } - - /// Imports XML Data from the given data. - void _importDataXml(List bytes, bool continueImportOnError) { - final String data = utf8.decode(bytes); - final XmlDocument document = XmlDocument.parse(data); - if (document.rootElement.name.local != 'Fields') { - ArgumentError.value('The XML form data stream is not valid'); - } else { - _importXmlData(document.rootElement.children, continueImportOnError); - } - } - - void _importXmlData(List children, bool continueImportOnError) { - for (final XmlNode childNode in children) { - if (childNode is XmlElement) { - if (childNode.innerText.isNotEmpty) { - String fieldName = childNode.name.local.replaceAll('_x0020_', ' '); - fieldName = fieldName - .replaceAll('_x0023_', '#') - .replaceAll('_x002C_', ',') - .replaceAll('_x005C_', r'\') - .replaceAll('_x0022_', '"') - .replaceAll('_x003A_', ':') - .replaceAll('_x005D_', ']') - .replaceAll('_x005D_', ']') - .replaceAll('_x007B_', '{') - .replaceAll('_x007D_', '}') - .replaceAll('_x0024_', r'$'); - try { - final int index = PdfFormFieldCollectionHelper.getHelper( - fields, - ).getFieldIndex(fieldName); - if (index == -1) { - throw ArgumentError('Incorrect field name.'); - } - final PdfField formField = fields[index]; - PdfFieldHelper.getHelper( - formField, - ).importFieldValue(childNode.innerText); - } catch (e) { - if (!continueImportOnError) { - rethrow; - } - } - } - if (childNode.children.isNotEmpty) { - _importXmlData(childNode.children, continueImportOnError); - } - } - } - } - - List _exportDataXML() { - final XmlBuilder builder = XmlBuilder(); - final List elements = []; - builder.processing('xml', 'version="1.0" encoding="utf-8"'); - for (int i = 0; i < fields.count; i++) { - final PdfField field = fields[i]; - if (field.canExport) { - PdfFieldHelper.getHelper(field).exportEmptyField = exportEmptyFields; - final XmlElement? element = - PdfFieldHelper.getHelper(field).exportFieldForXml(); - if (element != null) { - elements.add(element); - } - } - } - builder.element('Fields', nest: elements); - return utf8.encode(builder.buildDocument().toXmlString(pretty: true)); - } -} - -/// [PdfForm] helper -class PdfFormHelper { - /// internal constructor - PdfFormHelper(this.form); - - /// internal field - late PdfForm form; - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal field - bool? needAppearances = false; - - /// internal field - bool setAppearanceDictionary = false; - - /// internal field - final List fieldNames = []; - - /// internal field - PdfCrossTable? crossTable; - - /// internal field - final List terminalFields = []; - - /// internal field - bool formHasKids = false; - - /// internal field - bool isLoadedForm = false; - - /// internal field - Map>? widgetDictionary; - - /// internal field - bool isUR3 = false; - - /// internal field - // ignore: prefer_final_fields - List signatureFlags = [SignatureFlags.none]; - PdfResources? _resource; - - /// internal field - bool flatten = false; - bool _isDefaultAppearance = false; - PdfFormFieldCollection? _fields; - - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - static PdfFormHelper getHelper(PdfForm form) { - return form._helper; - } - - /// internal method - static PdfForm internal( - PdfCrossTable? crossTable, [ - PdfDictionary? formDictionary, - ]) { - return PdfForm._internal(crossTable, formDictionary); - } - - /// internal method - PdfResources get resources { - if (_resource == null) { - _resource = PdfResources(); - dictionary!.setProperty(PdfDictionaryProperties.dr, _resource); - } - return _resource!; - } - - set resources(PdfResources value) { - _resource = value; - if (isLoadedForm) { - dictionary!.setProperty(PdfDictionaryProperties.dr, value); - } - } - - /// internal method - //Raises before stream saves. - void beginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (!isLoadedForm) { - if (signatureFlags.length > 1 || - (signatureFlags.isNotEmpty && - !signatureFlags.contains(SignatureFlags.none))) { - _setSignatureFlags(signatureFlags); - needAppearances = false; - } - _checkFlatten(); - if (form.fields.count > 0 && setAppearanceDictionary) { - dictionary!.setBoolean( - PdfDictionaryProperties.needAppearances, - needAppearances, - ); - } - } else { - int i = 0; - if (signatureFlags.length > 1 || - (signatureFlags.isNotEmpty && - !signatureFlags.contains(SignatureFlags.none))) { - _setSignatureFlags(signatureFlags); - dictionary!.changed = true; - if (!_isDefaultAppearance) { - needAppearances = false; - } - if (dictionary!.containsKey(PdfDictionaryProperties.needAppearances)) { - dictionary!.setBoolean( - PdfDictionaryProperties.needAppearances, - needAppearances, - ); - } - } - while (i < form.fields.count) { - final PdfField field = form.fields[i]; - if (field is PdfSignatureField) { - needAppearances = false; - } - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if (helper.isLoadedField) { - final PdfDictionary dic = helper.dictionary!; - bool isSigned = false; - if (field is PdfSignatureField) { - if (dic.containsKey(PdfDictionaryProperties.v)) { - final IPdfPrimitive? value = PdfCrossTable.dereference( - dic[PdfDictionaryProperties.v], - ); - if (value != null) { - isSigned = true; - } - } - } - bool isNeedAppearance = false; - if (!dic.containsKey(PdfDictionaryProperties.ap) && - _isDefaultAppearance && - !needAppearances! && - !helper.changed) { - isNeedAppearance = true; - } - if (helper.flags.length > 1) { - helper.changed = true; - helper.setFlags(helper.flags); - } - int fieldFlag = 0; - if (dic.containsKey(PdfDictionaryProperties.f)) { - final IPdfPrimitive? flag = PdfCrossTable.dereference( - dic[PdfDictionaryProperties.f], - ); - if (flag != null && flag is PdfNumber) { - fieldFlag = flag.value!.toInt(); - } - } - PdfArray? kids; - if (helper.dictionary!.containsKey(PdfDictionaryProperties.kids)) { - kids = - PdfCrossTable.dereference( - helper.dictionary![PdfDictionaryProperties.kids], - ) - as PdfArray?; - } - if (helper.flattenField && fieldFlag != 6) { - if (field.page != null || kids != null) { - helper.draw(); - } - form.fields.remove(field); - final int? index = crossTable!.items!.lookFor(helper.dictionary!); - if (index != -1) { - crossTable!.items!.objectCollection!.removeAt(index!); - } - --i; - } else if (helper.changed || - isNeedAppearance || - (setAppearanceDictionary && !isSigned)) { - helper.beginSave(); - } - } else { - if (helper.flattenField) { - form.fields.remove(field); - helper.draw(); - --i; - } else { - helper.save(); - } - } - if (_fields?.count == 0) { - final int? index = crossTable!.items!.lookFor(helper.dictionary!); - dictionary?.clear(); - (sender as PdfDictionary).remove(PdfDictionaryProperties.acroForm); - if (index != -1) { - crossTable!.items!.objectCollection!.removeAt(index!); - } - } - ++i; - } - if (_isDefaultAppearance) { - dictionary!.setBoolean( - PdfDictionaryProperties.needAppearances, - _isDefaultAppearance, - ); - } else if (!_isDefaultAppearance && - dictionary!.containsKey(PdfDictionaryProperties.needAppearances)) { - dictionary!.setBoolean( - PdfDictionaryProperties.needAppearances, - _isDefaultAppearance, - ); - } - dictionary!.remove('XFA'); - } - } - - void _addFieldResourcesToPage(PdfField field) { - final PdfResources formResources = - PdfFormHelper.getHelper(field.form!).resources; - if (formResources.containsKey(PdfDictionaryProperties.font)) { - IPdfPrimitive? fieldFontResource = - formResources[PdfDictionaryProperties.font]; - if (fieldFontResource is PdfReferenceHolder) { - fieldFontResource = fieldFontResource.object as PdfDictionary?; - } - if (fieldFontResource != null && fieldFontResource is PdfDictionary) { - // ignore: avoid_function_literals_in_foreach_calls - fieldFontResource.items!.keys.forEach((PdfName? key) { - final PdfResources pageResources = - PdfPageHelper.getHelper(field.page!).getResources()!; - IPdfPrimitive? pageFontResource = - pageResources[PdfDictionaryProperties.font]; - if (pageFontResource is PdfDictionary) { - } else if (pageFontResource is PdfReferenceHolder) { - pageFontResource = pageFontResource.object as PdfDictionary?; - } - if (pageFontResource == null || - (pageFontResource is PdfDictionary && - !pageFontResource.containsKey(key))) { - final PdfReferenceHolder? fieldFontReference = - (fieldFontResource! as PdfDictionary)[key] - as PdfReferenceHolder?; - if (pageFontResource == null) { - final PdfDictionary fontDictionary = PdfDictionary(); - fontDictionary.items![key] = fieldFontReference; - pageResources[PdfDictionaryProperties.font] = fontDictionary; - } else { - (pageFontResource as PdfDictionary).items![key] = - fieldFontReference; - } - } - }); - } - } - } - - void _checkFlatten() { - int i = 0; - while (i < _fields!.count) { - final PdfField field = _fields![i]; - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if (helper.flattenField) { - int? fieldFlag = 0; - final PdfDictionary fieldDictionary = helper.dictionary!; - if (fieldDictionary.containsKey(PdfDictionaryProperties.f)) { - fieldFlag = - (fieldDictionary[PdfDictionaryProperties.f]! as PdfNumber).value - as int?; - } - if (fieldFlag != 6) { - _addFieldResourcesToPage(field); - helper.draw(); - _fields!.remove(field); - deleteFromPages(field); - deleteAnnotation(field); - --i; - } - } else if (helper.isLoadedField) { - helper.beginSave(); - } else { - helper.save(); - } - ++i; - } - } - - /// internal method - void deleteFromPages(PdfField field) { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final PdfDictionary dic = helper.dictionary!; - final PdfName kidsName = PdfName(PdfDictionaryProperties.kids); - final PdfName annotsName = PdfName(PdfDictionaryProperties.annots); - final PdfName pName = PdfName(PdfDictionaryProperties.p); - final bool isLoaded = helper.isLoadedField; - if (dic.items != null) { - if (dic.containsKey(kidsName)) { - final PdfArray array = dic[kidsName]! as PdfArray; - for (int i = 0; i < array.count; ++i) { - final PdfReferenceHolder holder = array[i]! as PdfReferenceHolder; - final PdfDictionary? widget = holder.object as PdfDictionary?; - PdfDictionary? page; - if (!isLoaded) { - final PdfReferenceHolder pageRef = - widget![pName]! as PdfReferenceHolder; - page = pageRef.object as PdfDictionary?; - } else { - PdfReference? pageRef; - if (widget!.containsKey(pName) && - widget[PdfDictionaryProperties.p] is! PdfNull) { - pageRef = crossTable!.getReference(widget[pName]); - } else if (dic.containsKey(pName) && - dic[PdfDictionaryProperties.p] is! PdfNull) { - pageRef = crossTable!.getReference(dic[pName]); - } else if (field.page != null) { - pageRef = crossTable!.getReference( - PdfPageHelper.getHelper(field.page!).dictionary, - ); - } - page = crossTable!.getObject(pageRef) as PdfDictionary?; - } - if (page != null && page.containsKey(annotsName)) { - PdfArray? annots; - if (isLoaded) { - annots = crossTable!.getObject(page[annotsName]) as PdfArray?; - for (int i = 0; i < annots!.count; i++) { - final IPdfPrimitive? obj = annots.elements[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object is PdfDictionary && - obj.object == holder.object) { - annots.remove(obj); - break; - } - } - annots.changed = true; - page.setProperty(annotsName, annots); - } else { - if (page[PdfDictionaryProperties.annots] is PdfReferenceHolder) { - final PdfReferenceHolder annotReference = - page[PdfDictionaryProperties.annots]! as PdfReferenceHolder; - annots = annotReference.object as PdfArray?; - for (int i = 0; i < annots!.count; i++) { - final IPdfPrimitive? obj = annots.elements[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object is PdfDictionary && - obj.object == holder.object) { - annots.remove(obj); - break; - } - } - annots.changed = true; - page.setProperty(PdfDictionaryProperties.annots, annots); - } else if (page[PdfDictionaryProperties.annots] is PdfArray) { - if (helper.page != null) { - final PdfAnnotationCollection annotCollection = - helper.page!.annotations; - if (annotCollection.count > 0) { - final int index = PdfAnnotationCollectionHelper.getHelper( - annotCollection, - ).annotations.indexOf(holder); - if (index >= 0 && index < annotCollection.count) { - annotCollection.remove(annotCollection[index]); - } - } - } - } - } - } else if (isLoaded) { - helper.requiredReference = holder; - if (field.page != null && - PdfPageHelper.getHelper( - field.page!, - ).dictionary!.containsKey(annotsName)) { - final PdfArray annots = - crossTable!.getObject( - PdfPageHelper.getHelper( - field.page!, - ).dictionary![annotsName], - )! - as PdfArray; - for (int i = 0; i < annots.count; i++) { - final IPdfPrimitive? obj = annots.elements[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object is PdfDictionary && - obj.object == widget) { - annots.remove(obj); - break; - } - } - annots.changed = true; - } - if (crossTable!.items != null && - crossTable!.items!.contains(widget)) { - crossTable!.items!.objectCollection!.removeAt( - crossTable!.items!.lookFor(widget)!, - ); - } - helper.requiredReference = null; - } - } - } else { - IPdfPrimitive? page; - if (!isLoaded) { - final PdfReferenceHolder pageRef = - dic.containsKey(pName) - ? (dic[pName] as PdfReferenceHolder?)! - : PdfReferenceHolder( - PdfPageHelper.getHelper(field.page!).dictionary, - ); - page = pageRef.object; - } else { - PdfReference? pageRef; - if (dic.containsKey(pName) && - dic[PdfDictionaryProperties.p] is! PdfNull) { - pageRef = crossTable!.getReference(dic[pName]); - } else if (field.page != null) { - pageRef = crossTable!.getReference( - PdfPageHelper.getHelper(field.page!).dictionary, - ); - } - page = crossTable!.getObject(pageRef); - } - if (page != null && - page is PdfDictionary && - page.containsKey(PdfDictionaryProperties.annots)) { - final IPdfPrimitive? annots = - isLoaded - ? crossTable!.getObject(page[annotsName]) - : page[PdfDictionaryProperties.annots]; - if (annots != null && annots is PdfArray) { - for (int i = 0; i < annots.count; i++) { - final IPdfPrimitive? obj = annots.elements[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object is PdfDictionary && - obj.object == dic) { - annots.remove(obj); - break; - } - } - annots.changed = true; - page.setProperty(PdfDictionaryProperties.annots, annots); - } - } else if (isLoaded && - field.page != null && - PdfPageHelper.getHelper( - field.page!, - ).dictionary!.containsKey(annotsName)) { - final PdfArray annots = - crossTable!.getObject( - PdfPageHelper.getHelper( - field.page!, - ).dictionary![annotsName], - )! - as PdfArray; - for (int i = 0; i < annots.count; i++) { - final IPdfPrimitive? obj = annots.elements[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object is PdfDictionary && - obj.object == dic) { - annots.remove(obj); - break; - } - } - annots.changed = true; - } - } - } - } - - void _setSignatureFlags(List value) { - int n = 0; - for (final SignatureFlags element in value) { - n |= element.index; - } - dictionary!.setNumber(PdfDictionaryProperties.sigFlags, n); - } - - /// internal method - void deleteAnnotation(PdfField field) { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - final PdfDictionary dic = helper.dictionary!; - if (dic.items != null) { - if (dic.containsKey(PdfDictionaryProperties.kids)) { - PdfArray? array; - array = - !helper.isLoadedField - ? dic[PdfDictionaryProperties.kids] as PdfArray? - : crossTable!.getObject(dic[PdfDictionaryProperties.kids]) - as PdfArray?; - array!.clear(); - dic.setProperty(PdfDictionaryProperties.kids, array); - } - } - } - - /// internal method - String? getCorrectName(String? name) { - String? correctName = name; - if (fieldNames.contains(name)) { - final int firstIndex = fieldNames.indexOf(name); - final int lastIndex = fieldNames.lastIndexOf(name); - if (firstIndex != lastIndex) { - correctName = PdfResources.globallyUniqueIdentifier; - fieldNames.removeAt(lastIndex); - fieldNames.add(correctName); - } - } - return correctName; - } - - /// internal method - //Removes field and kids annotation from dictionaries. - void removeFromDictionaries( - PdfField field, [ - bool removeFieldFromAcroForm = false, - ]) { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if ((_fields != null && _fields!.count > 0) || removeFieldFromAcroForm) { - final PdfName fieldsDict = PdfName(PdfDictionaryProperties.fields); - final PdfArray fields = - crossTable!.getObject(dictionary![fieldsDict])! as PdfArray; - for (int i = 0; i < fields.elements.length; i++) { - final IPdfPrimitive? obj = fields.elements[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object is PdfDictionary && - obj.object == helper.dictionary) { - fields.remove(obj); - break; - } - } - helper.dictionary!.isSkip = true; - fields.changed = true; - if (!(!formHasKids || - !helper.dictionary!.items!.containsKey( - PdfName(PdfDictionaryProperties.parent), - ))) { - if (helper.dictionary!.items!.containsKey( - PdfName(PdfDictionaryProperties.parent), - )) { - final PdfDictionary dic = - (helper.dictionary![PdfDictionaryProperties.parent]! - as PdfReferenceHolder) - .object! - as PdfDictionary; - final PdfArray kids = - dic.items![PdfName(PdfDictionaryProperties.kids)]! as PdfArray; - for (int k = 0; k < kids.count; k++) { - final PdfReferenceHolder kidsReference = - kids[k]! as PdfReferenceHolder; - if (kidsReference.object == helper.dictionary) { - kids.remove(kidsReference); - dic.modify(); - break; - } - } - } - } - dictionary!.setProperty(fieldsDict, fields); - } - if (helper.isLoadedField && !removeFieldFromAcroForm) { - deleteFromPages(field); - deleteAnnotation(field); - } - } - - /// internal method - static String decodeXMLConversion(String value) { - String newString = value; - while (newString.contains('_x')) { - final int index = newString.indexOf('_x'); - final String tempString = newString.substring(index); - if (tempString.length >= 7 && tempString[6] == '_') { - newString = newString.replaceRange(index, index + 2, '--'); - final int? charCode = int.tryParse( - value.substring(index + 2, index + 6), - radix: 16, - ); - if (charCode != null && charCode >= 0) { - value = value.replaceRange( - index, - index + 7, - String.fromCharCode(charCode), - ); - newString = newString.replaceRange(index, index + 7, '-'); - } - } else { - break; - } - } - return value; - } -} - -class _NodeInfo { - //Constructor - _NodeInfo(PdfArray? fields, int count) { - _fields = fields; - _count = count; - } - - //Fields - PdfArray? _fields; - late int _count; -} +import 'dart:collection'; +import 'dart:convert'; + +import 'package:xml/xml.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/pdf_annotation_collection.dart'; +import '../graphics/pdf_resources.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_reader.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/pdf_catalog.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_check_box_field.dart'; +import 'pdf_combo_box_field.dart'; +import 'pdf_field.dart'; +import 'pdf_form_field_collection.dart'; +import 'pdf_list_box_field.dart'; +import 'pdf_radio_button_list_field.dart'; +import 'pdf_signature_field.dart'; +import 'pdf_xfdf_document.dart'; + +/// Represents interactive form of the PDF document. +class PdfForm implements IPdfWrapper { + //Constructors + /// Initializes a new instance of the [PdfForm] class. + PdfForm() : super() { + _helper = PdfFormHelper(this); + _helper._fields = PdfFormFieldCollectionHelper.getCollection(); + PdfFormFieldCollectionHelper.getHelper(_helper._fields!).form = this; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.fields, + _helper._fields, + ); + if (!_helper.isLoadedForm) { + _helper.dictionary!.beginSave = _helper.beginSave; + } + _helper.setAppearanceDictionary = true; + } + + PdfForm._internal( + PdfCrossTable? crossTable, [ + PdfDictionary? formDictionary, + ]) { + _helper = PdfFormHelper(this); + _helper.isLoadedForm = true; + _helper.crossTable = crossTable; + _helper.dictionary!.setBoolean( + PdfDictionaryProperties.needAppearances, + _helper.needAppearances, + ); + PdfDocumentHelper.getHelper(_helper.crossTable!.document!) + .catalog + .beginSaveList ??= []; + PdfDocumentHelper.getHelper( + _helper.crossTable!.document!, + ).catalog.beginSaveList!.add(_helper.beginSave); + PdfDocumentHelper.getHelper(_helper.crossTable!.document!).catalog.modify(); + if (PdfDocumentHelper.getHelper( + _helper.crossTable!.document!, + ).catalog.containsKey(PdfDictionaryProperties.perms)) { + _checkPerms( + PdfDocumentHelper.getHelper(_helper.crossTable!.document!).catalog, + ); + } + if (formDictionary != null) { + _initialize(formDictionary, crossTable!); + } + } + + //Fields + late PdfFormHelper _helper; + bool _readOnly = false; + + /// Gets or sets a value indicating whether field auto naming. + /// + /// The default value is true. + bool fieldAutoNaming = true; + + /// Gets or sets the ExportEmptyFields property, enabling this will export + /// the empty acroform fields. + /// + /// The default value is false. + bool exportEmptyFields = false; + + //Properties + + /// Gets the fields collection. + PdfFormFieldCollection get fields { + if (_helper.isLoadedForm) { + _helper._fields ??= PdfFormFieldCollectionHelper.getCollection(this); + } + return _helper._fields!; + } + + /// Gets or sets a value indicating whether the form is read only. + /// + /// The default value is false. + bool get readOnly => _readOnly; + set readOnly(bool value) { + _readOnly = value; + if (_helper.isLoadedForm) { + for (int i = 0; i < fields.count; i++) { + fields[i].readOnly = value; + } + } + } + + //Public methods. + /// Specifies whether to set the default appearance for the form or not. + void setDefaultAppearance(bool value) { + _helper.needAppearances = value; + _helper.setAppearanceDictionary = !value; + _helper._isDefaultAppearance = value; + } + + /// Flatten all the fields available in the form. + /// + /// The flatten will add at the time of saving the current document. + void flattenAllFields() { + _helper.flatten = true; + } + + /// Imports form value from base 64 string to the file with the specific [DataFormat]. + void importDataFromBase64String( + String base64String, + DataFormat dataFormat, [ + bool continueImportOnError = false, + ]) { + importData( + base64.decode(base64String).toList(), + dataFormat, + continueImportOnError, + ); + } + + /// Imports form value to the file with the specific [DataFormat]. + void importData( + List inputBytes, + DataFormat dataFormat, [ + bool continueImportOnError = false, + ]) { + if (dataFormat == DataFormat.fdf) { + _importDataFDF(inputBytes, continueImportOnError); + } else if (dataFormat == DataFormat.json) { + _importDataJSON(inputBytes, continueImportOnError); + } else if (dataFormat == DataFormat.xfdf) { + _importDataXFDF(inputBytes); + } else if (dataFormat == DataFormat.xml) { + _importDataXml(inputBytes, continueImportOnError); + } + } + + /// Export the form data to a file with the specific [DataFormat] and form name. + List exportData(DataFormat dataFormat, [String formName = '']) { + List? data; + if (dataFormat == DataFormat.fdf) { + data = _exportDataFDF(formName); + } else if (dataFormat == DataFormat.xfdf) { + data = _exportDataXFDF(formName); + } else if (dataFormat == DataFormat.json) { + data = _exportDataJSON(); + } else if (dataFormat == DataFormat.xml) { + data = _exportDataXML(); + } + return data!; + } + + /// Imports XFDF Data from the given data. + void _importDataXFDF(List bytes) { + final String data = utf8.decode(bytes); + final XmlDocument xmlDoc = XmlDocument.parse(data); + PdfField formField; + for (final XmlNode node in xmlDoc.rootElement.firstElementChild!.children) { + if (node is XmlElement) { + final String fieldName = node.attributes.first.value; + final int index = PdfFormFieldCollectionHelper.getHelper( + fields, + ).getFieldIndex(fieldName); + if (index >= 0 && index < fields.count) { + formField = fields[index]; + String? fieldInnerValue; + final List fieldInnerValues = []; + if (node.childElements.length > 1) { + for (int i = 0; i < node.childElements.length; i++) { + fieldInnerValues.add(node.childElements.elementAt(i).innerText); + } + } else { + fieldInnerValue = node.firstElementChild!.innerText; + } + if (fieldInnerValues.isNotEmpty) { + PdfFieldHelper.getHelper( + formField, + ).importFieldValue(fieldInnerValues); + } else if (fieldInnerValue != null) { + PdfFieldHelper.getHelper( + formField, + ).importFieldValue(fieldInnerValue); + } + } + } + } + } + + //Implementation + + void _initialize(PdfDictionary formDictionary, PdfCrossTable crossTable) { + _helper.dictionary = formDictionary; + //Get terminal fields. + _createFields(); + //Gets NeedAppearance + if (_helper.dictionary!.containsKey( + PdfDictionaryProperties.needAppearances, + )) { + final PdfBoolean needAppearance = + crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.needAppearances], + )! + as PdfBoolean; + _helper.needAppearances = needAppearance.value; + _helper.setAppearanceDictionary = true; + } else { + _helper.setAppearanceDictionary = false; + } + //Gets resource dictionary + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.dr)) { + final IPdfPrimitive? resourceDictionary = PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.dr], + ); + if (resourceDictionary != null && resourceDictionary is PdfDictionary) { + _helper.resources = PdfResources(resourceDictionary); + } + } + } + + //Retrieves the terminal fields. + void _createFields() { + PdfArray? fields; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.fields)) { + final IPdfPrimitive? obj = _helper.crossTable!.getObject( + _helper.dictionary![PdfDictionaryProperties.fields], + ); + if (obj != null) { + fields = obj as PdfArray; + } + } + int count = 0; + final Queue<_NodeInfo> nodes = Queue<_NodeInfo>(); + while (true && fields != null) { + for (; count < fields!.count; ++count) { + final IPdfPrimitive? fieldDictionary = _helper.crossTable!.getObject( + fields[count], + ); + PdfArray? fieldKids; + if (fieldDictionary != null && + fieldDictionary is PdfDictionary && + fieldDictionary.containsKey(PdfDictionaryProperties.kids)) { + final IPdfPrimitive? fieldKid = _helper.crossTable!.getObject( + fieldDictionary[PdfDictionaryProperties.kids], + ); + if (fieldKid != null && fieldKid is PdfArray) { + fieldKids = fieldKid; + for (int i = 0; i < fieldKids.count; i++) { + final IPdfPrimitive? kidsDict = PdfCrossTable.dereference( + fieldKids[i], + ); + if (kidsDict != null && + kidsDict is PdfDictionary && + !kidsDict.containsKey(PdfDictionaryProperties.parent)) { + kidsDict[PdfDictionaryProperties.parent] = PdfReferenceHolder( + fieldDictionary, + ); + } + } + } + } + if (fieldKids == null) { + if (fieldDictionary != null && + fieldDictionary is PdfDictionary && + !_helper.terminalFields.contains(fieldDictionary)) { + _helper.terminalFields.add(fieldDictionary); + } + } else { + if (!(fieldDictionary! as PdfDictionary).containsKey( + PdfDictionaryProperties.ft, + ) || + _isNode(fieldKids)) { + nodes.addFirst(_NodeInfo(fields, count)); + _helper.formHasKids = true; + count = -1; + fields = fieldKids; + } else { + _helper.terminalFields.add(fieldDictionary as PdfDictionary); + } + } + } + if (nodes.isEmpty) { + break; + } + final _NodeInfo nInfo = nodes.elementAt(0); + nodes.removeFirst(); + fields = nInfo._fields; + count = nInfo._count + 1; + } + } + + //Determines whether the specified kids is node. + bool _isNode(PdfArray kids) { + bool isNode = false; + if (kids.count >= 1) { + final PdfDictionary dictionary = + _helper.crossTable!.getObject(kids[0])! as PdfDictionary; + if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName name = + _helper.crossTable!.getObject( + dictionary[PdfDictionaryProperties.subtype], + )! + as PdfName; + if (name.name != PdfDictionaryProperties.widget) { + isNode = true; + } + } + } + return isNode; + } + + void _checkPerms(PdfCatalog catalog) { + IPdfPrimitive? permission = catalog[PdfDictionaryProperties.perms]; + if (permission is PdfReferenceHolder) { + permission = + (catalog[PdfDictionaryProperties.perms]! as PdfReferenceHolder) + .object; + } + if (permission != null && + permission is PdfDictionary && + permission.containsKey('UR3')) { + _helper.isUR3 = true; + } + } + + /// Imports form value from FDF file. + void _importDataFDF(List inputBytes, bool continueImportOnError) { + final PdfReader reader = PdfReader(inputBytes); + reader.position = 0; + String? token = reader.getNextToken(); + if (token != null && token.startsWith('%')) { + token = reader.getNextToken(); + if (token != null && !token.startsWith('FDF-')) { + throw ArgumentError( + 'The source is not a valid FDF file because it does not start with"%FDF-"', + ); + } + } + final Map> table = >{}; + String? fieldName = ''; + token = reader.getNextToken(); + while (token != null && token.isNotEmpty) { + if (token.toUpperCase() == 'T') { + final List out = _getFieldName(reader, token); + fieldName = out[0]; + token = out[1]; + } + if (token != null && token.toUpperCase() == 'V') { + _getFieldValue(reader, token, fieldName!, table); + } + token = reader.getNextToken(); + } + PdfField? field; + table.forEach((String k, List v) { + try { + final int index = PdfFormFieldCollectionHelper.getHelper( + fields, + ).getFieldIndex(k); + if (index == -1) { + throw ArgumentError('Incorrect field name.'); + } + field = fields[index]; + if (field != null) { + PdfFieldHelper.getHelper(field!).importFieldValue(v); + } + } catch (e) { + if (!continueImportOnError) { + rethrow; + } + } + }); + } + + /// Export the form data in FDF file format. + List _exportDataFDF(String formName) { + List bytes = []; + final PdfString headerString = PdfString('%FDF-1.2\n') + ..encode = ForceEncoding.ascii; + bytes.addAll(headerString.value!.codeUnits); + int count = 1; + for (int i = 0; i < fields.count; i++) { + final PdfField field = fields[i]; + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + helper.exportEmptyField = exportEmptyFields; + if (field.canExport && helper.isLoadedField) { + final Map out = helper.exportField(bytes, count); + bytes = out['bytes'] as List; + count = out['objectID'] as int; + } + } + final PdfString formNameEncodedString = PdfString(formName) + ..encode = ForceEncoding.ascii; + final StringBuffer buffer = StringBuffer(); + buffer.write( + '$count 0 obj< /Fields [', + ); + for (int i = 0; i < fields.count; i++) { + final PdfField field = fields[i]; + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if (helper.isLoadedField && field.canExport && helper.objID != 0) { + buffer.write('${helper.objID} 0 R '); + } + } + buffer.write(']>>endobj\n'); + buffer.write('${count + 1} 0 obj<>endobj\n'); + buffer.write('trailer\n<>\n'); + final PdfString fdfString = PdfString(buffer.toString()) + ..encode = ForceEncoding.ascii; + bytes.addAll(fdfString.value!.codeUnits); + return bytes; + } + + List _getFieldName(PdfReader reader, String? token) { + String? fieldname = ''; + token = reader.getNextToken(); + if (token != null && token.isNotEmpty) { + if (token == '<') { + token = reader.getNextToken(); + if (token != null && token.isNotEmpty && token != '>') { + final PdfString str = PdfString(''); + final List buffer = str.hexToBytes(token); + token = PdfString.byteToString(buffer); + fieldname = token; + } + } else { + token = reader.getNextToken(); + if (token != null && token.isNotEmpty) { + String? str = ' '; + while (str != ')') { + str = reader.getNextToken(); + if (str != null && str.isNotEmpty && str != ')') { + token = '${token!} $str'; + } + } + fieldname = token; + token = str; + } + } + } + return [fieldname, token]; + } + + void _getFieldValue( + PdfReader reader, + String? token, + String fieldName, + Map> table, + ) { + token = reader.getNextToken(); + if (token != null && token.isNotEmpty) { + if (token == '[') { + token = reader.getNextToken(); + if (token != null && token.isNotEmpty) { + final List fieldValues = []; + while (token != ']') { + token = _fieldValue( + reader, + token, + true, + table, + fieldName, + fieldValues, + ); + } + if (!table.containsKey(fieldName) && fieldValues.isNotEmpty) { + table[fieldName] = fieldValues; + } + } + } else { + _fieldValue(reader, token, false, table, fieldName, null); + } + } + } + + String? _fieldValue( + PdfReader reader, + String? token, + bool isMultiSelect, + Map> table, + String fieldName, + List? fieldValues, + ) { + if (token == '<') { + token = reader.getNextToken(); + if (token != null && token.isNotEmpty && token != '>') { + final PdfString str = PdfString(''); + final List buffer = str.hexToBytes(token); + token = PdfString.byteToString(buffer); + if (isMultiSelect && fieldValues != null) { + fieldValues.add(token); + } else if (!table.containsKey(fieldName)) { + table[fieldName] = [token]; + } + } + } else { + if (isMultiSelect && fieldValues != null) { + while (token != '>' && token != ')' && token != ']') { + if (token != null && + token.isNotEmpty && + (token == '/' || token != ')')) { + token = reader.getNextToken(); + if (token != null && + token.isNotEmpty && + token != '>' && + token != ')') { + String? str = ' '; + while (str != ')' && str != '>') { + str = reader.getNextToken(); + if (str != null && + str.isNotEmpty && + str != '>' && + str != ')' && + str != '/') { + token = '${token!} $str'; + } + fieldValues.add(token!); + } + } + } + token = reader.getNextToken(); + } + } else { + while (token != '>' && token != ')') { + if (token != null && + token.isNotEmpty && + (token == '/' || token != ')')) { + token = reader.getNextToken(); + if (token != null && + token.isNotEmpty && + token != '>' && + token != ')') { + String? str = ' '; + while (str != ')' && str != '>') { + str = reader.getNextToken(); + if (str != null && + str.isNotEmpty && + str != '>' && + str != ')' && + str != '/') { + token = '${token!} $str'; + } + } + if (!table.containsKey(fieldName)) { + table[fieldName] = [token!]; + } + } + } + token = reader.getNextToken(); + } + } + } + return token; + } + + List _exportDataXFDF(String formName) { + final XFdfDocument xfdf = XFdfDocument(formName); + for (int i = 0; i < fields.count; i++) { + final PdfField field = fields[i]; + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if (field.canExport) { + helper.exportEmptyField = exportEmptyFields; + final IPdfPrimitive? name = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.ft, + true, + ); + if (name != null && name is PdfName) { + switch (name.name) { + case 'Tx': + final IPdfPrimitive? fieldValue = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (fieldValue is PdfString) { + xfdf.setFields(field.name!, fieldValue.value!); + } else if (exportEmptyFields) { + xfdf.setFields(field.name!, ''); + } + break; + case 'Ch': + if (field is PdfListBoxField) { + final IPdfPrimitive? primitive = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (primitive is PdfArray) { + xfdf.setFields(field.name!, primitive); + } else if (primitive is PdfString) { + xfdf.setFields(field.name!, primitive.value!); + } else if (exportEmptyFields) { + xfdf.setFields(field.name!, ''); + } + } else { + final IPdfPrimitive? listField = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (listField is PdfName) { + xfdf.setFields(field.name!, listField.name!); + } else { + final IPdfPrimitive? comboValue = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (comboValue is PdfString) { + xfdf.setFields(field.name!, comboValue.value!); + } else if (exportEmptyFields) { + xfdf.setFields(field.name!, ''); + } + } + } + break; + case 'Btn': + final IPdfPrimitive? buttonFieldPrimitive = + PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (buttonFieldPrimitive != null) { + final String? value = helper.getExportValue( + field, + buttonFieldPrimitive, + ); + if (value != null && value.isNotEmpty) { + xfdf.setFields(field.name!, value); + } else if (field is PdfRadioButtonListField || + field is PdfCheckBoxField) { + if (exportEmptyFields) { + xfdf.setFields(field.name!, ''); + } else { + xfdf.setFields(field.name!, PdfDictionaryProperties.off); + } + } + } else { + if (field is PdfRadioButtonListField) { + xfdf.setFields( + field.name!, + helper.getAppearanceStateValue(field), + ); + } else { + final PdfDictionary holder = helper.getWidgetAnnotation( + helper.dictionary!, + helper.crossTable, + ); + final IPdfPrimitive? holderName = + holder[PdfDictionaryProperties.usageApplication]; + if (holderName is PdfName) { + xfdf.setFields(field.name!, holderName.name!); + } else if (exportEmptyFields) { + xfdf.setFields(field.name!, ''); + } + } + } + break; + } + } + } + } + return xfdf.save(); + } + + void _importDataJSON(List bytes, bool continueImportOnError) { + String? fieldKey, fieldValue; + final Map table = {}; + final PdfReader reader = PdfReader(bytes); + String? token = reader.getNextJsonToken(); + reader.position = 0; + while (token != null && token.isNotEmpty) { + if (token != '{' && token != '}' && token != '"' && token != ',') { + fieldKey = token; + do { + token = reader.getNextJsonToken(); + } while (token != ':'); + do { + token = reader.getNextJsonToken(); + } while (token != '"'); + token = reader.getNextJsonToken(); + if (token != '"') { + fieldValue = token; + } + } + if (fieldKey != null && fieldValue != null) { + table[PdfFormHelper.decodeXMLConversion( + fieldKey, + )] = PdfFormHelper.decodeXMLConversion(fieldValue); + fieldKey = fieldValue = null; + } + token = reader.getNextJsonToken(); + } + PdfField? field; + table.forEach((String k, String v) { + try { + final int index = PdfFormFieldCollectionHelper.getHelper( + fields, + ).getFieldIndex(k); + if (index == -1) { + throw ArgumentError('Incorrect field name.'); + } + field = fields[index]; + if (field != null) { + PdfFieldHelper.getHelper(field!).importFieldValue(v); + } + } catch (e) { + if (!continueImportOnError) { + rethrow; + } + } + }); + } + + List _exportDataJSON() { + final List bytes = []; + final Map table = {}; + for (int i = 0; i < fields.count; i++) { + final PdfField field = fields[i]; + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if (helper.isLoadedField && field.canExport) { + final IPdfPrimitive? name = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.ft, + true, + ); + if (name != null && name is PdfName) { + switch (name.name) { + case 'Tx': + final IPdfPrimitive? textField = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (textField != null && textField is PdfString) { + table[field.name!] = textField.value!; + } + break; + case 'Ch': + if (field is PdfListBoxField || field is PdfComboBoxField) { + final IPdfPrimitive? listValue = PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (listValue != null) { + final String? value = helper.getExportValue(field, listValue); + if (value != null && value.isNotEmpty) { + table[field.name!] = value; + } + } + } + break; + case 'Btn': + final IPdfPrimitive? buttonFieldPrimitive = + PdfFieldHelper.getValue( + helper.dictionary!, + helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + if (buttonFieldPrimitive != null) { + final String? value = helper.getExportValue( + field, + buttonFieldPrimitive, + ); + if (value != null && value.isNotEmpty) { + table[field.name!] = value; + } else if (field is PdfRadioButtonListField || + field is PdfCheckBoxField) { + table[field.name!] = 'Off'; + } + } else { + if (field is PdfRadioButtonListField) { + table[field.name!] = helper.getAppearanceStateValue(field); + } else { + final PdfDictionary holder = helper.getWidgetAnnotation( + helper.dictionary!, + helper.crossTable, + ); + final IPdfPrimitive? holderName = + holder[PdfDictionaryProperties.usageApplication]; + if (holderName != null && holderName is PdfName) { + table[field.name!] = holderName.name!; + } + } + } + break; + } + } + } + } + bytes.addAll(utf8.encode('{')); + String json; + int j = 0; + table.forEach((String k, String v) { + json = '"${_replaceJsonDelimiters(k)}":"${_replaceJsonDelimiters(v)}"'; + bytes.addAll(utf8.encode(j > 0 ? ',$json' : json)); + j++; + }); + bytes.addAll(utf8.encode('}')); + return bytes; + } + + String _replaceJsonDelimiters(String value) { + // ignore: unnecessary_string_escapes + return value.contains(RegExp('[":,{}]|[\[]|]')) + ? value + .replaceAll(',', '_x002C_') + .replaceAll('"', '_x0022_') + .replaceAll(':', '_x003A_') + .replaceAll('{', '_x007B_') + .replaceAll('}', '_x007D_') + .replaceAll('[', '_x005B_') + .replaceAll(']', '_x005D_') + : value; + } + + /// Imports XML Data from the given data. + void _importDataXml(List bytes, bool continueImportOnError) { + final String data = utf8.decode(bytes); + final XmlDocument document = XmlDocument.parse(data); + if (document.rootElement.name.local != 'Fields') { + ArgumentError.value('The XML form data stream is not valid'); + } else { + _importXmlData(document.rootElement.children, continueImportOnError); + } + } + + void _importXmlData(List children, bool continueImportOnError) { + for (final XmlNode childNode in children) { + if (childNode is XmlElement) { + if (childNode.innerText.isNotEmpty) { + String fieldName = childNode.name.local.replaceAll('_x0020_', ' '); + fieldName = fieldName + .replaceAll('_x0023_', '#') + .replaceAll('_x002C_', ',') + .replaceAll('_x005C_', r'\') + .replaceAll('_x0022_', '"') + .replaceAll('_x003A_', ':') + .replaceAll('_x005D_', ']') + .replaceAll('_x005D_', ']') + .replaceAll('_x007B_', '{') + .replaceAll('_x007D_', '}') + .replaceAll('_x0024_', r'$'); + try { + final int index = PdfFormFieldCollectionHelper.getHelper( + fields, + ).getFieldIndex(fieldName); + if (index == -1) { + throw ArgumentError('Incorrect field name.'); + } + final PdfField formField = fields[index]; + PdfFieldHelper.getHelper( + formField, + ).importFieldValue(childNode.innerText); + } catch (e) { + if (!continueImportOnError) { + rethrow; + } + } + } + if (childNode.children.isNotEmpty) { + _importXmlData(childNode.children, continueImportOnError); + } + } + } + } + + List _exportDataXML() { + final XmlBuilder builder = XmlBuilder(); + final List elements = []; + builder.processing('xml', 'version="1.0" encoding="utf-8"'); + for (int i = 0; i < fields.count; i++) { + final PdfField field = fields[i]; + if (field.canExport) { + PdfFieldHelper.getHelper(field).exportEmptyField = exportEmptyFields; + final XmlElement? element = + PdfFieldHelper.getHelper(field).exportFieldForXml(); + if (element != null) { + elements.add(element); + } + } + } + builder.element('Fields', nest: elements); + return utf8.encode(builder.buildDocument().toXmlString(pretty: true)); + } +} + +/// [PdfForm] helper +class PdfFormHelper { + /// internal constructor + PdfFormHelper(this.form); + + /// internal field + late PdfForm form; + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal field + bool? needAppearances = false; + + /// internal field + bool setAppearanceDictionary = false; + + /// internal field + final List fieldNames = []; + + /// internal field + PdfCrossTable? crossTable; + + /// internal field + final List terminalFields = []; + + /// internal field + bool formHasKids = false; + + /// internal field + bool isLoadedForm = false; + + /// internal field + Map>? widgetDictionary; + + /// internal field + bool isUR3 = false; + + /// internal field + // ignore: prefer_final_fields + List signatureFlags = [SignatureFlags.none]; + PdfResources? _resource; + + /// internal field + bool flatten = false; + bool _isDefaultAppearance = false; + PdfFormFieldCollection? _fields; + + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + static PdfFormHelper getHelper(PdfForm form) { + return form._helper; + } + + /// internal method + static PdfForm internal( + PdfCrossTable? crossTable, [ + PdfDictionary? formDictionary, + ]) { + return PdfForm._internal(crossTable, formDictionary); + } + + /// internal method + PdfResources get resources { + if (_resource == null) { + _resource = PdfResources(); + dictionary!.setProperty(PdfDictionaryProperties.dr, _resource); + } + return _resource!; + } + + set resources(PdfResources value) { + _resource = value; + if (isLoadedForm) { + dictionary!.setProperty(PdfDictionaryProperties.dr, value); + } + } + + /// internal method + //Raises before stream saves. + void beginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (!isLoadedForm) { + if (signatureFlags.length > 1 || + (signatureFlags.isNotEmpty && + !signatureFlags.contains(SignatureFlags.none))) { + _setSignatureFlags(signatureFlags); + needAppearances = false; + } + _checkFlatten(); + if (form.fields.count > 0 && setAppearanceDictionary) { + dictionary!.setBoolean( + PdfDictionaryProperties.needAppearances, + needAppearances, + ); + } + } else { + int i = 0; + if (signatureFlags.length > 1 || + (signatureFlags.isNotEmpty && + !signatureFlags.contains(SignatureFlags.none))) { + _setSignatureFlags(signatureFlags); + dictionary!.changed = true; + if (!_isDefaultAppearance) { + needAppearances = false; + } + if (dictionary!.containsKey(PdfDictionaryProperties.needAppearances)) { + dictionary!.setBoolean( + PdfDictionaryProperties.needAppearances, + needAppearances, + ); + } + } + while (i < form.fields.count) { + final PdfField field = form.fields[i]; + if (field is PdfSignatureField) { + needAppearances = false; + } + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if (helper.isLoadedField) { + final PdfDictionary dic = helper.dictionary!; + bool isSigned = false; + if (field is PdfSignatureField) { + if (dic.containsKey(PdfDictionaryProperties.v)) { + final IPdfPrimitive? value = PdfCrossTable.dereference( + dic[PdfDictionaryProperties.v], + ); + if (value != null) { + isSigned = true; + } + } + } + bool isNeedAppearance = false; + if (!dic.containsKey(PdfDictionaryProperties.ap) && + _isDefaultAppearance && + !needAppearances! && + !helper.changed) { + isNeedAppearance = true; + } + if (helper.flags.length > 1) { + helper.changed = true; + helper.setFlags(helper.flags); + } + int fieldFlag = 0; + if (dic.containsKey(PdfDictionaryProperties.f)) { + final IPdfPrimitive? flag = PdfCrossTable.dereference( + dic[PdfDictionaryProperties.f], + ); + if (flag != null && flag is PdfNumber) { + fieldFlag = flag.value!.toInt(); + } + } + PdfArray? kids; + if (helper.dictionary!.containsKey(PdfDictionaryProperties.kids)) { + kids = + PdfCrossTable.dereference( + helper.dictionary![PdfDictionaryProperties.kids], + ) + as PdfArray?; + } + if (helper.flattenField && fieldFlag != 6) { + if (field.page != null || kids != null) { + helper.draw(); + } + form.fields.remove(field); + final int? index = crossTable!.items!.lookFor(helper.dictionary!); + if (index != -1) { + crossTable!.items!.objectCollection!.removeAt(index!); + } + --i; + } else if (helper.changed || + isNeedAppearance || + (setAppearanceDictionary && !isSigned)) { + helper.beginSave(); + } + } else { + if (helper.flattenField) { + form.fields.remove(field); + helper.draw(); + --i; + } else { + helper.save(); + } + } + if (_fields?.count == 0) { + final int? index = crossTable!.items!.lookFor(helper.dictionary!); + dictionary?.clear(); + (sender as PdfDictionary).remove(PdfDictionaryProperties.acroForm); + if (index != -1) { + crossTable!.items!.objectCollection!.removeAt(index!); + } + } + ++i; + } + if (_isDefaultAppearance) { + dictionary!.setBoolean( + PdfDictionaryProperties.needAppearances, + _isDefaultAppearance, + ); + } else if (!_isDefaultAppearance && + dictionary!.containsKey(PdfDictionaryProperties.needAppearances)) { + dictionary!.setBoolean( + PdfDictionaryProperties.needAppearances, + _isDefaultAppearance, + ); + } + dictionary!.remove('XFA'); + } + } + + void _addFieldResourcesToPage(PdfField field) { + final PdfResources formResources = + PdfFormHelper.getHelper(field.form!).resources; + if (formResources.containsKey(PdfDictionaryProperties.font)) { + IPdfPrimitive? fieldFontResource = + formResources[PdfDictionaryProperties.font]; + if (fieldFontResource is PdfReferenceHolder) { + fieldFontResource = fieldFontResource.object as PdfDictionary?; + } + if (fieldFontResource != null && fieldFontResource is PdfDictionary) { + // ignore: avoid_function_literals_in_foreach_calls + fieldFontResource.items!.keys.forEach((PdfName? key) { + final PdfResources pageResources = + PdfPageHelper.getHelper(field.page!).getResources()!; + IPdfPrimitive? pageFontResource = + pageResources[PdfDictionaryProperties.font]; + if (pageFontResource is PdfDictionary) { + } else if (pageFontResource is PdfReferenceHolder) { + pageFontResource = pageFontResource.object as PdfDictionary?; + } + if (pageFontResource == null || + (pageFontResource is PdfDictionary && + !pageFontResource.containsKey(key))) { + final PdfReferenceHolder? fieldFontReference = + (fieldFontResource! as PdfDictionary)[key] + as PdfReferenceHolder?; + if (pageFontResource == null) { + final PdfDictionary fontDictionary = PdfDictionary(); + fontDictionary.items![key] = fieldFontReference; + pageResources[PdfDictionaryProperties.font] = fontDictionary; + } else { + (pageFontResource as PdfDictionary).items![key] = + fieldFontReference; + } + } + }); + } + } + } + + void _checkFlatten() { + int i = 0; + while (i < _fields!.count) { + final PdfField field = _fields![i]; + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if (helper.flattenField) { + int? fieldFlag = 0; + final PdfDictionary fieldDictionary = helper.dictionary!; + if (fieldDictionary.containsKey(PdfDictionaryProperties.f)) { + fieldFlag = + (fieldDictionary[PdfDictionaryProperties.f]! as PdfNumber).value + as int?; + } + if (fieldFlag != 6) { + _addFieldResourcesToPage(field); + helper.draw(); + _fields!.remove(field); + deleteFromPages(field); + deleteAnnotation(field); + --i; + } + } else if (helper.isLoadedField) { + helper.beginSave(); + } else { + helper.save(); + } + ++i; + } + } + + /// internal method + void deleteFromPages(PdfField field) { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final PdfDictionary dic = helper.dictionary!; + final PdfName kidsName = PdfName(PdfDictionaryProperties.kids); + final PdfName annotsName = PdfName(PdfDictionaryProperties.annots); + final PdfName pName = PdfName(PdfDictionaryProperties.p); + final bool isLoaded = helper.isLoadedField; + if (dic.items != null) { + if (dic.containsKey(kidsName)) { + final PdfArray array = dic[kidsName]! as PdfArray; + for (int i = 0; i < array.count; ++i) { + final PdfReferenceHolder holder = array[i]! as PdfReferenceHolder; + final PdfDictionary? widget = holder.object as PdfDictionary?; + PdfDictionary? page; + if (!isLoaded) { + final PdfReferenceHolder pageRef = + widget![pName]! as PdfReferenceHolder; + page = pageRef.object as PdfDictionary?; + } else { + PdfReference? pageRef; + if (widget!.containsKey(pName) && + widget[PdfDictionaryProperties.p] is! PdfNull) { + pageRef = crossTable!.getReference(widget[pName]); + } else if (dic.containsKey(pName) && + dic[PdfDictionaryProperties.p] is! PdfNull) { + pageRef = crossTable!.getReference(dic[pName]); + } else if (field.page != null) { + pageRef = crossTable!.getReference( + PdfPageHelper.getHelper(field.page!).dictionary, + ); + } + page = crossTable!.getObject(pageRef) as PdfDictionary?; + } + if (page != null && page.containsKey(annotsName)) { + PdfArray? annots; + if (isLoaded) { + annots = crossTable!.getObject(page[annotsName]) as PdfArray?; + for (int i = 0; i < annots!.count; i++) { + final IPdfPrimitive? obj = annots.elements[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object is PdfDictionary && + obj.object == holder.object) { + annots.remove(obj); + break; + } + } + annots.changed = true; + page.setProperty(annotsName, annots); + } else { + if (page[PdfDictionaryProperties.annots] is PdfReferenceHolder) { + final PdfReferenceHolder annotReference = + page[PdfDictionaryProperties.annots]! as PdfReferenceHolder; + annots = annotReference.object as PdfArray?; + for (int i = 0; i < annots!.count; i++) { + final IPdfPrimitive? obj = annots.elements[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object is PdfDictionary && + obj.object == holder.object) { + annots.remove(obj); + break; + } + } + annots.changed = true; + page.setProperty(PdfDictionaryProperties.annots, annots); + } else if (page[PdfDictionaryProperties.annots] is PdfArray) { + if (helper.page != null) { + final PdfAnnotationCollection annotCollection = + helper.page!.annotations; + if (annotCollection.count > 0) { + final int index = PdfAnnotationCollectionHelper.getHelper( + annotCollection, + ).annotations.indexOf(holder); + if (index >= 0 && index < annotCollection.count) { + annotCollection.remove(annotCollection[index]); + } + } + } + } + } + } else if (isLoaded) { + helper.requiredReference = holder; + if (field.page != null && + PdfPageHelper.getHelper( + field.page!, + ).dictionary!.containsKey(annotsName)) { + final PdfArray annots = + crossTable!.getObject( + PdfPageHelper.getHelper( + field.page!, + ).dictionary![annotsName], + )! + as PdfArray; + for (int i = 0; i < annots.count; i++) { + final IPdfPrimitive? obj = annots.elements[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object is PdfDictionary && + obj.object == widget) { + annots.remove(obj); + break; + } + } + annots.changed = true; + } + if (crossTable!.items != null && + crossTable!.items!.contains(widget)) { + crossTable!.items!.objectCollection!.removeAt( + crossTable!.items!.lookFor(widget)!, + ); + } + helper.requiredReference = null; + } + } + } else { + IPdfPrimitive? page; + if (!isLoaded) { + final PdfReferenceHolder pageRef = + dic.containsKey(pName) + ? (dic[pName] as PdfReferenceHolder?)! + : PdfReferenceHolder( + PdfPageHelper.getHelper(field.page!).dictionary, + ); + page = pageRef.object; + } else { + PdfReference? pageRef; + if (dic.containsKey(pName) && + dic[PdfDictionaryProperties.p] is! PdfNull) { + pageRef = crossTable!.getReference(dic[pName]); + } else if (field.page != null) { + pageRef = crossTable!.getReference( + PdfPageHelper.getHelper(field.page!).dictionary, + ); + } + page = crossTable!.getObject(pageRef); + } + if (page != null && + page is PdfDictionary && + page.containsKey(PdfDictionaryProperties.annots)) { + final IPdfPrimitive? annots = + isLoaded + ? crossTable!.getObject(page[annotsName]) + : page[PdfDictionaryProperties.annots]; + if (annots != null && annots is PdfArray) { + for (int i = 0; i < annots.count; i++) { + final IPdfPrimitive? obj = annots.elements[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object is PdfDictionary && + obj.object == dic) { + annots.remove(obj); + break; + } + } + annots.changed = true; + page.setProperty(PdfDictionaryProperties.annots, annots); + } + } else if (isLoaded && + field.page != null && + PdfPageHelper.getHelper( + field.page!, + ).dictionary!.containsKey(annotsName)) { + final PdfArray annots = + crossTable!.getObject( + PdfPageHelper.getHelper( + field.page!, + ).dictionary![annotsName], + )! + as PdfArray; + for (int i = 0; i < annots.count; i++) { + final IPdfPrimitive? obj = annots.elements[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object is PdfDictionary && + obj.object == dic) { + annots.remove(obj); + break; + } + } + annots.changed = true; + } + } + } + } + + void _setSignatureFlags(List value) { + int n = 0; + for (final SignatureFlags element in value) { + n |= element.index; + } + dictionary!.setNumber(PdfDictionaryProperties.sigFlags, n); + } + + /// internal method + void deleteAnnotation(PdfField field) { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + final PdfDictionary dic = helper.dictionary!; + if (dic.items != null) { + if (dic.containsKey(PdfDictionaryProperties.kids)) { + PdfArray? array; + array = + !helper.isLoadedField + ? dic[PdfDictionaryProperties.kids] as PdfArray? + : crossTable!.getObject(dic[PdfDictionaryProperties.kids]) + as PdfArray?; + array!.clear(); + dic.setProperty(PdfDictionaryProperties.kids, array); + } + } + } + + /// internal method + String? getCorrectName(String? name) { + String? correctName = name; + if (fieldNames.contains(name)) { + final int firstIndex = fieldNames.indexOf(name); + final int lastIndex = fieldNames.lastIndexOf(name); + if (firstIndex != lastIndex) { + correctName = PdfResources.globallyUniqueIdentifier; + fieldNames.removeAt(lastIndex); + fieldNames.add(correctName); + } + } + return correctName; + } + + /// internal method + //Removes field and kids annotation from dictionaries. + void removeFromDictionaries( + PdfField field, [ + bool removeFieldFromAcroForm = false, + ]) { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if ((_fields != null && _fields!.count > 0) || removeFieldFromAcroForm) { + final PdfName fieldsDict = PdfName(PdfDictionaryProperties.fields); + final PdfArray fields = + crossTable!.getObject(dictionary![fieldsDict])! as PdfArray; + for (int i = 0; i < fields.elements.length; i++) { + final IPdfPrimitive? obj = fields.elements[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object is PdfDictionary && + obj.object == helper.dictionary) { + fields.remove(obj); + break; + } + } + helper.dictionary!.isSkip = true; + fields.changed = true; + if (!(!formHasKids || + !helper.dictionary!.items!.containsKey( + PdfName(PdfDictionaryProperties.parent), + ))) { + if (helper.dictionary!.items!.containsKey( + PdfName(PdfDictionaryProperties.parent), + )) { + final PdfDictionary dic = + (helper.dictionary![PdfDictionaryProperties.parent]! + as PdfReferenceHolder) + .object! + as PdfDictionary; + final PdfArray kids = + dic.items![PdfName(PdfDictionaryProperties.kids)]! as PdfArray; + for (int k = 0; k < kids.count; k++) { + final PdfReferenceHolder kidsReference = + kids[k]! as PdfReferenceHolder; + if (kidsReference.object == helper.dictionary) { + kids.remove(kidsReference); + dic.modify(); + break; + } + } + } + } + dictionary!.setProperty(fieldsDict, fields); + } + if (helper.isLoadedField && !removeFieldFromAcroForm) { + deleteFromPages(field); + deleteAnnotation(field); + } + } + + /// internal method + static String decodeXMLConversion(String value) { + String newString = value; + while (newString.contains('_x')) { + final int index = newString.indexOf('_x'); + final String tempString = newString.substring(index); + if (tempString.length >= 7 && tempString[6] == '_') { + newString = newString.replaceRange(index, index + 2, '--'); + final int? charCode = int.tryParse( + value.substring(index + 2, index + 6), + radix: 16, + ); + if (charCode != null && charCode >= 0) { + value = value.replaceRange( + index, + index + 7, + String.fromCharCode(charCode), + ); + newString = newString.replaceRange(index, index + 7, '-'); + } + } else { + break; + } + } + return value; + } +} + +class _NodeInfo { + //Constructor + _NodeInfo(PdfArray? fields, int count) { + _fields = fields; + _count = count; + } + + //Fields + PdfArray? _fields; + late int _count; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart index 62abf43b4..08a40026a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_form_field_collection.dart @@ -1,824 +1,828 @@ -import '../../interfaces/pdf_interface.dart'; -import '../annotations/pdf_annotation.dart'; -import '../general/pdf_collection.dart'; -import '../graphics/pdf_resources.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'enum.dart'; -import 'pdf_button_field.dart'; -import 'pdf_check_box_field.dart'; -import 'pdf_combo_box_field.dart'; -import 'pdf_field.dart'; -import 'pdf_field_item.dart'; -import 'pdf_field_item_collection.dart'; -import 'pdf_form.dart'; -import 'pdf_list_box_field.dart'; -import 'pdf_radio_button_list_field.dart'; -import 'pdf_signature_field.dart'; -import 'pdf_text_box_field.dart'; - -/// Represents a collection of form fields. -class PdfFormFieldCollection extends PdfObjectCollection - implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfFormFieldCollection] class. - PdfFormFieldCollection._([PdfForm? form]) : super() { - _helper = PdfFormFieldCollectionHelper(this, form); - } - - //Fields - late PdfFormFieldCollectionHelper _helper; - - //Properties - /// Gets the [PdfField] at the specified index. - PdfField operator [](int index) { - if ((count < 0) || (index >= count)) { - throw RangeError('index'); - } - return _helper.list[index] as PdfField; - } - - //Public methods - /// Adds the specified field to the collection. - int add(PdfField field) { - return _helper._doAdd(field); - } - - /// Adds a list of fields to the collection. - void addAll(List fields) { - if (fields.isEmpty) { - throw ArgumentError("fields can't be empty"); - } - // ignore: avoid_function_literals_in_foreach_calls - fields.forEach((PdfField element) => add(element)); - } - - /// Removes the specified field in the collection. - void remove(PdfField field) { - _helper._doRemove(field); - } - - /// Removes field at the specified position. - void removeAt(int index) { - _helper._doRemoveAt(index); - } - - /// Gets the index of the specific field. - int indexOf(PdfField field) { - return PdfObjectCollectionHelper.getHelper(this).list.indexOf(field); - } - - /// Determines whether field is contained within the collection. - bool contains(PdfField field) { - return PdfObjectCollectionHelper.getHelper(this).list.contains(field); - } - - /// Clears the form field collection. - void clear() { - _helper._doClear(); - } -} - -/// [PdfFormFieldCollection] helper -class PdfFormFieldCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfFormFieldCollectionHelper(this.formFieldCollection, PdfForm? form) - : super(formFieldCollection) { - if (form != null) { - this.form = form; - final PdfFormHelper formHelper = PdfFormHelper.getHelper(form); - for (int i = 0; i < formHelper.terminalFields.length; ++i) { - final PdfField? field = _getField(index: i); - if (field != null) { - _doAdd(field); - if (removeTerminalField) { - formHelper.terminalFields.removeAt(i); - i--; - } - } - } - } - } - - /// internal field - late PdfFormFieldCollection formFieldCollection; - - /// internal field - final PdfArray array = PdfArray(); - - /// internal field - PdfForm? form; - - /// internal field - bool isAction = false; - - /// internal field - bool removeTerminalField = false; - - /// internal field - // ignore: prefer_final_fields - final List addedFieldNames = []; - - /// internal method - static PdfFormFieldCollectionHelper getHelper( - PdfFormFieldCollection collection, - ) { - return collection._helper; - } - - /// internal method - static PdfFormFieldCollection getCollection([PdfForm? form]) { - return PdfFormFieldCollection._(form); - } - - /// internal method - IPdfPrimitive get element => array; - // ignore: unused_element - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - void createFormFieldsFromWidgets(int startFormFieldIndex) { - for ( - int i = startFormFieldIndex; - i < PdfFormHelper.getHelper(form!).terminalFields.length; - ++i - ) { - final PdfField? field = _getField(index: i); - if (field != null) { - _doAdd(field); - } - } - if (PdfFormHelper.getHelper(form!).widgetDictionary != null && - PdfFormHelper.getHelper(form!).widgetDictionary!.isNotEmpty) { - final Map> widgetDictionary = - PdfFormHelper.getHelper(form!).widgetDictionary!; - for (final List dictValue in widgetDictionary.values) { - if (dictValue.isNotEmpty) { - final PdfField? field = _getField(dictionary: dictValue[0]); - if (field != null) { - PdfFormHelper.getHelper( - form!, - ).terminalFields.add(PdfFieldHelper.getHelper(field).dictionary!); - _doAdd(field); - } - } - } - } - } - - int _doAdd(PdfField field) { - final bool isLoaded = - form != null && PdfFormHelper.getHelper(form!).isLoadedForm; - removeTerminalField = false; - if (!isAction) { - PdfFieldHelper.getHelper(field).setForm(form); - String? name = field.name; - PdfArray? array; - bool skipField = false; - if (isLoaded) { - array = - PdfFormHelper.getHelper( - form!, - ).dictionary!.containsKey(PdfDictionaryProperties.fields) - ? PdfFormHelper.getHelper(form!).crossTable!.getObject( - PdfFormHelper.getHelper( - form!, - ).dictionary![PdfDictionaryProperties.fields], - ) - as PdfArray? - : PdfArray(); - if (PdfFieldHelper.getHelper(field).dictionary!.items!.containsKey( - PdfName(PdfDictionaryProperties.parent), - )) { - skipField = true; - } - } else { - if (name == null || name.isEmpty) { - name = PdfResources.globallyUniqueIdentifier; - } - PdfFormHelper.getHelper(form!).fieldNames.add(name); - } - if (!isLoaded || !PdfFieldHelper.getHelper(field).isLoadedField) { - if (form!.fieldAutoNaming && !skipField) { - if (!isLoaded) { - PdfFieldHelper.getHelper( - field, - ).applyName(PdfFormHelper.getHelper(form!).getCorrectName(name)); - } else { - PdfFieldHelper.getHelper(field).applyName(getCorrectName(name)); - array!.add(PdfReferenceHolder(field)); - PdfFormHelper.getHelper( - form!, - ).dictionary!.setProperty(PdfDictionaryProperties.fields, array); - } - } else if (isLoaded && !addedFieldNames.contains(name) && !skipField) { - array!.add(PdfReferenceHolder(field)); - PdfFormHelper.getHelper( - form!, - ).dictionary!.setProperty(PdfDictionaryProperties.fields, array); - } else if (isLoaded && (!addedFieldNames.contains(name) && skipField) || - (form!.fieldAutoNaming && skipField)) { - addedFieldNames.add(field.name); - } else if (formFieldCollection.count > 0 && !isLoaded) { - final int index = _addFieldItem(field, isLoaded); - if (index >= 0) { - removeTerminalField = true; - return index; - } - } - } - } - if (isLoaded) { - if (!addedFieldNames.contains(field.name)) { - addedFieldNames.add(field.name); - } else if (PdfFieldHelper.getHelper(field).isLoadedField) { - final int index = _addFieldItem(field, isLoaded); - if (index >= 0) { - removeTerminalField = true; - return index; - } - } - } - if (field is! PdfRadioButtonListField && - PdfFieldHelper.getHelper(field).page != null) { - PdfFieldHelper.getHelper( - field, - ).page!.annotations.add(PdfFieldHelper.getHelper(field).widget!); - } - array.add(PdfReferenceHolder(field)); - list.add(field); - PdfFieldHelper.getHelper(field).annotationIndex = list.length - 1; - return list.length - 1; - } - - int _addFieldItem(PdfField field, bool isLoaded) { - for (int i = 0; i < formFieldCollection.count; i++) { - if (list[i] is PdfField) { - final PdfField oldField = list[i] as PdfField; - if (oldField.name == field.name) { - if ((field is PdfTextBoxField && oldField is PdfTextBoxField) || - (field is PdfCheckBoxField && oldField is PdfCheckBoxField)) { - final PdfFieldHelper fieldHelper = PdfFieldHelper.getHelper(field); - final PdfFieldHelper oldFieldHelper = PdfFieldHelper.getHelper( - oldField, - ); - PdfDictionary? dic; - PdfDictionary? oldFieldDic; - if (isLoaded) { - dic = _getWidgetAnnotation(fieldHelper.dictionary!); - oldFieldDic = _getWidgetAnnotation(oldFieldHelper.dictionary!); - PdfAnnotationHelper.getHelper(fieldHelper.widget!).dictionary = - dic; - PdfAnnotationHelper.getHelper(oldFieldHelper.widget!).dictionary = - oldFieldDic; - } else { - dic = - PdfAnnotationHelper.getHelper(fieldHelper.widget!).dictionary; - oldFieldDic = - PdfAnnotationHelper.getHelper( - oldFieldHelper.widget!, - ).dictionary; - } - if (isLoaded) { - final PdfCrossTable? crossTable = - PdfFormHelper.getHelper(form!).crossTable; - final PdfDictionary? cloneIprimitive = - dic?.cloneObject(crossTable!) as PdfDictionary?; - dic = cloneIprimitive; - dic?.setProperty( - PdfDictionaryProperties.p, - PdfReferenceHolder(field.page), - ); - } - dic!.remove(PdfDictionaryProperties.parent); - if (isLoaded) { - dic.setProperty( - PdfDictionaryProperties.parent, - PdfReferenceHolder(oldFieldDic), - ); - } - fieldHelper.widget!.parent = oldField; - if (!isLoaded && fieldHelper.page != null) { - fieldHelper.page!.annotations.add(fieldHelper.widget!); - } - final bool isOldFieldPresent = _checkCollection( - oldFieldHelper.array, - oldFieldDic!, - ); - bool isNewFieldPresent = false; - if (isLoaded) { - isNewFieldPresent = _checkCollection(oldFieldHelper.array, dic); - } - PdfReferenceHolder? oldFieldReferenceHolder; - PdfReferenceHolder? newFieldReferenceHolder; - if (!isOldFieldPresent) { - oldFieldHelper.array.clear(); - oldFieldReferenceHolder = PdfReferenceHolder(oldFieldDic); - oldFieldHelper.array.add(oldFieldReferenceHolder); - oldFieldHelper.fieldItems ??= []; - oldFieldHelper.fieldItems!.add(oldField); - } - if (!isNewFieldPresent) { - newFieldReferenceHolder = PdfReferenceHolder(dic); - oldFieldHelper.array.add(newFieldReferenceHolder); - oldFieldHelper.fieldItems ??= []; - oldFieldHelper.fieldItems!.add(field); - oldFieldHelper.dictionary!.setProperty( - PdfDictionaryProperties.kids, - oldFieldHelper.array, - ); - } - if (isLoaded) { - if (oldFieldReferenceHolder != null) { - _addItem(oldField, oldFieldReferenceHolder, 0, true); - } - if (newFieldReferenceHolder != null) { - _addItem( - oldField, - newFieldReferenceHolder, - oldFieldHelper.array.count - 1, - false, - ); - } - if (PdfFieldHelper.getHelper(field).isLoadedField) { - PdfFormHelper.getHelper( - form!, - ).removeFromDictionaries(field, true); - } - } - return formFieldCollection.count - 1; - } else if (!isLoaded && field is PdfSignatureField) { - final PdfSignatureField currentField = field; - final PdfDictionary dictionary = - PdfAnnotationHelper.getHelper( - PdfFieldHelper.getHelper(currentField).widget!, - ).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.parent)) { - dictionary.remove(PdfDictionaryProperties.parent); - } - PdfFieldHelper.getHelper(currentField).widget!.parent = oldField; - IPdfPrimitive? oldKids; - IPdfPrimitive? newKids; - if (PdfFieldHelper.getHelper( - oldField, - ).dictionary!.containsKey(PdfDictionaryProperties.kids)) { - oldKids = - PdfFieldHelper.getHelper(oldField).dictionary!.items![PdfName( - PdfDictionaryProperties.kids, - )]; - } - if (PdfFieldHelper.getHelper( - field, - ).dictionary!.containsKey(PdfDictionaryProperties.kids)) { - newKids = - PdfFieldHelper.getHelper(field).dictionary!.items![PdfName( - PdfDictionaryProperties.kids, - )]; - } - if (newKids != null && newKids is PdfArray) { - if (oldKids == null || oldKids is! PdfArray) { - oldKids = PdfArray(); - } - for (int i = 0; i < newKids.count; i++) { - final IPdfPrimitive? kidsReference = newKids[i]; - if (kidsReference != null && - kidsReference is PdfReferenceHolder) { - oldKids.add(kidsReference); - } - } - } - PdfFieldHelper.getHelper( - oldField, - ).dictionary!.setProperty(PdfDictionaryProperties.kids, oldKids); - PdfSignatureFieldHelper.getHelper(currentField) - .skipKidsCertificate = true; - if (!field.page!.annotations.contains( - PdfFieldHelper.getHelper(currentField).widget!, - )) { - field.page!.annotations.add( - PdfFieldHelper.getHelper(currentField).widget!, - ); - } - return formFieldCollection.count - 1; - } - } - } - } - return -1; - } - - PdfDictionary _getWidgetAnnotation(PdfDictionary dictionary) { - if (dictionary.containsKey(PdfDictionaryProperties.kids)) { - final IPdfPrimitive? array = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.kids], - ); - if (array is PdfArray && array.count > 0) { - final IPdfPrimitive? dic = PdfCrossTable.dereference(array[0]); - if (dic is PdfDictionary) { - return dic; - } - } - } - return dictionary; - } - - void _addItem( - PdfField field, - PdfReferenceHolder referenceHolder, - int index, - bool initializeNew, - ) { - PdfFieldItemCollection? items; - if (initializeNew) { - items = PdfFieldItemCollectionHelper.load(field); - if (field is PdfCheckBoxField) { - PdfCheckBoxFieldHelper.getHelper(field).items = items; - } else if (field is PdfTextBoxField) { - PdfTextBoxFieldHelper.getHelper(field).items = items; - } - } else { - if (field is PdfCheckBoxField) { - items = field.items; - } else if (field is PdfTextBoxField) { - items = field.items; - } - } - if (items != null) { - final PdfDictionary? itemDictionary = - PdfCrossTable.dereference(referenceHolder) as PdfDictionary?; - if (field is PdfCheckBoxField) { - PdfFieldItemCollectionHelper.getHelper( - items, - ).add(PdfCheckBoxItemHelper.getItem(field, index, itemDictionary)); - } else if (field is PdfTextBoxField) { - PdfFieldItemCollectionHelper.getHelper( - items, - ).add(PdfTextBoxItemHelper.getItem(field, index, itemDictionary)); - } - } - } - - bool _checkCollection(PdfArray array, PdfDictionary dictionary) { - for (int i = 0; i < array.count; i++) { - final IPdfPrimitive? obj = array.elements[i]; - if (obj != null && - obj is PdfReferenceHolder && - obj.object != null && - obj.object is PdfDictionary && - obj.object == dictionary) { - return true; - } - } - return false; - } - - // Gets the field. - PdfField? _getField({int? index, PdfDictionary? dictionary}) { - index != null - ? dictionary = PdfFormHelper.getHelper(form!).terminalFields[index] - : ArgumentError.checkNotNull( - dictionary, - 'method cannot be initialized without parameters', - ); - final PdfCrossTable? crossTable = PdfFormHelper.getHelper(form!).crossTable; - PdfField? field; - final PdfName? name = - PdfFieldHelper.getValue( - dictionary!, - crossTable, - PdfDictionaryProperties.ft, - true, - ) - as PdfName?; - PdfFieldTypes type = PdfFieldTypes.none; - if (name != null) { - type = _getFieldType(name, dictionary, crossTable); - } - switch (type) { - case PdfFieldTypes.comboBox: - field = _createComboBox(dictionary, crossTable!); - break; - case PdfFieldTypes.listBox: - field = _createListBox(dictionary, crossTable!); - break; - case PdfFieldTypes.textField: - field = _createTextField(dictionary, crossTable!); - break; - case PdfFieldTypes.checkBox: - field = _createCheckBox(dictionary, crossTable!); - break; - case PdfFieldTypes.radioButton: - field = _createRadioButton(dictionary, crossTable!); - break; - case PdfFieldTypes.pushButton: - field = _createPushButton(dictionary, crossTable!); - break; - case PdfFieldTypes.signatureField: - field = _createSignatureField(dictionary, crossTable!); - break; - case PdfFieldTypes.none: - break; - } - if (field != null) { - PdfFieldHelper.getHelper(field).setForm(form); - PdfFieldHelper.getHelper(field).beforeNameChanges = (String name) { - if (addedFieldNames.contains(name)) { - throw ArgumentError('Field with the same name already exist'); - } - }; - } - return field; - } - - //Gets the type of the field. - PdfFieldTypes _getFieldType( - PdfName name, - PdfDictionary dictionary, - PdfCrossTable? crossTable, - ) { - final String str = name.name!; - PdfFieldTypes type = PdfFieldTypes.none; - final PdfNumber? number = - PdfFieldHelper.getValue( - dictionary, - crossTable, - PdfDictionaryProperties.fieldFlags, - true, - ) - as PdfNumber?; - int fieldFlags = 0; - if (number != null) { - fieldFlags = number.value!.toInt(); - } - switch (str.toLowerCase()) { - case 'ch': - //check with FieldFlags.combo value. - if ((fieldFlags & 1 << 17) != 0) { - type = PdfFieldTypes.comboBox; - } else { - type = PdfFieldTypes.listBox; - } - break; - case 'tx': - type = PdfFieldTypes.textField; - break; - case 'btn': - if ((fieldFlags & 1 << 15) != 0) { - type = PdfFieldTypes.radioButton; - } else if ((fieldFlags & 1 << 16) != 0) { - type = PdfFieldTypes.pushButton; - } else { - type = PdfFieldTypes.checkBox; - } - break; - case 'sig': - type = PdfFieldTypes.signatureField; - break; - } - return type; - } - - //Creates the combo box. - PdfField _createComboBox(PdfDictionary dictionary, PdfCrossTable crossTable) { - final PdfField field = PdfComboBoxFieldHelper.loadComboBox( - dictionary, - crossTable, - ); - PdfFieldHelper.getHelper(field).setForm(form); - return field; - } - - //Creates the list box. - PdfField _createListBox(PdfDictionary dictionary, PdfCrossTable crossTable) { - final PdfField field = PdfListBoxFieldHelper.loadListBox( - dictionary, - crossTable, - ); - PdfFieldHelper.getHelper(field).setForm(form); - return field; - } - - //Creates the text field. - PdfField _createTextField( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final PdfField field = PdfTextBoxFieldHelper.loadTextBox( - dictionary, - crossTable, - ); - PdfFieldHelper.getHelper(field).setForm(form); - return field; - } - - PdfField _createCheckBox(PdfDictionary dictionary, PdfCrossTable crossTable) { - final PdfField field = PdfCheckBoxFieldHelper.loadCheckBoxField( - dictionary, - crossTable, - ); - PdfFieldHelper.getHelper(field).setForm(form); - return field; - } - - PdfField _createRadioButton( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final PdfField field = PdfRadioButtonListFieldHelper.loaded( - dictionary, - crossTable, - ); - PdfFieldHelper.getHelper(field).setForm(form); - return field; - } - - PdfField _createPushButton( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final PdfField field = PdfButtonFieldHelper.loadButtonField( - dictionary, - crossTable, - ); - PdfFieldHelper.getHelper(field).setForm(form); - return field; - } - - PdfField _createSignatureField( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - final PdfField field = PdfSignatureFieldHelper.loadSignatureField( - dictionary, - crossTable, - ); - PdfFieldHelper.getHelper(field).setForm(form); - return field; - } - - /// Gets the new name of the field. - String? getCorrectName(String? name) { - final List tempList = []; - for (int i = 0; i < formFieldCollection.count; i++) { - final Object entry = list[i]; - if (entry is PdfField) { - tempList.add(entry.name); - } - } - String? correctName = name; - int index = 0; - while (tempList.contains(correctName)) { - correctName = name! + index.toString(); - ++index; - } - tempList.clear(); - return correctName; - } - - /// internal method - int getFieldIndex(String name) { - int i = -1; - final List fieldNames = []; - final List indexedFieldNames = []; - for (int j = 0; j < formFieldCollection.count; j++) { - if (PdfObjectCollectionHelper.getHelper(formFieldCollection).list[j] - is PdfField) { - final PdfField field = - PdfObjectCollectionHelper.getHelper(formFieldCollection).list[j] - as PdfField; - fieldNames.add(field.name!); - if (field.name != null) { - indexedFieldNames.add(field.name!.split('[')[0]); - } - } - } - if (fieldNames.contains(name)) { - i = fieldNames.indexOf(name); - } else if (indexedFieldNames.contains(name)) { - i = indexedFieldNames.indexOf(name); - } - return i; - } - - /// internal method - void removeContainingField(PdfReferenceHolder pageReferenceHolder) { - for (int i = array.count - 1; i >= 0; --i) { - final IPdfPrimitive? fieldDictionary = PdfCrossTable.dereference( - array[i], - ); - if (fieldDictionary != null && fieldDictionary is PdfDictionary) { - if (fieldDictionary.containsKey(PdfDictionaryProperties.p)) { - final IPdfPrimitive? holder = - fieldDictionary[PdfDictionaryProperties.p]; - if (holder != null && - holder is PdfReferenceHolder && - holder.object == pageReferenceHolder.object) { - _doRemoveAt(i); - } - } else if (fieldDictionary.containsKey(PdfDictionaryProperties.kids)) { - final bool removed = _removeContainingFieldItems( - fieldDictionary, - pageReferenceHolder, - ); - if (removed) { - _doRemoveAt(i); - } - } - } - } - } - - void _removeFromDictionary(PdfField field) { - if (PdfFieldHelper.getHelper(field).isLoadedField) { - PdfFormHelper.getHelper(form!).removeFromDictionaries(field); - } - addedFieldNames.remove(field.name); - } - - void _doRemove(PdfField field) { - if (PdfFieldHelper.getHelper(field).isLoadedField || - (field.form != null && - PdfFormHelper.getHelper(field.form!).isLoadedForm)) { - _removeFromDictionary(field); - } - PdfFieldHelper.getHelper(field).setForm(null); - final int index = list.indexOf(field); - array.removeAt(index); - list.removeAt(index); - } - - void _doRemoveAt(int index) { - if (list[index] is PdfField && - PdfFieldHelper.getHelper(list[index] as PdfField).isLoadedField) { - _removeFromDictionary(list[index] as PdfField); - } - array.removeAt(index); - list.removeAt(index); - } - - void _doClear() { - if (formFieldCollection.count > 0) { - for (int i = 0; i < formFieldCollection.count; i++) { - if (list[i] is PdfField) { - final PdfField field = list[i] as PdfField; - if (PdfFieldHelper.getHelper(field).isLoadedField) { - _removeFromDictionary(field); - } else { - PdfFormHelper.getHelper(form!).deleteFromPages(field); - PdfFormHelper.getHelper(form!).deleteAnnotation(field); - PdfFieldHelper.getHelper(field).page = null; - if (PdfFieldHelper.getHelper(field).dictionary!.items != null) { - PdfFieldHelper.getHelper(field).dictionary!.clear(); - } - PdfFieldHelper.getHelper(field).setForm(null); - } - } - } - } - addedFieldNames.clear(); - PdfFormHelper.getHelper(form!).terminalFields.clear(); - array.clear(); - list.clear(); - } - - bool _removeContainingFieldItems( - PdfDictionary fieldDictionary, - PdfReferenceHolder pageReferenceHolder, - ) { - bool isAllKidsRemoved = false; - if (fieldDictionary.containsKey(PdfDictionaryProperties.kids)) { - final IPdfPrimitive? array = PdfCrossTable.dereference( - fieldDictionary[PdfDictionaryProperties.kids], - ); - if (array != null && array is PdfArray) { - for (int i = array.count - 1; i >= 0; --i) { - IPdfPrimitive? holder; - final IPdfPrimitive? kidObject = PdfCrossTable.dereference(array[i]); - if (kidObject != null && - kidObject is PdfDictionary && - kidObject.containsKey(PdfDictionaryProperties.p)) { - holder = kidObject[PdfDictionaryProperties.p]; - } - if (holder != null && - holder is PdfReferenceHolder && - holder.object == pageReferenceHolder.object) { - (kidObject as PdfDictionary?)!.isSkip = true; - array.removeAt(i); - array.changed = true; - } - } - if (array.count == 0) { - isAllKidsRemoved = true; - } - } - } - return isAllKidsRemoved; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../annotations/pdf_annotation.dart'; +import '../general/pdf_collection.dart'; +import '../graphics/pdf_resources.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'enum.dart'; +import 'pdf_button_field.dart'; +import 'pdf_check_box_field.dart'; +import 'pdf_combo_box_field.dart'; +import 'pdf_field.dart'; +import 'pdf_field_item.dart'; +import 'pdf_field_item_collection.dart'; +import 'pdf_form.dart'; +import 'pdf_list_box_field.dart'; +import 'pdf_radio_button_list_field.dart'; +import 'pdf_signature_field.dart'; +import 'pdf_text_box_field.dart'; + +/// Represents a collection of form fields. +class PdfFormFieldCollection extends PdfObjectCollection + implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfFormFieldCollection] class. + PdfFormFieldCollection._([PdfForm? form]) : super() { + _helper = PdfFormFieldCollectionHelper(this, form); + } + + //Fields + late PdfFormFieldCollectionHelper _helper; + + //Properties + /// Gets the [PdfField] at the specified index. + PdfField operator [](int index) { + if ((count < 0) || (index >= count)) { + throw RangeError('index'); + } + return _helper.list[index] as PdfField; + } + + //Public methods + /// Adds the specified field to the collection. + int add(PdfField field) { + return _helper._doAdd(field); + } + + /// Adds a list of fields to the collection. + void addAll(List fields) { + if (fields.isEmpty) { + throw ArgumentError("fields can't be empty"); + } + // ignore: avoid_function_literals_in_foreach_calls + fields.forEach((PdfField element) => add(element)); + } + + /// Removes the specified field in the collection. + void remove(PdfField field) { + _helper._doRemove(field); + } + + /// Removes field at the specified position. + void removeAt(int index) { + _helper._doRemoveAt(index); + } + + /// Gets the index of the specific field. + int indexOf(PdfField field) { + return PdfObjectCollectionHelper.getHelper(this).list.indexOf(field); + } + + /// Determines whether field is contained within the collection. + bool contains(PdfField field) { + return PdfObjectCollectionHelper.getHelper(this).list.contains(field); + } + + /// Clears the form field collection. + void clear() { + _helper._doClear(); + } +} + +/// [PdfFormFieldCollection] helper +class PdfFormFieldCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfFormFieldCollectionHelper(this.formFieldCollection, PdfForm? form) + : super(formFieldCollection) { + if (form != null) { + this.form = form; + final PdfFormHelper formHelper = PdfFormHelper.getHelper(form); + for (int i = 0; i < formHelper.terminalFields.length; ++i) { + final PdfField? field = _getField(index: i); + if (field != null) { + _doAdd(field); + if (removeTerminalField) { + formHelper.terminalFields.removeAt(i); + i--; + } + } + } + } + } + + /// internal field + late PdfFormFieldCollection formFieldCollection; + + /// internal field + final PdfArray array = PdfArray(); + + /// internal field + PdfForm? form; + + /// internal field + bool isAction = false; + + /// internal field + bool removeTerminalField = false; + + /// internal field + // ignore: prefer_final_fields + final List addedFieldNames = []; + + /// internal method + static PdfFormFieldCollectionHelper getHelper( + PdfFormFieldCollection collection, + ) { + return collection._helper; + } + + /// internal method + static PdfFormFieldCollection getCollection([PdfForm? form]) { + return PdfFormFieldCollection._(form); + } + + /// internal method + IPdfPrimitive get element => array; + // ignore: unused_element + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + void createFormFieldsFromWidgets(int startFormFieldIndex) { + for ( + int i = startFormFieldIndex; + i < PdfFormHelper.getHelper(form!).terminalFields.length; + ++i + ) { + final PdfField? field = _getField(index: i); + if (field != null) { + _doAdd(field); + } + } + if (PdfFormHelper.getHelper(form!).widgetDictionary != null && + PdfFormHelper.getHelper(form!).widgetDictionary!.isNotEmpty) { + final Map> widgetDictionary = + PdfFormHelper.getHelper(form!).widgetDictionary!; + for (final List dictValue in widgetDictionary.values) { + if (dictValue.isNotEmpty) { + final PdfField? field = _getField(dictionary: dictValue[0]); + if (field != null) { + PdfFormHelper.getHelper( + form!, + ).terminalFields.add(PdfFieldHelper.getHelper(field).dictionary!); + _doAdd(field); + } + } + } + } + } + + int _doAdd(PdfField field) { + final bool isLoaded = + form != null && PdfFormHelper.getHelper(form!).isLoadedForm; + removeTerminalField = false; + if (!isAction) { + PdfFieldHelper.getHelper(field).setForm(form); + String? name = field.name; + PdfArray? array; + bool skipField = false; + if (isLoaded) { + array = + PdfFormHelper.getHelper( + form!, + ).dictionary!.containsKey(PdfDictionaryProperties.fields) + ? PdfFormHelper.getHelper(form!).crossTable!.getObject( + PdfFormHelper.getHelper( + form!, + ).dictionary![PdfDictionaryProperties.fields], + ) + as PdfArray? + : PdfArray(); + if (PdfFieldHelper.getHelper(field).dictionary!.items!.containsKey( + PdfName(PdfDictionaryProperties.parent), + )) { + skipField = true; + } + } else { + if (name == null || name.isEmpty) { + name = PdfResources.globallyUniqueIdentifier; + } + PdfFormHelper.getHelper(form!).fieldNames.add(name); + } + if (!isLoaded || !PdfFieldHelper.getHelper(field).isLoadedField) { + if (form!.fieldAutoNaming && !skipField) { + if (!isLoaded) { + PdfFieldHelper.getHelper( + field, + ).applyName(PdfFormHelper.getHelper(form!).getCorrectName(name)); + } else { + PdfFieldHelper.getHelper(field).applyName(getCorrectName(name)); + array!.add(PdfReferenceHolder(field)); + PdfFormHelper.getHelper( + form!, + ).dictionary!.setProperty(PdfDictionaryProperties.fields, array); + } + } else if (isLoaded && !addedFieldNames.contains(name) && !skipField) { + array!.add(PdfReferenceHolder(field)); + PdfFormHelper.getHelper( + form!, + ).dictionary!.setProperty(PdfDictionaryProperties.fields, array); + } else if (isLoaded && (!addedFieldNames.contains(name) && skipField) || + (form!.fieldAutoNaming && skipField)) { + addedFieldNames.add(field.name); + } else if (formFieldCollection.count > 0 && !isLoaded) { + final int index = _addFieldItem(field, isLoaded); + if (index >= 0) { + removeTerminalField = true; + return index; + } + } + } + } + if (isLoaded) { + if (!addedFieldNames.contains(field.name)) { + addedFieldNames.add(field.name); + } else if (PdfFieldHelper.getHelper(field).isLoadedField) { + final int index = _addFieldItem(field, isLoaded); + if (index >= 0) { + removeTerminalField = true; + return index; + } + } + } + if (field is! PdfRadioButtonListField && + PdfFieldHelper.getHelper(field).page != null) { + PdfFieldHelper.getHelper( + field, + ).page!.annotations.add(PdfFieldHelper.getHelper(field).widget!); + } + array.add(PdfReferenceHolder(field)); + list.add(field); + PdfFieldHelper.getHelper(field).annotationIndex = list.length - 1; + return list.length - 1; + } + + int _addFieldItem(PdfField field, bool isLoaded) { + for (int i = 0; i < formFieldCollection.count; i++) { + if (list[i] is PdfField) { + final PdfField oldField = list[i] as PdfField; + if (oldField.name == field.name) { + if ((field is PdfTextBoxField && oldField is PdfTextBoxField) || + (field is PdfCheckBoxField && oldField is PdfCheckBoxField)) { + final PdfFieldHelper fieldHelper = PdfFieldHelper.getHelper(field); + final PdfFieldHelper oldFieldHelper = PdfFieldHelper.getHelper( + oldField, + ); + PdfDictionary? dic; + PdfDictionary? oldFieldDic; + if (isLoaded) { + dic = _getWidgetAnnotation(fieldHelper.dictionary!); + oldFieldDic = _getWidgetAnnotation(oldFieldHelper.dictionary!); + PdfAnnotationHelper.getHelper(fieldHelper.widget!).dictionary = + dic; + PdfAnnotationHelper.getHelper(oldFieldHelper.widget!).dictionary = + oldFieldDic; + } else { + dic = + PdfAnnotationHelper.getHelper(fieldHelper.widget!).dictionary; + oldFieldDic = + PdfAnnotationHelper.getHelper( + oldFieldHelper.widget!, + ).dictionary; + } + if (isLoaded) { + final PdfCrossTable? crossTable = + PdfFormHelper.getHelper(form!).crossTable; + final PdfDictionary? cloneIprimitive = + dic?.cloneObject(crossTable!) as PdfDictionary?; + dic = cloneIprimitive; + dic?.setProperty( + PdfDictionaryProperties.p, + PdfReferenceHolder(field.page), + ); + } + dic!.remove(PdfDictionaryProperties.parent); + if (fieldHelper.dictionary!.containsKey( + PdfDictionaryProperties.kids, + )) { + if (isLoaded) { + dic.setProperty( + PdfDictionaryProperties.parent, + PdfReferenceHolder(oldFieldDic), + ); + } + fieldHelper.widget!.parent = oldField; + } + if (!isLoaded && fieldHelper.page != null) { + fieldHelper.page!.annotations.add(fieldHelper.widget!); + } + final bool isOldFieldPresent = _checkCollection( + oldFieldHelper.array, + oldFieldDic!, + ); + bool isNewFieldPresent = false; + if (isLoaded) { + isNewFieldPresent = _checkCollection(oldFieldHelper.array, dic); + } + PdfReferenceHolder? oldFieldReferenceHolder; + PdfReferenceHolder? newFieldReferenceHolder; + if (!isOldFieldPresent) { + oldFieldHelper.array.clear(); + oldFieldReferenceHolder = PdfReferenceHolder(oldFieldDic); + oldFieldHelper.array.add(oldFieldReferenceHolder); + oldFieldHelper.fieldItems ??= []; + oldFieldHelper.fieldItems!.add(oldField); + } + if (!isNewFieldPresent) { + newFieldReferenceHolder = PdfReferenceHolder(dic); + oldFieldHelper.array.add(newFieldReferenceHolder); + oldFieldHelper.fieldItems ??= []; + oldFieldHelper.fieldItems!.add(field); + oldFieldHelper.dictionary!.setProperty( + PdfDictionaryProperties.kids, + oldFieldHelper.array, + ); + } + if (isLoaded) { + if (oldFieldReferenceHolder != null) { + _addItem(oldField, oldFieldReferenceHolder, 0, true); + } + if (newFieldReferenceHolder != null) { + _addItem( + oldField, + newFieldReferenceHolder, + oldFieldHelper.array.count - 1, + false, + ); + } + if (PdfFieldHelper.getHelper(field).isLoadedField) { + PdfFormHelper.getHelper( + form!, + ).removeFromDictionaries(field, true); + } + } + return formFieldCollection.count - 1; + } else if (!isLoaded && field is PdfSignatureField) { + final PdfSignatureField currentField = field; + final PdfDictionary dictionary = + PdfAnnotationHelper.getHelper( + PdfFieldHelper.getHelper(currentField).widget!, + ).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.parent)) { + dictionary.remove(PdfDictionaryProperties.parent); + } + PdfFieldHelper.getHelper(currentField).widget!.parent = oldField; + IPdfPrimitive? oldKids; + IPdfPrimitive? newKids; + if (PdfFieldHelper.getHelper( + oldField, + ).dictionary!.containsKey(PdfDictionaryProperties.kids)) { + oldKids = + PdfFieldHelper.getHelper(oldField).dictionary!.items![PdfName( + PdfDictionaryProperties.kids, + )]; + } + if (PdfFieldHelper.getHelper( + field, + ).dictionary!.containsKey(PdfDictionaryProperties.kids)) { + newKids = + PdfFieldHelper.getHelper(field).dictionary!.items![PdfName( + PdfDictionaryProperties.kids, + )]; + } + if (newKids != null && newKids is PdfArray) { + if (oldKids == null || oldKids is! PdfArray) { + oldKids = PdfArray(); + } + for (int i = 0; i < newKids.count; i++) { + final IPdfPrimitive? kidsReference = newKids[i]; + if (kidsReference != null && + kidsReference is PdfReferenceHolder) { + oldKids.add(kidsReference); + } + } + } + PdfFieldHelper.getHelper( + oldField, + ).dictionary!.setProperty(PdfDictionaryProperties.kids, oldKids); + PdfSignatureFieldHelper.getHelper(currentField) + .skipKidsCertificate = true; + if (!field.page!.annotations.contains( + PdfFieldHelper.getHelper(currentField).widget!, + )) { + field.page!.annotations.add( + PdfFieldHelper.getHelper(currentField).widget!, + ); + } + return formFieldCollection.count - 1; + } + } + } + } + return -1; + } + + PdfDictionary _getWidgetAnnotation(PdfDictionary dictionary) { + if (dictionary.containsKey(PdfDictionaryProperties.kids)) { + final IPdfPrimitive? array = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.kids], + ); + if (array is PdfArray && array.count > 0) { + final IPdfPrimitive? dic = PdfCrossTable.dereference(array[0]); + if (dic is PdfDictionary) { + return dic; + } + } + } + return dictionary; + } + + void _addItem( + PdfField field, + PdfReferenceHolder referenceHolder, + int index, + bool initializeNew, + ) { + PdfFieldItemCollection? items; + if (initializeNew) { + items = PdfFieldItemCollectionHelper.load(field); + if (field is PdfCheckBoxField) { + PdfCheckBoxFieldHelper.getHelper(field).items = items; + } else if (field is PdfTextBoxField) { + PdfTextBoxFieldHelper.getHelper(field).items = items; + } + } else { + if (field is PdfCheckBoxField) { + items = field.items; + } else if (field is PdfTextBoxField) { + items = field.items; + } + } + if (items != null) { + final PdfDictionary? itemDictionary = + PdfCrossTable.dereference(referenceHolder) as PdfDictionary?; + if (field is PdfCheckBoxField) { + PdfFieldItemCollectionHelper.getHelper( + items, + ).add(PdfCheckBoxItemHelper.getItem(field, index, itemDictionary)); + } else if (field is PdfTextBoxField) { + PdfFieldItemCollectionHelper.getHelper( + items, + ).add(PdfTextBoxItemHelper.getItem(field, index, itemDictionary)); + } + } + } + + bool _checkCollection(PdfArray array, PdfDictionary dictionary) { + for (int i = 0; i < array.count; i++) { + final IPdfPrimitive? obj = array.elements[i]; + if (obj != null && + obj is PdfReferenceHolder && + obj.object != null && + obj.object is PdfDictionary && + obj.object == dictionary) { + return true; + } + } + return false; + } + + // Gets the field. + PdfField? _getField({int? index, PdfDictionary? dictionary}) { + index != null + ? dictionary = PdfFormHelper.getHelper(form!).terminalFields[index] + : ArgumentError.checkNotNull( + dictionary, + 'method cannot be initialized without parameters', + ); + final PdfCrossTable? crossTable = PdfFormHelper.getHelper(form!).crossTable; + PdfField? field; + final PdfName? name = + PdfFieldHelper.getValue( + dictionary!, + crossTable, + PdfDictionaryProperties.ft, + true, + ) + as PdfName?; + PdfFieldTypes type = PdfFieldTypes.none; + if (name != null) { + type = _getFieldType(name, dictionary, crossTable); + } + switch (type) { + case PdfFieldTypes.comboBox: + field = _createComboBox(dictionary, crossTable!); + break; + case PdfFieldTypes.listBox: + field = _createListBox(dictionary, crossTable!); + break; + case PdfFieldTypes.textField: + field = _createTextField(dictionary, crossTable!); + break; + case PdfFieldTypes.checkBox: + field = _createCheckBox(dictionary, crossTable!); + break; + case PdfFieldTypes.radioButton: + field = _createRadioButton(dictionary, crossTable!); + break; + case PdfFieldTypes.pushButton: + field = _createPushButton(dictionary, crossTable!); + break; + case PdfFieldTypes.signatureField: + field = _createSignatureField(dictionary, crossTable!); + break; + case PdfFieldTypes.none: + break; + } + if (field != null) { + PdfFieldHelper.getHelper(field).setForm(form); + PdfFieldHelper.getHelper(field).beforeNameChanges = (String name) { + if (addedFieldNames.contains(name)) { + throw ArgumentError('Field with the same name already exist'); + } + }; + } + return field; + } + + //Gets the type of the field. + PdfFieldTypes _getFieldType( + PdfName name, + PdfDictionary dictionary, + PdfCrossTable? crossTable, + ) { + final String str = name.name!; + PdfFieldTypes type = PdfFieldTypes.none; + final PdfNumber? number = + PdfFieldHelper.getValue( + dictionary, + crossTable, + PdfDictionaryProperties.fieldFlags, + true, + ) + as PdfNumber?; + int fieldFlags = 0; + if (number != null) { + fieldFlags = number.value!.toInt(); + } + switch (str.toLowerCase()) { + case 'ch': + //check with FieldFlags.combo value. + if ((fieldFlags & 1 << 17) != 0) { + type = PdfFieldTypes.comboBox; + } else { + type = PdfFieldTypes.listBox; + } + break; + case 'tx': + type = PdfFieldTypes.textField; + break; + case 'btn': + if ((fieldFlags & 1 << 15) != 0) { + type = PdfFieldTypes.radioButton; + } else if ((fieldFlags & 1 << 16) != 0) { + type = PdfFieldTypes.pushButton; + } else { + type = PdfFieldTypes.checkBox; + } + break; + case 'sig': + type = PdfFieldTypes.signatureField; + break; + } + return type; + } + + //Creates the combo box. + PdfField _createComboBox(PdfDictionary dictionary, PdfCrossTable crossTable) { + final PdfField field = PdfComboBoxFieldHelper.loadComboBox( + dictionary, + crossTable, + ); + PdfFieldHelper.getHelper(field).setForm(form); + return field; + } + + //Creates the list box. + PdfField _createListBox(PdfDictionary dictionary, PdfCrossTable crossTable) { + final PdfField field = PdfListBoxFieldHelper.loadListBox( + dictionary, + crossTable, + ); + PdfFieldHelper.getHelper(field).setForm(form); + return field; + } + + //Creates the text field. + PdfField _createTextField( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final PdfField field = PdfTextBoxFieldHelper.loadTextBox( + dictionary, + crossTable, + ); + PdfFieldHelper.getHelper(field).setForm(form); + return field; + } + + PdfField _createCheckBox(PdfDictionary dictionary, PdfCrossTable crossTable) { + final PdfField field = PdfCheckBoxFieldHelper.loadCheckBoxField( + dictionary, + crossTable, + ); + PdfFieldHelper.getHelper(field).setForm(form); + return field; + } + + PdfField _createRadioButton( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final PdfField field = PdfRadioButtonListFieldHelper.loaded( + dictionary, + crossTable, + ); + PdfFieldHelper.getHelper(field).setForm(form); + return field; + } + + PdfField _createPushButton( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final PdfField field = PdfButtonFieldHelper.loadButtonField( + dictionary, + crossTable, + ); + PdfFieldHelper.getHelper(field).setForm(form); + return field; + } + + PdfField _createSignatureField( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + final PdfField field = PdfSignatureFieldHelper.loadSignatureField( + dictionary, + crossTable, + ); + PdfFieldHelper.getHelper(field).setForm(form); + return field; + } + + /// Gets the new name of the field. + String? getCorrectName(String? name) { + final List tempList = []; + for (int i = 0; i < formFieldCollection.count; i++) { + final Object entry = list[i]; + if (entry is PdfField) { + tempList.add(entry.name); + } + } + String? correctName = name; + int index = 0; + while (tempList.contains(correctName)) { + correctName = name! + index.toString(); + ++index; + } + tempList.clear(); + return correctName; + } + + /// internal method + int getFieldIndex(String name) { + int i = -1; + final List fieldNames = []; + final List indexedFieldNames = []; + for (int j = 0; j < formFieldCollection.count; j++) { + if (PdfObjectCollectionHelper.getHelper(formFieldCollection).list[j] + is PdfField) { + final PdfField field = + PdfObjectCollectionHelper.getHelper(formFieldCollection).list[j] + as PdfField; + fieldNames.add(field.name!); + if (field.name != null) { + indexedFieldNames.add(field.name!.split('[')[0]); + } + } + } + if (fieldNames.contains(name)) { + i = fieldNames.indexOf(name); + } else if (indexedFieldNames.contains(name)) { + i = indexedFieldNames.indexOf(name); + } + return i; + } + + /// internal method + void removeContainingField(PdfReferenceHolder pageReferenceHolder) { + for (int i = array.count - 1; i >= 0; --i) { + final IPdfPrimitive? fieldDictionary = PdfCrossTable.dereference( + array[i], + ); + if (fieldDictionary != null && fieldDictionary is PdfDictionary) { + if (fieldDictionary.containsKey(PdfDictionaryProperties.p)) { + final IPdfPrimitive? holder = + fieldDictionary[PdfDictionaryProperties.p]; + if (holder != null && + holder is PdfReferenceHolder && + holder.object == pageReferenceHolder.object) { + _doRemoveAt(i); + } + } else if (fieldDictionary.containsKey(PdfDictionaryProperties.kids)) { + final bool removed = _removeContainingFieldItems( + fieldDictionary, + pageReferenceHolder, + ); + if (removed) { + _doRemoveAt(i); + } + } + } + } + } + + void _removeFromDictionary(PdfField field) { + if (PdfFieldHelper.getHelper(field).isLoadedField) { + PdfFormHelper.getHelper(form!).removeFromDictionaries(field); + } + addedFieldNames.remove(field.name); + } + + void _doRemove(PdfField field) { + if (PdfFieldHelper.getHelper(field).isLoadedField || + (field.form != null && + PdfFormHelper.getHelper(field.form!).isLoadedForm)) { + _removeFromDictionary(field); + } + PdfFieldHelper.getHelper(field).setForm(null); + final int index = list.indexOf(field); + array.removeAt(index); + list.removeAt(index); + } + + void _doRemoveAt(int index) { + if (list[index] is PdfField && + PdfFieldHelper.getHelper(list[index] as PdfField).isLoadedField) { + _removeFromDictionary(list[index] as PdfField); + } + array.removeAt(index); + list.removeAt(index); + } + + void _doClear() { + if (formFieldCollection.count > 0) { + for (int i = 0; i < formFieldCollection.count; i++) { + if (list[i] is PdfField) { + final PdfField field = list[i] as PdfField; + if (PdfFieldHelper.getHelper(field).isLoadedField) { + _removeFromDictionary(field); + } else { + PdfFormHelper.getHelper(form!).deleteFromPages(field); + PdfFormHelper.getHelper(form!).deleteAnnotation(field); + PdfFieldHelper.getHelper(field).page = null; + if (PdfFieldHelper.getHelper(field).dictionary!.items != null) { + PdfFieldHelper.getHelper(field).dictionary!.clear(); + } + PdfFieldHelper.getHelper(field).setForm(null); + } + } + } + } + addedFieldNames.clear(); + PdfFormHelper.getHelper(form!).terminalFields.clear(); + array.clear(); + list.clear(); + } + + bool _removeContainingFieldItems( + PdfDictionary fieldDictionary, + PdfReferenceHolder pageReferenceHolder, + ) { + bool isAllKidsRemoved = false; + if (fieldDictionary.containsKey(PdfDictionaryProperties.kids)) { + final IPdfPrimitive? array = PdfCrossTable.dereference( + fieldDictionary[PdfDictionaryProperties.kids], + ); + if (array != null && array is PdfArray) { + for (int i = array.count - 1; i >= 0; --i) { + IPdfPrimitive? holder; + final IPdfPrimitive? kidObject = PdfCrossTable.dereference(array[i]); + if (kidObject != null && + kidObject is PdfDictionary && + kidObject.containsKey(PdfDictionaryProperties.p)) { + holder = kidObject[PdfDictionaryProperties.p]; + } + if (holder != null && + holder is PdfReferenceHolder && + holder.object == pageReferenceHolder.object) { + (kidObject as PdfDictionary?)!.isSkip = true; + array.removeAt(i); + array.changed = true; + } + } + if (array.count == 0) { + isAllKidsRemoved = true; + } + } + } + return isAllKidsRemoved; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_box_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_box_field.dart index d86918d4a..3f71862f2 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_box_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_box_field.dart @@ -1,360 +1,360 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/pdf_annotation.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'enum.dart'; -import 'pdf_field.dart'; -import 'pdf_field_painter.dart'; -import 'pdf_form.dart'; -import 'pdf_list_field.dart'; -import 'pdf_list_field_item.dart'; -import 'pdf_list_field_item_collection.dart'; - -/// Represents list box field of the PDF form. -class PdfListBoxField extends PdfListField { - //Constructor - /// Initializes a new instance of the [PdfListBoxField] class with the specific page and name. - PdfListBoxField( - PdfPage page, - String name, - Rect bounds, { - List? items, - bool multiSelect = false, - List? selectedIndexes, - List? selectedValues, - PdfFont? font, - PdfTextAlignment alignment = PdfTextAlignment.left, - PdfColor? borderColor, - PdfColor? foreColor, - PdfColor? backColor, - int? borderWidth, - PdfHighlightMode highlightMode = PdfHighlightMode.invert, - PdfBorderStyle borderStyle = PdfBorderStyle.solid, - String? tooltip, - }) { - _helper = PdfListBoxFieldHelper(this); - _helper.initializeInternal( - page, - name, - bounds, - font: font, - alignment: alignment, - items: items, - borderColor: borderColor, - foreColor: foreColor, - backColor: backColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - ); - this.multiSelect = multiSelect; - if (selectedIndexes != null) { - this.selectedIndexes = selectedIndexes; - } - if (selectedValues != null) { - this.selectedValues = selectedValues; - } - } - - /// Initializes a new instance of the [PdfListBoxField] class. - PdfListBoxField._load(PdfDictionary dictionary, PdfCrossTable crossTable) { - _helper = PdfListBoxFieldHelper(this); - _helper.loadListField(dictionary, crossTable); - } - - //Fields - bool _multiSelect = false; - late PdfListBoxFieldHelper _helper; - - //Properties - /// Gets or sets a value indicating whether the field is multi-selectable. - /// - /// The default value is false. - bool get multiSelect { - if (_helper.isLoadedField) { - _multiSelect = - _helper.isFlagPresent(FieldFlags.multiSelect) || - _helper.flags.contains(FieldFlags.multiSelect); - } - return _multiSelect; - } - - set multiSelect(bool value) { - if (_multiSelect != value || _helper.isLoadedField) { - _multiSelect = value; - _multiSelect - ? _helper.flags.add(FieldFlags.multiSelect) - : _helper.isLoadedField - ? _helper.removeFlag(FieldFlags.multiSelect) - : _helper.flags.remove(FieldFlags.multiSelect); - } - } - - /// Gets or sets selected indexes in the list. - /// - /// Multiple indexes will be selected only when multiSelect property is enabled, - /// Otherwise only the first index in the collection will be selected. - List get selectedIndexes => _helper.selectedIndexes; - set selectedIndexes(List value) { - _helper.selectedIndexes = - multiSelect || value.isEmpty ? value : [value[0]]; - } - - /// Gets or sets the selected values in the list. - /// - /// Multiple values will be selected only when multiSelect property is enabled, - /// Otherwise only the first value in the collection will be selected. - List get selectedValues => _helper.selectedValues; - set selectedValues(List value) { - _helper.selectedValues = - multiSelect || value.isEmpty ? value : [value[0]]; - } - - /// Gets the selected items in the list. - PdfListFieldItemCollection get selectedItems => _helper.selectedItems; -} - -/// [PdfListBoxField] helper -class PdfListBoxFieldHelper extends PdfListFieldHelper { - /// internal constructor - PdfListBoxFieldHelper(this.listBoxField) : super(listBoxField); - - /// internal field - PdfListBoxField listBoxField; - - /// internal method - static PdfListBoxFieldHelper getHelper(PdfListBoxField listBoxField) { - return listBoxField._helper; - } - - /// internal method - @override - void drawAppearance(PdfTemplate template) { - super.drawAppearance(template); - final PaintParams params = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - listBoxField.bounds.width, - listBoxField.bounds.height, - ), - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: listBoxField.borderStyle, - borderWidth: listBoxField.borderWidth, - shadowBrush: shadowBrush, - ); - PdfFont font; - if (listBoxField.font == null) { - if (PdfPageHelper.getHelper(listBoxField.page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(listBoxField.page!).document!, - ).conformanceLevel != - PdfConformanceLevel.none) { - throw ArgumentError( - 'Font data is not embedded to the conformance PDF.', - ); - } - font = PdfStandardFont( - PdfFontFamily.timesRoman, - getFontHeight(PdfFontFamily.timesRoman), - ); - } else { - font = listBoxField.font!; - } - FieldPainter().drawListBox( - template.graphics!, - params, - listBoxField.items, - selectedIndexes, - font, - format, - ); - } - - /// internal method - @override - void draw() { - super.draw(); - if (!isLoadedField) { - if (PdfAnnotationHelper.getHelper(widget!).appearance != null) { - listBoxField.page!.graphics.drawPdfTemplate( - widget!.appearance.normal, - listBoxField.bounds.topLeft, - ); - } else { - final Rect rect = Rect.fromLTWH( - 0, - 0, - listBoxField.bounds.width, - listBoxField.bounds.height, - ); - final PdfFont font = - listBoxField.font ?? - PdfStandardFont( - PdfFontFamily.helvetica, - getFontHeight(PdfFontFamily.helvetica), - ); - final PaintParams parameters = PaintParams( - bounds: rect, - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: listBoxField.borderStyle, - borderWidth: listBoxField.borderWidth, - shadowBrush: shadowBrush, - ); - final PdfTemplate template = PdfTemplate(rect.width, rect.height); - FieldPainter().drawListBox( - template.graphics!, - parameters, - listBoxField.items, - listBoxField.selectedIndexes, - font, - format, - ); - listBoxField.page!.graphics.drawPdfTemplate( - template, - listBoxField.bounds.topLeft, - rect.size, - ); - } - } else { - final PdfTemplate template = PdfTemplate( - listBoxField.bounds.width, - listBoxField.bounds.height, - ); - _drawListBox(template.graphics!); - listBoxField.page!.graphics.drawPdfTemplate( - template, - listBoxField.bounds.topLeft, - ); - } - } - - /// internal method - @override - void beginSave() { - super.beginSave(); - _applyAppearance(getWidgetAnnotation(dictionary!, crossTable)); - } - - void _applyAppearance(PdfDictionary widget) { - if (widget.containsKey(PdfDictionaryProperties.ap) && - !PdfFormHelper.getHelper(listBoxField.form!).needAppearances!) { - final IPdfPrimitive? appearance = crossTable!.getObject( - widget[PdfDictionaryProperties.ap], - ); - if (appearance != null && - appearance is PdfDictionary && - appearance.containsKey(PdfDictionaryProperties.n)) { - final PdfTemplate template = PdfTemplate( - listBoxField.bounds.width, - listBoxField.bounds.height, - ); - PdfTemplateHelper.getHelper(template).writeTransformation = false; - beginMarkupSequence( - PdfGraphicsHelper.getHelper(template.graphics!).streamWriter!.stream!, - ); - PdfGraphicsHelper.getHelper(template.graphics!).initializeCoordinates(); - _drawListBox(template.graphics!); - endMarkupSequence( - PdfGraphicsHelper.getHelper(template.graphics!).streamWriter!.stream!, - ); - appearance.remove(PdfDictionaryProperties.n); - appearance.setProperty( - PdfDictionaryProperties.n, - PdfReferenceHolder(template), - ); - widget.setProperty(PdfDictionaryProperties.ap, appearance); - } - } else if (PdfFormHelper.getHelper( - listBoxField.form!, - ).setAppearanceDictionary && - !PdfFormHelper.getHelper(listBoxField.form!).needAppearances!) { - final PdfDictionary dic = PdfDictionary(); - final PdfTemplate template = PdfTemplate( - listBoxField.bounds.width, - listBoxField.bounds.height, - ); - drawAppearance(template); - dic.setProperty(PdfDictionaryProperties.n, PdfReferenceHolder(template)); - widget.setProperty(PdfDictionaryProperties.ap, dic); - } - } - - void _drawListBox(PdfGraphics graphics) { - final GraphicsProperties gp = GraphicsProperties(listBoxField); - gp.bounds = Rect.fromLTWH( - 0, - 0, - listBoxField.bounds.width, - listBoxField.bounds.height, - ); - final PaintParams prms = PaintParams( - bounds: gp.bounds, - backBrush: gp.backBrush, - foreBrush: gp.foreBrush, - borderPen: gp.borderPen, - style: gp.style, - borderWidth: gp.borderWidth, - shadowBrush: gp.shadowBrush, - ); - if (!PdfFormHelper.getHelper(listBoxField.form!).setAppearanceDictionary && - !PdfFormHelper.getHelper(listBoxField.form!).flatten) { - prms.backBrush = null; - } - FieldPainter().drawListBox( - graphics, - prms, - listBoxField.items, - selectedIndexes, - gp.font!, - gp.stringFormat, - ); - } - - /// internal method - @override - double getFontHeight(PdfFontFamily family) { - double s = 0; - if (listBoxField.items.count > 0) { - final PdfFont font = PdfStandardFont(family, 12); - double max = font.measureString(listBoxField.items[0].text).width; - for (int i = 1; i < listBoxField.items.count; ++i) { - final double temp = - font.measureString(listBoxField.items[i].text).width; - max = (max > temp) ? max : temp; - } - s = (12 * (listBoxField.bounds.size.width - 4 * borderWidth)) / max; - s = (s > 12) ? 12 : s; - } - return s; - } - - /// internal method - static PdfListBoxField loadListBox( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfListBoxField._load(dictionary, crossTable); - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/pdf_annotation.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'enum.dart'; +import 'pdf_field.dart'; +import 'pdf_field_painter.dart'; +import 'pdf_form.dart'; +import 'pdf_list_field.dart'; +import 'pdf_list_field_item.dart'; +import 'pdf_list_field_item_collection.dart'; + +/// Represents list box field of the PDF form. +class PdfListBoxField extends PdfListField { + //Constructor + /// Initializes a new instance of the [PdfListBoxField] class with the specific page and name. + PdfListBoxField( + PdfPage page, + String name, + Rect bounds, { + List? items, + bool multiSelect = false, + List? selectedIndexes, + List? selectedValues, + PdfFont? font, + PdfTextAlignment alignment = PdfTextAlignment.left, + PdfColor? borderColor, + PdfColor? foreColor, + PdfColor? backColor, + int? borderWidth, + PdfHighlightMode highlightMode = PdfHighlightMode.invert, + PdfBorderStyle borderStyle = PdfBorderStyle.solid, + String? tooltip, + }) { + _helper = PdfListBoxFieldHelper(this); + _helper.initializeInternal( + page, + name, + bounds, + font: font, + alignment: alignment, + items: items, + borderColor: borderColor, + foreColor: foreColor, + backColor: backColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + ); + this.multiSelect = multiSelect; + if (selectedIndexes != null) { + this.selectedIndexes = selectedIndexes; + } + if (selectedValues != null) { + this.selectedValues = selectedValues; + } + } + + /// Initializes a new instance of the [PdfListBoxField] class. + PdfListBoxField._load(PdfDictionary dictionary, PdfCrossTable crossTable) { + _helper = PdfListBoxFieldHelper(this); + _helper.loadListField(dictionary, crossTable); + } + + //Fields + bool _multiSelect = false; + late PdfListBoxFieldHelper _helper; + + //Properties + /// Gets or sets a value indicating whether the field is multi-selectable. + /// + /// The default value is false. + bool get multiSelect { + if (_helper.isLoadedField) { + _multiSelect = + _helper.isFlagPresent(FieldFlags.multiSelect) || + _helper.flags.contains(FieldFlags.multiSelect); + } + return _multiSelect; + } + + set multiSelect(bool value) { + if (_multiSelect != value || _helper.isLoadedField) { + _multiSelect = value; + _multiSelect + ? _helper.flags.add(FieldFlags.multiSelect) + : _helper.isLoadedField + ? _helper.removeFlag(FieldFlags.multiSelect) + : _helper.flags.remove(FieldFlags.multiSelect); + } + } + + /// Gets or sets selected indexes in the list. + /// + /// Multiple indexes will be selected only when multiSelect property is enabled, + /// Otherwise only the first index in the collection will be selected. + List get selectedIndexes => _helper.selectedIndexes; + set selectedIndexes(List value) { + _helper.selectedIndexes = + multiSelect || value.isEmpty ? value : [value[0]]; + } + + /// Gets or sets the selected values in the list. + /// + /// Multiple values will be selected only when multiSelect property is enabled, + /// Otherwise only the first value in the collection will be selected. + List get selectedValues => _helper.selectedValues; + set selectedValues(List value) { + _helper.selectedValues = + multiSelect || value.isEmpty ? value : [value[0]]; + } + + /// Gets the selected items in the list. + PdfListFieldItemCollection get selectedItems => _helper.selectedItems; +} + +/// [PdfListBoxField] helper +class PdfListBoxFieldHelper extends PdfListFieldHelper { + /// internal constructor + PdfListBoxFieldHelper(this.listBoxField) : super(listBoxField); + + /// internal field + PdfListBoxField listBoxField; + + /// internal method + static PdfListBoxFieldHelper getHelper(PdfListBoxField listBoxField) { + return listBoxField._helper; + } + + /// internal method + @override + void drawAppearance(PdfTemplate template) { + super.drawAppearance(template); + final PaintParams params = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + listBoxField.bounds.width, + listBoxField.bounds.height, + ), + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: listBoxField.borderStyle, + borderWidth: listBoxField.borderWidth, + shadowBrush: shadowBrush, + ); + PdfFont font; + if (listBoxField.font == null) { + if (PdfPageHelper.getHelper(listBoxField.page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(listBoxField.page!).document!, + ).conformanceLevel != + PdfConformanceLevel.none) { + throw ArgumentError( + 'Font data is not embedded to the conformance PDF.', + ); + } + font = PdfStandardFont( + PdfFontFamily.timesRoman, + getFontHeight(PdfFontFamily.timesRoman), + ); + } else { + font = listBoxField.font!; + } + FieldPainter().drawListBox( + template.graphics!, + params, + listBoxField.items, + selectedIndexes, + font, + format, + ); + } + + /// internal method + @override + void draw() { + super.draw(); + if (!isLoadedField) { + if (PdfAnnotationHelper.getHelper(widget!).appearance != null) { + listBoxField.page!.graphics.drawPdfTemplate( + widget!.appearance.normal, + listBoxField.bounds.topLeft, + ); + } else { + final Rect rect = Rect.fromLTWH( + 0, + 0, + listBoxField.bounds.width, + listBoxField.bounds.height, + ); + final PdfFont font = + listBoxField.font ?? + PdfStandardFont( + PdfFontFamily.helvetica, + getFontHeight(PdfFontFamily.helvetica), + ); + final PaintParams parameters = PaintParams( + bounds: rect, + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: listBoxField.borderStyle, + borderWidth: listBoxField.borderWidth, + shadowBrush: shadowBrush, + ); + final PdfTemplate template = PdfTemplate(rect.width, rect.height); + FieldPainter().drawListBox( + template.graphics!, + parameters, + listBoxField.items, + listBoxField.selectedIndexes, + font, + format, + ); + listBoxField.page!.graphics.drawPdfTemplate( + template, + listBoxField.bounds.topLeft, + rect.size, + ); + } + } else { + final PdfTemplate template = PdfTemplate( + listBoxField.bounds.width, + listBoxField.bounds.height, + ); + _drawListBox(template.graphics!); + listBoxField.page!.graphics.drawPdfTemplate( + template, + listBoxField.bounds.topLeft, + ); + } + } + + /// internal method + @override + void beginSave() { + super.beginSave(); + _applyAppearance(getWidgetAnnotation(dictionary!, crossTable)); + } + + void _applyAppearance(PdfDictionary widget) { + if (widget.containsKey(PdfDictionaryProperties.ap) && + !PdfFormHelper.getHelper(listBoxField.form!).needAppearances!) { + final IPdfPrimitive? appearance = crossTable!.getObject( + widget[PdfDictionaryProperties.ap], + ); + if (appearance != null && + appearance is PdfDictionary && + appearance.containsKey(PdfDictionaryProperties.n)) { + final PdfTemplate template = PdfTemplate( + listBoxField.bounds.width, + listBoxField.bounds.height, + ); + PdfTemplateHelper.getHelper(template).writeTransformation = false; + beginMarkupSequence( + PdfGraphicsHelper.getHelper(template.graphics!).streamWriter!.stream!, + ); + PdfGraphicsHelper.getHelper(template.graphics!).initializeCoordinates(); + _drawListBox(template.graphics!); + endMarkupSequence( + PdfGraphicsHelper.getHelper(template.graphics!).streamWriter!.stream!, + ); + appearance.remove(PdfDictionaryProperties.n); + appearance.setProperty( + PdfDictionaryProperties.n, + PdfReferenceHolder(template), + ); + widget.setProperty(PdfDictionaryProperties.ap, appearance); + } + } else if (PdfFormHelper.getHelper( + listBoxField.form!, + ).setAppearanceDictionary && + !PdfFormHelper.getHelper(listBoxField.form!).needAppearances!) { + final PdfDictionary dic = PdfDictionary(); + final PdfTemplate template = PdfTemplate( + listBoxField.bounds.width, + listBoxField.bounds.height, + ); + drawAppearance(template); + dic.setProperty(PdfDictionaryProperties.n, PdfReferenceHolder(template)); + widget.setProperty(PdfDictionaryProperties.ap, dic); + } + } + + void _drawListBox(PdfGraphics graphics) { + final GraphicsProperties gp = GraphicsProperties(listBoxField); + gp.bounds = Rect.fromLTWH( + 0, + 0, + listBoxField.bounds.width, + listBoxField.bounds.height, + ); + final PaintParams prms = PaintParams( + bounds: gp.bounds, + backBrush: gp.backBrush, + foreBrush: gp.foreBrush, + borderPen: gp.borderPen, + style: gp.style, + borderWidth: gp.borderWidth, + shadowBrush: gp.shadowBrush, + ); + if (!PdfFormHelper.getHelper(listBoxField.form!).setAppearanceDictionary && + !PdfFormHelper.getHelper(listBoxField.form!).flatten) { + prms.backBrush = null; + } + FieldPainter().drawListBox( + graphics, + prms, + listBoxField.items, + selectedIndexes, + gp.font!, + gp.stringFormat, + ); + } + + /// internal method + @override + double getFontHeight(PdfFontFamily family) { + double s = 0; + if (listBoxField.items.count > 0) { + final PdfFont font = PdfStandardFont(family, 12); + double max = font.measureString(listBoxField.items[0].text).width; + for (int i = 1; i < listBoxField.items.count; ++i) { + final double temp = + font.measureString(listBoxField.items[i].text).width; + max = (max > temp) ? max : temp; + } + s = (12 * (listBoxField.bounds.size.width - 4 * borderWidth)) / max; + s = (s > 12) ? 12 : s; + } + return s; + } + + /// internal method + static PdfListBoxField loadListBox( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfListBoxField._load(dictionary, crossTable); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field.dart index 657f6ca76..8387bb52b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field.dart @@ -1,492 +1,492 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../graphics/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/pdf_color.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_combo_box_field.dart'; -import 'pdf_field.dart'; -import 'pdf_list_box_field.dart'; -import 'pdf_list_field_item.dart'; -import 'pdf_list_field_item_collection.dart'; - -/// Represents base class for form's list fields. -abstract class PdfListField extends PdfField { - /// internal constructor - void _internal( - PdfPage? page, - String name, - Rect bounds, { - List? items, - PdfFont? font, - PdfTextAlignment? alignment, - PdfColor? borderColor, - PdfColor? foreColor, - PdfColor? backColor, - int? borderWidth, - PdfHighlightMode? highlightMode, - PdfBorderStyle? borderStyle, - String? tooltip, - PdfListFieldHelper? helper, - }) { - _helper = helper!; - _helper.internal( - page, - name, - bounds, - font: font, - alignment: alignment, - borderColor: borderColor, - foreColor: foreColor, - backColor: backColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - ); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.ft, - PdfName(PdfDictionaryProperties.ch), - ); - if (items != null && items.isNotEmpty) { - items.toList().forEach( - (PdfListFieldItem element) => this.items.add(element), - ); - } - } - - /// internal constructor - void _load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - PdfListFieldHelper helper, - ) { - _helper = helper; - _helper.load(dictionary, crossTable); - } - - //Fields - late PdfListFieldHelper _helper; - - //Properties - /// Gets the list field items. - PdfListFieldItemCollection get items { - if (_helper._items == null) { - if (!_helper.isLoadedField) { - _helper._items = PdfListFieldItemCollectionHelper.itemCollection(); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.opt, - _helper._items, - ); - } else { - _helper._items = _getListItemCollection(); - } - } - return _helper._items!; - } - - /// Gets or sets the font. - PdfFont? get font => _helper.font; - set font(PdfFont? value) { - if (value != null) { - _helper.font = value; - } - } - - /// Gets or sets the text alignment. - /// - /// The default alignment is left. - PdfTextAlignment get textAlignment => _helper.textAlignment; - set textAlignment(PdfTextAlignment value) { - _helper.textAlignment = value; - } - - /// Gets or sets the color of the border. - /// - /// The default color is black. - PdfColor get borderColor => _helper.borderColor; - set borderColor(PdfColor value) { - _helper.borderColor = value; - } - - /// Gets or sets the color of the background. - /// - /// The default color is empty. - PdfColor get backColor => _helper.backColor; - set backColor(PdfColor value) { - _helper.backColor = value; - } - - /// Gets or sets the color of the text. - /// - /// The default color is black. - PdfColor get foreColor => _helper.foreColor; - set foreColor(PdfColor value) { - _helper.foreColor = value; - } - - /// Gets or sets the width of the border. - /// - /// The default value is 1. - int get borderWidth => _helper.borderWidth; - set borderWidth(int value) { - _helper.borderWidth = value; - } - - /// Gets or sets the highlighting mode. - /// - /// The default mode is invert. - PdfHighlightMode get highlightMode => _helper.highlightMode; - set highlightMode(PdfHighlightMode value) => _helper.highlightMode = value; - - /// Gets or sets the border style. - /// - /// The default style is solid. - PdfBorderStyle get borderStyle => _helper.borderStyle; - set borderStyle(PdfBorderStyle value) => _helper.borderStyle = value; - - //Implementations - - // Gets the list item. - PdfListFieldItemCollection _getListItemCollection() { - final PdfListFieldItemCollection items = - PdfListFieldItemCollectionHelper.itemCollection(this); - final IPdfPrimitive? array = PdfFieldHelper.getValue( - _helper.dictionary!, - _helper.crossTable, - PdfDictionaryProperties.opt, - true, - ); - if (array != null && array is PdfArray) { - for (int i = 0; i < array.count; i++) { - final IPdfPrimitive? primitive = _helper.crossTable!.getObject( - array[i], - ); - PdfListFieldItem item; - if (primitive is PdfString) { - final PdfString str = primitive; - item = PdfListFieldItemHelper.load( - str.value, - null, - this, - _helper.crossTable, - ); - } else { - final PdfArray arr = primitive! as PdfArray; - final PdfString value = - _helper.crossTable!.getObject(arr[0])! as PdfString; - final PdfString text = - _helper.crossTable!.getObject(arr[1])! as PdfString; - item = PdfListFieldItemHelper.load( - text.value, - value.value, - this, - _helper.crossTable, - ); - } - PdfListFieldItemCollectionHelper.getHelper(items).addItem(item); - } - } - return items; - } -} - -/// [PdfListField] helper -class PdfListFieldHelper extends PdfFieldHelper { - /// internal costructor - PdfListFieldHelper(this.listField) : super(listField); - - /// internal field - PdfListField listField; - - /// internal field - List selectedIndex = []; - PdfListFieldItemCollection? _items; - - /// internal method - void initializeInternal( - PdfPage? page, - String name, - Rect bounds, { - List? items, - PdfFont? font, - PdfTextAlignment? alignment, - PdfColor? borderColor, - PdfColor? foreColor, - PdfColor? backColor, - int? borderWidth, - PdfHighlightMode? highlightMode, - PdfBorderStyle? borderStyle, - String? tooltip, - }) { - listField._internal( - page, - name, - bounds, - items: items, - font: font, - alignment: alignment, - borderColor: borderColor, - foreColor: foreColor, - backColor: backColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - helper: this, - ); - } - - /// internal method - void loadListField(PdfDictionary dictionary, PdfCrossTable crossTable) { - listField._load(dictionary, crossTable, this); - } - - /// internal method - static PdfListFieldHelper getHelper(PdfListField listField) { - return listField._helper; - } - - /// internal method - List get selectedIndexes => - isLoadedField ? _obtainSelectedIndex() : selectedIndex; - set selectedIndexes(List value) { - for (final int element in value) { - if (element < 0 || element >= listField.items.count) { - throw RangeError('index'); - } - } - if (isLoadedField) { - _assignSelectedIndex(value); - } else { - if (selectedIndex != value) { - selectedIndex = value; - dictionary!.setProperty( - PdfDictionaryProperties.i, - PdfArray(selectedIndex), - ); - } - } - } - - /// internal method - List get selectedValues { - if (isLoadedField) { - return _obtainSelectedValue(); - } else { - final List values = []; - for (final int index in selectedIndex) { - values.add(_items![index].value); - } - return values; - } - } - - set selectedValues(List value) { - if (isLoadedField) { - bool isText = false; - if (listField.items[0].value.isEmpty) { - isText = true; - } - _assignSelectedValue(value, isText); - } else { - for (int i = 0; i < _items!.count; i++) { - if (value.contains(_items![i].value)) { - selectedIndex.add(i); - if (selectedIndex.contains(-1)) { - selectedIndex.remove(-1); - } - break; - } - } - dictionary!.setProperty( - PdfDictionaryProperties.i, - PdfArray(selectedIndex), - ); - } - } - - /// internal method - PdfListFieldItemCollection get selectedItems { - if (selectedIndex == [-1]) { - throw ArgumentError('No item is selected.'); - } - final PdfListFieldItemCollection item = - PdfListFieldItemCollectionHelper.itemCollection( - isLoadedField ? listField : null, - ); - for (final int index in selectedIndexes) { - if (index > -1 && - listField.items.count > 0 && - listField.items.count > index) { - PdfListFieldItemCollectionHelper.getHelper( - item, - ).addItem(listField.items[index]); - } - } - return item; - } - - List _obtainSelectedIndex() { - final List selectedIndex = []; - if (dictionary!.containsKey(PdfDictionaryProperties.i)) { - final IPdfPrimitive? array = crossTable!.getObject( - dictionary![PdfDictionaryProperties.i], - ); - if (array != null && array is PdfArray) { - if (array.count > 0) { - for (int i = 0; i < array.count; i++) { - final IPdfPrimitive? number = crossTable!.getObject(array[i]); - if (number != null && number is PdfNumber) { - selectedIndex.add(number.value!.toInt()); - } - } - } - } else { - final IPdfPrimitive? number = crossTable!.getObject( - dictionary![PdfDictionaryProperties.i], - ); - if (number != null && number is PdfNumber) { - selectedIndex.add(number.value!.toInt()); - } - } - } - return selectedIndex; - } - - //Gets selected value. - List _obtainSelectedValue() { - final List value = []; - if (dictionary!.containsKey(PdfDictionaryProperties.v)) { - final IPdfPrimitive? primitive = crossTable!.getObject( - dictionary![PdfDictionaryProperties.v], - ); - if (primitive is PdfString) { - value.add(primitive.value!); - } else { - final PdfArray array = primitive! as PdfArray; - for (int i = 0; i < array.count; i++) { - final PdfString stringValue = array[i]! as PdfString; - value.add(stringValue.value!); - } - } - } else { - for (final int index in selectedIndexes) { - if (index > -1) { - value.add(listField.items[index].value); - } - } - } - return value; - } - - void _assignSelectedIndex(List value) { - // ignore: avoid_function_literals_in_foreach_calls - value.forEach((int element) { - if (element >= listField.items.count) { - throw RangeError('selectedIndex'); - } - }); - if (listField.readOnly == false) { - value.sort(); - dictionary!.setProperty(PdfDictionaryProperties.i, PdfArray(value)); - List selectedValues = []; - bool isText = false; - // ignore: avoid_function_literals_in_foreach_calls - value.forEach((int element) { - if (element >= 0) { - selectedValues.add(listField.items[element].value); - } - }); - if (listField.items[0].value.isEmpty) { - selectedValues = []; - isText = true; - // ignore: avoid_function_literals_in_foreach_calls - value.forEach((int element) { - selectedValues.add(listField.items[element].text); - }); - } - _assignSelectedValue(selectedValues, isText); - changed = true; - } - } - - void _assignSelectedValue(List values, bool isText) { - final List selectedIndexes = []; - final PdfListFieldItemCollection collection = listField.items; - if (listField.readOnly == false) { - // ignore: avoid_function_literals_in_foreach_calls - values.forEach((String? element) { - bool isvaluePresent = false; - for (int i = 0; i < collection.count; i++) { - if ((isText ? collection[i].text : collection[i].value) == element) { - isvaluePresent = true; - selectedIndexes.add(i); - } - } - if (!isvaluePresent && - (listField is PdfComboBoxField) && - !(listField as PdfComboBoxField).editable) { - throw RangeError('index'); - } - }); - if (listField is PdfListBoxField && values.length > 1) { - final PdfListBoxField tempField = listField as PdfListBoxField; - if (!tempField.multiSelect) { - selectedIndexes.removeRange(1, selectedIndexes.length - 1); - values = [collection[selectedIndexes[0]].value]; - } - } - if (selectedIndexes.isNotEmpty) { - selectedIndexes.sort(); - dictionary!.setProperty( - PdfDictionaryProperties.i, - PdfArray(selectedIndexes), - ); - } else { - dictionary!.remove(PdfDictionaryProperties.i); - } - } - if (dictionary!.containsKey(PdfDictionaryProperties.v)) { - final IPdfPrimitive? primitive = crossTable!.getObject( - dictionary![PdfDictionaryProperties.v], - ); - if ((primitive == null) || (primitive is PdfString)) { - if (listField is PdfListBoxField) { - final PdfArray array = PdfArray(); - for (final String? selectedValue in values) { - array.add(PdfString(selectedValue!)); - } - dictionary!.setProperty(PdfDictionaryProperties.v, array); - } else { - dictionary!.setString(PdfDictionaryProperties.v, values[0]); - } - } else { - final PdfArray array = primitive as PdfArray; - array.clear(); - for (final String? selectedValue in values) { - array.add(PdfString(selectedValue!)); - } - dictionary!.setProperty(PdfDictionaryProperties.v, array); - } - } else if (listField is PdfComboBoxField) { - dictionary!.setString(PdfDictionaryProperties.v, values[0]); - } else { - final PdfArray array = PdfArray(); - for (final String? selectedValue in values) { - array.add(PdfString(selectedValue!)); - } - dictionary!.setProperty(PdfDictionaryProperties.v, array); - } - changed = true; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../graphics/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/pdf_color.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_combo_box_field.dart'; +import 'pdf_field.dart'; +import 'pdf_list_box_field.dart'; +import 'pdf_list_field_item.dart'; +import 'pdf_list_field_item_collection.dart'; + +/// Represents base class for form's list fields. +abstract class PdfListField extends PdfField { + /// internal constructor + void _internal( + PdfPage? page, + String name, + Rect bounds, { + List? items, + PdfFont? font, + PdfTextAlignment? alignment, + PdfColor? borderColor, + PdfColor? foreColor, + PdfColor? backColor, + int? borderWidth, + PdfHighlightMode? highlightMode, + PdfBorderStyle? borderStyle, + String? tooltip, + PdfListFieldHelper? helper, + }) { + _helper = helper!; + _helper.internal( + page, + name, + bounds, + font: font, + alignment: alignment, + borderColor: borderColor, + foreColor: foreColor, + backColor: backColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + ); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.ft, + PdfName(PdfDictionaryProperties.ch), + ); + if (items != null && items.isNotEmpty) { + items.toList().forEach( + (PdfListFieldItem element) => this.items.add(element), + ); + } + } + + /// internal constructor + void _load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + PdfListFieldHelper helper, + ) { + _helper = helper; + _helper.load(dictionary, crossTable); + } + + //Fields + late PdfListFieldHelper _helper; + + //Properties + /// Gets the list field items. + PdfListFieldItemCollection get items { + if (_helper._items == null) { + if (!_helper.isLoadedField) { + _helper._items = PdfListFieldItemCollectionHelper.itemCollection(); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.opt, + _helper._items, + ); + } else { + _helper._items = _getListItemCollection(); + } + } + return _helper._items!; + } + + /// Gets or sets the font. + PdfFont? get font => _helper.font; + set font(PdfFont? value) { + if (value != null) { + _helper.font = value; + } + } + + /// Gets or sets the text alignment. + /// + /// The default alignment is left. + PdfTextAlignment get textAlignment => _helper.textAlignment; + set textAlignment(PdfTextAlignment value) { + _helper.textAlignment = value; + } + + /// Gets or sets the color of the border. + /// + /// The default color is black. + PdfColor get borderColor => _helper.borderColor; + set borderColor(PdfColor value) { + _helper.borderColor = value; + } + + /// Gets or sets the color of the background. + /// + /// The default color is empty. + PdfColor get backColor => _helper.backColor; + set backColor(PdfColor value) { + _helper.backColor = value; + } + + /// Gets or sets the color of the text. + /// + /// The default color is black. + PdfColor get foreColor => _helper.foreColor; + set foreColor(PdfColor value) { + _helper.foreColor = value; + } + + /// Gets or sets the width of the border. + /// + /// The default value is 1. + int get borderWidth => _helper.borderWidth; + set borderWidth(int value) { + _helper.borderWidth = value; + } + + /// Gets or sets the highlighting mode. + /// + /// The default mode is invert. + PdfHighlightMode get highlightMode => _helper.highlightMode; + set highlightMode(PdfHighlightMode value) => _helper.highlightMode = value; + + /// Gets or sets the border style. + /// + /// The default style is solid. + PdfBorderStyle get borderStyle => _helper.borderStyle; + set borderStyle(PdfBorderStyle value) => _helper.borderStyle = value; + + //Implementations + + // Gets the list item. + PdfListFieldItemCollection _getListItemCollection() { + final PdfListFieldItemCollection items = + PdfListFieldItemCollectionHelper.itemCollection(this); + final IPdfPrimitive? array = PdfFieldHelper.getValue( + _helper.dictionary!, + _helper.crossTable, + PdfDictionaryProperties.opt, + true, + ); + if (array != null && array is PdfArray) { + for (int i = 0; i < array.count; i++) { + final IPdfPrimitive? primitive = _helper.crossTable!.getObject( + array[i], + ); + PdfListFieldItem item; + if (primitive is PdfString) { + final PdfString str = primitive; + item = PdfListFieldItemHelper.load( + str.value, + null, + this, + _helper.crossTable, + ); + } else { + final PdfArray arr = primitive! as PdfArray; + final PdfString value = + _helper.crossTable!.getObject(arr[0])! as PdfString; + final PdfString text = + _helper.crossTable!.getObject(arr[1])! as PdfString; + item = PdfListFieldItemHelper.load( + text.value, + value.value, + this, + _helper.crossTable, + ); + } + PdfListFieldItemCollectionHelper.getHelper(items).addItem(item); + } + } + return items; + } +} + +/// [PdfListField] helper +class PdfListFieldHelper extends PdfFieldHelper { + /// internal costructor + PdfListFieldHelper(this.listField) : super(listField); + + /// internal field + PdfListField listField; + + /// internal field + List selectedIndex = []; + PdfListFieldItemCollection? _items; + + /// internal method + void initializeInternal( + PdfPage? page, + String name, + Rect bounds, { + List? items, + PdfFont? font, + PdfTextAlignment? alignment, + PdfColor? borderColor, + PdfColor? foreColor, + PdfColor? backColor, + int? borderWidth, + PdfHighlightMode? highlightMode, + PdfBorderStyle? borderStyle, + String? tooltip, + }) { + listField._internal( + page, + name, + bounds, + items: items, + font: font, + alignment: alignment, + borderColor: borderColor, + foreColor: foreColor, + backColor: backColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + helper: this, + ); + } + + /// internal method + void loadListField(PdfDictionary dictionary, PdfCrossTable crossTable) { + listField._load(dictionary, crossTable, this); + } + + /// internal method + static PdfListFieldHelper getHelper(PdfListField listField) { + return listField._helper; + } + + /// internal method + List get selectedIndexes => + isLoadedField ? _obtainSelectedIndex() : selectedIndex; + set selectedIndexes(List value) { + for (final int element in value) { + if (element < 0 || element >= listField.items.count) { + throw RangeError('index'); + } + } + if (isLoadedField) { + _assignSelectedIndex(value); + } else { + if (selectedIndex != value) { + selectedIndex = value; + dictionary!.setProperty( + PdfDictionaryProperties.i, + PdfArray(selectedIndex), + ); + } + } + } + + /// internal method + List get selectedValues { + if (isLoadedField) { + return _obtainSelectedValue(); + } else { + final List values = []; + for (final int index in selectedIndex) { + values.add(_items![index].value); + } + return values; + } + } + + set selectedValues(List value) { + if (isLoadedField) { + bool isText = false; + if (listField.items[0].value.isEmpty) { + isText = true; + } + _assignSelectedValue(value, isText); + } else { + for (int i = 0; i < _items!.count; i++) { + if (value.contains(_items![i].value)) { + selectedIndex.add(i); + if (selectedIndex.contains(-1)) { + selectedIndex.remove(-1); + } + break; + } + } + dictionary!.setProperty( + PdfDictionaryProperties.i, + PdfArray(selectedIndex), + ); + } + } + + /// internal method + PdfListFieldItemCollection get selectedItems { + if (selectedIndex == [-1]) { + throw ArgumentError('No item is selected.'); + } + final PdfListFieldItemCollection item = + PdfListFieldItemCollectionHelper.itemCollection( + isLoadedField ? listField : null, + ); + for (final int index in selectedIndexes) { + if (index > -1 && + listField.items.count > 0 && + listField.items.count > index) { + PdfListFieldItemCollectionHelper.getHelper( + item, + ).addItem(listField.items[index]); + } + } + return item; + } + + List _obtainSelectedIndex() { + final List selectedIndex = []; + if (dictionary!.containsKey(PdfDictionaryProperties.i)) { + final IPdfPrimitive? array = crossTable!.getObject( + dictionary![PdfDictionaryProperties.i], + ); + if (array != null && array is PdfArray) { + if (array.count > 0) { + for (int i = 0; i < array.count; i++) { + final IPdfPrimitive? number = crossTable!.getObject(array[i]); + if (number != null && number is PdfNumber) { + selectedIndex.add(number.value!.toInt()); + } + } + } + } else { + final IPdfPrimitive? number = crossTable!.getObject( + dictionary![PdfDictionaryProperties.i], + ); + if (number != null && number is PdfNumber) { + selectedIndex.add(number.value!.toInt()); + } + } + } + return selectedIndex; + } + + //Gets selected value. + List _obtainSelectedValue() { + final List value = []; + if (dictionary!.containsKey(PdfDictionaryProperties.v)) { + final IPdfPrimitive? primitive = crossTable!.getObject( + dictionary![PdfDictionaryProperties.v], + ); + if (primitive is PdfString) { + value.add(primitive.value!); + } else { + final PdfArray array = primitive! as PdfArray; + for (int i = 0; i < array.count; i++) { + final PdfString stringValue = array[i]! as PdfString; + value.add(stringValue.value!); + } + } + } else { + for (final int index in selectedIndexes) { + if (index > -1) { + value.add(listField.items[index].value); + } + } + } + return value; + } + + void _assignSelectedIndex(List value) { + // ignore: avoid_function_literals_in_foreach_calls + value.forEach((int element) { + if (element >= listField.items.count) { + throw RangeError('selectedIndex'); + } + }); + if (listField.readOnly == false) { + value.sort(); + dictionary!.setProperty(PdfDictionaryProperties.i, PdfArray(value)); + List selectedValues = []; + bool isText = false; + // ignore: avoid_function_literals_in_foreach_calls + value.forEach((int element) { + if (element >= 0) { + selectedValues.add(listField.items[element].value); + } + }); + if (listField.items[0].value.isEmpty) { + selectedValues = []; + isText = true; + // ignore: avoid_function_literals_in_foreach_calls + value.forEach((int element) { + selectedValues.add(listField.items[element].text); + }); + } + _assignSelectedValue(selectedValues, isText); + changed = true; + } + } + + void _assignSelectedValue(List values, bool isText) { + final List selectedIndexes = []; + final PdfListFieldItemCollection collection = listField.items; + if (listField.readOnly == false) { + // ignore: avoid_function_literals_in_foreach_calls + values.forEach((String? element) { + bool isvaluePresent = false; + for (int i = 0; i < collection.count; i++) { + if ((isText ? collection[i].text : collection[i].value) == element) { + isvaluePresent = true; + selectedIndexes.add(i); + } + } + if (!isvaluePresent && + (listField is PdfComboBoxField) && + !(listField as PdfComboBoxField).editable) { + throw RangeError('index'); + } + }); + if (listField is PdfListBoxField && values.length > 1) { + final PdfListBoxField tempField = listField as PdfListBoxField; + if (!tempField.multiSelect) { + selectedIndexes.removeRange(1, selectedIndexes.length - 1); + values = [collection[selectedIndexes[0]].value]; + } + } + if (selectedIndexes.isNotEmpty) { + selectedIndexes.sort(); + dictionary!.setProperty( + PdfDictionaryProperties.i, + PdfArray(selectedIndexes), + ); + } else { + dictionary!.remove(PdfDictionaryProperties.i); + } + } + if (dictionary!.containsKey(PdfDictionaryProperties.v)) { + final IPdfPrimitive? primitive = crossTable!.getObject( + dictionary![PdfDictionaryProperties.v], + ); + if ((primitive == null) || (primitive is PdfString)) { + if (listField is PdfListBoxField) { + final PdfArray array = PdfArray(); + for (final String? selectedValue in values) { + array.add(PdfString(selectedValue!)); + } + dictionary!.setProperty(PdfDictionaryProperties.v, array); + } else { + dictionary!.setString(PdfDictionaryProperties.v, values[0]); + } + } else { + final PdfArray array = primitive as PdfArray; + array.clear(); + for (final String? selectedValue in values) { + array.add(PdfString(selectedValue!)); + } + dictionary!.setProperty(PdfDictionaryProperties.v, array); + } + } else if (listField is PdfComboBoxField) { + dictionary!.setString(PdfDictionaryProperties.v, values[0]); + } else { + final PdfArray array = PdfArray(); + for (final String? selectedValue in values) { + array.add(PdfString(selectedValue!)); + } + dictionary!.setProperty(PdfDictionaryProperties.v, array); + } + changed = true; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item.dart index 53e8307e5..5026241d7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item.dart @@ -1,139 +1,139 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_field.dart'; -import 'pdf_list_field.dart'; - -/// Represents an item of the list fields. -class PdfListFieldItem implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfListFieldItem] class. - PdfListFieldItem(String text, String value) : super() { - _helper = PdfListFieldItemHelper(this); - _initialize(text, value); - } - - /// Initializes a new instance of the [PdfListFieldItem] class. - PdfListFieldItem._load( - String? text, - String? value, - PdfListField field, - PdfCrossTable? cTable, - ) { - _helper = PdfListFieldItemHelper(this); - _field = field; - _crossTable = cTable; - _text = text ?? ''; - _value = value ?? ''; - } - - //Fields - late PdfListFieldItemHelper _helper; - String? _text; - String? _value; - PdfListField? _field; - PdfCrossTable? _crossTable; - - //Properties - /// Gets or sets the text. - String get text => _text!; - set text(String value) { - if (_text != value) { - if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { - _assignValues(value, true); - } else { - //text index: 1. - _text = (_helper._array[1]! as PdfString).value = value; - } - } - } - - /// Gets or sets the value. - String get value => _value!; - set value(String value) { - if (_value != value) { - if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { - _assignValues(value, false); - } else { - //value index: 0. - _value = (_helper._array[0]! as PdfString).value = value; - } - } - } - - //Implementation - void _initialize(String text, String value) { - _helper._array.add(PdfString(value)); - _helper._array.add(PdfString(text)); - _value = value; - _text = text; - } - - //Sets the text of the item. - void _assignValues(String value, bool isText) { - final PdfDictionary fieldDic = - PdfFieldHelper.getHelper(_field!).dictionary!; - if (fieldDic.containsKey(PdfDictionaryProperties.opt)) { - final PdfArray array = - _crossTable!.getObject(fieldDic[PdfDictionaryProperties.opt])! - as PdfArray; - final PdfArray item = - isText - ? (PdfArray() - ..add(PdfString(_value!)) - ..add(PdfString(value))) - : (PdfArray() - ..add(PdfString(value)) - ..add(PdfString(_text!))); - for (int i = 0; i < array.count; ++i) { - final IPdfPrimitive primitive = _crossTable!.getObject(array[i])!; - final PdfArray arr = primitive as PdfArray; - final PdfString text = _crossTable!.getObject(arr[1])! as PdfString; - if (text.value == _text || text.value == _value) { - isText ? _text = value : _value = value; - array.removeAt(i); - array.insert(i, item); - } - } - fieldDic.setProperty(PdfDictionaryProperties.opt, array); - PdfFieldHelper.getHelper(_field!).changed = true; - } - } -} - -/// [PdfListFieldItem] helper -class PdfListFieldItemHelper { - /// internal costructor - PdfListFieldItemHelper(this.fieldItem); - - /// internal field - PdfListFieldItem fieldItem; - - /// internal field - final PdfArray _array = PdfArray(); - - /// internal method - IPdfPrimitive get element => _array; - // ignore: unused_element - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - static PdfListFieldItemHelper getHelper(PdfListFieldItem fieldItem) { - return fieldItem._helper; - } - - /// internal method - static PdfListFieldItem load( - String? text, - String? value, - PdfListField field, - PdfCrossTable? cTable, - ) { - return PdfListFieldItem._load(text, value, field, cTable); - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_field.dart'; +import 'pdf_list_field.dart'; + +/// Represents an item of the list fields. +class PdfListFieldItem implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfListFieldItem] class. + PdfListFieldItem(String text, String value) : super() { + _helper = PdfListFieldItemHelper(this); + _initialize(text, value); + } + + /// Initializes a new instance of the [PdfListFieldItem] class. + PdfListFieldItem._load( + String? text, + String? value, + PdfListField field, + PdfCrossTable? cTable, + ) { + _helper = PdfListFieldItemHelper(this); + _field = field; + _crossTable = cTable; + _text = text ?? ''; + _value = value ?? ''; + } + + //Fields + late PdfListFieldItemHelper _helper; + String? _text; + String? _value; + PdfListField? _field; + PdfCrossTable? _crossTable; + + //Properties + /// Gets or sets the text. + String get text => _text!; + set text(String value) { + if (_text != value) { + if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { + _assignValues(value, true); + } else { + //text index: 1. + _text = (_helper._array[1]! as PdfString).value = value; + } + } + } + + /// Gets or sets the value. + String get value => _value!; + set value(String value) { + if (_value != value) { + if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { + _assignValues(value, false); + } else { + //value index: 0. + _value = (_helper._array[0]! as PdfString).value = value; + } + } + } + + //Implementation + void _initialize(String text, String value) { + _helper._array.add(PdfString(value)); + _helper._array.add(PdfString(text)); + _value = value; + _text = text; + } + + //Sets the text of the item. + void _assignValues(String value, bool isText) { + final PdfDictionary fieldDic = + PdfFieldHelper.getHelper(_field!).dictionary!; + if (fieldDic.containsKey(PdfDictionaryProperties.opt)) { + final PdfArray array = + _crossTable!.getObject(fieldDic[PdfDictionaryProperties.opt])! + as PdfArray; + final PdfArray item = + isText + ? (PdfArray() + ..add(PdfString(_value!)) + ..add(PdfString(value))) + : (PdfArray() + ..add(PdfString(value)) + ..add(PdfString(_text!))); + for (int i = 0; i < array.count; ++i) { + final IPdfPrimitive primitive = _crossTable!.getObject(array[i])!; + final PdfArray arr = primitive as PdfArray; + final PdfString text = _crossTable!.getObject(arr[1])! as PdfString; + if (text.value == _text || text.value == _value) { + isText ? _text = value : _value = value; + array.removeAt(i); + array.insert(i, item); + } + } + fieldDic.setProperty(PdfDictionaryProperties.opt, array); + PdfFieldHelper.getHelper(_field!).changed = true; + } + } +} + +/// [PdfListFieldItem] helper +class PdfListFieldItemHelper { + /// internal costructor + PdfListFieldItemHelper(this.fieldItem); + + /// internal field + PdfListFieldItem fieldItem; + + /// internal field + final PdfArray _array = PdfArray(); + + /// internal method + IPdfPrimitive get element => _array; + // ignore: unused_element + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + static PdfListFieldItemHelper getHelper(PdfListFieldItem fieldItem) { + return fieldItem._helper; + } + + /// internal method + static PdfListFieldItem load( + String? text, + String? value, + PdfListField field, + PdfCrossTable? cTable, + ) { + return PdfListFieldItem._load(text, value, field, cTable); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item_collection.dart index db90064f1..3bd7ed4a7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_list_field_item_collection.dart @@ -1,195 +1,195 @@ -import '../../interfaces/pdf_interface.dart'; -import '../general/pdf_collection.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_field.dart'; -import 'pdf_list_field.dart'; -import 'pdf_list_field_item.dart'; - -/// Represents list field item collection. -class PdfListFieldItemCollection extends PdfObjectCollection - implements IPdfWrapper { - //Constructor - PdfListFieldItemCollection._([PdfListField? field]) : super() { - _helper = PdfListFieldItemCollectionHelper(this); - if (field != null) { - _field = field; - } - } - - //Fields - late PdfListFieldItemCollectionHelper _helper; - PdfListField? _field; - - //Properties - /// Gets the [PdfListFieldItem] at the specified index. - PdfListFieldItem operator [](int index) { - if (index < 0 || index >= count) { - throw RangeError('index'); - } - return _helper.list[index] as PdfListFieldItem; - } - - //Public methods - /// Adds the specified item in the collection and returns its index. - int add(PdfListFieldItem item) { - return _doAdd(item); - } - - /// Inserts the list item field at the specified index. - void insert(int index, PdfListFieldItem item) { - if (index < 0 || index > count) { - throw RangeError('index'); - } - _doInsert(index, item); - } - - /// Removes the specified [PdfListFieldItem]. - void remove(PdfListFieldItem item) { - if (_helper.list.contains(item)) { - _doRemove(item); - } - } - - /// Removes the item at the specified position. - void removeAt(int index) { - if ((index < 0) || (index >= count)) { - throw RangeError('index'); - } - _doRemove(null, index); - } - - /// Determines whether the item is present in the collection. - bool contains(PdfListFieldItem item) { - return _helper.list.contains(item); - } - - /// Gets the index of the specified item. - int indexOf(PdfListFieldItem item) { - return _helper.list.indexOf(item); - } - - /// Clears the collection. - void clear() { - if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { - final PdfArray list = _getItems()..clear(); - PdfFieldHelper.getHelper( - _field!, - ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); - } else { - _helper._items.clear(); - } - _helper.list.clear(); - } - - //Implementations - int _doAdd(PdfListFieldItem item) { - if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { - final PdfArray list = _getItems(); - final PdfArray itemArray = _getArray(item); - list.add(itemArray); - PdfFieldHelper.getHelper( - _field!, - ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); - } else { - _helper._items.add(IPdfWrapper.getElement(item)!); - } - _helper.list.add(item); - return count - 1; - } - - void _doInsert(int index, PdfListFieldItem item) { - if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { - final PdfArray list = _getItems(); - final PdfArray itemArray = _getArray(item); - list.insert(index, itemArray); - PdfFieldHelper.getHelper( - _field!, - ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); - } else { - _helper._items.insert(index, IPdfWrapper.getElement(item)!); - } - _helper.list.insert(index, item); - } - - void _doRemove(PdfListFieldItem? item, [int? index]) { - if (index == null && item != null) { - index = _helper.list.indexOf(item); - } - if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { - final PdfArray list = _getItems()..removeAt(index!); - PdfFieldHelper.getHelper( - _field!, - ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); - } else { - _helper._items.removeAt(index!); - } - _helper.list.removeAt(index); - } - - PdfArray _getItems() { - PdfArray? items; - if (PdfFieldHelper.getHelper( - _field!, - ).dictionary!.containsKey(PdfDictionaryProperties.opt)) { - final IPdfPrimitive? obj = PdfFieldHelper.getHelper( - _field!, - ).crossTable!.getObject( - PdfFieldHelper.getHelper(_field!).dictionary![PdfDictionaryProperties - .opt], - ); - if (obj != null && obj is PdfArray) { - items = obj; - } - } - return items ?? PdfArray(); - } - - PdfArray _getArray(PdfListFieldItem item) { - final PdfArray array = PdfArray(); - if (item.value != '') { - array.add(PdfString(item.value)); - } - if (item.value != '') { - array.add(PdfString(item.text)); - } - return array; - } -} - -/// [PdfListFieldItemCollection] helper -class PdfListFieldItemCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfListFieldItemCollectionHelper(this.listFieldItemCollection) - : super(listFieldItemCollection); - - /// internal field - PdfListFieldItemCollection listFieldItemCollection; - final PdfArray _items = PdfArray(); - - /// internal property - IPdfPrimitive? get element => _items; - // ignore: unused_element - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - static PdfListFieldItemCollectionHelper getHelper( - PdfListFieldItemCollection itemCollection, - ) { - return itemCollection._helper; - } - - /// internal method - static PdfListFieldItemCollection itemCollection([PdfListField? field]) { - return PdfListFieldItemCollection._(field); - } - - /// internal method - int addItem(PdfListFieldItem item) { - list.add(item); - return listFieldItemCollection.count - 1; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../general/pdf_collection.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_field.dart'; +import 'pdf_list_field.dart'; +import 'pdf_list_field_item.dart'; + +/// Represents list field item collection. +class PdfListFieldItemCollection extends PdfObjectCollection + implements IPdfWrapper { + //Constructor + PdfListFieldItemCollection._([PdfListField? field]) : super() { + _helper = PdfListFieldItemCollectionHelper(this); + if (field != null) { + _field = field; + } + } + + //Fields + late PdfListFieldItemCollectionHelper _helper; + PdfListField? _field; + + //Properties + /// Gets the [PdfListFieldItem] at the specified index. + PdfListFieldItem operator [](int index) { + if (index < 0 || index >= count) { + throw RangeError('index'); + } + return _helper.list[index] as PdfListFieldItem; + } + + //Public methods + /// Adds the specified item in the collection and returns its index. + int add(PdfListFieldItem item) { + return _doAdd(item); + } + + /// Inserts the list item field at the specified index. + void insert(int index, PdfListFieldItem item) { + if (index < 0 || index > count) { + throw RangeError('index'); + } + _doInsert(index, item); + } + + /// Removes the specified [PdfListFieldItem]. + void remove(PdfListFieldItem item) { + if (_helper.list.contains(item)) { + _doRemove(item); + } + } + + /// Removes the item at the specified position. + void removeAt(int index) { + if ((index < 0) || (index >= count)) { + throw RangeError('index'); + } + _doRemove(null, index); + } + + /// Determines whether the item is present in the collection. + bool contains(PdfListFieldItem item) { + return _helper.list.contains(item); + } + + /// Gets the index of the specified item. + int indexOf(PdfListFieldItem item) { + return _helper.list.indexOf(item); + } + + /// Clears the collection. + void clear() { + if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { + final PdfArray list = _getItems()..clear(); + PdfFieldHelper.getHelper( + _field!, + ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); + } else { + _helper._items.clear(); + } + _helper.list.clear(); + } + + //Implementations + int _doAdd(PdfListFieldItem item) { + if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { + final PdfArray list = _getItems(); + final PdfArray itemArray = _getArray(item); + list.add(itemArray); + PdfFieldHelper.getHelper( + _field!, + ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); + } else { + _helper._items.add(IPdfWrapper.getElement(item)!); + } + _helper.list.add(item); + return count - 1; + } + + void _doInsert(int index, PdfListFieldItem item) { + if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { + final PdfArray list = _getItems(); + final PdfArray itemArray = _getArray(item); + list.insert(index, itemArray); + PdfFieldHelper.getHelper( + _field!, + ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); + } else { + _helper._items.insert(index, IPdfWrapper.getElement(item)!); + } + _helper.list.insert(index, item); + } + + void _doRemove(PdfListFieldItem? item, [int? index]) { + if (index == null && item != null) { + index = _helper.list.indexOf(item); + } + if (_field != null && PdfFieldHelper.getHelper(_field!).isLoadedField) { + final PdfArray list = _getItems()..removeAt(index!); + PdfFieldHelper.getHelper( + _field!, + ).dictionary!.setProperty(PdfDictionaryProperties.opt, list); + } else { + _helper._items.removeAt(index!); + } + _helper.list.removeAt(index); + } + + PdfArray _getItems() { + PdfArray? items; + if (PdfFieldHelper.getHelper( + _field!, + ).dictionary!.containsKey(PdfDictionaryProperties.opt)) { + final IPdfPrimitive? obj = PdfFieldHelper.getHelper( + _field!, + ).crossTable!.getObject( + PdfFieldHelper.getHelper(_field!).dictionary![PdfDictionaryProperties + .opt], + ); + if (obj != null && obj is PdfArray) { + items = obj; + } + } + return items ?? PdfArray(); + } + + PdfArray _getArray(PdfListFieldItem item) { + final PdfArray array = PdfArray(); + if (item.value != '') { + array.add(PdfString(item.value)); + } + if (item.value != '') { + array.add(PdfString(item.text)); + } + return array; + } +} + +/// [PdfListFieldItemCollection] helper +class PdfListFieldItemCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfListFieldItemCollectionHelper(this.listFieldItemCollection) + : super(listFieldItemCollection); + + /// internal field + PdfListFieldItemCollection listFieldItemCollection; + final PdfArray _items = PdfArray(); + + /// internal property + IPdfPrimitive? get element => _items; + // ignore: unused_element + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + static PdfListFieldItemCollectionHelper getHelper( + PdfListFieldItemCollection itemCollection, + ) { + return itemCollection._helper; + } + + /// internal method + static PdfListFieldItemCollection itemCollection([PdfListField? field]) { + return PdfListFieldItemCollection._(field); + } + + /// internal method + int addItem(PdfListFieldItem item) { + list.add(item); + return listFieldItemCollection.count - 1; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_item_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_item_collection.dart index b1801a89d..a7845cdf7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_item_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_item_collection.dart @@ -1,160 +1,160 @@ -import '../../interfaces/pdf_interface.dart'; -import '../general/pdf_collection.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'pdf_check_box_field.dart'; -import 'pdf_radio_button_list_field.dart'; - -/// Represents an item of a radio button list. -class PdfRadioButtonItemCollection extends PdfObjectCollection - implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfRadioButtonItemCollection] - /// class with the specific [PdfRadioButtonListField]. - PdfRadioButtonItemCollection._(PdfRadioButtonListField field) { - _helper = PdfRadioButtonItemCollectionHelper(this, field); - } - - //Fields - late PdfRadioButtonItemCollectionHelper _helper; - - //Properties - /// Gets the PdfRadioButtonListItem at the specified index. - PdfRadioButtonListItem operator [](int index) => - _helper.list[index] as PdfRadioButtonListItem; - - //Implementation - - /// Adds the specified item. - int add(PdfRadioButtonListItem item) { - return _helper.doAdd(item, false); - } - - /// Inserts an item at the specified index. - void insert(int index, PdfRadioButtonListItem item) { - _helper.doInsert(index, item); - } - - /// Removes the specified item from the collection. - void remove(PdfRadioButtonListItem item) { - _helper.doRemove(item); - } - - /// Removes the item at the specified index. - void removeAt(int index) { - _helper.removeAt(index); - } - - /// Gets the index of the item within the collection. - int indexOf(PdfRadioButtonListItem item) => _helper.indexOf(item); - - /// Determines whether the collection contains the specified item. - bool contains(PdfRadioButtonListItem item) => _helper.contains(item); - - /// Clears the item collection. - void clear() => _helper.doClear(); -} - -/// [PdfRadioButtonItemCollection] helper -class PdfRadioButtonItemCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfRadioButtonItemCollectionHelper(this.radioButtonItemCollection, this.field) - : super(radioButtonItemCollection); - - /// internal field - PdfRadioButtonItemCollection radioButtonItemCollection; - - /// internal field - PdfRadioButtonListField? field; - - /// internal field - PdfArray array = PdfArray(); - - /// internal method - static PdfRadioButtonItemCollectionHelper getHelper( - PdfRadioButtonItemCollection collection, - ) { - return collection._helper; - } - - /// internal method - static PdfRadioButtonItemCollection getCollection( - PdfRadioButtonListField field, - ) { - return PdfRadioButtonItemCollection._(field); - } - - /// internal property - IPdfPrimitive get element => array; - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfArray) { - array = value; - } - } - - /// Gets the index of the item within the collection. - int indexOf(PdfRadioButtonListItem item) => list.indexOf(item); - - /// Determines whether the collection contains the specified item. - bool contains(PdfRadioButtonListItem item) => list.contains(item); - - /// internal method - int doAdd(PdfRadioButtonListItem item, bool isItem) { - array.add(PdfReferenceHolder(item)); - PdfRadioButtonListItemHelper.getHelper(item).setField(field, isItem); - list.add(item); - return list.length - 1; - } - - /// internal method - void removeAt(int index) { - RangeError.range(index, 0, list.length); - array.removeAt(index); - final PdfRadioButtonListItem item = list[index] as PdfRadioButtonListItem; - PdfRadioButtonListItemHelper.getHelper(item).setField(null); - list.removeAt(index); - if ((field != null && - PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex >= - index) || - (list.isEmpty)) { - PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex = -1; - } - } - - /// internal method - void doInsert(int index, PdfRadioButtonListItem item) { - array.insert(index, PdfReferenceHolder(item)); - PdfRadioButtonListItemHelper.getHelper(item).setField(field); - list.insert(index, item); - } - - /// internal method - void doRemove(PdfRadioButtonListItem item) { - if (list.contains(item)) { - final int index = list.indexOf(item); - array.removeAt(index); - PdfRadioButtonListItemHelper.getHelper(item).setField(null); - list.removeAt(index); - if ((field != null && - PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex >= - index) || - (list.isEmpty)) { - PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex = -1; - } - } - } - - /// internal method - void doClear() { - final List objects = list; - for (final Object? item in objects) { - if (item is PdfRadioButtonListItem) { - PdfRadioButtonListItemHelper.getHelper(item).setField(null); - } - } - array.clear(); - list.clear(); - PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex = -1; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../general/pdf_collection.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'pdf_check_box_field.dart'; +import 'pdf_radio_button_list_field.dart'; + +/// Represents an item of a radio button list. +class PdfRadioButtonItemCollection extends PdfObjectCollection + implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfRadioButtonItemCollection] + /// class with the specific [PdfRadioButtonListField]. + PdfRadioButtonItemCollection._(PdfRadioButtonListField field) { + _helper = PdfRadioButtonItemCollectionHelper(this, field); + } + + //Fields + late PdfRadioButtonItemCollectionHelper _helper; + + //Properties + /// Gets the PdfRadioButtonListItem at the specified index. + PdfRadioButtonListItem operator [](int index) => + _helper.list[index] as PdfRadioButtonListItem; + + //Implementation + + /// Adds the specified item. + int add(PdfRadioButtonListItem item) { + return _helper.doAdd(item, false); + } + + /// Inserts an item at the specified index. + void insert(int index, PdfRadioButtonListItem item) { + _helper.doInsert(index, item); + } + + /// Removes the specified item from the collection. + void remove(PdfRadioButtonListItem item) { + _helper.doRemove(item); + } + + /// Removes the item at the specified index. + void removeAt(int index) { + _helper.removeAt(index); + } + + /// Gets the index of the item within the collection. + int indexOf(PdfRadioButtonListItem item) => _helper.indexOf(item); + + /// Determines whether the collection contains the specified item. + bool contains(PdfRadioButtonListItem item) => _helper.contains(item); + + /// Clears the item collection. + void clear() => _helper.doClear(); +} + +/// [PdfRadioButtonItemCollection] helper +class PdfRadioButtonItemCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfRadioButtonItemCollectionHelper(this.radioButtonItemCollection, this.field) + : super(radioButtonItemCollection); + + /// internal field + PdfRadioButtonItemCollection radioButtonItemCollection; + + /// internal field + PdfRadioButtonListField? field; + + /// internal field + PdfArray array = PdfArray(); + + /// internal method + static PdfRadioButtonItemCollectionHelper getHelper( + PdfRadioButtonItemCollection collection, + ) { + return collection._helper; + } + + /// internal method + static PdfRadioButtonItemCollection getCollection( + PdfRadioButtonListField field, + ) { + return PdfRadioButtonItemCollection._(field); + } + + /// internal property + IPdfPrimitive get element => array; + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfArray) { + array = value; + } + } + + /// Gets the index of the item within the collection. + int indexOf(PdfRadioButtonListItem item) => list.indexOf(item); + + /// Determines whether the collection contains the specified item. + bool contains(PdfRadioButtonListItem item) => list.contains(item); + + /// internal method + int doAdd(PdfRadioButtonListItem item, bool isItem) { + array.add(PdfReferenceHolder(item)); + PdfRadioButtonListItemHelper.getHelper(item).setField(field, isItem); + list.add(item); + return list.length - 1; + } + + /// internal method + void removeAt(int index) { + RangeError.range(index, 0, list.length); + array.removeAt(index); + final PdfRadioButtonListItem item = list[index] as PdfRadioButtonListItem; + PdfRadioButtonListItemHelper.getHelper(item).setField(null); + list.removeAt(index); + if ((field != null && + PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex >= + index) || + (list.isEmpty)) { + PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex = -1; + } + } + + /// internal method + void doInsert(int index, PdfRadioButtonListItem item) { + array.insert(index, PdfReferenceHolder(item)); + PdfRadioButtonListItemHelper.getHelper(item).setField(field); + list.insert(index, item); + } + + /// internal method + void doRemove(PdfRadioButtonListItem item) { + if (list.contains(item)) { + final int index = list.indexOf(item); + array.removeAt(index); + PdfRadioButtonListItemHelper.getHelper(item).setField(null); + list.removeAt(index); + if ((field != null && + PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex >= + index) || + (list.isEmpty)) { + PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex = -1; + } + } + } + + /// internal method + void doClear() { + final List objects = list; + for (final Object? item in objects) { + if (item is PdfRadioButtonListItem) { + PdfRadioButtonListItemHelper.getHelper(item).setField(null); + } + } + array.clear(); + list.clear(); + PdfRadioButtonListFieldHelper.getHelper(field!).selectedIndex = -1; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_list_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_list_field.dart index 3830fe39b..41875f898 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_list_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_radio_button_list_field.dart @@ -1,391 +1,391 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../general/pdf_collection.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_check_box_field.dart'; -import 'pdf_field.dart'; -import 'pdf_radio_button_item_collection.dart'; - -/// Represents radio button field in the PDF form. -class PdfRadioButtonListField extends PdfField { - //Constructor - /// Initializes a new instance of the [PdfRadioButtonListField] class with - /// the specific page, name and bounds. - PdfRadioButtonListField( - PdfPage page, - String name, { - List? items, - int? selectedIndex, - String? selectedValue, - }) { - _helper = PdfRadioButtonListFieldHelper(this); - _helper.internal(page, name, Rect.zero); - _initValues(items, selectedIndex, selectedValue); - _helper.flags.add(FieldFlags.radio); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.ft, - PdfName(PdfDictionaryProperties.btn), - ); - } - - PdfRadioButtonListField._loaded( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - _helper = PdfRadioButtonListFieldHelper(this); - _helper.load(dictionary, crossTable); - _retrieveOptionValue(); - } - - //Fields - PdfRadioButtonItemCollection? _items; - late PdfRadioButtonListFieldHelper _helper; - - //Properties - /// Gets the items of the radio button field.{Read-Only} - PdfRadioButtonItemCollection get items { - if (_helper.isLoadedField) { - _items ??= _getRadioButtonListItems( - PdfRadioButtonItemCollectionHelper.getCollection(this), - ); - return _items!; - } else { - if (_items == null) { - _items = PdfRadioButtonItemCollectionHelper.getCollection(this); - _helper.dictionary!.setProperty(PdfDictionaryProperties.kids, _items); - } - return _items!; - } - } - - /// Gets or sets the first selected item in the list. - int get selectedIndex { - if (_helper.isLoadedField && _helper.selectedIndex == -1) { - _helper.selectedIndex = _obtainSelectedIndex(); - } - if (_helper.selectedIndex == -1) { - ArgumentError.value('None of the item to be selected in the list'); - } - return _helper.selectedIndex; - } - - set selectedIndex(int value) { - RangeError.range(value, 0, items.count, 'SelectedIndex'); - if (selectedIndex != value) { - if (_helper.isLoadedField) { - _assignSelectedIndex(value); - _helper.changed = true; - } - _helper.selectedIndex = value; - final PdfRadioButtonListItem item = _items![_helper.selectedIndex]; - final PdfDictionary dictionary = _helper.dictionary!; - dictionary.setName(PdfName(PdfDictionaryProperties.v), item.value); - dictionary.setName(PdfName(PdfDictionaryProperties.dv), item.value); - } - } - - /// Gets the first selected item in the list.{Read-Only} - PdfRadioButtonListItem? get selectedItem { - PdfRadioButtonListItem? item; - if (selectedIndex != -1) { - item = items[_helper.selectedIndex]; - } - return item; - } - - /// Gets or sets the value of the first selected item in the list. - String get selectedValue { - if (_helper.isLoadedField) { - if (selectedIndex == -1) { - _helper.selectedIndex = _obtainSelectedIndex(); - } - if (_helper.selectedIndex != -1) { - return _items![_helper.selectedIndex].value; - } else { - ArgumentError('None of the item to be selected in the list'); - } - return _items![_helper.selectedIndex].value; - } else { - if (_helper.selectedIndex == -1) { - ArgumentError('None of the item to be selected in the list'); - } - return _items![_helper.selectedIndex].value; - } - } - - set selectedValue(String value) { - if (_helper.isLoadedField) { - _assignSelectedValue(value); - _helper.changed = true; - } else { - final List objects = - PdfObjectCollectionHelper.getHelper(items).list; - for (final Object? item in objects) { - if (item is PdfRadioButtonListItem && item.value == value) { - _helper.selectedIndex = items.indexOf(item); - final PdfDictionary dictionary = _helper.dictionary!; - dictionary.setName(PdfName(PdfDictionaryProperties.v), item.value); - dictionary.setName(PdfName(PdfDictionaryProperties.dv), item.value); - break; - } - } - } - } - - //Implementation - void _initValues( - List? radioItems, - int? index, - String? value, - ) { - if (radioItems != null) { - radioItems.toList().forEach( - (PdfRadioButtonListItem item) => items.add(item), - ); - } - if (index != null) { - selectedIndex = index; - } - if (value != null) { - selectedValue = value; - } - } - - PdfRadioButtonItemCollection _getRadioButtonListItems( - PdfRadioButtonItemCollection listItems, - ) { - final PdfArray? fieldKids = _helper.obtainKids(); - if (fieldKids != null) { - for (int i = 0; i < fieldKids.count; i++) { - final IPdfPrimitive? kidsDict = PdfCrossTable.dereference(fieldKids[i]); - if (kidsDict != null && kidsDict is PdfDictionary) { - final PdfRadioButtonListItem item = - PdfRadioButtonListItemHelper.loaded( - kidsDict, - _helper.crossTable!, - this, - ); - PdfRadioButtonItemCollectionHelper.getHelper( - listItems, - ).doAdd(item, true); - } - } - } - return listItems; - } - - int _obtainSelectedIndex() { - int index = -1; - for (int i = 0; i < items.count; ++i) { - final PdfRadioButtonListItem item = items[i]; - final PdfDictionary dic = PdfFieldHelper.getHelper(item).dictionary!; - final IPdfPrimitive? checkNamePrimitive = PdfFieldHelper.searchInParents( - dic, - _helper.crossTable, - PdfDictionaryProperties.v, - ); - if (dic.containsKey(PdfDictionaryProperties.usageApplication) && - (checkNamePrimitive is PdfName || checkNamePrimitive is PdfString)) { - final IPdfPrimitive? name = _helper.crossTable!.getObject( - dic[PdfDictionaryProperties.usageApplication], - ); - if (name is PdfName && name.name!.toLowerCase() != 'off') { - if (checkNamePrimitive is PdfName && - checkNamePrimitive.name!.toLowerCase() != 'off') { - if (name.name == checkNamePrimitive.name) { - index = i; - } - break; - } else if (checkNamePrimitive is PdfString && - checkNamePrimitive.value!.toLowerCase() != 'off') { - if (name.name == checkNamePrimitive.value) { - index = i; - } - break; - } - } - } - } - return index; - } - - void _assignSelectedIndex(int value) { - final int index = _helper.selectedIndex; - if (index != value) { - PdfName? name; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - name = _helper.dictionary![PdfDictionaryProperties.v] as PdfName?; - _helper.dictionary!.remove(PdfDictionaryProperties.v); - _helper.dictionary!.remove(PdfDictionaryProperties.dv); - } - if (name != null) { - for (int i = 0; i < items.count; i++) { - final PdfRadioButtonListItem item = items[i]; - if (item.value == name.name) { - PdfFieldHelper.getHelper(item).dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - PdfDictionaryProperties.off, - ); - } - } - } - PdfFieldHelper.getHelper(items[value]).dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - items[value].value, - ); - } - } - - void _assignSelectedValue(String value) { - PdfName? name; - value = PdfName.decodeName(value)!; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - name = _helper.dictionary![PdfDictionaryProperties.v] as PdfName?; - _helper.dictionary!.remove(PdfDictionaryProperties.v); - _helper.dictionary!.remove(PdfDictionaryProperties.dv); - } - if (name != null) { - for (int i = 0; i < items.count; i++) { - final PdfRadioButtonListItem item = items[i]; - if (item.value == PdfName.decodeName(name.name)) { - PdfFieldHelper.getHelper(item).dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - PdfDictionaryProperties.off, - ); - } - } - } - final List objects = - PdfObjectCollectionHelper.getHelper(items).list; - for (final Object? item in objects) { - if (item is PdfRadioButtonListItem && - (item.value == value || - PdfRadioButtonListItemHelper.getHelper(item).optionValue == - value)) { - _helper.selectedIndex = items.indexOf(item); - _helper.dictionary!.setName( - PdfName(PdfDictionaryProperties.v), - item.value, - ); - _helper.dictionary!.setName( - PdfName(PdfDictionaryProperties.dv), - item.value, - ); - final PdfFieldHelper helper = PdfFieldHelper.getHelper(item); - helper.dictionary!.setName( - PdfName(PdfDictionaryProperties.usageApplication), - item.value, - ); - helper.dictionary!.setName( - PdfName(PdfDictionaryProperties.v), - item.value, - ); - break; - } - } - } - - void _retrieveOptionValue() { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.opt)) { - final IPdfPrimitive optionArray = - _helper.dictionary![PdfDictionaryProperties.opt]!; - final IPdfPrimitive? options = - optionArray is PdfReferenceHolder ? optionArray.object : optionArray; - if (options != null && options is PdfArray) { - final int count = - (options.count <= items.count) ? options.count : items.count; - for (int i = 0; i < count; i++) { - final IPdfPrimitive? option = - options[i] is PdfReferenceHolder - ? (options[i]! as PdfReferenceHolder).object - : options[i]; - if (option != null && option is PdfString) { - PdfRadioButtonListItemHelper.getHelper(items[i]).optionValue = - option.value; - } - } - } - } - } -} - -/// [PdfRadioButtonListField] helper -class PdfRadioButtonListFieldHelper extends PdfFieldHelper { - /// internal constructor - PdfRadioButtonListFieldHelper(this.radioButtonList) : super(radioButtonList); - - /// internal field - PdfRadioButtonListField radioButtonList; - - /// internal field - int selectedIndex = -1; - - /// internal method - static PdfRadioButtonListFieldHelper getHelper( - PdfRadioButtonListField radioButtonList, - ) { - return radioButtonList._helper; - } - - /// internal method - static PdfRadioButtonListField loaded( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfRadioButtonListField._loaded(dictionary, crossTable); - } - - /// internal method - @override - void beginSave() { - super.beginSave(); - final PdfArray? kids = obtainKids(); - int i = 0; - if (kids != null) { - for (i = 0; i < kids.count; ++i) { - final PdfDictionary? widget = - crossTable!.getObject(kids[i]) as PdfDictionary?; - final PdfRadioButtonListItem item = radioButtonList.items[i]; - PdfCheckFieldBaseHelper.getHelper(item).applyAppearance(widget, item); - } - } - while (i < radioButtonList.items.count) { - PdfRadioButtonListItemHelper.getHelper(radioButtonList.items[i]).save(); - i++; - } - } - - /// internal method - @override - void draw() { - if (isLoadedField) { - final PdfArray? kids = obtainKids(); - if (kids != null) { - for (int i = 0; i < kids.count; ++i) { - final PdfRadioButtonListItem item = radioButtonList.items[i]; - PdfCheckFieldState state = PdfCheckFieldState.unchecked; - if ((radioButtonList.selectedIndex >= 0) && - (radioButtonList.selectedValue == item.value)) { - state = PdfCheckFieldState.checked; - } - if (item.page != null) { - drawStateItem(item.page!.graphics, state, item); - } - } - } - } else { - for (int i = 0; i < radioButtonList.items.count; ++i) { - PdfRadioButtonListItemHelper.getHelper(radioButtonList.items[i]).draw(); - } - } - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../general/pdf_collection.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_check_box_field.dart'; +import 'pdf_field.dart'; +import 'pdf_radio_button_item_collection.dart'; + +/// Represents radio button field in the PDF form. +class PdfRadioButtonListField extends PdfField { + //Constructor + /// Initializes a new instance of the [PdfRadioButtonListField] class with + /// the specific page, name and bounds. + PdfRadioButtonListField( + PdfPage page, + String name, { + List? items, + int? selectedIndex, + String? selectedValue, + }) { + _helper = PdfRadioButtonListFieldHelper(this); + _helper.internal(page, name, Rect.zero); + _initValues(items, selectedIndex, selectedValue); + _helper.flags.add(FieldFlags.radio); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.ft, + PdfName(PdfDictionaryProperties.btn), + ); + } + + PdfRadioButtonListField._loaded( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + _helper = PdfRadioButtonListFieldHelper(this); + _helper.load(dictionary, crossTable); + _retrieveOptionValue(); + } + + //Fields + PdfRadioButtonItemCollection? _items; + late PdfRadioButtonListFieldHelper _helper; + + //Properties + /// Gets the items of the radio button field.{Read-Only} + PdfRadioButtonItemCollection get items { + if (_helper.isLoadedField) { + _items ??= _getRadioButtonListItems( + PdfRadioButtonItemCollectionHelper.getCollection(this), + ); + return _items!; + } else { + if (_items == null) { + _items = PdfRadioButtonItemCollectionHelper.getCollection(this); + _helper.dictionary!.setProperty(PdfDictionaryProperties.kids, _items); + } + return _items!; + } + } + + /// Gets or sets the first selected item in the list. + int get selectedIndex { + if (_helper.isLoadedField && _helper.selectedIndex == -1) { + _helper.selectedIndex = _obtainSelectedIndex(); + } + if (_helper.selectedIndex == -1) { + ArgumentError.value('None of the item to be selected in the list'); + } + return _helper.selectedIndex; + } + + set selectedIndex(int value) { + RangeError.range(value, 0, items.count, 'SelectedIndex'); + if (selectedIndex != value) { + if (_helper.isLoadedField) { + _assignSelectedIndex(value); + _helper.changed = true; + } + _helper.selectedIndex = value; + final PdfRadioButtonListItem item = _items![_helper.selectedIndex]; + final PdfDictionary dictionary = _helper.dictionary!; + dictionary.setName(PdfName(PdfDictionaryProperties.v), item.value); + dictionary.setName(PdfName(PdfDictionaryProperties.dv), item.value); + } + } + + /// Gets the first selected item in the list.{Read-Only} + PdfRadioButtonListItem? get selectedItem { + PdfRadioButtonListItem? item; + if (selectedIndex != -1) { + item = items[_helper.selectedIndex]; + } + return item; + } + + /// Gets or sets the value of the first selected item in the list. + String get selectedValue { + if (_helper.isLoadedField) { + if (selectedIndex == -1) { + _helper.selectedIndex = _obtainSelectedIndex(); + } + if (_helper.selectedIndex != -1) { + return _items![_helper.selectedIndex].value; + } else { + ArgumentError('None of the item to be selected in the list'); + } + return _items![_helper.selectedIndex].value; + } else { + if (_helper.selectedIndex == -1) { + ArgumentError('None of the item to be selected in the list'); + } + return _items![_helper.selectedIndex].value; + } + } + + set selectedValue(String value) { + if (_helper.isLoadedField) { + _assignSelectedValue(value); + _helper.changed = true; + } else { + final List objects = + PdfObjectCollectionHelper.getHelper(items).list; + for (final Object? item in objects) { + if (item is PdfRadioButtonListItem && item.value == value) { + _helper.selectedIndex = items.indexOf(item); + final PdfDictionary dictionary = _helper.dictionary!; + dictionary.setName(PdfName(PdfDictionaryProperties.v), item.value); + dictionary.setName(PdfName(PdfDictionaryProperties.dv), item.value); + break; + } + } + } + } + + //Implementation + void _initValues( + List? radioItems, + int? index, + String? value, + ) { + if (radioItems != null) { + radioItems.toList().forEach( + (PdfRadioButtonListItem item) => items.add(item), + ); + } + if (index != null) { + selectedIndex = index; + } + if (value != null) { + selectedValue = value; + } + } + + PdfRadioButtonItemCollection _getRadioButtonListItems( + PdfRadioButtonItemCollection listItems, + ) { + final PdfArray? fieldKids = _helper.obtainKids(); + if (fieldKids != null) { + for (int i = 0; i < fieldKids.count; i++) { + final IPdfPrimitive? kidsDict = PdfCrossTable.dereference(fieldKids[i]); + if (kidsDict != null && kidsDict is PdfDictionary) { + final PdfRadioButtonListItem item = + PdfRadioButtonListItemHelper.loaded( + kidsDict, + _helper.crossTable!, + this, + ); + PdfRadioButtonItemCollectionHelper.getHelper( + listItems, + ).doAdd(item, true); + } + } + } + return listItems; + } + + int _obtainSelectedIndex() { + int index = -1; + for (int i = 0; i < items.count; ++i) { + final PdfRadioButtonListItem item = items[i]; + final PdfDictionary dic = PdfFieldHelper.getHelper(item).dictionary!; + final IPdfPrimitive? checkNamePrimitive = PdfFieldHelper.searchInParents( + dic, + _helper.crossTable, + PdfDictionaryProperties.v, + ); + if (dic.containsKey(PdfDictionaryProperties.usageApplication) && + (checkNamePrimitive is PdfName || checkNamePrimitive is PdfString)) { + final IPdfPrimitive? name = _helper.crossTable!.getObject( + dic[PdfDictionaryProperties.usageApplication], + ); + if (name is PdfName && name.name!.toLowerCase() != 'off') { + if (checkNamePrimitive is PdfName && + checkNamePrimitive.name!.toLowerCase() != 'off') { + if (name.name == checkNamePrimitive.name) { + index = i; + } + break; + } else if (checkNamePrimitive is PdfString && + checkNamePrimitive.value!.toLowerCase() != 'off') { + if (name.name == checkNamePrimitive.value) { + index = i; + } + break; + } + } + } + } + return index; + } + + void _assignSelectedIndex(int value) { + final int index = _helper.selectedIndex; + if (index != value) { + PdfName? name; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + name = _helper.dictionary![PdfDictionaryProperties.v] as PdfName?; + _helper.dictionary!.remove(PdfDictionaryProperties.v); + _helper.dictionary!.remove(PdfDictionaryProperties.dv); + } + if (name != null) { + for (int i = 0; i < items.count; i++) { + final PdfRadioButtonListItem item = items[i]; + if (item.value == name.name) { + PdfFieldHelper.getHelper(item).dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + PdfDictionaryProperties.off, + ); + } + } + } + PdfFieldHelper.getHelper(items[value]).dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + items[value].value, + ); + } + } + + void _assignSelectedValue(String value) { + PdfName? name; + value = PdfName.decodeName(value)!; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + name = _helper.dictionary![PdfDictionaryProperties.v] as PdfName?; + _helper.dictionary!.remove(PdfDictionaryProperties.v); + _helper.dictionary!.remove(PdfDictionaryProperties.dv); + } + if (name != null) { + for (int i = 0; i < items.count; i++) { + final PdfRadioButtonListItem item = items[i]; + if (item.value == PdfName.decodeName(name.name)) { + PdfFieldHelper.getHelper(item).dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + PdfDictionaryProperties.off, + ); + } + } + } + final List objects = + PdfObjectCollectionHelper.getHelper(items).list; + for (final Object? item in objects) { + if (item is PdfRadioButtonListItem && + (item.value == value || + PdfRadioButtonListItemHelper.getHelper(item).optionValue == + value)) { + _helper.selectedIndex = items.indexOf(item); + _helper.dictionary!.setName( + PdfName(PdfDictionaryProperties.v), + item.value, + ); + _helper.dictionary!.setName( + PdfName(PdfDictionaryProperties.dv), + item.value, + ); + final PdfFieldHelper helper = PdfFieldHelper.getHelper(item); + helper.dictionary!.setName( + PdfName(PdfDictionaryProperties.usageApplication), + item.value, + ); + helper.dictionary!.setName( + PdfName(PdfDictionaryProperties.v), + item.value, + ); + break; + } + } + } + + void _retrieveOptionValue() { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.opt)) { + final IPdfPrimitive optionArray = + _helper.dictionary![PdfDictionaryProperties.opt]!; + final IPdfPrimitive? options = + optionArray is PdfReferenceHolder ? optionArray.object : optionArray; + if (options != null && options is PdfArray) { + final int count = + (options.count <= items.count) ? options.count : items.count; + for (int i = 0; i < count; i++) { + final IPdfPrimitive? option = + options[i] is PdfReferenceHolder + ? (options[i]! as PdfReferenceHolder).object + : options[i]; + if (option != null && option is PdfString) { + PdfRadioButtonListItemHelper.getHelper(items[i]).optionValue = + option.value; + } + } + } + } + } +} + +/// [PdfRadioButtonListField] helper +class PdfRadioButtonListFieldHelper extends PdfFieldHelper { + /// internal constructor + PdfRadioButtonListFieldHelper(this.radioButtonList) : super(radioButtonList); + + /// internal field + PdfRadioButtonListField radioButtonList; + + /// internal field + int selectedIndex = -1; + + /// internal method + static PdfRadioButtonListFieldHelper getHelper( + PdfRadioButtonListField radioButtonList, + ) { + return radioButtonList._helper; + } + + /// internal method + static PdfRadioButtonListField loaded( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfRadioButtonListField._loaded(dictionary, crossTable); + } + + /// internal method + @override + void beginSave() { + super.beginSave(); + final PdfArray? kids = obtainKids(); + int i = 0; + if (kids != null) { + for (i = 0; i < kids.count; ++i) { + final PdfDictionary? widget = + crossTable!.getObject(kids[i]) as PdfDictionary?; + final PdfRadioButtonListItem item = radioButtonList.items[i]; + PdfCheckFieldBaseHelper.getHelper(item).applyAppearance(widget, item); + } + } + while (i < radioButtonList.items.count) { + PdfRadioButtonListItemHelper.getHelper(radioButtonList.items[i]).save(); + i++; + } + } + + /// internal method + @override + void draw() { + if (isLoadedField) { + final PdfArray? kids = obtainKids(); + if (kids != null) { + for (int i = 0; i < kids.count; ++i) { + final PdfRadioButtonListItem item = radioButtonList.items[i]; + PdfCheckFieldState state = PdfCheckFieldState.unchecked; + if ((radioButtonList.selectedIndex >= 0) && + (radioButtonList.selectedValue == item.value)) { + state = PdfCheckFieldState.checked; + } + if (item.page != null) { + drawStateItem(item.page!.graphics, state, item); + } + } + } + } else { + for (int i = 0; i < radioButtonList.items.count; ++i) { + PdfRadioButtonListItemHelper.getHelper(radioButtonList.items[i]).draw(); + } + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_signature_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_signature_field.dart index fdf4ccd96..a2c13815c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_signature_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_signature_field.dart @@ -1,711 +1,711 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/pdf_annotation.dart'; -import '../annotations/pdf_appearance.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_color.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_main_object_collection.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import '../security/digital_signature/pdf_signature.dart'; -import '../security/digital_signature/pdf_signature_dictionary.dart'; -import '../security/enum.dart'; -import 'enum.dart'; -import 'pdf_field.dart'; -import 'pdf_field_painter.dart'; -import 'pdf_form.dart'; - -/// Represents signature field in the PDF Form. -class PdfSignatureField extends PdfField { - //Constructor - /// Initializes a new instance of the [PdfSignatureField] class. - PdfSignatureField( - PdfPage page, - String name, { - Rect bounds = Rect.zero, - int? borderWidth, - PdfHighlightMode? highlightMode, - PdfSignature? signature, - String? tooltip, - PdfColor? backColor, - PdfColor? borderColor, - PdfBorderStyle? borderStyle, - }) { - _helper = PdfSignatureFieldHelper(this); - _helper.internal( - page, - name, - bounds, - borderWidth: borderWidth, - highlightMode: highlightMode, - tooltip: tooltip, - backColor: backColor, - borderColor: borderColor, - borderStyle: borderStyle, - ); - form!.fieldAutoNaming - ? PdfAnnotationHelper.getHelper( - _helper.widget!, - ).dictionary!.setProperty( - PdfDictionaryProperties.ft, - PdfName(PdfDictionaryProperties.sig), - ) - : _helper.dictionary!.setProperty( - PdfDictionaryProperties.ft, - PdfName(PdfDictionaryProperties.sig), - ); - if (PdfPageHelper.getHelper(page).document != null) { - PdfFormHelper.getHelper(form!).signatureFlags = [ - SignatureFlags.signaturesExists, - SignatureFlags.appendOnly, - ]; - } - if (signature != null) { - this.signature = signature; - } - if (borderWidth != null || - borderColor != null || - backColor != null || - borderStyle != null) { - _helper.appearance = true; - } - } - - PdfSignatureField._(PdfDictionary dictionary, PdfCrossTable crossTable) { - _helper = PdfSignatureFieldHelper(this); - _helper.load(dictionary, crossTable); - if (dictionary.containsKey(PdfDictionaryProperties.v)) { - _helper.isLoadedSign = true; - } - } - - //Fields - late PdfSignatureFieldHelper _helper; - PdfSignature? _signature; - - //Properties - /// Gets or sets the width of the border. - /// - /// The default value is 1. - int get borderWidth => _helper.borderWidth; - set borderWidth(int value) { - _helper.appearance = true; - _helper.borderWidth = value; - } - - /// Gets or sets the highlighting mode. - /// - /// The default mode is invert. - PdfHighlightMode get highlightMode => _helper.highlightMode; - set highlightMode(PdfHighlightMode value) { - _helper.highlightMode = value; - } - - ///Gets the visual appearance of the field - PdfAppearance get appearance => _helper.widget!.appearance; - - /// Gets or sets the digital signature for signing the field. - PdfSignature? get signature { - if (_helper.isLoadedField && _signature == null) { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - _setSignature(_helper.dictionary![PdfDictionaryProperties.v]); - PdfSignatureHelper.getHelper(_signature!).field = this; - } - } - return _signature; - } - - set signature(PdfSignature? value) { - _initializeSignature(value); - } - - /// Gets or sets the color of the background. - /// - /// The default color is empty. - PdfColor get backColor => _helper.backColor; - set backColor(PdfColor value) { - _helper.appearance = true; - _helper.backColor = value; - _helper.assignBackColor(value); - } - - /// Gets or sets the color of the border. - /// - /// The default color is black. - PdfColor get borderColor => _helper.borderColor; - set borderColor(PdfColor value) { - _helper.appearance = true; - _helper.borderColor = value; - _helper.assignBorderColor(value); - } - - /// Gets or sets the border style. - /// - /// The default style is solid. - PdfBorderStyle get borderStyle => _helper.borderStyle; - set borderStyle(PdfBorderStyle value) { - _helper.appearance = true; - _helper.borderStyle = value; - } - - /// Checks whether the signature field is signed or not. - /// - /// ``` dart - /// // Load the existing PDF document. - /// PdfDocument document = - /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - /// // Create a new PDF document. - /// PdfSignatureField field = document.form.fields[0] as PdfSignatureField; - /// // Check if field is signed. - /// bool isSigned = field.isSigned; - /// // Dispose the document. - /// document.dispose(); - /// ``` - bool get isSigned => _helper.isLoadedSign; - - //Implementations - void _initializeSignature(PdfSignature? value) { - if (value != null) { - _signature = value; - PdfSignatureHelper.getHelper(_signature!).page = page; - PdfSignatureHelper.getHelper(_signature!).document = - PdfPageHelper.getHelper( - PdfSignatureHelper.getHelper(_signature!).page!, - ).document; - PdfSignatureHelper.getHelper( - _signature!, - ).checkAnnotationElementsContainsSignature(page!, name); - PdfSignatureHelper.getHelper(_signature!).field = this; - PdfDocumentHelper.getHelper( - PdfSignatureHelper.getHelper(_signature!).document!, - ).catalog.beginSave = - PdfSignatureHelper.getHelper(_signature!).catalogBeginSave; - _helper.dictionary!.beginSaveList ??= []; - _helper.dictionary!.beginSaveList!.add( - PdfSignatureHelper.getHelper(_signature!).dictionaryBeginSave, - ); - if (!_helper.skipKidsCertificate) { - final PdfDocument document = - PdfSignatureHelper.getHelper(_signature!).document!; - PdfSignatureHelper.getHelper( - _signature!, - ).signatureDictionary = PdfSignatureDictionary(document, _signature!); - final PdfSignatureDictionary signatureDictionary = - PdfSignatureHelper.getHelper(_signature!).signatureDictionary!; - if (!PdfDocumentHelper.getHelper(document).isLoadedDocument || - document.fileStructure.incrementalUpdate != false) { - signatureDictionary.dictionary!.archive = false; - PdfDocumentHelper.getHelper( - document, - ).objects.add(signatureDictionary.element); - PdfDocumentHelper.getHelper(document) - .objects[PdfDocumentHelper.getHelper(document).objects.count - 1] - .isModified = true; - signatureDictionary.element!.position = -1; - } - if (_helper.isLoadedField) { - PdfFormHelper.getHelper(form!).signatureFlags = [ - SignatureFlags.signaturesExists, - SignatureFlags.appendOnly, - ]; - final PdfDictionary widget = _helper.getWidgetAnnotation( - _helper.dictionary!, - _helper.crossTable, - ); - widget[PdfDictionaryProperties.v] = PdfReferenceHolder( - signatureDictionary, - ); - widget.modify(); - _helper.changed = true; - widget.setProperty(PdfDictionaryProperties.fieldFlags, PdfNumber(0)); - signatureDictionary.dictionary!.archive = false; - } else { - final PdfDictionary widget = - PdfAnnotationHelper.getHelper(_helper.widget!).dictionary!; - widget.setProperty( - PdfDictionaryProperties.v, - PdfReferenceHolder(signatureDictionary), - ); - widget.setProperty(PdfDictionaryProperties.fieldFlags, PdfNumber(0)); - } - } else { - PdfAnnotationHelper.getHelper(_helper.widget!).dictionary!.setProperty( - PdfDictionaryProperties.fieldFlags, - PdfNumber(0), - ); - } - _helper.widget!.bounds = bounds; - } - } - - void _setSignature(IPdfPrimitive? signature) { - final PdfCrossTable? crossTable = _helper.crossTable; - if (signature is PdfReferenceHolder && - signature.object != null && - signature.object is PdfDictionary) { - final PdfDictionary signatureDictionary = - signature.object! as PdfDictionary; - _signature = PdfSignature(); - PdfSignatureHelper.getHelper(_signature!).document = crossTable!.document; - String? subFilterType = ''; - if (signatureDictionary.containsKey(PdfDictionaryProperties.subFilter)) { - final IPdfPrimitive? filter = PdfCrossTable.dereference( - signatureDictionary[PdfDictionaryProperties.subFilter], - ); - if (filter != null && filter is PdfName) { - subFilterType = filter.name; - } - if (subFilterType == 'ETSI.CAdES.detached') { - _signature!.cryptographicStandard = CryptographicStandard.cades; - } - } - if (crossTable.document != null && - !PdfDocumentHelper.getHelper(crossTable.document!).isLoadedDocument) { - if (signatureDictionary.containsKey( - PdfDictionaryProperties.reference, - )) { - final IPdfPrimitive? tempArray = - signatureDictionary[PdfDictionaryProperties.reference]; - if (tempArray != null && tempArray is PdfArray) { - final IPdfPrimitive? tempDictionary = tempArray.elements[0]; - if (tempDictionary != null && tempDictionary is PdfDictionary) { - if (tempDictionary.containsKey(PdfDictionaryProperties.data)) { - final PdfMainObjectCollection mainObjectCollection = - PdfDocumentHelper.getHelper(crossTable.document!).objects; - IPdfPrimitive? tempReferenceHolder = - tempDictionary[PdfDictionaryProperties.data]; - if (tempReferenceHolder != null && - tempReferenceHolder is PdfReferenceHolder && - !mainObjectCollection.containsReference( - tempReferenceHolder.reference!, - )) { - final IPdfPrimitive? tempObject = - mainObjectCollection - .objectCollection![tempReferenceHolder - .reference! - .objectCollectionIndex!] - .object; - tempReferenceHolder = PdfReferenceHolder(tempObject); - tempDictionary.setProperty( - PdfDictionaryProperties.data, - tempReferenceHolder, - ); - } - } - } - } - } - signatureDictionary.remove(PdfDictionaryProperties.byteRange); - PdfSignatureDictionary.fromDictionary( - crossTable.document!, - signatureDictionary, - ); - _helper.dictionary!.remove(PdfDictionaryProperties.contents); - _helper.dictionary!.remove(PdfDictionaryProperties.byteRange); - } - if (signatureDictionary.containsKey(PdfDictionaryProperties.m) && - signatureDictionary[PdfDictionaryProperties.m] is PdfString) { - PdfSignatureHelper.getHelper(_signature!).dateOfSign = _helper - .dictionary! - .getDateTime( - signatureDictionary[PdfDictionaryProperties.m]! as PdfString, - ); - } - if (signatureDictionary.containsKey(PdfDictionaryProperties.name) && - signatureDictionary[PdfDictionaryProperties.name] is PdfString) { - _signature!.signedName = - (signatureDictionary[PdfDictionaryProperties.name]! as PdfString) - .value; - } - if (signatureDictionary.containsKey(PdfDictionaryProperties.reason)) { - final IPdfPrimitive? reason = PdfCrossTable.dereference( - signatureDictionary[PdfDictionaryProperties.reason], - ); - if (reason != null && reason is PdfString) { - _signature!.reason = reason.value; - } - } - if (signatureDictionary.containsKey(PdfDictionaryProperties.location)) { - final IPdfPrimitive? location = PdfCrossTable.dereference( - signatureDictionary[PdfDictionaryProperties.location], - ); - if (location != null && location is PdfString) { - _signature!.locationInfo = location.value; - } - } - if (signatureDictionary.containsKey( - PdfDictionaryProperties.contactInfo, - )) { - final IPdfPrimitive? contactInfo = PdfCrossTable.dereference( - signatureDictionary[PdfDictionaryProperties.contactInfo], - ); - if (contactInfo != null && contactInfo is PdfString) { - _signature!.contactInfo = contactInfo.value; - } - } - if (signatureDictionary.containsKey(PdfDictionaryProperties.byteRange)) { - PdfSignatureHelper.getHelper(_signature!).byteRange = - signatureDictionary[PdfDictionaryProperties.byteRange] as PdfArray?; - if (crossTable.documentCatalog != null) { - final PdfDictionary catalog = crossTable.documentCatalog!; - bool hasPermission = false; - if (catalog.containsKey(PdfDictionaryProperties.perms)) { - final IPdfPrimitive? primitive = - catalog[PdfDictionaryProperties.perms]; - final IPdfPrimitive? catalogDictionary = - (primitive is PdfReferenceHolder) - ? primitive.object - : primitive; - if (catalogDictionary != null && - catalogDictionary is PdfDictionary && - catalogDictionary.containsKey(PdfDictionaryProperties.docMDP)) { - final IPdfPrimitive? docPermission = - catalogDictionary[PdfDictionaryProperties.docMDP]; - final IPdfPrimitive? permissionDictionary = - (docPermission is PdfReferenceHolder) - ? docPermission.object - : docPermission; - if (permissionDictionary != null && - permissionDictionary is PdfDictionary && - permissionDictionary.containsKey( - PdfDictionaryProperties.byteRange, - )) { - final IPdfPrimitive? byteRange = PdfCrossTable.dereference( - permissionDictionary[PdfDictionaryProperties.byteRange], - ); - bool isValid = true; - if (byteRange != null && - byteRange is PdfArray && - _signature != null && - PdfSignatureHelper.getHelper(_signature!).byteRange != - null) { - for (int i = 0; i < byteRange.count; i++) { - final IPdfPrimitive? byteValue = byteRange[i]; - final IPdfPrimitive? signByte = - PdfSignatureHelper.getHelper(_signature!).byteRange![i]; - if (byteValue != null && - signByte != null && - byteValue is PdfNumber && - signByte is PdfNumber && - byteValue.value != signByte.value) { - isValid = false; - break; - } - } - } - hasPermission = isValid; - } - } - } - if (hasPermission && - signatureDictionary.containsKey( - PdfDictionaryProperties.reference, - )) { - IPdfPrimitive? primitive = - signatureDictionary[PdfDictionaryProperties.reference]; - if (primitive is PdfArray) { - primitive = primitive.elements[0]; - } - IPdfPrimitive? reference = - (primitive is PdfReferenceHolder) - ? primitive.object - : primitive; - if (reference != null && - reference is PdfDictionary && - reference.containsKey('TransformParams')) { - primitive = reference['TransformParams']; - if (primitive is PdfReferenceHolder) { - reference = primitive.object as PdfDictionary?; - } else if (primitive is PdfDictionary) { - reference = primitive; - } - if (reference is PdfDictionary && - reference.containsKey(PdfDictionaryProperties.p)) { - final IPdfPrimitive? permissionNumber = - PdfCrossTable.dereference( - reference[PdfDictionaryProperties.p], - ); - if (permissionNumber != null && permissionNumber is PdfNumber) { - _signature! - .documentPermissions = PdfSignatureHelper.getHelper( - _signature!, - ).getCertificateFlags(permissionNumber.value!.toInt()); - } - } - } - } - } - } - } - } -} - -/// [PdfSignatureField] helper -class PdfSignatureFieldHelper extends PdfFieldHelper { - /// internal constructor - PdfSignatureFieldHelper(this.signatureField) : super(signatureField); - - /// internal field - PdfSignatureField signatureField; - - /// internal field - bool appearance = false; - - /// internal field - bool isLoadedSign = false; - - /// internal method - static PdfSignatureFieldHelper getHelper(PdfSignatureField signatureField) { - return signatureField._helper; - } - - /// internal method - static PdfSignatureField loadSignatureField( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfSignatureField._(dictionary, crossTable); - } - - /// internal field - // ignore: prefer_final_fields - bool skipKidsCertificate = false; - - /// internal method - @override - void draw() { - if (!isLoadedField) { - if (PdfAnnotationHelper.getHelper(widget!).appearance == null && - appearance) { - PdfAnnotationHelper.getHelper(widget!).appearance = PdfAppearance( - widget!, - ); - PdfAnnotationHelper.getHelper(widget!).appearance!.normal = PdfTemplate( - signatureField.bounds.width, - signatureField.bounds.height, - ); - drawAppearance( - PdfAnnotationHelper.getHelper(widget!).appearance!.normal, - ); - } - super.draw(); - if (PdfAnnotationHelper.getHelper(widget!).appearance != null) { - signatureField.page!.graphics.drawPdfTemplate( - widget!.appearance.normal, - signatureField.bounds.topLeft, - ); - } - } else if (flattenField) { - if (!isLoadedSign && - PdfAppearanceHelper.getHelper( - signatureField.appearance, - ).templateNormal != - null) { - final PdfDictionary widget = getWidgetAnnotation( - dictionary!, - crossTable, - ); - widget.setProperty( - PdfDictionaryProperties.ap, - signatureField.appearance, - ); - } - if (dictionary![PdfDictionaryProperties.ap] != null) { - final IPdfPrimitive? tempDictionary = - dictionary![PdfDictionaryProperties.ap]; - final IPdfPrimitive? appearanceDictionary = PdfCrossTable.dereference( - tempDictionary, - ); - PdfTemplate template; - if (appearanceDictionary != null && - appearanceDictionary is PdfDictionary) { - final IPdfPrimitive? appearanceRefHolder = - appearanceDictionary[PdfDictionaryProperties.n]; - final IPdfPrimitive? objectDictionary = PdfCrossTable.dereference( - appearanceRefHolder, - ); - if (objectDictionary != null && objectDictionary is PdfDictionary) { - if (objectDictionary is PdfStream && - objectDictionary.dataStream != null && - objectDictionary.dataStream!.isNotEmpty && - (isLoadedSign || (!isLoadedSign && !appearance))) { - final PdfStream stream = objectDictionary; - template = _drawRotatedTemplate( - PdfTemplateHelper.fromPdfStream(stream), - ); - signatureField.page!.graphics.drawPdfTemplate( - template, - signatureField.bounds.topLeft, - ); - } else { - drawRectangularControl(); - } - } - } - } else { - drawRectangularControl(); - } - } - } - - PdfTemplate _drawRotatedTemplate(PdfTemplate template) { - final PdfStream content = PdfTemplateHelper.getHelper(template).content; - if (content.containsKey(PdfDictionaryProperties.matrix)) { - final IPdfPrimitive? matrix = PdfCrossTable.dereference( - content[PdfDictionaryProperties.matrix], - ); - if (matrix != null && matrix is PdfArray) { - final int angle = _obtainGraphicsRotation( - (matrix.elements[2]! as PdfNumber).value!, - (matrix.elements[0]! as PdfNumber).value!, - ); - if (angle != 0) { - PdfAnnotationHelper.setMatrixToZeroRotation(content); - final PdfTemplate rotatedTemplate = PdfTemplate( - template.size.width, - template.size.height, - ); - rotatedTemplate.graphics!.save(); - if (angle == 90) { - rotatedTemplate.graphics!.translateTransform( - 0, - template.size.height, - ); - rotatedTemplate.graphics!.rotateTransform(-90); - rotatedTemplate.graphics!.drawPdfTemplate( - template, - Offset.zero, - Size(template.size.height, template.size.width), - ); - } else if (angle == 180) { - rotatedTemplate.graphics!.translateTransform( - template.size.width, - template.size.height, - ); - rotatedTemplate.graphics!.rotateTransform(-180); - rotatedTemplate.graphics!.drawPdfTemplate( - template, - Offset.zero, - template.size, - ); - } else if (angle == 270) { - rotatedTemplate.graphics!.translateTransform( - template.size.width, - 0, - ); - rotatedTemplate.graphics!.rotateTransform(-270); - rotatedTemplate.graphics!.drawPdfTemplate( - template, - Offset.zero, - Size(template.size.height, template.size.width), - ); - } - rotatedTemplate.graphics!.restore(); - return rotatedTemplate; - } - } - } - return template; - } - - int _obtainGraphicsRotation(num a, num b) { - int angle = 0; - final double radians = atan2(a, b); - angle = (radians * 180 / pi).round(); - switch (angle) { - case -90: - angle = 90; - break; - case -180: - angle = 180; - break; - case 90: - angle = 270; - break; - } - return angle; - } - - /// internal method - void drawRectangularControl() { - if (!isLoadedSign && appearance) { - final PaintParams params = PaintParams( - bounds: signatureField.bounds, - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: signatureField.borderStyle, - borderWidth: signatureField.borderWidth, - shadowBrush: shadowBrush, - ); - FieldPainter().drawSignature(signatureField.page!.graphics, params); - } - } - - /// internal method - @override - void drawAppearance(PdfTemplate template) { - super.drawAppearance(template); - if (appearance) { - final PaintParams params = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - signatureField.bounds.width, - signatureField.bounds.height, - ), - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: signatureField.borderStyle, - borderWidth: signatureField.borderWidth, - shadowBrush: shadowBrush, - ); - FieldPainter().drawSignature(template.graphics!, params); - } else { - FieldPainter().drawSignature( - template.graphics!, - PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - signatureField.bounds.width, - signatureField.bounds.height, - ), - ), - ); - } - } - - /// internal method - @override - void beginSave() { - if (!isLoadedSign && - appearance && - PdfAppearanceHelper.getHelper( - signatureField.appearance, - ).templateNormal == - null) { - signatureField.appearance.normal = PdfTemplate( - signatureField.bounds.width, - signatureField.bounds.height, - ); - drawAppearance(signatureField.appearance.normal); - final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); - widget.setProperty(PdfDictionaryProperties.ap, signatureField.appearance); - } - } -} +import 'dart:math'; +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/pdf_annotation.dart'; +import '../annotations/pdf_appearance.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_color.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_main_object_collection.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import '../security/digital_signature/pdf_signature.dart'; +import '../security/digital_signature/pdf_signature_dictionary.dart'; +import '../security/enum.dart'; +import 'enum.dart'; +import 'pdf_field.dart'; +import 'pdf_field_painter.dart'; +import 'pdf_form.dart'; + +/// Represents signature field in the PDF Form. +class PdfSignatureField extends PdfField { + //Constructor + /// Initializes a new instance of the [PdfSignatureField] class. + PdfSignatureField( + PdfPage page, + String name, { + Rect bounds = Rect.zero, + int? borderWidth, + PdfHighlightMode? highlightMode, + PdfSignature? signature, + String? tooltip, + PdfColor? backColor, + PdfColor? borderColor, + PdfBorderStyle? borderStyle, + }) { + _helper = PdfSignatureFieldHelper(this); + _helper.internal( + page, + name, + bounds, + borderWidth: borderWidth, + highlightMode: highlightMode, + tooltip: tooltip, + backColor: backColor, + borderColor: borderColor, + borderStyle: borderStyle, + ); + form!.fieldAutoNaming + ? PdfAnnotationHelper.getHelper( + _helper.widget!, + ).dictionary!.setProperty( + PdfDictionaryProperties.ft, + PdfName(PdfDictionaryProperties.sig), + ) + : _helper.dictionary!.setProperty( + PdfDictionaryProperties.ft, + PdfName(PdfDictionaryProperties.sig), + ); + if (PdfPageHelper.getHelper(page).document != null) { + PdfFormHelper.getHelper(form!).signatureFlags = [ + SignatureFlags.signaturesExists, + SignatureFlags.appendOnly, + ]; + } + if (signature != null) { + this.signature = signature; + } + if (borderWidth != null || + borderColor != null || + backColor != null || + borderStyle != null) { + _helper.appearance = true; + } + } + + PdfSignatureField._(PdfDictionary dictionary, PdfCrossTable crossTable) { + _helper = PdfSignatureFieldHelper(this); + _helper.load(dictionary, crossTable); + if (dictionary.containsKey(PdfDictionaryProperties.v)) { + _helper.isLoadedSign = true; + } + } + + //Fields + late PdfSignatureFieldHelper _helper; + PdfSignature? _signature; + + //Properties + /// Gets or sets the width of the border. + /// + /// The default value is 1. + int get borderWidth => _helper.borderWidth; + set borderWidth(int value) { + _helper.appearance = true; + _helper.borderWidth = value; + } + + /// Gets or sets the highlighting mode. + /// + /// The default mode is invert. + PdfHighlightMode get highlightMode => _helper.highlightMode; + set highlightMode(PdfHighlightMode value) { + _helper.highlightMode = value; + } + + ///Gets the visual appearance of the field + PdfAppearance get appearance => _helper.widget!.appearance; + + /// Gets or sets the digital signature for signing the field. + PdfSignature? get signature { + if (_helper.isLoadedField && _signature == null) { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + _setSignature(_helper.dictionary![PdfDictionaryProperties.v]); + PdfSignatureHelper.getHelper(_signature!).field = this; + } + } + return _signature; + } + + set signature(PdfSignature? value) { + _initializeSignature(value); + } + + /// Gets or sets the color of the background. + /// + /// The default color is empty. + PdfColor get backColor => _helper.backColor; + set backColor(PdfColor value) { + _helper.appearance = true; + _helper.backColor = value; + _helper.assignBackColor(value); + } + + /// Gets or sets the color of the border. + /// + /// The default color is black. + PdfColor get borderColor => _helper.borderColor; + set borderColor(PdfColor value) { + _helper.appearance = true; + _helper.borderColor = value; + _helper.assignBorderColor(value); + } + + /// Gets or sets the border style. + /// + /// The default style is solid. + PdfBorderStyle get borderStyle => _helper.borderStyle; + set borderStyle(PdfBorderStyle value) { + _helper.appearance = true; + _helper.borderStyle = value; + } + + /// Checks whether the signature field is signed or not. + /// + /// ``` dart + /// // Load the existing PDF document. + /// PdfDocument document = + /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + /// // Create a new PDF document. + /// PdfSignatureField field = document.form.fields[0] as PdfSignatureField; + /// // Check if field is signed. + /// bool isSigned = field.isSigned; + /// // Dispose the document. + /// document.dispose(); + /// ``` + bool get isSigned => _helper.isLoadedSign; + + //Implementations + void _initializeSignature(PdfSignature? value) { + if (value != null) { + _signature = value; + PdfSignatureHelper.getHelper(_signature!).page = page; + PdfSignatureHelper.getHelper(_signature!).document = + PdfPageHelper.getHelper( + PdfSignatureHelper.getHelper(_signature!).page!, + ).document; + PdfSignatureHelper.getHelper( + _signature!, + ).checkAnnotationElementsContainsSignature(page!, name); + PdfSignatureHelper.getHelper(_signature!).field = this; + PdfDocumentHelper.getHelper( + PdfSignatureHelper.getHelper(_signature!).document!, + ).catalog.beginSave = + PdfSignatureHelper.getHelper(_signature!).catalogBeginSave; + _helper.dictionary!.beginSaveList ??= []; + _helper.dictionary!.beginSaveList!.add( + PdfSignatureHelper.getHelper(_signature!).dictionaryBeginSave, + ); + if (!_helper.skipKidsCertificate) { + final PdfDocument document = + PdfSignatureHelper.getHelper(_signature!).document!; + PdfSignatureHelper.getHelper( + _signature!, + ).signatureDictionary = PdfSignatureDictionary(document, _signature!); + final PdfSignatureDictionary signatureDictionary = + PdfSignatureHelper.getHelper(_signature!).signatureDictionary!; + if (!PdfDocumentHelper.getHelper(document).isLoadedDocument || + document.fileStructure.incrementalUpdate != false) { + signatureDictionary.dictionary!.archive = false; + PdfDocumentHelper.getHelper( + document, + ).objects.add(signatureDictionary.element); + PdfDocumentHelper.getHelper(document) + .objects[PdfDocumentHelper.getHelper(document).objects.count - 1] + .isModified = true; + signatureDictionary.element!.position = -1; + } + if (_helper.isLoadedField) { + PdfFormHelper.getHelper(form!).signatureFlags = [ + SignatureFlags.signaturesExists, + SignatureFlags.appendOnly, + ]; + final PdfDictionary widget = _helper.getWidgetAnnotation( + _helper.dictionary!, + _helper.crossTable, + ); + widget[PdfDictionaryProperties.v] = PdfReferenceHolder( + signatureDictionary, + ); + widget.modify(); + _helper.changed = true; + widget.setProperty(PdfDictionaryProperties.fieldFlags, PdfNumber(0)); + signatureDictionary.dictionary!.archive = false; + } else { + final PdfDictionary widget = + PdfAnnotationHelper.getHelper(_helper.widget!).dictionary!; + widget.setProperty( + PdfDictionaryProperties.v, + PdfReferenceHolder(signatureDictionary), + ); + widget.setProperty(PdfDictionaryProperties.fieldFlags, PdfNumber(0)); + } + } else { + PdfAnnotationHelper.getHelper(_helper.widget!).dictionary!.setProperty( + PdfDictionaryProperties.fieldFlags, + PdfNumber(0), + ); + } + _helper.widget!.bounds = bounds; + } + } + + void _setSignature(IPdfPrimitive? signature) { + final PdfCrossTable? crossTable = _helper.crossTable; + if (signature is PdfReferenceHolder && + signature.object != null && + signature.object is PdfDictionary) { + final PdfDictionary signatureDictionary = + signature.object! as PdfDictionary; + _signature = PdfSignature(); + PdfSignatureHelper.getHelper(_signature!).document = crossTable!.document; + String? subFilterType = ''; + if (signatureDictionary.containsKey(PdfDictionaryProperties.subFilter)) { + final IPdfPrimitive? filter = PdfCrossTable.dereference( + signatureDictionary[PdfDictionaryProperties.subFilter], + ); + if (filter != null && filter is PdfName) { + subFilterType = filter.name; + } + if (subFilterType == 'ETSI.CAdES.detached') { + _signature!.cryptographicStandard = CryptographicStandard.cades; + } + } + if (crossTable.document != null && + !PdfDocumentHelper.getHelper(crossTable.document!).isLoadedDocument) { + if (signatureDictionary.containsKey( + PdfDictionaryProperties.reference, + )) { + final IPdfPrimitive? tempArray = + signatureDictionary[PdfDictionaryProperties.reference]; + if (tempArray != null && tempArray is PdfArray) { + final IPdfPrimitive? tempDictionary = tempArray.elements[0]; + if (tempDictionary != null && tempDictionary is PdfDictionary) { + if (tempDictionary.containsKey(PdfDictionaryProperties.data)) { + final PdfMainObjectCollection mainObjectCollection = + PdfDocumentHelper.getHelper(crossTable.document!).objects; + IPdfPrimitive? tempReferenceHolder = + tempDictionary[PdfDictionaryProperties.data]; + if (tempReferenceHolder != null && + tempReferenceHolder is PdfReferenceHolder && + !mainObjectCollection.containsReference( + tempReferenceHolder.reference!, + )) { + final IPdfPrimitive? tempObject = + mainObjectCollection + .objectCollection![tempReferenceHolder + .reference! + .objectCollectionIndex!] + .object; + tempReferenceHolder = PdfReferenceHolder(tempObject); + tempDictionary.setProperty( + PdfDictionaryProperties.data, + tempReferenceHolder, + ); + } + } + } + } + } + signatureDictionary.remove(PdfDictionaryProperties.byteRange); + PdfSignatureDictionary.fromDictionary( + crossTable.document!, + signatureDictionary, + ); + _helper.dictionary!.remove(PdfDictionaryProperties.contents); + _helper.dictionary!.remove(PdfDictionaryProperties.byteRange); + } + if (signatureDictionary.containsKey(PdfDictionaryProperties.m) && + signatureDictionary[PdfDictionaryProperties.m] is PdfString) { + PdfSignatureHelper.getHelper(_signature!).dateOfSign = _helper + .dictionary! + .getDateTime( + signatureDictionary[PdfDictionaryProperties.m]! as PdfString, + ); + } + if (signatureDictionary.containsKey(PdfDictionaryProperties.name) && + signatureDictionary[PdfDictionaryProperties.name] is PdfString) { + _signature!.signedName = + (signatureDictionary[PdfDictionaryProperties.name]! as PdfString) + .value; + } + if (signatureDictionary.containsKey(PdfDictionaryProperties.reason)) { + final IPdfPrimitive? reason = PdfCrossTable.dereference( + signatureDictionary[PdfDictionaryProperties.reason], + ); + if (reason != null && reason is PdfString) { + _signature!.reason = reason.value; + } + } + if (signatureDictionary.containsKey(PdfDictionaryProperties.location)) { + final IPdfPrimitive? location = PdfCrossTable.dereference( + signatureDictionary[PdfDictionaryProperties.location], + ); + if (location != null && location is PdfString) { + _signature!.locationInfo = location.value; + } + } + if (signatureDictionary.containsKey( + PdfDictionaryProperties.contactInfo, + )) { + final IPdfPrimitive? contactInfo = PdfCrossTable.dereference( + signatureDictionary[PdfDictionaryProperties.contactInfo], + ); + if (contactInfo != null && contactInfo is PdfString) { + _signature!.contactInfo = contactInfo.value; + } + } + if (signatureDictionary.containsKey(PdfDictionaryProperties.byteRange)) { + PdfSignatureHelper.getHelper(_signature!).byteRange = + signatureDictionary[PdfDictionaryProperties.byteRange] as PdfArray?; + if (crossTable.documentCatalog != null) { + final PdfDictionary catalog = crossTable.documentCatalog!; + bool hasPermission = false; + if (catalog.containsKey(PdfDictionaryProperties.perms)) { + final IPdfPrimitive? primitive = + catalog[PdfDictionaryProperties.perms]; + final IPdfPrimitive? catalogDictionary = + (primitive is PdfReferenceHolder) + ? primitive.object + : primitive; + if (catalogDictionary != null && + catalogDictionary is PdfDictionary && + catalogDictionary.containsKey(PdfDictionaryProperties.docMDP)) { + final IPdfPrimitive? docPermission = + catalogDictionary[PdfDictionaryProperties.docMDP]; + final IPdfPrimitive? permissionDictionary = + (docPermission is PdfReferenceHolder) + ? docPermission.object + : docPermission; + if (permissionDictionary != null && + permissionDictionary is PdfDictionary && + permissionDictionary.containsKey( + PdfDictionaryProperties.byteRange, + )) { + final IPdfPrimitive? byteRange = PdfCrossTable.dereference( + permissionDictionary[PdfDictionaryProperties.byteRange], + ); + bool isValid = true; + if (byteRange != null && + byteRange is PdfArray && + _signature != null && + PdfSignatureHelper.getHelper(_signature!).byteRange != + null) { + for (int i = 0; i < byteRange.count; i++) { + final IPdfPrimitive? byteValue = byteRange[i]; + final IPdfPrimitive? signByte = + PdfSignatureHelper.getHelper(_signature!).byteRange![i]; + if (byteValue != null && + signByte != null && + byteValue is PdfNumber && + signByte is PdfNumber && + byteValue.value != signByte.value) { + isValid = false; + break; + } + } + } + hasPermission = isValid; + } + } + } + if (hasPermission && + signatureDictionary.containsKey( + PdfDictionaryProperties.reference, + )) { + IPdfPrimitive? primitive = + signatureDictionary[PdfDictionaryProperties.reference]; + if (primitive is PdfArray) { + primitive = primitive.elements[0]; + } + IPdfPrimitive? reference = + (primitive is PdfReferenceHolder) + ? primitive.object + : primitive; + if (reference != null && + reference is PdfDictionary && + reference.containsKey('TransformParams')) { + primitive = reference['TransformParams']; + if (primitive is PdfReferenceHolder) { + reference = primitive.object as PdfDictionary?; + } else if (primitive is PdfDictionary) { + reference = primitive; + } + if (reference is PdfDictionary && + reference.containsKey(PdfDictionaryProperties.p)) { + final IPdfPrimitive? permissionNumber = + PdfCrossTable.dereference( + reference[PdfDictionaryProperties.p], + ); + if (permissionNumber != null && permissionNumber is PdfNumber) { + _signature! + .documentPermissions = PdfSignatureHelper.getHelper( + _signature!, + ).getCertificateFlags(permissionNumber.value!.toInt()); + } + } + } + } + } + } + } + } +} + +/// [PdfSignatureField] helper +class PdfSignatureFieldHelper extends PdfFieldHelper { + /// internal constructor + PdfSignatureFieldHelper(this.signatureField) : super(signatureField); + + /// internal field + PdfSignatureField signatureField; + + /// internal field + bool appearance = false; + + /// internal field + bool isLoadedSign = false; + + /// internal method + static PdfSignatureFieldHelper getHelper(PdfSignatureField signatureField) { + return signatureField._helper; + } + + /// internal method + static PdfSignatureField loadSignatureField( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfSignatureField._(dictionary, crossTable); + } + + /// internal field + // ignore: prefer_final_fields + bool skipKidsCertificate = false; + + /// internal method + @override + void draw() { + if (!isLoadedField) { + if (PdfAnnotationHelper.getHelper(widget!).appearance == null && + appearance) { + PdfAnnotationHelper.getHelper(widget!).appearance = PdfAppearance( + widget!, + ); + PdfAnnotationHelper.getHelper(widget!).appearance!.normal = PdfTemplate( + signatureField.bounds.width, + signatureField.bounds.height, + ); + drawAppearance( + PdfAnnotationHelper.getHelper(widget!).appearance!.normal, + ); + } + super.draw(); + if (PdfAnnotationHelper.getHelper(widget!).appearance != null) { + signatureField.page!.graphics.drawPdfTemplate( + widget!.appearance.normal, + signatureField.bounds.topLeft, + ); + } + } else if (flattenField) { + if (!isLoadedSign && + PdfAppearanceHelper.getHelper( + signatureField.appearance, + ).templateNormal != + null) { + final PdfDictionary widget = getWidgetAnnotation( + dictionary!, + crossTable, + ); + widget.setProperty( + PdfDictionaryProperties.ap, + signatureField.appearance, + ); + } + if (dictionary![PdfDictionaryProperties.ap] != null) { + final IPdfPrimitive? tempDictionary = + dictionary![PdfDictionaryProperties.ap]; + final IPdfPrimitive? appearanceDictionary = PdfCrossTable.dereference( + tempDictionary, + ); + PdfTemplate template; + if (appearanceDictionary != null && + appearanceDictionary is PdfDictionary) { + final IPdfPrimitive? appearanceRefHolder = + appearanceDictionary[PdfDictionaryProperties.n]; + final IPdfPrimitive? objectDictionary = PdfCrossTable.dereference( + appearanceRefHolder, + ); + if (objectDictionary != null && objectDictionary is PdfDictionary) { + if (objectDictionary is PdfStream && + objectDictionary.dataStream != null && + objectDictionary.dataStream!.isNotEmpty && + (isLoadedSign || (!isLoadedSign && !appearance))) { + final PdfStream stream = objectDictionary; + template = _drawRotatedTemplate( + PdfTemplateHelper.fromPdfStream(stream), + ); + signatureField.page!.graphics.drawPdfTemplate( + template, + signatureField.bounds.topLeft, + ); + } else { + drawRectangularControl(); + } + } + } + } else { + drawRectangularControl(); + } + } + } + + PdfTemplate _drawRotatedTemplate(PdfTemplate template) { + final PdfStream content = PdfTemplateHelper.getHelper(template).content; + if (content.containsKey(PdfDictionaryProperties.matrix)) { + final IPdfPrimitive? matrix = PdfCrossTable.dereference( + content[PdfDictionaryProperties.matrix], + ); + if (matrix != null && matrix is PdfArray) { + final int angle = _obtainGraphicsRotation( + (matrix.elements[2]! as PdfNumber).value!, + (matrix.elements[0]! as PdfNumber).value!, + ); + if (angle != 0) { + PdfAnnotationHelper.setMatrixToZeroRotation(content); + final PdfTemplate rotatedTemplate = PdfTemplate( + template.size.width, + template.size.height, + ); + rotatedTemplate.graphics!.save(); + if (angle == 90) { + rotatedTemplate.graphics!.translateTransform( + 0, + template.size.height, + ); + rotatedTemplate.graphics!.rotateTransform(-90); + rotatedTemplate.graphics!.drawPdfTemplate( + template, + Offset.zero, + Size(template.size.height, template.size.width), + ); + } else if (angle == 180) { + rotatedTemplate.graphics!.translateTransform( + template.size.width, + template.size.height, + ); + rotatedTemplate.graphics!.rotateTransform(-180); + rotatedTemplate.graphics!.drawPdfTemplate( + template, + Offset.zero, + template.size, + ); + } else if (angle == 270) { + rotatedTemplate.graphics!.translateTransform( + template.size.width, + 0, + ); + rotatedTemplate.graphics!.rotateTransform(-270); + rotatedTemplate.graphics!.drawPdfTemplate( + template, + Offset.zero, + Size(template.size.height, template.size.width), + ); + } + rotatedTemplate.graphics!.restore(); + return rotatedTemplate; + } + } + } + return template; + } + + int _obtainGraphicsRotation(num a, num b) { + int angle = 0; + final double radians = atan2(a, b); + angle = (radians * 180 / pi).round(); + switch (angle) { + case -90: + angle = 90; + break; + case -180: + angle = 180; + break; + case 90: + angle = 270; + break; + } + return angle; + } + + /// internal method + void drawRectangularControl() { + if (!isLoadedSign && appearance) { + final PaintParams params = PaintParams( + bounds: signatureField.bounds, + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: signatureField.borderStyle, + borderWidth: signatureField.borderWidth, + shadowBrush: shadowBrush, + ); + FieldPainter().drawSignature(signatureField.page!.graphics, params); + } + } + + /// internal method + @override + void drawAppearance(PdfTemplate template) { + super.drawAppearance(template); + if (appearance) { + final PaintParams params = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + signatureField.bounds.width, + signatureField.bounds.height, + ), + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: signatureField.borderStyle, + borderWidth: signatureField.borderWidth, + shadowBrush: shadowBrush, + ); + FieldPainter().drawSignature(template.graphics!, params); + } else { + FieldPainter().drawSignature( + template.graphics!, + PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + signatureField.bounds.width, + signatureField.bounds.height, + ), + ), + ); + } + } + + /// internal method + @override + void beginSave() { + if (!isLoadedSign && + appearance && + PdfAppearanceHelper.getHelper( + signatureField.appearance, + ).templateNormal == + null) { + signatureField.appearance.normal = PdfTemplate( + signatureField.bounds.width, + signatureField.bounds.height, + ); + drawAppearance(signatureField.appearance.normal); + final PdfDictionary widget = getWidgetAnnotation(dictionary!, crossTable); + widget.setProperty(PdfDictionaryProperties.ap, signatureField.appearance); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_text_box_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_text_box_field.dart index a3616f65d..97bf11167 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_text_box_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_text_box_field.dart @@ -1,874 +1,874 @@ -import 'dart:convert'; -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/pdf_annotation.dart'; -import '../annotations/pdf_paintparams.dart'; -import '../graphics/enums.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/fonts/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/fonts/pdf_standard_font.dart'; -import '../graphics/fonts/pdf_string_format.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_graphics.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_field.dart'; -import 'pdf_field_item.dart'; -import 'pdf_field_item_collection.dart'; -import 'pdf_field_painter.dart'; -import 'pdf_form.dart'; - -/// Represents text box field in the PDF form. -class PdfTextBoxField extends PdfField { - //Constructor - /// Initializes a new instance of the [PdfTextBoxField] class with the provided page and name. - PdfTextBoxField( - PdfPage page, - String name, - Rect bounds, { - PdfFont? font, - String? text, - String? defaultValue, - int maxLength = 0, - bool spellCheck = false, - bool insertSpaces = false, - bool multiline = false, - bool isPassword = false, - bool scrollable = false, - PdfTextAlignment alignment = PdfTextAlignment.left, - PdfColor? borderColor, - PdfColor? foreColor, - PdfColor? backColor, - int? borderWidth, - PdfHighlightMode highlightMode = PdfHighlightMode.invert, - PdfBorderStyle borderStyle = PdfBorderStyle.solid, - String? tooltip, - }) { - _helper = PdfTextBoxFieldHelper(this); - _helper.internal( - page, - name, - bounds, - font: font, - alignment: alignment, - borderColor: borderColor, - foreColor: foreColor, - backColor: backColor, - borderWidth: borderWidth, - highlightMode: highlightMode, - borderStyle: borderStyle, - tooltip: tooltip, - ); - this.font = font ?? PdfStandardFont(PdfFontFamily.helvetica, 8); - _init( - text, - defaultValue, - maxLength, - spellCheck, - insertSpaces, - multiline, - isPassword, - scrollable, - ); - _helper.flags.add(FieldFlags.doNotSpellCheck); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.ft, - PdfName(PdfDictionaryProperties.tx), - ); - } - - /// Initializes a new instance of the [PdfTextBoxField] class. - PdfTextBoxField._load(PdfDictionary dictionary, PdfCrossTable crossTable) { - _helper = PdfTextBoxFieldHelper(this); - _helper.load(dictionary, crossTable); - _items = PdfFieldItemCollectionHelper.load(this); - final PdfArray? kids = _helper.kids; - if (kids != null) { - for (int i = 0; i < kids.count; ++i) { - final PdfDictionary? itemDictionary = - crossTable.getObject(kids[i]) as PdfDictionary?; - PdfFieldItemCollectionHelper.getHelper( - _items!, - ).add(PdfTextBoxItemHelper.getItem(this, i, itemDictionary)); - } - _helper.array = kids; - } - } - - //Fields - late PdfTextBoxFieldHelper _helper; - String? _text = ''; - String? _defaultValue = ''; - bool _spellCheck = false; - bool _insertSpaces = false; - bool _multiline = false; - bool _password = false; - bool _scrollable = true; - int _maxLength = 0; - PdfFieldItemCollection? _items; - - //Properties - /// Gets or sets the text in the text box. - String get text { - if (_helper.isLoadedField) { - IPdfPrimitive? str; - final IPdfPrimitive? referenceHolder = - _helper.dictionary![PdfDictionaryProperties.v]; - if (referenceHolder != null && referenceHolder is PdfReferenceHolder) { - final IPdfPrimitive? textObject = PdfCrossTable.dereference( - referenceHolder, - ); - if (textObject is PdfStream) { - final PdfStream stream = referenceHolder.object! as PdfStream; - stream.decompress(); - final List bytes = stream.dataStream!; - final String data = utf8.decode(bytes); - str = PdfString(data); - } else if (textObject is PdfString) { - str = PdfFieldHelper.getValue( - _helper.dictionary!, - _helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - } else { - str = PdfString(''); - } - } else { - str = PdfFieldHelper.getValue( - _helper.dictionary!, - _helper.crossTable, - PdfDictionaryProperties.v, - true, - ); - } - _text = str != null && str is PdfString ? str.value : ''; - return _text!; - } - return _text!; - } - - set text(String value) { - if (_helper.isLoadedField) { - //check if not readOnly. - if (!_helper.isFlagPresent(FieldFlags.readOnly)) { - _helper.isTextChanged = true; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.aa)) { - final IPdfPrimitive? dic = - _helper.dictionary![PdfDictionaryProperties.aa]; - if (dic != null && dic is PdfDictionary) { - final IPdfPrimitive? dicRef = dic[PdfDictionaryProperties.k]; - if (dicRef != null && dicRef is PdfReferenceHolder) { - final IPdfPrimitive? dict = dicRef.object; - if (dict != null && dict is PdfDictionary) { - final IPdfPrimitive? str = PdfCrossTable.dereference( - dict['JS'], - ); - if (str != null && str is PdfString) { - _helper.dictionary!.setProperty( - PdfDictionaryProperties.v, - PdfString(str.value!), - ); - } - } - } - } - } - _helper.dictionary!.setProperty( - PdfDictionaryProperties.v, - PdfString(value), - ); - _helper.changed = true; - PdfFormHelper.getHelper(super.form!).setAppearanceDictionary = true; - if (PdfFormHelper.getHelper(super.form!).isUR3) { - _helper.dictionary!.beginSaveList ??= []; - _helper.dictionary!.beginSaveList!.add(_dictSave); - } - } else { - _helper.changed = false; - } - } else { - if (_text != value) { - _text = value; - _helper.dictionary!.setString(PdfDictionaryProperties.v, _text); - } - } - } - - /// Gets or sets the font. - PdfFont get font => _helper.font!; - set font(PdfFont? value) { - _helper.font = value; - } - - /// Gets or sets the default value. - String get defaultValue { - if (_helper.isLoadedField) { - final IPdfPrimitive? str = PdfFieldHelper.getValue( - _helper.dictionary!, - _helper.crossTable, - PdfDictionaryProperties.dv, - true, - ); - if (str != null && str is PdfString) { - _defaultValue = str.value; - } - } - return _defaultValue!; - } - - set defaultValue(String value) { - if (defaultValue != value) { - _defaultValue = value; - _helper.dictionary!.setString(PdfDictionaryProperties.dv, _defaultValue); - if (_helper.isLoadedField) { - _helper.changed = true; - } - } - } - - /// Gets or sets the maximum number of characters that can be entered in the text box. - /// - /// The default value is 0. - int get maxLength { - if (_helper.isLoadedField) { - final IPdfPrimitive? number = PdfFieldHelper.getValue( - _helper.dictionary!, - _helper.crossTable, - PdfDictionaryProperties.maxLen, - true, - ); - if (number != null && number is PdfNumber) { - _maxLength = number.value!.toInt(); - } - } - return _maxLength; - } - - set maxLength(int value) { - if (maxLength != value) { - _maxLength = value; - _helper.dictionary!.setNumber(PdfDictionaryProperties.maxLen, _maxLength); - if (_helper.isLoadedField) { - _helper.changed = true; - } - } - } - - /// Gets or sets a value indicating whether to check spelling. - /// - /// The default value is false. - bool get spellCheck { - if (_helper.isLoadedField) { - _spellCheck = - !(_helper.isFlagPresent(FieldFlags.doNotSpellCheck) || - _helper.flags.contains(FieldFlags.doNotSpellCheck)); - } - return _spellCheck; - } - - set spellCheck(bool value) { - if (spellCheck != value) { - _spellCheck = value; - _spellCheck - ? _helper.isLoadedField - ? _helper.removeFlag(FieldFlags.doNotSpellCheck) - : _helper.flags.remove(FieldFlags.doNotSpellCheck) - : _helper.flags.add(FieldFlags.doNotSpellCheck); - } - } - - /// Meaningful only if the maxLength property is set and the multiline, isPassword properties are false. - /// - /// If set, the field is automatically divided into as many equally spaced positions, or combs, - /// as the value of maxLength, and the text is laid out into those combs. - /// - /// The default value is false. - bool get insertSpaces { - final List flags = _helper.flags; - _insertSpaces = - flags.contains(FieldFlags.comb) && - !flags.contains(FieldFlags.multiline) && - !flags.contains(FieldFlags.password) && - !flags.contains(FieldFlags.fileSelect); - if (_helper.isLoadedField) { - _insertSpaces = - _insertSpaces || - (_helper.isFlagPresent(FieldFlags.comb) && - !_helper.isFlagPresent(FieldFlags.multiline) && - !_helper.isFlagPresent(FieldFlags.password) && - !_helper.isFlagPresent(FieldFlags.fileSelect)); - } - return _insertSpaces; - } - - set insertSpaces(bool value) { - if (insertSpaces != value) { - _insertSpaces = value; - _insertSpaces - ? _helper.flags.add(FieldFlags.comb) - : _helper.isLoadedField - ? _helper.removeFlag(FieldFlags.comb) - : _helper.flags.remove(FieldFlags.comb); - } - } - - /// Gets or sets a value indicating whether this [PdfTextBoxField] is multiline. - /// - /// The default value is false. - bool get multiline { - if (_helper.isLoadedField) { - _multiline = - _helper.isFlagPresent(FieldFlags.multiline) || - _helper.flags.contains(FieldFlags.multiline); - } - return _multiline; - } - - set multiline(bool value) { - if (multiline != value) { - _multiline = value; - if (_multiline) { - _helper.flags.add(FieldFlags.multiline); - _helper.format!.lineAlignment = PdfVerticalAlignment.top; - } else { - _helper.isLoadedField - ? _helper.removeFlag(FieldFlags.multiline) - : _helper.flags.remove(FieldFlags.multiline); - _helper.format!.lineAlignment = PdfVerticalAlignment.middle; - } - } - } - - /// Gets or sets a value indicating whether this [PdfTextBoxField] is password field. - /// - /// The default value is false. - bool get isPassword { - if (_helper.isLoadedField) { - _password = - _helper.isFlagPresent(FieldFlags.password) || - _helper.flags.contains(FieldFlags.password); - } - return _password; - } - - set isPassword(bool value) { - if (isPassword != value) { - _password = value; - _password - ? _helper.flags.add(FieldFlags.password) - : _helper.isLoadedField - ? _helper.removeFlag(FieldFlags.password) - : _helper.flags.remove(FieldFlags.password); - } - } - - /// Gets or sets a value indicating whether this [PdfTextBoxField] is scrollable. - /// - /// The default value is true. - bool get scrollable { - if (_helper.isLoadedField) { - _scrollable = - !(_helper.isFlagPresent(FieldFlags.doNotScroll) || - _helper.flags.contains(FieldFlags.doNotScroll)); - } - return _scrollable; - } - - set scrollable(bool value) { - if (scrollable != value) { - _scrollable = value; - _spellCheck - ? _helper.isLoadedField - ? _helper.removeFlag(FieldFlags.doNotScroll) - : _helper.flags.remove(FieldFlags.doNotScroll) - : _helper.flags.add(FieldFlags.doNotScroll); - } - } - - /// Gets or sets the text alignment. - /// - /// The default alignment is left. - PdfTextAlignment get textAlignment => _helper.textAlignment; - set textAlignment(PdfTextAlignment value) { - _helper.textAlignment = value; - } - - /// Gets or sets the color of the border. - /// - /// The default color is black. - PdfColor get borderColor => _helper.borderColor; - set borderColor(PdfColor value) { - _helper.borderColor = value; - } - - /// Gets or sets the color of the background. - /// - /// The default color is empty. - PdfColor get backColor => _helper.backColor; - set backColor(PdfColor value) { - _helper.backColor = value; - } - - /// Gets or sets the color of the text. - /// - /// The default color is black. - PdfColor get foreColor => _helper.foreColor; - set foreColor(PdfColor value) { - _helper.foreColor = value; - } - - /// Gets or sets the width of the border. - /// - /// The default value is 1. - int get borderWidth => _helper.borderWidth; - set borderWidth(int value) { - _helper.borderWidth = value; - } - - /// Gets or sets the highlighting mode. - /// - /// The default mode is invert. - PdfHighlightMode get highlightMode => _helper.highlightMode; - set highlightMode(PdfHighlightMode value) { - _helper.highlightMode = value; - } - - /// Gets or sets the border style. - /// - /// The default style is solid. - PdfBorderStyle get borderStyle => _helper.borderStyle; - set borderStyle(PdfBorderStyle value) { - _helper.borderStyle = value; - } - - /// Gets the collection of text box field items. - PdfFieldItemCollection? get items => _items; - - //Implementations - - void _dictSave(Object sender, SavePdfPrimitiveArgs? ars) { - _helper.beginSave(); - } - - void _init( - String? text, - String? defaultValue, - int maxLength, - bool spellCheck, - bool insertSpaces, - bool multiline, - bool password, - bool scrollable, - ) { - if (text != null) { - this.text = text; - } - if (defaultValue != null) { - this.defaultValue = defaultValue; - } - this.maxLength = maxLength; - this.spellCheck = spellCheck; - this.insertSpaces = insertSpaces; - this.multiline = multiline; - isPassword = password; - this.scrollable = scrollable; - } - - void _drawTextBox( - PdfGraphics? graphics, { - PaintParams? params, - PdfFieldItem? item, - }) { - if (params != null) { - String newText = text; - if (isPassword && text.isNotEmpty) { - newText = ''; - for (int i = 0; i < text.length; ++i) { - newText += '*'; - } - } - graphics!.save(); - if (insertSpaces) { - double width = 0; - final List ch = text.split(''); - if (maxLength > 0) { - width = params.bounds!.width / maxLength; - graphics.drawRectangle( - bounds: params.bounds!, - pen: _helper.borderPen, - ); - for (int i = 0; i < maxLength; i++) { - if (_helper.format!.alignment != PdfTextAlignment.right) { - if (_helper.format!.alignment == PdfTextAlignment.center && - ch.length < maxLength) { - final int startLocation = - (maxLength / 2 - (ch.length / 2).ceil()).toInt(); - newText = - i >= startLocation && i < startLocation + ch.length - ? ch[i - startLocation] - : ''; - } else { - newText = ch.length > i ? ch[i] : ''; - } - } else { - newText = - maxLength - ch.length <= i - ? ch[i - (maxLength - ch.length)] - : ''; - } - params.bounds = Rect.fromLTWH( - params.bounds!.left, - params.bounds!.top, - width, - params.bounds!.height, - ); - final PdfStringFormat format = PdfStringFormat( - alignment: PdfTextAlignment.center, - lineAlignment: _helper.format!.lineAlignment, - ); - FieldPainter().drawTextBox( - graphics, - params, - newText, - font, - format, - insertSpaces, - multiline, - ); - params.bounds = Rect.fromLTWH( - params.bounds!.left + width, - params.bounds!.top, - width, - params.bounds!.height, - ); - if (params.borderWidth != 0) { - graphics.drawLine( - params.borderPen!, - Offset(params.bounds!.left, params.bounds!.top), - Offset( - params.bounds!.left, - params.bounds!.top + params.bounds!.height, - ), - ); - } - } - } else { - FieldPainter().drawTextBox( - graphics, - params, - newText, - font, - _helper.format!, - insertSpaces, - multiline, - ); - } - } else { - FieldPainter().drawTextBox( - graphics, - params, - newText, - font, - _helper.format!, - insertSpaces, - multiline, - ); - } - graphics.restore(); - } else { - final GraphicsProperties gp = - item != null - ? GraphicsProperties.fromFieldItem(item) - : GraphicsProperties(this); - if (gp.borderWidth == 0 && gp.borderPen != null) { - gp.borderWidth = 1; - gp.borderPen!.width = 1; - } - if (PdfGraphicsHelper.getHelper(graphics!).layer == null) { - gp.bounds = Rect.fromLTWH( - gp.bounds!.left, - gp.bounds!.top, - graphics.size.width, - graphics.size.height, - ); - } - if (!_helper.flattenField) { - gp.bounds = Rect.fromLTWH(0, 0, gp.bounds!.width, gp.bounds!.height); - } - final PaintParams prms = PaintParams( - bounds: gp.bounds, - backBrush: gp.backBrush, - foreBrush: gp.foreBrush, - borderPen: gp.borderPen, - style: gp.style, - borderWidth: gp.borderWidth, - shadowBrush: gp.shadowBrush, - ); - _drawTextBox(graphics, params: prms); - } - } - - void _applyAppearance(PdfDictionary? widget, [PdfFieldItem? item]) { - if (PdfFormHelper.getHelper(super.form!).setAppearanceDictionary) { - if (widget != null && - !PdfFormHelper.getHelper(super.form!).needAppearances!) { - final PdfDictionary appearance = PdfDictionary(); - final Rect bounds = item == null ? this.bounds : item.bounds; - PdfTemplate? template; - if (widget.containsKey(PdfDictionaryProperties.mk)) { - final IPdfPrimitive? mkDic = widget[PdfDictionaryProperties.mk]; - if (mkDic != null && - mkDic is PdfDictionary && - mkDic.containsKey(PdfDictionaryProperties.r)) { - final IPdfPrimitive? angle = mkDic[PdfDictionaryProperties.r]; - if (angle != null && angle is PdfNumber) { - if (angle.value == 90) { - template = PdfTemplate(bounds.size.height, bounds.size.width); - PdfTemplateHelper.getHelper( - template, - ).content[PdfDictionaryProperties.matrix] = PdfArray([ - 0, - 1, - -1, - 0, - bounds.size.width, - 0, - ]); - } else if (angle.value == 180) { - template = PdfTemplate(bounds.size.width, bounds.size.height); - PdfTemplateHelper.getHelper( - template, - ).content[PdfDictionaryProperties.matrix] = PdfArray([ - -1, - 0, - 0, - -1, - bounds.size.width, - bounds.size.height, - ]); - } else if (angle.value == 270) { - template = PdfTemplate(bounds.size.height, bounds.size.width); - PdfTemplateHelper.getHelper( - template, - ).content[PdfDictionaryProperties.matrix] = PdfArray([ - 0, - -1, - 1, - 0, - 0, - bounds.size.height, - ]); - } - if (template != null) { - PdfTemplateHelper.getHelper(template).writeTransformation = - false; - } - } - } - } - if (template == null) { - template = PdfTemplate(bounds.size.width, bounds.size.height); - PdfTemplateHelper.getHelper(template).writeTransformation = false; - PdfTemplateHelper.getHelper(template).content[PdfDictionaryProperties - .matrix] = PdfArray([1, 0, 0, 1, 0, 0]); - } - if (item != null) { - _helper.beginMarkupSequence( - PdfGraphicsHelper.getHelper( - template.graphics!, - ).streamWriter!.stream!, - ); - PdfGraphicsHelper.getHelper( - template.graphics!, - ).initializeCoordinates(); - _drawTextBox(template.graphics, item: item); - _helper.endMarkupSequence( - PdfGraphicsHelper.getHelper( - template.graphics!, - ).streamWriter!.stream!, - ); - } else { - _helper.drawAppearance(template); - } - appearance.setProperty( - PdfDictionaryProperties.n, - PdfReferenceHolder(template), - ); - widget.setProperty(PdfDictionaryProperties.ap, appearance); - } else { - PdfFormHelper.getHelper(super.form!).needAppearances = true; - } - } - } -} - -/// [PdfTextBoxField] helper -class PdfTextBoxFieldHelper extends PdfFieldHelper { - /// internal constructor - PdfTextBoxFieldHelper(this.textBoxField) : super(textBoxField); - - /// internal field - PdfTextBoxField textBoxField; - - /// internal field - // ignore: avoid_setters_without_getters - set items(PdfFieldItemCollection? value) { - textBoxField._items = value; - } - - /// internal method - static PdfTextBoxFieldHelper getHelper(PdfTextBoxField textBoxField) { - return textBoxField._helper; - } - - /// internal method - static PdfTextBoxField loadTextBox( - PdfDictionary dictionary, - PdfCrossTable crossTable, - ) { - return PdfTextBoxField._load(dictionary, crossTable); - } - - /// internal method - @override - void save() { - super.save(); - if (fieldItems != null && fieldItems!.length > 1) { - for (int i = 1; i < fieldItems!.length; i++) { - final PdfTextBoxField field = fieldItems![i] as PdfTextBoxField; - field.text = textBoxField.text; - field._helper.save(); - } - } - } - - /// internal method - @override - void drawAppearance(PdfTemplate template) { - super.drawAppearance(template); - final PaintParams params = PaintParams( - bounds: Rect.fromLTWH( - 0, - 0, - textBoxField.bounds.width, - textBoxField.bounds.height, - ), - backBrush: backBrush, - foreBrush: foreBrush, - borderPen: borderPen, - style: textBoxField.borderStyle, - borderWidth: textBoxField.borderWidth, - shadowBrush: shadowBrush, - ); - PdfTemplateHelper.getHelper(template).writeTransformation = false; - final PdfGraphics graphics = template.graphics!; - beginMarkupSequence( - PdfGraphicsHelper.getHelper(graphics).streamWriter!.stream!, - ); - PdfGraphicsHelper.getHelper(graphics).initializeCoordinates(); - if (params.borderWidth == 0 && params.borderPen != null) { - params.borderWidth = 1; - params.borderPen!.width = 1; - } - textBoxField._drawTextBox(graphics, params: params); - endMarkupSequence( - PdfGraphicsHelper.getHelper(graphics).streamWriter!.stream!, - ); - } - - /// internal method - @override - void beginSave() { - super.beginSave(); - if (kids != null) { - for (int i = 0; i < kids!.count; ++i) { - final PdfDictionary? widget = - crossTable!.getObject(kids![i]) as PdfDictionary?; - textBoxField._applyAppearance(widget, textBoxField.items![i]); - } - } else { - textBoxField._applyAppearance( - getWidgetAnnotation(dictionary!, crossTable), - ); - } - } - - /// internal method - @override - double getFontHeight(PdfFontFamily family) { - double s = 12; - if (!textBoxField.multiline) { - final PdfStandardFont font = PdfStandardFont(family, 12); - final Size fontSize = font.measureString(textBoxField.text); - s = - (8 * - (textBoxField.bounds.size.width - 4 * textBoxField.borderWidth)) / - fontSize.width; - s = (s > 8) ? 8 : s; - } else { - s = 12.5; - } - return s; - } - - /// internal method - @override - void draw() { - super.draw(); - if (!isLoadedField && - PdfAnnotationHelper.getHelper(widget!).appearance != null) { - textBoxField.page!.graphics.drawPdfTemplate( - PdfAnnotationHelper.getHelper(widget!).appearance!.normal, - Offset(textBoxField.bounds.width, textBoxField.bounds.height), - ); - if (fieldItems != null && fieldItems!.length > 1) { - for (int i = 1; i < fieldItems!.length; i++) { - final PdfTextBoxField field = fieldItems![i] as PdfTextBoxField; - field.text = textBoxField.text; - field.page!.graphics.drawPdfTemplate( - PdfAnnotationHelper.getHelper( - field._helper.widget!, - ).appearance!.normal, - Offset(field.bounds.width, field.bounds.height), - ); - } - } - } else { - if (isLoadedField) { - if (kids != null) { - for (int i = 0; i < kids!.count; ++i) { - final PdfFieldItem item = textBoxField.items![i]; - if (item.page != null && - PdfPageHelper.getHelper(item.page!).isLoadedPage) { - textBoxField._drawTextBox(item.page!.graphics, item: item); - } - } - } else { - textBoxField._drawTextBox(textBoxField.page!.graphics); - } - } else { - textBoxField._drawTextBox(textBoxField.page!.graphics); - if (fieldItems != null && fieldItems!.length > 1) { - for (int i = 1; i < fieldItems!.length; i++) { - final PdfTextBoxField field = fieldItems![i] as PdfTextBoxField; - field.text = textBoxField.text; - field._drawTextBox(field.page!.graphics); - } - } - } - } - } -} +import 'dart:convert'; +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/pdf_annotation.dart'; +import '../annotations/pdf_paintparams.dart'; +import '../graphics/enums.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/fonts/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/fonts/pdf_standard_font.dart'; +import '../graphics/fonts/pdf_string_format.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_graphics.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_field.dart'; +import 'pdf_field_item.dart'; +import 'pdf_field_item_collection.dart'; +import 'pdf_field_painter.dart'; +import 'pdf_form.dart'; + +/// Represents text box field in the PDF form. +class PdfTextBoxField extends PdfField { + //Constructor + /// Initializes a new instance of the [PdfTextBoxField] class with the provided page and name. + PdfTextBoxField( + PdfPage page, + String name, + Rect bounds, { + PdfFont? font, + String? text, + String? defaultValue, + int maxLength = 0, + bool spellCheck = false, + bool insertSpaces = false, + bool multiline = false, + bool isPassword = false, + bool scrollable = false, + PdfTextAlignment alignment = PdfTextAlignment.left, + PdfColor? borderColor, + PdfColor? foreColor, + PdfColor? backColor, + int? borderWidth, + PdfHighlightMode highlightMode = PdfHighlightMode.invert, + PdfBorderStyle borderStyle = PdfBorderStyle.solid, + String? tooltip, + }) { + _helper = PdfTextBoxFieldHelper(this); + _helper.internal( + page, + name, + bounds, + font: font, + alignment: alignment, + borderColor: borderColor, + foreColor: foreColor, + backColor: backColor, + borderWidth: borderWidth, + highlightMode: highlightMode, + borderStyle: borderStyle, + tooltip: tooltip, + ); + this.font = font ?? PdfStandardFont(PdfFontFamily.helvetica, 8); + _init( + text, + defaultValue, + maxLength, + spellCheck, + insertSpaces, + multiline, + isPassword, + scrollable, + ); + _helper.flags.add(FieldFlags.doNotSpellCheck); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.ft, + PdfName(PdfDictionaryProperties.tx), + ); + } + + /// Initializes a new instance of the [PdfTextBoxField] class. + PdfTextBoxField._load(PdfDictionary dictionary, PdfCrossTable crossTable) { + _helper = PdfTextBoxFieldHelper(this); + _helper.load(dictionary, crossTable); + _items = PdfFieldItemCollectionHelper.load(this); + final PdfArray? kids = _helper.kids; + if (kids != null) { + for (int i = 0; i < kids.count; ++i) { + final PdfDictionary? itemDictionary = + crossTable.getObject(kids[i]) as PdfDictionary?; + PdfFieldItemCollectionHelper.getHelper( + _items!, + ).add(PdfTextBoxItemHelper.getItem(this, i, itemDictionary)); + } + _helper.array = kids; + } + } + + //Fields + late PdfTextBoxFieldHelper _helper; + String? _text = ''; + String? _defaultValue = ''; + bool _spellCheck = false; + bool _insertSpaces = false; + bool _multiline = false; + bool _password = false; + bool _scrollable = true; + int _maxLength = 0; + PdfFieldItemCollection? _items; + + //Properties + /// Gets or sets the text in the text box. + String get text { + if (_helper.isLoadedField) { + IPdfPrimitive? str; + final IPdfPrimitive? referenceHolder = + _helper.dictionary![PdfDictionaryProperties.v]; + if (referenceHolder != null && referenceHolder is PdfReferenceHolder) { + final IPdfPrimitive? textObject = PdfCrossTable.dereference( + referenceHolder, + ); + if (textObject is PdfStream) { + final PdfStream stream = referenceHolder.object! as PdfStream; + stream.decompress(); + final List bytes = stream.dataStream!; + final String data = utf8.decode(bytes); + str = PdfString(data); + } else if (textObject is PdfString) { + str = PdfFieldHelper.getValue( + _helper.dictionary!, + _helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + } else { + str = PdfString(''); + } + } else { + str = PdfFieldHelper.getValue( + _helper.dictionary!, + _helper.crossTable, + PdfDictionaryProperties.v, + true, + ); + } + _text = str != null && str is PdfString ? str.value : ''; + return _text!; + } + return _text!; + } + + set text(String value) { + if (_helper.isLoadedField) { + //check if not readOnly. + if (!_helper.isFlagPresent(FieldFlags.readOnly)) { + _helper.isTextChanged = true; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.aa)) { + final IPdfPrimitive? dic = + _helper.dictionary![PdfDictionaryProperties.aa]; + if (dic != null && dic is PdfDictionary) { + final IPdfPrimitive? dicRef = dic[PdfDictionaryProperties.k]; + if (dicRef != null && dicRef is PdfReferenceHolder) { + final IPdfPrimitive? dict = dicRef.object; + if (dict != null && dict is PdfDictionary) { + final IPdfPrimitive? str = PdfCrossTable.dereference( + dict['JS'], + ); + if (str != null && str is PdfString) { + _helper.dictionary!.setProperty( + PdfDictionaryProperties.v, + PdfString(str.value!), + ); + } + } + } + } + } + _helper.dictionary!.setProperty( + PdfDictionaryProperties.v, + PdfString(value), + ); + _helper.changed = true; + PdfFormHelper.getHelper(super.form!).setAppearanceDictionary = true; + if (PdfFormHelper.getHelper(super.form!).isUR3) { + _helper.dictionary!.beginSaveList ??= []; + _helper.dictionary!.beginSaveList!.add(_dictSave); + } + } else { + _helper.changed = false; + } + } else { + if (_text != value) { + _text = value; + _helper.dictionary!.setString(PdfDictionaryProperties.v, _text); + } + } + } + + /// Gets or sets the font. + PdfFont get font => _helper.font!; + set font(PdfFont? value) { + _helper.font = value; + } + + /// Gets or sets the default value. + String get defaultValue { + if (_helper.isLoadedField) { + final IPdfPrimitive? str = PdfFieldHelper.getValue( + _helper.dictionary!, + _helper.crossTable, + PdfDictionaryProperties.dv, + true, + ); + if (str != null && str is PdfString) { + _defaultValue = str.value; + } + } + return _defaultValue!; + } + + set defaultValue(String value) { + if (defaultValue != value) { + _defaultValue = value; + _helper.dictionary!.setString(PdfDictionaryProperties.dv, _defaultValue); + if (_helper.isLoadedField) { + _helper.changed = true; + } + } + } + + /// Gets or sets the maximum number of characters that can be entered in the text box. + /// + /// The default value is 0. + int get maxLength { + if (_helper.isLoadedField) { + final IPdfPrimitive? number = PdfFieldHelper.getValue( + _helper.dictionary!, + _helper.crossTable, + PdfDictionaryProperties.maxLen, + true, + ); + if (number != null && number is PdfNumber) { + _maxLength = number.value!.toInt(); + } + } + return _maxLength; + } + + set maxLength(int value) { + if (maxLength != value) { + _maxLength = value; + _helper.dictionary!.setNumber(PdfDictionaryProperties.maxLen, _maxLength); + if (_helper.isLoadedField) { + _helper.changed = true; + } + } + } + + /// Gets or sets a value indicating whether to check spelling. + /// + /// The default value is false. + bool get spellCheck { + if (_helper.isLoadedField) { + _spellCheck = + !(_helper.isFlagPresent(FieldFlags.doNotSpellCheck) || + _helper.flags.contains(FieldFlags.doNotSpellCheck)); + } + return _spellCheck; + } + + set spellCheck(bool value) { + if (spellCheck != value) { + _spellCheck = value; + _spellCheck + ? _helper.isLoadedField + ? _helper.removeFlag(FieldFlags.doNotSpellCheck) + : _helper.flags.remove(FieldFlags.doNotSpellCheck) + : _helper.flags.add(FieldFlags.doNotSpellCheck); + } + } + + /// Meaningful only if the maxLength property is set and the multiline, isPassword properties are false. + /// + /// If set, the field is automatically divided into as many equally spaced positions, or combs, + /// as the value of maxLength, and the text is laid out into those combs. + /// + /// The default value is false. + bool get insertSpaces { + final List flags = _helper.flags; + _insertSpaces = + flags.contains(FieldFlags.comb) && + !flags.contains(FieldFlags.multiline) && + !flags.contains(FieldFlags.password) && + !flags.contains(FieldFlags.fileSelect); + if (_helper.isLoadedField) { + _insertSpaces = + _insertSpaces || + (_helper.isFlagPresent(FieldFlags.comb) && + !_helper.isFlagPresent(FieldFlags.multiline) && + !_helper.isFlagPresent(FieldFlags.password) && + !_helper.isFlagPresent(FieldFlags.fileSelect)); + } + return _insertSpaces; + } + + set insertSpaces(bool value) { + if (insertSpaces != value) { + _insertSpaces = value; + _insertSpaces + ? _helper.flags.add(FieldFlags.comb) + : _helper.isLoadedField + ? _helper.removeFlag(FieldFlags.comb) + : _helper.flags.remove(FieldFlags.comb); + } + } + + /// Gets or sets a value indicating whether this [PdfTextBoxField] is multiline. + /// + /// The default value is false. + bool get multiline { + if (_helper.isLoadedField) { + _multiline = + _helper.isFlagPresent(FieldFlags.multiline) || + _helper.flags.contains(FieldFlags.multiline); + } + return _multiline; + } + + set multiline(bool value) { + if (multiline != value) { + _multiline = value; + if (_multiline) { + _helper.flags.add(FieldFlags.multiline); + _helper.format!.lineAlignment = PdfVerticalAlignment.top; + } else { + _helper.isLoadedField + ? _helper.removeFlag(FieldFlags.multiline) + : _helper.flags.remove(FieldFlags.multiline); + _helper.format!.lineAlignment = PdfVerticalAlignment.middle; + } + } + } + + /// Gets or sets a value indicating whether this [PdfTextBoxField] is password field. + /// + /// The default value is false. + bool get isPassword { + if (_helper.isLoadedField) { + _password = + _helper.isFlagPresent(FieldFlags.password) || + _helper.flags.contains(FieldFlags.password); + } + return _password; + } + + set isPassword(bool value) { + if (isPassword != value) { + _password = value; + _password + ? _helper.flags.add(FieldFlags.password) + : _helper.isLoadedField + ? _helper.removeFlag(FieldFlags.password) + : _helper.flags.remove(FieldFlags.password); + } + } + + /// Gets or sets a value indicating whether this [PdfTextBoxField] is scrollable. + /// + /// The default value is true. + bool get scrollable { + if (_helper.isLoadedField) { + _scrollable = + !(_helper.isFlagPresent(FieldFlags.doNotScroll) || + _helper.flags.contains(FieldFlags.doNotScroll)); + } + return _scrollable; + } + + set scrollable(bool value) { + if (scrollable != value) { + _scrollable = value; + _spellCheck + ? _helper.isLoadedField + ? _helper.removeFlag(FieldFlags.doNotScroll) + : _helper.flags.remove(FieldFlags.doNotScroll) + : _helper.flags.add(FieldFlags.doNotScroll); + } + } + + /// Gets or sets the text alignment. + /// + /// The default alignment is left. + PdfTextAlignment get textAlignment => _helper.textAlignment; + set textAlignment(PdfTextAlignment value) { + _helper.textAlignment = value; + } + + /// Gets or sets the color of the border. + /// + /// The default color is black. + PdfColor get borderColor => _helper.borderColor; + set borderColor(PdfColor value) { + _helper.borderColor = value; + } + + /// Gets or sets the color of the background. + /// + /// The default color is empty. + PdfColor get backColor => _helper.backColor; + set backColor(PdfColor value) { + _helper.backColor = value; + } + + /// Gets or sets the color of the text. + /// + /// The default color is black. + PdfColor get foreColor => _helper.foreColor; + set foreColor(PdfColor value) { + _helper.foreColor = value; + } + + /// Gets or sets the width of the border. + /// + /// The default value is 1. + int get borderWidth => _helper.borderWidth; + set borderWidth(int value) { + _helper.borderWidth = value; + } + + /// Gets or sets the highlighting mode. + /// + /// The default mode is invert. + PdfHighlightMode get highlightMode => _helper.highlightMode; + set highlightMode(PdfHighlightMode value) { + _helper.highlightMode = value; + } + + /// Gets or sets the border style. + /// + /// The default style is solid. + PdfBorderStyle get borderStyle => _helper.borderStyle; + set borderStyle(PdfBorderStyle value) { + _helper.borderStyle = value; + } + + /// Gets the collection of text box field items. + PdfFieldItemCollection? get items => _items; + + //Implementations + + void _dictSave(Object sender, SavePdfPrimitiveArgs? ars) { + _helper.beginSave(); + } + + void _init( + String? text, + String? defaultValue, + int maxLength, + bool spellCheck, + bool insertSpaces, + bool multiline, + bool password, + bool scrollable, + ) { + if (text != null) { + this.text = text; + } + if (defaultValue != null) { + this.defaultValue = defaultValue; + } + this.maxLength = maxLength; + this.spellCheck = spellCheck; + this.insertSpaces = insertSpaces; + this.multiline = multiline; + isPassword = password; + this.scrollable = scrollable; + } + + void _drawTextBox( + PdfGraphics? graphics, { + PaintParams? params, + PdfFieldItem? item, + }) { + if (params != null) { + String newText = text; + if (isPassword && text.isNotEmpty) { + newText = ''; + for (int i = 0; i < text.length; ++i) { + newText += '*'; + } + } + graphics!.save(); + if (insertSpaces) { + double width = 0; + final List ch = text.split(''); + if (maxLength > 0) { + width = params.bounds!.width / maxLength; + graphics.drawRectangle( + bounds: params.bounds!, + pen: _helper.borderPen, + ); + for (int i = 0; i < maxLength; i++) { + if (_helper.format!.alignment != PdfTextAlignment.right) { + if (_helper.format!.alignment == PdfTextAlignment.center && + ch.length < maxLength) { + final int startLocation = + (maxLength / 2 - (ch.length / 2).ceil()).toInt(); + newText = + i >= startLocation && i < startLocation + ch.length + ? ch[i - startLocation] + : ''; + } else { + newText = ch.length > i ? ch[i] : ''; + } + } else { + newText = + maxLength - ch.length <= i + ? ch[i - (maxLength - ch.length)] + : ''; + } + params.bounds = Rect.fromLTWH( + params.bounds!.left, + params.bounds!.top, + width, + params.bounds!.height, + ); + final PdfStringFormat format = PdfStringFormat( + alignment: PdfTextAlignment.center, + lineAlignment: _helper.format!.lineAlignment, + ); + FieldPainter().drawTextBox( + graphics, + params, + newText, + font, + format, + insertSpaces, + multiline, + ); + params.bounds = Rect.fromLTWH( + params.bounds!.left + width, + params.bounds!.top, + width, + params.bounds!.height, + ); + if (params.borderWidth != 0) { + graphics.drawLine( + params.borderPen!, + Offset(params.bounds!.left, params.bounds!.top), + Offset( + params.bounds!.left, + params.bounds!.top + params.bounds!.height, + ), + ); + } + } + } else { + FieldPainter().drawTextBox( + graphics, + params, + newText, + font, + _helper.format!, + insertSpaces, + multiline, + ); + } + } else { + FieldPainter().drawTextBox( + graphics, + params, + newText, + font, + _helper.format!, + insertSpaces, + multiline, + ); + } + graphics.restore(); + } else { + final GraphicsProperties gp = + item != null + ? GraphicsProperties.fromFieldItem(item) + : GraphicsProperties(this); + if (gp.borderWidth == 0 && gp.borderPen != null) { + gp.borderWidth = 1; + gp.borderPen!.width = 1; + } + if (PdfGraphicsHelper.getHelper(graphics!).layer == null) { + gp.bounds = Rect.fromLTWH( + gp.bounds!.left, + gp.bounds!.top, + graphics.size.width, + graphics.size.height, + ); + } + if (!_helper.flattenField) { + gp.bounds = Rect.fromLTWH(0, 0, gp.bounds!.width, gp.bounds!.height); + } + final PaintParams prms = PaintParams( + bounds: gp.bounds, + backBrush: gp.backBrush, + foreBrush: gp.foreBrush, + borderPen: gp.borderPen, + style: gp.style, + borderWidth: gp.borderWidth, + shadowBrush: gp.shadowBrush, + ); + _drawTextBox(graphics, params: prms); + } + } + + void _applyAppearance(PdfDictionary? widget, [PdfFieldItem? item]) { + if (PdfFormHelper.getHelper(super.form!).setAppearanceDictionary) { + if (widget != null && + !PdfFormHelper.getHelper(super.form!).needAppearances!) { + final PdfDictionary appearance = PdfDictionary(); + final Rect bounds = item == null ? this.bounds : item.bounds; + PdfTemplate? template; + if (widget.containsKey(PdfDictionaryProperties.mk)) { + final IPdfPrimitive? mkDic = widget[PdfDictionaryProperties.mk]; + if (mkDic != null && + mkDic is PdfDictionary && + mkDic.containsKey(PdfDictionaryProperties.r)) { + final IPdfPrimitive? angle = mkDic[PdfDictionaryProperties.r]; + if (angle != null && angle is PdfNumber) { + if (angle.value == 90) { + template = PdfTemplate(bounds.size.height, bounds.size.width); + PdfTemplateHelper.getHelper( + template, + ).content[PdfDictionaryProperties.matrix] = PdfArray([ + 0, + 1, + -1, + 0, + bounds.size.width, + 0, + ]); + } else if (angle.value == 180) { + template = PdfTemplate(bounds.size.width, bounds.size.height); + PdfTemplateHelper.getHelper( + template, + ).content[PdfDictionaryProperties.matrix] = PdfArray([ + -1, + 0, + 0, + -1, + bounds.size.width, + bounds.size.height, + ]); + } else if (angle.value == 270) { + template = PdfTemplate(bounds.size.height, bounds.size.width); + PdfTemplateHelper.getHelper( + template, + ).content[PdfDictionaryProperties.matrix] = PdfArray([ + 0, + -1, + 1, + 0, + 0, + bounds.size.height, + ]); + } + if (template != null) { + PdfTemplateHelper.getHelper(template).writeTransformation = + false; + } + } + } + } + if (template == null) { + template = PdfTemplate(bounds.size.width, bounds.size.height); + PdfTemplateHelper.getHelper(template).writeTransformation = false; + PdfTemplateHelper.getHelper(template).content[PdfDictionaryProperties + .matrix] = PdfArray([1, 0, 0, 1, 0, 0]); + } + if (item != null) { + _helper.beginMarkupSequence( + PdfGraphicsHelper.getHelper( + template.graphics!, + ).streamWriter!.stream!, + ); + PdfGraphicsHelper.getHelper( + template.graphics!, + ).initializeCoordinates(); + _drawTextBox(template.graphics, item: item); + _helper.endMarkupSequence( + PdfGraphicsHelper.getHelper( + template.graphics!, + ).streamWriter!.stream!, + ); + } else { + _helper.drawAppearance(template); + } + appearance.setProperty( + PdfDictionaryProperties.n, + PdfReferenceHolder(template), + ); + widget.setProperty(PdfDictionaryProperties.ap, appearance); + } else { + PdfFormHelper.getHelper(super.form!).needAppearances = true; + } + } + } +} + +/// [PdfTextBoxField] helper +class PdfTextBoxFieldHelper extends PdfFieldHelper { + /// internal constructor + PdfTextBoxFieldHelper(this.textBoxField) : super(textBoxField); + + /// internal field + PdfTextBoxField textBoxField; + + /// internal field + // ignore: avoid_setters_without_getters + set items(PdfFieldItemCollection? value) { + textBoxField._items = value; + } + + /// internal method + static PdfTextBoxFieldHelper getHelper(PdfTextBoxField textBoxField) { + return textBoxField._helper; + } + + /// internal method + static PdfTextBoxField loadTextBox( + PdfDictionary dictionary, + PdfCrossTable crossTable, + ) { + return PdfTextBoxField._load(dictionary, crossTable); + } + + /// internal method + @override + void save() { + super.save(); + if (fieldItems != null && fieldItems!.length > 1) { + for (int i = 1; i < fieldItems!.length; i++) { + final PdfTextBoxField field = fieldItems![i] as PdfTextBoxField; + field.text = textBoxField.text; + field._helper.save(); + } + } + } + + /// internal method + @override + void drawAppearance(PdfTemplate template) { + super.drawAppearance(template); + final PaintParams params = PaintParams( + bounds: Rect.fromLTWH( + 0, + 0, + textBoxField.bounds.width, + textBoxField.bounds.height, + ), + backBrush: backBrush, + foreBrush: foreBrush, + borderPen: borderPen, + style: textBoxField.borderStyle, + borderWidth: textBoxField.borderWidth, + shadowBrush: shadowBrush, + ); + PdfTemplateHelper.getHelper(template).writeTransformation = false; + final PdfGraphics graphics = template.graphics!; + beginMarkupSequence( + PdfGraphicsHelper.getHelper(graphics).streamWriter!.stream!, + ); + PdfGraphicsHelper.getHelper(graphics).initializeCoordinates(); + if (params.borderWidth == 0 && params.borderPen != null) { + params.borderWidth = 1; + params.borderPen!.width = 1; + } + textBoxField._drawTextBox(graphics, params: params); + endMarkupSequence( + PdfGraphicsHelper.getHelper(graphics).streamWriter!.stream!, + ); + } + + /// internal method + @override + void beginSave() { + super.beginSave(); + if (kids != null) { + for (int i = 0; i < kids!.count; ++i) { + final PdfDictionary? widget = + crossTable!.getObject(kids![i]) as PdfDictionary?; + textBoxField._applyAppearance(widget, textBoxField.items![i]); + } + } else { + textBoxField._applyAppearance( + getWidgetAnnotation(dictionary!, crossTable), + ); + } + } + + /// internal method + @override + double getFontHeight(PdfFontFamily family) { + double s = 12; + if (!textBoxField.multiline) { + final PdfStandardFont font = PdfStandardFont(family, 12); + final Size fontSize = font.measureString(textBoxField.text); + s = + (8 * + (textBoxField.bounds.size.width - 4 * textBoxField.borderWidth)) / + fontSize.width; + s = (s > 8) ? 8 : s; + } else { + s = 12.5; + } + return s; + } + + /// internal method + @override + void draw() { + super.draw(); + if (!isLoadedField && + PdfAnnotationHelper.getHelper(widget!).appearance != null) { + textBoxField.page!.graphics.drawPdfTemplate( + PdfAnnotationHelper.getHelper(widget!).appearance!.normal, + Offset(textBoxField.bounds.width, textBoxField.bounds.height), + ); + if (fieldItems != null && fieldItems!.length > 1) { + for (int i = 1; i < fieldItems!.length; i++) { + final PdfTextBoxField field = fieldItems![i] as PdfTextBoxField; + field.text = textBoxField.text; + field.page!.graphics.drawPdfTemplate( + PdfAnnotationHelper.getHelper( + field._helper.widget!, + ).appearance!.normal, + Offset(field.bounds.width, field.bounds.height), + ); + } + } + } else { + if (isLoadedField) { + if (kids != null) { + for (int i = 0; i < kids!.count; ++i) { + final PdfFieldItem item = textBoxField.items![i]; + if (item.page != null && + PdfPageHelper.getHelper(item.page!).isLoadedPage) { + textBoxField._drawTextBox(item.page!.graphics, item: item); + } + } + } else { + textBoxField._drawTextBox(textBoxField.page!.graphics); + } + } else { + textBoxField._drawTextBox(textBoxField.page!.graphics); + if (fieldItems != null && fieldItems!.length > 1) { + for (int i = 1; i < fieldItems!.length; i++) { + final PdfTextBoxField field = fieldItems![i] as PdfTextBoxField; + field.text = textBoxField.text; + field._drawTextBox(field.page!.graphics); + } + } + } + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_xfdf_document.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_xfdf_document.dart index ef26ebe75..74e960a39 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_xfdf_document.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/forms/pdf_xfdf_document.dart @@ -1,1594 +1,1594 @@ -import 'dart:convert'; - -import 'package:xml/xml.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/json_parser.dart'; -import '../annotations/pdf_annotation.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; - -/// internal class -class XFdfDocument { - /// internal constructor - XFdfDocument(String filename) { - _pdfFilePath = filename; - } - - //Fields - late String? _pdfFilePath; - final Map _table = {}; - List? _annotationAttributes; - bool _skipBorderStyle = false; - bool _isStampAnnotation = false; - PdfDocument? _document; - - //Implementation - /// internal method - void setFields(Object fieldName, Object fieldvalue) { - _table[fieldName] = fieldvalue; - } - - /// internal method - List save([List? annotationData]) { - List xmlData; - final XmlBuilder builder = XmlBuilder(); - builder.processing('xml', 'version="1.0" encoding="utf-8"'); - builder.element( - PdfDictionaryProperties.xfdf.toLowerCase(), - nest: () { - builder.attribute('xmlns', 'http://ns.adobe.com/xfdf/'); - builder.attribute('xml:space', 'preserve'); - if (annotationData != null && annotationData.isNotEmpty) { - builder.element( - PdfDictionaryProperties.annots.toLowerCase(), - nest: annotationData, - ); - } else { - builder.element( - PdfDictionaryProperties.fields.toLowerCase(), - nest: _writeFormData(), - ); - } - builder.element( - 'f', - nest: () { - // ignore: unnecessary_null_checks - builder.attribute('href', _pdfFilePath!); - }, - ); - }, - ); - xmlData = utf8.encode(builder.buildDocument().toXmlString(pretty: true)); - return xmlData; - } - - List _writeFormData() { - final List elements = []; - _table.forEach((Object key, Object value) { - final XmlElement xmlElement = XmlElement( - XmlName(PdfDictionaryProperties.field.toLowerCase()), - ); - xmlElement.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.name.toLowerCase()), - key.toString(), - ), - ); - if (value is PdfArray) { - for (final IPdfPrimitive? str in value.elements) { - if (str is PdfString) { - xmlElement.children.add( - XmlElement( - XmlName(PdfDictionaryProperties.value.toLowerCase()), - [], - [XmlText(str.value.toString())], - ), - ); - } - } - } else { - xmlElement.children.add( - XmlElement( - XmlName(PdfDictionaryProperties.value.toLowerCase()), - [], - [XmlText(value.toString())], - ), - ); - } - elements.add(xmlElement); - }); - return elements; - } - - /// internal method - XmlElement? exportAnnotationData( - PdfDictionary annotationDictionary, - int pageIndex, - bool exportAppearance, - PdfDocument document, - ) { - _document = document; - if (!PdfDocumentHelper.isLinkAnnotation(annotationDictionary)) { - return _writeAnnotationData( - pageIndex, - exportAppearance, - annotationDictionary, - ); - } - return null; - } - - XmlElement? _writeAnnotationData( - int pageIndex, - bool exportAppearance, - PdfDictionary annotationDictionary, - ) { - XmlElement? element; - final String? type = _getAnnotationType(annotationDictionary); - _skipBorderStyle = false; - if (type != null && type.isNotEmpty) { - _annotationAttributes ??= []; - element = XmlElement(XmlName(type.toLowerCase())); - element.attributes.add( - XmlAttribute(XmlName('page'), pageIndex.toString()), - ); - switch (type) { - case PdfDictionaryProperties.line: - if (annotationDictionary.containsKey(PdfDictionaryProperties.l)) { - final IPdfPrimitive? linePoints = PdfCrossTable.dereference( - annotationDictionary[PdfDictionaryProperties.l], - ); - if (linePoints != null && - linePoints is PdfArray && - linePoints.count == 4 && - linePoints[0] != null && - linePoints[0] is PdfNumber && - linePoints[1] != null && - linePoints[1] is PdfNumber && - linePoints[2] != null && - linePoints[2] is PdfNumber && - linePoints[3] != null && - linePoints[3] is PdfNumber) { - element.attributes.add( - XmlAttribute( - XmlName('start'), - '${(linePoints[0]! as PdfNumber).value},${(linePoints[1]! as PdfNumber).value}', - ), - ); - element.attributes.add( - XmlAttribute( - XmlName('end'), - '${(linePoints[2]! as PdfNumber).value},${(linePoints[3]! as PdfNumber).value}', - ), - ); - } - } - break; - case 'Stamp': - exportAppearance = true; - _isStampAnnotation = true; - break; - case PdfDictionaryProperties.square: - if (!exportAppearance && - annotationDictionary.containsKey(PdfDictionaryProperties.it)) { - final IPdfPrimitive? name = - annotationDictionary[PdfDictionaryProperties.it]; - if (name != null && name is PdfName && name.name == 'SquareImage') { - exportAppearance = true; - } - } - break; - } - if (annotationDictionary.containsKey(PdfDictionaryProperties.be) && - annotationDictionary.containsKey(PdfDictionaryProperties.bs)) { - final IPdfPrimitive? borderEffect = PdfCrossTable.dereference( - annotationDictionary[PdfDictionaryProperties.be], - ); - if (borderEffect != null && - borderEffect is PdfDictionary && - borderEffect.containsKey(PdfDictionaryProperties.s)) { - _skipBorderStyle = true; - } - } - _writeDictionary( - annotationDictionary, - pageIndex, - element, - exportAppearance, - ); - _annotationAttributes!.clear(); - if (_isStampAnnotation) { - _isStampAnnotation = false; - } - } - return element; - } - - void _writeDictionary( - PdfDictionary dictionary, - int pageIndex, - XmlElement element, - bool exportAppearance, - ) { - bool isBSdictionary = false; - if (dictionary.containsKey(PdfDictionaryProperties.type)) { - final IPdfPrimitive? name = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.type], - ); - if (name != null && - name is PdfName && - name.name == PdfDictionaryProperties.border && - _skipBorderStyle) { - isBSdictionary = true; - } - } - dictionary.items!.forEach((PdfName? name, IPdfPrimitive? value) { - final String key = name!.name!; - if (!((!exportAppearance && key == PdfDictionaryProperties.ap) || - key == PdfDictionaryProperties.p || - key == PdfDictionaryProperties.parent)) { - final IPdfPrimitive? primitive = value; - if (primitive is PdfReferenceHolder) { - final IPdfPrimitive? obj = primitive.object; - if (obj != null && obj is PdfDictionary) { - switch (key) { - case PdfDictionaryProperties.bs: - _writeDictionary(obj, pageIndex, element, false); - break; - case PdfDictionaryProperties.be: - _writeDictionary(obj, pageIndex, element, false); - break; - case PdfDictionaryProperties.irt: - if (obj.containsKey('NM')) { - element.attributes.add( - XmlAttribute(XmlName('inreplyto'), _getValue(obj['NM'])), - ); - } - break; - } - } - } else if (primitive is PdfDictionary) { - _writeDictionary(primitive, pageIndex, element, false); - } else if (primitive != null && (!isBSdictionary) || - (isBSdictionary && key != PdfDictionaryProperties.s)) { - _writeAttribute(element, key, primitive!); - } - } - }); - if (exportAppearance && - dictionary.containsKey(PdfDictionaryProperties.ap)) { - final IPdfPrimitive? appearance = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.ap], - ); - if (appearance != null && appearance is PdfDictionary) { - final List elements = _getAppearanceString(appearance); - if (elements.isNotEmpty) { - element.children.add( - XmlElement(XmlName('appearance'), [], [ - XmlText(base64.encode(elements)), - ]), - ); - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.measure)) { - element.children.add(_exportMeasureDictionary(dictionary)); - } - if (dictionary.containsKey('Sound')) { - final IPdfPrimitive? sound = PdfCrossTable.dereference( - dictionary['Sound'], - ); - if (sound != null && sound is PdfStream) { - if (sound.containsKey('B')) { - element.attributes.add( - XmlAttribute(XmlName('bits'), _getValue(sound['B'])), - ); - } - if (sound.containsKey(PdfDictionaryProperties.c)) { - element.attributes.add( - XmlAttribute( - XmlName('channels'), - _getValue(sound[PdfDictionaryProperties.c]), - ), - ); - } - if (sound.containsKey(PdfDictionaryProperties.e)) { - element.attributes.add( - XmlAttribute( - XmlName('encoding'), - _getValue(sound[PdfDictionaryProperties.e]), - ), - ); - } - if (sound.containsKey(PdfDictionaryProperties.r)) { - element.attributes.add( - XmlAttribute( - XmlName('rate'), - _getValue(sound[PdfDictionaryProperties.r]), - ), - ); - } - if (sound.dataStream != null && sound.dataStream!.isNotEmpty) { - final String data = PdfString.bytesToHex(sound.dataStream!); - if (!isNullOrEmpty(data)) { - element.children.add( - XmlElement( - XmlName(XfdfProperties.data.toLowerCase()), - [ - XmlAttribute(XmlName(XfdfProperties.mode), 'raw'), - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toLowerCase()), - 'hex', - ), - if (sound.containsKey(PdfDictionaryProperties.length)) - XmlAttribute( - XmlName(PdfDictionaryProperties.length.toLowerCase()), - _getValue(sound[PdfDictionaryProperties.length]), - ), - if (sound.containsKey(PdfDictionaryProperties.filter)) - XmlAttribute( - XmlName(PdfDictionaryProperties.filter), - _getValue(sound[PdfDictionaryProperties.filter]), - ), - ], - [XmlText(data)], - ), - ); - } - } - } - } else if (dictionary.containsKey(PdfDictionaryProperties.fs)) { - final IPdfPrimitive? fsDictionary = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.fs], - ); - if (fsDictionary != null && fsDictionary is PdfDictionary) { - if (fsDictionary.containsKey(PdfDictionaryProperties.f)) { - element.attributes.add( - XmlAttribute( - XmlName('file'), - _getValue(fsDictionary[PdfDictionaryProperties.f]), - ), - ); - } - if (fsDictionary.containsKey(PdfDictionaryProperties.ef)) { - final IPdfPrimitive? efDictionary = PdfCrossTable.dereference( - fsDictionary[PdfDictionaryProperties.ef], - ); - if (efDictionary != null && - efDictionary is PdfDictionary && - efDictionary.containsKey(PdfDictionaryProperties.f)) { - final IPdfPrimitive? fStream = PdfCrossTable.dereference( - efDictionary[PdfDictionaryProperties.f], - ); - if (fStream != null && fStream is PdfStream) { - if (fStream.containsKey(PdfDictionaryProperties.params)) { - final IPdfPrimitive? paramsDictionary = - PdfCrossTable.dereference( - fStream[PdfDictionaryProperties.params], - ); - if (paramsDictionary != null && - paramsDictionary is PdfDictionary) { - if (paramsDictionary.containsKey( - PdfDictionaryProperties.creationDate, - )) { - element.attributes.add( - XmlAttribute( - XmlName('creation'), - _getValue( - paramsDictionary[PdfDictionaryProperties - .creationDate], - ), - ), - ); - } - if (paramsDictionary.containsKey( - PdfDictionaryProperties.modificationDate, - )) { - element.attributes.add( - XmlAttribute( - XmlName('modification'), - _getValue( - paramsDictionary[PdfDictionaryProperties - .modificationDate], - ), - ), - ); - } - if (paramsDictionary.containsKey( - PdfDictionaryProperties.size, - )) { - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.size.toLowerCase()), - _getValue( - paramsDictionary[PdfDictionaryProperties.size], - ), - ), - ); - } - if (paramsDictionary.containsKey('CheckSum')) { - final List checksum = utf8.encode( - _getValue(paramsDictionary['CheckSum']), - ); - final String hexString = PdfString.bytesToHex(checksum); - element.attributes.add( - XmlAttribute(XmlName('checksum'), hexString), - ); - } - } - } - final String data = PdfString.bytesToHex(fStream.dataStream!); - if (!isNullOrEmpty(data)) { - element.children.add( - XmlElement( - XmlName(XfdfProperties.data.toLowerCase()), - [ - XmlAttribute( - XmlName(XfdfProperties.mode), - XfdfProperties.raw.toLowerCase(), - ), - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toLowerCase()), - XfdfProperties.hex.toLowerCase(), - ), - if (fStream.containsKey(PdfDictionaryProperties.length)) - XmlAttribute( - XmlName(PdfDictionaryProperties.length.toLowerCase()), - _getValue(fStream[PdfDictionaryProperties.length]), - ), - if (fStream.containsKey(PdfDictionaryProperties.filter)) - XmlAttribute( - XmlName(PdfDictionaryProperties.filter), - _getValue(fStream[PdfDictionaryProperties.filter]), - ), - ], - [XmlText(data)], - ), - ); - } - } - } - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.vertices)) { - final XmlElement verticesElement = XmlElement( - XmlName(PdfDictionaryProperties.vertices.toLowerCase()), - ); - final IPdfPrimitive? vertices = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.vertices], - ); - if (vertices != null && vertices is PdfArray && vertices.count > 0) { - final int elementCount = vertices.count; - if (elementCount.isEven) { - String value = ''; - IPdfPrimitive? numberElement; - for (int i = 0; i < elementCount - 1; i++) { - numberElement = vertices.elements[i]; - if (numberElement != null && numberElement is PdfNumber) { - value += _getValue(numberElement) + (i % 2 != 0 ? ';' : ','); - } - } - numberElement = vertices.elements[elementCount - 1]; - if (numberElement != null && numberElement is PdfNumber) { - value += _getValue(numberElement); - } - if (!isNullOrEmpty(value)) { - verticesElement.children.add(XmlText(value)); - } - } - } - element.children.add(verticesElement); - } - if (dictionary.containsKey(PdfDictionaryProperties.popup)) { - final IPdfPrimitive? popup = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.popup], - ); - if (popup != null && popup is PdfDictionary) { - final XmlElement? popupElement = _writeAnnotationData( - pageIndex, - exportAppearance, - popup, - ); - if (popupElement != null) { - element.children.add(popupElement); - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.da)) { - final IPdfPrimitive? defaultAppearance = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.da], - ); - if (defaultAppearance != null && defaultAppearance is PdfString) { - if (!isNullOrEmpty(defaultAppearance.value)) { - element.children.add( - XmlElement( - XmlName('defaultappearance'), - [], - [XmlText(defaultAppearance.value!)], - ), - ); - } - } - } - if (dictionary.containsKey('DS')) { - final IPdfPrimitive? defaultStyle = PdfCrossTable.dereference( - dictionary['DS'], - ); - if (defaultStyle != null && defaultStyle is PdfString) { - if (!isNullOrEmpty(defaultStyle.value)) { - element.children.add( - XmlElement(XmlName('defaultstyle'), [], [ - XmlText(defaultStyle.value!), - ]), - ); - } - } - } - if (dictionary.containsKey('InkList')) { - final IPdfPrimitive? inkList = PdfCrossTable.dereference( - dictionary['InkList'], - ); - if (inkList != null && inkList is PdfArray && inkList.count > 0) { - final XmlElement inkListElement = XmlElement(XmlName('inkList')); - for (int j = 0; j < inkList.count; j++) { - final IPdfPrimitive? list = PdfCrossTable.dereference(inkList[j]); - if (list != null && list is PdfArray) { - inkListElement.children.add( - XmlElement(XmlName('gesture'), [], [ - XmlText(_getValue(list)), - ]), - ); - } - } - element.children.add(inkListElement); - } - } - if (dictionary.containsKey('RC')) { - final IPdfPrimitive? contents = PdfCrossTable.dereference( - dictionary['RC'], - ); - if (contents != null && contents is PdfString) { - String? value = contents.value; - if (!isNullOrEmpty(value)) { - final int index = value!.indexOf(' 0) { - value = value.substring(index); - } - element.children.add( - XmlElement( - XmlName('contents-richtext'), - [], - [XmlText(value)], - ), - ); - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.contents)) { - final IPdfPrimitive? contents = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.contents], - ); - if (contents != null && contents is PdfString) { - if (!isNullOrEmpty(contents.value)) { - element.children.add( - XmlElement(XmlName('contents'), [], [ - XmlText(contents.value!), - ]), - ); - } - } - } - } - - String _getColor(IPdfPrimitive primitive) { - String color = ''; - final PdfArray colorArray = primitive as PdfArray; - if (colorArray.count >= 3) { - final String r = - PdfString.bytesToHex([ - ((colorArray.elements[0]! as PdfNumber).value! * 255).round(), - ]).toUpperCase(); - final String g = - PdfString.bytesToHex([ - ((colorArray.elements[1]! as PdfNumber).value! * 255).round(), - ]).toUpperCase(); - final String b = - PdfString.bytesToHex([ - ((colorArray.elements[2]! as PdfNumber).value! * 255).round(), - ]).toUpperCase(); - color = '#$r$g$b'; - } - return color; - } - - void _writeAttribute( - XmlElement element, - String key, - IPdfPrimitive primitive, - ) { - if (_annotationAttributes != null && - !_annotationAttributes!.contains(key)) { - switch (key) { - case PdfDictionaryProperties.c: - final String color = _getColor(primitive); - if (primitive is PdfNumber) { - final String c = _getValue(primitive); - if (!isNullOrEmpty(c) && !_annotationAttributes!.contains('c')) { - element.attributes.add(XmlAttribute(XmlName('c'), c)); - _annotationAttributes!.add('c'); - } - } - if (!isNullOrEmpty(color) && - !_annotationAttributes!.contains('color')) { - element.attributes.add(XmlAttribute(XmlName('color'), color)); - _annotationAttributes!.add('color'); - } - break; - case PdfDictionaryProperties.ic: - final String interiorColor = _getColor(primitive); - if (!isNullOrEmpty(interiorColor) && - !_annotationAttributes!.contains('interior-color')) { - element.attributes.add( - XmlAttribute(XmlName('interior-color'), interiorColor), - ); - _annotationAttributes!.add('interior-color'); - } - break; - case PdfDictionaryProperties.m: - if (!_annotationAttributes!.contains('date')) { - element.attributes.add( - XmlAttribute(XmlName('date'), _getValue(primitive)), - ); - _annotationAttributes!.add('date'); - } - break; - case 'NM': - if (!_annotationAttributes!.contains( - PdfDictionaryProperties.name.toLowerCase(), - )) { - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.name.toLowerCase()), - _getValue(primitive), - ), - ); - _annotationAttributes!.add( - PdfDictionaryProperties.name.toLowerCase(), - ); - } - break; - case PdfDictionaryProperties.name: - if (!_annotationAttributes!.contains('icon')) { - element.attributes.add( - XmlAttribute(XmlName('icon'), _getValue(primitive)), - ); - _annotationAttributes!.add('icon'); - } - break; - case PdfDictionaryProperties.subj: - if (!_annotationAttributes!.contains( - PdfDictionaryProperties.subject.toLowerCase(), - )) { - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.subject.toLowerCase()), - _getValue(primitive), - ), - ); - _annotationAttributes!.add( - PdfDictionaryProperties.subject.toLowerCase(), - ); - } - break; - case PdfDictionaryProperties.t: - if (!_annotationAttributes!.contains( - PdfDictionaryProperties.title.toLowerCase(), - )) { - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.title.toLowerCase()), - _getValue(primitive), - ), - ); - _annotationAttributes!.add( - PdfDictionaryProperties.title.toLowerCase(), - ); - } - break; - case PdfDictionaryProperties.rect: - case PdfDictionaryProperties.creationDate: - if (!_annotationAttributes!.contains(key.toLowerCase())) { - element.attributes.add( - XmlAttribute(XmlName(key.toLowerCase()), _getValue(primitive)), - ); - _annotationAttributes!.add(key.toLowerCase()); - } - break; - case PdfDictionaryProperties.rotate: - if (!_annotationAttributes!.contains('rotation')) { - element.attributes.add( - XmlAttribute(XmlName('rotation'), _getValue(primitive)), - ); - _annotationAttributes!.add('rotation'); - } - break; - case PdfDictionaryProperties.w: - if (!_annotationAttributes!.contains( - PdfDictionaryProperties.width.toLowerCase(), - )) { - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.width.toLowerCase()), - _getValue(primitive), - ), - ); - _annotationAttributes!.add( - PdfDictionaryProperties.width.toLowerCase(), - ); - } - break; - case PdfDictionaryProperties.le: - if (primitive is PdfArray) { - if (primitive.count == 2) { - element.attributes.add( - XmlAttribute(XmlName('head'), _getValue(primitive.elements[0])), - ); - element.attributes.add( - XmlAttribute(XmlName('tail'), _getValue(primitive.elements[1])), - ); - } - } else if (primitive is PdfName && - !_annotationAttributes!.contains('head')) { - element.attributes.add( - XmlAttribute(XmlName('head'), _getValue(primitive)), - ); - _annotationAttributes!.add('head'); - } - break; - case PdfDictionaryProperties.s: - if (!_annotationAttributes!.contains('style')) { - switch (_getValue(primitive)) { - case PdfDictionaryProperties.d: - element.attributes.add(XmlAttribute(XmlName('style'), 'dash')); - break; - case PdfDictionaryProperties.c: - element.attributes.add( - XmlAttribute(XmlName('style'), 'cloudy'), - ); - break; - case PdfDictionaryProperties.s: - element.attributes.add(XmlAttribute(XmlName('style'), 'solid')); - break; - case 'B': - element.attributes.add( - XmlAttribute(XmlName('style'), 'bevelled'), - ); - break; - case PdfDictionaryProperties.i: - element.attributes.add(XmlAttribute(XmlName('style'), 'inset')); - break; - case PdfDictionaryProperties.u: - element.attributes.add( - XmlAttribute(XmlName('style'), 'underline'), - ); - break; - } - _annotationAttributes!.add('style'); - } - break; - case PdfDictionaryProperties.d: - if (!_annotationAttributes!.contains('dashes')) { - element.attributes.add( - XmlAttribute(XmlName('dashes'), _getValue(primitive)), - ); - _annotationAttributes!.add('dashes'); - } - break; - case PdfDictionaryProperties.i: - if (!_annotationAttributes!.contains('intensity')) { - element.attributes.add( - XmlAttribute(XmlName('intensity'), _getValue(primitive)), - ); - _annotationAttributes!.add('intensity'); - } - break; - case PdfDictionaryProperties.rd: - if (!_annotationAttributes!.contains('fringe')) { - element.attributes.add( - XmlAttribute(XmlName('fringe'), _getValue(primitive)), - ); - _annotationAttributes!.add('fringe'); - } - break; - case PdfDictionaryProperties.it: - if (!_annotationAttributes!.contains(key)) { - element.attributes.add( - XmlAttribute(XmlName(key), _getValue(primitive)), - ); - _annotationAttributes!.add(key); - } - break; - case 'RT': - if (!_annotationAttributes!.contains('replyType')) { - element.attributes.add( - XmlAttribute( - XmlName('replyType'), - _getValue(primitive).toLowerCase(), - ), - ); - _annotationAttributes!.add('replyType'); - } - break; - case PdfDictionaryProperties.ll: - if (!_annotationAttributes!.contains('leaderLength')) { - element.attributes.add( - XmlAttribute(XmlName('leaderLength'), _getValue(primitive)), - ); - _annotationAttributes!.add('leaderLength'); - } - break; - case PdfDictionaryProperties.lle: - if (!_annotationAttributes!.contains('leaderExtend')) { - element.attributes.add( - XmlAttribute(XmlName('leaderExtend'), _getValue(primitive)), - ); - _annotationAttributes!.add('leaderExtend'); - } - break; - case PdfDictionaryProperties.cap: - if (!_annotationAttributes!.contains('caption')) { - element.attributes.add( - XmlAttribute(XmlName('caption'), _getValue(primitive)), - ); - _annotationAttributes!.add('caption'); - } - break; - case PdfDictionaryProperties.q: - if (!_annotationAttributes!.contains('justification')) { - element.attributes.add( - XmlAttribute(XmlName('justification'), _getValue(primitive)), - ); - _annotationAttributes!.add('justification'); - } - break; - case PdfDictionaryProperties.cp: - if (!_annotationAttributes!.contains('caption-style')) { - element.attributes.add( - XmlAttribute(XmlName('caption-style'), _getValue(primitive)), - ); - _annotationAttributes!.add('caption-style'); - } - break; - case 'CL': - if (!_annotationAttributes!.contains('callout')) { - element.attributes.add( - XmlAttribute(XmlName('callout'), _getValue(primitive)), - ); - _annotationAttributes!.add('callout'); - } - break; - case 'FD': - if (!_annotationAttributes!.contains(key.toLowerCase())) { - element.attributes.add( - XmlAttribute(XmlName(key.toLowerCase()), _getValue(primitive)), - ); - _annotationAttributes!.add(key.toLowerCase()); - } - break; - case PdfDictionaryProperties.quadPoints: - if (!_annotationAttributes!.contains('Coords')) { - element.attributes.add( - XmlAttribute(XmlName('coords'), _getValue(primitive)), - ); - _annotationAttributes!.add('coords'); - } - break; - case PdfDictionaryProperties.ca: - if (!_annotationAttributes!.contains('opacity')) { - element.attributes.add( - XmlAttribute(XmlName('opacity'), _getValue(primitive)), - ); - _annotationAttributes!.add('opacity'); - } - break; - case PdfDictionaryProperties.f: - if (primitive is PdfNumber && - !_annotationAttributes!.contains( - PdfDictionaryProperties.flags.toLowerCase(), - )) { - final List annotationFlags = - PdfAnnotationHelper.obtainAnnotationFlags( - primitive.value!.toInt(), - ); - final String flag = annotationFlags - .map( - (PdfAnnotationFlags flag) => getEnumName(flag).toLowerCase(), - ) - .toString() - .replaceAll(' ', ''); - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.flags.toLowerCase()), - flag.substring(1, flag.length - 1), - ), - ); - _annotationAttributes!.add( - PdfDictionaryProperties.flags.toLowerCase(), - ); - } - break; - case 'InkList': - case PdfDictionaryProperties.type: - case PdfDictionaryProperties.subtype: - case PdfDictionaryProperties.p: - case PdfDictionaryProperties.parent: - case PdfDictionaryProperties.l: - case PdfDictionaryProperties.contents: - case 'RC': - case PdfDictionaryProperties.da: - case 'DS': - case PdfDictionaryProperties.fs: - case 'MeasurementTypes': - case PdfDictionaryProperties.vertices: - case 'GroupNesting': - case 'ITEx': - break; - case PdfDictionaryProperties.open: - case 'State': - case 'StateModel': - case 'OverlayText': - case 'OC': - case PdfDictionaryProperties.llo: - case 'Repeat': - if (!_annotationAttributes!.contains(key)) { - element.attributes.add( - XmlAttribute(XmlName(key.toLowerCase()), _getValue(primitive)), - ); - _annotationAttributes!.add(key.toLowerCase()); - } - break; - case PdfDictionaryProperties.border: - if (!_annotationAttributes!.contains( - PdfDictionaryProperties.width.toLowerCase(), - ) && - !_annotationAttributes!.contains( - PdfDictionaryProperties.border.toLowerCase(), - ) && - primitive is PdfArray && - primitive.count >= 3 && - primitive.elements[2] is PdfNumber) { - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.width.toLowerCase()), - _getValue(primitive.elements[2]), - ), - ); - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.border.toLowerCase()), - _getValue(primitive), - ), - ); - _annotationAttributes!.add(PdfDictionaryProperties.border); - _annotationAttributes!.add(PdfDictionaryProperties.width); - } - break; - default: - if (!_annotationAttributes!.contains(key)) { - element.attributes.add( - XmlAttribute(XmlName(key), _getValue(primitive)), - ); - _annotationAttributes!.add(key); - } - break; - } - } - } - - /// internal method - String _getValue(IPdfPrimitive? primitive) { - String value = ''; - if (primitive != null) { - if (primitive is PdfName) { - value = primitive.name!; - } else if (primitive is PdfBoolean) { - value = primitive.value! ? 'yes' : 'no'; - } else if (primitive is PdfString) { - value = primitive.value!; - } else if (primitive is PdfArray) { - if (primitive.elements.isNotEmpty) { - value = _getValue(primitive.elements[0]); - } - for (int i = 1; i < primitive.elements.length; i++) { - value += ',${_getValue(primitive.elements[i])}'; - } - } else if (primitive is PdfNumber) { - value = primitive.value.toString(); - } - if (value.contains('\u0002')) { - value = value.replaceAll('\u0002', '\u2010'); - } - } - return value; - } - - String? _getAnnotationType(PdfDictionary dictionary) { - if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? subtype = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.subtype], - ); - if (subtype != null && subtype is PdfName && subtype.name != null) { - return subtype.name!; - } - } - return null; - } - - List _getAppearanceString(PdfDictionary appearanceDictionary) { - final XmlBuilder builder = XmlBuilder(); - builder.processing('xml', 'version="1.0" encoding="utf-8"'); - builder.element( - 'DICT', - attributes: { - XfdfProperties.key: PdfDictionaryProperties.ap, - }, - nest: _writeAppearanceDictionary(appearanceDictionary), - ); - final String xmlString = builder.buildDocument().toXmlString(); - return utf8.encode(xmlString); - } - - List _writeAppearanceDictionary(PdfDictionary dictionary) { - final List elements = []; - if (dictionary.count > 0) { - dictionary.items!.forEach((PdfName? key, IPdfPrimitive? value) { - final XmlElement? element = _writeObject(key!.name!, value); - if (element != null) { - elements.add(element); - } - }); - } - return elements; - } - - XmlElement? _writeObject(String key, IPdfPrimitive? primitive) { - XmlElement? element; - if (primitive != null) { - final String type = primitive.runtimeType.toString(); - switch (type) { - case 'PdfReferenceHolder': - element = _writeObject(key, (primitive as PdfReferenceHolder).object); - break; - case 'PdfDictionary': - element = XmlElement(XmlName(XfdfProperties.dict)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - element.children.addAll( - _writeAppearanceDictionary(primitive as PdfDictionary), - ); - break; - case 'PdfStream': - final PdfStream streamElement = primitive as PdfStream; - if (streamElement.dataStream != null && - streamElement.dataStream!.isNotEmpty) { - element = XmlElement(XmlName(XfdfProperties.stream)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.define), ''), - ); - element.children.addAll(_writeAppearanceDictionary(streamElement)); - final String type = _getValue( - streamElement[PdfDictionaryProperties.subtype], - ); - final XmlElement dataElement = XmlElement( - XmlName(XfdfProperties.data), - ); - if ((streamElement.containsKey(PdfDictionaryProperties.subtype) && - PdfDictionaryProperties.image == type) || - (!streamElement.containsKey(PdfDictionaryProperties.type) && - !streamElement.containsKey( - PdfDictionaryProperties.subtype, - ))) { - dataElement.attributes.add( - XmlAttribute(XmlName(XfdfProperties.mode), XfdfProperties.raw), - ); - dataElement.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toUpperCase()), - XfdfProperties.hex, - ), - ); - String data = ''; - if (streamElement.dataStream != null) { - data = PdfString.bytesToHex(streamElement.dataStream!); - } - if (data.isNotEmpty) { - dataElement.children.add(XmlText(data)); - } - } else if (streamElement.containsKey( - PdfDictionaryProperties.subtype, - ) && - PdfDictionaryProperties.form == type && - !_isStampAnnotation) { - dataElement.attributes.add( - XmlAttribute(XmlName(XfdfProperties.mode), XfdfProperties.raw), - ); - dataElement.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toUpperCase()), - XfdfProperties.hex, - ), - ); - String data = ''; - streamElement.decompress(); - if (streamElement.dataStream != null) { - data = PdfString.bytesToHex(streamElement.dataStream!); - } - if (data.isNotEmpty) { - dataElement.children.add(XmlText(data)); - } - } else { - streamElement.decompress(); - if (streamElement.dataStream != null) { - final String ascii = utf8.decode(streamElement.dataStream!); - if (_isStampAnnotation && !ascii.contains('TJ')) { - dataElement.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.mode), - XfdfProperties.filtered, - ), - ); - dataElement.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toUpperCase()), - XfdfProperties.ascii, - ), - ); - if (!isNullOrEmpty(ascii)) { - dataElement.children.add( - XmlText(_getFormatedString(ascii)), - ); - } - } - } else { - dataElement.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.mode), - XfdfProperties.raw, - ), - ); - dataElement.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toUpperCase()), - XfdfProperties.hex, - ), - ); - String data = ''; - streamElement.decompress(); - if (streamElement.dataStream != null) { - data = PdfString.bytesToHex(streamElement.dataStream!); - } - if (data.isNotEmpty) { - dataElement.children.add(XmlText(data)); - } - } - } - element.children.add(dataElement); - } - break; - case 'PdfBoolean': - element = XmlElement(XmlName(XfdfProperties.bool)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - element.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.val), - primitive is PdfBoolean && - primitive.value != null && - primitive.value! - ? 'true' - : 'false', - ), - ); - break; - case 'PdfName': - element = XmlElement(XmlName(XfdfProperties.name)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - element.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.val), - (primitive as PdfName).name ?? '', - ), - ); - break; - case 'PdfString': - element = XmlElement(XmlName(XfdfProperties.string)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - element.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.val), - (primitive as PdfString).value ?? '', - ), - ); - break; - case 'PdfNumber': - element = XmlElement(XmlName(XfdfProperties.fixed)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - final String value = (primitive as PdfNumber).value! - .toDouble() - .toStringAsFixed(6); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.val), value), - ); - break; - case 'PdfNull': - element = XmlElement(XmlName(XfdfProperties.nullVal)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - break; - case 'PdfArray': - element = XmlElement(XmlName(XfdfProperties.array)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.key), key), - ); - element.children.addAll(_writeArray(primitive as PdfArray)); - break; - } - } - return element; - } - - List _writeArray(PdfArray array) { - final List elements = []; - for (final IPdfPrimitive? element in array.elements) { - final XmlElement? xmlElement = _writeArrayElement(element!); - if (xmlElement != null) { - elements.add(xmlElement); - } - } - return elements; - } - - XmlElement? _writeArrayElement(IPdfPrimitive primitive) { - XmlElement? element; - final String type = primitive.runtimeType.toString(); - switch (type) { - case 'PdfArray': - element = XmlElement(XmlName(XfdfProperties.array)); - element.children.addAll(_writeArray(primitive as PdfArray)); - break; - case 'PdfName': - element = XmlElement(XmlName(XfdfProperties.name)); - element.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.val), - (primitive as PdfName).name ?? '', - ), - ); - break; - case 'PdfString': - element = XmlElement(XmlName(XfdfProperties.string)); - final RegExp regex = RegExp(r'[\u0085-\u00FF]'); - if ((primitive as PdfString).value != null && - regex.hasMatch(primitive.value!) && - primitive.isHex != null && - primitive.isHex!) { - final List bytes = primitive.pdfEncode(_document); - primitive.value = PdfString.byteToString(bytes); - element.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toUpperCase()), - XfdfProperties.hex, - ), - ); - if (!isNullOrEmpty(primitive.value)) { - element.children.add(XmlText(_getFormatedString(primitive.value!))); - } - } else { - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.val), primitive.value ?? ''), - ); - } - break; - case 'PdfNumber': - element = XmlElement(XmlName(XfdfProperties.fixed)); - final String value = (primitive as PdfNumber).value! - .toDouble() - .toStringAsFixed(6); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.val), value), - ); - break; - case 'PdfBoolean': - element = XmlElement(XmlName(XfdfProperties.bool)); - element.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.val), - (primitive as PdfBoolean).value != null && primitive.value! - ? 'true' - : 'false', - ), - ); - break; - case 'PdfDictionary': - element = XmlElement(XmlName(XfdfProperties.dict)); - element.children.addAll( - _writeAppearanceDictionary(primitive as PdfDictionary), - ); - break; - case 'PdfStream': - final PdfStream streamElement = primitive as PdfStream; - if (streamElement.dataStream != null && - streamElement.dataStream!.isNotEmpty) { - element = XmlElement(XmlName(XfdfProperties.stream)); - element.attributes.add( - XmlAttribute(XmlName(XfdfProperties.define), ''), - ); - element.children.addAll(_writeAppearanceDictionary(streamElement)); - final XmlElement dataElement = XmlElement( - XmlName(XfdfProperties.data), - ); - final String type = _getValue( - streamElement[PdfDictionaryProperties.subtype], - ); - if (streamElement.containsKey(PdfDictionaryProperties.subtype) && - PdfDictionaryProperties.image == type) { - dataElement.attributes.add( - XmlAttribute(XmlName(XfdfProperties.mode), XfdfProperties.raw), - ); - dataElement.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toUpperCase()), - XfdfProperties.hex, - ), - ); - String data = ''; - streamElement.decompress(); - if (streamElement.dataStream != null) { - data = PdfString.bytesToHex(streamElement.dataStream!); - } - if (data.isNotEmpty) { - dataElement.children.add(XmlText(data)); - } - } else { - dataElement.attributes.add( - XmlAttribute( - XmlName(XfdfProperties.mode), - XfdfProperties.filtered, - ), - ); - dataElement.attributes.add( - XmlAttribute( - XmlName(PdfDictionaryProperties.encoding.toUpperCase()), - XfdfProperties.ascii, - ), - ); - String data = ''; - streamElement.decompress(); - if (streamElement.dataStream != null) { - data = utf8.decode(streamElement.dataStream!); - } - if (data.isNotEmpty) { - dataElement.children.add(XmlText(_getFormatedString(data))); - } - } - element.children.add(dataElement); - } - break; - case 'PdfReferenceHolder': - if ((primitive as PdfReferenceHolder).object != null) { - element = _writeArrayElement(primitive.object!); - } - break; - } - return element; - } - - XmlElement _exportMeasureDictionary(PdfDictionary dictionary) { - final XmlElement measureXmlElement = XmlElement(XmlName('measure')); - final IPdfPrimitive? mdictionary = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.measure], - ); - if (mdictionary != null && mdictionary is PdfDictionary) { - if (mdictionary.containsKey(PdfDictionaryProperties.r)) { - measureXmlElement.attributes.add( - XmlAttribute( - XmlName('rateValue'), - _getValue(mdictionary[PdfDictionaryProperties.r]), - ), - ); - } - if (mdictionary.containsKey(PdfDictionaryProperties.a)) { - IPdfPrimitive? aprimitive = PdfCrossTable.dereference( - mdictionary[PdfDictionaryProperties.a], - ); - if (aprimitive != null && aprimitive is PdfArray) { - aprimitive = PdfCrossTable.dereference(aprimitive.elements[0]); - if (aprimitive != null && aprimitive is PdfDictionary) { - final XmlElement areaXmlElement = XmlElement(XmlName('area')); - _exportMeasureFormatDetails(aprimitive, areaXmlElement); - measureXmlElement.children.add(areaXmlElement); - } - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.d)) { - IPdfPrimitive? dprimitive = PdfCrossTable.dereference( - mdictionary[PdfDictionaryProperties.d], - ); - if (dprimitive != null && dprimitive is PdfArray) { - dprimitive = PdfCrossTable.dereference(dprimitive.elements[0]); - if (dprimitive != null && dprimitive is PdfDictionary) { - final XmlElement distanceXmlElement = XmlElement( - XmlName('distance'), - ); - _exportMeasureFormatDetails(dprimitive, distanceXmlElement); - measureXmlElement.children.add(distanceXmlElement); - } - } - } - if (mdictionary.containsKey(PdfDictionaryProperties.x)) { - IPdfPrimitive? xprimitive = PdfCrossTable.dereference( - mdictionary[PdfDictionaryProperties.x], - ); - if (xprimitive != null && xprimitive is PdfArray) { - xprimitive = PdfCrossTable.dereference(xprimitive.elements[0]); - if (xprimitive != null && xprimitive is PdfDictionary) { - final XmlElement xformatXmlElement = XmlElement(XmlName('xformat')); - _exportMeasureFormatDetails(xprimitive, xformatXmlElement); - measureXmlElement.children.add(xformatXmlElement); - } - } - } - } - return measureXmlElement; - } - - void _exportMeasureFormatDetails( - PdfDictionary measurementDetails, - XmlElement element, - ) { - if (measurementDetails.containsKey(PdfDictionaryProperties.c)) { - element.attributes.add( - XmlAttribute( - XmlName('c'), - _getValue(measurementDetails[PdfDictionaryProperties.c]), - ), - ); - } - if (measurementDetails.containsKey(PdfDictionaryProperties.f)) { - element.attributes.add( - XmlAttribute( - XmlName('f'), - _getValue(measurementDetails[PdfDictionaryProperties.f]), - ), - ); - } - if (measurementDetails.containsKey(PdfDictionaryProperties.d)) { - element.attributes.add( - XmlAttribute( - XmlName('d'), - _getValue(measurementDetails[PdfDictionaryProperties.d]), - ), - ); - } - if (measurementDetails.containsKey(PdfDictionaryProperties.rd)) { - element.attributes.add( - XmlAttribute( - XmlName('rd'), - _getValue(measurementDetails[PdfDictionaryProperties.rd]), - ), - ); - } - if (measurementDetails.containsKey(PdfDictionaryProperties.u)) { - element.attributes.add( - XmlAttribute( - XmlName('u'), - _getValue(measurementDetails[PdfDictionaryProperties.u]), - ), - ); - } - if (measurementDetails.containsKey('RT')) { - element.attributes.add( - XmlAttribute(XmlName('rt'), _getValue(measurementDetails['RT'])), - ); - } - if (measurementDetails.containsKey('SS')) { - element.attributes.add( - XmlAttribute(XmlName('ss'), _getValue(measurementDetails['SS'])), - ); - } - if (measurementDetails.containsKey('FD')) { - element.attributes.add( - XmlAttribute(XmlName('fd'), _getValue(measurementDetails['FD'])), - ); - } - } - - String _getFormatedString(String value) { - value = value.replaceAll('&', '&'); - value = value.replaceAll('<', '<'); - value = value.replaceAll('>', '>'); - return value; - } -} - -/// XFDF dictionary properties. -class XfdfProperties { - //Constants - /// internal field - static const String dict = 'DICT'; - - /// internal field - static const String key = 'KEY'; - - /// internal field - static const String stream = 'STREAM'; - - /// internal field - static const String define = 'DEFINE'; - - /// internal field - static const String data = 'DATA'; - - /// internal field - static const String mode = 'MODE'; - - /// internal field - static const String raw = 'RAW'; - - /// internal field - static const String hex = 'HEX'; - - /// internal field - static const String filtered = 'FILTERED'; - - /// internal field - static const String ascii = 'ASCII'; - - /// internal field - static const String bool = 'BOOL'; - - /// internal field - static const String val = 'VAL'; - - /// internal field - static const String name = 'NAME'; - - /// internal field - static const String string = 'STRING'; - - /// internal field - static const String int = 'INT'; - - /// internal field - static const String fixed = 'FIXED'; - - /// internal field - static const String nullVal = 'NULL'; - - /// internal field - static const String array = 'ARRAY'; -} +import 'dart:convert'; + +import 'package:xml/xml.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/json_parser.dart'; +import '../annotations/pdf_annotation.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; + +/// internal class +class XFdfDocument { + /// internal constructor + XFdfDocument(String filename) { + _pdfFilePath = filename; + } + + //Fields + late String? _pdfFilePath; + final Map _table = {}; + List? _annotationAttributes; + bool _skipBorderStyle = false; + bool _isStampAnnotation = false; + PdfDocument? _document; + + //Implementation + /// internal method + void setFields(Object fieldName, Object fieldvalue) { + _table[fieldName] = fieldvalue; + } + + /// internal method + List save([List? annotationData]) { + List xmlData; + final XmlBuilder builder = XmlBuilder(); + builder.processing('xml', 'version="1.0" encoding="utf-8"'); + builder.element( + PdfDictionaryProperties.xfdf.toLowerCase(), + nest: () { + builder.attribute('xmlns', 'http://ns.adobe.com/xfdf/'); + builder.attribute('xml:space', 'preserve'); + if (annotationData != null && annotationData.isNotEmpty) { + builder.element( + PdfDictionaryProperties.annots.toLowerCase(), + nest: annotationData, + ); + } else { + builder.element( + PdfDictionaryProperties.fields.toLowerCase(), + nest: _writeFormData(), + ); + } + builder.element( + 'f', + nest: () { + // ignore: unnecessary_null_checks + builder.attribute('href', _pdfFilePath!); + }, + ); + }, + ); + xmlData = utf8.encode(builder.buildDocument().toXmlString(pretty: true)); + return xmlData; + } + + List _writeFormData() { + final List elements = []; + _table.forEach((Object key, Object value) { + final XmlElement xmlElement = XmlElement( + XmlName(PdfDictionaryProperties.field.toLowerCase()), + ); + xmlElement.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.name.toLowerCase()), + key.toString(), + ), + ); + if (value is PdfArray) { + for (final IPdfPrimitive? str in value.elements) { + if (str is PdfString) { + xmlElement.children.add( + XmlElement( + XmlName(PdfDictionaryProperties.value.toLowerCase()), + [], + [XmlText(str.value.toString())], + ), + ); + } + } + } else { + xmlElement.children.add( + XmlElement( + XmlName(PdfDictionaryProperties.value.toLowerCase()), + [], + [XmlText(value.toString())], + ), + ); + } + elements.add(xmlElement); + }); + return elements; + } + + /// internal method + XmlElement? exportAnnotationData( + PdfDictionary annotationDictionary, + int pageIndex, + bool exportAppearance, + PdfDocument document, + ) { + _document = document; + if (!PdfDocumentHelper.isLinkAnnotation(annotationDictionary)) { + return _writeAnnotationData( + pageIndex, + exportAppearance, + annotationDictionary, + ); + } + return null; + } + + XmlElement? _writeAnnotationData( + int pageIndex, + bool exportAppearance, + PdfDictionary annotationDictionary, + ) { + XmlElement? element; + final String? type = _getAnnotationType(annotationDictionary); + _skipBorderStyle = false; + if (type != null && type.isNotEmpty) { + _annotationAttributes ??= []; + element = XmlElement(XmlName(type.toLowerCase())); + element.attributes.add( + XmlAttribute(XmlName('page'), pageIndex.toString()), + ); + switch (type) { + case PdfDictionaryProperties.line: + if (annotationDictionary.containsKey(PdfDictionaryProperties.l)) { + final IPdfPrimitive? linePoints = PdfCrossTable.dereference( + annotationDictionary[PdfDictionaryProperties.l], + ); + if (linePoints != null && + linePoints is PdfArray && + linePoints.count == 4 && + linePoints[0] != null && + linePoints[0] is PdfNumber && + linePoints[1] != null && + linePoints[1] is PdfNumber && + linePoints[2] != null && + linePoints[2] is PdfNumber && + linePoints[3] != null && + linePoints[3] is PdfNumber) { + element.attributes.add( + XmlAttribute( + XmlName('start'), + '${(linePoints[0]! as PdfNumber).value},${(linePoints[1]! as PdfNumber).value}', + ), + ); + element.attributes.add( + XmlAttribute( + XmlName('end'), + '${(linePoints[2]! as PdfNumber).value},${(linePoints[3]! as PdfNumber).value}', + ), + ); + } + } + break; + case 'Stamp': + exportAppearance = true; + _isStampAnnotation = true; + break; + case PdfDictionaryProperties.square: + if (!exportAppearance && + annotationDictionary.containsKey(PdfDictionaryProperties.it)) { + final IPdfPrimitive? name = + annotationDictionary[PdfDictionaryProperties.it]; + if (name != null && name is PdfName && name.name == 'SquareImage') { + exportAppearance = true; + } + } + break; + } + if (annotationDictionary.containsKey(PdfDictionaryProperties.be) && + annotationDictionary.containsKey(PdfDictionaryProperties.bs)) { + final IPdfPrimitive? borderEffect = PdfCrossTable.dereference( + annotationDictionary[PdfDictionaryProperties.be], + ); + if (borderEffect != null && + borderEffect is PdfDictionary && + borderEffect.containsKey(PdfDictionaryProperties.s)) { + _skipBorderStyle = true; + } + } + _writeDictionary( + annotationDictionary, + pageIndex, + element, + exportAppearance, + ); + _annotationAttributes!.clear(); + if (_isStampAnnotation) { + _isStampAnnotation = false; + } + } + return element; + } + + void _writeDictionary( + PdfDictionary dictionary, + int pageIndex, + XmlElement element, + bool exportAppearance, + ) { + bool isBSdictionary = false; + if (dictionary.containsKey(PdfDictionaryProperties.type)) { + final IPdfPrimitive? name = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.type], + ); + if (name != null && + name is PdfName && + name.name == PdfDictionaryProperties.border && + _skipBorderStyle) { + isBSdictionary = true; + } + } + dictionary.items!.forEach((PdfName? name, IPdfPrimitive? value) { + final String key = name!.name!; + if (!((!exportAppearance && key == PdfDictionaryProperties.ap) || + key == PdfDictionaryProperties.p || + key == PdfDictionaryProperties.parent)) { + final IPdfPrimitive? primitive = value; + if (primitive is PdfReferenceHolder) { + final IPdfPrimitive? obj = primitive.object; + if (obj != null && obj is PdfDictionary) { + switch (key) { + case PdfDictionaryProperties.bs: + _writeDictionary(obj, pageIndex, element, false); + break; + case PdfDictionaryProperties.be: + _writeDictionary(obj, pageIndex, element, false); + break; + case PdfDictionaryProperties.irt: + if (obj.containsKey('NM')) { + element.attributes.add( + XmlAttribute(XmlName('inreplyto'), _getValue(obj['NM'])), + ); + } + break; + } + } + } else if (primitive is PdfDictionary) { + _writeDictionary(primitive, pageIndex, element, false); + } else if (primitive != null && (!isBSdictionary) || + (isBSdictionary && key != PdfDictionaryProperties.s)) { + _writeAttribute(element, key, primitive!); + } + } + }); + if (exportAppearance && + dictionary.containsKey(PdfDictionaryProperties.ap)) { + final IPdfPrimitive? appearance = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.ap], + ); + if (appearance != null && appearance is PdfDictionary) { + final List elements = _getAppearanceString(appearance); + if (elements.isNotEmpty) { + element.children.add( + XmlElement(XmlName('appearance'), [], [ + XmlText(base64.encode(elements)), + ]), + ); + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.measure)) { + element.children.add(_exportMeasureDictionary(dictionary)); + } + if (dictionary.containsKey('Sound')) { + final IPdfPrimitive? sound = PdfCrossTable.dereference( + dictionary['Sound'], + ); + if (sound != null && sound is PdfStream) { + if (sound.containsKey('B')) { + element.attributes.add( + XmlAttribute(XmlName('bits'), _getValue(sound['B'])), + ); + } + if (sound.containsKey(PdfDictionaryProperties.c)) { + element.attributes.add( + XmlAttribute( + XmlName('channels'), + _getValue(sound[PdfDictionaryProperties.c]), + ), + ); + } + if (sound.containsKey(PdfDictionaryProperties.e)) { + element.attributes.add( + XmlAttribute( + XmlName('encoding'), + _getValue(sound[PdfDictionaryProperties.e]), + ), + ); + } + if (sound.containsKey(PdfDictionaryProperties.r)) { + element.attributes.add( + XmlAttribute( + XmlName('rate'), + _getValue(sound[PdfDictionaryProperties.r]), + ), + ); + } + if (sound.dataStream != null && sound.dataStream!.isNotEmpty) { + final String data = PdfString.bytesToHex(sound.dataStream!); + if (!isNullOrEmpty(data)) { + element.children.add( + XmlElement( + XmlName(XfdfProperties.data.toLowerCase()), + [ + XmlAttribute(XmlName(XfdfProperties.mode), 'raw'), + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toLowerCase()), + 'hex', + ), + if (sound.containsKey(PdfDictionaryProperties.length)) + XmlAttribute( + XmlName(PdfDictionaryProperties.length.toLowerCase()), + _getValue(sound[PdfDictionaryProperties.length]), + ), + if (sound.containsKey(PdfDictionaryProperties.filter)) + XmlAttribute( + XmlName(PdfDictionaryProperties.filter), + _getValue(sound[PdfDictionaryProperties.filter]), + ), + ], + [XmlText(data)], + ), + ); + } + } + } + } else if (dictionary.containsKey(PdfDictionaryProperties.fs)) { + final IPdfPrimitive? fsDictionary = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.fs], + ); + if (fsDictionary != null && fsDictionary is PdfDictionary) { + if (fsDictionary.containsKey(PdfDictionaryProperties.f)) { + element.attributes.add( + XmlAttribute( + XmlName('file'), + _getValue(fsDictionary[PdfDictionaryProperties.f]), + ), + ); + } + if (fsDictionary.containsKey(PdfDictionaryProperties.ef)) { + final IPdfPrimitive? efDictionary = PdfCrossTable.dereference( + fsDictionary[PdfDictionaryProperties.ef], + ); + if (efDictionary != null && + efDictionary is PdfDictionary && + efDictionary.containsKey(PdfDictionaryProperties.f)) { + final IPdfPrimitive? fStream = PdfCrossTable.dereference( + efDictionary[PdfDictionaryProperties.f], + ); + if (fStream != null && fStream is PdfStream) { + if (fStream.containsKey(PdfDictionaryProperties.params)) { + final IPdfPrimitive? paramsDictionary = + PdfCrossTable.dereference( + fStream[PdfDictionaryProperties.params], + ); + if (paramsDictionary != null && + paramsDictionary is PdfDictionary) { + if (paramsDictionary.containsKey( + PdfDictionaryProperties.creationDate, + )) { + element.attributes.add( + XmlAttribute( + XmlName('creation'), + _getValue( + paramsDictionary[PdfDictionaryProperties + .creationDate], + ), + ), + ); + } + if (paramsDictionary.containsKey( + PdfDictionaryProperties.modificationDate, + )) { + element.attributes.add( + XmlAttribute( + XmlName('modification'), + _getValue( + paramsDictionary[PdfDictionaryProperties + .modificationDate], + ), + ), + ); + } + if (paramsDictionary.containsKey( + PdfDictionaryProperties.size, + )) { + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.size.toLowerCase()), + _getValue( + paramsDictionary[PdfDictionaryProperties.size], + ), + ), + ); + } + if (paramsDictionary.containsKey('CheckSum')) { + final List checksum = utf8.encode( + _getValue(paramsDictionary['CheckSum']), + ); + final String hexString = PdfString.bytesToHex(checksum); + element.attributes.add( + XmlAttribute(XmlName('checksum'), hexString), + ); + } + } + } + final String data = PdfString.bytesToHex(fStream.dataStream!); + if (!isNullOrEmpty(data)) { + element.children.add( + XmlElement( + XmlName(XfdfProperties.data.toLowerCase()), + [ + XmlAttribute( + XmlName(XfdfProperties.mode), + XfdfProperties.raw.toLowerCase(), + ), + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toLowerCase()), + XfdfProperties.hex.toLowerCase(), + ), + if (fStream.containsKey(PdfDictionaryProperties.length)) + XmlAttribute( + XmlName(PdfDictionaryProperties.length.toLowerCase()), + _getValue(fStream[PdfDictionaryProperties.length]), + ), + if (fStream.containsKey(PdfDictionaryProperties.filter)) + XmlAttribute( + XmlName(PdfDictionaryProperties.filter), + _getValue(fStream[PdfDictionaryProperties.filter]), + ), + ], + [XmlText(data)], + ), + ); + } + } + } + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.vertices)) { + final XmlElement verticesElement = XmlElement( + XmlName(PdfDictionaryProperties.vertices.toLowerCase()), + ); + final IPdfPrimitive? vertices = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.vertices], + ); + if (vertices != null && vertices is PdfArray && vertices.count > 0) { + final int elementCount = vertices.count; + if (elementCount.isEven) { + String value = ''; + IPdfPrimitive? numberElement; + for (int i = 0; i < elementCount - 1; i++) { + numberElement = vertices.elements[i]; + if (numberElement != null && numberElement is PdfNumber) { + value += _getValue(numberElement) + (i % 2 != 0 ? ';' : ','); + } + } + numberElement = vertices.elements[elementCount - 1]; + if (numberElement != null && numberElement is PdfNumber) { + value += _getValue(numberElement); + } + if (!isNullOrEmpty(value)) { + verticesElement.children.add(XmlText(value)); + } + } + } + element.children.add(verticesElement); + } + if (dictionary.containsKey(PdfDictionaryProperties.popup)) { + final IPdfPrimitive? popup = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.popup], + ); + if (popup != null && popup is PdfDictionary) { + final XmlElement? popupElement = _writeAnnotationData( + pageIndex, + exportAppearance, + popup, + ); + if (popupElement != null) { + element.children.add(popupElement); + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.da)) { + final IPdfPrimitive? defaultAppearance = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.da], + ); + if (defaultAppearance != null && defaultAppearance is PdfString) { + if (!isNullOrEmpty(defaultAppearance.value)) { + element.children.add( + XmlElement( + XmlName('defaultappearance'), + [], + [XmlText(defaultAppearance.value!)], + ), + ); + } + } + } + if (dictionary.containsKey('DS')) { + final IPdfPrimitive? defaultStyle = PdfCrossTable.dereference( + dictionary['DS'], + ); + if (defaultStyle != null && defaultStyle is PdfString) { + if (!isNullOrEmpty(defaultStyle.value)) { + element.children.add( + XmlElement(XmlName('defaultstyle'), [], [ + XmlText(defaultStyle.value!), + ]), + ); + } + } + } + if (dictionary.containsKey('InkList')) { + final IPdfPrimitive? inkList = PdfCrossTable.dereference( + dictionary['InkList'], + ); + if (inkList != null && inkList is PdfArray && inkList.count > 0) { + final XmlElement inkListElement = XmlElement(XmlName('inkList')); + for (int j = 0; j < inkList.count; j++) { + final IPdfPrimitive? list = PdfCrossTable.dereference(inkList[j]); + if (list != null && list is PdfArray) { + inkListElement.children.add( + XmlElement(XmlName('gesture'), [], [ + XmlText(_getValue(list)), + ]), + ); + } + } + element.children.add(inkListElement); + } + } + if (dictionary.containsKey('RC')) { + final IPdfPrimitive? contents = PdfCrossTable.dereference( + dictionary['RC'], + ); + if (contents != null && contents is PdfString) { + String? value = contents.value; + if (!isNullOrEmpty(value)) { + final int index = value!.indexOf(' 0) { + value = value.substring(index); + } + element.children.add( + XmlElement( + XmlName('contents-richtext'), + [], + [XmlText(value)], + ), + ); + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.contents)) { + final IPdfPrimitive? contents = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.contents], + ); + if (contents != null && contents is PdfString) { + if (!isNullOrEmpty(contents.value)) { + element.children.add( + XmlElement(XmlName('contents'), [], [ + XmlText(contents.value!), + ]), + ); + } + } + } + } + + String _getColor(IPdfPrimitive primitive) { + String color = ''; + final PdfArray colorArray = primitive as PdfArray; + if (colorArray.count >= 3) { + final String r = + PdfString.bytesToHex([ + ((colorArray.elements[0]! as PdfNumber).value! * 255).round(), + ]).toUpperCase(); + final String g = + PdfString.bytesToHex([ + ((colorArray.elements[1]! as PdfNumber).value! * 255).round(), + ]).toUpperCase(); + final String b = + PdfString.bytesToHex([ + ((colorArray.elements[2]! as PdfNumber).value! * 255).round(), + ]).toUpperCase(); + color = '#$r$g$b'; + } + return color; + } + + void _writeAttribute( + XmlElement element, + String key, + IPdfPrimitive primitive, + ) { + if (_annotationAttributes != null && + !_annotationAttributes!.contains(key)) { + switch (key) { + case PdfDictionaryProperties.c: + final String color = _getColor(primitive); + if (primitive is PdfNumber) { + final String c = _getValue(primitive); + if (!isNullOrEmpty(c) && !_annotationAttributes!.contains('c')) { + element.attributes.add(XmlAttribute(XmlName('c'), c)); + _annotationAttributes!.add('c'); + } + } + if (!isNullOrEmpty(color) && + !_annotationAttributes!.contains('color')) { + element.attributes.add(XmlAttribute(XmlName('color'), color)); + _annotationAttributes!.add('color'); + } + break; + case PdfDictionaryProperties.ic: + final String interiorColor = _getColor(primitive); + if (!isNullOrEmpty(interiorColor) && + !_annotationAttributes!.contains('interior-color')) { + element.attributes.add( + XmlAttribute(XmlName('interior-color'), interiorColor), + ); + _annotationAttributes!.add('interior-color'); + } + break; + case PdfDictionaryProperties.m: + if (!_annotationAttributes!.contains('date')) { + element.attributes.add( + XmlAttribute(XmlName('date'), _getValue(primitive)), + ); + _annotationAttributes!.add('date'); + } + break; + case 'NM': + if (!_annotationAttributes!.contains( + PdfDictionaryProperties.name.toLowerCase(), + )) { + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.name.toLowerCase()), + _getValue(primitive), + ), + ); + _annotationAttributes!.add( + PdfDictionaryProperties.name.toLowerCase(), + ); + } + break; + case PdfDictionaryProperties.name: + if (!_annotationAttributes!.contains('icon')) { + element.attributes.add( + XmlAttribute(XmlName('icon'), _getValue(primitive)), + ); + _annotationAttributes!.add('icon'); + } + break; + case PdfDictionaryProperties.subj: + if (!_annotationAttributes!.contains( + PdfDictionaryProperties.subject.toLowerCase(), + )) { + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.subject.toLowerCase()), + _getValue(primitive), + ), + ); + _annotationAttributes!.add( + PdfDictionaryProperties.subject.toLowerCase(), + ); + } + break; + case PdfDictionaryProperties.t: + if (!_annotationAttributes!.contains( + PdfDictionaryProperties.title.toLowerCase(), + )) { + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.title.toLowerCase()), + _getValue(primitive), + ), + ); + _annotationAttributes!.add( + PdfDictionaryProperties.title.toLowerCase(), + ); + } + break; + case PdfDictionaryProperties.rect: + case PdfDictionaryProperties.creationDate: + if (!_annotationAttributes!.contains(key.toLowerCase())) { + element.attributes.add( + XmlAttribute(XmlName(key.toLowerCase()), _getValue(primitive)), + ); + _annotationAttributes!.add(key.toLowerCase()); + } + break; + case PdfDictionaryProperties.rotate: + if (!_annotationAttributes!.contains('rotation')) { + element.attributes.add( + XmlAttribute(XmlName('rotation'), _getValue(primitive)), + ); + _annotationAttributes!.add('rotation'); + } + break; + case PdfDictionaryProperties.w: + if (!_annotationAttributes!.contains( + PdfDictionaryProperties.width.toLowerCase(), + )) { + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.width.toLowerCase()), + _getValue(primitive), + ), + ); + _annotationAttributes!.add( + PdfDictionaryProperties.width.toLowerCase(), + ); + } + break; + case PdfDictionaryProperties.le: + if (primitive is PdfArray) { + if (primitive.count == 2) { + element.attributes.add( + XmlAttribute(XmlName('head'), _getValue(primitive.elements[0])), + ); + element.attributes.add( + XmlAttribute(XmlName('tail'), _getValue(primitive.elements[1])), + ); + } + } else if (primitive is PdfName && + !_annotationAttributes!.contains('head')) { + element.attributes.add( + XmlAttribute(XmlName('head'), _getValue(primitive)), + ); + _annotationAttributes!.add('head'); + } + break; + case PdfDictionaryProperties.s: + if (!_annotationAttributes!.contains('style')) { + switch (_getValue(primitive)) { + case PdfDictionaryProperties.d: + element.attributes.add(XmlAttribute(XmlName('style'), 'dash')); + break; + case PdfDictionaryProperties.c: + element.attributes.add( + XmlAttribute(XmlName('style'), 'cloudy'), + ); + break; + case PdfDictionaryProperties.s: + element.attributes.add(XmlAttribute(XmlName('style'), 'solid')); + break; + case 'B': + element.attributes.add( + XmlAttribute(XmlName('style'), 'bevelled'), + ); + break; + case PdfDictionaryProperties.i: + element.attributes.add(XmlAttribute(XmlName('style'), 'inset')); + break; + case PdfDictionaryProperties.u: + element.attributes.add( + XmlAttribute(XmlName('style'), 'underline'), + ); + break; + } + _annotationAttributes!.add('style'); + } + break; + case PdfDictionaryProperties.d: + if (!_annotationAttributes!.contains('dashes')) { + element.attributes.add( + XmlAttribute(XmlName('dashes'), _getValue(primitive)), + ); + _annotationAttributes!.add('dashes'); + } + break; + case PdfDictionaryProperties.i: + if (!_annotationAttributes!.contains('intensity')) { + element.attributes.add( + XmlAttribute(XmlName('intensity'), _getValue(primitive)), + ); + _annotationAttributes!.add('intensity'); + } + break; + case PdfDictionaryProperties.rd: + if (!_annotationAttributes!.contains('fringe')) { + element.attributes.add( + XmlAttribute(XmlName('fringe'), _getValue(primitive)), + ); + _annotationAttributes!.add('fringe'); + } + break; + case PdfDictionaryProperties.it: + if (!_annotationAttributes!.contains(key)) { + element.attributes.add( + XmlAttribute(XmlName(key), _getValue(primitive)), + ); + _annotationAttributes!.add(key); + } + break; + case 'RT': + if (!_annotationAttributes!.contains('replyType')) { + element.attributes.add( + XmlAttribute( + XmlName('replyType'), + _getValue(primitive).toLowerCase(), + ), + ); + _annotationAttributes!.add('replyType'); + } + break; + case PdfDictionaryProperties.ll: + if (!_annotationAttributes!.contains('leaderLength')) { + element.attributes.add( + XmlAttribute(XmlName('leaderLength'), _getValue(primitive)), + ); + _annotationAttributes!.add('leaderLength'); + } + break; + case PdfDictionaryProperties.lle: + if (!_annotationAttributes!.contains('leaderExtend')) { + element.attributes.add( + XmlAttribute(XmlName('leaderExtend'), _getValue(primitive)), + ); + _annotationAttributes!.add('leaderExtend'); + } + break; + case PdfDictionaryProperties.cap: + if (!_annotationAttributes!.contains('caption')) { + element.attributes.add( + XmlAttribute(XmlName('caption'), _getValue(primitive)), + ); + _annotationAttributes!.add('caption'); + } + break; + case PdfDictionaryProperties.q: + if (!_annotationAttributes!.contains('justification')) { + element.attributes.add( + XmlAttribute(XmlName('justification'), _getValue(primitive)), + ); + _annotationAttributes!.add('justification'); + } + break; + case PdfDictionaryProperties.cp: + if (!_annotationAttributes!.contains('caption-style')) { + element.attributes.add( + XmlAttribute(XmlName('caption-style'), _getValue(primitive)), + ); + _annotationAttributes!.add('caption-style'); + } + break; + case 'CL': + if (!_annotationAttributes!.contains('callout')) { + element.attributes.add( + XmlAttribute(XmlName('callout'), _getValue(primitive)), + ); + _annotationAttributes!.add('callout'); + } + break; + case 'FD': + if (!_annotationAttributes!.contains(key.toLowerCase())) { + element.attributes.add( + XmlAttribute(XmlName(key.toLowerCase()), _getValue(primitive)), + ); + _annotationAttributes!.add(key.toLowerCase()); + } + break; + case PdfDictionaryProperties.quadPoints: + if (!_annotationAttributes!.contains('Coords')) { + element.attributes.add( + XmlAttribute(XmlName('coords'), _getValue(primitive)), + ); + _annotationAttributes!.add('coords'); + } + break; + case PdfDictionaryProperties.ca: + if (!_annotationAttributes!.contains('opacity')) { + element.attributes.add( + XmlAttribute(XmlName('opacity'), _getValue(primitive)), + ); + _annotationAttributes!.add('opacity'); + } + break; + case PdfDictionaryProperties.f: + if (primitive is PdfNumber && + !_annotationAttributes!.contains( + PdfDictionaryProperties.flags.toLowerCase(), + )) { + final List annotationFlags = + PdfAnnotationHelper.obtainAnnotationFlags( + primitive.value!.toInt(), + ); + final String flag = annotationFlags + .map( + (PdfAnnotationFlags flag) => getEnumName(flag).toLowerCase(), + ) + .toString() + .replaceAll(' ', ''); + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.flags.toLowerCase()), + flag.substring(1, flag.length - 1), + ), + ); + _annotationAttributes!.add( + PdfDictionaryProperties.flags.toLowerCase(), + ); + } + break; + case 'InkList': + case PdfDictionaryProperties.type: + case PdfDictionaryProperties.subtype: + case PdfDictionaryProperties.p: + case PdfDictionaryProperties.parent: + case PdfDictionaryProperties.l: + case PdfDictionaryProperties.contents: + case 'RC': + case PdfDictionaryProperties.da: + case 'DS': + case PdfDictionaryProperties.fs: + case 'MeasurementTypes': + case PdfDictionaryProperties.vertices: + case 'GroupNesting': + case 'ITEx': + break; + case PdfDictionaryProperties.open: + case 'State': + case 'StateModel': + case 'OverlayText': + case 'OC': + case PdfDictionaryProperties.llo: + case 'Repeat': + if (!_annotationAttributes!.contains(key)) { + element.attributes.add( + XmlAttribute(XmlName(key.toLowerCase()), _getValue(primitive)), + ); + _annotationAttributes!.add(key.toLowerCase()); + } + break; + case PdfDictionaryProperties.border: + if (!_annotationAttributes!.contains( + PdfDictionaryProperties.width.toLowerCase(), + ) && + !_annotationAttributes!.contains( + PdfDictionaryProperties.border.toLowerCase(), + ) && + primitive is PdfArray && + primitive.count >= 3 && + primitive.elements[2] is PdfNumber) { + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.width.toLowerCase()), + _getValue(primitive.elements[2]), + ), + ); + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.border.toLowerCase()), + _getValue(primitive), + ), + ); + _annotationAttributes!.add(PdfDictionaryProperties.border); + _annotationAttributes!.add(PdfDictionaryProperties.width); + } + break; + default: + if (!_annotationAttributes!.contains(key)) { + element.attributes.add( + XmlAttribute(XmlName(key), _getValue(primitive)), + ); + _annotationAttributes!.add(key); + } + break; + } + } + } + + /// internal method + String _getValue(IPdfPrimitive? primitive) { + String value = ''; + if (primitive != null) { + if (primitive is PdfName) { + value = primitive.name!; + } else if (primitive is PdfBoolean) { + value = primitive.value! ? 'yes' : 'no'; + } else if (primitive is PdfString) { + value = primitive.value!; + } else if (primitive is PdfArray) { + if (primitive.elements.isNotEmpty) { + value = _getValue(primitive.elements[0]); + } + for (int i = 1; i < primitive.elements.length; i++) { + value += ',${_getValue(primitive.elements[i])}'; + } + } else if (primitive is PdfNumber) { + value = primitive.value.toString(); + } + if (value.contains('\u0002')) { + value = value.replaceAll('\u0002', '\u2010'); + } + } + return value; + } + + String? _getAnnotationType(PdfDictionary dictionary) { + if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? subtype = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.subtype], + ); + if (subtype != null && subtype is PdfName && subtype.name != null) { + return subtype.name!; + } + } + return null; + } + + List _getAppearanceString(PdfDictionary appearanceDictionary) { + final XmlBuilder builder = XmlBuilder(); + builder.processing('xml', 'version="1.0" encoding="utf-8"'); + builder.element( + 'DICT', + attributes: { + XfdfProperties.key: PdfDictionaryProperties.ap, + }, + nest: _writeAppearanceDictionary(appearanceDictionary), + ); + final String xmlString = builder.buildDocument().toXmlString(); + return utf8.encode(xmlString); + } + + List _writeAppearanceDictionary(PdfDictionary dictionary) { + final List elements = []; + if (dictionary.count > 0) { + dictionary.items!.forEach((PdfName? key, IPdfPrimitive? value) { + final XmlElement? element = _writeObject(key!.name!, value); + if (element != null) { + elements.add(element); + } + }); + } + return elements; + } + + XmlElement? _writeObject(String key, IPdfPrimitive? primitive) { + XmlElement? element; + if (primitive != null) { + final String type = primitive.runtimeType.toString(); + switch (type) { + case 'PdfReferenceHolder': + element = _writeObject(key, (primitive as PdfReferenceHolder).object); + break; + case 'PdfDictionary': + element = XmlElement(XmlName(XfdfProperties.dict)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + element.children.addAll( + _writeAppearanceDictionary(primitive as PdfDictionary), + ); + break; + case 'PdfStream': + final PdfStream streamElement = primitive as PdfStream; + if (streamElement.dataStream != null && + streamElement.dataStream!.isNotEmpty) { + element = XmlElement(XmlName(XfdfProperties.stream)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.define), ''), + ); + element.children.addAll(_writeAppearanceDictionary(streamElement)); + final String type = _getValue( + streamElement[PdfDictionaryProperties.subtype], + ); + final XmlElement dataElement = XmlElement( + XmlName(XfdfProperties.data), + ); + if ((streamElement.containsKey(PdfDictionaryProperties.subtype) && + PdfDictionaryProperties.image == type) || + (!streamElement.containsKey(PdfDictionaryProperties.type) && + !streamElement.containsKey( + PdfDictionaryProperties.subtype, + ))) { + dataElement.attributes.add( + XmlAttribute(XmlName(XfdfProperties.mode), XfdfProperties.raw), + ); + dataElement.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toUpperCase()), + XfdfProperties.hex, + ), + ); + String data = ''; + if (streamElement.dataStream != null) { + data = PdfString.bytesToHex(streamElement.dataStream!); + } + if (data.isNotEmpty) { + dataElement.children.add(XmlText(data)); + } + } else if (streamElement.containsKey( + PdfDictionaryProperties.subtype, + ) && + PdfDictionaryProperties.form == type && + !_isStampAnnotation) { + dataElement.attributes.add( + XmlAttribute(XmlName(XfdfProperties.mode), XfdfProperties.raw), + ); + dataElement.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toUpperCase()), + XfdfProperties.hex, + ), + ); + String data = ''; + streamElement.decompress(); + if (streamElement.dataStream != null) { + data = PdfString.bytesToHex(streamElement.dataStream!); + } + if (data.isNotEmpty) { + dataElement.children.add(XmlText(data)); + } + } else { + streamElement.decompress(); + if (streamElement.dataStream != null) { + final String ascii = utf8.decode(streamElement.dataStream!); + if (_isStampAnnotation && !ascii.contains('TJ')) { + dataElement.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.mode), + XfdfProperties.filtered, + ), + ); + dataElement.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toUpperCase()), + XfdfProperties.ascii, + ), + ); + if (!isNullOrEmpty(ascii)) { + dataElement.children.add( + XmlText(_getFormatedString(ascii)), + ); + } + } + } else { + dataElement.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.mode), + XfdfProperties.raw, + ), + ); + dataElement.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toUpperCase()), + XfdfProperties.hex, + ), + ); + String data = ''; + streamElement.decompress(); + if (streamElement.dataStream != null) { + data = PdfString.bytesToHex(streamElement.dataStream!); + } + if (data.isNotEmpty) { + dataElement.children.add(XmlText(data)); + } + } + } + element.children.add(dataElement); + } + break; + case 'PdfBoolean': + element = XmlElement(XmlName(XfdfProperties.bool)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + element.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.val), + primitive is PdfBoolean && + primitive.value != null && + primitive.value! + ? 'true' + : 'false', + ), + ); + break; + case 'PdfName': + element = XmlElement(XmlName(XfdfProperties.name)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + element.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.val), + (primitive as PdfName).name ?? '', + ), + ); + break; + case 'PdfString': + element = XmlElement(XmlName(XfdfProperties.string)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + element.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.val), + (primitive as PdfString).value ?? '', + ), + ); + break; + case 'PdfNumber': + element = XmlElement(XmlName(XfdfProperties.fixed)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + final String value = (primitive as PdfNumber).value! + .toDouble() + .toStringAsFixed(6); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.val), value), + ); + break; + case 'PdfNull': + element = XmlElement(XmlName(XfdfProperties.nullVal)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + break; + case 'PdfArray': + element = XmlElement(XmlName(XfdfProperties.array)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.key), key), + ); + element.children.addAll(_writeArray(primitive as PdfArray)); + break; + } + } + return element; + } + + List _writeArray(PdfArray array) { + final List elements = []; + for (final IPdfPrimitive? element in array.elements) { + final XmlElement? xmlElement = _writeArrayElement(element!); + if (xmlElement != null) { + elements.add(xmlElement); + } + } + return elements; + } + + XmlElement? _writeArrayElement(IPdfPrimitive primitive) { + XmlElement? element; + final String type = primitive.runtimeType.toString(); + switch (type) { + case 'PdfArray': + element = XmlElement(XmlName(XfdfProperties.array)); + element.children.addAll(_writeArray(primitive as PdfArray)); + break; + case 'PdfName': + element = XmlElement(XmlName(XfdfProperties.name)); + element.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.val), + (primitive as PdfName).name ?? '', + ), + ); + break; + case 'PdfString': + element = XmlElement(XmlName(XfdfProperties.string)); + final RegExp regex = RegExp(r'[\u0085-\u00FF]'); + if ((primitive as PdfString).value != null && + regex.hasMatch(primitive.value!) && + primitive.isHex != null && + primitive.isHex!) { + final List bytes = primitive.pdfEncode(_document); + primitive.value = PdfString.byteToString(bytes); + element.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toUpperCase()), + XfdfProperties.hex, + ), + ); + if (!isNullOrEmpty(primitive.value)) { + element.children.add(XmlText(_getFormatedString(primitive.value!))); + } + } else { + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.val), primitive.value ?? ''), + ); + } + break; + case 'PdfNumber': + element = XmlElement(XmlName(XfdfProperties.fixed)); + final String value = (primitive as PdfNumber).value! + .toDouble() + .toStringAsFixed(6); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.val), value), + ); + break; + case 'PdfBoolean': + element = XmlElement(XmlName(XfdfProperties.bool)); + element.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.val), + (primitive as PdfBoolean).value != null && primitive.value! + ? 'true' + : 'false', + ), + ); + break; + case 'PdfDictionary': + element = XmlElement(XmlName(XfdfProperties.dict)); + element.children.addAll( + _writeAppearanceDictionary(primitive as PdfDictionary), + ); + break; + case 'PdfStream': + final PdfStream streamElement = primitive as PdfStream; + if (streamElement.dataStream != null && + streamElement.dataStream!.isNotEmpty) { + element = XmlElement(XmlName(XfdfProperties.stream)); + element.attributes.add( + XmlAttribute(XmlName(XfdfProperties.define), ''), + ); + element.children.addAll(_writeAppearanceDictionary(streamElement)); + final XmlElement dataElement = XmlElement( + XmlName(XfdfProperties.data), + ); + final String type = _getValue( + streamElement[PdfDictionaryProperties.subtype], + ); + if (streamElement.containsKey(PdfDictionaryProperties.subtype) && + PdfDictionaryProperties.image == type) { + dataElement.attributes.add( + XmlAttribute(XmlName(XfdfProperties.mode), XfdfProperties.raw), + ); + dataElement.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toUpperCase()), + XfdfProperties.hex, + ), + ); + String data = ''; + streamElement.decompress(); + if (streamElement.dataStream != null) { + data = PdfString.bytesToHex(streamElement.dataStream!); + } + if (data.isNotEmpty) { + dataElement.children.add(XmlText(data)); + } + } else { + dataElement.attributes.add( + XmlAttribute( + XmlName(XfdfProperties.mode), + XfdfProperties.filtered, + ), + ); + dataElement.attributes.add( + XmlAttribute( + XmlName(PdfDictionaryProperties.encoding.toUpperCase()), + XfdfProperties.ascii, + ), + ); + String data = ''; + streamElement.decompress(); + if (streamElement.dataStream != null) { + data = utf8.decode(streamElement.dataStream!); + } + if (data.isNotEmpty) { + dataElement.children.add(XmlText(_getFormatedString(data))); + } + } + element.children.add(dataElement); + } + break; + case 'PdfReferenceHolder': + if ((primitive as PdfReferenceHolder).object != null) { + element = _writeArrayElement(primitive.object!); + } + break; + } + return element; + } + + XmlElement _exportMeasureDictionary(PdfDictionary dictionary) { + final XmlElement measureXmlElement = XmlElement(XmlName('measure')); + final IPdfPrimitive? mdictionary = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.measure], + ); + if (mdictionary != null && mdictionary is PdfDictionary) { + if (mdictionary.containsKey(PdfDictionaryProperties.r)) { + measureXmlElement.attributes.add( + XmlAttribute( + XmlName('rateValue'), + _getValue(mdictionary[PdfDictionaryProperties.r]), + ), + ); + } + if (mdictionary.containsKey(PdfDictionaryProperties.a)) { + IPdfPrimitive? aprimitive = PdfCrossTable.dereference( + mdictionary[PdfDictionaryProperties.a], + ); + if (aprimitive != null && aprimitive is PdfArray) { + aprimitive = PdfCrossTable.dereference(aprimitive.elements[0]); + if (aprimitive != null && aprimitive is PdfDictionary) { + final XmlElement areaXmlElement = XmlElement(XmlName('area')); + _exportMeasureFormatDetails(aprimitive, areaXmlElement); + measureXmlElement.children.add(areaXmlElement); + } + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.d)) { + IPdfPrimitive? dprimitive = PdfCrossTable.dereference( + mdictionary[PdfDictionaryProperties.d], + ); + if (dprimitive != null && dprimitive is PdfArray) { + dprimitive = PdfCrossTable.dereference(dprimitive.elements[0]); + if (dprimitive != null && dprimitive is PdfDictionary) { + final XmlElement distanceXmlElement = XmlElement( + XmlName('distance'), + ); + _exportMeasureFormatDetails(dprimitive, distanceXmlElement); + measureXmlElement.children.add(distanceXmlElement); + } + } + } + if (mdictionary.containsKey(PdfDictionaryProperties.x)) { + IPdfPrimitive? xprimitive = PdfCrossTable.dereference( + mdictionary[PdfDictionaryProperties.x], + ); + if (xprimitive != null && xprimitive is PdfArray) { + xprimitive = PdfCrossTable.dereference(xprimitive.elements[0]); + if (xprimitive != null && xprimitive is PdfDictionary) { + final XmlElement xformatXmlElement = XmlElement(XmlName('xformat')); + _exportMeasureFormatDetails(xprimitive, xformatXmlElement); + measureXmlElement.children.add(xformatXmlElement); + } + } + } + } + return measureXmlElement; + } + + void _exportMeasureFormatDetails( + PdfDictionary measurementDetails, + XmlElement element, + ) { + if (measurementDetails.containsKey(PdfDictionaryProperties.c)) { + element.attributes.add( + XmlAttribute( + XmlName('c'), + _getValue(measurementDetails[PdfDictionaryProperties.c]), + ), + ); + } + if (measurementDetails.containsKey(PdfDictionaryProperties.f)) { + element.attributes.add( + XmlAttribute( + XmlName('f'), + _getValue(measurementDetails[PdfDictionaryProperties.f]), + ), + ); + } + if (measurementDetails.containsKey(PdfDictionaryProperties.d)) { + element.attributes.add( + XmlAttribute( + XmlName('d'), + _getValue(measurementDetails[PdfDictionaryProperties.d]), + ), + ); + } + if (measurementDetails.containsKey(PdfDictionaryProperties.rd)) { + element.attributes.add( + XmlAttribute( + XmlName('rd'), + _getValue(measurementDetails[PdfDictionaryProperties.rd]), + ), + ); + } + if (measurementDetails.containsKey(PdfDictionaryProperties.u)) { + element.attributes.add( + XmlAttribute( + XmlName('u'), + _getValue(measurementDetails[PdfDictionaryProperties.u]), + ), + ); + } + if (measurementDetails.containsKey('RT')) { + element.attributes.add( + XmlAttribute(XmlName('rt'), _getValue(measurementDetails['RT'])), + ); + } + if (measurementDetails.containsKey('SS')) { + element.attributes.add( + XmlAttribute(XmlName('ss'), _getValue(measurementDetails['SS'])), + ); + } + if (measurementDetails.containsKey('FD')) { + element.attributes.add( + XmlAttribute(XmlName('fd'), _getValue(measurementDetails['FD'])), + ); + } + } + + String _getFormatedString(String value) { + value = value.replaceAll('&', '&'); + value = value.replaceAll('<', '<'); + value = value.replaceAll('>', '>'); + return value; + } +} + +/// XFDF dictionary properties. +class XfdfProperties { + //Constants + /// internal field + static const String dict = 'DICT'; + + /// internal field + static const String key = 'KEY'; + + /// internal field + static const String stream = 'STREAM'; + + /// internal field + static const String define = 'DEFINE'; + + /// internal field + static const String data = 'DATA'; + + /// internal field + static const String mode = 'MODE'; + + /// internal field + static const String raw = 'RAW'; + + /// internal field + static const String hex = 'HEX'; + + /// internal field + static const String filtered = 'FILTERED'; + + /// internal field + static const String ascii = 'ASCII'; + + /// internal field + static const String bool = 'BOOL'; + + /// internal field + static const String val = 'VAL'; + + /// internal field + static const String name = 'NAME'; + + /// internal field + static const String string = 'STRING'; + + /// internal field + static const String int = 'INT'; + + /// internal field + static const String fixed = 'FIXED'; + + /// internal field + static const String nullVal = 'NULL'; + + /// internal field + static const String array = 'ARRAY'; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file.dart index 19f1e4776..7bca911d1 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file.dart @@ -1,129 +1,129 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_stream.dart'; - -/// Class which represents embedded file into Pdf document. -class EmbeddedFile implements IPdfWrapper { - //Constructor. - /// Initializes a new instance of the [EmbeddedFile] class. - EmbeddedFile(String fileName, List data) : super() { - this.data = data.toList(); - _initialize(); - this.fileName = fileName; - } - - //Fields. - /// Gets or sets the data. - late List data; - final PdfStream _stream = PdfStream(); - String _fileName = ''; - String _mimeType = ''; - - /// internal field - final EmbeddedFileParams params = EmbeddedFileParams(); - - //Properties. - /// Gets the name of the file. - String get fileName => _fileName; - - /// Sets the name of the file. - set fileName(String value) { - _fileName = _getFileName(value); - } - - /// Gets the type of the MIME. - String get mimeType => _mimeType; - - /// Sets the type of the MIME. - set mimeType(String value) { - if (_mimeType != value) { - _mimeType = value; - value = value - .replaceAll('#', '#23') - .replaceAll(' ', '#20') - .replaceAll('/', '#2F'); - _stream.setName(PdfName(PdfDictionaryProperties.subtype), value); - } - } - - //Implementations. - void _initialize() { - _stream.setProperty( - PdfDictionaryProperties.type, - PdfName(PdfDictionaryProperties.embeddedFile), - ); - _stream.setProperty(PdfDictionaryProperties.params, params); - _stream.beginSave = _streamBeginSave; - } - - String _getFileName(String attachmentName) { - final List fileName = attachmentName.split(RegExp(r'[/\\]')); - return fileName[fileName.length - 1]; - } - - void _streamBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - _stream.clearStream(); - _stream.compress = false; - _stream.data = data; - params.size = data.length; - } - - //Overrides - /// internal property - IPdfPrimitive? get element => _stream; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } -} - -/// Defines additional parameters for the embedded file. -class EmbeddedFileParams implements IPdfWrapper { - //Constructor. - /// internal constructor - EmbeddedFileParams() : super() { - creationDate = DateTime.now(); - modificationDate = DateTime.now(); - } - - //Fields - DateTime _cDate = DateTime.now(); - DateTime _mDate = DateTime.now(); - int? _fileSize; - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - //Properties. - /// internal property - DateTime get creationDate => _cDate; - set creationDate(DateTime value) { - _cDate = value; - dictionary!.setDateTime(PdfDictionaryProperties.creationDate, value); - } - - /// internal property - DateTime get modificationDate => _mDate; - set modificationDate(DateTime value) { - _mDate = value; - dictionary!.setDateTime(PdfDictionaryProperties.modificationDate, value); - } - - // int get _size => _fileSize; - /// internal property - // ignore: avoid_setters_without_getters - set size(int value) { - if (_fileSize != value) { - _fileSize = value; - dictionary!.setNumber(PdfDictionaryProperties.size, _fileSize); - } - } - - /// internal property - IPdfPrimitive? get element => dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_stream.dart'; + +/// Class which represents embedded file into Pdf document. +class EmbeddedFile implements IPdfWrapper { + //Constructor. + /// Initializes a new instance of the [EmbeddedFile] class. + EmbeddedFile(String fileName, List data) : super() { + this.data = data.toList(); + _initialize(); + this.fileName = fileName; + } + + //Fields. + /// Gets or sets the data. + late List data; + final PdfStream _stream = PdfStream(); + String _fileName = ''; + String _mimeType = ''; + + /// internal field + final EmbeddedFileParams params = EmbeddedFileParams(); + + //Properties. + /// Gets the name of the file. + String get fileName => _fileName; + + /// Sets the name of the file. + set fileName(String value) { + _fileName = _getFileName(value); + } + + /// Gets the type of the MIME. + String get mimeType => _mimeType; + + /// Sets the type of the MIME. + set mimeType(String value) { + if (_mimeType != value) { + _mimeType = value; + value = value + .replaceAll('#', '#23') + .replaceAll(' ', '#20') + .replaceAll('/', '#2F'); + _stream.setName(PdfName(PdfDictionaryProperties.subtype), value); + } + } + + //Implementations. + void _initialize() { + _stream.setProperty( + PdfDictionaryProperties.type, + PdfName(PdfDictionaryProperties.embeddedFile), + ); + _stream.setProperty(PdfDictionaryProperties.params, params); + _stream.beginSave = _streamBeginSave; + } + + String _getFileName(String attachmentName) { + final List fileName = attachmentName.split(RegExp(r'[/\\]')); + return fileName[fileName.length - 1]; + } + + void _streamBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + _stream.clearStream(); + _stream.compress = false; + _stream.data = data; + params.size = data.length; + } + + //Overrides + /// internal property + IPdfPrimitive? get element => _stream; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } +} + +/// Defines additional parameters for the embedded file. +class EmbeddedFileParams implements IPdfWrapper { + //Constructor. + /// internal constructor + EmbeddedFileParams() : super() { + creationDate = DateTime.now(); + modificationDate = DateTime.now(); + } + + //Fields + DateTime _cDate = DateTime.now(); + DateTime _mDate = DateTime.now(); + int? _fileSize; + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + //Properties. + /// internal property + DateTime get creationDate => _cDate; + set creationDate(DateTime value) { + _cDate = value; + dictionary!.setDateTime(PdfDictionaryProperties.creationDate, value); + } + + /// internal property + DateTime get modificationDate => _mDate; + set modificationDate(DateTime value) { + _mDate = value; + dictionary!.setDateTime(PdfDictionaryProperties.modificationDate, value); + } + + // int get _size => _fileSize; + /// internal property + // ignore: avoid_setters_without_getters + set size(int value) { + if (_fileSize != value) { + _fileSize = value; + dictionary!.setNumber(PdfDictionaryProperties.size, _fileSize); + } + } + + /// internal property + IPdfPrimitive? get element => dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file_specification.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file_specification.dart index 07bd6fa4b..db7393186 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file_specification.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/embedded_file_specification.dart @@ -1,85 +1,85 @@ -import '../io/pdf_constants.dart'; -import '../pdf_document/enums.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'embedded_file.dart'; -import 'file_specification_base.dart'; - -/// Represents specification of embedded file. -class PdfEmbeddedFileSpecification extends PdfFileSpecificationBase { - //Constructor - /// Initializes a new instance of the [PdfEmbeddedFileSpecification] class - PdfEmbeddedFileSpecification(String fileName, List data) : super() { - _helper = PdfEmbeddedFileSpecificationHelper(this); - PdfFileSpecificationBaseHelper.getHelper( - this, - ).dictionary!.setProperty(PdfDictionaryProperties.ef, _helper._dict); - _helper.embeddedFile = EmbeddedFile(fileName, data); - _helper.description = fileName; - } - - //Fields - late PdfEmbeddedFileSpecificationHelper _helper; -} - -/// [PdfEmbeddedFileSpecification] helper -class PdfEmbeddedFileSpecificationHelper { - /// internal constructor - PdfEmbeddedFileSpecificationHelper(this.base); - - /// internal field - PdfEmbeddedFileSpecification base; - - /// internal method - static PdfEmbeddedFileSpecificationHelper getHelper( - PdfEmbeddedFileSpecification base, - ) { - return base._helper; - } - - /// internal field - late EmbeddedFile embeddedFile; - - /// internal field - // ignore: prefer_final_fields - PdfAttachmentRelationship relationship = PdfAttachmentRelationship.source; - String _desc = ''; - final PdfDictionary _dict = PdfDictionary(); - - /// Gets the description. - String get description => _desc; - - /// Sets the description. - set description(String value) { - if (_desc != value) { - _desc = value; - PdfFileSpecificationBaseHelper.getHelper( - base, - ).dictionary!.setString(PdfDictionaryProperties.description, _desc); - } - } - - /// internal method - String getEnumName(dynamic text) { - final int index = text.toString().indexOf('.'); - final String name = text.toString().substring(index + 1); - return name[0].toUpperCase() + name.substring(1); - } - - /// internal method - void save() { - _dict[PdfDictionaryProperties.f] = PdfReferenceHolder(embeddedFile); - final PdfString str = PdfString( - PdfFileSpecificationBaseHelper.getHelper( - base, - ).formatFileName(embeddedFile.fileName, false), - ); - PdfFileSpecificationBaseHelper.getHelper( - base, - ).dictionary!.setProperty(PdfDictionaryProperties.f, str); - PdfFileSpecificationBaseHelper.getHelper( - base, - ).dictionary!.setProperty(PdfDictionaryProperties.uf, str); - } -} +import '../io/pdf_constants.dart'; +import '../pdf_document/enums.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'embedded_file.dart'; +import 'file_specification_base.dart'; + +/// Represents specification of embedded file. +class PdfEmbeddedFileSpecification extends PdfFileSpecificationBase { + //Constructor + /// Initializes a new instance of the [PdfEmbeddedFileSpecification] class + PdfEmbeddedFileSpecification(String fileName, List data) : super() { + _helper = PdfEmbeddedFileSpecificationHelper(this); + PdfFileSpecificationBaseHelper.getHelper( + this, + ).dictionary!.setProperty(PdfDictionaryProperties.ef, _helper._dict); + _helper.embeddedFile = EmbeddedFile(fileName, data); + _helper.description = fileName; + } + + //Fields + late PdfEmbeddedFileSpecificationHelper _helper; +} + +/// [PdfEmbeddedFileSpecification] helper +class PdfEmbeddedFileSpecificationHelper { + /// internal constructor + PdfEmbeddedFileSpecificationHelper(this.base); + + /// internal field + PdfEmbeddedFileSpecification base; + + /// internal method + static PdfEmbeddedFileSpecificationHelper getHelper( + PdfEmbeddedFileSpecification base, + ) { + return base._helper; + } + + /// internal field + late EmbeddedFile embeddedFile; + + /// internal field + // ignore: prefer_final_fields + PdfAttachmentRelationship relationship = PdfAttachmentRelationship.source; + String _desc = ''; + final PdfDictionary _dict = PdfDictionary(); + + /// Gets the description. + String get description => _desc; + + /// Sets the description. + set description(String value) { + if (_desc != value) { + _desc = value; + PdfFileSpecificationBaseHelper.getHelper( + base, + ).dictionary!.setString(PdfDictionaryProperties.description, _desc); + } + } + + /// internal method + String getEnumName(dynamic text) { + final int index = text.toString().indexOf('.'); + final String name = text.toString().substring(index + 1); + return name[0].toUpperCase() + name.substring(1); + } + + /// internal method + void save() { + _dict[PdfDictionaryProperties.f] = PdfReferenceHolder(embeddedFile); + final PdfString str = PdfString( + PdfFileSpecificationBaseHelper.getHelper( + base, + ).formatFileName(embeddedFile.fileName, false), + ); + PdfFileSpecificationBaseHelper.getHelper( + base, + ).dictionary!.setProperty(PdfDictionaryProperties.f, str); + PdfFileSpecificationBaseHelper.getHelper( + base, + ).dictionary!.setProperty(PdfDictionaryProperties.uf, str); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/enum.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/enum.dart index 72ac59380..e8bbd9c1f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/enum.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/enum.dart @@ -1,29 +1,29 @@ -/// Enumeration that represents fit mode. -enum PdfDestinationMode { - /// Display the page designated by page, with the coordinates (left, top) - /// positioned at the top-left corner of the window and the contents of - /// the page magnified by the factor zoom. A NULL value for any of the - /// parameters left, top, or zoom specifies that the current value of that - /// parameter is to be retained unchanged. - /// A zoom value of 0 has the same meaning as a NULL value. - location, - - /// Display the page designated by page, with its contents magnified - /// just enough to fit the entire page within the window both horizontally - /// and vertically. If the required horizontal and vertical magnification - /// factors are different, use the smaller of the two, centering the page - /// within the window in the other dimension. - fitToPage, - - /// Display the page designated by page, with the horizontal coordinate - /// left positioned at the left edge of the window and the contents of - /// the page magnified just enough to fit the entire height of the page - /// within the window. - fitR, - - /// Display the page designated by page, with the vertical coordinate - /// top positioned at the top edge of the window and the contents of the page - /// magnified just enough to fit the entire width of the page - /// within the window. - fitH, -} +/// Enumeration that represents fit mode. +enum PdfDestinationMode { + /// Display the page designated by page, with the coordinates (left, top) + /// positioned at the top-left corner of the window and the contents of + /// the page magnified by the factor zoom. A NULL value for any of the + /// parameters left, top, or zoom specifies that the current value of that + /// parameter is to be retained unchanged. + /// A zoom value of 0 has the same meaning as a NULL value. + location, + + /// Display the page designated by page, with its contents magnified + /// just enough to fit the entire page within the window both horizontally + /// and vertically. If the required horizontal and vertical magnification + /// factors are different, use the smaller of the two, centering the page + /// within the window in the other dimension. + fitToPage, + + /// Display the page designated by page, with the horizontal coordinate + /// left positioned at the left edge of the window and the contents of + /// the page magnified just enough to fit the entire height of the page + /// within the window. + fitR, + + /// Display the page designated by page, with the vertical coordinate + /// top positioned at the top edge of the window and the contents of the page + /// magnified just enough to fit the entire width of the page + /// within the window. + fitH, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/file_specification_base.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/file_specification_base.dart index 2d2520a29..e344c335d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/file_specification_base.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/file_specification_base.dart @@ -1,85 +1,85 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import 'embedded_file_specification.dart'; - -/// Represents base class for file specification objects. -abstract class PdfFileSpecificationBase implements IPdfWrapper { - //Constructor. - /// Initializes a new instance of the [PdfFileSpecificationBase] class. - PdfFileSpecificationBase() { - _helper = PdfFileSpecificationBaseHelper(this); - _helper.initialize(); - } - - //Fields - late PdfFileSpecificationBaseHelper _helper; -} - -/// [PdfFileSpecificationBase] helper -class PdfFileSpecificationBaseHelper { - /// internal constructor - PdfFileSpecificationBaseHelper(this.base); - - /// internal field - PdfFileSpecificationBase base; - - /// internal field - PdfDictionary? dictionary; - - /// internal method - static PdfFileSpecificationBaseHelper getHelper( - PdfFileSpecificationBase base, - ) { - return base._helper; - } - - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - - void initialize() { - dictionary = PdfDictionary(); - dictionary!.setProperty( - PdfDictionaryProperties.type, - PdfName(PdfDictionaryProperties.filespec), - ); - dictionary!.beginSave = _dictionaryBeginSave; - } - - //Handles the BeginSave event of the m_dictionary control. - void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - PdfFileSpecificationBaseHelper.save(base); - } - - /// internal method - String formatFileName(String fileName, bool flag) { - const String oldSlash = r'\'; - const String newSlash = '/'; - const String driveDelimiter = ':'; - if (fileName.isEmpty) { - throw ArgumentError('fileName, String can not be empty'); - } - String formated = fileName.replaceAll(oldSlash, newSlash); - formated = formated.replaceAll(driveDelimiter, ''); - if (formated.substring(0, 2) == oldSlash) { - formated = formated[0] + formated.substring(2, formated.length); - } - if (formated.substring(0, 1) != newSlash && flag == false) { - formated = formated; - } - return formated; - } - - /// internal method - static void save(PdfFileSpecificationBase base) { - if (base is PdfEmbeddedFileSpecification) { - PdfEmbeddedFileSpecificationHelper.getHelper(base).save(); - } - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import 'embedded_file_specification.dart'; + +/// Represents base class for file specification objects. +abstract class PdfFileSpecificationBase implements IPdfWrapper { + //Constructor. + /// Initializes a new instance of the [PdfFileSpecificationBase] class. + PdfFileSpecificationBase() { + _helper = PdfFileSpecificationBaseHelper(this); + _helper.initialize(); + } + + //Fields + late PdfFileSpecificationBaseHelper _helper; +} + +/// [PdfFileSpecificationBase] helper +class PdfFileSpecificationBaseHelper { + /// internal constructor + PdfFileSpecificationBaseHelper(this.base); + + /// internal field + PdfFileSpecificationBase base; + + /// internal field + PdfDictionary? dictionary; + + /// internal method + static PdfFileSpecificationBaseHelper getHelper( + PdfFileSpecificationBase base, + ) { + return base._helper; + } + + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + + void initialize() { + dictionary = PdfDictionary(); + dictionary!.setProperty( + PdfDictionaryProperties.type, + PdfName(PdfDictionaryProperties.filespec), + ); + dictionary!.beginSave = _dictionaryBeginSave; + } + + //Handles the BeginSave event of the m_dictionary control. + void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + PdfFileSpecificationBaseHelper.save(base); + } + + /// internal method + String formatFileName(String fileName, bool flag) { + const String oldSlash = r'\'; + const String newSlash = '/'; + const String driveDelimiter = ':'; + if (fileName.isEmpty) { + throw ArgumentError('fileName, String can not be empty'); + } + String formated = fileName.replaceAll(oldSlash, newSlash); + formated = formated.replaceAll(driveDelimiter, ''); + if (formated.substring(0, 2) == oldSlash) { + formated = formated[0] + formated.substring(2, formated.length); + } + if (formated.substring(0, 1) != newSlash && flag == false) { + formated = formated; + } + return formated; + } + + /// internal method + static void save(PdfFileSpecificationBase base) { + if (base is PdfEmbeddedFileSpecification) { + PdfEmbeddedFileSpecificationHelper.getHelper(base).save(); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_collection.dart index a8c11ed88..30752b1a8 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_collection.dart @@ -1,29 +1,29 @@ -/// The class used to handle the collection of PDF objects. -abstract class PdfObjectCollection { - //Fields - late PdfObjectCollectionHelper _objectCollectionHelper; - - //Properties - /// Gets number of the elements in the collection. - int get count => _objectCollectionHelper.list.length; -} - -/// [PdfObjectCollection] helper -class PdfObjectCollectionHelper { - /// internal constructor - PdfObjectCollectionHelper(this.collection) { - list = []; - collection._objectCollectionHelper = this; - } - - /// internal field - late PdfObjectCollection collection; - - /// internal method - static PdfObjectCollectionHelper getHelper(PdfObjectCollection collection) { - return collection._objectCollectionHelper; - } - - /// internal field - late List list; -} +/// The class used to handle the collection of PDF objects. +abstract class PdfObjectCollection { + //Fields + late PdfObjectCollectionHelper _objectCollectionHelper; + + //Properties + /// Gets number of the elements in the collection. + int get count => _objectCollectionHelper.list.length; +} + +/// [PdfObjectCollection] helper +class PdfObjectCollectionHelper { + /// internal constructor + PdfObjectCollectionHelper(this.collection) { + list = []; + collection._objectCollectionHelper = this; + } + + /// internal field + late PdfObjectCollection collection; + + /// internal method + static PdfObjectCollectionHelper getHelper(PdfObjectCollection collection) { + return collection._objectCollectionHelper; + } + + /// internal field + late List list; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_default_appearance.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_default_appearance.dart index 9e22adab3..61a4af6df 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_default_appearance.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_default_appearance.dart @@ -1,25 +1,25 @@ -import '../graphics/enums.dart'; -import '../graphics/pdf_color.dart'; - -/// Represents default appearance string. -class PdfDefaultAppearance { - //Constructor - /// initialize [PdfDefaultAppearance] object - PdfDefaultAppearance(); - - //Fields - /// Internal variable to store fore color. - PdfColor foreColor = PdfColor(0, 0, 0); - - /// Internal variable to store font name. - String? fontName = ''; - - /// Internal variable to store font size. - double? fontSize = 0; - - //Implementation - /// internal method - String getString() { - return '/$fontName ${fontSize! % 1 == 0 ? fontSize!.toInt() : fontSize} Tf ${PdfColorHelper.getHelper(foreColor).getString(PdfColorSpace.rgb, false)}'; - } -} +import '../graphics/enums.dart'; +import '../graphics/pdf_color.dart'; + +/// Represents default appearance string. +class PdfDefaultAppearance { + //Constructor + /// initialize [PdfDefaultAppearance] object + PdfDefaultAppearance(); + + //Fields + /// Internal variable to store fore color. + PdfColor foreColor = PdfColor(0, 0, 0); + + /// Internal variable to store font name. + String? fontName = ''; + + /// Internal variable to store font size. + double? fontSize = 0; + + //Implementation + /// internal method + String getString() { + return '/$fontName ${fontSize! % 1 == 0 ? fontSize!.toInt() : fontSize} Tf ${PdfColorHelper.getHelper(foreColor).getString(PdfColorSpace.rgb, false)}'; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_destination.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_destination.dart index f0d2fd111..ccb1f836d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_destination.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_destination.dart @@ -1,174 +1,174 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../io/pdf_constants.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_section.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'enum.dart'; - -/// Represents an anchor in the document where bookmarks -/// or annotations can direct when clicked. -class PdfDestination implements IPdfWrapper { - // constructor - /// Initializes a new instance of the [PdfDestination] class with - /// specified page and location. - PdfDestination(PdfPage page, [Offset? location]) { - _helper = PdfDestinationHelper(this); - this.page = page; - this.location = (location == null) ? Offset(0, _location.y) : location; - } - - PdfDestination._(PdfPage page, PdfRectangle rect) { - _helper = PdfDestinationHelper(this); - this.page = page; - location = rect.location.offset; - _bounds = rect; - } - - // fields - late PdfDestinationHelper _helper; - double _zoom = 0; - PdfPoint _location = PdfPoint.empty; - PdfRectangle _rect = PdfRectangle.empty; - PdfPage? _page; - final PdfArray _array = PdfArray(); - PdfDestinationMode _destinationMode = PdfDestinationMode.location; - - // Properties - /// Gets zoom factor. - double get zoom => _zoom; - - /// Sets zoom factor. - set zoom(double value) { - if (value != _zoom) { - _zoom = value; - _initializePrimitive(); - } - } - - /// Gets a page where the destination is situated. - PdfPage get page => _page!; - - /// Sets a page where the destination is situated. - set page(PdfPage value) { - if (value != _page) { - _page = value; - _initializePrimitive(); - } - } - - /// Gets mode of the destination. - PdfDestinationMode get mode { - return _destinationMode; - } - - /// Sets mode of the destination. - set mode(PdfDestinationMode value) { - if (value != _destinationMode) { - _destinationMode = value; - _initializePrimitive(); - } - } - - /// Gets a location of the destination. - Offset get location => _location.offset; - - /// Sets a location of the destination. - set location(Offset value) { - final PdfPoint position = PdfPoint.fromOffset(value); - if (position != _location) { - _location = position; - _initializePrimitive(); - } - } - - PdfRectangle get _bounds => _rect; - - set _bounds(PdfRectangle value) { - if (_rect != value) { - _rect = value; - _initializePrimitive(); - } - } - - // implementation - void _initializePrimitive() { - _array.clear(); - _array.add(PdfReferenceHolder(_page)); - switch (mode) { - case PdfDestinationMode.location: - PdfPoint point = PdfPoint.empty; - if (PdfPageHelper.getHelper(page).isLoadedPage) { - point.x = _location.x; - point.y = page.size.height - _location.y; - } else { - point = _pointToNativePdf(page, PdfPoint(_location.x, _location.y)); - } - _array.add(PdfName(PdfDictionaryProperties.xyz)); - _array.add(PdfNumber(point.x)); - _array.add(PdfNumber(point.y)); - _array.add(PdfNumber(_zoom)); - break; - - case PdfDestinationMode.fitToPage: - _array.add(PdfName(PdfDictionaryProperties.fit)); - break; - - case PdfDestinationMode.fitR: - { - _array.add(PdfName(PdfDictionaryProperties.fitR)); - _array.add(PdfNumber(_bounds.x)); - _array.add(PdfNumber(_bounds.y)); - _array.add(PdfNumber(_bounds.width)); - _array.add(PdfNumber(_bounds.height)); - } - break; - - case PdfDestinationMode.fitH: - final PdfPage page = _page!; - double value = 0; - if (PdfPageHelper.getHelper(page).isLoadedPage) { - value = page.size.height - _location.y; - } else { - value = page.size.height - _location.y; - } - _array.add(PdfName(PdfDictionaryProperties.fitH)); - _array.add(PdfNumber(value)); - break; - } - _helper.element = _array; - } - - PdfPoint _pointToNativePdf(PdfPage page, PdfPoint point) { - return PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page).section!, - ).pointToNativePdf(page, point); - } -} - -/// [PdfDestination] helper -class PdfDestinationHelper { - /// internal constructor - PdfDestinationHelper(this.destination); - - /// internal field - late PdfDestination destination; - - /// internal method - static PdfDestinationHelper getHelper(PdfDestination destination) { - return destination._helper; - } - - /// internal method - static PdfDestination getDestination(PdfPage page, PdfRectangle rect) { - return PdfDestination._(page, rect); - } - - /// internal field - IPdfPrimitive? element; -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../io/pdf_constants.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_section.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'enum.dart'; + +/// Represents an anchor in the document where bookmarks +/// or annotations can direct when clicked. +class PdfDestination implements IPdfWrapper { + // constructor + /// Initializes a new instance of the [PdfDestination] class with + /// specified page and location. + PdfDestination(PdfPage page, [Offset? location]) { + _helper = PdfDestinationHelper(this); + this.page = page; + this.location = (location == null) ? Offset(0, _location.y) : location; + } + + PdfDestination._(PdfPage page, PdfRectangle rect) { + _helper = PdfDestinationHelper(this); + this.page = page; + location = rect.location.offset; + _bounds = rect; + } + + // fields + late PdfDestinationHelper _helper; + double _zoom = 0; + PdfPoint _location = PdfPoint.empty; + PdfRectangle _rect = PdfRectangle.empty; + PdfPage? _page; + final PdfArray _array = PdfArray(); + PdfDestinationMode _destinationMode = PdfDestinationMode.location; + + // Properties + /// Gets zoom factor. + double get zoom => _zoom; + + /// Sets zoom factor. + set zoom(double value) { + if (value != _zoom) { + _zoom = value; + _initializePrimitive(); + } + } + + /// Gets a page where the destination is situated. + PdfPage get page => _page!; + + /// Sets a page where the destination is situated. + set page(PdfPage value) { + if (value != _page) { + _page = value; + _initializePrimitive(); + } + } + + /// Gets mode of the destination. + PdfDestinationMode get mode { + return _destinationMode; + } + + /// Sets mode of the destination. + set mode(PdfDestinationMode value) { + if (value != _destinationMode) { + _destinationMode = value; + _initializePrimitive(); + } + } + + /// Gets a location of the destination. + Offset get location => _location.offset; + + /// Sets a location of the destination. + set location(Offset value) { + final PdfPoint position = PdfPoint.fromOffset(value); + if (position != _location) { + _location = position; + _initializePrimitive(); + } + } + + PdfRectangle get _bounds => _rect; + + set _bounds(PdfRectangle value) { + if (_rect != value) { + _rect = value; + _initializePrimitive(); + } + } + + // implementation + void _initializePrimitive() { + _array.clear(); + _array.add(PdfReferenceHolder(_page)); + switch (mode) { + case PdfDestinationMode.location: + PdfPoint point = PdfPoint.empty; + if (PdfPageHelper.getHelper(page).isLoadedPage) { + point.x = _location.x; + point.y = page.size.height - _location.y; + } else { + point = _pointToNativePdf(page, PdfPoint(_location.x, _location.y)); + } + _array.add(PdfName(PdfDictionaryProperties.xyz)); + _array.add(PdfNumber(point.x)); + _array.add(PdfNumber(point.y)); + _array.add(PdfNumber(_zoom)); + break; + + case PdfDestinationMode.fitToPage: + _array.add(PdfName(PdfDictionaryProperties.fit)); + break; + + case PdfDestinationMode.fitR: + { + _array.add(PdfName(PdfDictionaryProperties.fitR)); + _array.add(PdfNumber(_bounds.x)); + _array.add(PdfNumber(_bounds.y)); + _array.add(PdfNumber(_bounds.width)); + _array.add(PdfNumber(_bounds.height)); + } + break; + + case PdfDestinationMode.fitH: + final PdfPage page = _page!; + double value = 0; + if (PdfPageHelper.getHelper(page).isLoadedPage) { + value = page.size.height - _location.y; + } else { + value = page.size.height - _location.y; + } + _array.add(PdfName(PdfDictionaryProperties.fitH)); + _array.add(PdfNumber(value)); + break; + } + _helper.element = _array; + } + + PdfPoint _pointToNativePdf(PdfPage page, PdfPoint point) { + return PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page).section!, + ).pointToNativePdf(page, point); + } +} + +/// [PdfDestination] helper +class PdfDestinationHelper { + /// internal constructor + PdfDestinationHelper(this.destination); + + /// internal field + late PdfDestination destination; + + /// internal method + static PdfDestinationHelper getHelper(PdfDestination destination) { + return destination._helper; + } + + /// internal method + static PdfDestination getDestination(PdfPage page, PdfRectangle rect) { + return PdfDestination._(page, rect); + } + + /// internal field + IPdfPrimitive? element; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination.dart index 69333f7da..5eef5e925 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination.dart @@ -1,198 +1,198 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_collection.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_destination.dart'; - -/// Represents an named destination which goes to a destination -/// in the current document. -class PdfNamedDestination implements IPdfWrapper { - /// Initializes a new instance of the [PdfNamedDestination] class - /// with the title to be displayed. - PdfNamedDestination(String title) { - _helper = PdfNamedDestinationHelper(this); - this.title = title; - _initialize(); - } - - PdfNamedDestination._( - PdfDictionary dictionary, - PdfCrossTable crossTable, - bool isLoaded, - ) : super() { - _helper = PdfNamedDestinationHelper(this); - _helper.dictionary = dictionary; - _crossTable = crossTable; - _isLoaded = isLoaded; - } - - //Fields - late PdfNamedDestinationHelper _helper; - PdfDestination? _destination; - PdfCrossTable _crossTable = PdfCrossTable(); - bool _isLoaded = false; - - //Properties - /// Gets the named destination's destination. - PdfDestination? get destination { - if (_isLoaded) { - return _obtainDestination(); - } else { - return _destination; - } - } - - /// Sets the named destination's destination. - /// The destination property has to be mentioned as multiples of 100. - /// If we mention as 2, the zoom value will be 200. - set destination(PdfDestination? value) { - if (value != null) { - _destination = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.d, _destination); - } - } - - /// Gets the named destination title. - String get title { - if (_isLoaded) { - String? title = ''; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.title)) { - final PdfString str = - _crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.title], - )! - as PdfString; - title = str.value; - } - return title!; - } else { - final PdfString? title = - _helper.dictionary![PdfDictionaryProperties.title] as PdfString?; - String? value; - if (title != null) { - value = title.value; - } - return value!; - } - } - - /// Sets the named destination title. - set title(String value) { - _helper.dictionary![PdfDictionaryProperties.title] = PdfString(value); - } - - /// Initializes instance. - void _initialize() { - _helper.dictionary!.beginSave = (Object sender, SavePdfPrimitiveArgs? ars) { - _helper.dictionary!.setProperty(PdfDictionaryProperties.d, _destination); - }; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.s, - PdfName(PdfDictionaryProperties.goTo), - ); - } - - PdfDestination? _obtainDestination() { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.d) && - (_destination == null)) { - final IPdfPrimitive? obj = _crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.d], - ); - final PdfArray? destination = obj as PdfArray?; - if (destination != null && destination.count > 1) { - final PdfReferenceHolder? referenceHolder = - destination[0] as PdfReferenceHolder?; - PdfPage? page; - if (referenceHolder != null) { - final PdfDictionary? dictionary = - _crossTable.getObject(referenceHolder) as PdfDictionary?; - if (dictionary != null) { - page = PdfPageCollectionHelper.getHelper( - _crossTable.document!.pages, - ).getPage(dictionary); - } - } - - final PdfName? mode = destination[1] as PdfName?; - if (mode != null) { - if ((mode.name == 'FitBH' || mode.name == 'FitH') && - destination.count > 2) { - final PdfNumber? top = destination[2] as PdfNumber?; - if (page != null) { - final double topValue = - (top == null) ? 0 : page.size.height - top.value!; - _destination = PdfDestination(page, Offset(0, topValue)); - _destination!.mode = PdfDestinationMode.fitH; - } - } else if (mode.name == 'XYZ' && destination.count > 3) { - final PdfNumber? left = destination[2] as PdfNumber?; - final PdfNumber? top = destination[3] as PdfNumber?; - PdfNumber? zoom; - if (destination.count > 4 && destination[4] is PdfNumber) { - zoom = destination[4]! as PdfNumber; - } - if (page != null) { - final double topValue = - (top == null) ? 0 : page.size.height - top.value!; - final double leftValue = - (left == null) ? 0 : left.value! as double; - _destination = PdfDestination(page, Offset(leftValue, topValue)); - if (zoom != null) { - _destination!.zoom = zoom.value!.toDouble(); - } - } - } else { - if (page != null && mode.name == 'Fit') { - _destination = PdfDestination(page); - _destination!.mode = PdfDestinationMode.fitToPage; - } - } - } - } - } - return _destination; - } -} - -/// [PdfNamedDestination] helper -class PdfNamedDestinationHelper { - /// internal constructor - PdfNamedDestinationHelper(this.destination); - - /// internal field - late PdfNamedDestination destination; - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal property - IPdfPrimitive? get element => dictionary; - - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - static PdfNamedDestinationHelper getHelper(PdfNamedDestination destination) { - return destination._helper; - } - - /// internal method - static PdfNamedDestination load( - PdfDictionary dictionary, - PdfCrossTable crossTable, - bool isLoaded, - ) { - return PdfNamedDestination._(dictionary, crossTable, isLoaded); - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_collection.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_destination.dart'; + +/// Represents an named destination which goes to a destination +/// in the current document. +class PdfNamedDestination implements IPdfWrapper { + /// Initializes a new instance of the [PdfNamedDestination] class + /// with the title to be displayed. + PdfNamedDestination(String title) { + _helper = PdfNamedDestinationHelper(this); + this.title = title; + _initialize(); + } + + PdfNamedDestination._( + PdfDictionary dictionary, + PdfCrossTable crossTable, + bool isLoaded, + ) : super() { + _helper = PdfNamedDestinationHelper(this); + _helper.dictionary = dictionary; + _crossTable = crossTable; + _isLoaded = isLoaded; + } + + //Fields + late PdfNamedDestinationHelper _helper; + PdfDestination? _destination; + PdfCrossTable _crossTable = PdfCrossTable(); + bool _isLoaded = false; + + //Properties + /// Gets the named destination's destination. + PdfDestination? get destination { + if (_isLoaded) { + return _obtainDestination(); + } else { + return _destination; + } + } + + /// Sets the named destination's destination. + /// The destination property has to be mentioned as multiples of 100. + /// If we mention as 2, the zoom value will be 200. + set destination(PdfDestination? value) { + if (value != null) { + _destination = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.d, _destination); + } + } + + /// Gets the named destination title. + String get title { + if (_isLoaded) { + String? title = ''; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.title)) { + final PdfString str = + _crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.title], + )! + as PdfString; + title = str.value; + } + return title!; + } else { + final PdfString? title = + _helper.dictionary![PdfDictionaryProperties.title] as PdfString?; + String? value; + if (title != null) { + value = title.value; + } + return value!; + } + } + + /// Sets the named destination title. + set title(String value) { + _helper.dictionary![PdfDictionaryProperties.title] = PdfString(value); + } + + /// Initializes instance. + void _initialize() { + _helper.dictionary!.beginSave = (Object sender, SavePdfPrimitiveArgs? ars) { + _helper.dictionary!.setProperty(PdfDictionaryProperties.d, _destination); + }; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.s, + PdfName(PdfDictionaryProperties.goTo), + ); + } + + PdfDestination? _obtainDestination() { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.d) && + (_destination == null)) { + final IPdfPrimitive? obj = _crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.d], + ); + final PdfArray? destination = obj as PdfArray?; + if (destination != null && destination.count > 1) { + final PdfReferenceHolder? referenceHolder = + destination[0] as PdfReferenceHolder?; + PdfPage? page; + if (referenceHolder != null) { + final PdfDictionary? dictionary = + _crossTable.getObject(referenceHolder) as PdfDictionary?; + if (dictionary != null) { + page = PdfPageCollectionHelper.getHelper( + _crossTable.document!.pages, + ).getPage(dictionary); + } + } + + final PdfName? mode = destination[1] as PdfName?; + if (mode != null) { + if ((mode.name == 'FitBH' || mode.name == 'FitH') && + destination.count > 2) { + final PdfNumber? top = destination[2] as PdfNumber?; + if (page != null) { + final double topValue = + (top == null) ? 0 : page.size.height - top.value!; + _destination = PdfDestination(page, Offset(0, topValue)); + _destination!.mode = PdfDestinationMode.fitH; + } + } else if (mode.name == 'XYZ' && destination.count > 3) { + final PdfNumber? left = destination[2] as PdfNumber?; + final PdfNumber? top = destination[3] as PdfNumber?; + PdfNumber? zoom; + if (destination.count > 4 && destination[4] is PdfNumber) { + zoom = destination[4]! as PdfNumber; + } + if (page != null) { + final double topValue = + (top == null) ? 0 : page.size.height - top.value!; + final double leftValue = + (left == null) ? 0 : left.value! as double; + _destination = PdfDestination(page, Offset(leftValue, topValue)); + if (zoom != null) { + _destination!.zoom = zoom.value!.toDouble(); + } + } + } else { + if (page != null && mode.name == 'Fit') { + _destination = PdfDestination(page); + _destination!.mode = PdfDestinationMode.fitToPage; + } + } + } + } + } + return _destination; + } +} + +/// [PdfNamedDestination] helper +class PdfNamedDestinationHelper { + /// internal constructor + PdfNamedDestinationHelper(this.destination); + + /// internal field + late PdfNamedDestination destination; + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal property + IPdfPrimitive? get element => dictionary; + + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + static PdfNamedDestinationHelper getHelper(PdfNamedDestination destination) { + return destination._helper; + } + + /// internal method + static PdfNamedDestination load( + PdfDictionary dictionary, + PdfCrossTable crossTable, + bool isLoaded, + ) { + return PdfNamedDestination._(dictionary, crossTable, isLoaded); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination_collection.dart index d87f1fd46..13aa72015 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/pdf_named_destination_collection.dart @@ -1,261 +1,261 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_named_destination.dart'; - -/// Implements a collection of named destinations in the document. -class PdfNamedDestinationCollection implements IPdfWrapper { - /// Initializes a new instance of the [PdfNamedDestinationCollection] class. - PdfNamedDestinationCollection() : super() { - _helper = PdfNamedDestinationCollectionHelper(this); - _initialize(); - } - - PdfNamedDestinationCollection._( - PdfDictionary? dictionary, - PdfCrossTable? crossTable, - ) { - _helper = PdfNamedDestinationCollectionHelper(this); - _helper.dictionary = dictionary; - if (crossTable != null) { - _crossTable = crossTable; - } - if (_helper.dictionary != null && - _helper.dictionary!.containsKey(PdfDictionaryProperties.dests)) { - final PdfDictionary? destination = - PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.dests], - ) - as PdfDictionary?; - if (destination != null && - destination.containsKey(PdfDictionaryProperties.names)) { - _addCollection(destination); - } else if (destination != null && - destination.containsKey(PdfDictionaryProperties.kids)) { - final PdfArray? kids = - PdfCrossTable.dereference(destination[PdfDictionaryProperties.kids]) - as PdfArray?; - if (kids != null) { - for (int i = 0; i < kids.count; i++) { - _findDestination( - PdfCrossTable.dereference(kids[i]) as PdfDictionary?, - ); - } - } - } - } - PdfDocumentHelper.getHelper(_crossTable.document!).catalog.beginSave = ( - Object sender, - SavePdfPrimitiveArgs? ars, - ) { - for (final PdfNamedDestination values in _namedCollections) { - _namedDestination.add(PdfString(values.title)); - _namedDestination.add(PdfReferenceHolder(values)); - } - _helper.dictionary!.setProperty( - PdfDictionaryProperties.names, - PdfReferenceHolder(_namedDestination), - ); - - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.dests)) { - final PdfDictionary? destsDictionary = - PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.dests], - ) - as PdfDictionary?; - if (destsDictionary != null && - !destsDictionary.containsKey(PdfDictionaryProperties.kids)) { - destsDictionary.setProperty( - PdfDictionaryProperties.names, - PdfReferenceHolder(_namedDestination), - ); - } - } else { - _helper.dictionary!.setProperty( - PdfDictionaryProperties.names, - PdfReferenceHolder(_namedDestination), - ); - } - }; - PdfDocumentHelper.getHelper(_crossTable.document!).catalog.modify(); - } - - //Fields - late PdfNamedDestinationCollectionHelper _helper; - final List _namedCollections = []; - PdfCrossTable _crossTable = PdfCrossTable(); - final PdfArray _namedDestination = PdfArray(); - - //Properties - /// Gets number of the elements in the collection. - int get count => _namedCollections.length; - - /// Gets the [PdfNamedDestination] at the specified index. - PdfNamedDestination operator [](int index) { - if (index < 0 || index > count - 1) { - throw RangeError('$index, Index is out of range.'); - } - return _namedCollections[index]; - } - - /// Creates and adds a named destination. - void add(PdfNamedDestination namedDestination) { - _namedCollections.add(namedDestination); - } - - /// Determines whether the specified named destinations - /// presents in the collection. - bool contains(PdfNamedDestination namedDestination) { - return _namedCollections.contains(namedDestination); - } - - /// Remove the specified named destination from the document. - void remove(String title) { - int index = -1; - for (int i = 0; i < _namedCollections.length; i++) { - if (_namedCollections[i].title == title) { - index = i; - break; - } - } - removeAt(index); - } - - /// Remove the specified named destination from the document. - void removeAt(int index) { - if (index >= _namedCollections.length) { - throw RangeError( - 'The index value should not be greater than or equal to the count.', - ); - } - _namedCollections.removeAt(index); - } - - /// Removes all the named destination from the collection. - void clear() { - _namedCollections.clear(); - } - - /// Inserts a new named destination at the specified index. - void insert(int index, PdfNamedDestination namedDestination) { - if (index < 0 || index > count) { - throw RangeError( - "The index can't be less then zero or greater then Count.", - ); - } - _namedCollections.insert(index, namedDestination); - } - - /// Initializes instance. - void _initialize() { - _helper.dictionary!.beginSave = (Object sender, SavePdfPrimitiveArgs? ars) { - for (final PdfNamedDestination values in _namedCollections) { - _namedDestination.add(PdfString(values.title)); - _namedDestination.add(PdfReferenceHolder(values)); - } - _helper.dictionary!.setProperty( - PdfDictionaryProperties.names, - PdfReferenceHolder(_namedDestination), - ); - }; - } - - void _addCollection(PdfDictionary namedDictionary) { - final PdfArray? elements = - PdfCrossTable.dereference( - namedDictionary[PdfDictionaryProperties.names], - ) - as PdfArray?; - if (elements != null) { - for (int i = 1; i <= elements.count; i = i + 2) { - PdfReferenceHolder? reference; - if (elements[i] is PdfReferenceHolder) { - reference = elements[i]! as PdfReferenceHolder; - } - PdfDictionary? dictionary; - if (reference != null && reference.object is PdfArray) { - dictionary = PdfDictionary(); - dictionary.setProperty( - PdfDictionaryProperties.d, - PdfArray(reference.object as PdfArray?), - ); - } else if (reference == null && elements[i] is PdfArray) { - dictionary = PdfDictionary(); - final PdfArray referenceArray = elements[i]! as PdfArray; - dictionary.setProperty( - PdfDictionaryProperties.d, - PdfArray(referenceArray), - ); - } else { - dictionary = reference!.object as PdfDictionary?; - } - if (dictionary != null) { - final PdfNamedDestination namedDestinations = - PdfNamedDestinationHelper.load(dictionary, _crossTable, true); - final PdfString? title = elements[i - 1] as PdfString?; - if (title != null) { - namedDestinations.title = title.value!; - } - _namedCollections.add(namedDestinations); - } - } - } - } - - void _findDestination(PdfDictionary? destination) { - if (destination != null && - destination.containsKey(PdfDictionaryProperties.names)) { - _addCollection(destination); - } else if (destination != null && - destination.containsKey(PdfDictionaryProperties.kids)) { - final PdfArray? kids = - PdfCrossTable.dereference(destination[PdfDictionaryProperties.kids]) - as PdfArray?; - if (kids != null) { - for (int i = 0; i < kids.count; i++) { - _findDestination( - PdfCrossTable.dereference(kids[i]) as PdfDictionary?, - ); - } - } - } - } -} - -/// [PdfNamedDestinationCollection] helper -class PdfNamedDestinationCollectionHelper { - /// internal constructor - PdfNamedDestinationCollectionHelper(this.destination); - - /// internal field - late PdfNamedDestinationCollection destination; - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal method - static PdfNamedDestinationCollectionHelper getHelper( - PdfNamedDestinationCollection destination, - ) { - return destination._helper; - } - - /// internal method - static PdfNamedDestinationCollection load( - PdfDictionary? dictionary, - PdfCrossTable? crossTable, - ) { - return PdfNamedDestinationCollection._(dictionary, crossTable); - } - - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_named_destination.dart'; + +/// Implements a collection of named destinations in the document. +class PdfNamedDestinationCollection implements IPdfWrapper { + /// Initializes a new instance of the [PdfNamedDestinationCollection] class. + PdfNamedDestinationCollection() : super() { + _helper = PdfNamedDestinationCollectionHelper(this); + _initialize(); + } + + PdfNamedDestinationCollection._( + PdfDictionary? dictionary, + PdfCrossTable? crossTable, + ) { + _helper = PdfNamedDestinationCollectionHelper(this); + _helper.dictionary = dictionary; + if (crossTable != null) { + _crossTable = crossTable; + } + if (_helper.dictionary != null && + _helper.dictionary!.containsKey(PdfDictionaryProperties.dests)) { + final PdfDictionary? destination = + PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.dests], + ) + as PdfDictionary?; + if (destination != null && + destination.containsKey(PdfDictionaryProperties.names)) { + _addCollection(destination); + } else if (destination != null && + destination.containsKey(PdfDictionaryProperties.kids)) { + final PdfArray? kids = + PdfCrossTable.dereference(destination[PdfDictionaryProperties.kids]) + as PdfArray?; + if (kids != null) { + for (int i = 0; i < kids.count; i++) { + _findDestination( + PdfCrossTable.dereference(kids[i]) as PdfDictionary?, + ); + } + } + } + } + PdfDocumentHelper.getHelper(_crossTable.document!).catalog.beginSave = ( + Object sender, + SavePdfPrimitiveArgs? ars, + ) { + for (final PdfNamedDestination values in _namedCollections) { + _namedDestination.add(PdfString(values.title)); + _namedDestination.add(PdfReferenceHolder(values)); + } + _helper.dictionary!.setProperty( + PdfDictionaryProperties.names, + PdfReferenceHolder(_namedDestination), + ); + + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.dests)) { + final PdfDictionary? destsDictionary = + PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.dests], + ) + as PdfDictionary?; + if (destsDictionary != null && + !destsDictionary.containsKey(PdfDictionaryProperties.kids)) { + destsDictionary.setProperty( + PdfDictionaryProperties.names, + PdfReferenceHolder(_namedDestination), + ); + } + } else { + _helper.dictionary!.setProperty( + PdfDictionaryProperties.names, + PdfReferenceHolder(_namedDestination), + ); + } + }; + PdfDocumentHelper.getHelper(_crossTable.document!).catalog.modify(); + } + + //Fields + late PdfNamedDestinationCollectionHelper _helper; + final List _namedCollections = []; + PdfCrossTable _crossTable = PdfCrossTable(); + final PdfArray _namedDestination = PdfArray(); + + //Properties + /// Gets number of the elements in the collection. + int get count => _namedCollections.length; + + /// Gets the [PdfNamedDestination] at the specified index. + PdfNamedDestination operator [](int index) { + if (index < 0 || index > count - 1) { + throw RangeError('$index, Index is out of range.'); + } + return _namedCollections[index]; + } + + /// Creates and adds a named destination. + void add(PdfNamedDestination namedDestination) { + _namedCollections.add(namedDestination); + } + + /// Determines whether the specified named destinations + /// presents in the collection. + bool contains(PdfNamedDestination namedDestination) { + return _namedCollections.contains(namedDestination); + } + + /// Remove the specified named destination from the document. + void remove(String title) { + int index = -1; + for (int i = 0; i < _namedCollections.length; i++) { + if (_namedCollections[i].title == title) { + index = i; + break; + } + } + removeAt(index); + } + + /// Remove the specified named destination from the document. + void removeAt(int index) { + if (index >= _namedCollections.length) { + throw RangeError( + 'The index value should not be greater than or equal to the count.', + ); + } + _namedCollections.removeAt(index); + } + + /// Removes all the named destination from the collection. + void clear() { + _namedCollections.clear(); + } + + /// Inserts a new named destination at the specified index. + void insert(int index, PdfNamedDestination namedDestination) { + if (index < 0 || index > count) { + throw RangeError( + "The index can't be less then zero or greater then Count.", + ); + } + _namedCollections.insert(index, namedDestination); + } + + /// Initializes instance. + void _initialize() { + _helper.dictionary!.beginSave = (Object sender, SavePdfPrimitiveArgs? ars) { + for (final PdfNamedDestination values in _namedCollections) { + _namedDestination.add(PdfString(values.title)); + _namedDestination.add(PdfReferenceHolder(values)); + } + _helper.dictionary!.setProperty( + PdfDictionaryProperties.names, + PdfReferenceHolder(_namedDestination), + ); + }; + } + + void _addCollection(PdfDictionary namedDictionary) { + final PdfArray? elements = + PdfCrossTable.dereference( + namedDictionary[PdfDictionaryProperties.names], + ) + as PdfArray?; + if (elements != null) { + for (int i = 1; i <= elements.count; i = i + 2) { + PdfReferenceHolder? reference; + if (elements[i] is PdfReferenceHolder) { + reference = elements[i]! as PdfReferenceHolder; + } + PdfDictionary? dictionary; + if (reference != null && reference.object is PdfArray) { + dictionary = PdfDictionary(); + dictionary.setProperty( + PdfDictionaryProperties.d, + PdfArray(reference.object as PdfArray?), + ); + } else if (reference == null && elements[i] is PdfArray) { + dictionary = PdfDictionary(); + final PdfArray referenceArray = elements[i]! as PdfArray; + dictionary.setProperty( + PdfDictionaryProperties.d, + PdfArray(referenceArray), + ); + } else { + dictionary = reference!.object as PdfDictionary?; + } + if (dictionary != null) { + final PdfNamedDestination namedDestinations = + PdfNamedDestinationHelper.load(dictionary, _crossTable, true); + final PdfString? title = elements[i - 1] as PdfString?; + if (title != null) { + namedDestinations.title = title.value!; + } + _namedCollections.add(namedDestinations); + } + } + } + } + + void _findDestination(PdfDictionary? destination) { + if (destination != null && + destination.containsKey(PdfDictionaryProperties.names)) { + _addCollection(destination); + } else if (destination != null && + destination.containsKey(PdfDictionaryProperties.kids)) { + final PdfArray? kids = + PdfCrossTable.dereference(destination[PdfDictionaryProperties.kids]) + as PdfArray?; + if (kids != null) { + for (int i = 0; i < kids.count; i++) { + _findDestination( + PdfCrossTable.dereference(kids[i]) as PdfDictionary?, + ); + } + } + } + } +} + +/// [PdfNamedDestinationCollection] helper +class PdfNamedDestinationCollectionHelper { + /// internal constructor + PdfNamedDestinationCollectionHelper(this.destination); + + /// internal field + late PdfNamedDestinationCollection destination; + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal method + static PdfNamedDestinationCollectionHelper getHelper( + PdfNamedDestinationCollection destination, + ) { + return destination._helper; + } + + /// internal method + static PdfNamedDestinationCollection load( + PdfDictionary? dictionary, + PdfCrossTable? crossTable, + ) { + return PdfNamedDestinationCollection._(dictionary, crossTable); + } + + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/windows1252encoding.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/windows1252encoding.dart index 85fae6576..ac190b5d6 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/windows1252encoding.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/general/windows1252encoding.dart @@ -1,271 +1,271 @@ -class Windows1252Encoding { - static const List _charCodeTable = [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 123, - 124, - 125, - 126, - 127, - 8364, - 65533, - 8218, - 402, - 8222, - 8230, - 8224, - 8225, - 710, - 8240, - 352, - 8249, - 338, - 65533, - 381, - 65533, - 65533, - 8216, - 8217, - 8220, - 8221, - 8226, - 8211, - 8212, - 732, - 8482, - 353, - 8250, - 339, - 65533, - 382, - 376, - 160, - 161, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 171, - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 187, - 188, - 189, - 190, - 191, - 192, - 193, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 209, - 210, - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 219, - 220, - 221, - 222, - 223, - 224, - 225, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237, - 238, - 239, - 240, - 241, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 251, - 252, - 253, - 254, - 255, - ]; - - List getBytes(String s) { - final List bytes = []; - for (int i = 0; i < s.length; i++) { - final int index = s.codeUnitAt(i); - if (index < _charCodeTable.length) { - bytes.add(_charCodeTable[index]); - } - } - return bytes; - } -} +class Windows1252Encoding { + static const List _charCodeTable = [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 8364, + 65533, + 8218, + 402, + 8222, + 8230, + 8224, + 8225, + 710, + 8240, + 352, + 8249, + 338, + 65533, + 381, + 65533, + 65533, + 8216, + 8217, + 8220, + 8221, + 8226, + 8211, + 8212, + 732, + 8482, + 353, + 8250, + 339, + 65533, + 382, + 376, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + ]; + + List getBytes(String s) { + final List bytes = []; + for (int i = 0; i < s.length; i++) { + final int index = s.codeUnitAt(i); + if (index < _charCodeTable.length) { + bytes.add(_charCodeTable[index]); + } + } + return bytes; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_brush.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_brush.dart index 412e2c7bb..edc2f2b83 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_brush.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_brush.dart @@ -1,3032 +1,3032 @@ -import '../../drawing/color.dart'; -import '../../graphics/pdf_color.dart'; -import 'pdf_solid_brush.dart'; - -/// Brushes for all the standard colors. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Draw rectangle. -/// doc.pages.add().graphics.drawRectangle( -/// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 200, 100)); -/// //Save the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -class PdfBrushes { - PdfBrushes._(); - static final Map _brushes = {}; - - /// Gets the AliceBlue brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.aliceBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get aliceBlue { - if (_brushes.containsKey(KnownColor.aliceBlue)) { - return _brushes[KnownColor.aliceBlue]!; - } else { - return _getBrush(KnownColor.aliceBlue); - } - } - - /// Gets the Antique white brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.antiqueWhite, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get antiqueWhite { - if (_brushes.containsKey(KnownColor.antiqueWhite)) { - return _brushes[KnownColor.antiqueWhite]!; - } else { - return _getBrush(KnownColor.antiqueWhite); - } - } - - /// Gets the Aqua default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.aqua, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get aqua { - if (_brushes.containsKey(KnownColor.aqua)) { - return _brushes[KnownColor.aqua]!; - } else { - return _getBrush(KnownColor.aqua); - } - } - - /// Gets the Aquamarine default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.aquamarine, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get aquamarine { - if (_brushes.containsKey(KnownColor.aquamarine)) { - return _brushes[KnownColor.aquamarine]!; - } else { - return _getBrush(KnownColor.aquamarine); - } - } - - /// Gets the Azure default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.azure, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get azure { - if (_brushes.containsKey(KnownColor.azure)) { - return _brushes[KnownColor.azure]!; - } else { - return _getBrush(KnownColor.azure); - } - } - - /// Gets the Beige default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.beige, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get beige { - if (_brushes.containsKey(KnownColor.beige)) { - return _brushes[KnownColor.beige]!; - } else { - return _getBrush(KnownColor.beige); - } - } - - /// Gets the Bisque default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.bisque, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get bisque { - if (_brushes.containsKey(KnownColor.bisque)) { - return _brushes[KnownColor.bisque]!; - } else { - return _getBrush(KnownColor.bisque); - } - } - - /// Gets the Black default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get black { - if (_brushes.containsKey(KnownColor.black)) { - return _brushes[KnownColor.black]!; - } else { - return _getBrush(KnownColor.black); - } - } - - /// Gets the BlanchedAlmond default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.blanchedAlmond, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get blanchedAlmond { - if (_brushes.containsKey(KnownColor.blanchedAlmond)) { - return _brushes[KnownColor.blanchedAlmond]!; - } else { - return _getBrush(KnownColor.blanchedAlmond); - } - } - - /// Gets the Blue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.blue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get blue { - if (_brushes.containsKey(KnownColor.blue)) { - return _brushes[KnownColor.blue]!; - } else { - return _getBrush(KnownColor.blue); - } - } - - /// Gets the BlueViolet default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.blueViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get blueViolet { - if (_brushes.containsKey(KnownColor.blueViolet)) { - return _brushes[KnownColor.blueViolet]!; - } else { - return _getBrush(KnownColor.blueViolet); - } - } - - /// Gets the Brown default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.brown, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get brown { - if (_brushes.containsKey(KnownColor.brown)) { - return _brushes[KnownColor.brown]!; - } else { - return _getBrush(KnownColor.brown); - } - } - - /// Gets the BurlyWood default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.burlyWood, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get burlyWood { - if (_brushes.containsKey(KnownColor.burlyWood)) { - return _brushes[KnownColor.burlyWood]!; - } else { - return _getBrush(KnownColor.burlyWood); - } - } - - /// Gets the CadetBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.cadetBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get cadetBlue { - if (_brushes.containsKey(KnownColor.cadetBlue)) { - return _brushes[KnownColor.cadetBlue]!; - } else { - return _getBrush(KnownColor.cadetBlue); - } - } - - /// Gets the Chartreuse default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.chartreuse, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get chartreuse { - if (_brushes.containsKey(KnownColor.chartreuse)) { - return _brushes[KnownColor.chartreuse]!; - } else { - return _getBrush(KnownColor.chartreuse); - } - } - - /// Gets the Chocolate default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.chocolate, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get chocolate { - if (_brushes.containsKey(KnownColor.chocolate)) { - return _brushes[KnownColor.chocolate]!; - } else { - return _getBrush(KnownColor.chocolate); - } - } - - /// Gets the Coral default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.coral, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get coral { - if (_brushes.containsKey(KnownColor.coral)) { - return _brushes[KnownColor.coral]!; - } else { - return _getBrush(KnownColor.coral); - } - } - - /// Gets the CornflowerBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.cornflowerBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get cornflowerBlue { - if (_brushes.containsKey(KnownColor.cornflowerBlue)) { - return _brushes[KnownColor.cornflowerBlue]!; - } else { - return _getBrush(KnownColor.cornflowerBlue); - } - } - - /// Gets the Corn silk default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.cornsilk, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get cornsilk { - if (_brushes.containsKey(KnownColor.cornsilk)) { - return _brushes[KnownColor.cornsilk]!; - } else { - return _getBrush(KnownColor.cornsilk); - } - } - - /// Gets the Crimson default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.crimson, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get crimson { - if (_brushes.containsKey(KnownColor.crimson)) { - return _brushes[KnownColor.crimson]!; - } else { - return _getBrush(KnownColor.crimson); - } - } - - /// Gets the Cyan default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.cyan, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get cyan { - if (_brushes.containsKey(KnownColor.cyan)) { - return _brushes[KnownColor.cyan]!; - } else { - return _getBrush(KnownColor.cyan); - } - } - - /// Gets the DarkBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkBlue { - if (_brushes.containsKey(KnownColor.darkBlue)) { - return _brushes[KnownColor.darkBlue]!; - } else { - return _getBrush(KnownColor.darkBlue); - } - } - - /// Gets the DarkCyan default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkCyan, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkCyan { - if (_brushes.containsKey(KnownColor.darkCyan)) { - return _brushes[KnownColor.darkCyan]!; - } else { - return _getBrush(KnownColor.darkCyan); - } - } - - /// Gets the DarkGoldenrod default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkGoldenrod, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkGoldenrod { - if (_brushes.containsKey(KnownColor.darkGoldenrod)) { - return _brushes[KnownColor.darkGoldenrod]!; - } else { - return _getBrush(KnownColor.darkGoldenrod); - } - } - - /// Gets the DarkGray default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkGray { - if (_brushes.containsKey(KnownColor.darkGray)) { - return _brushes[KnownColor.darkGray]!; - } else { - return _getBrush(KnownColor.darkGray); - } - } - - /// Gets the DarkGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkGreen { - if (_brushes.containsKey(KnownColor.darkGreen)) { - return _brushes[KnownColor.darkGreen]!; - } else { - return _getBrush(KnownColor.darkGreen); - } - } - - /// Gets the DarkKhaki default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkKhaki, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkKhaki { - if (_brushes.containsKey(KnownColor.darkKhaki)) { - return _brushes[KnownColor.darkKhaki]!; - } else { - return _getBrush(KnownColor.darkKhaki); - } - } - - /// Gets the DarkMagenta default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkMagenta, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkMagenta { - if (_brushes.containsKey(KnownColor.darkMagenta)) { - return _brushes[KnownColor.darkMagenta]!; - } else { - return _getBrush(KnownColor.darkMagenta); - } - } - - /// Gets the DarkOliveGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkOliveGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkOliveGreen { - if (_brushes.containsKey(KnownColor.darkOliveGreen)) { - return _brushes[KnownColor.darkOliveGreen]!; - } else { - return _getBrush(KnownColor.darkOliveGreen); - } - } - - /// Gets the DarkOrange default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkOrange, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkOrange { - if (_brushes.containsKey(KnownColor.darkOrange)) { - return _brushes[KnownColor.darkOrange]!; - } else { - return _getBrush(KnownColor.darkOrange); - } - } - - /// Gets the DarkOrchid default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkOrchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkOrchid { - if (_brushes.containsKey(KnownColor.darkOrchid)) { - return _brushes[KnownColor.darkOrchid]!; - } else { - return _getBrush(KnownColor.darkOrchid); - } - } - - /// Gets the DarkRed default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkRed { - if (_brushes.containsKey(KnownColor.darkRed)) { - return _brushes[KnownColor.darkRed]!; - } else { - return _getBrush(KnownColor.darkRed); - } - } - - /// Gets the DarkSalmon default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkSalmon { - if (_brushes.containsKey(KnownColor.darkSalmon)) { - return _brushes[KnownColor.darkSalmon]!; - } else { - return _getBrush(KnownColor.darkSalmon); - } - } - - /// Gets the DarkSeaGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkSeaGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkSeaGreen { - if (_brushes.containsKey(KnownColor.darkSeaGreen)) { - return _brushes[KnownColor.darkSeaGreen]!; - } else { - return _getBrush(KnownColor.darkSeaGreen); - } - } - - /// Gets the DarkSlateBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkSlateBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkSlateBlue { - if (_brushes.containsKey(KnownColor.darkSlateBlue)) { - return _brushes[KnownColor.darkSlateBlue]!; - } else { - return _getBrush(KnownColor.darkSlateBlue); - } - } - - /// Gets the DarkSlateGray default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkSlateGray, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkSlateGray { - if (_brushes.containsKey(KnownColor.darkSlateGray)) { - return _brushes[KnownColor.darkSlateGray]!; - } else { - return _getBrush(KnownColor.darkSlateGray); - } - } - - /// Gets the DarkTurquoise default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkTurquoise, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkTurquoise { - if (_brushes.containsKey(KnownColor.darkTurquoise)) { - return _brushes[KnownColor.darkTurquoise]!; - } else { - return _getBrush(KnownColor.darkTurquoise); - } - } - - /// Gets the DarkViolet default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.darkViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get darkViolet { - if (_brushes.containsKey(KnownColor.darkViolet)) { - return _brushes[KnownColor.darkViolet]!; - } else { - return _getBrush(KnownColor.darkViolet); - } - } - - /// Gets the DeepPink default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.deepPink, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get deepPink { - if (_brushes.containsKey(KnownColor.deepPink)) { - return _brushes[KnownColor.deepPink]!; - } else { - return _getBrush(KnownColor.deepPink); - } - } - - /// Gets the DeepSkyBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.deepSkyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get deepSkyBlue { - if (_brushes.containsKey(KnownColor.deepSkyBlue)) { - return _brushes[KnownColor.deepSkyBlue]!; - } else { - return _getBrush(KnownColor.deepSkyBlue); - } - } - - /// Gets the DimGray default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.dimGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get dimGray { - if (_brushes.containsKey(KnownColor.dimGray)) { - return _brushes[KnownColor.dimGray]!; - } else { - return _getBrush(KnownColor.dimGray); - } - } - - /// Gets the DodgerBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.dodgerBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get dodgerBlue { - if (_brushes.containsKey(KnownColor.dodgerBlue)) { - return _brushes[KnownColor.dodgerBlue]!; - } else { - return _getBrush(KnownColor.dodgerBlue); - } - } - - /// Gets the Firebrick default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.firebrick, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get firebrick { - if (_brushes.containsKey(KnownColor.firebrick)) { - return _brushes[KnownColor.firebrick]!; - } else { - return _getBrush(KnownColor.firebrick); - } - } - - /// Gets the FloralWhite default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.floralWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get floralWhite { - if (_brushes.containsKey(KnownColor.floralWhite)) { - return _brushes[KnownColor.floralWhite]!; - } else { - return _getBrush(KnownColor.floralWhite); - } - } - - /// Gets the ForestGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.forestGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get forestGreen { - if (_brushes.containsKey(KnownColor.forestGreen)) { - return _brushes[KnownColor.forestGreen]!; - } else { - return _getBrush(KnownColor.forestGreen); - } - } - - /// Gets the Fuchsia default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.fuchsia, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get fuchsia { - if (_brushes.containsKey(KnownColor.fuchsia)) { - return _brushes[KnownColor.fuchsia]!; - } else { - return _getBrush(KnownColor.fuchsia); - } - } - - /// Gets the Gainsborough default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.gainsboro, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get gainsboro { - if (_brushes.containsKey(KnownColor.gainsboro)) { - return _brushes[KnownColor.gainsboro]!; - } else { - return _getBrush(KnownColor.gainsboro); - } - } - - /// Gets the GhostWhite default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.ghostWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get ghostWhite { - if (_brushes.containsKey(KnownColor.ghostWhite)) { - return _brushes[KnownColor.ghostWhite]!; - } else { - return _getBrush(KnownColor.ghostWhite); - } - } - - /// Gets the Gold default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.gold, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get gold { - if (_brushes.containsKey(KnownColor.gold)) { - return _brushes[KnownColor.gold]!; - } else { - return _getBrush(KnownColor.gold); - } - } - - /// Gets the Goldenrod default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.goldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get goldenrod { - if (_brushes.containsKey(KnownColor.goldenrod)) { - return _brushes[KnownColor.goldenrod]!; - } else { - return _getBrush(KnownColor.goldenrod); - } - } - - /// Gets the Gray default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.gray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get gray { - if (_brushes.containsKey(KnownColor.gray)) { - return _brushes[KnownColor.gray]!; - } else { - return _getBrush(KnownColor.gray); - } - } - - /// Gets the Green default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.green, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get green { - if (_brushes.containsKey(KnownColor.green)) { - return _brushes[KnownColor.green]!; - } else { - return _getBrush(KnownColor.green); - } - } - - /// Gets the GreenYellow default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.greenYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get greenYellow { - if (_brushes.containsKey(KnownColor.greenYellow)) { - return _brushes[KnownColor.greenYellow]!; - } else { - return _getBrush(KnownColor.greenYellow); - } - } - - /// Gets the Honeydew default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.honeydew, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get honeydew { - if (_brushes.containsKey(KnownColor.honeydew)) { - return _brushes[KnownColor.honeydew]!; - } else { - return _getBrush(KnownColor.honeydew); - } - } - - /// Gets the HotPink default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.hotPink, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get hotPink { - if (_brushes.containsKey(KnownColor.hotPink)) { - return _brushes[KnownColor.hotPink]!; - } else { - return _getBrush(KnownColor.hotPink); - } - } - - /// Gets the IndianRed default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.indianRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get indianRed { - if (_brushes.containsKey(KnownColor.indianRed)) { - return _brushes[KnownColor.indianRed]!; - } else { - return _getBrush(KnownColor.indianRed); - } - } - - /// Gets the Indigo default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.indigo, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get indigo { - if (_brushes.containsKey(KnownColor.indigo)) { - return _brushes[KnownColor.indigo]!; - } else { - return _getBrush(KnownColor.indigo); - } - } - - /// Gets the Ivory default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.ivory, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get ivory { - if (_brushes.containsKey(KnownColor.ivory)) { - return _brushes[KnownColor.ivory]!; - } else { - return _getBrush(KnownColor.ivory); - } - } - - /// Gets the Khaki default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.khaki, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get khaki { - if (_brushes.containsKey(KnownColor.khaki)) { - return _brushes[KnownColor.khaki]!; - } else { - return _getBrush(KnownColor.khaki); - } - } - - /// Gets the Lavender default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lavender, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lavender { - if (_brushes.containsKey(KnownColor.lavender)) { - return _brushes[KnownColor.lavender]!; - } else { - return _getBrush(KnownColor.lavender); - } - } - - /// Gets the LavenderBlush default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lavenderBlush, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lavenderBlush { - if (_brushes.containsKey(KnownColor.lavenderBlush)) { - return _brushes[KnownColor.lavenderBlush]!; - } else { - return _getBrush(KnownColor.lavenderBlush); - } - } - - /// Gets the LawnGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lawnGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lawnGreen { - if (_brushes.containsKey(KnownColor.lawnGreen)) { - return _brushes[KnownColor.lawnGreen]!; - } else { - return _getBrush(KnownColor.lawnGreen); - } - } - - /// Gets the LemonChiffon default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lemonChiffon, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lemonChiffon { - if (_brushes.containsKey(KnownColor.lemonChiffon)) { - return _brushes[KnownColor.lemonChiffon]!; - } else { - return _getBrush(KnownColor.lemonChiffon); - } - } - - /// Gets the LightBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightBlue { - if (_brushes.containsKey(KnownColor.lightBlue)) { - return _brushes[KnownColor.lightBlue]!; - } else { - return _getBrush(KnownColor.lightBlue); - } - } - - /// Gets the LightCoral default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightCoral, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightCoral { - if (_brushes.containsKey(KnownColor.lightCoral)) { - return _brushes[KnownColor.lightCoral]!; - } else { - return _getBrush(KnownColor.lightCoral); - } - } - - /// Gets the LightCyan default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightCyan, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightCyan { - if (_brushes.containsKey(KnownColor.lightCyan)) { - return _brushes[KnownColor.lightCyan]!; - } else { - return _getBrush(KnownColor.lightCyan); - } - } - - /// Gets the LightGoldenrodYellow default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightGoldenrodYellow, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightGoldenrodYellow { - if (_brushes.containsKey(KnownColor.lightGoldenrodYellow)) { - return _brushes[KnownColor.lightGoldenrodYellow]!; - } else { - return _getBrush(KnownColor.lightGoldenrodYellow); - } - } - - /// Gets the LightGray default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightGray { - if (_brushes.containsKey(KnownColor.lightGray)) { - return _brushes[KnownColor.lightGray]!; - } else { - return _getBrush(KnownColor.lightGray); - } - } - - /// Gets the LightGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightGreen { - if (_brushes.containsKey(KnownColor.lightGreen)) { - return _brushes[KnownColor.lightGreen]!; - } else { - return _getBrush(KnownColor.lightGreen); - } - } - - /// Gets the LightPink default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightPink, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightPink { - if (_brushes.containsKey(KnownColor.lightPink)) { - return _brushes[KnownColor.lightPink]!; - } else { - return _getBrush(KnownColor.lightPink); - } - } - - /// Gets the LightSalmon default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightSalmon { - if (_brushes.containsKey(KnownColor.lightSalmon)) { - return _brushes[KnownColor.lightSalmon]!; - } else { - return _getBrush(KnownColor.lightSalmon); - } - } - - /// Gets the LightSeaGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightSeaGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightSeaGreen { - if (_brushes.containsKey(KnownColor.lightSeaGreen)) { - return _brushes[KnownColor.lightSeaGreen]!; - } else { - return _getBrush(KnownColor.lightSeaGreen); - } - } - - /// Gets the LightSkyBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightSkyBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightSkyBlue { - if (_brushes.containsKey(KnownColor.lightSkyBlue)) { - return _brushes[KnownColor.lightSkyBlue]!; - } else { - return _getBrush(KnownColor.lightSkyBlue); - } - } - - /// Gets the LightSlateGray default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightSlateGray, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightSlateGray { - if (_brushes.containsKey(KnownColor.lightSlateGray)) { - return _brushes[KnownColor.lightSlateGray]!; - } else { - return _getBrush(KnownColor.lightSlateGray); - } - } - - /// Gets the LightSteelBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightSteelBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightSteelBlue { - if (_brushes.containsKey(KnownColor.lightSteelBlue)) { - return _brushes[KnownColor.lightSteelBlue]!; - } else { - return _getBrush(KnownColor.lightSteelBlue); - } - } - - /// Gets the LightYellow default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lightYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lightYellow { - if (_brushes.containsKey(KnownColor.lightYellow)) { - return _brushes[KnownColor.lightYellow]!; - } else { - return _getBrush(KnownColor.lightYellow); - } - } - - /// Gets the Lime default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.lime, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get lime { - if (_brushes.containsKey(KnownColor.lime)) { - return _brushes[KnownColor.lime]!; - } else { - return _getBrush(KnownColor.lime); - } - } - - /// Gets the LimeGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.limeGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get limeGreen { - if (_brushes.containsKey(KnownColor.limeGreen)) { - return _brushes[KnownColor.limeGreen]!; - } else { - return _getBrush(KnownColor.limeGreen); - } - } - - /// Gets the Linen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.linen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get linen { - if (_brushes.containsKey(KnownColor.linen)) { - return _brushes[KnownColor.linen]!; - } else { - return _getBrush(KnownColor.linen); - } - } - - /// Gets the Magenta default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.magenta, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get magenta { - if (_brushes.containsKey(KnownColor.magenta)) { - return _brushes[KnownColor.magenta]!; - } else { - return _getBrush(KnownColor.magenta); - } - } - - /// Gets the Maroon default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.maroon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get maroon { - if (_brushes.containsKey(KnownColor.maroon)) { - return _brushes[KnownColor.maroon]!; - } else { - return _getBrush(KnownColor.maroon); - } - } - - /// Gets the MediumAquamarine default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumAquamarine, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumAquamarine { - if (_brushes.containsKey(KnownColor.mediumAquamarine)) { - return _brushes[KnownColor.mediumAquamarine]!; - } else { - return _getBrush(KnownColor.mediumAquamarine); - } - } - - /// Gets the MediumBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumBlue { - if (_brushes.containsKey(KnownColor.mediumBlue)) { - return _brushes[KnownColor.mediumBlue]!; - } else { - return _getBrush(KnownColor.mediumBlue); - } - } - - /// Gets the MediumOrchid default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumOrchid, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumOrchid { - if (_brushes.containsKey(KnownColor.mediumOrchid)) { - return _brushes[KnownColor.mediumOrchid]!; - } else { - return _getBrush(KnownColor.mediumOrchid); - } - } - - /// Gets the MediumPurple default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumPurple, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumPurple { - if (_brushes.containsKey(KnownColor.mediumPurple)) { - return _brushes[KnownColor.mediumPurple]!; - } else { - return _getBrush(KnownColor.mediumPurple); - } - } - - /// Gets the MediumSeaGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumSeaGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumSeaGreen { - if (_brushes.containsKey(KnownColor.mediumSeaGreen)) { - return _brushes[KnownColor.mediumSeaGreen]!; - } else { - return _getBrush(KnownColor.mediumSeaGreen); - } - } - - /// Gets the MediumSlateBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumSlateBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumSlateBlue { - if (_brushes.containsKey(KnownColor.mediumSlateBlue)) { - return _brushes[KnownColor.mediumSlateBlue]!; - } else { - return _getBrush(KnownColor.mediumSlateBlue); - } - } - - /// Gets the MediumSpringGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumSpringGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumSpringGreen { - if (_brushes.containsKey(KnownColor.mediumSpringGreen)) { - return _brushes[KnownColor.mediumSpringGreen]!; - } else { - return _getBrush(KnownColor.mediumSpringGreen); - } - } - - /// Gets the MediumTurquoise default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumTurquoise, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumTurquoise { - if (_brushes.containsKey(KnownColor.mediumTurquoise)) { - return _brushes[KnownColor.mediumTurquoise]!; - } else { - return _getBrush(KnownColor.mediumTurquoise); - } - } - - /// Gets the MediumVioletRed default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mediumVioletRed, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mediumVioletRed { - if (_brushes.containsKey(KnownColor.mediumVioletRed)) { - return _brushes[KnownColor.mediumVioletRed]!; - } else { - return _getBrush(KnownColor.mediumVioletRed); - } - } - - /// Gets the MidnightBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.midnightBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get midnightBlue { - if (_brushes.containsKey(KnownColor.midnightBlue)) { - return _brushes[KnownColor.midnightBlue]!; - } else { - return _getBrush(KnownColor.midnightBlue); - } - } - - /// Gets the MintCream default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mintCream, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mintCream { - if (_brushes.containsKey(KnownColor.mintCream)) { - return _brushes[KnownColor.mintCream]!; - } else { - return _getBrush(KnownColor.mintCream); - } - } - - /// Gets the MistyRose default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.mistyRose, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get mistyRose { - if (_brushes.containsKey(KnownColor.mistyRose)) { - return _brushes[KnownColor.mistyRose]!; - } else { - return _getBrush(KnownColor.mistyRose); - } - } - - /// Gets the Moccasin default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.moccasin, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get moccasin { - if (_brushes.containsKey(KnownColor.moccasin)) { - return _brushes[KnownColor.moccasin]!; - } else { - return _getBrush(KnownColor.moccasin); - } - } - - /// Gets the NavajoWhite default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.navajoWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get navajoWhite { - if (_brushes.containsKey(KnownColor.navajoWhite)) { - return _brushes[KnownColor.navajoWhite]!; - } else { - return _getBrush(KnownColor.navajoWhite); - } - } - - /// Gets the Navy default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.navy, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get navy { - if (_brushes.containsKey(KnownColor.navy)) { - return _brushes[KnownColor.navy]!; - } else { - return _getBrush(KnownColor.navy); - } - } - - /// Gets the OldLace default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.oldLace, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get oldLace { - if (_brushes.containsKey(KnownColor.oldLace)) { - return _brushes[KnownColor.oldLace]!; - } else { - return _getBrush(KnownColor.oldLace); - } - } - - /// Gets the Olive default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.olive, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get olive { - if (_brushes.containsKey(KnownColor.olive)) { - return _brushes[KnownColor.olive]!; - } else { - return _getBrush(KnownColor.olive); - } - } - - /// Gets the OliveDrab default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.oliveDrab, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get oliveDrab { - if (_brushes.containsKey(KnownColor.oliveDrab)) { - return _brushes[KnownColor.oliveDrab]!; - } else { - return _getBrush(KnownColor.oliveDrab); - } - } - - /// Gets the Orange default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.orange, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get orange { - if (_brushes.containsKey(KnownColor.orange)) { - return _brushes[KnownColor.orange]!; - } else { - return _getBrush(KnownColor.orange); - } - } - - /// Gets the OrangeRed default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.orangeRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get orangeRed { - if (_brushes.containsKey(KnownColor.orangeRed)) { - return _brushes[KnownColor.orangeRed]!; - } else { - return _getBrush(KnownColor.orangeRed); - } - } - - /// Gets the Orchid default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.orchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get orchid { - if (_brushes.containsKey(KnownColor.orchid)) { - return _brushes[KnownColor.orchid]!; - } else { - return _getBrush(KnownColor.orchid); - } - } - - /// Gets the PaleGoldenrod default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.paleGoldenrod, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get paleGoldenrod { - if (_brushes.containsKey(KnownColor.paleGoldenrod)) { - return _brushes[KnownColor.paleGoldenrod]!; - } else { - return _getBrush(KnownColor.paleGoldenrod); - } - } - - /// Gets the PaleGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.paleGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get paleGreen { - if (_brushes.containsKey(KnownColor.paleGreen)) { - return _brushes[KnownColor.paleGreen]!; - } else { - return _getBrush(KnownColor.paleGreen); - } - } - - /// Gets the PaleTurquoise default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.paleTurquoise, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get paleTurquoise { - if (_brushes.containsKey(KnownColor.paleTurquoise)) { - return _brushes[KnownColor.paleTurquoise]!; - } else { - return _getBrush(KnownColor.paleTurquoise); - } - } - - /// Gets the PaleVioletRed default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.paleVioletRed, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get paleVioletRed { - if (_brushes.containsKey(KnownColor.paleVioletRed)) { - return _brushes[KnownColor.paleVioletRed]!; - } else { - return _getBrush(KnownColor.paleVioletRed); - } - } - - /// Gets the PapayaWhip default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.papayaWhip, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get papayaWhip { - if (_brushes.containsKey(KnownColor.papayaWhip)) { - return _brushes[KnownColor.papayaWhip]!; - } else { - return _getBrush(KnownColor.papayaWhip); - } - } - - /// Gets the PeachPuff default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.peachPuff, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get peachPuff { - if (_brushes.containsKey(KnownColor.peachPuff)) { - return _brushes[KnownColor.peachPuff]!; - } else { - return _getBrush(KnownColor.peachPuff); - } - } - - /// Gets the Peru default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.peru, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get peru { - if (_brushes.containsKey(KnownColor.peru)) { - return _brushes[KnownColor.peru]!; - } else { - return _getBrush(KnownColor.peru); - } - } - - /// Gets the Pink default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.pink, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get pink { - if (_brushes.containsKey(KnownColor.pink)) { - return _brushes[KnownColor.pink]!; - } else { - return _getBrush(KnownColor.pink); - } - } - - /// Gets the Plum default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.plum, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get plum { - if (_brushes.containsKey(KnownColor.plum)) { - return _brushes[KnownColor.plum]!; - } else { - return _getBrush(KnownColor.plum); - } - } - - /// Gets the PowderBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.powderBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get powderBlue { - if (_brushes.containsKey(KnownColor.powderBlue)) { - return _brushes[KnownColor.powderBlue]!; - } else { - return _getBrush(KnownColor.powderBlue); - } - } - - /// Gets the Purple default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.purple, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get purple { - if (_brushes.containsKey(KnownColor.purple)) { - return _brushes[KnownColor.purple]!; - } else { - return _getBrush(KnownColor.purple); - } - } - - /// Gets the Red default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get red { - if (_brushes.containsKey(KnownColor.red)) { - return _brushes[KnownColor.red]!; - } else { - return _getBrush(KnownColor.red); - } - } - - /// Gets the RosyBrown default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.rosyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get rosyBrown { - if (_brushes.containsKey(KnownColor.rosyBrown)) { - return _brushes[KnownColor.rosyBrown]!; - } else { - return _getBrush(KnownColor.rosyBrown); - } - } - - /// Gets the RoyalBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.royalBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get royalBlue { - if (_brushes.containsKey(KnownColor.royalBlue)) { - return _brushes[KnownColor.royalBlue]!; - } else { - return _getBrush(KnownColor.royalBlue); - } - } - - /// Gets the SaddleBrown default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.saddleBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get saddleBrown { - if (_brushes.containsKey(KnownColor.saddleBrown)) { - return _brushes[KnownColor.saddleBrown]!; - } else { - return _getBrush(KnownColor.saddleBrown); - } - } - - /// Gets the Salmon default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.salmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get salmon { - if (_brushes.containsKey(KnownColor.salmon)) { - return _brushes[KnownColor.salmon]!; - } else { - return _getBrush(KnownColor.salmon); - } - } - - /// Gets the SandyBrown default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.sandyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get sandyBrown { - if (_brushes.containsKey(KnownColor.sandyBrown)) { - return _brushes[KnownColor.sandyBrown]!; - } else { - return _getBrush(KnownColor.sandyBrown); - } - } - - /// Gets the SeaGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.seaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get seaGreen { - if (_brushes.containsKey(KnownColor.seaGreen)) { - return _brushes[KnownColor.seaGreen]!; - } else { - return _getBrush(KnownColor.seaGreen); - } - } - - /// Gets the SeaShell default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.seaShell, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get seaShell { - if (_brushes.containsKey(KnownColor.seaShell)) { - return _brushes[KnownColor.seaShell]!; - } else { - return _getBrush(KnownColor.seaShell); - } - } - - /// Gets the Sienna default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.sienna, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get sienna { - if (_brushes.containsKey(KnownColor.sienna)) { - return _brushes[KnownColor.sienna]!; - } else { - return _getBrush(KnownColor.sienna); - } - } - - /// Gets the Silver default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.silver, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get silver { - if (_brushes.containsKey(KnownColor.silver)) { - return _brushes[KnownColor.silver]!; - } else { - return _getBrush(KnownColor.silver); - } - } - - /// Gets the SkyBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.skyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get skyBlue { - if (_brushes.containsKey(KnownColor.skyBlue)) { - return _brushes[KnownColor.skyBlue]!; - } else { - return _getBrush(KnownColor.skyBlue); - } - } - - /// Gets the SlateBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.slateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get slateBlue { - if (_brushes.containsKey(KnownColor.slateBlue)) { - return _brushes[KnownColor.slateBlue]!; - } else { - return _getBrush(KnownColor.slateBlue); - } - } - - /// Gets the SlateGray default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.slateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get slateGray { - if (_brushes.containsKey(KnownColor.slateGray)) { - return _brushes[KnownColor.slateGray]!; - } else { - return _getBrush(KnownColor.slateGray); - } - } - - /// Gets the Snow default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.snow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get snow { - if (_brushes.containsKey(KnownColor.snow)) { - return _brushes[KnownColor.snow]!; - } else { - return _getBrush(KnownColor.snow); - } - } - - /// Gets the SpringGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.springGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get springGreen { - if (_brushes.containsKey(KnownColor.springGreen)) { - return _brushes[KnownColor.springGreen]!; - } else { - return _getBrush(KnownColor.springGreen); - } - } - - /// Gets the SteelBlue default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.steelBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get steelBlue { - if (_brushes.containsKey(KnownColor.steelBlue)) { - return _brushes[KnownColor.steelBlue]!; - } else { - return _getBrush(KnownColor.steelBlue); - } - } - - /// Gets the Tan default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.tan, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get tan { - if (_brushes.containsKey(KnownColor.tan)) { - return _brushes[KnownColor.tan]!; - } else { - return _getBrush(KnownColor.tan); - } - } - - /// Gets the Teal default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.teal, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get teal { - if (_brushes.containsKey(KnownColor.teal)) { - return _brushes[KnownColor.teal]!; - } else { - return _getBrush(KnownColor.teal); - } - } - - /// Gets the Thistle default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.thistle, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get thistle { - if (_brushes.containsKey(KnownColor.thistle)) { - return _brushes[KnownColor.thistle]!; - } else { - return _getBrush(KnownColor.thistle); - } - } - - /// Gets the Tomato default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.tomato, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get tomato { - if (_brushes.containsKey(KnownColor.tomato)) { - return _brushes[KnownColor.tomato]!; - } else { - return _getBrush(KnownColor.tomato); - } - } - - /// Gets the Transparent default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.transparent, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get transparent { - if (_brushes.containsKey(KnownColor.transparent)) { - return _brushes[KnownColor.transparent]!; - } else { - return _getBrush(KnownColor.transparent); - } - } - - /// Gets the Turquoise default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.turquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get turquoise { - if (_brushes.containsKey(KnownColor.turquoise)) { - return _brushes[KnownColor.turquoise]!; - } else { - return _getBrush(KnownColor.turquoise); - } - } - - /// Gets the Violet default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.violet, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get violet { - if (_brushes.containsKey(KnownColor.violet)) { - return _brushes[KnownColor.violet]!; - } else { - return _getBrush(KnownColor.violet); - } - } - - /// Gets the Wheat default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.wheat, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get wheat { - if (_brushes.containsKey(KnownColor.wheat)) { - return _brushes[KnownColor.wheat]!; - } else { - return _getBrush(KnownColor.wheat); - } - } - - /// Gets the White default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.white, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get white { - if (_brushes.containsKey(KnownColor.white)) { - return _brushes[KnownColor.white]!; - } else { - return _getBrush(KnownColor.white); - } - } - - /// Gets the WhiteSmoke default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.whiteSmoke, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get whiteSmoke { - if (_brushes.containsKey(KnownColor.whiteSmoke)) { - return _brushes[KnownColor.whiteSmoke]!; - } else { - return _getBrush(KnownColor.whiteSmoke); - } - } - - /// Gets the Yellow default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.yellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get yellow { - if (_brushes.containsKey(KnownColor.yellow)) { - return _brushes[KnownColor.yellow]!; - } else { - return _getBrush(KnownColor.yellow); - } - } - - /// Gets the YellowGreen default brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// brush: PdfBrushes.yellowGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfBrush get yellowGreen { - if (_brushes.containsKey(KnownColor.yellowGreen)) { - return _brushes[KnownColor.yellowGreen]!; - } else { - return _getBrush(KnownColor.yellowGreen); - } - } - - static PdfBrush _getBrush(KnownColor kColor) { - final ColorHelper color = ColorHelper(kColor); - final PdfBrush brush = PdfSolidBrush( - PdfColor(color.r, color.g, color.b, color.a), - ); - _brushes[kColor] = brush; - return brush; - } - - static void _dispose() { - _brushes.clear(); - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfBrushes] helper -class PdfBrushesHelper { - /// internal method - static void dispose() { - PdfBrushes._dispose(); - } -} +import '../../drawing/color.dart'; +import '../../graphics/pdf_color.dart'; +import 'pdf_solid_brush.dart'; + +/// Brushes for all the standard colors. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Draw rectangle. +/// doc.pages.add().graphics.drawRectangle( +/// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 200, 100)); +/// //Save the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +class PdfBrushes { + PdfBrushes._(); + static final Map _brushes = {}; + + /// Gets the AliceBlue brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.aliceBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get aliceBlue { + if (_brushes.containsKey(KnownColor.aliceBlue)) { + return _brushes[KnownColor.aliceBlue]!; + } else { + return _getBrush(KnownColor.aliceBlue); + } + } + + /// Gets the Antique white brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.antiqueWhite, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get antiqueWhite { + if (_brushes.containsKey(KnownColor.antiqueWhite)) { + return _brushes[KnownColor.antiqueWhite]!; + } else { + return _getBrush(KnownColor.antiqueWhite); + } + } + + /// Gets the Aqua default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.aqua, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get aqua { + if (_brushes.containsKey(KnownColor.aqua)) { + return _brushes[KnownColor.aqua]!; + } else { + return _getBrush(KnownColor.aqua); + } + } + + /// Gets the Aquamarine default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.aquamarine, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get aquamarine { + if (_brushes.containsKey(KnownColor.aquamarine)) { + return _brushes[KnownColor.aquamarine]!; + } else { + return _getBrush(KnownColor.aquamarine); + } + } + + /// Gets the Azure default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.azure, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get azure { + if (_brushes.containsKey(KnownColor.azure)) { + return _brushes[KnownColor.azure]!; + } else { + return _getBrush(KnownColor.azure); + } + } + + /// Gets the Beige default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.beige, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get beige { + if (_brushes.containsKey(KnownColor.beige)) { + return _brushes[KnownColor.beige]!; + } else { + return _getBrush(KnownColor.beige); + } + } + + /// Gets the Bisque default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.bisque, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get bisque { + if (_brushes.containsKey(KnownColor.bisque)) { + return _brushes[KnownColor.bisque]!; + } else { + return _getBrush(KnownColor.bisque); + } + } + + /// Gets the Black default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get black { + if (_brushes.containsKey(KnownColor.black)) { + return _brushes[KnownColor.black]!; + } else { + return _getBrush(KnownColor.black); + } + } + + /// Gets the BlanchedAlmond default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.blanchedAlmond, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get blanchedAlmond { + if (_brushes.containsKey(KnownColor.blanchedAlmond)) { + return _brushes[KnownColor.blanchedAlmond]!; + } else { + return _getBrush(KnownColor.blanchedAlmond); + } + } + + /// Gets the Blue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.blue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get blue { + if (_brushes.containsKey(KnownColor.blue)) { + return _brushes[KnownColor.blue]!; + } else { + return _getBrush(KnownColor.blue); + } + } + + /// Gets the BlueViolet default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.blueViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get blueViolet { + if (_brushes.containsKey(KnownColor.blueViolet)) { + return _brushes[KnownColor.blueViolet]!; + } else { + return _getBrush(KnownColor.blueViolet); + } + } + + /// Gets the Brown default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.brown, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get brown { + if (_brushes.containsKey(KnownColor.brown)) { + return _brushes[KnownColor.brown]!; + } else { + return _getBrush(KnownColor.brown); + } + } + + /// Gets the BurlyWood default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.burlyWood, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get burlyWood { + if (_brushes.containsKey(KnownColor.burlyWood)) { + return _brushes[KnownColor.burlyWood]!; + } else { + return _getBrush(KnownColor.burlyWood); + } + } + + /// Gets the CadetBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.cadetBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get cadetBlue { + if (_brushes.containsKey(KnownColor.cadetBlue)) { + return _brushes[KnownColor.cadetBlue]!; + } else { + return _getBrush(KnownColor.cadetBlue); + } + } + + /// Gets the Chartreuse default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.chartreuse, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get chartreuse { + if (_brushes.containsKey(KnownColor.chartreuse)) { + return _brushes[KnownColor.chartreuse]!; + } else { + return _getBrush(KnownColor.chartreuse); + } + } + + /// Gets the Chocolate default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.chocolate, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get chocolate { + if (_brushes.containsKey(KnownColor.chocolate)) { + return _brushes[KnownColor.chocolate]!; + } else { + return _getBrush(KnownColor.chocolate); + } + } + + /// Gets the Coral default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.coral, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get coral { + if (_brushes.containsKey(KnownColor.coral)) { + return _brushes[KnownColor.coral]!; + } else { + return _getBrush(KnownColor.coral); + } + } + + /// Gets the CornflowerBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.cornflowerBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get cornflowerBlue { + if (_brushes.containsKey(KnownColor.cornflowerBlue)) { + return _brushes[KnownColor.cornflowerBlue]!; + } else { + return _getBrush(KnownColor.cornflowerBlue); + } + } + + /// Gets the Corn silk default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.cornsilk, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get cornsilk { + if (_brushes.containsKey(KnownColor.cornsilk)) { + return _brushes[KnownColor.cornsilk]!; + } else { + return _getBrush(KnownColor.cornsilk); + } + } + + /// Gets the Crimson default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.crimson, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get crimson { + if (_brushes.containsKey(KnownColor.crimson)) { + return _brushes[KnownColor.crimson]!; + } else { + return _getBrush(KnownColor.crimson); + } + } + + /// Gets the Cyan default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.cyan, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get cyan { + if (_brushes.containsKey(KnownColor.cyan)) { + return _brushes[KnownColor.cyan]!; + } else { + return _getBrush(KnownColor.cyan); + } + } + + /// Gets the DarkBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkBlue { + if (_brushes.containsKey(KnownColor.darkBlue)) { + return _brushes[KnownColor.darkBlue]!; + } else { + return _getBrush(KnownColor.darkBlue); + } + } + + /// Gets the DarkCyan default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkCyan, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkCyan { + if (_brushes.containsKey(KnownColor.darkCyan)) { + return _brushes[KnownColor.darkCyan]!; + } else { + return _getBrush(KnownColor.darkCyan); + } + } + + /// Gets the DarkGoldenrod default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkGoldenrod, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkGoldenrod { + if (_brushes.containsKey(KnownColor.darkGoldenrod)) { + return _brushes[KnownColor.darkGoldenrod]!; + } else { + return _getBrush(KnownColor.darkGoldenrod); + } + } + + /// Gets the DarkGray default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkGray { + if (_brushes.containsKey(KnownColor.darkGray)) { + return _brushes[KnownColor.darkGray]!; + } else { + return _getBrush(KnownColor.darkGray); + } + } + + /// Gets the DarkGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkGreen { + if (_brushes.containsKey(KnownColor.darkGreen)) { + return _brushes[KnownColor.darkGreen]!; + } else { + return _getBrush(KnownColor.darkGreen); + } + } + + /// Gets the DarkKhaki default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkKhaki, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkKhaki { + if (_brushes.containsKey(KnownColor.darkKhaki)) { + return _brushes[KnownColor.darkKhaki]!; + } else { + return _getBrush(KnownColor.darkKhaki); + } + } + + /// Gets the DarkMagenta default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkMagenta, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkMagenta { + if (_brushes.containsKey(KnownColor.darkMagenta)) { + return _brushes[KnownColor.darkMagenta]!; + } else { + return _getBrush(KnownColor.darkMagenta); + } + } + + /// Gets the DarkOliveGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkOliveGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkOliveGreen { + if (_brushes.containsKey(KnownColor.darkOliveGreen)) { + return _brushes[KnownColor.darkOliveGreen]!; + } else { + return _getBrush(KnownColor.darkOliveGreen); + } + } + + /// Gets the DarkOrange default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkOrange, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkOrange { + if (_brushes.containsKey(KnownColor.darkOrange)) { + return _brushes[KnownColor.darkOrange]!; + } else { + return _getBrush(KnownColor.darkOrange); + } + } + + /// Gets the DarkOrchid default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkOrchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkOrchid { + if (_brushes.containsKey(KnownColor.darkOrchid)) { + return _brushes[KnownColor.darkOrchid]!; + } else { + return _getBrush(KnownColor.darkOrchid); + } + } + + /// Gets the DarkRed default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkRed { + if (_brushes.containsKey(KnownColor.darkRed)) { + return _brushes[KnownColor.darkRed]!; + } else { + return _getBrush(KnownColor.darkRed); + } + } + + /// Gets the DarkSalmon default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkSalmon { + if (_brushes.containsKey(KnownColor.darkSalmon)) { + return _brushes[KnownColor.darkSalmon]!; + } else { + return _getBrush(KnownColor.darkSalmon); + } + } + + /// Gets the DarkSeaGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkSeaGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkSeaGreen { + if (_brushes.containsKey(KnownColor.darkSeaGreen)) { + return _brushes[KnownColor.darkSeaGreen]!; + } else { + return _getBrush(KnownColor.darkSeaGreen); + } + } + + /// Gets the DarkSlateBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkSlateBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkSlateBlue { + if (_brushes.containsKey(KnownColor.darkSlateBlue)) { + return _brushes[KnownColor.darkSlateBlue]!; + } else { + return _getBrush(KnownColor.darkSlateBlue); + } + } + + /// Gets the DarkSlateGray default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkSlateGray, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkSlateGray { + if (_brushes.containsKey(KnownColor.darkSlateGray)) { + return _brushes[KnownColor.darkSlateGray]!; + } else { + return _getBrush(KnownColor.darkSlateGray); + } + } + + /// Gets the DarkTurquoise default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkTurquoise, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkTurquoise { + if (_brushes.containsKey(KnownColor.darkTurquoise)) { + return _brushes[KnownColor.darkTurquoise]!; + } else { + return _getBrush(KnownColor.darkTurquoise); + } + } + + /// Gets the DarkViolet default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.darkViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get darkViolet { + if (_brushes.containsKey(KnownColor.darkViolet)) { + return _brushes[KnownColor.darkViolet]!; + } else { + return _getBrush(KnownColor.darkViolet); + } + } + + /// Gets the DeepPink default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.deepPink, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get deepPink { + if (_brushes.containsKey(KnownColor.deepPink)) { + return _brushes[KnownColor.deepPink]!; + } else { + return _getBrush(KnownColor.deepPink); + } + } + + /// Gets the DeepSkyBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.deepSkyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get deepSkyBlue { + if (_brushes.containsKey(KnownColor.deepSkyBlue)) { + return _brushes[KnownColor.deepSkyBlue]!; + } else { + return _getBrush(KnownColor.deepSkyBlue); + } + } + + /// Gets the DimGray default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.dimGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get dimGray { + if (_brushes.containsKey(KnownColor.dimGray)) { + return _brushes[KnownColor.dimGray]!; + } else { + return _getBrush(KnownColor.dimGray); + } + } + + /// Gets the DodgerBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.dodgerBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get dodgerBlue { + if (_brushes.containsKey(KnownColor.dodgerBlue)) { + return _brushes[KnownColor.dodgerBlue]!; + } else { + return _getBrush(KnownColor.dodgerBlue); + } + } + + /// Gets the Firebrick default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.firebrick, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get firebrick { + if (_brushes.containsKey(KnownColor.firebrick)) { + return _brushes[KnownColor.firebrick]!; + } else { + return _getBrush(KnownColor.firebrick); + } + } + + /// Gets the FloralWhite default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.floralWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get floralWhite { + if (_brushes.containsKey(KnownColor.floralWhite)) { + return _brushes[KnownColor.floralWhite]!; + } else { + return _getBrush(KnownColor.floralWhite); + } + } + + /// Gets the ForestGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.forestGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get forestGreen { + if (_brushes.containsKey(KnownColor.forestGreen)) { + return _brushes[KnownColor.forestGreen]!; + } else { + return _getBrush(KnownColor.forestGreen); + } + } + + /// Gets the Fuchsia default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.fuchsia, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get fuchsia { + if (_brushes.containsKey(KnownColor.fuchsia)) { + return _brushes[KnownColor.fuchsia]!; + } else { + return _getBrush(KnownColor.fuchsia); + } + } + + /// Gets the Gainsborough default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.gainsboro, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get gainsboro { + if (_brushes.containsKey(KnownColor.gainsboro)) { + return _brushes[KnownColor.gainsboro]!; + } else { + return _getBrush(KnownColor.gainsboro); + } + } + + /// Gets the GhostWhite default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.ghostWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get ghostWhite { + if (_brushes.containsKey(KnownColor.ghostWhite)) { + return _brushes[KnownColor.ghostWhite]!; + } else { + return _getBrush(KnownColor.ghostWhite); + } + } + + /// Gets the Gold default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.gold, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get gold { + if (_brushes.containsKey(KnownColor.gold)) { + return _brushes[KnownColor.gold]!; + } else { + return _getBrush(KnownColor.gold); + } + } + + /// Gets the Goldenrod default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.goldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get goldenrod { + if (_brushes.containsKey(KnownColor.goldenrod)) { + return _brushes[KnownColor.goldenrod]!; + } else { + return _getBrush(KnownColor.goldenrod); + } + } + + /// Gets the Gray default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.gray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get gray { + if (_brushes.containsKey(KnownColor.gray)) { + return _brushes[KnownColor.gray]!; + } else { + return _getBrush(KnownColor.gray); + } + } + + /// Gets the Green default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.green, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get green { + if (_brushes.containsKey(KnownColor.green)) { + return _brushes[KnownColor.green]!; + } else { + return _getBrush(KnownColor.green); + } + } + + /// Gets the GreenYellow default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.greenYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get greenYellow { + if (_brushes.containsKey(KnownColor.greenYellow)) { + return _brushes[KnownColor.greenYellow]!; + } else { + return _getBrush(KnownColor.greenYellow); + } + } + + /// Gets the Honeydew default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.honeydew, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get honeydew { + if (_brushes.containsKey(KnownColor.honeydew)) { + return _brushes[KnownColor.honeydew]!; + } else { + return _getBrush(KnownColor.honeydew); + } + } + + /// Gets the HotPink default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.hotPink, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get hotPink { + if (_brushes.containsKey(KnownColor.hotPink)) { + return _brushes[KnownColor.hotPink]!; + } else { + return _getBrush(KnownColor.hotPink); + } + } + + /// Gets the IndianRed default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.indianRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get indianRed { + if (_brushes.containsKey(KnownColor.indianRed)) { + return _brushes[KnownColor.indianRed]!; + } else { + return _getBrush(KnownColor.indianRed); + } + } + + /// Gets the Indigo default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.indigo, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get indigo { + if (_brushes.containsKey(KnownColor.indigo)) { + return _brushes[KnownColor.indigo]!; + } else { + return _getBrush(KnownColor.indigo); + } + } + + /// Gets the Ivory default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.ivory, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get ivory { + if (_brushes.containsKey(KnownColor.ivory)) { + return _brushes[KnownColor.ivory]!; + } else { + return _getBrush(KnownColor.ivory); + } + } + + /// Gets the Khaki default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.khaki, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get khaki { + if (_brushes.containsKey(KnownColor.khaki)) { + return _brushes[KnownColor.khaki]!; + } else { + return _getBrush(KnownColor.khaki); + } + } + + /// Gets the Lavender default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lavender, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lavender { + if (_brushes.containsKey(KnownColor.lavender)) { + return _brushes[KnownColor.lavender]!; + } else { + return _getBrush(KnownColor.lavender); + } + } + + /// Gets the LavenderBlush default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lavenderBlush, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lavenderBlush { + if (_brushes.containsKey(KnownColor.lavenderBlush)) { + return _brushes[KnownColor.lavenderBlush]!; + } else { + return _getBrush(KnownColor.lavenderBlush); + } + } + + /// Gets the LawnGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lawnGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lawnGreen { + if (_brushes.containsKey(KnownColor.lawnGreen)) { + return _brushes[KnownColor.lawnGreen]!; + } else { + return _getBrush(KnownColor.lawnGreen); + } + } + + /// Gets the LemonChiffon default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lemonChiffon, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lemonChiffon { + if (_brushes.containsKey(KnownColor.lemonChiffon)) { + return _brushes[KnownColor.lemonChiffon]!; + } else { + return _getBrush(KnownColor.lemonChiffon); + } + } + + /// Gets the LightBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightBlue { + if (_brushes.containsKey(KnownColor.lightBlue)) { + return _brushes[KnownColor.lightBlue]!; + } else { + return _getBrush(KnownColor.lightBlue); + } + } + + /// Gets the LightCoral default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightCoral, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightCoral { + if (_brushes.containsKey(KnownColor.lightCoral)) { + return _brushes[KnownColor.lightCoral]!; + } else { + return _getBrush(KnownColor.lightCoral); + } + } + + /// Gets the LightCyan default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightCyan, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightCyan { + if (_brushes.containsKey(KnownColor.lightCyan)) { + return _brushes[KnownColor.lightCyan]!; + } else { + return _getBrush(KnownColor.lightCyan); + } + } + + /// Gets the LightGoldenrodYellow default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightGoldenrodYellow, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightGoldenrodYellow { + if (_brushes.containsKey(KnownColor.lightGoldenrodYellow)) { + return _brushes[KnownColor.lightGoldenrodYellow]!; + } else { + return _getBrush(KnownColor.lightGoldenrodYellow); + } + } + + /// Gets the LightGray default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightGray { + if (_brushes.containsKey(KnownColor.lightGray)) { + return _brushes[KnownColor.lightGray]!; + } else { + return _getBrush(KnownColor.lightGray); + } + } + + /// Gets the LightGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightGreen { + if (_brushes.containsKey(KnownColor.lightGreen)) { + return _brushes[KnownColor.lightGreen]!; + } else { + return _getBrush(KnownColor.lightGreen); + } + } + + /// Gets the LightPink default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightPink, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightPink { + if (_brushes.containsKey(KnownColor.lightPink)) { + return _brushes[KnownColor.lightPink]!; + } else { + return _getBrush(KnownColor.lightPink); + } + } + + /// Gets the LightSalmon default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightSalmon { + if (_brushes.containsKey(KnownColor.lightSalmon)) { + return _brushes[KnownColor.lightSalmon]!; + } else { + return _getBrush(KnownColor.lightSalmon); + } + } + + /// Gets the LightSeaGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightSeaGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightSeaGreen { + if (_brushes.containsKey(KnownColor.lightSeaGreen)) { + return _brushes[KnownColor.lightSeaGreen]!; + } else { + return _getBrush(KnownColor.lightSeaGreen); + } + } + + /// Gets the LightSkyBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightSkyBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightSkyBlue { + if (_brushes.containsKey(KnownColor.lightSkyBlue)) { + return _brushes[KnownColor.lightSkyBlue]!; + } else { + return _getBrush(KnownColor.lightSkyBlue); + } + } + + /// Gets the LightSlateGray default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightSlateGray, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightSlateGray { + if (_brushes.containsKey(KnownColor.lightSlateGray)) { + return _brushes[KnownColor.lightSlateGray]!; + } else { + return _getBrush(KnownColor.lightSlateGray); + } + } + + /// Gets the LightSteelBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightSteelBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightSteelBlue { + if (_brushes.containsKey(KnownColor.lightSteelBlue)) { + return _brushes[KnownColor.lightSteelBlue]!; + } else { + return _getBrush(KnownColor.lightSteelBlue); + } + } + + /// Gets the LightYellow default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lightYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lightYellow { + if (_brushes.containsKey(KnownColor.lightYellow)) { + return _brushes[KnownColor.lightYellow]!; + } else { + return _getBrush(KnownColor.lightYellow); + } + } + + /// Gets the Lime default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.lime, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get lime { + if (_brushes.containsKey(KnownColor.lime)) { + return _brushes[KnownColor.lime]!; + } else { + return _getBrush(KnownColor.lime); + } + } + + /// Gets the LimeGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.limeGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get limeGreen { + if (_brushes.containsKey(KnownColor.limeGreen)) { + return _brushes[KnownColor.limeGreen]!; + } else { + return _getBrush(KnownColor.limeGreen); + } + } + + /// Gets the Linen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.linen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get linen { + if (_brushes.containsKey(KnownColor.linen)) { + return _brushes[KnownColor.linen]!; + } else { + return _getBrush(KnownColor.linen); + } + } + + /// Gets the Magenta default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.magenta, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get magenta { + if (_brushes.containsKey(KnownColor.magenta)) { + return _brushes[KnownColor.magenta]!; + } else { + return _getBrush(KnownColor.magenta); + } + } + + /// Gets the Maroon default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.maroon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get maroon { + if (_brushes.containsKey(KnownColor.maroon)) { + return _brushes[KnownColor.maroon]!; + } else { + return _getBrush(KnownColor.maroon); + } + } + + /// Gets the MediumAquamarine default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumAquamarine, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumAquamarine { + if (_brushes.containsKey(KnownColor.mediumAquamarine)) { + return _brushes[KnownColor.mediumAquamarine]!; + } else { + return _getBrush(KnownColor.mediumAquamarine); + } + } + + /// Gets the MediumBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumBlue { + if (_brushes.containsKey(KnownColor.mediumBlue)) { + return _brushes[KnownColor.mediumBlue]!; + } else { + return _getBrush(KnownColor.mediumBlue); + } + } + + /// Gets the MediumOrchid default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumOrchid, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumOrchid { + if (_brushes.containsKey(KnownColor.mediumOrchid)) { + return _brushes[KnownColor.mediumOrchid]!; + } else { + return _getBrush(KnownColor.mediumOrchid); + } + } + + /// Gets the MediumPurple default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumPurple, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumPurple { + if (_brushes.containsKey(KnownColor.mediumPurple)) { + return _brushes[KnownColor.mediumPurple]!; + } else { + return _getBrush(KnownColor.mediumPurple); + } + } + + /// Gets the MediumSeaGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumSeaGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumSeaGreen { + if (_brushes.containsKey(KnownColor.mediumSeaGreen)) { + return _brushes[KnownColor.mediumSeaGreen]!; + } else { + return _getBrush(KnownColor.mediumSeaGreen); + } + } + + /// Gets the MediumSlateBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumSlateBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumSlateBlue { + if (_brushes.containsKey(KnownColor.mediumSlateBlue)) { + return _brushes[KnownColor.mediumSlateBlue]!; + } else { + return _getBrush(KnownColor.mediumSlateBlue); + } + } + + /// Gets the MediumSpringGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumSpringGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumSpringGreen { + if (_brushes.containsKey(KnownColor.mediumSpringGreen)) { + return _brushes[KnownColor.mediumSpringGreen]!; + } else { + return _getBrush(KnownColor.mediumSpringGreen); + } + } + + /// Gets the MediumTurquoise default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumTurquoise, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumTurquoise { + if (_brushes.containsKey(KnownColor.mediumTurquoise)) { + return _brushes[KnownColor.mediumTurquoise]!; + } else { + return _getBrush(KnownColor.mediumTurquoise); + } + } + + /// Gets the MediumVioletRed default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mediumVioletRed, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mediumVioletRed { + if (_brushes.containsKey(KnownColor.mediumVioletRed)) { + return _brushes[KnownColor.mediumVioletRed]!; + } else { + return _getBrush(KnownColor.mediumVioletRed); + } + } + + /// Gets the MidnightBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.midnightBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get midnightBlue { + if (_brushes.containsKey(KnownColor.midnightBlue)) { + return _brushes[KnownColor.midnightBlue]!; + } else { + return _getBrush(KnownColor.midnightBlue); + } + } + + /// Gets the MintCream default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mintCream, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mintCream { + if (_brushes.containsKey(KnownColor.mintCream)) { + return _brushes[KnownColor.mintCream]!; + } else { + return _getBrush(KnownColor.mintCream); + } + } + + /// Gets the MistyRose default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.mistyRose, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get mistyRose { + if (_brushes.containsKey(KnownColor.mistyRose)) { + return _brushes[KnownColor.mistyRose]!; + } else { + return _getBrush(KnownColor.mistyRose); + } + } + + /// Gets the Moccasin default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.moccasin, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get moccasin { + if (_brushes.containsKey(KnownColor.moccasin)) { + return _brushes[KnownColor.moccasin]!; + } else { + return _getBrush(KnownColor.moccasin); + } + } + + /// Gets the NavajoWhite default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.navajoWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get navajoWhite { + if (_brushes.containsKey(KnownColor.navajoWhite)) { + return _brushes[KnownColor.navajoWhite]!; + } else { + return _getBrush(KnownColor.navajoWhite); + } + } + + /// Gets the Navy default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.navy, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get navy { + if (_brushes.containsKey(KnownColor.navy)) { + return _brushes[KnownColor.navy]!; + } else { + return _getBrush(KnownColor.navy); + } + } + + /// Gets the OldLace default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.oldLace, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get oldLace { + if (_brushes.containsKey(KnownColor.oldLace)) { + return _brushes[KnownColor.oldLace]!; + } else { + return _getBrush(KnownColor.oldLace); + } + } + + /// Gets the Olive default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.olive, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get olive { + if (_brushes.containsKey(KnownColor.olive)) { + return _brushes[KnownColor.olive]!; + } else { + return _getBrush(KnownColor.olive); + } + } + + /// Gets the OliveDrab default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.oliveDrab, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get oliveDrab { + if (_brushes.containsKey(KnownColor.oliveDrab)) { + return _brushes[KnownColor.oliveDrab]!; + } else { + return _getBrush(KnownColor.oliveDrab); + } + } + + /// Gets the Orange default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.orange, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get orange { + if (_brushes.containsKey(KnownColor.orange)) { + return _brushes[KnownColor.orange]!; + } else { + return _getBrush(KnownColor.orange); + } + } + + /// Gets the OrangeRed default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.orangeRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get orangeRed { + if (_brushes.containsKey(KnownColor.orangeRed)) { + return _brushes[KnownColor.orangeRed]!; + } else { + return _getBrush(KnownColor.orangeRed); + } + } + + /// Gets the Orchid default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.orchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get orchid { + if (_brushes.containsKey(KnownColor.orchid)) { + return _brushes[KnownColor.orchid]!; + } else { + return _getBrush(KnownColor.orchid); + } + } + + /// Gets the PaleGoldenrod default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.paleGoldenrod, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get paleGoldenrod { + if (_brushes.containsKey(KnownColor.paleGoldenrod)) { + return _brushes[KnownColor.paleGoldenrod]!; + } else { + return _getBrush(KnownColor.paleGoldenrod); + } + } + + /// Gets the PaleGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.paleGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get paleGreen { + if (_brushes.containsKey(KnownColor.paleGreen)) { + return _brushes[KnownColor.paleGreen]!; + } else { + return _getBrush(KnownColor.paleGreen); + } + } + + /// Gets the PaleTurquoise default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.paleTurquoise, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get paleTurquoise { + if (_brushes.containsKey(KnownColor.paleTurquoise)) { + return _brushes[KnownColor.paleTurquoise]!; + } else { + return _getBrush(KnownColor.paleTurquoise); + } + } + + /// Gets the PaleVioletRed default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.paleVioletRed, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get paleVioletRed { + if (_brushes.containsKey(KnownColor.paleVioletRed)) { + return _brushes[KnownColor.paleVioletRed]!; + } else { + return _getBrush(KnownColor.paleVioletRed); + } + } + + /// Gets the PapayaWhip default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.papayaWhip, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get papayaWhip { + if (_brushes.containsKey(KnownColor.papayaWhip)) { + return _brushes[KnownColor.papayaWhip]!; + } else { + return _getBrush(KnownColor.papayaWhip); + } + } + + /// Gets the PeachPuff default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.peachPuff, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get peachPuff { + if (_brushes.containsKey(KnownColor.peachPuff)) { + return _brushes[KnownColor.peachPuff]!; + } else { + return _getBrush(KnownColor.peachPuff); + } + } + + /// Gets the Peru default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.peru, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get peru { + if (_brushes.containsKey(KnownColor.peru)) { + return _brushes[KnownColor.peru]!; + } else { + return _getBrush(KnownColor.peru); + } + } + + /// Gets the Pink default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.pink, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get pink { + if (_brushes.containsKey(KnownColor.pink)) { + return _brushes[KnownColor.pink]!; + } else { + return _getBrush(KnownColor.pink); + } + } + + /// Gets the Plum default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.plum, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get plum { + if (_brushes.containsKey(KnownColor.plum)) { + return _brushes[KnownColor.plum]!; + } else { + return _getBrush(KnownColor.plum); + } + } + + /// Gets the PowderBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.powderBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get powderBlue { + if (_brushes.containsKey(KnownColor.powderBlue)) { + return _brushes[KnownColor.powderBlue]!; + } else { + return _getBrush(KnownColor.powderBlue); + } + } + + /// Gets the Purple default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.purple, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get purple { + if (_brushes.containsKey(KnownColor.purple)) { + return _brushes[KnownColor.purple]!; + } else { + return _getBrush(KnownColor.purple); + } + } + + /// Gets the Red default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get red { + if (_brushes.containsKey(KnownColor.red)) { + return _brushes[KnownColor.red]!; + } else { + return _getBrush(KnownColor.red); + } + } + + /// Gets the RosyBrown default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.rosyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get rosyBrown { + if (_brushes.containsKey(KnownColor.rosyBrown)) { + return _brushes[KnownColor.rosyBrown]!; + } else { + return _getBrush(KnownColor.rosyBrown); + } + } + + /// Gets the RoyalBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.royalBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get royalBlue { + if (_brushes.containsKey(KnownColor.royalBlue)) { + return _brushes[KnownColor.royalBlue]!; + } else { + return _getBrush(KnownColor.royalBlue); + } + } + + /// Gets the SaddleBrown default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.saddleBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get saddleBrown { + if (_brushes.containsKey(KnownColor.saddleBrown)) { + return _brushes[KnownColor.saddleBrown]!; + } else { + return _getBrush(KnownColor.saddleBrown); + } + } + + /// Gets the Salmon default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.salmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get salmon { + if (_brushes.containsKey(KnownColor.salmon)) { + return _brushes[KnownColor.salmon]!; + } else { + return _getBrush(KnownColor.salmon); + } + } + + /// Gets the SandyBrown default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.sandyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get sandyBrown { + if (_brushes.containsKey(KnownColor.sandyBrown)) { + return _brushes[KnownColor.sandyBrown]!; + } else { + return _getBrush(KnownColor.sandyBrown); + } + } + + /// Gets the SeaGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.seaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get seaGreen { + if (_brushes.containsKey(KnownColor.seaGreen)) { + return _brushes[KnownColor.seaGreen]!; + } else { + return _getBrush(KnownColor.seaGreen); + } + } + + /// Gets the SeaShell default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.seaShell, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get seaShell { + if (_brushes.containsKey(KnownColor.seaShell)) { + return _brushes[KnownColor.seaShell]!; + } else { + return _getBrush(KnownColor.seaShell); + } + } + + /// Gets the Sienna default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.sienna, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get sienna { + if (_brushes.containsKey(KnownColor.sienna)) { + return _brushes[KnownColor.sienna]!; + } else { + return _getBrush(KnownColor.sienna); + } + } + + /// Gets the Silver default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.silver, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get silver { + if (_brushes.containsKey(KnownColor.silver)) { + return _brushes[KnownColor.silver]!; + } else { + return _getBrush(KnownColor.silver); + } + } + + /// Gets the SkyBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.skyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get skyBlue { + if (_brushes.containsKey(KnownColor.skyBlue)) { + return _brushes[KnownColor.skyBlue]!; + } else { + return _getBrush(KnownColor.skyBlue); + } + } + + /// Gets the SlateBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.slateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get slateBlue { + if (_brushes.containsKey(KnownColor.slateBlue)) { + return _brushes[KnownColor.slateBlue]!; + } else { + return _getBrush(KnownColor.slateBlue); + } + } + + /// Gets the SlateGray default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.slateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get slateGray { + if (_brushes.containsKey(KnownColor.slateGray)) { + return _brushes[KnownColor.slateGray]!; + } else { + return _getBrush(KnownColor.slateGray); + } + } + + /// Gets the Snow default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.snow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get snow { + if (_brushes.containsKey(KnownColor.snow)) { + return _brushes[KnownColor.snow]!; + } else { + return _getBrush(KnownColor.snow); + } + } + + /// Gets the SpringGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.springGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get springGreen { + if (_brushes.containsKey(KnownColor.springGreen)) { + return _brushes[KnownColor.springGreen]!; + } else { + return _getBrush(KnownColor.springGreen); + } + } + + /// Gets the SteelBlue default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.steelBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get steelBlue { + if (_brushes.containsKey(KnownColor.steelBlue)) { + return _brushes[KnownColor.steelBlue]!; + } else { + return _getBrush(KnownColor.steelBlue); + } + } + + /// Gets the Tan default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.tan, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get tan { + if (_brushes.containsKey(KnownColor.tan)) { + return _brushes[KnownColor.tan]!; + } else { + return _getBrush(KnownColor.tan); + } + } + + /// Gets the Teal default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.teal, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get teal { + if (_brushes.containsKey(KnownColor.teal)) { + return _brushes[KnownColor.teal]!; + } else { + return _getBrush(KnownColor.teal); + } + } + + /// Gets the Thistle default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.thistle, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get thistle { + if (_brushes.containsKey(KnownColor.thistle)) { + return _brushes[KnownColor.thistle]!; + } else { + return _getBrush(KnownColor.thistle); + } + } + + /// Gets the Tomato default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.tomato, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get tomato { + if (_brushes.containsKey(KnownColor.tomato)) { + return _brushes[KnownColor.tomato]!; + } else { + return _getBrush(KnownColor.tomato); + } + } + + /// Gets the Transparent default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.transparent, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get transparent { + if (_brushes.containsKey(KnownColor.transparent)) { + return _brushes[KnownColor.transparent]!; + } else { + return _getBrush(KnownColor.transparent); + } + } + + /// Gets the Turquoise default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.turquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get turquoise { + if (_brushes.containsKey(KnownColor.turquoise)) { + return _brushes[KnownColor.turquoise]!; + } else { + return _getBrush(KnownColor.turquoise); + } + } + + /// Gets the Violet default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.violet, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get violet { + if (_brushes.containsKey(KnownColor.violet)) { + return _brushes[KnownColor.violet]!; + } else { + return _getBrush(KnownColor.violet); + } + } + + /// Gets the Wheat default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.wheat, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get wheat { + if (_brushes.containsKey(KnownColor.wheat)) { + return _brushes[KnownColor.wheat]!; + } else { + return _getBrush(KnownColor.wheat); + } + } + + /// Gets the White default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.white, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get white { + if (_brushes.containsKey(KnownColor.white)) { + return _brushes[KnownColor.white]!; + } else { + return _getBrush(KnownColor.white); + } + } + + /// Gets the WhiteSmoke default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.whiteSmoke, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get whiteSmoke { + if (_brushes.containsKey(KnownColor.whiteSmoke)) { + return _brushes[KnownColor.whiteSmoke]!; + } else { + return _getBrush(KnownColor.whiteSmoke); + } + } + + /// Gets the Yellow default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.yellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get yellow { + if (_brushes.containsKey(KnownColor.yellow)) { + return _brushes[KnownColor.yellow]!; + } else { + return _getBrush(KnownColor.yellow); + } + } + + /// Gets the YellowGreen default brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// brush: PdfBrushes.yellowGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfBrush get yellowGreen { + if (_brushes.containsKey(KnownColor.yellowGreen)) { + return _brushes[KnownColor.yellowGreen]!; + } else { + return _getBrush(KnownColor.yellowGreen); + } + } + + static PdfBrush _getBrush(KnownColor kColor) { + final ColorHelper color = ColorHelper(kColor); + final PdfBrush brush = PdfSolidBrush( + PdfColor(color.r, color.g, color.b, color.a), + ); + _brushes[kColor] = brush; + return brush; + } + + static void _dispose() { + _brushes.clear(); + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfBrushes] helper +class PdfBrushesHelper { + /// internal method + static void dispose() { + PdfBrushes._dispose(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_solid_brush.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_solid_brush.dart index 3b5140717..a71cc4ae3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_solid_brush.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/brushes/pdf_solid_brush.dart @@ -1,104 +1,104 @@ -import '../../io/pdf_stream_writer.dart'; -import '../enums.dart'; -import '../pdf_color.dart'; - -/// Represents a brush that fills any object with a solid color. -class PdfSolidBrush implements PdfBrush { - //Constructor - /// Initializes a new instance of the [PdfSolidBrush] class. - PdfSolidBrush(this.color); - - //Fields - final PdfColorSpace _colorSpace = PdfColorSpace.rgb; - - /// Indicates the color of the [PdfSolidBrush]. - late PdfColor color; - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is PdfSolidBrush && color == other.color; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => color.hashCode; - - @override - bool _monitorChanges( - PdfBrush? brush, - PdfStreamWriter? streamWriter, - Function? getResources, - bool saveChanges, - PdfColorSpace? currentColorSpace, - ) { - bool diff = false; - if (getResources != null && streamWriter != null) { - if (brush == null) { - diff = true; - streamWriter.setColorAndSpace(color, currentColorSpace, false); - } else if (brush != this && brush is PdfSolidBrush) { - if (brush.color != color || brush._colorSpace != currentColorSpace) { - diff = true; - streamWriter.setColorAndSpace(color, currentColorSpace, false); - } else if (brush._colorSpace == currentColorSpace && - currentColorSpace == PdfColorSpace.rgb) { - diff = true; - streamWriter.setColorAndSpace(color, currentColorSpace, false); - } - } - } - return diff; - } -} - -/// Provides objects used to fill the interiors of graphical shapes -/// such as rectangles, ellipses, pies, polygons, and paths. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Create a new PDF solid brush. -/// PdfBrush solidBrush = PdfSolidBrush(PdfColor(1, 0, 0)); -/// //Add a page and draw a rectangle using the brush. -/// doc.pages -/// .add() -/// .graphics -/// .drawRectangle(brush: solidBrush, -/// bounds: Rect.fromLTWH(0, 0, 200, 100)); -/// //Save the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -abstract class PdfBrush { - bool _monitorChanges( - PdfBrush? brush, - PdfStreamWriter? streamWriter, - Function? getResources, - bool saveChanges, - PdfColorSpace? currentColorSpace, - ); -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfBrush] helper -class PdfBrushHelper { - /// internal method - static bool monitorChanges( - PdfBrush base, - PdfBrush? brush, - PdfStreamWriter? streamWriter, - Function? getResources, - bool saveChanges, - PdfColorSpace? currentColorSpace, - ) { - return base._monitorChanges( - brush, - streamWriter, - getResources, - saveChanges, - currentColorSpace, - ); - } -} +import '../../io/pdf_stream_writer.dart'; +import '../enums.dart'; +import '../pdf_color.dart'; + +/// Represents a brush that fills any object with a solid color. +class PdfSolidBrush implements PdfBrush { + //Constructor + /// Initializes a new instance of the [PdfSolidBrush] class. + PdfSolidBrush(this.color); + + //Fields + final PdfColorSpace _colorSpace = PdfColorSpace.rgb; + + /// Indicates the color of the [PdfSolidBrush]. + late PdfColor color; + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is PdfSolidBrush && color == other.color; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => color.hashCode; + + @override + bool _monitorChanges( + PdfBrush? brush, + PdfStreamWriter? streamWriter, + Function? getResources, + bool saveChanges, + PdfColorSpace? currentColorSpace, + ) { + bool diff = false; + if (getResources != null && streamWriter != null) { + if (brush == null) { + diff = true; + streamWriter.setColorAndSpace(color, currentColorSpace, false); + } else if (brush != this && brush is PdfSolidBrush) { + if (brush.color != color || brush._colorSpace != currentColorSpace) { + diff = true; + streamWriter.setColorAndSpace(color, currentColorSpace, false); + } else if (brush._colorSpace == currentColorSpace && + currentColorSpace == PdfColorSpace.rgb) { + diff = true; + streamWriter.setColorAndSpace(color, currentColorSpace, false); + } + } + } + return diff; + } +} + +/// Provides objects used to fill the interiors of graphical shapes +/// such as rectangles, ellipses, pies, polygons, and paths. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Create a new PDF solid brush. +/// PdfBrush solidBrush = PdfSolidBrush(PdfColor(1, 0, 0)); +/// //Add a page and draw a rectangle using the brush. +/// doc.pages +/// .add() +/// .graphics +/// .drawRectangle(brush: solidBrush, +/// bounds: Rect.fromLTWH(0, 0, 200, 100)); +/// //Save the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +abstract class PdfBrush { + bool _monitorChanges( + PdfBrush? brush, + PdfStreamWriter? streamWriter, + Function? getResources, + bool saveChanges, + PdfColorSpace? currentColorSpace, + ); +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfBrush] helper +class PdfBrushHelper { + /// internal method + static bool monitorChanges( + PdfBrush base, + PdfBrush? brush, + PdfStreamWriter? streamWriter, + Function? getResources, + bool saveChanges, + PdfColorSpace? currentColorSpace, + ) { + return base._monitorChanges( + brush, + streamWriter, + getResources, + saveChanges, + currentColorSpace, + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/enums.dart index 55f5d8252..12f497d31 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/enums.dart @@ -1,325 +1,325 @@ -/// Specifies the type of horizontal text alignment. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// format: PdfStringFormat(alignment: PdfTextAlignment.left)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfTextAlignment { - /// Specifies the text is aligned to Left. - left, - - /// Specifies the text is aligned to Center. - center, - - /// Specifies the text is aligned to Right. - right, - - /// Specifies the text as Justified text. - justify, -} - -/// Specifies the type of Vertical alignment. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.top)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfVerticalAlignment { - /// Specifies the element is aligned to Top. - top, - - /// Specifies the element is aligned to Middle. - middle, - - /// Specifies the element is aligned to Bottom. - bottom, -} - -/// Represents the text rendering direction. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// format: PdfStringFormat(textDirection: PdfTextDirection.none)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfTextDirection { - /// Specifies the default text order. - none, - - /// Specifies the left to right direction. - leftToRight, - - /// Specifies the right to left direction. - rightToLeft, -} - -/// Defines set of color spaces. -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Create PDF graphics for the page -/// doc.pages.add().graphics -/// ..colorSpace = PdfColorSpace.grayScale -/// ..drawRectangle( -/// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 515, 762)); -/// //Saves the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -enum PdfColorSpace { - /// RGB color space. - rgb, - - /// CMYK color space. - cmyk, - - /// GrayScale color space. - grayScale, - - /// Indexed color space. - indexed, -} - -/// Possible dash styles of the pen. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawRectangle( -/// pen: PdfPen(PdfColor(255, 0, 0), -/// dashStyle: PdfDashStyle.custom, lineCap: PdfLineCap.round) -/// ..dashPattern = [4, 2, 1, 3], -/// bounds: Rect.fromLTWH(0, 0, 200, 100)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfDashStyle { - /// Solid line. - solid, - - /// Dashed line. - dash, - - /// Dotted line. - dot, - - /// Dash-dot line. - dashDot, - - /// Dash-dot-dot line. - dashDotDot, - - /// User defined dash style. - custom, -} - -/// Specifies the corner style of the shapes. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawRectangle( -/// pen: PdfPen(PdfColor(255, 0, 0), -/// dashStyle: PdfDashStyle.custom, lineJoin: PdfLineJoin.bevel) -/// ..dashPattern = [4, 2, 1, 3], -/// bounds: Rect.fromLTWH(0, 0, 200, 100)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfLineJoin { - /// The outer edges for the two segments are extended - /// until they meet at an angle. - miter, - - /// An arc of a circle with a diameter equal to the line width is drawn - /// around the point where the two segments meet, connecting the - /// outer edges for the two segments. - round, - - /// The two segments are finished with caps and the resulting notch beyond - /// the ends of the segments is filled with a triangle. - bevel, -} - -/// Specifies the line cap style to be used at the ends of the lines. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawRectangle( -/// pen: PdfPen(PdfColor(255, 0, 0), -/// dashStyle: PdfDashStyle.custom, lineCap: PdfLineCap.round) -/// ..dashPattern = [4, 2, 1, 3], -/// bounds: Rect.fromLTWH(0, 0, 200, 100)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfLineCap { - /// The stroke is squared off at the endpoint of the path. - /// There is no projection beyond the end of the path. - flat, - - /// A semicircular arc with a diameter equal to the line width is drawn - /// around the endpoint and filled in. - round, - - /// The stroke continues beyond the endpoint of the path for a distance - /// equal to half the line width and is squared off. - square, -} - -/// Specifies how the shapes are filled. -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Create PDF graphics for the page -/// doc.pages.add().graphics -/// //set clip. -/// ..setClip(bounds: Rect.fromLTWH(0, 0, 50, 12), mode: PdfFillMode.alternate) -/// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// pen: PdfPens.red); -/// //Saves the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -enum PdfFillMode { - /// Nonzero winding number rule of determining "insideness" of point. - winding, - - /// Even odd rule of determining "insideness" of point. - alternate, -} - -/// Specifies the blend mode for transparency. -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Create PDF graphics for the page -/// doc.pages.add().graphics -/// ..setTransparency(0.5, alphaBrush: 0.5, mode: PdfBlendMode.hardLight) -/// ..drawString('Hello world!', -/// PdfStandardFont(PdfFontFamily.helvetica, 12, style: PdfFontStyle.bold), -/// brush: PdfBrushes.red, pen: PdfPens.black); -/// //Saves the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -enum PdfBlendMode { - /// Selects the source color, ignoring the backdrop. - normal, - - /// Multiplies the backdrop and source color values. - /// The result color is always at least as dark as either - /// of the two constituent colors. Multiplying - /// any color with black produces black; multiplying - /// with white leaves the original color unchanged. - /// Painting successive overlapping objects with a color - /// other than black or white produces progressively darker colors. - multiply, - - /// Multiplies the complements of the backdrop and source - /// color values, then complements the result. The result - /// color is always at least as light as either of the two - /// constituent colors. Screening any color with white - /// produces white; screening with black leaves the original - /// color unchanged. The effect is similar to projecting - /// multiple photographic slides simultaneously onto a single screen. - screen, - - /// Multiplies or screens the colors, depending on - /// the backdrop color value. Source colors overlay - /// the backdrop while preserving its highlights and - /// shadows. The backdrop color is not replaced but - /// is mixed with the source color to reflect the - /// lightness or darkness of the backdrop. - overlay, - - /// Selects the darker of the backdrop and source colors. - /// The backdrop is replaced with the source where the source - /// is darker; otherwise, it is left unchanged. - darken, - - /// Selects the lighter of the backdrop and source colors. - /// The backdrop is replaced with the source where the source - /// is lighter; otherwise, it is left unchanged. - lighten, - - /// Brightens the backdrop color to reflect the source color. - /// Painting with black produces no changes. - colorDodge, - - /// Darkens the backdrop color to reflect the source color. - /// Painting with white produces no change. - colorBurn, - - /// Multiplies or screens the colors, depending on the source color value. - /// The effect is similar to shining a harsh spotlight on the backdrop. - hardLight, - - /// Darkens or lightens the colors, depending on the source color value. - /// The effect is similar to shining a diffused spotlight on the backdrop. - softLight, - - /// Subtracts the darker of the two constituent colors from the lighter color. - /// Painting with white inverts the backdrop color; - /// painting with black produces no change. - difference, - - /// Produces an effect similar to that of the Difference mode - /// but lower in contrast. Painting with white inverts - /// the backdrop color; painting with black produces no change. - exclusion, - - /// Creates a color with the hue of the source color and - /// the saturation and luminosity of the backdrop color. - hue, - - /// Creates a color with the saturation of the source color - /// and the hue and luminosity of the backdrop color. Painting - /// with this mode in an area of the backdrop that is a pure - /// gray (no saturation) produces no change. - saturation, - - /// Creates a color with the hue and saturation of - /// the source color and the luminosity of the backdrop - /// color. This preserves the gray levels of the backdrop - /// and is useful for coloring monochrome images or tinting color images. - color, - - /// Creates a color with the luminosity of the source color - /// and the hue and saturation of the backdrop color. This - /// produces an inverse effect to that of the Color mode. - luminosity, -} +/// Specifies the type of horizontal text alignment. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// format: PdfStringFormat(alignment: PdfTextAlignment.left)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfTextAlignment { + /// Specifies the text is aligned to Left. + left, + + /// Specifies the text is aligned to Center. + center, + + /// Specifies the text is aligned to Right. + right, + + /// Specifies the text as Justified text. + justify, +} + +/// Specifies the type of Vertical alignment. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.top)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfVerticalAlignment { + /// Specifies the element is aligned to Top. + top, + + /// Specifies the element is aligned to Middle. + middle, + + /// Specifies the element is aligned to Bottom. + bottom, +} + +/// Represents the text rendering direction. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// format: PdfStringFormat(textDirection: PdfTextDirection.none)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfTextDirection { + /// Specifies the default text order. + none, + + /// Specifies the left to right direction. + leftToRight, + + /// Specifies the right to left direction. + rightToLeft, +} + +/// Defines set of color spaces. +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Create PDF graphics for the page +/// doc.pages.add().graphics +/// ..colorSpace = PdfColorSpace.grayScale +/// ..drawRectangle( +/// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 515, 762)); +/// //Saves the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +enum PdfColorSpace { + /// RGB color space. + rgb, + + /// CMYK color space. + cmyk, + + /// GrayScale color space. + grayScale, + + /// Indexed color space. + indexed, +} + +/// Possible dash styles of the pen. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawRectangle( +/// pen: PdfPen(PdfColor(255, 0, 0), +/// dashStyle: PdfDashStyle.custom, lineCap: PdfLineCap.round) +/// ..dashPattern = [4, 2, 1, 3], +/// bounds: Rect.fromLTWH(0, 0, 200, 100)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfDashStyle { + /// Solid line. + solid, + + /// Dashed line. + dash, + + /// Dotted line. + dot, + + /// Dash-dot line. + dashDot, + + /// Dash-dot-dot line. + dashDotDot, + + /// User defined dash style. + custom, +} + +/// Specifies the corner style of the shapes. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawRectangle( +/// pen: PdfPen(PdfColor(255, 0, 0), +/// dashStyle: PdfDashStyle.custom, lineJoin: PdfLineJoin.bevel) +/// ..dashPattern = [4, 2, 1, 3], +/// bounds: Rect.fromLTWH(0, 0, 200, 100)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfLineJoin { + /// The outer edges for the two segments are extended + /// until they meet at an angle. + miter, + + /// An arc of a circle with a diameter equal to the line width is drawn + /// around the point where the two segments meet, connecting the + /// outer edges for the two segments. + round, + + /// The two segments are finished with caps and the resulting notch beyond + /// the ends of the segments is filled with a triangle. + bevel, +} + +/// Specifies the line cap style to be used at the ends of the lines. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawRectangle( +/// pen: PdfPen(PdfColor(255, 0, 0), +/// dashStyle: PdfDashStyle.custom, lineCap: PdfLineCap.round) +/// ..dashPattern = [4, 2, 1, 3], +/// bounds: Rect.fromLTWH(0, 0, 200, 100)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfLineCap { + /// The stroke is squared off at the endpoint of the path. + /// There is no projection beyond the end of the path. + flat, + + /// A semicircular arc with a diameter equal to the line width is drawn + /// around the endpoint and filled in. + round, + + /// The stroke continues beyond the endpoint of the path for a distance + /// equal to half the line width and is squared off. + square, +} + +/// Specifies how the shapes are filled. +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Create PDF graphics for the page +/// doc.pages.add().graphics +/// //set clip. +/// ..setClip(bounds: Rect.fromLTWH(0, 0, 50, 12), mode: PdfFillMode.alternate) +/// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// pen: PdfPens.red); +/// //Saves the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +enum PdfFillMode { + /// Nonzero winding number rule of determining "insideness" of point. + winding, + + /// Even odd rule of determining "insideness" of point. + alternate, +} + +/// Specifies the blend mode for transparency. +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Create PDF graphics for the page +/// doc.pages.add().graphics +/// ..setTransparency(0.5, alphaBrush: 0.5, mode: PdfBlendMode.hardLight) +/// ..drawString('Hello world!', +/// PdfStandardFont(PdfFontFamily.helvetica, 12, style: PdfFontStyle.bold), +/// brush: PdfBrushes.red, pen: PdfPens.black); +/// //Saves the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +enum PdfBlendMode { + /// Selects the source color, ignoring the backdrop. + normal, + + /// Multiplies the backdrop and source color values. + /// The result color is always at least as dark as either + /// of the two constituent colors. Multiplying + /// any color with black produces black; multiplying + /// with white leaves the original color unchanged. + /// Painting successive overlapping objects with a color + /// other than black or white produces progressively darker colors. + multiply, + + /// Multiplies the complements of the backdrop and source + /// color values, then complements the result. The result + /// color is always at least as light as either of the two + /// constituent colors. Screening any color with white + /// produces white; screening with black leaves the original + /// color unchanged. The effect is similar to projecting + /// multiple photographic slides simultaneously onto a single screen. + screen, + + /// Multiplies or screens the colors, depending on + /// the backdrop color value. Source colors overlay + /// the backdrop while preserving its highlights and + /// shadows. The backdrop color is not replaced but + /// is mixed with the source color to reflect the + /// lightness or darkness of the backdrop. + overlay, + + /// Selects the darker of the backdrop and source colors. + /// The backdrop is replaced with the source where the source + /// is darker; otherwise, it is left unchanged. + darken, + + /// Selects the lighter of the backdrop and source colors. + /// The backdrop is replaced with the source where the source + /// is lighter; otherwise, it is left unchanged. + lighten, + + /// Brightens the backdrop color to reflect the source color. + /// Painting with black produces no changes. + colorDodge, + + /// Darkens the backdrop color to reflect the source color. + /// Painting with white produces no change. + colorBurn, + + /// Multiplies or screens the colors, depending on the source color value. + /// The effect is similar to shining a harsh spotlight on the backdrop. + hardLight, + + /// Darkens or lightens the colors, depending on the source color value. + /// The effect is similar to shining a diffused spotlight on the backdrop. + softLight, + + /// Subtracts the darker of the two constituent colors from the lighter color. + /// Painting with white inverts the backdrop color; + /// painting with black produces no change. + difference, + + /// Produces an effect similar to that of the Difference mode + /// but lower in contrast. Painting with white inverts + /// the backdrop color; painting with black produces no change. + exclusion, + + /// Creates a color with the hue of the source color and + /// the saturation and luminosity of the backdrop color. + hue, + + /// Creates a color with the saturation of the source color + /// and the hue and luminosity of the backdrop color. Painting + /// with this mode in an area of the backdrop that is a pure + /// gray (no saturation) produces no change. + saturation, + + /// Creates a color with the hue and saturation of + /// the source color and the luminosity of the backdrop + /// color. This preserves the gray levels of the backdrop + /// and is useful for coloring monochrome images or tinting color images. + color, + + /// Creates a color with the luminosity of the source color + /// and the hue and saturation of the backdrop color. This + /// produces an inverse effect to that of the Color mode. + luminosity, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/element_layouter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/element_layouter.dart index dc5afb420..9af251d7d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/element_layouter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/element_layouter.dart @@ -1,135 +1,135 @@ -import 'dart:ui'; - -import '../../../drawing/drawing.dart'; -import '../../../pages/pdf_page.dart'; -import '../../../pages/pdf_section.dart'; -import '../enums.dart'; -import 'layout_element.dart'; -import 'text_layouter.dart'; - -/// Base class for elements lay outing. -abstract class ElementLayouter { - //Constructor - /// Initializes a new instance of the [ElementLayouter] class. - ElementLayouter(PdfLayoutElement element) { - _element = element; - } - - //Fields - /// Layout the element. - PdfLayoutElement? _element; - - //Properties - /// Gets element`s layout. - PdfLayoutElement? get element => _element; - - //Implementation - /// internal method - PdfLayoutResult? layout(PdfLayoutParams param) { - return layoutInternal(param); - } - - /// internal method - PdfLayoutResult? layoutInternal(PdfLayoutParams param); - - /// internal method - PdfPage? getNextPage(PdfPage currentPage) { - final PdfSection section = PdfPageHelper.getHelper(currentPage).section!; - PdfPage? nextPage; - final int index = PdfSectionHelper.getHelper(section).indexOf(currentPage); - if (index == PdfSectionHelper.getHelper(section).count - 1) { - nextPage = section.pages.add(); - } else { - nextPage = PdfSectionHelper.getHelper(section).getPageByIndex(index + 1); - } - return nextPage; - } - - /// internal method - PdfRectangle getPaginateBounds(PdfLayoutParams param) { - return param.format!._boundsSet - ? PdfRectangle.fromRect(param.format!.paginateBounds) - : PdfRectangle( - param.bounds!.x, - 0, - param.bounds!.width, - param.bounds!.height, - ); - } -} - -/// Represents a layouting format -class PdfLayoutFormat { - //Constructor - /// Initializes a new instance of the [PdfLayoutFormat] class. - PdfLayoutFormat({ - PdfLayoutType? layoutType, - PdfLayoutBreakType? breakType, - Rect? paginateBounds, - }) { - this.breakType = breakType ?? PdfLayoutBreakType.fitPage; - this.layoutType = layoutType ?? PdfLayoutType.paginate; - if (paginateBounds != null) { - _paginateBounds = PdfRectangle.fromRect(paginateBounds); - _boundsSet = true; - } else { - _paginateBounds = PdfRectangle.empty; - _boundsSet = false; - } - } - - /// Initializes a new instance of the [PdfLayoutFormat] class - /// from an existing format. - PdfLayoutFormat.fromFormat(PdfLayoutFormat baseFormat) { - breakType = baseFormat.breakType; - layoutType = baseFormat.layoutType; - _paginateBounds = baseFormat._paginateBounds; - _boundsSet = baseFormat._boundsSet; - } - - //Fields - /// Layout type of the element. - PdfLayoutType layoutType = PdfLayoutType.paginate; - - /// Gets the bounds on the next page. - Rect get paginateBounds => _paginateBounds.rect; - - /// Sets the bounds on the next page. - set paginateBounds(Rect value) { - _paginateBounds = PdfRectangle.fromRect(value); - _boundsSet = true; - } - - /// Break type of the element. - PdfLayoutBreakType breakType = PdfLayoutBreakType.fitPage; - - /// Indicates whether PaginateBounds were set and should be used or not. - late bool _boundsSet; - - /// Bounds for the paginating. - late PdfRectangle _paginateBounds; -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfLayoutFormat] helper -class PdfLayoutFormatHelper { - /// internal method - static bool isBoundsSet(PdfLayoutFormat format, [bool? value]) { - if (value != null) { - format._boundsSet = value; - } - return format._boundsSet; - } -} - -/// Represents the layouting parameters. -class PdfLayoutParams { - /// Gets and Sets Start lay outing page. - PdfPage? page; - - /// Gets and Sets Lay outing bounds. - PdfRectangle? bounds; - - /// Gets and Sets Layout settings. - PdfLayoutFormat? format; -} +import 'dart:ui'; + +import '../../../drawing/drawing.dart'; +import '../../../pages/pdf_page.dart'; +import '../../../pages/pdf_section.dart'; +import '../enums.dart'; +import 'layout_element.dart'; +import 'text_layouter.dart'; + +/// Base class for elements lay outing. +abstract class ElementLayouter { + //Constructor + /// Initializes a new instance of the [ElementLayouter] class. + ElementLayouter(PdfLayoutElement element) { + _element = element; + } + + //Fields + /// Layout the element. + PdfLayoutElement? _element; + + //Properties + /// Gets element`s layout. + PdfLayoutElement? get element => _element; + + //Implementation + /// internal method + PdfLayoutResult? layout(PdfLayoutParams param) { + return layoutInternal(param); + } + + /// internal method + PdfLayoutResult? layoutInternal(PdfLayoutParams param); + + /// internal method + PdfPage? getNextPage(PdfPage currentPage) { + final PdfSection section = PdfPageHelper.getHelper(currentPage).section!; + PdfPage? nextPage; + final int index = PdfSectionHelper.getHelper(section).indexOf(currentPage); + if (index == PdfSectionHelper.getHelper(section).count - 1) { + nextPage = section.pages.add(); + } else { + nextPage = PdfSectionHelper.getHelper(section).getPageByIndex(index + 1); + } + return nextPage; + } + + /// internal method + PdfRectangle getPaginateBounds(PdfLayoutParams param) { + return param.format!._boundsSet + ? PdfRectangle.fromRect(param.format!.paginateBounds) + : PdfRectangle( + param.bounds!.x, + 0, + param.bounds!.width, + param.bounds!.height, + ); + } +} + +/// Represents a layouting format +class PdfLayoutFormat { + //Constructor + /// Initializes a new instance of the [PdfLayoutFormat] class. + PdfLayoutFormat({ + PdfLayoutType? layoutType, + PdfLayoutBreakType? breakType, + Rect? paginateBounds, + }) { + this.breakType = breakType ?? PdfLayoutBreakType.fitPage; + this.layoutType = layoutType ?? PdfLayoutType.paginate; + if (paginateBounds != null) { + _paginateBounds = PdfRectangle.fromRect(paginateBounds); + _boundsSet = true; + } else { + _paginateBounds = PdfRectangle.empty; + _boundsSet = false; + } + } + + /// Initializes a new instance of the [PdfLayoutFormat] class + /// from an existing format. + PdfLayoutFormat.fromFormat(PdfLayoutFormat baseFormat) { + breakType = baseFormat.breakType; + layoutType = baseFormat.layoutType; + _paginateBounds = baseFormat._paginateBounds; + _boundsSet = baseFormat._boundsSet; + } + + //Fields + /// Layout type of the element. + PdfLayoutType layoutType = PdfLayoutType.paginate; + + /// Gets the bounds on the next page. + Rect get paginateBounds => _paginateBounds.rect; + + /// Sets the bounds on the next page. + set paginateBounds(Rect value) { + _paginateBounds = PdfRectangle.fromRect(value); + _boundsSet = true; + } + + /// Break type of the element. + PdfLayoutBreakType breakType = PdfLayoutBreakType.fitPage; + + /// Indicates whether PaginateBounds were set and should be used or not. + late bool _boundsSet; + + /// Bounds for the paginating. + late PdfRectangle _paginateBounds; +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfLayoutFormat] helper +class PdfLayoutFormatHelper { + /// internal method + static bool isBoundsSet(PdfLayoutFormat format, [bool? value]) { + if (value != null) { + format._boundsSet = value; + } + return format._boundsSet; + } +} + +/// Represents the layouting parameters. +class PdfLayoutParams { + /// Gets and Sets Start lay outing page. + PdfPage? page; + + /// Gets and Sets Lay outing bounds. + PdfRectangle? bounds; + + /// Gets and Sets Layout settings. + PdfLayoutFormat? format; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/layout_element.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/layout_element.dart index 292665532..190af124e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/layout_element.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/layout_element.dart @@ -1,224 +1,224 @@ -import 'dart:ui'; - -import '../../../drawing/drawing.dart'; -import '../../../pages/pdf_page.dart'; -import '../../../structured_elements/grid/pdf_grid.dart'; -import '../../../structured_elements/lists/pdf_list.dart'; -import '../../images/pdf_bitmap.dart'; -import '../../images/pdf_image.dart'; -import '../../pdf_graphics.dart'; -import '../pdf_bezier_curve.dart'; -import '../pdf_path.dart'; -import '../pdf_text_element.dart'; -import 'element_layouter.dart'; -import 'pdf_shape_element.dart'; -import 'text_layouter.dart'; - -/// Represents the base class for all elements that can be layout on the pages. -abstract class PdfLayoutElement { - //Constructor - /// Initializes a insteace of the [PdfLayoutElement] class. - PdfLayoutElement() { - _helper = PdfLayoutElementHelper(this); - } - - //Properties - late PdfLayoutElementHelper _helper; - - //Public methods - /// Draws an element on the graphics or page. - /// - /// If both graphics and page provide in the arguments - /// then page takes more precedence than graphics - PdfLayoutResult? draw({ - PdfGraphics? graphics, - PdfPage? page, - Rect? bounds, - PdfLayoutFormat? format, - }) { - return _draw(graphics, page, bounds, format); - } - - //Implementation - - PdfLayoutResult? _draw( - PdfGraphics? graphics, - PdfPage? page, - Rect? bounds, - PdfLayoutFormat? format, - ) { - if (page != null) { - final PdfLayoutParams param = PdfLayoutParams(); - param.page = page; - param.bounds = - bounds != null ? PdfRectangle.fromRect(bounds) : PdfRectangle.empty; - param.format = (format != null) ? format : PdfLayoutFormat(); - return _helper.layout(param); - } else if (graphics != null) { - final PdfRectangle rectangle = - bounds != null ? PdfRectangle.fromRect(bounds) : PdfRectangle.empty; - if (rectangle.x != 0 || rectangle.y != 0) { - final PdfGraphicsState gState = graphics.save(); - graphics.translateTransform(rectangle.x, rectangle.y); - rectangle.x = 0; - rectangle.y = 0; - _helper.drawInternal(graphics, rectangle); - graphics.restore(gState); - } else { - _helper.drawInternal(graphics, rectangle); - } - return null; - } else { - return null; - } - } - - //Events - /// Raises before the element should be printed on the page. - BeginPageLayoutCallback? beginPageLayout; - - /// Raises after the element was printed on the page. - EndPageLayoutCallback? endPageLayout; -} - -/// [PdfLayoutElement] helper -class PdfLayoutElementHelper { - /// internal constructor - PdfLayoutElementHelper(this.base); - - /// internal field - PdfLayoutElement base; - - /// internal method - static PdfLayoutElementHelper getHelper(PdfLayoutElement base) { - return base._helper; - } - - /// internal property - bool get raiseBeginPageLayout => base.beginPageLayout != null; - - /// internal property - bool get raisePageLayouted => base.endPageLayout != null; - - /// internal method - PdfLayoutResult? layout(PdfLayoutParams param) { - if (base is PdfShapeElement) { - return PdfShapeElementHelper.layout(base as PdfShapeElement, param); - } else if (base is PdfTextElement) { - return PdfTextElementHelper.getHelper( - base as PdfTextElement, - ).layout(param); - } else if (base is PdfList) { - return PdfListHelper.getHelper(base as PdfList).layout(param); - } else if (base is PdfGrid) { - return PdfGridHelper.getHelper(base as PdfGrid).layout(param); - } - return null; - } - - /// internal method - void onBeginPageLayout(BeginPageLayoutArgs e) { - if (base.beginPageLayout != null) { - base.beginPageLayout!(base, e); - } - } - - /// internal method - void onEndPageLayout(EndPageLayoutArgs e) { - if (base.endPageLayout != null) { - base.endPageLayout!(base, e); - } - } - - /// internal method - void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { - if (base is PdfBezierCurve) { - PdfBezierCurveHelper.getHelper( - base as PdfBezierCurve, - ).drawInternal(graphics, bounds); - } else if (base is PdfPath) { - PdfPathHelper.getHelper(base as PdfPath).drawInternal(graphics, bounds); - } else if (base is PdfTextElement) { - PdfTextElementHelper.getHelper( - base as PdfTextElement, - ).drawInternal(graphics, bounds); - } else if (base is PdfImage) { - PdfBitmapHelper.getHelper( - base as PdfBitmap, - ).drawInternal(graphics, bounds); - } else if (base is PdfList) { - PdfListHelper.getHelper(base as PdfList).drawInternal(graphics, bounds); - } else if (base is PdfGrid) { - PdfGridHelper.getHelper(base as PdfGrid).drawInternal(graphics, bounds); - } - } -} - -/// Represents the base class for classes that contain event data, and provides -/// a value to use for events, once completed the text lay outing on the page. -class EndTextPageLayoutArgs extends EndPageLayoutArgs { - /// Initializes a new instance of the [EndTextPageLayoutArgs] class - /// with the specified [PdfTextLayoutResult]. - EndTextPageLayoutArgs(PdfTextLayoutResult super.result); -} - -/// Provides data for event once lay outing completed on the new page. -class EndPageLayoutArgs extends PdfCancelArgs { - //Constructor - /// Initialize an instance of [EndPageLayoutArgs]. - EndPageLayoutArgs(PdfLayoutResult result) { - _result = result; - } - - //Fields - /// The next page for lay outing. - PdfPage? nextPage; - late PdfLayoutResult _result; - - //Properties - /// Gets the lay outing result of the page. - PdfLayoutResult get result => _result; -} - -/// Provides data for event before lay outing the new page. -class BeginPageLayoutArgs extends PdfCancelArgs { - //Constructor - /// Initialize an instance of [BeginPageLayoutArgs]. - BeginPageLayoutArgs(Rect bounds, PdfPage page) { - _bounds = PdfRectangle.fromRect(bounds); - _page = page; - } - - //Fields - /// The bounds of the lay outing on the page. - late PdfRectangle _bounds; - late PdfPage _page; - - //Properties - /// Gets the page where the lay outing should start. - PdfPage get page => _page; - - /// The bounds of the lay outing on the page. - Rect get bounds => _bounds.rect; - - /// Sets value that indicates the lay outing bounds on the page. - set bounds(Rect value) { - _bounds = PdfRectangle.fromRect(value); - } -} - -/// Provides the data for a cancelable event. -class PdfCancelArgs { - ///The value indicating whether this [PdfCancelArgs] is cancel. - bool cancel = false; -} - -/// Represents the method that will handle an event -/// that before lay outing on the page. -typedef BeginPageLayoutCallback = - void Function(Object sender, BeginPageLayoutArgs args); - -/// Represents the method that will handle an event, -/// once completed the lay outing on the page. -typedef EndPageLayoutCallback = - void Function(Object sender, EndPageLayoutArgs args); +import 'dart:ui'; + +import '../../../drawing/drawing.dart'; +import '../../../pages/pdf_page.dart'; +import '../../../structured_elements/grid/pdf_grid.dart'; +import '../../../structured_elements/lists/pdf_list.dart'; +import '../../images/pdf_bitmap.dart'; +import '../../images/pdf_image.dart'; +import '../../pdf_graphics.dart'; +import '../pdf_bezier_curve.dart'; +import '../pdf_path.dart'; +import '../pdf_text_element.dart'; +import 'element_layouter.dart'; +import 'pdf_shape_element.dart'; +import 'text_layouter.dart'; + +/// Represents the base class for all elements that can be layout on the pages. +abstract class PdfLayoutElement { + //Constructor + /// Initializes a insteace of the [PdfLayoutElement] class. + PdfLayoutElement() { + _helper = PdfLayoutElementHelper(this); + } + + //Properties + late PdfLayoutElementHelper _helper; + + //Public methods + /// Draws an element on the graphics or page. + /// + /// If both graphics and page provide in the arguments + /// then page takes more precedence than graphics + PdfLayoutResult? draw({ + PdfGraphics? graphics, + PdfPage? page, + Rect? bounds, + PdfLayoutFormat? format, + }) { + return _draw(graphics, page, bounds, format); + } + + //Implementation + + PdfLayoutResult? _draw( + PdfGraphics? graphics, + PdfPage? page, + Rect? bounds, + PdfLayoutFormat? format, + ) { + if (page != null) { + final PdfLayoutParams param = PdfLayoutParams(); + param.page = page; + param.bounds = + bounds != null ? PdfRectangle.fromRect(bounds) : PdfRectangle.empty; + param.format = (format != null) ? format : PdfLayoutFormat(); + return _helper.layout(param); + } else if (graphics != null) { + final PdfRectangle rectangle = + bounds != null ? PdfRectangle.fromRect(bounds) : PdfRectangle.empty; + if (rectangle.x != 0 || rectangle.y != 0) { + final PdfGraphicsState gState = graphics.save(); + graphics.translateTransform(rectangle.x, rectangle.y); + rectangle.x = 0; + rectangle.y = 0; + _helper.drawInternal(graphics, rectangle); + graphics.restore(gState); + } else { + _helper.drawInternal(graphics, rectangle); + } + return null; + } else { + return null; + } + } + + //Events + /// Raises before the element should be printed on the page. + BeginPageLayoutCallback? beginPageLayout; + + /// Raises after the element was printed on the page. + EndPageLayoutCallback? endPageLayout; +} + +/// [PdfLayoutElement] helper +class PdfLayoutElementHelper { + /// internal constructor + PdfLayoutElementHelper(this.base); + + /// internal field + PdfLayoutElement base; + + /// internal method + static PdfLayoutElementHelper getHelper(PdfLayoutElement base) { + return base._helper; + } + + /// internal property + bool get raiseBeginPageLayout => base.beginPageLayout != null; + + /// internal property + bool get raisePageLayouted => base.endPageLayout != null; + + /// internal method + PdfLayoutResult? layout(PdfLayoutParams param) { + if (base is PdfShapeElement) { + return PdfShapeElementHelper.layout(base as PdfShapeElement, param); + } else if (base is PdfTextElement) { + return PdfTextElementHelper.getHelper( + base as PdfTextElement, + ).layout(param); + } else if (base is PdfList) { + return PdfListHelper.getHelper(base as PdfList).layout(param); + } else if (base is PdfGrid) { + return PdfGridHelper.getHelper(base as PdfGrid).layout(param); + } + return null; + } + + /// internal method + void onBeginPageLayout(BeginPageLayoutArgs e) { + if (base.beginPageLayout != null) { + base.beginPageLayout!(base, e); + } + } + + /// internal method + void onEndPageLayout(EndPageLayoutArgs e) { + if (base.endPageLayout != null) { + base.endPageLayout!(base, e); + } + } + + /// internal method + void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { + if (base is PdfBezierCurve) { + PdfBezierCurveHelper.getHelper( + base as PdfBezierCurve, + ).drawInternal(graphics, bounds); + } else if (base is PdfPath) { + PdfPathHelper.getHelper(base as PdfPath).drawInternal(graphics, bounds); + } else if (base is PdfTextElement) { + PdfTextElementHelper.getHelper( + base as PdfTextElement, + ).drawInternal(graphics, bounds); + } else if (base is PdfImage) { + PdfBitmapHelper.getHelper( + base as PdfBitmap, + ).drawInternal(graphics, bounds); + } else if (base is PdfList) { + PdfListHelper.getHelper(base as PdfList).drawInternal(graphics, bounds); + } else if (base is PdfGrid) { + PdfGridHelper.getHelper(base as PdfGrid).drawInternal(graphics, bounds); + } + } +} + +/// Represents the base class for classes that contain event data, and provides +/// a value to use for events, once completed the text lay outing on the page. +class EndTextPageLayoutArgs extends EndPageLayoutArgs { + /// Initializes a new instance of the [EndTextPageLayoutArgs] class + /// with the specified [PdfTextLayoutResult]. + EndTextPageLayoutArgs(PdfTextLayoutResult super.result); +} + +/// Provides data for event once lay outing completed on the new page. +class EndPageLayoutArgs extends PdfCancelArgs { + //Constructor + /// Initialize an instance of [EndPageLayoutArgs]. + EndPageLayoutArgs(PdfLayoutResult result) { + _result = result; + } + + //Fields + /// The next page for lay outing. + PdfPage? nextPage; + late PdfLayoutResult _result; + + //Properties + /// Gets the lay outing result of the page. + PdfLayoutResult get result => _result; +} + +/// Provides data for event before lay outing the new page. +class BeginPageLayoutArgs extends PdfCancelArgs { + //Constructor + /// Initialize an instance of [BeginPageLayoutArgs]. + BeginPageLayoutArgs(Rect bounds, PdfPage page) { + _bounds = PdfRectangle.fromRect(bounds); + _page = page; + } + + //Fields + /// The bounds of the lay outing on the page. + late PdfRectangle _bounds; + late PdfPage _page; + + //Properties + /// Gets the page where the lay outing should start. + PdfPage get page => _page; + + /// The bounds of the lay outing on the page. + Rect get bounds => _bounds.rect; + + /// Sets value that indicates the lay outing bounds on the page. + set bounds(Rect value) { + _bounds = PdfRectangle.fromRect(value); + } +} + +/// Provides the data for a cancelable event. +class PdfCancelArgs { + ///The value indicating whether this [PdfCancelArgs] is cancel. + bool cancel = false; +} + +/// Represents the method that will handle an event +/// that before lay outing on the page. +typedef BeginPageLayoutCallback = + void Function(Object sender, BeginPageLayoutArgs args); + +/// Represents the method that will handle an event, +/// once completed the lay outing on the page. +typedef EndPageLayoutCallback = + void Function(Object sender, EndPageLayoutArgs args); diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/pdf_shape_element.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/pdf_shape_element.dart index 5bf1097ed..f7d0b72c1 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/pdf_shape_element.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/pdf_shape_element.dart @@ -1,89 +1,89 @@ -import '../../../drawing/drawing.dart'; -import '../../brushes/pdf_solid_brush.dart'; -import '../../images/pdf_bitmap.dart'; -import '../../images/pdf_image.dart'; -import '../../pdf_pen.dart'; -import '../../pdf_pens.dart'; -import '../pdf_bezier_curve.dart'; -import '../pdf_path.dart'; -import 'element_layouter.dart'; -import 'layout_element.dart'; -import 'shape_layouter.dart'; -import 'text_layouter.dart'; - -/// Base class for the main shapes. -abstract class PdfShapeElement extends PdfLayoutElement { - // fields - final PdfShapeElementHelper _helper = PdfShapeElementHelper(); - - // properties - /// Gets a pen that will be used to draw the element. - PdfPen get pen { - _helper.pen ??= PdfPens.black; - return _helper.pen!; - } - - /// Sets a pen that will be used to draw the element. - set pen(PdfPen value) { - _helper.pen = value; - } - - // implementation - PdfPen _obtainPen() { - return (_helper.pen == null) ? PdfPens.black : _helper.pen!; - } - - PdfLayoutResult? _layout(PdfLayoutParams param) { - final ShapeLayouter layouter = ShapeLayouter(this); - final PdfLayoutResult? result = layouter.layout(param); - return result; - } - - PdfRectangle? _getBoundsInternal() { - if (this is PdfBezierCurve) { - return PdfBezierCurveHelper.getHelper( - this as PdfBezierCurve, - ).getBoundsInternal(); - } else if (this is PdfPath) { - return PdfPathHelper.getHelper(this as PdfPath).getBoundsInternal(); - } else if (this is PdfImage) { - return PdfBitmapHelper.getHelper(this as PdfBitmap).getBoundsInternal(); - } - return null; - } -} - -/// [PdfShapeElement] helper -class PdfShapeElementHelper { - /// internal constructor - PdfShapeElementHelper(); - - /// internal method - static PdfShapeElementHelper getHelper(PdfShapeElement base) { - return base._helper; - } - - /// internal field - PdfPen? pen; - - /// internal field - PdfBrush? brush; - - /// internal method - static PdfPen obtainPen(PdfShapeElement element) { - return element._obtainPen(); - } - - /// internal method - static PdfLayoutResult? layout( - PdfShapeElement element, - PdfLayoutParams param, - ) { - return element._layout(param); - } - - /// internal method - static PdfRectangle? getBoundsInternal(PdfShapeElement element) { - return element._getBoundsInternal(); - } -} +import '../../../drawing/drawing.dart'; +import '../../brushes/pdf_solid_brush.dart'; +import '../../images/pdf_bitmap.dart'; +import '../../images/pdf_image.dart'; +import '../../pdf_pen.dart'; +import '../../pdf_pens.dart'; +import '../pdf_bezier_curve.dart'; +import '../pdf_path.dart'; +import 'element_layouter.dart'; +import 'layout_element.dart'; +import 'shape_layouter.dart'; +import 'text_layouter.dart'; + +/// Base class for the main shapes. +abstract class PdfShapeElement extends PdfLayoutElement { + // fields + final PdfShapeElementHelper _helper = PdfShapeElementHelper(); + + // properties + /// Gets a pen that will be used to draw the element. + PdfPen get pen { + _helper.pen ??= PdfPens.black; + return _helper.pen!; + } + + /// Sets a pen that will be used to draw the element. + set pen(PdfPen value) { + _helper.pen = value; + } + + // implementation + PdfPen _obtainPen() { + return (_helper.pen == null) ? PdfPens.black : _helper.pen!; + } + + PdfLayoutResult? _layout(PdfLayoutParams param) { + final ShapeLayouter layouter = ShapeLayouter(this); + final PdfLayoutResult? result = layouter.layout(param); + return result; + } + + PdfRectangle? _getBoundsInternal() { + if (this is PdfBezierCurve) { + return PdfBezierCurveHelper.getHelper( + this as PdfBezierCurve, + ).getBoundsInternal(); + } else if (this is PdfPath) { + return PdfPathHelper.getHelper(this as PdfPath).getBoundsInternal(); + } else if (this is PdfImage) { + return PdfBitmapHelper.getHelper(this as PdfBitmap).getBoundsInternal(); + } + return null; + } +} + +/// [PdfShapeElement] helper +class PdfShapeElementHelper { + /// internal constructor + PdfShapeElementHelper(); + + /// internal method + static PdfShapeElementHelper getHelper(PdfShapeElement base) { + return base._helper; + } + + /// internal field + PdfPen? pen; + + /// internal field + PdfBrush? brush; + + /// internal method + static PdfPen obtainPen(PdfShapeElement element) { + return element._obtainPen(); + } + + /// internal method + static PdfLayoutResult? layout( + PdfShapeElement element, + PdfLayoutParams param, + ) { + return element._layout(param); + } + + /// internal method + static PdfRectangle? getBoundsInternal(PdfShapeElement element) { + return element._getBoundsInternal(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/shape_layouter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/shape_layouter.dart index f737a6730..6ef1b39a9 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/shape_layouter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/shape_layouter.dart @@ -1,231 +1,231 @@ -import 'dart:ui'; - -import '../../../drawing/drawing.dart'; -import '../../../pages/pdf_page.dart'; -import '../../images/pdf_image.dart'; -import '../../pdf_graphics.dart'; -import '../enums.dart'; -import 'element_layouter.dart'; -import 'layout_element.dart'; -import 'pdf_shape_element.dart'; -import 'text_layouter.dart'; - -/// internal class -class ShapeLayouter extends ElementLayouter { - // constructor - /// internal constructor - ShapeLayouter(PdfShapeElement super.element); - - // properties - /// Gets shape element. - @override - PdfShapeElement? get element => super.element as PdfShapeElement?; - - // implementation - @override - PdfLayoutResult? layoutInternal(PdfLayoutParams param) { - PdfPage? currentPage = param.page; - PdfRectangle? currentBounds = param.bounds; - PdfRectangle? shapeLayoutBounds = PdfRectangle.empty; - if (element is PdfImage) { - shapeLayoutBounds = PdfShapeElementHelper.getBoundsInternal(element!); - } - PdfLayoutResult result; - _ShapeLayoutResult pageResult = _ShapeLayoutResult(); - pageResult._page = currentPage; - while (true) { - // ref is there so implement in proper way - final Map returnedValue = _raiseBeforePageLayout( - currentPage, - currentBounds!.rect, - ); - bool cancel = returnedValue['cancel'] as bool; - currentBounds = PdfRectangle.fromRect(returnedValue['bounds']); - EndPageLayoutArgs? endArgs; - if (!cancel) { - pageResult = _layoutOnPage( - currentPage!, - currentBounds, - shapeLayoutBounds!, - param, - ); - endArgs = _raiseEndPageLayout(pageResult); - cancel = endArgs != null && endArgs.cancel; - } - if (!pageResult._end && !cancel) { - currentBounds = getPaginateBounds(param); - shapeLayoutBounds = _getNextShapeBounds(shapeLayoutBounds!, pageResult); - currentPage = - (endArgs == null || endArgs.nextPage == null) - ? getNextPage(currentPage!) - : endArgs.nextPage; - } else { - result = _getLayoutResult(pageResult); - break; - } - } - return result; - } - - Map _raiseBeforePageLayout( - PdfPage? currentPage, - Rect currentBounds, - ) { - bool cancel = false; - if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout) { - final BeginPageLayoutArgs args = BeginPageLayoutArgs( - currentBounds, - currentPage!, - ); - PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); - cancel = args.cancel; - currentBounds = args.bounds; - } - return {'cancel': cancel, 'bounds': currentBounds}; - } - - _ShapeLayoutResult _layoutOnPage( - PdfPage currentPage, - PdfRectangle currentBounds, - PdfRectangle shapeLayoutBounds, - PdfLayoutParams param, - ) { - final _ShapeLayoutResult result = _ShapeLayoutResult(); - currentBounds = _checkCorrectCurrentBounds( - currentPage, - currentBounds, - shapeLayoutBounds, - param, - ); - final bool fitToPage = _fitsToBounds(currentBounds, shapeLayoutBounds); - final bool canDraw = - !(param.format!.breakType == PdfLayoutBreakType.fitElement && - !fitToPage && - currentPage == param.page); - bool shapeFinished = false; - if (canDraw) { - final PdfRectangle drawRectangle = _getDrawBounds( - currentBounds, - shapeLayoutBounds, - ); - _drawShape(currentPage.graphics, currentBounds.rect, drawRectangle); - result._bounds = - _getPageResultBounds(currentBounds, shapeLayoutBounds).rect; - shapeFinished = - currentBounds.height.toInt() >= shapeLayoutBounds.height.toInt(); - } - result._end = - shapeFinished || param.format!.layoutType == PdfLayoutType.onePage; - result._page = currentPage; - return result; - } - - PdfRectangle _checkCorrectCurrentBounds( - PdfPage currentPage, - PdfRectangle currentBounds, - PdfRectangle shapeLayoutBounds, - PdfLayoutParams param, - ) { - final Size pageSize = currentPage.graphics.clientSize; - currentBounds.width = - (currentBounds.width > 0) - ? currentBounds.width - : pageSize.width - currentBounds.x; - currentBounds.height = - (currentBounds.height > 0) - ? currentBounds.height - : pageSize.height - currentBounds.y; - return currentBounds; - } - - bool _fitsToBounds( - PdfRectangle currentBounds, - PdfRectangle shapeLayoutBounds, - ) { - final bool fits = shapeLayoutBounds.height <= currentBounds.height; - return fits; - } - - PdfRectangle _getDrawBounds( - PdfRectangle currentBounds, - PdfRectangle shapeLayoutBounds, - ) { - final PdfRectangle result = PdfRectangle( - currentBounds.x, - currentBounds.y, - currentBounds.width, - currentBounds.height, - ); - result.y -= shapeLayoutBounds.y; - result.height += shapeLayoutBounds.y; - return result; - } - - void _drawShape( - PdfGraphics g, - Rect currentBounds, - PdfRectangle drawRectangle, - ) { - final PdfGraphicsState gState = g.save(); - try { - g.setClip(bounds: currentBounds); - element!.draw( - graphics: g, - bounds: Rect.fromLTWH(drawRectangle.x, drawRectangle.y, 0, 0), - ); - } finally { - g.restore(gState); - } - } - - PdfRectangle _getPageResultBounds( - PdfRectangle currentBounds, - PdfRectangle shapeLayoutBounds, - ) { - final PdfRectangle result = currentBounds; - result.height = - (result.height > shapeLayoutBounds.height) - ? shapeLayoutBounds.height - : result.height; - return result; - } - - PdfRectangle _getNextShapeBounds( - PdfRectangle shapeLayoutBounds, - _ShapeLayoutResult pageResult, - ) { - shapeLayoutBounds.y += pageResult._bounds!.height; - shapeLayoutBounds.height -= pageResult._bounds!.height; - return shapeLayoutBounds; - } - - EndPageLayoutArgs? _raiseEndPageLayout(_ShapeLayoutResult pageResult) { - EndPageLayoutArgs? args; - if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted) { - final PdfLayoutResult res = _getLayoutResult(pageResult); - args = EndPageLayoutArgs(res); - PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); - } - return args; - } - - PdfLayoutResult _getLayoutResult(_ShapeLayoutResult pageResult) { - final PdfLayoutResult result = PdfLayoutResultHelper.load( - pageResult._page!, - pageResult._bounds!, - ); - return result; - } -} - -class _ShapeLayoutResult { - //Constructor - _ShapeLayoutResult() { - _bounds = Rect.zero; - _end = false; - } - //Fields - PdfPage? _page; - Rect? _bounds; - late bool _end; -} +import 'dart:ui'; + +import '../../../drawing/drawing.dart'; +import '../../../pages/pdf_page.dart'; +import '../../images/pdf_image.dart'; +import '../../pdf_graphics.dart'; +import '../enums.dart'; +import 'element_layouter.dart'; +import 'layout_element.dart'; +import 'pdf_shape_element.dart'; +import 'text_layouter.dart'; + +/// internal class +class ShapeLayouter extends ElementLayouter { + // constructor + /// internal constructor + ShapeLayouter(PdfShapeElement super.element); + + // properties + /// Gets shape element. + @override + PdfShapeElement? get element => super.element as PdfShapeElement?; + + // implementation + @override + PdfLayoutResult? layoutInternal(PdfLayoutParams param) { + PdfPage? currentPage = param.page; + PdfRectangle? currentBounds = param.bounds; + PdfRectangle? shapeLayoutBounds = PdfRectangle.empty; + if (element is PdfImage) { + shapeLayoutBounds = PdfShapeElementHelper.getBoundsInternal(element!); + } + PdfLayoutResult result; + _ShapeLayoutResult pageResult = _ShapeLayoutResult(); + pageResult._page = currentPage; + while (true) { + // ref is there so implement in proper way + final Map returnedValue = _raiseBeforePageLayout( + currentPage, + currentBounds!.rect, + ); + bool cancel = returnedValue['cancel'] as bool; + currentBounds = PdfRectangle.fromRect(returnedValue['bounds']); + EndPageLayoutArgs? endArgs; + if (!cancel) { + pageResult = _layoutOnPage( + currentPage!, + currentBounds, + shapeLayoutBounds!, + param, + ); + endArgs = _raiseEndPageLayout(pageResult); + cancel = endArgs != null && endArgs.cancel; + } + if (!pageResult._end && !cancel) { + currentBounds = getPaginateBounds(param); + shapeLayoutBounds = _getNextShapeBounds(shapeLayoutBounds!, pageResult); + currentPage = + (endArgs == null || endArgs.nextPage == null) + ? getNextPage(currentPage!) + : endArgs.nextPage; + } else { + result = _getLayoutResult(pageResult); + break; + } + } + return result; + } + + Map _raiseBeforePageLayout( + PdfPage? currentPage, + Rect currentBounds, + ) { + bool cancel = false; + if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout) { + final BeginPageLayoutArgs args = BeginPageLayoutArgs( + currentBounds, + currentPage!, + ); + PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); + cancel = args.cancel; + currentBounds = args.bounds; + } + return {'cancel': cancel, 'bounds': currentBounds}; + } + + _ShapeLayoutResult _layoutOnPage( + PdfPage currentPage, + PdfRectangle currentBounds, + PdfRectangle shapeLayoutBounds, + PdfLayoutParams param, + ) { + final _ShapeLayoutResult result = _ShapeLayoutResult(); + currentBounds = _checkCorrectCurrentBounds( + currentPage, + currentBounds, + shapeLayoutBounds, + param, + ); + final bool fitToPage = _fitsToBounds(currentBounds, shapeLayoutBounds); + final bool canDraw = + !(param.format!.breakType == PdfLayoutBreakType.fitElement && + !fitToPage && + currentPage == param.page); + bool shapeFinished = false; + if (canDraw) { + final PdfRectangle drawRectangle = _getDrawBounds( + currentBounds, + shapeLayoutBounds, + ); + _drawShape(currentPage.graphics, currentBounds.rect, drawRectangle); + result._bounds = + _getPageResultBounds(currentBounds, shapeLayoutBounds).rect; + shapeFinished = + currentBounds.height.toInt() >= shapeLayoutBounds.height.toInt(); + } + result._end = + shapeFinished || param.format!.layoutType == PdfLayoutType.onePage; + result._page = currentPage; + return result; + } + + PdfRectangle _checkCorrectCurrentBounds( + PdfPage currentPage, + PdfRectangle currentBounds, + PdfRectangle shapeLayoutBounds, + PdfLayoutParams param, + ) { + final Size pageSize = currentPage.graphics.clientSize; + currentBounds.width = + (currentBounds.width > 0) + ? currentBounds.width + : pageSize.width - currentBounds.x; + currentBounds.height = + (currentBounds.height > 0) + ? currentBounds.height + : pageSize.height - currentBounds.y; + return currentBounds; + } + + bool _fitsToBounds( + PdfRectangle currentBounds, + PdfRectangle shapeLayoutBounds, + ) { + final bool fits = shapeLayoutBounds.height <= currentBounds.height; + return fits; + } + + PdfRectangle _getDrawBounds( + PdfRectangle currentBounds, + PdfRectangle shapeLayoutBounds, + ) { + final PdfRectangle result = PdfRectangle( + currentBounds.x, + currentBounds.y, + currentBounds.width, + currentBounds.height, + ); + result.y -= shapeLayoutBounds.y; + result.height += shapeLayoutBounds.y; + return result; + } + + void _drawShape( + PdfGraphics g, + Rect currentBounds, + PdfRectangle drawRectangle, + ) { + final PdfGraphicsState gState = g.save(); + try { + g.setClip(bounds: currentBounds); + element!.draw( + graphics: g, + bounds: Rect.fromLTWH(drawRectangle.x, drawRectangle.y, 0, 0), + ); + } finally { + g.restore(gState); + } + } + + PdfRectangle _getPageResultBounds( + PdfRectangle currentBounds, + PdfRectangle shapeLayoutBounds, + ) { + final PdfRectangle result = currentBounds; + result.height = + (result.height > shapeLayoutBounds.height) + ? shapeLayoutBounds.height + : result.height; + return result; + } + + PdfRectangle _getNextShapeBounds( + PdfRectangle shapeLayoutBounds, + _ShapeLayoutResult pageResult, + ) { + shapeLayoutBounds.y += pageResult._bounds!.height; + shapeLayoutBounds.height -= pageResult._bounds!.height; + return shapeLayoutBounds; + } + + EndPageLayoutArgs? _raiseEndPageLayout(_ShapeLayoutResult pageResult) { + EndPageLayoutArgs? args; + if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted) { + final PdfLayoutResult res = _getLayoutResult(pageResult); + args = EndPageLayoutArgs(res); + PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); + } + return args; + } + + PdfLayoutResult _getLayoutResult(_ShapeLayoutResult pageResult) { + final PdfLayoutResult result = PdfLayoutResultHelper.load( + pageResult._page!, + pageResult._bounds!, + ); + return result; + } +} + +class _ShapeLayoutResult { + //Constructor + _ShapeLayoutResult() { + _bounds = Rect.zero; + _end = false; + } + //Fields + PdfPage? _page; + Rect? _bounds; + late bool _end; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/text_layouter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/text_layouter.dart index 8bfbf7fbe..501405f30 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/text_layouter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/base/text_layouter.dart @@ -1,318 +1,318 @@ -import 'dart:ui'; - -import '../../../drawing/drawing.dart'; -import '../../../pages/pdf_page.dart'; -import '../../fonts/enums.dart'; -import '../../fonts/pdf_string_format.dart'; -import '../../fonts/pdf_string_layout_result.dart'; -import '../../fonts/pdf_string_layouter.dart'; -import '../../pdf_graphics.dart'; -import '../enums.dart'; -import '../pdf_text_element.dart'; -import 'element_layouter.dart'; -import 'layout_element.dart'; - -/// internal class -class TextLayouter extends ElementLayouter { - //Constructor - /// internal constructor - TextLayouter(PdfTextElement super.element); - - //Fields - PdfStringFormat? _format; - - //Properties - @override - PdfTextElement? get element => - super.element is PdfTextElement ? super.element as PdfTextElement? : null; - - //Implementation - _TextPageLayoutResult _layoutOnPage( - String text, - PdfPage currentPage, - PdfRectangle currentBounds, - PdfLayoutParams param, - ) { - final _TextPageLayoutResult result = _TextPageLayoutResult(); - result.remainder = text; - result.page = currentPage; - currentBounds = _checkCorrectBounds(currentPage, currentBounds); - if (currentBounds.height < 0) { - currentPage = getNextPage(currentPage)!; - result.page = currentPage; - currentBounds = PdfRectangle( - currentBounds.x, - 0, - currentBounds.width, - currentBounds.height, - ); - } - final PdfStringLayouter layouter = PdfStringLayouter(); - final PdfStringLayoutResult stringResult = layouter.layout( - text, - element!.font, - _format, - bounds: currentBounds, - pageHeight: currentPage.getClientSize().height, - ); - final bool textFinished = - stringResult.remainder == null || stringResult.remainder!.isEmpty; - final bool doesntFit = - param.format!.breakType == PdfLayoutBreakType.fitElement && - currentPage == param.page && - !textFinished; - final bool canDraw = !(doesntFit || stringResult.isEmpty); - if (canDraw) { - final PdfGraphics graphics = currentPage.graphics; - PdfGraphicsHelper.getHelper(graphics).drawStringLayoutResult( - stringResult, - element!.font, - element!.pen, - PdfTextElementHelper.getHelper(element!).obtainBrush(), - currentBounds, - _format, - ); - final LineInfo lineInfo = stringResult.lines![stringResult.lineCount - 1]; - result.lastLineBounds = PdfGraphicsHelper.getHelper( - graphics, - ).getLineBounds( - stringResult.lineCount - 1, - stringResult, - element!.font, - currentBounds, - _format, - ); - result.bounds = _getTextPageBounds( - currentPage, - currentBounds, - stringResult, - ); - result.remainder = stringResult.remainder; - _checkCorectStringFormat(lineInfo); - } else { - result.bounds = _getTextPageBounds( - currentPage, - currentBounds, - stringResult, - ); - } - final bool stopLayouting = - stringResult.isEmpty && - ((param.format!.breakType != PdfLayoutBreakType.fitElement) && - (param.format!.layoutType != PdfLayoutType.paginate) && - canDraw) || - (param.format!.breakType == PdfLayoutBreakType.fitElement && - currentPage != param.page); - result.end = - textFinished || - stopLayouting || - param.format!.layoutType == PdfLayoutType.onePage; - return result; - } - - PdfRectangle _checkCorrectBounds( - PdfPage currentPage, - PdfRectangle currentBounds, - ) { - final Size pageSize = currentPage.graphics.clientSize; - currentBounds.height = - (currentBounds.height > 0) - ? currentBounds.height - : pageSize.height - currentBounds.y; - return currentBounds; - } - - Rect _getTextPageBounds( - PdfPage currentPage, - PdfRectangle currentBounds, - PdfStringLayoutResult stringResult, - ) { - final PdfSize textSize = stringResult.size; - double? x = currentBounds.x; - double? y = currentBounds.y; - final double width = - (currentBounds.width > 0) ? currentBounds.width : textSize.width; - final double height = textSize.height; - final PdfRectangle shiftedRect = PdfGraphicsHelper.getHelper( - currentPage.graphics, - ).checkCorrectLayoutRectangle( - textSize, - currentBounds.x, - currentBounds.y, - _format, - ); - if (currentBounds.width <= 0) { - x = shiftedRect.x; - } - if (currentBounds.height <= 0) { - y = shiftedRect.y; - } - final double verticalShift = PdfGraphicsHelper.getHelper( - currentPage.graphics, - ).getTextVerticalAlignShift(textSize.height, currentBounds.height, _format); - y += verticalShift; - return Rect.fromLTWH(x, y, width, height); - } - - void _checkCorectStringFormat(LineInfo lineInfo) { - if (_format != null) { - PdfStringFormatHelper.getHelper(_format!).firstLineIndent = - (lineInfo.lineType & - PdfStringLayouter.getLineTypeValue( - LineType.newLineBreak, - )! > - 0) - ? PdfStringFormatHelper.getHelper( - element!.stringFormat!, - ).firstLineIndent - : 0; - } - } - - PdfTextLayoutResult _getLayoutResult(_TextPageLayoutResult pageResult) { - return PdfTextLayoutResult._( - pageResult.page, - pageResult.bounds, - pageResult.remainder, - pageResult.lastLineBounds, - ); - } - - bool _raiseBeforePageLayout(PdfPage? currentPage, Rect currentBounds) { - bool cancel = false; - if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout) { - final BeginPageLayoutArgs args = BeginPageLayoutArgs( - currentBounds, - currentPage!, - ); - PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); - cancel = args.cancel; - currentBounds = args.bounds; - } - return cancel; - } - - EndTextPageLayoutArgs? _raisePageLayouted(_TextPageLayoutResult pageResult) { - EndTextPageLayoutArgs? args; - if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted) { - args = EndTextPageLayoutArgs(_getLayoutResult(pageResult)); - PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); - } - return args; - } - - //Override methods - @override - PdfLayoutResult layoutInternal(PdfLayoutParams param) { - if (element != null) { - _format = (element!.stringFormat != null) ? element!.stringFormat : null; - PdfPage? currentPage = param.page; - PdfRectangle? currentBounds = param.bounds; - String? text = element!.text; - PdfTextLayoutResult result; - _TextPageLayoutResult pageResult = _TextPageLayoutResult(); - pageResult.page = currentPage; - pageResult.remainder = text; - while (true) { - bool cancel = _raiseBeforePageLayout(currentPage, currentBounds!.rect); - EndTextPageLayoutArgs? endArgs; - if (!cancel) { - pageResult = _layoutOnPage(text!, currentPage!, currentBounds, param); - endArgs = _raisePageLayouted(pageResult); - cancel = endArgs != null && endArgs.cancel; - } - if (!pageResult.end && !cancel) { - if (PdfTextElementHelper.getHelper(element!).isPdfTextElement) { - result = _getLayoutResult(pageResult); - break; - } - currentBounds = getPaginateBounds(param); - text = pageResult.remainder; - currentPage = - endArgs == null || endArgs.nextPage == null - ? getNextPage(currentPage!) - : endArgs.nextPage; - } else { - result = _getLayoutResult(pageResult); - break; - } - } - return result; - } else { - throw ArgumentError.value(element, 'text element cannot be null'); - } - } -} - -/// Represents the text lay outing result settings. -class PdfTextLayoutResult extends PdfLayoutResult { - //Contructor - PdfTextLayoutResult._( - PdfPage? page, - Rect? bounds, - String? remainder, - Rect? lastLineBounds, - ) : super._(page!, bounds!) { - _remainder = remainder; - _lastLineBounds = lastLineBounds; - } - - //Fields - String? _remainder; - Rect? _lastLineBounds; - - //Properties - /// Gets a value that contains the text that was not printed. - String? get remainder => _remainder; - - /// Gets a value that indicates the bounds of the last line - /// that was printed on the page. - Rect? get lastLineBounds => _lastLineBounds; -} - -/// Represents the layouting result format. -class PdfLayoutResult { - //Constructors - /// Represents the layouting result format - /// including bounds and resultant page. - PdfLayoutResult._(PdfPage page, Rect bounds) { - _page = page; - _bounds = bounds; - } - - //Fields - /// The last page where the element was drawn. - late PdfPage _page; - - /// The bounds of the element on the last page where it was drawn. - late Rect _bounds; - - //Properties - /// Gets the last page where the element was drawn. - PdfPage get page => _page; - - /// Gets the bounds of the element on the last page where it was drawn. - Rect get bounds => _bounds; -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfLayoutResult] helper -class PdfLayoutResultHelper { - /// internal method - static PdfLayoutResult load(PdfPage page, Rect bounds) { - return PdfLayoutResult._(page, bounds); - } -} - -class _TextPageLayoutResult { - _TextPageLayoutResult() { - bounds = Rect.zero; - end = false; - lastLineBounds = Rect.zero; - } - PdfPage? page; - late Rect bounds; - late bool end; - String? remainder; - late Rect lastLineBounds; -} +import 'dart:ui'; + +import '../../../drawing/drawing.dart'; +import '../../../pages/pdf_page.dart'; +import '../../fonts/enums.dart'; +import '../../fonts/pdf_string_format.dart'; +import '../../fonts/pdf_string_layout_result.dart'; +import '../../fonts/pdf_string_layouter.dart'; +import '../../pdf_graphics.dart'; +import '../enums.dart'; +import '../pdf_text_element.dart'; +import 'element_layouter.dart'; +import 'layout_element.dart'; + +/// internal class +class TextLayouter extends ElementLayouter { + //Constructor + /// internal constructor + TextLayouter(PdfTextElement super.element); + + //Fields + PdfStringFormat? _format; + + //Properties + @override + PdfTextElement? get element => + super.element is PdfTextElement ? super.element as PdfTextElement? : null; + + //Implementation + _TextPageLayoutResult _layoutOnPage( + String text, + PdfPage currentPage, + PdfRectangle currentBounds, + PdfLayoutParams param, + ) { + final _TextPageLayoutResult result = _TextPageLayoutResult(); + result.remainder = text; + result.page = currentPage; + currentBounds = _checkCorrectBounds(currentPage, currentBounds); + if (currentBounds.height < 0) { + currentPage = getNextPage(currentPage)!; + result.page = currentPage; + currentBounds = PdfRectangle( + currentBounds.x, + 0, + currentBounds.width, + currentBounds.height, + ); + } + final PdfStringLayouter layouter = PdfStringLayouter(); + final PdfStringLayoutResult stringResult = layouter.layout( + text, + element!.font, + _format, + bounds: currentBounds, + pageHeight: currentPage.getClientSize().height, + ); + final bool textFinished = + stringResult.remainder == null || stringResult.remainder!.isEmpty; + final bool doesntFit = + param.format!.breakType == PdfLayoutBreakType.fitElement && + currentPage == param.page && + !textFinished; + final bool canDraw = !(doesntFit || stringResult.isEmpty); + if (canDraw) { + final PdfGraphics graphics = currentPage.graphics; + PdfGraphicsHelper.getHelper(graphics).drawStringLayoutResult( + stringResult, + element!.font, + element!.pen, + PdfTextElementHelper.getHelper(element!).obtainBrush(), + currentBounds, + _format, + ); + final LineInfo lineInfo = stringResult.lines![stringResult.lineCount - 1]; + result.lastLineBounds = PdfGraphicsHelper.getHelper( + graphics, + ).getLineBounds( + stringResult.lineCount - 1, + stringResult, + element!.font, + currentBounds, + _format, + ); + result.bounds = _getTextPageBounds( + currentPage, + currentBounds, + stringResult, + ); + result.remainder = stringResult.remainder; + _checkCorectStringFormat(lineInfo); + } else { + result.bounds = _getTextPageBounds( + currentPage, + currentBounds, + stringResult, + ); + } + final bool stopLayouting = + stringResult.isEmpty && + ((param.format!.breakType != PdfLayoutBreakType.fitElement) && + (param.format!.layoutType != PdfLayoutType.paginate) && + canDraw) || + (param.format!.breakType == PdfLayoutBreakType.fitElement && + currentPage != param.page); + result.end = + textFinished || + stopLayouting || + param.format!.layoutType == PdfLayoutType.onePage; + return result; + } + + PdfRectangle _checkCorrectBounds( + PdfPage currentPage, + PdfRectangle currentBounds, + ) { + final Size pageSize = currentPage.graphics.clientSize; + currentBounds.height = + (currentBounds.height > 0) + ? currentBounds.height + : pageSize.height - currentBounds.y; + return currentBounds; + } + + Rect _getTextPageBounds( + PdfPage currentPage, + PdfRectangle currentBounds, + PdfStringLayoutResult stringResult, + ) { + final PdfSize textSize = stringResult.size; + double? x = currentBounds.x; + double? y = currentBounds.y; + final double width = + (currentBounds.width > 0) ? currentBounds.width : textSize.width; + final double height = textSize.height; + final PdfRectangle shiftedRect = PdfGraphicsHelper.getHelper( + currentPage.graphics, + ).checkCorrectLayoutRectangle( + textSize, + currentBounds.x, + currentBounds.y, + _format, + ); + if (currentBounds.width <= 0) { + x = shiftedRect.x; + } + if (currentBounds.height <= 0) { + y = shiftedRect.y; + } + final double verticalShift = PdfGraphicsHelper.getHelper( + currentPage.graphics, + ).getTextVerticalAlignShift(textSize.height, currentBounds.height, _format); + y += verticalShift; + return Rect.fromLTWH(x, y, width, height); + } + + void _checkCorectStringFormat(LineInfo lineInfo) { + if (_format != null) { + PdfStringFormatHelper.getHelper(_format!).firstLineIndent = + (lineInfo.lineType & + PdfStringLayouter.getLineTypeValue( + LineType.newLineBreak, + )! > + 0) + ? PdfStringFormatHelper.getHelper( + element!.stringFormat!, + ).firstLineIndent + : 0; + } + } + + PdfTextLayoutResult _getLayoutResult(_TextPageLayoutResult pageResult) { + return PdfTextLayoutResult._( + pageResult.page, + pageResult.bounds, + pageResult.remainder, + pageResult.lastLineBounds, + ); + } + + bool _raiseBeforePageLayout(PdfPage? currentPage, Rect currentBounds) { + bool cancel = false; + if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout) { + final BeginPageLayoutArgs args = BeginPageLayoutArgs( + currentBounds, + currentPage!, + ); + PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); + cancel = args.cancel; + currentBounds = args.bounds; + } + return cancel; + } + + EndTextPageLayoutArgs? _raisePageLayouted(_TextPageLayoutResult pageResult) { + EndTextPageLayoutArgs? args; + if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted) { + args = EndTextPageLayoutArgs(_getLayoutResult(pageResult)); + PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); + } + return args; + } + + //Override methods + @override + PdfLayoutResult layoutInternal(PdfLayoutParams param) { + if (element != null) { + _format = (element!.stringFormat != null) ? element!.stringFormat : null; + PdfPage? currentPage = param.page; + PdfRectangle? currentBounds = param.bounds; + String? text = element!.text; + PdfTextLayoutResult result; + _TextPageLayoutResult pageResult = _TextPageLayoutResult(); + pageResult.page = currentPage; + pageResult.remainder = text; + while (true) { + bool cancel = _raiseBeforePageLayout(currentPage, currentBounds!.rect); + EndTextPageLayoutArgs? endArgs; + if (!cancel) { + pageResult = _layoutOnPage(text!, currentPage!, currentBounds, param); + endArgs = _raisePageLayouted(pageResult); + cancel = endArgs != null && endArgs.cancel; + } + if (!pageResult.end && !cancel) { + if (PdfTextElementHelper.getHelper(element!).isPdfTextElement) { + result = _getLayoutResult(pageResult); + break; + } + currentBounds = getPaginateBounds(param); + text = pageResult.remainder; + currentPage = + endArgs == null || endArgs.nextPage == null + ? getNextPage(currentPage!) + : endArgs.nextPage; + } else { + result = _getLayoutResult(pageResult); + break; + } + } + return result; + } else { + throw ArgumentError.value(element, 'text element cannot be null'); + } + } +} + +/// Represents the text lay outing result settings. +class PdfTextLayoutResult extends PdfLayoutResult { + //Contructor + PdfTextLayoutResult._( + PdfPage? page, + Rect? bounds, + String? remainder, + Rect? lastLineBounds, + ) : super._(page!, bounds!) { + _remainder = remainder; + _lastLineBounds = lastLineBounds; + } + + //Fields + String? _remainder; + Rect? _lastLineBounds; + + //Properties + /// Gets a value that contains the text that was not printed. + String? get remainder => _remainder; + + /// Gets a value that indicates the bounds of the last line + /// that was printed on the page. + Rect? get lastLineBounds => _lastLineBounds; +} + +/// Represents the layouting result format. +class PdfLayoutResult { + //Constructors + /// Represents the layouting result format + /// including bounds and resultant page. + PdfLayoutResult._(PdfPage page, Rect bounds) { + _page = page; + _bounds = bounds; + } + + //Fields + /// The last page where the element was drawn. + late PdfPage _page; + + /// The bounds of the element on the last page where it was drawn. + late Rect _bounds; + + //Properties + /// Gets the last page where the element was drawn. + PdfPage get page => _page; + + /// Gets the bounds of the element on the last page where it was drawn. + Rect get bounds => _bounds; +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfLayoutResult] helper +class PdfLayoutResultHelper { + /// internal method + static PdfLayoutResult load(PdfPage page, Rect bounds) { + return PdfLayoutResult._(page, bounds); + } +} + +class _TextPageLayoutResult { + _TextPageLayoutResult() { + bounds = Rect.zero; + end = false; + lastLineBounds = Rect.zero; + } + PdfPage? page; + late Rect bounds; + late bool end; + String? remainder; + late Rect lastLineBounds; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/enums.dart index 3bc9a90b9..a93dc973e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/enums.dart @@ -1,35 +1,35 @@ -/// Specifies type of paginating. -enum PdfLayoutType { - /// If the element exceeds the page, proceed it on the next page. - paginate, - - /// Draw the element on the one page only. - onePage, -} - -/// Specifies how the element should be contained on the page. -enum PdfLayoutBreakType { - /// Fit the element according to the bounds specified or the page bounds. - fitPage, - - /// If the element doesn't fit at the first page, don't draw it on this page. - fitElement, - - /// Fit the columns withtin the page. - fitColumnsToPage, -} - -/// Specifies path point type -enum PathPointType { - /// start type - start, - - /// line type - line, - - /// bezier3 type - bezier3, - - /// closeSubpath type - closeSubpath, -} +/// Specifies type of paginating. +enum PdfLayoutType { + /// If the element exceeds the page, proceed it on the next page. + paginate, + + /// Draw the element on the one page only. + onePage, +} + +/// Specifies how the element should be contained on the page. +enum PdfLayoutBreakType { + /// Fit the element according to the bounds specified or the page bounds. + fitPage, + + /// If the element doesn't fit at the first page, don't draw it on this page. + fitElement, + + /// Fit the columns withtin the page. + fitColumnsToPage, +} + +/// Specifies path point type +enum PathPointType { + /// start type + start, + + /// line type + line, + + /// bezier3 type + bezier3, + + /// closeSubpath type + closeSubpath, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_bezier_curve.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_bezier_curve.dart index 3a305ec6f..0f7b67b4e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_bezier_curve.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_bezier_curve.dart @@ -1,99 +1,99 @@ -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../pdf_graphics.dart'; -import '../pdf_pen.dart'; -import 'base/pdf_shape_element.dart'; - -/// Represents Bezier curve shape. -class PdfBezierCurve extends PdfShapeElement { - // constructor - /// Initializes a new instance of the [PdfBezierCurve] class - /// with the specified [PdfPen] and [Offset] structure. - PdfBezierCurve( - Offset startPoint, - Offset firstControlPoint, - Offset secondControlPoint, - Offset endPoint, { - PdfPen? pen, - }) { - _helper = PdfBezierCurveHelper(this); - if (pen != null) { - super.pen = pen; - } - this.startPoint = startPoint; - this.firstControlPoint = firstControlPoint; - this.secondControlPoint = secondControlPoint; - this.endPoint = endPoint; - } - - // fields - late PdfBezierCurveHelper _helper; - PdfPoint _startPoint = PdfPoint.empty; - PdfPoint _firstControlPoint = PdfPoint.empty; - PdfPoint _secondControlPoint = PdfPoint.empty; - PdfPoint _endPoint = PdfPoint.empty; - - // properties - /// Gets the starting point of the curve - Offset get startPoint => _startPoint.offset; - - /// Sets the starting point of the curve - set startPoint(Offset value) { - _startPoint = PdfPoint.fromOffset(value); - } - - /// Gets the first control point of the curve. - Offset get firstControlPoint => _firstControlPoint.offset; - - /// Sets the first control point of the curve. - set firstControlPoint(Offset value) { - _firstControlPoint = PdfPoint.fromOffset(value); - } - - /// Gets the second control point of the curve - Offset get secondControlPoint => _secondControlPoint.offset; - - /// Sets the second control point of the curve - set secondControlPoint(Offset value) { - _secondControlPoint = PdfPoint.fromOffset(value); - } - - /// Gets the ending point of the curve. - Offset get endPoint => _endPoint.offset; - - /// Sets the ending point of the curve. - set endPoint(Offset value) { - _endPoint = PdfPoint.fromOffset(value); - } -} - -/// [PdfBezierCurve] helper -class PdfBezierCurveHelper { - /// internal constructor - PdfBezierCurveHelper(this.base); - - /// internal field - late PdfBezierCurve base; - - /// internal method - static PdfBezierCurveHelper getHelper(PdfBezierCurve base) { - return base._helper; - } - - /// internal method - void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { - graphics.drawBezier( - base.startPoint, - base.firstControlPoint, - base.secondControlPoint, - base.endPoint, - pen: PdfShapeElementHelper.obtainPen(base), - ); - } - - /// internal method - PdfRectangle? getBoundsInternal() { - return null; - } -} +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../pdf_graphics.dart'; +import '../pdf_pen.dart'; +import 'base/pdf_shape_element.dart'; + +/// Represents Bezier curve shape. +class PdfBezierCurve extends PdfShapeElement { + // constructor + /// Initializes a new instance of the [PdfBezierCurve] class + /// with the specified [PdfPen] and [Offset] structure. + PdfBezierCurve( + Offset startPoint, + Offset firstControlPoint, + Offset secondControlPoint, + Offset endPoint, { + PdfPen? pen, + }) { + _helper = PdfBezierCurveHelper(this); + if (pen != null) { + super.pen = pen; + } + this.startPoint = startPoint; + this.firstControlPoint = firstControlPoint; + this.secondControlPoint = secondControlPoint; + this.endPoint = endPoint; + } + + // fields + late PdfBezierCurveHelper _helper; + PdfPoint _startPoint = PdfPoint.empty; + PdfPoint _firstControlPoint = PdfPoint.empty; + PdfPoint _secondControlPoint = PdfPoint.empty; + PdfPoint _endPoint = PdfPoint.empty; + + // properties + /// Gets the starting point of the curve + Offset get startPoint => _startPoint.offset; + + /// Sets the starting point of the curve + set startPoint(Offset value) { + _startPoint = PdfPoint.fromOffset(value); + } + + /// Gets the first control point of the curve. + Offset get firstControlPoint => _firstControlPoint.offset; + + /// Sets the first control point of the curve. + set firstControlPoint(Offset value) { + _firstControlPoint = PdfPoint.fromOffset(value); + } + + /// Gets the second control point of the curve + Offset get secondControlPoint => _secondControlPoint.offset; + + /// Sets the second control point of the curve + set secondControlPoint(Offset value) { + _secondControlPoint = PdfPoint.fromOffset(value); + } + + /// Gets the ending point of the curve. + Offset get endPoint => _endPoint.offset; + + /// Sets the ending point of the curve. + set endPoint(Offset value) { + _endPoint = PdfPoint.fromOffset(value); + } +} + +/// [PdfBezierCurve] helper +class PdfBezierCurveHelper { + /// internal constructor + PdfBezierCurveHelper(this.base); + + /// internal field + late PdfBezierCurve base; + + /// internal method + static PdfBezierCurveHelper getHelper(PdfBezierCurve base) { + return base._helper; + } + + /// internal method + void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { + graphics.drawBezier( + base.startPoint, + base.firstControlPoint, + base.secondControlPoint, + base.endPoint, + pen: PdfShapeElementHelper.obtainPen(base), + ); + } + + /// internal method + PdfRectangle? getBoundsInternal() { + return null; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_path.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_path.dart index 2b6303bfe..81fbe77a9 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_path.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_path.dart @@ -1,293 +1,293 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../brushes/pdf_solid_brush.dart'; -import '../enums.dart'; -import '../pdf_graphics.dart'; -import '../pdf_pen.dart'; -import 'base/pdf_shape_element.dart'; -import 'enums.dart'; - -/// Implements graphics path, which is a sequence of -/// primitive graphics elements. -class PdfPath extends PdfShapeElement { - // constructor - /// Initializes a new instance of the [PdfPath] class - /// with pen, brush, fillMode, points and pathTypes - PdfPath({ - PdfPen? pen, - PdfBrush? brush, - PdfFillMode fillMode = PdfFillMode.winding, - List points = const [], - List? pathTypes, - }) { - _helper = PdfPathHelper(this); - if (pen != null) { - super.pen = pen; - } - if (points.isNotEmpty && pathTypes != null) { - addPath(points, pathTypes); - } - _helper.fillMode = fillMode; - this.brush = brush; - } - - // fields - late PdfPathHelper _helper; - final bool _isBeziers3 = false; - bool _bStartFigure = true; - - // properties - /// Gets the brush of the element - PdfBrush? get brush { - return PdfShapeElementHelper.getHelper(this).brush; - } - - /// Sets the brush of the element - set brush(PdfBrush? value) { - if (value != null) { - PdfShapeElementHelper.getHelper(this).brush = value; - } - } - - // implementation - List _assignPathtype(List types) { - final List pathType = []; - for (final dynamic t in types) { - switch (t) { - case 0: - pathType.add(PathPointType.start); - break; - case 1: - pathType.add(PathPointType.line); - break; - case 3: - pathType.add(PathPointType.bezier3); - break; - case 129: - pathType.add(PathPointType.closeSubpath); - break; - default: - throw ArgumentError('Invalid pathType'); - } - } - return pathType; - } - - /// Appends the path specified by the points and their types to this one. - void addPath(List pathPoints, List pathTypes) { - final int count = pathPoints.length; - if (count != pathTypes.length) { - throw ArgumentError.value( - 'The argument arrays should be of equal length.', - ); - } - _helper.points.addAll(pathPoints); - _helper.pathTypes.addAll(_assignPathtype(pathTypes)); - } - - /// Adds a line - void addLine(Offset point1, Offset point2) { - _addPoints([ - point1.dx, - point1.dy, - point2.dx, - point2.dy, - ], PathPointType.line); - } - - /// Adds a rectangle - void addRectangle(Rect bounds) { - startFigure(); - _addPoints([ - bounds.left, - bounds.top, - bounds.left + bounds.width, - bounds.top, - bounds.left + bounds.width, - bounds.top + bounds.height, - bounds.left, - bounds.top + bounds.height, - ], PathPointType.line); - closeFigure(); - } - - /// Adds a pie - void addPie(Rect bounds, double startAngle, double sweepAngle) { - startFigure(); - addArc(bounds, startAngle, sweepAngle); - _addPoint( - Offset(bounds.left + bounds.width / 2, bounds.top + bounds.height / 2), - PathPointType.line, - ); - closeFigure(); - } - - /// Adds an ellipse - void addEllipse(Rect bounds) { - startFigure(); - addArc(bounds, 0, 360); - closeFigure(); - } - - /// Adds an bezier curve - void addBezier( - Offset startPoint, - Offset firstControlPoint, - Offset secondControlPoint, - Offset endPoint, - ) { - final List points = []; - points.add(startPoint.dx); - points.add(startPoint.dy); - points.add(firstControlPoint.dx); - points.add(firstControlPoint.dy); - points.add(secondControlPoint.dx); - points.add(secondControlPoint.dy); - points.add(endPoint.dx); - points.add(endPoint.dy); - _addPoints(points, PathPointType.bezier3); - } - - /// Adds an arc - void addArc(Rect bounds, double startAngle, double sweepAngle) { - final List> points = PdfGraphicsHelper.getBezierArcPoints( - bounds.left, - bounds.top, - bounds.left + bounds.width, - bounds.top + bounds.height, - startAngle, - sweepAngle, - ); - final List list = []; - for (int i = 0; i < points.length; ++i) { - final List pt = points[i]; - list.clear(); - list.addAll(pt); - _addPoints(list, PathPointType.bezier3); - } - } - - /// Adds a polygon - void addPolygon(List points) { - final List p = []; - startFigure(); - for (final Offset point in points) { - p.add(point.dx); - p.add(point.dy); - } - _addPoints(p, PathPointType.line); - closeFigure(); - } - - /// Starts a new figure. - void startFigure() { - _bStartFigure = true; - } - - /// Closes the last figure. - void closeFigure() { - if (_helper.points.isNotEmpty) { - _helper.points.add(Offset.zero); - _helper.pathTypes.add(PathPointType.closeSubpath); - } - startFigure(); - } - - void _addPoints(List points, PathPointType pointType) { - for (int i = 0; i < points.length; ++i) { - final Offset point = Offset(points[i], points[i + 1]); - if (i == 0) { - if (_helper.points.isEmpty || _bStartFigure) { - _addPoint(point, PathPointType.start); - _bStartFigure = false; - } else if (point != - _helper.points.elementAt(_helper.points.length - 1) && - !_isBeziers3) { - _addPoint(point, PathPointType.line); - } else if (point != - _helper.points.elementAt(_helper.points.length - 1)) { - _addPoint(point, PathPointType.bezier3); - } - } else { - _addPoint(point, pointType); - } - ++i; - } - } - - void _addPoint(Offset point, PathPointType pointType) { - _helper.points.add(point); - _helper.pathTypes.add(pointType); - } -} - -/// [PdfPath] helper -class PdfPathHelper { - /// internal constructor - PdfPathHelper(this.path); - - /// internal field - PdfPath path; - - /// internal field - // ignore: prefer_final_fields - List points = []; - - /// internal field - final List pathTypes = []; - - /// internal field - late PdfFillMode fillMode; - - /// internal method - static PdfPathHelper getHelper(PdfPath path) { - return path._helper; - } - - /// internal method - PdfRectangle getBoundsInternal() { - final List points = this.points; - PdfRectangle bounds = PdfRectangle.empty; - if (points.isNotEmpty) { - double xmin = points[0].dx; - double xmax = points[0].dx; - double ymin = points[0].dy; - double ymax = points[0].dy; - for (int i = 1; i < points.length; ++i) { - if (points.length - 1 == i) { - if (points[i] == Offset.zero) { - break; - } - } - final Offset point = points[i]; - xmin = min(point.dx, xmin); - xmax = max(point.dx, xmax); - ymin = min(point.dy, ymin); - ymax = max(point.dy, ymax); - } - bounds = PdfRectangle(xmin, ymin, xmax - xmin, ymax - ymin); - } - return bounds; - } - - /// internal method - void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { - graphics.drawPath(path, pen: path.pen, brush: path.brush); - } - - /// internal method - void addLines(List linePoints) { - Offset start = linePoints[0]; - if (linePoints.length == 1) { - path._addPoint(linePoints[0], PathPointType.line); - } else { - for (int i = 1; i < linePoints.length; i++) { - final Offset last = linePoints[i]; - path.addLine(start, last); - start = last; - } - } - } -} +import 'dart:math'; +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../brushes/pdf_solid_brush.dart'; +import '../enums.dart'; +import '../pdf_graphics.dart'; +import '../pdf_pen.dart'; +import 'base/pdf_shape_element.dart'; +import 'enums.dart'; + +/// Implements graphics path, which is a sequence of +/// primitive graphics elements. +class PdfPath extends PdfShapeElement { + // constructor + /// Initializes a new instance of the [PdfPath] class + /// with pen, brush, fillMode, points and pathTypes + PdfPath({ + PdfPen? pen, + PdfBrush? brush, + PdfFillMode fillMode = PdfFillMode.winding, + List points = const [], + List? pathTypes, + }) { + _helper = PdfPathHelper(this); + if (pen != null) { + super.pen = pen; + } + if (points.isNotEmpty && pathTypes != null) { + addPath(points, pathTypes); + } + _helper.fillMode = fillMode; + this.brush = brush; + } + + // fields + late PdfPathHelper _helper; + final bool _isBeziers3 = false; + bool _bStartFigure = true; + + // properties + /// Gets the brush of the element + PdfBrush? get brush { + return PdfShapeElementHelper.getHelper(this).brush; + } + + /// Sets the brush of the element + set brush(PdfBrush? value) { + if (value != null) { + PdfShapeElementHelper.getHelper(this).brush = value; + } + } + + // implementation + List _assignPathtype(List types) { + final List pathType = []; + for (final dynamic t in types) { + switch (t) { + case 0: + pathType.add(PathPointType.start); + break; + case 1: + pathType.add(PathPointType.line); + break; + case 3: + pathType.add(PathPointType.bezier3); + break; + case 129: + pathType.add(PathPointType.closeSubpath); + break; + default: + throw ArgumentError('Invalid pathType'); + } + } + return pathType; + } + + /// Appends the path specified by the points and their types to this one. + void addPath(List pathPoints, List pathTypes) { + final int count = pathPoints.length; + if (count != pathTypes.length) { + throw ArgumentError.value( + 'The argument arrays should be of equal length.', + ); + } + _helper.points.addAll(pathPoints); + _helper.pathTypes.addAll(_assignPathtype(pathTypes)); + } + + /// Adds a line + void addLine(Offset point1, Offset point2) { + _addPoints([ + point1.dx, + point1.dy, + point2.dx, + point2.dy, + ], PathPointType.line); + } + + /// Adds a rectangle + void addRectangle(Rect bounds) { + startFigure(); + _addPoints([ + bounds.left, + bounds.top, + bounds.left + bounds.width, + bounds.top, + bounds.left + bounds.width, + bounds.top + bounds.height, + bounds.left, + bounds.top + bounds.height, + ], PathPointType.line); + closeFigure(); + } + + /// Adds a pie + void addPie(Rect bounds, double startAngle, double sweepAngle) { + startFigure(); + addArc(bounds, startAngle, sweepAngle); + _addPoint( + Offset(bounds.left + bounds.width / 2, bounds.top + bounds.height / 2), + PathPointType.line, + ); + closeFigure(); + } + + /// Adds an ellipse + void addEllipse(Rect bounds) { + startFigure(); + addArc(bounds, 0, 360); + closeFigure(); + } + + /// Adds an bezier curve + void addBezier( + Offset startPoint, + Offset firstControlPoint, + Offset secondControlPoint, + Offset endPoint, + ) { + final List points = []; + points.add(startPoint.dx); + points.add(startPoint.dy); + points.add(firstControlPoint.dx); + points.add(firstControlPoint.dy); + points.add(secondControlPoint.dx); + points.add(secondControlPoint.dy); + points.add(endPoint.dx); + points.add(endPoint.dy); + _addPoints(points, PathPointType.bezier3); + } + + /// Adds an arc + void addArc(Rect bounds, double startAngle, double sweepAngle) { + final List> points = PdfGraphicsHelper.getBezierArcPoints( + bounds.left, + bounds.top, + bounds.left + bounds.width, + bounds.top + bounds.height, + startAngle, + sweepAngle, + ); + final List list = []; + for (int i = 0; i < points.length; ++i) { + final List pt = points[i]; + list.clear(); + list.addAll(pt); + _addPoints(list, PathPointType.bezier3); + } + } + + /// Adds a polygon + void addPolygon(List points) { + final List p = []; + startFigure(); + for (final Offset point in points) { + p.add(point.dx); + p.add(point.dy); + } + _addPoints(p, PathPointType.line); + closeFigure(); + } + + /// Starts a new figure. + void startFigure() { + _bStartFigure = true; + } + + /// Closes the last figure. + void closeFigure() { + if (_helper.points.isNotEmpty) { + _helper.points.add(Offset.zero); + _helper.pathTypes.add(PathPointType.closeSubpath); + } + startFigure(); + } + + void _addPoints(List points, PathPointType pointType) { + for (int i = 0; i < points.length; ++i) { + final Offset point = Offset(points[i], points[i + 1]); + if (i == 0) { + if (_helper.points.isEmpty || _bStartFigure) { + _addPoint(point, PathPointType.start); + _bStartFigure = false; + } else if (point != + _helper.points.elementAt(_helper.points.length - 1) && + !_isBeziers3) { + _addPoint(point, PathPointType.line); + } else if (point != + _helper.points.elementAt(_helper.points.length - 1)) { + _addPoint(point, PathPointType.bezier3); + } + } else { + _addPoint(point, pointType); + } + ++i; + } + } + + void _addPoint(Offset point, PathPointType pointType) { + _helper.points.add(point); + _helper.pathTypes.add(pointType); + } +} + +/// [PdfPath] helper +class PdfPathHelper { + /// internal constructor + PdfPathHelper(this.path); + + /// internal field + PdfPath path; + + /// internal field + // ignore: prefer_final_fields + List points = []; + + /// internal field + final List pathTypes = []; + + /// internal field + late PdfFillMode fillMode; + + /// internal method + static PdfPathHelper getHelper(PdfPath path) { + return path._helper; + } + + /// internal method + PdfRectangle getBoundsInternal() { + final List points = this.points; + PdfRectangle bounds = PdfRectangle.empty; + if (points.isNotEmpty) { + double xmin = points[0].dx; + double xmax = points[0].dx; + double ymin = points[0].dy; + double ymax = points[0].dy; + for (int i = 1; i < points.length; ++i) { + if (points.length - 1 == i) { + if (points[i] == Offset.zero) { + break; + } + } + final Offset point = points[i]; + xmin = min(point.dx, xmin); + xmax = max(point.dx, xmax); + ymin = min(point.dy, ymin); + ymax = max(point.dy, ymax); + } + bounds = PdfRectangle(xmin, ymin, xmax - xmin, ymax - ymin); + } + return bounds; + } + + /// internal method + void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { + graphics.drawPath(path, pen: path.pen, brush: path.brush); + } + + /// internal method + void addLines(List linePoints) { + Offset start = linePoints[0]; + if (linePoints.length == 1) { + path._addPoint(linePoints[0], PathPointType.line); + } else { + for (int i = 1; i < linePoints.length; i++) { + final Offset last = linePoints[i]; + path.addLine(start, last); + start = last; + } + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_template.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_template.dart index bd9359d67..61706f09d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_template.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_template.dart @@ -1,338 +1,338 @@ -import 'dart:ui'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../drawing/drawing.dart'; -import '../../io/pdf_constants.dart'; -import '../../io/pdf_cross_table.dart'; -import '../../pages/pdf_page.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_reference.dart'; -import '../../primitives/pdf_stream.dart'; -import '../pdf_graphics.dart'; -import '../pdf_resources.dart'; - -/// Represents PDF Template object. -/// ```dart -/// //Create a new PDF template and draw graphical content like text, images, and more. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawPdfTemplate( -/// PdfTemplate(100, 50) -/// ..graphics!.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 14), -/// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)), -/// Offset(0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfTemplate implements IPdfWrapper { - /// Initializes a new instance of the [PdfTemplate] class. - /// ```dart - /// //Create a new PDF template and draw graphical content like text, images, and more. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawPdfTemplate( - /// PdfTemplate(100, 50) - /// ..graphics!.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 14), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)), - /// Offset(0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfTemplate(double width, double height) { - _helper = PdfTemplateHelper(this); - _helper.content = PdfStream(); - _setSize(width, height); - _helper.content[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.xObject, - ); - _helper.content[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.form, - ); - } - - PdfTemplate._fromRect(Rect bounds) { - _helper = PdfTemplateHelper(this); - _helper.content = PdfStream(); - _setBounds(bounds); - _helper.content[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.xObject, - ); - _helper.content[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.form, - ); - } - - PdfTemplate._fromPdfStream(PdfStream template) { - _helper = PdfTemplateHelper(this); - _helper.content = template; - final IPdfPrimitive obj = - PdfCrossTable.dereference( - _helper.content[PdfDictionaryProperties.bBox], - )!; - final PdfRectangle rect = (obj as PdfArray).toRectangle(); - _size = rect.size; - _helper.isReadonly = true; - } - - PdfTemplate._( - Offset origin, - Size size, - List stream, - PdfDictionary resources, - bool isLoadedPage, - PdfPageHelper page, - ) : super() { - _helper = PdfTemplateHelper(this); - if (size == Size.zero) { - throw ArgumentError.value( - size, - 'size', - 'The size of the new PdfTemplate cannot be empty.', - ); - } - _helper.content = PdfStream(); - if (page.cropBox.left > 0 && page.cropBox.top > 0) { - _setBounds(page.cropBox); - _helper._origin = Offset(page.cropBox.left, page.cropBox.top); - _setSize(page.cropBox.right, page.cropBox.bottom, _helper._origin); - } else { - if (origin.dx < 0 || origin.dy < 0) { - _setSize(size.width, size.height, origin); - } else { - _setSize(size.width, size.height); - } - } - _initialize(); - _helper.content.dataStream!.addAll(stream); - _helper.content[PdfDictionaryProperties.resources] = PdfDictionary( - resources, - ); - _helper._resources = PdfResources(resources); - _helper.isLoadedPageTemplate = isLoadedPage; - _helper.isReadonly = true; - } - - //Fields - late PdfTemplateHelper _helper; - late PdfSize _size; - PdfGraphics? _graphics; - - //Properties - /// Gets the size of the template. - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a PDF Template. - /// PdfTemplate template = PdfTemplate(100, 50); - /// //Gets the PDF template size. - /// Size size = template.size; - /// //Draw a string using the graphics of the template. - /// template.graphics!.drawString( - /// 'Hello World', PdfStandardFont(PdfFontFamily.helvetica, 14), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)); - /// //Add a new page and draw the template on the page graphics of the document. - /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Size get size => _size.size; - - /// Gets graphics context of the template. - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a PDF Template. - /// PdfTemplate template = PdfTemplate(100, 50); - /// //Draw a rectangle on the template graphics - /// template.graphics!.drawRectangle( - /// brush: PdfBrushes.burlyWood, bounds: Rect.fromLTWH(0, 0, 100, 50)); - /// //Draw a string using the graphics of the template. - /// template.graphics!.drawString( - /// 'Hello World', PdfStandardFont(PdfFontFamily.helvetica, 14), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)); - /// //Add a new page and draw the template on the page graphics of the document. - /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGraphics? get graphics { - if (_helper.isReadonly) { - _graphics = null; - } else if (_graphics == null) { - _graphics = PdfGraphicsHelper.load(size, _getResources, _helper.content); - _helper.writeTransformation ??= true; - if (_helper.writeTransformation!) { - PdfGraphicsHelper.getHelper(_graphics!).initializeCoordinates(); - } - } - return _graphics; - } - - //Public methods - /// Resets an instance. - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a PDF Template. - /// PdfTemplate template = PdfTemplate(100, 50); - /// //Draw a rectangle on the template graphics - /// template.graphics!.drawRectangle( - /// brush: PdfBrushes.burlyWood, bounds: Rect.fromLTWH(0, 0, 100, 50)); - /// //Add a new page and draw the template on the page graphics of the document. - /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); - /// //Reset PDF template - /// template.reset(); - /// //Draw a string using the graphics of the template. - /// template.graphics!.drawString( - /// 'Hello World', PdfStandardFont(PdfFontFamily.helvetica, 14), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)); - /// //Add a new page and draw the template on the page graphics of the document. - /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void reset([double? width, double? height]) { - if (width != null && height != null) { - _setSize(width, height); - reset(); - } else { - if (_helper._resources != null) { - _helper._resources = null; - _helper.content.remove(PdfDictionaryProperties.resources); - } - if (_graphics != null) { - PdfGraphicsHelper.getHelper(_graphics!).reset(size); - } - } - } - - //Implementation - PdfResources? _getResources() { - if (_helper._resources == null) { - _helper._resources = PdfResources(); - _helper.content[PdfDictionaryProperties.resources] = _helper._resources; - } - return _helper._resources; - } - - void _setSize(double width, double height, [Offset? origin]) { - if (origin != null) { - final PdfArray array = PdfArray([ - origin.dx, - origin.dy, - width, - height, - ]); - _helper.content[PdfDictionaryProperties.bBox] = array; - _size = PdfSize(width, height); - } else { - final PdfRectangle rectangle = PdfRectangle(0, 0, width, height); - _helper.content[PdfDictionaryProperties.bBox] = PdfArray.fromRectangle( - rectangle, - ); - _size = PdfSize(width, height); - } - } - - void _setBounds(Rect bounds) { - final PdfRectangle rect = PdfRectangle.fromRect(bounds); - final PdfArray val = PdfArray.fromRectangle(rect); - _helper.content[PdfDictionaryProperties.bBox] = val; - _size = rect.size; - } - - void _initialize() { - _helper.content[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.xObject, - ); - _helper.content[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.form, - ); - } -} - -/// [PdfTemplate] helper -class PdfTemplateHelper { - /// internal constructor - PdfTemplateHelper(this.template); - - /// internal field - PdfTemplate template; - - /// internal field - late PdfStream content; - - /// internal field - bool? writeTransformation; - - /// internal field - bool isReadonly = false; - - /// internal field - bool isLoadedPageTemplate = false; - PdfResources? _resources; - Offset _origin = Offset.zero; - - /// internal method - static PdfTemplateHelper getHelper(PdfTemplate template) { - return template._helper; - } - - /// internal property - IPdfPrimitive? get element => content; - //ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfStream) { - content = value; - } - } - - Offset get origin => _origin; - - /// internal method - static PdfTemplate fromRect(Rect bounds) { - return PdfTemplate._fromRect(bounds); - } - - /// internal method - static PdfTemplate fromPdfStream(PdfStream template) { - return PdfTemplate._fromPdfStream(template); - } - - /// internal method - static PdfTemplate internal( - Offset origin, - Size size, - List stream, - PdfDictionary resources, - bool isLoadedPage, - PdfPageHelper page, - ) { - return PdfTemplate._(origin, size, stream, resources, isLoadedPage, page); - } - - /// internal method - void cloneResources(PdfCrossTable? crossTable) { - if (_resources != null && crossTable != null) { - final List prevReference = crossTable.prevReference!; - crossTable.prevReference = []; - final PdfDictionary? resourceDict = - _resources!.cloneObject(crossTable) as PdfDictionary?; - crossTable.prevReference!.addAll(prevReference); - _resources = PdfResources(resourceDict); - content[PdfDictionaryProperties.resources] = resourceDict; - } - } -} +import 'dart:ui'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../drawing/drawing.dart'; +import '../../io/pdf_constants.dart'; +import '../../io/pdf_cross_table.dart'; +import '../../pages/pdf_page.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_reference.dart'; +import '../../primitives/pdf_stream.dart'; +import '../pdf_graphics.dart'; +import '../pdf_resources.dart'; + +/// Represents PDF Template object. +/// ```dart +/// //Create a new PDF template and draw graphical content like text, images, and more. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawPdfTemplate( +/// PdfTemplate(100, 50) +/// ..graphics!.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 14), +/// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)), +/// Offset(0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfTemplate implements IPdfWrapper { + /// Initializes a new instance of the [PdfTemplate] class. + /// ```dart + /// //Create a new PDF template and draw graphical content like text, images, and more. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawPdfTemplate( + /// PdfTemplate(100, 50) + /// ..graphics!.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 14), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)), + /// Offset(0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfTemplate(double width, double height) { + _helper = PdfTemplateHelper(this); + _helper.content = PdfStream(); + _setSize(width, height); + _helper.content[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.xObject, + ); + _helper.content[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.form, + ); + } + + PdfTemplate._fromRect(Rect bounds) { + _helper = PdfTemplateHelper(this); + _helper.content = PdfStream(); + _setBounds(bounds); + _helper.content[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.xObject, + ); + _helper.content[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.form, + ); + } + + PdfTemplate._fromPdfStream(PdfStream template) { + _helper = PdfTemplateHelper(this); + _helper.content = template; + final IPdfPrimitive obj = + PdfCrossTable.dereference( + _helper.content[PdfDictionaryProperties.bBox], + )!; + final PdfRectangle rect = (obj as PdfArray).toRectangle(); + _size = rect.size; + _helper.isReadonly = true; + } + + PdfTemplate._( + Offset origin, + Size size, + List stream, + PdfDictionary resources, + bool isLoadedPage, + PdfPageHelper page, + ) : super() { + _helper = PdfTemplateHelper(this); + if (size == Size.zero) { + throw ArgumentError.value( + size, + 'size', + 'The size of the new PdfTemplate cannot be empty.', + ); + } + _helper.content = PdfStream(); + if (page.cropBox.left > 0 && page.cropBox.top > 0) { + _setBounds(page.cropBox); + _helper._origin = Offset(page.cropBox.left, page.cropBox.top); + _setSize(page.cropBox.right, page.cropBox.bottom, _helper._origin); + } else { + if (origin.dx < 0 || origin.dy < 0) { + _setSize(size.width, size.height, origin); + } else { + _setSize(size.width, size.height); + } + } + _initialize(); + _helper.content.dataStream!.addAll(stream); + _helper.content[PdfDictionaryProperties.resources] = PdfDictionary( + resources, + ); + _helper._resources = PdfResources(resources); + _helper.isLoadedPageTemplate = isLoadedPage; + _helper.isReadonly = true; + } + + //Fields + late PdfTemplateHelper _helper; + late PdfSize _size; + PdfGraphics? _graphics; + + //Properties + /// Gets the size of the template. + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a PDF Template. + /// PdfTemplate template = PdfTemplate(100, 50); + /// //Gets the PDF template size. + /// Size size = template.size; + /// //Draw a string using the graphics of the template. + /// template.graphics!.drawString( + /// 'Hello World', PdfStandardFont(PdfFontFamily.helvetica, 14), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)); + /// //Add a new page and draw the template on the page graphics of the document. + /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Size get size => _size.size; + + /// Gets graphics context of the template. + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a PDF Template. + /// PdfTemplate template = PdfTemplate(100, 50); + /// //Draw a rectangle on the template graphics + /// template.graphics!.drawRectangle( + /// brush: PdfBrushes.burlyWood, bounds: Rect.fromLTWH(0, 0, 100, 50)); + /// //Draw a string using the graphics of the template. + /// template.graphics!.drawString( + /// 'Hello World', PdfStandardFont(PdfFontFamily.helvetica, 14), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)); + /// //Add a new page and draw the template on the page graphics of the document. + /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGraphics? get graphics { + if (_helper.isReadonly) { + _graphics = null; + } else if (_graphics == null) { + _graphics = PdfGraphicsHelper.load(size, _getResources, _helper.content); + _helper.writeTransformation ??= true; + if (_helper.writeTransformation!) { + PdfGraphicsHelper.getHelper(_graphics!).initializeCoordinates(); + } + } + return _graphics; + } + + //Public methods + /// Resets an instance. + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a PDF Template. + /// PdfTemplate template = PdfTemplate(100, 50); + /// //Draw a rectangle on the template graphics + /// template.graphics!.drawRectangle( + /// brush: PdfBrushes.burlyWood, bounds: Rect.fromLTWH(0, 0, 100, 50)); + /// //Add a new page and draw the template on the page graphics of the document. + /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); + /// //Reset PDF template + /// template.reset(); + /// //Draw a string using the graphics of the template. + /// template.graphics!.drawString( + /// 'Hello World', PdfStandardFont(PdfFontFamily.helvetica, 14), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(5, 5, 0, 0)); + /// //Add a new page and draw the template on the page graphics of the document. + /// document.pages.add().graphics.drawPdfTemplate(template, Offset(0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void reset([double? width, double? height]) { + if (width != null && height != null) { + _setSize(width, height); + reset(); + } else { + if (_helper._resources != null) { + _helper._resources = null; + _helper.content.remove(PdfDictionaryProperties.resources); + } + if (_graphics != null) { + PdfGraphicsHelper.getHelper(_graphics!).reset(size); + } + } + } + + //Implementation + PdfResources? _getResources() { + if (_helper._resources == null) { + _helper._resources = PdfResources(); + _helper.content[PdfDictionaryProperties.resources] = _helper._resources; + } + return _helper._resources; + } + + void _setSize(double width, double height, [Offset? origin]) { + if (origin != null) { + final PdfArray array = PdfArray([ + origin.dx, + origin.dy, + width, + height, + ]); + _helper.content[PdfDictionaryProperties.bBox] = array; + _size = PdfSize(width, height); + } else { + final PdfRectangle rectangle = PdfRectangle(0, 0, width, height); + _helper.content[PdfDictionaryProperties.bBox] = PdfArray.fromRectangle( + rectangle, + ); + _size = PdfSize(width, height); + } + } + + void _setBounds(Rect bounds) { + final PdfRectangle rect = PdfRectangle.fromRect(bounds); + final PdfArray val = PdfArray.fromRectangle(rect); + _helper.content[PdfDictionaryProperties.bBox] = val; + _size = rect.size; + } + + void _initialize() { + _helper.content[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.xObject, + ); + _helper.content[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.form, + ); + } +} + +/// [PdfTemplate] helper +class PdfTemplateHelper { + /// internal constructor + PdfTemplateHelper(this.template); + + /// internal field + PdfTemplate template; + + /// internal field + late PdfStream content; + + /// internal field + bool? writeTransformation; + + /// internal field + bool isReadonly = false; + + /// internal field + bool isLoadedPageTemplate = false; + PdfResources? _resources; + Offset _origin = Offset.zero; + + /// internal method + static PdfTemplateHelper getHelper(PdfTemplate template) { + return template._helper; + } + + /// internal property + IPdfPrimitive? get element => content; + //ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfStream) { + content = value; + } + } + + Offset get origin => _origin; + + /// internal method + static PdfTemplate fromRect(Rect bounds) { + return PdfTemplate._fromRect(bounds); + } + + /// internal method + static PdfTemplate fromPdfStream(PdfStream template) { + return PdfTemplate._fromPdfStream(template); + } + + /// internal method + static PdfTemplate internal( + Offset origin, + Size size, + List stream, + PdfDictionary resources, + bool isLoadedPage, + PdfPageHelper page, + ) { + return PdfTemplate._(origin, size, stream, resources, isLoadedPage, page); + } + + /// internal method + void cloneResources(PdfCrossTable? crossTable) { + if (_resources != null && crossTable != null) { + final List prevReference = crossTable.prevReference!; + crossTable.prevReference = []; + final PdfDictionary? resourceDict = + _resources!.cloneObject(crossTable) as PdfDictionary?; + crossTable.prevReference!.addAll(prevReference); + _resources = PdfResources(resourceDict); + content[PdfDictionaryProperties.resources] = resourceDict; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_text_element.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_text_element.dart index 25f7c3836..f5f81eaed 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_text_element.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/figures/pdf_text_element.dart @@ -1,119 +1,119 @@ -import '../../drawing/drawing.dart'; -import '../brushes/pdf_solid_brush.dart'; -import '../fonts/enums.dart'; -import '../fonts/pdf_font.dart'; -import '../fonts/pdf_standard_font.dart'; -import '../fonts/pdf_string_format.dart'; -import '../pdf_color.dart'; -import '../pdf_graphics.dart'; -import '../pdf_pen.dart'; -import 'base/element_layouter.dart'; -import 'base/layout_element.dart'; -import 'base/text_layouter.dart'; - -/// Represents the text area with the ability to span several pages -/// and inherited from the [PdfLayoutElement] class -class PdfTextElement extends PdfLayoutElement { - //Constructors - /// Initializes a new instance of the [PdfTextElement] class. - PdfTextElement({ - String text = '', - PdfFont? font, - PdfPen? pen, - PdfBrush? brush, - PdfStringFormat? format, - }) { - _helper = PdfTextElementHelper(this); - _initialize(text, font, pen, brush, format); - } - - //Fields - late PdfTextElementHelper _helper; - - /// A value indicating the text that should be printed. - late String text; - - /// Gets or sets a [PdfFont] that defines the text format. - late PdfFont font; - - /// Gets or sets a [PdfPen] that determines the color, width, - /// and style of the text - PdfPen? pen; - - /// Gets or sets the [PdfBrush] that will be used to draw the text with color - /// and texture. - PdfBrush? brush; - - /// Gets or sets the [PdfStringFormat] that will be used to - /// set the string format - PdfStringFormat? stringFormat; - - //Implementation - void _initialize( - String text, - PdfFont? font, - PdfPen? pen, - PdfBrush? brush, - PdfStringFormat? format, - ) { - this.text = text; - if (font != null) { - this.font = font; - } else { - this.font = PdfStandardFont(PdfFontFamily.helvetica, 8); - } - if (brush != null) { - this.brush = brush; - } - if (pen != null) { - this.pen = pen; - } - if (format != null) { - stringFormat = format; - } - _helper.isPdfTextElement = false; - } -} - -/// [PdfTextElement] helper -class PdfTextElementHelper { - /// internal constructor - PdfTextElementHelper(this.base); - - /// internal field - PdfTextElement base; - - /// internal field - late bool isPdfTextElement; - - /// internal method - static PdfTextElementHelper getHelper(PdfTextElement base) { - return base._helper; - } - - /// internal method - PdfBrush obtainBrush() { - return (base.brush == null) - ? PdfSolidBrush(PdfColor(0, 0, 0)) - : base.brush!; - } - - /// internal method - PdfLayoutResult? layout(PdfLayoutParams param) { - final TextLayouter layouter = TextLayouter(base); - final PdfLayoutResult? result = layouter.layout(param); - return (result != null && result is PdfTextLayoutResult) ? result : null; - } - - /// internal method - void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { - graphics.drawString( - base.text, - base.font, - pen: base.pen, - brush: obtainBrush(), - bounds: bounds.rect, - format: base.stringFormat, - ); - } -} +import '../../drawing/drawing.dart'; +import '../brushes/pdf_solid_brush.dart'; +import '../fonts/enums.dart'; +import '../fonts/pdf_font.dart'; +import '../fonts/pdf_standard_font.dart'; +import '../fonts/pdf_string_format.dart'; +import '../pdf_color.dart'; +import '../pdf_graphics.dart'; +import '../pdf_pen.dart'; +import 'base/element_layouter.dart'; +import 'base/layout_element.dart'; +import 'base/text_layouter.dart'; + +/// Represents the text area with the ability to span several pages +/// and inherited from the [PdfLayoutElement] class +class PdfTextElement extends PdfLayoutElement { + //Constructors + /// Initializes a new instance of the [PdfTextElement] class. + PdfTextElement({ + String text = '', + PdfFont? font, + PdfPen? pen, + PdfBrush? brush, + PdfStringFormat? format, + }) { + _helper = PdfTextElementHelper(this); + _initialize(text, font, pen, brush, format); + } + + //Fields + late PdfTextElementHelper _helper; + + /// A value indicating the text that should be printed. + late String text; + + /// Gets or sets a [PdfFont] that defines the text format. + late PdfFont font; + + /// Gets or sets a [PdfPen] that determines the color, width, + /// and style of the text + PdfPen? pen; + + /// Gets or sets the [PdfBrush] that will be used to draw the text with color + /// and texture. + PdfBrush? brush; + + /// Gets or sets the [PdfStringFormat] that will be used to + /// set the string format + PdfStringFormat? stringFormat; + + //Implementation + void _initialize( + String text, + PdfFont? font, + PdfPen? pen, + PdfBrush? brush, + PdfStringFormat? format, + ) { + this.text = text; + if (font != null) { + this.font = font; + } else { + this.font = PdfStandardFont(PdfFontFamily.helvetica, 8); + } + if (brush != null) { + this.brush = brush; + } + if (pen != null) { + this.pen = pen; + } + if (format != null) { + stringFormat = format; + } + _helper.isPdfTextElement = false; + } +} + +/// [PdfTextElement] helper +class PdfTextElementHelper { + /// internal constructor + PdfTextElementHelper(this.base); + + /// internal field + PdfTextElement base; + + /// internal field + late bool isPdfTextElement; + + /// internal method + static PdfTextElementHelper getHelper(PdfTextElement base) { + return base._helper; + } + + /// internal method + PdfBrush obtainBrush() { + return (base.brush == null) + ? PdfSolidBrush(PdfColor(0, 0, 0)) + : base.brush!; + } + + /// internal method + PdfLayoutResult? layout(PdfLayoutParams param) { + final TextLayouter layouter = TextLayouter(base); + final PdfLayoutResult? result = layouter.layout(param); + return (result != null && result is PdfTextLayoutResult) ? result : null; + } + + /// internal method + void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { + graphics.drawString( + base.text, + base.font, + pen: base.pen, + brush: obtainBrush(), + bounds: bounds.rect, + format: base.stringFormat, + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/enums.dart index 3ef4c90fe..9b80bac5f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/enums.dart @@ -1,170 +1,170 @@ -/// Specifies style information applied to text. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString('Hello World!', -/// PdfStandardFont(PdfFontFamily.helvetica, 12, style: PdfFontStyle.bold)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfFontStyle { - ///Represents Regular text - regular, - - ///Represents Bold text - bold, - - ///Represents Italic text - italic, - - ///Represents Underline text - underline, - - ///Represents Strikeout text - strikethrough, -} - -/// Indicates type of standard PDF fonts. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// brush: PdfBrushes.black); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfFontFamily { - /// Represents the Helvetica font. - helvetica, - - /// Represents the Courier font. - courier, - - /// Represents the Times Roman font. - timesRoman, - - /// Represents the Symbol font. - symbol, - - /// Represents the ZapfDingbats font. - zapfDingbats, -} - -/// Specifies the type of SubSuperscript. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// format: PdfStringFormat( -/// alignment: PdfTextAlignment.left, -/// subSuperscript: PdfSubSuperscript.subscript)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfSubSuperscript { - /// Specifies no subscript or superscript. - none, - - /// Specifies superscript format. - superscript, - - /// Specifies subscript format. - subscript, -} - -/// Specifies the type of CJK font. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'こんにちは世界', PdfCjkStandardFont(PdfCjkFontFamily.heiseiMinchoW3, 20), -/// brush: PdfBrushes.black); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfCjkFontFamily { - /// Represents the Hanyang Systems Gothic Medium font. - hanyangSystemsGothicMedium, - - /// Represents the Hanyang Systems shin myeong Jo Medium font. - hanyangSystemsShinMyeongJoMedium, - - /// Represents the Heisei kaku GothicW5 font. - heiseiKakuGothicW5, - - /// Represents the Heisei MinchoW3 font. - heiseiMinchoW3, - - /// Represents the Monotype Hei Medium font. - monotypeHeiMedium, - - /// Represents the monotype sung Light font. - monotypeSungLight, - - /// Represents the sinotype song light font. - sinoTypeSongLight, -} - -/// Specifies the types of text wrapping. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// format: PdfStringFormat( -/// alignment: PdfTextAlignment.left, wordWrap: PdfWordWrapType.word)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -enum PdfWordWrapType { - /// Text wrapping between lines when formatting - /// within a rectangle is disabled. - none, - - /// Text is wrapped by words. If there is a word that is longer than bounds' - /// width, this word is wrapped by characters. - word, - - /// Text is wrapped by words. If there is a word that is longer than bounds' - /// width, it won't be wrapped at all and the process will be finished. - wordOnly, - - /// Text is wrapped by characters. In this case the word - /// at the end of the text line can be split. - character, -} - -/// Break type of the line. -enum LineType { - /// Unknown type line. - none, - - /// The line has new line symbol. - newLineBreak, - - /// layout break. - layoutBreak, - - /// The line is the first in the paragraph. - firstParagraphLine, - - /// The line is the last in the paragraph. - lastParagraphLine, -} +/// Specifies style information applied to text. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString('Hello World!', +/// PdfStandardFont(PdfFontFamily.helvetica, 12, style: PdfFontStyle.bold)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfFontStyle { + ///Represents Regular text + regular, + + ///Represents Bold text + bold, + + ///Represents Italic text + italic, + + ///Represents Underline text + underline, + + ///Represents Strikeout text + strikethrough, +} + +/// Indicates type of standard PDF fonts. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// brush: PdfBrushes.black); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfFontFamily { + /// Represents the Helvetica font. + helvetica, + + /// Represents the Courier font. + courier, + + /// Represents the Times Roman font. + timesRoman, + + /// Represents the Symbol font. + symbol, + + /// Represents the ZapfDingbats font. + zapfDingbats, +} + +/// Specifies the type of SubSuperscript. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// format: PdfStringFormat( +/// alignment: PdfTextAlignment.left, +/// subSuperscript: PdfSubSuperscript.subscript)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfSubSuperscript { + /// Specifies no subscript or superscript. + none, + + /// Specifies superscript format. + superscript, + + /// Specifies subscript format. + subscript, +} + +/// Specifies the type of CJK font. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'こんにちは世界', PdfCjkStandardFont(PdfCjkFontFamily.heiseiMinchoW3, 20), +/// brush: PdfBrushes.black); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfCjkFontFamily { + /// Represents the Hanyang Systems Gothic Medium font. + hanyangSystemsGothicMedium, + + /// Represents the Hanyang Systems shin myeong Jo Medium font. + hanyangSystemsShinMyeongJoMedium, + + /// Represents the Heisei kaku GothicW5 font. + heiseiKakuGothicW5, + + /// Represents the Heisei MinchoW3 font. + heiseiMinchoW3, + + /// Represents the Monotype Hei Medium font. + monotypeHeiMedium, + + /// Represents the monotype sung Light font. + monotypeSungLight, + + /// Represents the sinotype song light font. + sinoTypeSongLight, +} + +/// Specifies the types of text wrapping. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// format: PdfStringFormat( +/// alignment: PdfTextAlignment.left, wordWrap: PdfWordWrapType.word)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +enum PdfWordWrapType { + /// Text wrapping between lines when formatting + /// within a rectangle is disabled. + none, + + /// Text is wrapped by words. If there is a word that is longer than bounds' + /// width, this word is wrapped by characters. + word, + + /// Text is wrapped by words. If there is a word that is longer than bounds' + /// width, it won't be wrapped at all and the process will be finished. + wordOnly, + + /// Text is wrapped by characters. In this case the word + /// at the end of the text line can be split. + character, +} + +/// Break type of the line. +enum LineType { + /// Unknown type line. + none, + + /// The line has new line symbol. + newLineBreak, + + /// layout break. + layoutBreak, + + /// The line is the first in the paragraph. + firstParagraphLine, + + /// The line is the last in the paragraph. + lastParagraphLine, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cid_font.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cid_font.dart index 615b0a69b..30fd56f9b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cid_font.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cid_font.dart @@ -1,320 +1,320 @@ -import '../../drawing/drawing.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_number.dart'; -import '../../primitives/pdf_string.dart'; -import 'enums.dart'; -import 'pdf_font.dart'; -import 'pdf_font_metrics.dart'; - -/// internal class -class PdfCidFont extends PdfDictionary { - /// Initializes a new instance of the [PdfCidFont] class. - PdfCidFont( - PdfCjkFontFamily? fontFamily, - int? fontStyle, - PdfFontMetrics fontMetrics, - ) { - this[PdfDictionaryProperties.type] = PdfName(PdfDictionaryProperties.font); - this[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.cidFontType2, - ); - this[PdfDictionaryProperties.baseFont] = PdfName( - fontMetrics.postScriptName, - ); - this[PdfDictionaryProperties.dw] = PdfNumber( - (fontMetrics.widthTable! as CjkWidthTable).defaultWidth, - ); - this[PdfDictionaryProperties.w] = fontMetrics.widthTable!.toArray(); - this[PdfDictionaryProperties.fontDescriptor] = _getFontDescryptor( - fontFamily, - fontStyle, - fontMetrics, - ); - this[PdfDictionaryProperties.cidSystemInfo] = _getSystemInfo(fontFamily); - } - - /// Gets the system info. - PdfDictionary _getSystemInfo(PdfCjkFontFamily? fontFamily) { - final PdfDictionary sysInfo = PdfDictionary(); - sysInfo[PdfDictionaryProperties.registry] = PdfString('Adobe'); - switch (fontFamily) { - case PdfCjkFontFamily.hanyangSystemsGothicMedium: - case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: - sysInfo[PdfDictionaryProperties.ordering] = PdfString('Korea1'); - sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(1); - break; - case PdfCjkFontFamily.heiseiKakuGothicW5: - case PdfCjkFontFamily.heiseiMinchoW3: - sysInfo[PdfDictionaryProperties.ordering] = PdfString('Japan1'); - sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(2); - break; - case PdfCjkFontFamily.monotypeHeiMedium: - case PdfCjkFontFamily.monotypeSungLight: - sysInfo[PdfDictionaryProperties.ordering] = PdfString('CNS1'); - sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(0); - break; - case PdfCjkFontFamily.sinoTypeSongLight: - sysInfo[PdfDictionaryProperties.ordering] = PdfString('GB1'); - sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(2); - break; - // ignore: no_default_cases - default: - break; - } - return sysInfo; - } - - /// internal method - PdfDictionary _getFontDescryptor( - PdfCjkFontFamily? fontFamily, - int? fontStyle, - PdfFontMetrics fontMetrics, - ) { - final PdfDictionary fontDescryptor = PdfDictionary(); - switch (fontFamily) { - case PdfCjkFontFamily.hanyangSystemsGothicMedium: - _fillHanyangSystemsGothicMedium( - fontDescryptor, - fontFamily, - fontMetrics, - ); - break; - case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: - _fillHanyangSystemsShinMyeongJoMedium( - fontDescryptor, - fontFamily, - fontMetrics, - ); - break; - case PdfCjkFontFamily.heiseiKakuGothicW5: - _fillHanyangSystemsGothicMediumWithStyle( - fontDescryptor, - fontStyle!, - fontFamily, - fontMetrics, - ); - break; - case PdfCjkFontFamily.heiseiMinchoW3: - _fillHeiseiMinchoW3(fontDescryptor, fontFamily, fontMetrics); - break; - case PdfCjkFontFamily.monotypeHeiMedium: - _fillMonotypeHeiMedium(fontDescryptor, fontFamily, fontMetrics); - break; - case PdfCjkFontFamily.monotypeSungLight: - _fillMonotypeSungLight(fontDescryptor, fontFamily, fontMetrics); - break; - case PdfCjkFontFamily.sinoTypeSongLight: - _fillSinoTypeSongLight(fontDescryptor, fontFamily, fontMetrics); - break; - // ignore: no_default_cases - default: - break; - } - return fontDescryptor; - } - - /// Fills the monotype sung light font descryptor. - void _fillMonotypeSungLight( - PdfDictionary fontDescryptor, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - final PdfRectangle fontBBox = PdfRectangle(-160, -249, 1175, 1137); - _fillFontBBox(fontDescryptor, fontBBox); - _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); - final PdfNumber stem = PdfNumber(93); - fontDescryptor[PdfDictionaryProperties.stemV] = stem; - fontDescryptor[PdfDictionaryProperties.stemH] = stem; - final PdfNumber width = PdfNumber(1000); - fontDescryptor[PdfDictionaryProperties.avgWidth] = width; - fontDescryptor[PdfDictionaryProperties.maxWidth] = width; - fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); - fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); - fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); - } - - /// Fills the hanyang systems shin myeong jo medium font descryptor. - void _fillHanyangSystemsShinMyeongJoMedium( - PdfDictionary fontDescryptor, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - final PdfRectangle fontBBox = PdfRectangle(0, -148, 1001, 1028); - _fillFontBBox(fontDescryptor, fontBBox); - _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); - final PdfNumber stem = PdfNumber(93); - fontDescryptor[PdfDictionaryProperties.stemV] = stem; - fontDescryptor[PdfDictionaryProperties.stemH] = stem; - final PdfNumber width = PdfNumber(1000); - fontDescryptor[PdfDictionaryProperties.avgWidth] = width; - fontDescryptor[PdfDictionaryProperties.maxWidth] = width; - fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); - fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); - fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); - } - - /// Fills the heisei mincho w3 font descryptor. - void _fillHeiseiMinchoW3( - PdfDictionary fontDescryptor, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - final PdfRectangle fontBBox = PdfRectangle(-123, -257, 1124, 1167); - _fillFontBBox(fontDescryptor, fontBBox); - _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); - final PdfNumber stem = PdfNumber(93); - fontDescryptor[PdfDictionaryProperties.stemV] = stem; - fontDescryptor[PdfDictionaryProperties.stemH] = stem; - final PdfNumber width = PdfNumber(1000); - fontDescryptor[PdfDictionaryProperties.avgWidth] = PdfNumber(702); - fontDescryptor[PdfDictionaryProperties.maxWidth] = width; - fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(718); - fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(500); - fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); - } - - /// Fills the sino type song light font descryptor. - void _fillSinoTypeSongLight( - PdfDictionary fontDescryptor, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - final PdfRectangle fontBBox = PdfRectangle(-25, -254, 1025, 1134); - _fillFontBBox(fontDescryptor, fontBBox); - _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); - final PdfNumber stem = PdfNumber(93); - fontDescryptor[PdfDictionaryProperties.stemV] = stem; - fontDescryptor[PdfDictionaryProperties.stemH] = stem; - final PdfNumber width = PdfNumber(1000); - fontDescryptor[PdfDictionaryProperties.avgWidth] = width; - fontDescryptor[PdfDictionaryProperties.maxWidth] = width; - fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); - fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); - fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); - } - - /// Fills the monotype hei medium font descryptor. - void _fillMonotypeHeiMedium( - PdfDictionary fontDescryptor, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - final PdfRectangle fontBBox = PdfRectangle(-45, -250, 1060, 1137); - _fillFontBBox(fontDescryptor, fontBBox); - _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); - final PdfNumber stem = PdfNumber(93); - fontDescryptor[PdfDictionaryProperties.stemV] = stem; - fontDescryptor[PdfDictionaryProperties.stemH] = stem; - final PdfNumber width = PdfNumber(1000); - fontDescryptor[PdfDictionaryProperties.avgWidth] = width; - fontDescryptor[PdfDictionaryProperties.maxWidth] = width; - fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); - fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); - fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); - } - - /// Fills the hanyang systems gothic medium font descryptor. - void _fillHanyangSystemsGothicMedium( - PdfDictionary fontDescryptor, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - final PdfRectangle fontBBox = PdfRectangle(-6, -145, 1009, 1025); - _fillFontBBox(fontDescryptor, fontBBox); - _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); - fontDescryptor[PdfDictionaryProperties.flags] = PdfNumber(4); - final PdfNumber stem = PdfNumber(93); - fontDescryptor[PdfDictionaryProperties.stemV] = stem; - fontDescryptor[PdfDictionaryProperties.stemH] = stem; - final PdfNumber width = PdfNumber(1000); - fontDescryptor[PdfDictionaryProperties.avgWidth] = width; - fontDescryptor[PdfDictionaryProperties.maxWidth] = width; - fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); - fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); - fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); - } - - /// Fills the heisei kaku gothic w5 font descryptor. - void _fillHanyangSystemsGothicMediumWithStyle( - PdfDictionary fontDescryptor, - int fontStyle, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - final PdfRectangle fontBBox = PdfRectangle(-92, -250, 1102, 1175); - final PdfRectangle fontBBoxI = PdfRectangle(-92, -250, 1102, 1932); - if ((fontStyle & - (PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) | - PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold))) != - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) { - _fillFontBBox(fontDescryptor, fontBBox); - } else { - _fillFontBBox(fontDescryptor, fontBBoxI); - } - _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); - final PdfNumber stem = PdfNumber(93); - fontDescryptor[PdfDictionaryProperties.stemV] = stem; - fontDescryptor[PdfDictionaryProperties.stemH] = stem; - final PdfNumber width = PdfNumber(1000); - fontDescryptor[PdfDictionaryProperties.avgWidth] = PdfNumber(689); - fontDescryptor[PdfDictionaryProperties.maxWidth] = width; - fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(718); - fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(500); - fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); - } - - /// Fills the known info. - void _fillKnownInfo( - PdfDictionary fontDescryptor, - PdfCjkFontFamily? fontFamily, - PdfFontMetrics fontMetrics, - ) { - fontDescryptor[PdfDictionaryProperties.fontName] = PdfName( - fontMetrics.postScriptName, - ); - fontDescryptor[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.fontDescriptor, - ); - fontDescryptor[PdfDictionaryProperties.italicAngle] = PdfNumber(0); - fontDescryptor[PdfDictionaryProperties.missingWidth] = PdfNumber( - (fontMetrics.widthTable! as CjkWidthTable).defaultWidth, - ); - fontDescryptor[PdfDictionaryProperties.ascent] = PdfNumber( - fontMetrics.ascent, - ); - fontDescryptor[PdfDictionaryProperties.descent] = PdfNumber( - fontMetrics.descent, - ); - _fillFlags(fontDescryptor, fontFamily); - } - - /// Fills the flags. - void _fillFlags(PdfDictionary fontDescryptor, PdfCjkFontFamily? fontFamily) { - switch (fontFamily) { - case PdfCjkFontFamily.monotypeHeiMedium: - case PdfCjkFontFamily.hanyangSystemsGothicMedium: - case PdfCjkFontFamily.heiseiKakuGothicW5: - fontDescryptor[PdfDictionaryProperties.flags] = PdfNumber(4); - break; - case PdfCjkFontFamily.sinoTypeSongLight: - case PdfCjkFontFamily.monotypeSungLight: - case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: - case PdfCjkFontFamily.heiseiMinchoW3: - fontDescryptor[PdfDictionaryProperties.flags] = PdfNumber(6); - break; - // ignore: no_default_cases - default: - break; - } - } - - /// Fills the font BBox. - void _fillFontBBox(PdfDictionary fontDescryptor, PdfRectangle fontBBox) { - fontDescryptor[PdfDictionaryProperties.fontBBox] = PdfArray.fromRectangle( - fontBBox, - ); - } -} +import '../../drawing/drawing.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_number.dart'; +import '../../primitives/pdf_string.dart'; +import 'enums.dart'; +import 'pdf_font.dart'; +import 'pdf_font_metrics.dart'; + +/// internal class +class PdfCidFont extends PdfDictionary { + /// Initializes a new instance of the [PdfCidFont] class. + PdfCidFont( + PdfCjkFontFamily? fontFamily, + int? fontStyle, + PdfFontMetrics fontMetrics, + ) { + this[PdfDictionaryProperties.type] = PdfName(PdfDictionaryProperties.font); + this[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.cidFontType2, + ); + this[PdfDictionaryProperties.baseFont] = PdfName( + fontMetrics.postScriptName, + ); + this[PdfDictionaryProperties.dw] = PdfNumber( + (fontMetrics.widthTable! as CjkWidthTable).defaultWidth, + ); + this[PdfDictionaryProperties.w] = fontMetrics.widthTable!.toArray(); + this[PdfDictionaryProperties.fontDescriptor] = _getFontDescryptor( + fontFamily, + fontStyle, + fontMetrics, + ); + this[PdfDictionaryProperties.cidSystemInfo] = _getSystemInfo(fontFamily); + } + + /// Gets the system info. + PdfDictionary _getSystemInfo(PdfCjkFontFamily? fontFamily) { + final PdfDictionary sysInfo = PdfDictionary(); + sysInfo[PdfDictionaryProperties.registry] = PdfString('Adobe'); + switch (fontFamily) { + case PdfCjkFontFamily.hanyangSystemsGothicMedium: + case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: + sysInfo[PdfDictionaryProperties.ordering] = PdfString('Korea1'); + sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(1); + break; + case PdfCjkFontFamily.heiseiKakuGothicW5: + case PdfCjkFontFamily.heiseiMinchoW3: + sysInfo[PdfDictionaryProperties.ordering] = PdfString('Japan1'); + sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(2); + break; + case PdfCjkFontFamily.monotypeHeiMedium: + case PdfCjkFontFamily.monotypeSungLight: + sysInfo[PdfDictionaryProperties.ordering] = PdfString('CNS1'); + sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(0); + break; + case PdfCjkFontFamily.sinoTypeSongLight: + sysInfo[PdfDictionaryProperties.ordering] = PdfString('GB1'); + sysInfo[PdfDictionaryProperties.supplement] = PdfNumber(2); + break; + // ignore: no_default_cases + default: + break; + } + return sysInfo; + } + + /// internal method + PdfDictionary _getFontDescryptor( + PdfCjkFontFamily? fontFamily, + int? fontStyle, + PdfFontMetrics fontMetrics, + ) { + final PdfDictionary fontDescryptor = PdfDictionary(); + switch (fontFamily) { + case PdfCjkFontFamily.hanyangSystemsGothicMedium: + _fillHanyangSystemsGothicMedium( + fontDescryptor, + fontFamily, + fontMetrics, + ); + break; + case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: + _fillHanyangSystemsShinMyeongJoMedium( + fontDescryptor, + fontFamily, + fontMetrics, + ); + break; + case PdfCjkFontFamily.heiseiKakuGothicW5: + _fillHanyangSystemsGothicMediumWithStyle( + fontDescryptor, + fontStyle!, + fontFamily, + fontMetrics, + ); + break; + case PdfCjkFontFamily.heiseiMinchoW3: + _fillHeiseiMinchoW3(fontDescryptor, fontFamily, fontMetrics); + break; + case PdfCjkFontFamily.monotypeHeiMedium: + _fillMonotypeHeiMedium(fontDescryptor, fontFamily, fontMetrics); + break; + case PdfCjkFontFamily.monotypeSungLight: + _fillMonotypeSungLight(fontDescryptor, fontFamily, fontMetrics); + break; + case PdfCjkFontFamily.sinoTypeSongLight: + _fillSinoTypeSongLight(fontDescryptor, fontFamily, fontMetrics); + break; + // ignore: no_default_cases + default: + break; + } + return fontDescryptor; + } + + /// Fills the monotype sung light font descryptor. + void _fillMonotypeSungLight( + PdfDictionary fontDescryptor, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + final PdfRectangle fontBBox = PdfRectangle(-160, -249, 1175, 1137); + _fillFontBBox(fontDescryptor, fontBBox); + _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); + final PdfNumber stem = PdfNumber(93); + fontDescryptor[PdfDictionaryProperties.stemV] = stem; + fontDescryptor[PdfDictionaryProperties.stemH] = stem; + final PdfNumber width = PdfNumber(1000); + fontDescryptor[PdfDictionaryProperties.avgWidth] = width; + fontDescryptor[PdfDictionaryProperties.maxWidth] = width; + fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); + fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); + fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); + } + + /// Fills the hanyang systems shin myeong jo medium font descryptor. + void _fillHanyangSystemsShinMyeongJoMedium( + PdfDictionary fontDescryptor, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + final PdfRectangle fontBBox = PdfRectangle(0, -148, 1001, 1028); + _fillFontBBox(fontDescryptor, fontBBox); + _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); + final PdfNumber stem = PdfNumber(93); + fontDescryptor[PdfDictionaryProperties.stemV] = stem; + fontDescryptor[PdfDictionaryProperties.stemH] = stem; + final PdfNumber width = PdfNumber(1000); + fontDescryptor[PdfDictionaryProperties.avgWidth] = width; + fontDescryptor[PdfDictionaryProperties.maxWidth] = width; + fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); + fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); + fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); + } + + /// Fills the heisei mincho w3 font descryptor. + void _fillHeiseiMinchoW3( + PdfDictionary fontDescryptor, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + final PdfRectangle fontBBox = PdfRectangle(-123, -257, 1124, 1167); + _fillFontBBox(fontDescryptor, fontBBox); + _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); + final PdfNumber stem = PdfNumber(93); + fontDescryptor[PdfDictionaryProperties.stemV] = stem; + fontDescryptor[PdfDictionaryProperties.stemH] = stem; + final PdfNumber width = PdfNumber(1000); + fontDescryptor[PdfDictionaryProperties.avgWidth] = PdfNumber(702); + fontDescryptor[PdfDictionaryProperties.maxWidth] = width; + fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(718); + fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(500); + fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); + } + + /// Fills the sino type song light font descryptor. + void _fillSinoTypeSongLight( + PdfDictionary fontDescryptor, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + final PdfRectangle fontBBox = PdfRectangle(-25, -254, 1025, 1134); + _fillFontBBox(fontDescryptor, fontBBox); + _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); + final PdfNumber stem = PdfNumber(93); + fontDescryptor[PdfDictionaryProperties.stemV] = stem; + fontDescryptor[PdfDictionaryProperties.stemH] = stem; + final PdfNumber width = PdfNumber(1000); + fontDescryptor[PdfDictionaryProperties.avgWidth] = width; + fontDescryptor[PdfDictionaryProperties.maxWidth] = width; + fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); + fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); + fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); + } + + /// Fills the monotype hei medium font descryptor. + void _fillMonotypeHeiMedium( + PdfDictionary fontDescryptor, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + final PdfRectangle fontBBox = PdfRectangle(-45, -250, 1060, 1137); + _fillFontBBox(fontDescryptor, fontBBox); + _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); + final PdfNumber stem = PdfNumber(93); + fontDescryptor[PdfDictionaryProperties.stemV] = stem; + fontDescryptor[PdfDictionaryProperties.stemH] = stem; + final PdfNumber width = PdfNumber(1000); + fontDescryptor[PdfDictionaryProperties.avgWidth] = width; + fontDescryptor[PdfDictionaryProperties.maxWidth] = width; + fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); + fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); + fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); + } + + /// Fills the hanyang systems gothic medium font descryptor. + void _fillHanyangSystemsGothicMedium( + PdfDictionary fontDescryptor, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + final PdfRectangle fontBBox = PdfRectangle(-6, -145, 1009, 1025); + _fillFontBBox(fontDescryptor, fontBBox); + _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); + fontDescryptor[PdfDictionaryProperties.flags] = PdfNumber(4); + final PdfNumber stem = PdfNumber(93); + fontDescryptor[PdfDictionaryProperties.stemV] = stem; + fontDescryptor[PdfDictionaryProperties.stemH] = stem; + final PdfNumber width = PdfNumber(1000); + fontDescryptor[PdfDictionaryProperties.avgWidth] = width; + fontDescryptor[PdfDictionaryProperties.maxWidth] = width; + fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(880); + fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(616); + fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); + } + + /// Fills the heisei kaku gothic w5 font descryptor. + void _fillHanyangSystemsGothicMediumWithStyle( + PdfDictionary fontDescryptor, + int fontStyle, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + final PdfRectangle fontBBox = PdfRectangle(-92, -250, 1102, 1175); + final PdfRectangle fontBBoxI = PdfRectangle(-92, -250, 1102, 1932); + if ((fontStyle & + (PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) | + PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold))) != + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) { + _fillFontBBox(fontDescryptor, fontBBox); + } else { + _fillFontBBox(fontDescryptor, fontBBoxI); + } + _fillKnownInfo(fontDescryptor, fontFamily, fontMetrics); + final PdfNumber stem = PdfNumber(93); + fontDescryptor[PdfDictionaryProperties.stemV] = stem; + fontDescryptor[PdfDictionaryProperties.stemH] = stem; + final PdfNumber width = PdfNumber(1000); + fontDescryptor[PdfDictionaryProperties.avgWidth] = PdfNumber(689); + fontDescryptor[PdfDictionaryProperties.maxWidth] = width; + fontDescryptor[PdfDictionaryProperties.capHeight] = PdfNumber(718); + fontDescryptor[PdfDictionaryProperties.xHeight] = PdfNumber(500); + fontDescryptor[PdfDictionaryProperties.leading] = PdfNumber(250); + } + + /// Fills the known info. + void _fillKnownInfo( + PdfDictionary fontDescryptor, + PdfCjkFontFamily? fontFamily, + PdfFontMetrics fontMetrics, + ) { + fontDescryptor[PdfDictionaryProperties.fontName] = PdfName( + fontMetrics.postScriptName, + ); + fontDescryptor[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.fontDescriptor, + ); + fontDescryptor[PdfDictionaryProperties.italicAngle] = PdfNumber(0); + fontDescryptor[PdfDictionaryProperties.missingWidth] = PdfNumber( + (fontMetrics.widthTable! as CjkWidthTable).defaultWidth, + ); + fontDescryptor[PdfDictionaryProperties.ascent] = PdfNumber( + fontMetrics.ascent, + ); + fontDescryptor[PdfDictionaryProperties.descent] = PdfNumber( + fontMetrics.descent, + ); + _fillFlags(fontDescryptor, fontFamily); + } + + /// Fills the flags. + void _fillFlags(PdfDictionary fontDescryptor, PdfCjkFontFamily? fontFamily) { + switch (fontFamily) { + case PdfCjkFontFamily.monotypeHeiMedium: + case PdfCjkFontFamily.hanyangSystemsGothicMedium: + case PdfCjkFontFamily.heiseiKakuGothicW5: + fontDescryptor[PdfDictionaryProperties.flags] = PdfNumber(4); + break; + case PdfCjkFontFamily.sinoTypeSongLight: + case PdfCjkFontFamily.monotypeSungLight: + case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: + case PdfCjkFontFamily.heiseiMinchoW3: + fontDescryptor[PdfDictionaryProperties.flags] = PdfNumber(6); + break; + // ignore: no_default_cases + default: + break; + } + } + + /// Fills the font BBox. + void _fillFontBBox(PdfDictionary fontDescryptor, PdfRectangle fontBBox) { + fontDescryptor[PdfDictionaryProperties.fontBBox] = PdfArray.fromRectangle( + fontBBox, + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font.dart index 527070d5e..85846e387 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font.dart @@ -1,235 +1,235 @@ -import '../../../interfaces/pdf_interface.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import 'enums.dart'; -import 'pdf_cid_font.dart'; -import 'pdf_cjk_standard_font_metrics_factory.dart'; -import 'pdf_font.dart'; -import 'pdf_string_format.dart'; - -/// Represents the standard CJK fonts. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'こんにちは世界', -/// PdfCjkStandardFont( -/// PdfCjkFontFamily.heiseiMinchoW3, 20), -/// brush: PdfBrushes.black); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -class PdfCjkStandardFont extends PdfFont { - //Constructors - /// Initializes a new instance of the [PdfCjkStandardFont] class - /// with font family, size and font style. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'こんにちは世界', - /// PdfCjkStandardFont( - /// PdfCjkFontFamily.heiseiMinchoW3, 20), - /// brush: PdfBrushes.black); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfCjkStandardFont( - PdfCjkFontFamily fontFamily, - double size, { - PdfFontStyle? style, - List? multiStyle, - }) { - _helper = PdfCjkStandardFontHelper(this); - PdfFontHelper.getHelper( - this, - ).initialize(size, style: style, multiStyle: multiStyle); - _fontFamily = fontFamily; - _initializeInternals(); - } - - /// Initializes a new instance of the [PdfCjkStandardFont] class - /// with [PdfCjkStandardFont] as prototype, size and font style. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Draw the text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', - /// PdfCjkStandardFont.prototype( - /// PdfCjkStandardFont(PdfCjkFontFamily.heiseiMinchoW3, 12), 12), - /// brush: PdfBrushes.black); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfCjkStandardFont.protoType( - PdfCjkStandardFont prototype, - double size, { - PdfFontStyle? style, - List? multiStyle, - }) { - _helper = PdfCjkStandardFontHelper(this); - PdfFontHelper.getHelper( - this, - ).initialize(size, style: style, multiStyle: multiStyle); - _fontFamily = prototype.fontFamily; - if (style == null && (multiStyle == null || multiStyle.isEmpty)) { - PdfFontHelper.getHelper(this).setStyle(prototype.style, null); - } - _initializeInternals(); - } - - //Fields - late PdfCjkStandardFontHelper _helper; - - /// FontFamily of the font. - PdfCjkFontFamily _fontFamily = PdfCjkFontFamily.heiseiKakuGothicW5; - - //Properties - /// Gets the font family - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create PDF cjk font. - /// PdfCjkStandardFont font = - /// PdfCjkStandardFont(PdfCjkFontFamily.heiseiMinchoW3, 12); - /// //Draw the text. - /// document.pages.add().graphics.drawString( - /// '"The CJK font family name is ${font.fontFamily}', font, - /// brush: PdfBrushes.black); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfCjkFontFamily get fontFamily => _fontFamily; - - void _initializeInternals() { - PdfFontHelper.getHelper( - this, - ).metrics = PdfCjkStandardFontMetricsFactory.getMetrics( - _fontFamily, - PdfFontHelper.getHelper(this).fontStyle, - size, - ); - PdfFontHelper.getHelper(this).fontInternals = _createInternals(); - } - - /// Creates font's dictionary. - PdfDictionary _createInternals() { - final PdfDictionary dictionary = PdfDictionary(); - - dictionary[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.font, - ); - dictionary[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.type0, - ); - dictionary[PdfDictionaryProperties.baseFont] = PdfName( - PdfFontHelper.getHelper(this).metrics!.postScriptName, - ); - - dictionary[PdfDictionaryProperties.encoding] = _getEncoding(_fontFamily); - dictionary[PdfDictionaryProperties.descendantFonts] = _getDescendantFont(); - - return dictionary; - } - - /// Gets the prope CJK encoding. - static PdfName _getEncoding(PdfCjkFontFamily? fontFamily) { - String encoding = 'Unknown'; - - switch (fontFamily) { - case PdfCjkFontFamily.hanyangSystemsGothicMedium: - case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: - encoding = 'UniKS-UCS2-H'; - break; - case PdfCjkFontFamily.heiseiKakuGothicW5: - case PdfCjkFontFamily.heiseiMinchoW3: - encoding = 'UniJIS-UCS2-H'; - break; - case PdfCjkFontFamily.monotypeHeiMedium: - case PdfCjkFontFamily.monotypeSungLight: - encoding = 'UniCNS-UCS2-H'; - break; - case PdfCjkFontFamily.sinoTypeSongLight: - encoding = 'UniGB-UCS2-H'; - break; - // ignore: no_default_cases - default: - break; - } - final PdfName name = PdfName(encoding); - return name; - } - - /// Returns descendant font. - PdfArray _getDescendantFont() { - final PdfArray df = PdfArray(); - final PdfCidFont cidFont = PdfCidFont( - _fontFamily, - PdfFontHelper.getHelper(this).fontStyle, - PdfFontHelper.getHelper(this).metrics!, - ); - df.add(cidFont); - return df; - } - - IPdfPrimitive? get _element => PdfFontHelper.getHelper(this).fontInternals; - set _element(IPdfPrimitive? value) { - PdfFontHelper.getHelper(this).fontInternals = value; - } -} - -/// [PdfCjkStandardFont] element -class PdfCjkStandardFontHelper { - /// internal constructor - PdfCjkStandardFontHelper(this.base); - - /// internal field - PdfCjkStandardFont base; - - /// internal method - static PdfCjkStandardFontHelper getHelper(PdfCjkStandardFont base) { - return base._helper; - } - - /// internal method - IPdfPrimitive? get element => base._element; - set element(IPdfPrimitive? value) { - base._element = value; - } - - /// internal method - double getLineWidth(String line, PdfStringFormat? format) { - double width = 0; - for (int i = 0; i < line.length; i++) { - final String ch = line[i]; - final double charWidth = getCharWidthInternal(ch); - width += charWidth; - } - final double size = PdfFontHelper.getHelper(base).metrics!.getSize(format)!; - width *= PdfFontHelper.characterSizeMultiplier * size; - width = PdfFontHelper.applyFormatSettings(base, line, format, width); - return width; - } - - /// Gets the char width internal. - double getCharWidthInternal(String charCode) { - int code = charCode.codeUnitAt(0); - code = (code >= 0) ? code : 0; - return PdfFontHelper.getHelper(base).metrics!.widthTable![code]!.toDouble(); - } -} +import '../../../interfaces/pdf_interface.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import 'enums.dart'; +import 'pdf_cid_font.dart'; +import 'pdf_cjk_standard_font_metrics_factory.dart'; +import 'pdf_font.dart'; +import 'pdf_string_format.dart'; + +/// Represents the standard CJK fonts. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'こんにちは世界', +/// PdfCjkStandardFont( +/// PdfCjkFontFamily.heiseiMinchoW3, 20), +/// brush: PdfBrushes.black); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +class PdfCjkStandardFont extends PdfFont { + //Constructors + /// Initializes a new instance of the [PdfCjkStandardFont] class + /// with font family, size and font style. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'こんにちは世界', + /// PdfCjkStandardFont( + /// PdfCjkFontFamily.heiseiMinchoW3, 20), + /// brush: PdfBrushes.black); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfCjkStandardFont( + PdfCjkFontFamily fontFamily, + double size, { + PdfFontStyle? style, + List? multiStyle, + }) { + _helper = PdfCjkStandardFontHelper(this); + PdfFontHelper.getHelper( + this, + ).initialize(size, style: style, multiStyle: multiStyle); + _fontFamily = fontFamily; + _initializeInternals(); + } + + /// Initializes a new instance of the [PdfCjkStandardFont] class + /// with [PdfCjkStandardFont] as prototype, size and font style. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Draw the text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', + /// PdfCjkStandardFont.prototype( + /// PdfCjkStandardFont(PdfCjkFontFamily.heiseiMinchoW3, 12), 12), + /// brush: PdfBrushes.black); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfCjkStandardFont.protoType( + PdfCjkStandardFont prototype, + double size, { + PdfFontStyle? style, + List? multiStyle, + }) { + _helper = PdfCjkStandardFontHelper(this); + PdfFontHelper.getHelper( + this, + ).initialize(size, style: style, multiStyle: multiStyle); + _fontFamily = prototype.fontFamily; + if (style == null && (multiStyle == null || multiStyle.isEmpty)) { + PdfFontHelper.getHelper(this).setStyle(prototype.style, null); + } + _initializeInternals(); + } + + //Fields + late PdfCjkStandardFontHelper _helper; + + /// FontFamily of the font. + PdfCjkFontFamily _fontFamily = PdfCjkFontFamily.heiseiKakuGothicW5; + + //Properties + /// Gets the font family + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create PDF cjk font. + /// PdfCjkStandardFont font = + /// PdfCjkStandardFont(PdfCjkFontFamily.heiseiMinchoW3, 12); + /// //Draw the text. + /// document.pages.add().graphics.drawString( + /// '"The CJK font family name is ${font.fontFamily}', font, + /// brush: PdfBrushes.black); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfCjkFontFamily get fontFamily => _fontFamily; + + void _initializeInternals() { + PdfFontHelper.getHelper( + this, + ).metrics = PdfCjkStandardFontMetricsFactory.getMetrics( + _fontFamily, + PdfFontHelper.getHelper(this).fontStyle, + size, + ); + PdfFontHelper.getHelper(this).fontInternals = _createInternals(); + } + + /// Creates font's dictionary. + PdfDictionary _createInternals() { + final PdfDictionary dictionary = PdfDictionary(); + + dictionary[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.font, + ); + dictionary[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.type0, + ); + dictionary[PdfDictionaryProperties.baseFont] = PdfName( + PdfFontHelper.getHelper(this).metrics!.postScriptName, + ); + + dictionary[PdfDictionaryProperties.encoding] = _getEncoding(_fontFamily); + dictionary[PdfDictionaryProperties.descendantFonts] = _getDescendantFont(); + + return dictionary; + } + + /// Gets the prope CJK encoding. + static PdfName _getEncoding(PdfCjkFontFamily? fontFamily) { + String encoding = 'Unknown'; + + switch (fontFamily) { + case PdfCjkFontFamily.hanyangSystemsGothicMedium: + case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: + encoding = 'UniKS-UCS2-H'; + break; + case PdfCjkFontFamily.heiseiKakuGothicW5: + case PdfCjkFontFamily.heiseiMinchoW3: + encoding = 'UniJIS-UCS2-H'; + break; + case PdfCjkFontFamily.monotypeHeiMedium: + case PdfCjkFontFamily.monotypeSungLight: + encoding = 'UniCNS-UCS2-H'; + break; + case PdfCjkFontFamily.sinoTypeSongLight: + encoding = 'UniGB-UCS2-H'; + break; + // ignore: no_default_cases + default: + break; + } + final PdfName name = PdfName(encoding); + return name; + } + + /// Returns descendant font. + PdfArray _getDescendantFont() { + final PdfArray df = PdfArray(); + final PdfCidFont cidFont = PdfCidFont( + _fontFamily, + PdfFontHelper.getHelper(this).fontStyle, + PdfFontHelper.getHelper(this).metrics!, + ); + df.add(cidFont); + return df; + } + + IPdfPrimitive? get _element => PdfFontHelper.getHelper(this).fontInternals; + set _element(IPdfPrimitive? value) { + PdfFontHelper.getHelper(this).fontInternals = value; + } +} + +/// [PdfCjkStandardFont] element +class PdfCjkStandardFontHelper { + /// internal constructor + PdfCjkStandardFontHelper(this.base); + + /// internal field + PdfCjkStandardFont base; + + /// internal method + static PdfCjkStandardFontHelper getHelper(PdfCjkStandardFont base) { + return base._helper; + } + + /// internal method + IPdfPrimitive? get element => base._element; + set element(IPdfPrimitive? value) { + base._element = value; + } + + /// internal method + double getLineWidth(String line, PdfStringFormat? format) { + double width = 0; + for (int i = 0; i < line.length; i++) { + final String ch = line[i]; + final double charWidth = getCharWidthInternal(ch); + width += charWidth; + } + final double size = PdfFontHelper.getHelper(base).metrics!.getSize(format)!; + width *= PdfFontHelper.characterSizeMultiplier * size; + width = PdfFontHelper.applyFormatSettings(base, line, format, width); + return width; + } + + /// Gets the char width internal. + double getCharWidthInternal(String charCode) { + int code = charCode.codeUnitAt(0); + code = (code >= 0) ? code : 0; + return PdfFontHelper.getHelper(base).metrics!.widthTable![code]!.toDouble(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font_metrics_factory.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font_metrics_factory.dart index 2e679d630..f9661b947 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font_metrics_factory.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_cjk_standard_font_metrics_factory.dart @@ -1,315 +1,315 @@ -import 'enums.dart'; -import 'pdf_font.dart'; -import 'pdf_font_metrics.dart'; - -/// A Class representing PDF document which is used for -/// Cjk Font Metrics Factory. -class PdfCjkStandardFontMetricsFactory { - /// internal constructor - PdfCjkStandardFontMetricsFactory(); - - /// Multiplier of subscript superscript. - static const double _subSuperscriptFactor = 1.52; - - /// Returns font metrics depending on the font settings. - static PdfFontMetrics getMetrics( - PdfCjkFontFamily? fontFamily, - int? fontStyle, - double size, - ) { - PdfFontMetrics metrics; - final PdfCjkStandardFontMetricsFactory fontfactory = - PdfCjkStandardFontMetricsFactory(); - switch (fontFamily) { - case PdfCjkFontFamily.hanyangSystemsGothicMedium: - metrics = _getHanyangSystemsGothicMediumMetrix( - fontFamily, - fontStyle!, - size, - ); - break; - - case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: - metrics = _getHanyangSystemsShinMyeongJoMediumMetrix( - fontFamily, - fontStyle!, - size, - ); - break; - - case PdfCjkFontFamily.heiseiKakuGothicW5: - metrics = _getHeiseiKakuGothicW5Metrix(fontFamily, fontStyle!, size); - break; - - case PdfCjkFontFamily.heiseiMinchoW3: - metrics = _getHeiseiMinchoW3(fontFamily, fontStyle!, size); - break; - - case PdfCjkFontFamily.monotypeHeiMedium: - metrics = _getMonotypeHeiMedium(fontFamily, fontStyle!, size); - break; - - case PdfCjkFontFamily.monotypeSungLight: - metrics = _getMonotypeSungLightMetrix(fontFamily, fontStyle!, size); - break; - - case PdfCjkFontFamily.sinoTypeSongLight: - metrics = fontfactory._getSinoTypeSongLight( - fontFamily, - fontStyle!, - size, - ); - break; - - // ignore: no_default_cases - default: - throw Exception('Unsupported font family, $fontFamily'); - } - - metrics.name = PdfFontHelper.standardCjkFontNames[fontFamily!.index]; - metrics.subscriptSizeFactor = _subSuperscriptFactor; - metrics.superscriptSizeFactor = _subSuperscriptFactor; - - return metrics; - } - - /// Gets the hanyang systems gothic medium font metrix. - static PdfFontMetrics _getHanyangSystemsGothicMediumMetrix( - PdfCjkFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final CjkWidthTable widthTable = CjkWidthTable(1000); - metrics.widthTable = widthTable; - widthTable.add(CjkSameWidth(1, 127, 500)); - widthTable.add(CjkSameWidth(8094, 8190, 500)); - - metrics.ascent = 880; - metrics.descent = -120; - metrics.size = size; - metrics.height = metrics.ascent - metrics.descent; - - if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && - (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { - metrics.postScriptName = 'HYGoThic-Medium,BoldItalic'; - } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != - 0) { - metrics.postScriptName = 'HYGoThic-Medium,Bold'; - } else if ((fontStyle & - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != - 0) { - metrics.postScriptName = 'HYGoThic-Medium,Italic'; - } else { - metrics.postScriptName = 'HYGoThic-Medium'; - } - - return metrics; - } - - /// Gets the monotype hei medium metrix. - static PdfFontMetrics _getMonotypeHeiMedium( - PdfCjkFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final CjkWidthTable widthTable = CjkWidthTable(1000); - metrics.widthTable = widthTable; - widthTable.add(CjkSameWidth(1, 95, 500)); - widthTable.add(CjkSameWidth(13648, 13742, 500)); - - metrics.ascent = 880; - metrics.descent = -120; - metrics.size = size; - metrics.height = metrics.ascent - metrics.descent; - - if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && - (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { - metrics.postScriptName = 'MHei-Medium,BoldItalic'; - } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != - 0) { - metrics.postScriptName = 'MHei-Medium,Bold'; - } else if ((fontStyle & - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != - 0) { - metrics.postScriptName = 'MHei-Medium,Italic'; - } else { - metrics.postScriptName = 'MHei-Medium'; - } - - return metrics; - } - - /// Gets the monotype sung light metrix. - static PdfFontMetrics _getMonotypeSungLightMetrix( - PdfCjkFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final CjkWidthTable widthTable = CjkWidthTable(1000); - metrics.widthTable = widthTable; - widthTable.add(CjkSameWidth(1, 95, 500)); - widthTable.add(CjkSameWidth(13648, 13742, 500)); - - metrics.ascent = 880; - metrics.descent = -120; - metrics.size = size; - metrics.height = metrics.ascent - metrics.descent; - - if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && - (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { - metrics.postScriptName = 'MSung-Light,BoldItalic'; - } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != - 0) { - metrics.postScriptName = 'MSung-Light,Bold'; - } else if ((fontStyle & - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != - 0) { - metrics.postScriptName = 'MSung-Light,Italic'; - } else { - metrics.postScriptName = 'MSung-Light'; - } - - return metrics; - } - - /// Gets the sino type song light font metrics. - PdfFontMetrics _getSinoTypeSongLight( - PdfCjkFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final CjkWidthTable widthTable = CjkWidthTable(1000); - metrics.widthTable = widthTable; - widthTable.add(CjkSameWidth(1, 95, 500)); - widthTable.add(CjkSameWidth(814, 939, 500)); - widthTable.add(CjkDifferentWidth(7712, [500])); - widthTable.add(CjkDifferentWidth(7716, [500])); - - metrics.ascent = 880; - metrics.descent = -120; - metrics.size = size; - metrics.height = metrics.ascent - metrics.descent; - - if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && - (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { - metrics.postScriptName = 'STSong-Light,BoldItalic'; - } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != - 0) { - metrics.postScriptName = 'STSong-Light,Bold'; - } else if ((fontStyle & - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != - 0) { - metrics.postScriptName = 'STSong-Light,Italic'; - } else { - metrics.postScriptName = 'STSong-Light'; - } - - return metrics; - } - - /// Gets the heisei mincho w3. - static PdfFontMetrics _getHeiseiMinchoW3( - PdfCjkFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final CjkWidthTable widthTable = CjkWidthTable(1000); - metrics.widthTable = widthTable; - widthTable.add(CjkSameWidth(1, 95, 500)); - widthTable.add(CjkSameWidth(231, 632, 500)); - - metrics.ascent = 857; - metrics.descent = -143; - metrics.size = size; - metrics.height = metrics.ascent - metrics.descent; - - if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && - (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { - metrics.postScriptName = 'HeiseiMin-W3,BoldItalic'; - } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != - 0) { - metrics.postScriptName = 'HeiseiMin-W3,Bold'; - } else if ((fontStyle & - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != - 0) { - metrics.postScriptName = 'HeiseiMin-W3,Italic'; - } else { - metrics.postScriptName = 'HeiseiMin-W3'; - } - - return metrics; - } - - /// Gets the heisei kaku gothic w5 metrix. - static PdfFontMetrics _getHeiseiKakuGothicW5Metrix( - PdfCjkFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final CjkWidthTable widthTable = CjkWidthTable(1000); - metrics.widthTable = widthTable; - widthTable.add(CjkSameWidth(1, 95, 500)); - widthTable.add(CjkSameWidth(231, 632, 500)); - - metrics.ascent = 857; - metrics.descent = -125; - metrics.size = size; - metrics.height = metrics.ascent - metrics.descent; - - if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && - (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { - metrics.postScriptName = 'HeiseiKakuGo-W5,BoldItalic'; - } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != - 0) { - metrics.postScriptName = 'HeiseiKakuGo-W5,Bold'; - } else if ((fontStyle & - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != - 0) { - metrics.postScriptName = 'HeiseiKakuGo-W5,Italic'; - } else { - metrics.postScriptName = 'HeiseiKakuGo-W5'; - } - - return metrics; - } - - /// Gets the hanyang systems shin myeong jo medium metrix. - static PdfFontMetrics _getHanyangSystemsShinMyeongJoMediumMetrix( - PdfCjkFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final CjkWidthTable widthTable = CjkWidthTable(1000); - metrics.widthTable = widthTable; - widthTable.add(CjkSameWidth(1, 95, 500)); - widthTable.add(CjkSameWidth(8094, 8190, 500)); - - metrics.ascent = 880; - metrics.descent = -120; - metrics.size = size; - metrics.height = metrics.ascent - metrics.descent; - - if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && - (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { - metrics.postScriptName = 'HYSMyeongJo-Medium,BoldItalic'; - } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != - 0) { - metrics.postScriptName = 'HYSMyeongJo-Medium,Bold'; - } else if ((fontStyle & - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != - 0) { - metrics.postScriptName = 'HYSMyeongJo-Medium,Italic'; - } else { - metrics.postScriptName = 'HYSMyeongJo-Medium'; - } - - return metrics; - } -} +import 'enums.dart'; +import 'pdf_font.dart'; +import 'pdf_font_metrics.dart'; + +/// A Class representing PDF document which is used for +/// Cjk Font Metrics Factory. +class PdfCjkStandardFontMetricsFactory { + /// internal constructor + PdfCjkStandardFontMetricsFactory(); + + /// Multiplier of subscript superscript. + static const double _subSuperscriptFactor = 1.52; + + /// Returns font metrics depending on the font settings. + static PdfFontMetrics getMetrics( + PdfCjkFontFamily? fontFamily, + int? fontStyle, + double size, + ) { + PdfFontMetrics metrics; + final PdfCjkStandardFontMetricsFactory fontfactory = + PdfCjkStandardFontMetricsFactory(); + switch (fontFamily) { + case PdfCjkFontFamily.hanyangSystemsGothicMedium: + metrics = _getHanyangSystemsGothicMediumMetrix( + fontFamily, + fontStyle!, + size, + ); + break; + + case PdfCjkFontFamily.hanyangSystemsShinMyeongJoMedium: + metrics = _getHanyangSystemsShinMyeongJoMediumMetrix( + fontFamily, + fontStyle!, + size, + ); + break; + + case PdfCjkFontFamily.heiseiKakuGothicW5: + metrics = _getHeiseiKakuGothicW5Metrix(fontFamily, fontStyle!, size); + break; + + case PdfCjkFontFamily.heiseiMinchoW3: + metrics = _getHeiseiMinchoW3(fontFamily, fontStyle!, size); + break; + + case PdfCjkFontFamily.monotypeHeiMedium: + metrics = _getMonotypeHeiMedium(fontFamily, fontStyle!, size); + break; + + case PdfCjkFontFamily.monotypeSungLight: + metrics = _getMonotypeSungLightMetrix(fontFamily, fontStyle!, size); + break; + + case PdfCjkFontFamily.sinoTypeSongLight: + metrics = fontfactory._getSinoTypeSongLight( + fontFamily, + fontStyle!, + size, + ); + break; + + // ignore: no_default_cases + default: + throw Exception('Unsupported font family, $fontFamily'); + } + + metrics.name = PdfFontHelper.standardCjkFontNames[fontFamily!.index]; + metrics.subscriptSizeFactor = _subSuperscriptFactor; + metrics.superscriptSizeFactor = _subSuperscriptFactor; + + return metrics; + } + + /// Gets the hanyang systems gothic medium font metrix. + static PdfFontMetrics _getHanyangSystemsGothicMediumMetrix( + PdfCjkFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final CjkWidthTable widthTable = CjkWidthTable(1000); + metrics.widthTable = widthTable; + widthTable.add(CjkSameWidth(1, 127, 500)); + widthTable.add(CjkSameWidth(8094, 8190, 500)); + + metrics.ascent = 880; + metrics.descent = -120; + metrics.size = size; + metrics.height = metrics.ascent - metrics.descent; + + if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && + (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { + metrics.postScriptName = 'HYGoThic-Medium,BoldItalic'; + } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != + 0) { + metrics.postScriptName = 'HYGoThic-Medium,Bold'; + } else if ((fontStyle & + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != + 0) { + metrics.postScriptName = 'HYGoThic-Medium,Italic'; + } else { + metrics.postScriptName = 'HYGoThic-Medium'; + } + + return metrics; + } + + /// Gets the monotype hei medium metrix. + static PdfFontMetrics _getMonotypeHeiMedium( + PdfCjkFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final CjkWidthTable widthTable = CjkWidthTable(1000); + metrics.widthTable = widthTable; + widthTable.add(CjkSameWidth(1, 95, 500)); + widthTable.add(CjkSameWidth(13648, 13742, 500)); + + metrics.ascent = 880; + metrics.descent = -120; + metrics.size = size; + metrics.height = metrics.ascent - metrics.descent; + + if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && + (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { + metrics.postScriptName = 'MHei-Medium,BoldItalic'; + } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != + 0) { + metrics.postScriptName = 'MHei-Medium,Bold'; + } else if ((fontStyle & + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != + 0) { + metrics.postScriptName = 'MHei-Medium,Italic'; + } else { + metrics.postScriptName = 'MHei-Medium'; + } + + return metrics; + } + + /// Gets the monotype sung light metrix. + static PdfFontMetrics _getMonotypeSungLightMetrix( + PdfCjkFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final CjkWidthTable widthTable = CjkWidthTable(1000); + metrics.widthTable = widthTable; + widthTable.add(CjkSameWidth(1, 95, 500)); + widthTable.add(CjkSameWidth(13648, 13742, 500)); + + metrics.ascent = 880; + metrics.descent = -120; + metrics.size = size; + metrics.height = metrics.ascent - metrics.descent; + + if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && + (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { + metrics.postScriptName = 'MSung-Light,BoldItalic'; + } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != + 0) { + metrics.postScriptName = 'MSung-Light,Bold'; + } else if ((fontStyle & + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != + 0) { + metrics.postScriptName = 'MSung-Light,Italic'; + } else { + metrics.postScriptName = 'MSung-Light'; + } + + return metrics; + } + + /// Gets the sino type song light font metrics. + PdfFontMetrics _getSinoTypeSongLight( + PdfCjkFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final CjkWidthTable widthTable = CjkWidthTable(1000); + metrics.widthTable = widthTable; + widthTable.add(CjkSameWidth(1, 95, 500)); + widthTable.add(CjkSameWidth(814, 939, 500)); + widthTable.add(CjkDifferentWidth(7712, [500])); + widthTable.add(CjkDifferentWidth(7716, [500])); + + metrics.ascent = 880; + metrics.descent = -120; + metrics.size = size; + metrics.height = metrics.ascent - metrics.descent; + + if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && + (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { + metrics.postScriptName = 'STSong-Light,BoldItalic'; + } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != + 0) { + metrics.postScriptName = 'STSong-Light,Bold'; + } else if ((fontStyle & + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != + 0) { + metrics.postScriptName = 'STSong-Light,Italic'; + } else { + metrics.postScriptName = 'STSong-Light'; + } + + return metrics; + } + + /// Gets the heisei mincho w3. + static PdfFontMetrics _getHeiseiMinchoW3( + PdfCjkFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final CjkWidthTable widthTable = CjkWidthTable(1000); + metrics.widthTable = widthTable; + widthTable.add(CjkSameWidth(1, 95, 500)); + widthTable.add(CjkSameWidth(231, 632, 500)); + + metrics.ascent = 857; + metrics.descent = -143; + metrics.size = size; + metrics.height = metrics.ascent - metrics.descent; + + if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && + (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { + metrics.postScriptName = 'HeiseiMin-W3,BoldItalic'; + } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != + 0) { + metrics.postScriptName = 'HeiseiMin-W3,Bold'; + } else if ((fontStyle & + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != + 0) { + metrics.postScriptName = 'HeiseiMin-W3,Italic'; + } else { + metrics.postScriptName = 'HeiseiMin-W3'; + } + + return metrics; + } + + /// Gets the heisei kaku gothic w5 metrix. + static PdfFontMetrics _getHeiseiKakuGothicW5Metrix( + PdfCjkFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final CjkWidthTable widthTable = CjkWidthTable(1000); + metrics.widthTable = widthTable; + widthTable.add(CjkSameWidth(1, 95, 500)); + widthTable.add(CjkSameWidth(231, 632, 500)); + + metrics.ascent = 857; + metrics.descent = -125; + metrics.size = size; + metrics.height = metrics.ascent - metrics.descent; + + if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && + (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { + metrics.postScriptName = 'HeiseiKakuGo-W5,BoldItalic'; + } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != + 0) { + metrics.postScriptName = 'HeiseiKakuGo-W5,Bold'; + } else if ((fontStyle & + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != + 0) { + metrics.postScriptName = 'HeiseiKakuGo-W5,Italic'; + } else { + metrics.postScriptName = 'HeiseiKakuGo-W5'; + } + + return metrics; + } + + /// Gets the hanyang systems shin myeong jo medium metrix. + static PdfFontMetrics _getHanyangSystemsShinMyeongJoMediumMetrix( + PdfCjkFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final CjkWidthTable widthTable = CjkWidthTable(1000); + metrics.widthTable = widthTable; + widthTable.add(CjkSameWidth(1, 95, 500)); + widthTable.add(CjkSameWidth(8094, 8190, 500)); + + metrics.ascent = 880; + metrics.descent = -120; + metrics.size = size; + metrics.height = metrics.ascent - metrics.descent; + + if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != 0 && + (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != 0) { + metrics.postScriptName = 'HYSMyeongJo-Medium,BoldItalic'; + } else if ((fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold)) != + 0) { + metrics.postScriptName = 'HYSMyeongJo-Medium,Bold'; + } else if ((fontStyle & + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)) != + 0) { + metrics.postScriptName = 'HYSMyeongJo-Medium,Italic'; + } else { + metrics.postScriptName = 'HYSMyeongJo-Medium'; + } + + return metrics; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font.dart index 0ef21dca3..1178ad7e8 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font.dart @@ -1,319 +1,319 @@ -import 'dart:ui'; - -import '../../../interfaces/pdf_interface.dart'; -import 'enums.dart'; -import 'pdf_cjk_standard_font.dart'; -import 'pdf_font_metrics.dart'; -import 'pdf_standard_font.dart'; -import 'pdf_string_format.dart'; -import 'pdf_string_layout_result.dart'; -import 'pdf_string_layouter.dart'; -import 'pdf_true_type_font.dart'; -import 'string_tokenizer.dart'; - -/// Defines a particular format for text, including font face, size, -/// and style attributes. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString('Hello World!', -/// PdfStandardFont(PdfFontFamily.helvetica, 12), -/// brush: PdfBrushes.black); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -abstract class PdfFont implements IPdfWrapper { - final PdfFontHelper _helper = PdfFontHelper(); - - //Properties - /// Gets style of the font. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF font instance. - /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); - /// //Draw string to PDF page. - /// document.pages.add().graphics.drawString( - /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', - /// font); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfFontStyle get style => _helper.style; - - /// Gets the font name. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF font instance. - /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); - /// //Draw string to PDF page. - /// document.pages.add().graphics.drawString( - /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', - /// font); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - String get name => _helper.metrics!.name; - - /// Gets the font size. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF font instance. - /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); - /// //Draw string to PDF page. - /// document.pages.add().graphics.drawString( - /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', - /// font); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - double get size => _helper.size; - - /// Gets the height of the font in points. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF font instance. - /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); - /// //Draw string to PDF page. - /// document.pages.add().graphics.drawString( - /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', - /// font); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - double get height => _helper.metrics!.getHeight(null); - - //Public methods - /// Measures a string by using this font. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Add a page to the document. - /// PdfPage page = document.pages.add(); - /// //Create PDF graphics for the page. - /// PdfGraphics graphics = page.graphics; - /// //Create a new PDF font instance. - /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); - /// String text = "Hello World!"; - /// //Measure the text. - /// Size size = font.measureString(text); - /// //Draw string to PDF page. - /// graphics.drawString(text, font, - /// brush: PdfBrushes.black, - /// bounds: Rect.fromLTWH(0, 0, size.width, size.height)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Size measureString(String text, {Size? layoutArea, PdfStringFormat? format}) { - layoutArea ??= Size.zero; - final PdfStringLayouter layouter = PdfStringLayouter(); - final PdfStringLayoutResult result = layouter.layout( - text, - this, - format, - width: layoutArea.width, - height: layoutArea.height, - ); - return result.size.size; - } - - //Implementation - - /// Returns width of the line. - double _getLineWidth(String line, PdfStringFormat? format); - - /// Applies settings to the default line width. - double _applyFormatSettings( - String line, - PdfStringFormat? format, - double width, - ) { - double realWidth = width; - if (format != null && width > 0) { - if (format.characterSpacing != 0) { - realWidth += (line.length - 1) * format.characterSpacing; - } - if (format.wordSpacing != 0) { - final int whitespacesCount = StringTokenizer.getCharacterCount( - line, - StringTokenizer.spaces, - ); - realWidth += whitespacesCount * format.wordSpacing; - } - } - return realWidth; - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfFont] helper -class PdfFontHelper { - /// internal method - static PdfFontHelper getHelper(PdfFont font) { - return font._helper; - } - - /// internal field - static const double characterSizeMultiplier = 0.001; - - /// internal field - static const List standardFontNames = [ - 'Helvetica', - 'courier', - 'TimesRoman', - 'Symbol', - 'ZapfDingbats', - ]; - - /// internal field - static const List standardCjkFontNames = [ - 'HanyangSystemsGothicMedium', - 'HanyangSystemsShinMyeongJoMedium', - 'HeiseiKakuGothicW5', - 'HeiseiMinchoW3', - 'MonotypeHeiMedium', - 'MonotypeSungLight', - 'SinoTypeSongLight', - ]; - - /// internal field - late double size; - - /// internal field - PdfFontMetrics? metrics; - - /// internal field - IPdfPrimitive? fontInternals; - - /// internal field - int fontStyle = 0; - - /// internal field - PdfFontStyle style = PdfFontStyle.regular; - - /// internal field - bool isBold = false; - - /// internal field - bool isItalic = false; - - /// internal field - //ignore:unused_element - bool get isUnderline => - fontStyle & getPdfFontStyle(PdfFontStyle.underline) > 0; - - /// internal field - //ignore:unused_element - bool get isStrikeout => - fontStyle & getPdfFontStyle(PdfFontStyle.strikethrough) > 0; - - /// Initializes a new instance of the [PdfFont] class - /// with font size and style. - void initialize( - double size, { - PdfFontStyle? style, - List? multiStyle, - }) { - setSize(size); - setStyle(style, multiStyle); - } - - ///Sets the font size. - void setSize(double value) { - if (metrics != null) { - metrics!.size = value; - } - size = value; - } - - ///Sets the style. - void setStyle(PdfFontStyle? style, List? multiStyle) { - if (style != null) { - this.style = style; - fontStyle = getPdfFontStyle(style); - if (style == PdfFontStyle.bold) { - isBold = true; - } else if (style == PdfFontStyle.italic) { - isItalic = true; - } - } - if (multiStyle != null && multiStyle.isNotEmpty) { - for (int i = 0; i < multiStyle.length; i++) { - fontStyle = fontStyle | getPdfFontStyle(multiStyle[i]); - if (multiStyle[i] == PdfFontStyle.bold) { - isBold = true; - } else if (multiStyle[i] == PdfFontStyle.italic) { - isItalic = true; - } - } - } else if (style == null) { - this.style = PdfFontStyle.regular; - } - } - - /// internal method - /// Gets the value for PdfFontStyle. - static int getPdfFontStyle(PdfFontStyle value) { - switch (value) { - case PdfFontStyle.bold: - return 1; - case PdfFontStyle.italic: - return 2; - case PdfFontStyle.underline: - return 4; - case PdfFontStyle.strikethrough: - return 8; - case PdfFontStyle.regular: - return 0; - } - } - - /// internal method - static double getLineWidth( - PdfFont font, - String line, - PdfStringFormat? format, - ) { - if (font is PdfCjkStandardFont) { - return PdfCjkStandardFontHelper.getHelper( - font, - ).getLineWidth(line, format); - } else if (font is PdfStandardFont) { - return PdfStandardFontHelper.getHelper(font).getLineWidth(line, format); - } else if (font is PdfTrueTypeFont) { - return PdfTrueTypeFontHelper.getHelper(font).getLineWidth(line, format); - } - return font._getLineWidth(line, format); - } - - /// internal method - static double applyFormatSettings( - PdfFont font, - String line, - PdfStringFormat? format, - double width, - ) { - return font._applyFormatSettings(line, format, width); - } -} +import 'dart:ui'; + +import '../../../interfaces/pdf_interface.dart'; +import 'enums.dart'; +import 'pdf_cjk_standard_font.dart'; +import 'pdf_font_metrics.dart'; +import 'pdf_standard_font.dart'; +import 'pdf_string_format.dart'; +import 'pdf_string_layout_result.dart'; +import 'pdf_string_layouter.dart'; +import 'pdf_true_type_font.dart'; +import 'string_tokenizer.dart'; + +/// Defines a particular format for text, including font face, size, +/// and style attributes. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString('Hello World!', +/// PdfStandardFont(PdfFontFamily.helvetica, 12), +/// brush: PdfBrushes.black); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +abstract class PdfFont implements IPdfWrapper { + final PdfFontHelper _helper = PdfFontHelper(); + + //Properties + /// Gets style of the font. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF font instance. + /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); + /// //Draw string to PDF page. + /// document.pages.add().graphics.drawString( + /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', + /// font); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfFontStyle get style => _helper.style; + + /// Gets the font name. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF font instance. + /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); + /// //Draw string to PDF page. + /// document.pages.add().graphics.drawString( + /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', + /// font); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + String get name => _helper.metrics!.name; + + /// Gets the font size. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF font instance. + /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); + /// //Draw string to PDF page. + /// document.pages.add().graphics.drawString( + /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', + /// font); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + double get size => _helper.size; + + /// Gets the height of the font in points. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF font instance. + /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); + /// //Draw string to PDF page. + /// document.pages.add().graphics.drawString( + /// 'Font Name: ${font.name}\nFont Size: ${font.size}\nFont Height: ${font.height}\nFont Style: ${font.style}', + /// font); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + double get height => _helper.metrics!.getHeight(null); + + //Public methods + /// Measures a string by using this font. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Add a page to the document. + /// PdfPage page = document.pages.add(); + /// //Create PDF graphics for the page. + /// PdfGraphics graphics = page.graphics; + /// //Create a new PDF font instance. + /// PdfFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); + /// String text = "Hello World!"; + /// //Measure the text. + /// Size size = font.measureString(text); + /// //Draw string to PDF page. + /// graphics.drawString(text, font, + /// brush: PdfBrushes.black, + /// bounds: Rect.fromLTWH(0, 0, size.width, size.height)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Size measureString(String text, {Size? layoutArea, PdfStringFormat? format}) { + layoutArea ??= Size.zero; + final PdfStringLayouter layouter = PdfStringLayouter(); + final PdfStringLayoutResult result = layouter.layout( + text, + this, + format, + width: layoutArea.width, + height: layoutArea.height, + ); + return result.size.size; + } + + //Implementation + + /// Returns width of the line. + double _getLineWidth(String line, PdfStringFormat? format); + + /// Applies settings to the default line width. + double _applyFormatSettings( + String line, + PdfStringFormat? format, + double width, + ) { + double realWidth = width; + if (format != null && width > 0) { + if (format.characterSpacing != 0) { + realWidth += (line.length - 1) * format.characterSpacing; + } + if (format.wordSpacing != 0) { + final int whitespacesCount = StringTokenizer.getCharacterCount( + line, + StringTokenizer.spaces, + ); + realWidth += whitespacesCount * format.wordSpacing; + } + } + return realWidth; + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfFont] helper +class PdfFontHelper { + /// internal method + static PdfFontHelper getHelper(PdfFont font) { + return font._helper; + } + + /// internal field + static const double characterSizeMultiplier = 0.001; + + /// internal field + static const List standardFontNames = [ + 'Helvetica', + 'courier', + 'TimesRoman', + 'Symbol', + 'ZapfDingbats', + ]; + + /// internal field + static const List standardCjkFontNames = [ + 'HanyangSystemsGothicMedium', + 'HanyangSystemsShinMyeongJoMedium', + 'HeiseiKakuGothicW5', + 'HeiseiMinchoW3', + 'MonotypeHeiMedium', + 'MonotypeSungLight', + 'SinoTypeSongLight', + ]; + + /// internal field + late double size; + + /// internal field + PdfFontMetrics? metrics; + + /// internal field + IPdfPrimitive? fontInternals; + + /// internal field + int fontStyle = 0; + + /// internal field + PdfFontStyle style = PdfFontStyle.regular; + + /// internal field + bool isBold = false; + + /// internal field + bool isItalic = false; + + /// internal field + //ignore:unused_element + bool get isUnderline => + fontStyle & getPdfFontStyle(PdfFontStyle.underline) > 0; + + /// internal field + //ignore:unused_element + bool get isStrikeout => + fontStyle & getPdfFontStyle(PdfFontStyle.strikethrough) > 0; + + /// Initializes a new instance of the [PdfFont] class + /// with font size and style. + void initialize( + double size, { + PdfFontStyle? style, + List? multiStyle, + }) { + setSize(size); + setStyle(style, multiStyle); + } + + ///Sets the font size. + void setSize(double value) { + if (metrics != null) { + metrics!.size = value; + } + size = value; + } + + ///Sets the style. + void setStyle(PdfFontStyle? style, List? multiStyle) { + if (style != null) { + this.style = style; + fontStyle = getPdfFontStyle(style); + if (style == PdfFontStyle.bold) { + isBold = true; + } else if (style == PdfFontStyle.italic) { + isItalic = true; + } + } + if (multiStyle != null && multiStyle.isNotEmpty) { + for (int i = 0; i < multiStyle.length; i++) { + fontStyle = fontStyle | getPdfFontStyle(multiStyle[i]); + if (multiStyle[i] == PdfFontStyle.bold) { + isBold = true; + } else if (multiStyle[i] == PdfFontStyle.italic) { + isItalic = true; + } + } + } else if (style == null) { + this.style = PdfFontStyle.regular; + } + } + + /// internal method + /// Gets the value for PdfFontStyle. + static int getPdfFontStyle(PdfFontStyle value) { + switch (value) { + case PdfFontStyle.bold: + return 1; + case PdfFontStyle.italic: + return 2; + case PdfFontStyle.underline: + return 4; + case PdfFontStyle.strikethrough: + return 8; + case PdfFontStyle.regular: + return 0; + } + } + + /// internal method + static double getLineWidth( + PdfFont font, + String line, + PdfStringFormat? format, + ) { + if (font is PdfCjkStandardFont) { + return PdfCjkStandardFontHelper.getHelper( + font, + ).getLineWidth(line, format); + } else if (font is PdfStandardFont) { + return PdfStandardFontHelper.getHelper(font).getLineWidth(line, format); + } else if (font is PdfTrueTypeFont) { + return PdfTrueTypeFontHelper.getHelper(font).getLineWidth(line, format); + } + return font._getLineWidth(line, format); + } + + /// internal method + static double applyFormatSettings( + PdfFont font, + String line, + PdfStringFormat? format, + double width, + ) { + return font._applyFormatSettings(line, format, width); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font_metrics.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font_metrics.dart index 9af8c2c3e..0fddb2f1e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font_metrics.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_font_metrics.dart @@ -1,255 +1,255 @@ -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_number.dart'; -import 'enums.dart'; -import 'pdf_font.dart'; -import 'pdf_string_format.dart'; - -/// Metrics of the font. -class PdfFontMetrics { - //Fields - /// Gets ascent of the font. - double ascent = 0; - - /// Gets descent of the font. - double descent = 0; - - /// Gets name of the font. - String name = ''; - - /// Gets PostScript Name of the font. - String? postScriptName; - - /// Gets size of the font. - double size = 0; - - /// Gets height of the font. - double height = 0; - - /// Gets a first character of the font. - int firstChar = 0; - - /// Gets a last character of the font. - int lastChar = 0; - - /// Gets line gap of the font. - int lineGap = 0; - - /// Subscript size factor. - double? subscriptSizeFactor = 0; - - /// Superscript size factor. - double? superscriptSizeFactor; - - /// internal field - WidthTable? widthTable; - - /// Indicate whether the true type font reader font has bold style. - bool? isBold; - - //Implementation - /// Calculates size of the font depending on the subscript/superscript value. - double? getSize([PdfStringFormat? format]) { - double? sizeValue = size; - if (format != null) { - switch (format.subSuperscript) { - case PdfSubSuperscript.subscript: - sizeValue = sizeValue / 1.5; - break; - case PdfSubSuperscript.superscript: - sizeValue = sizeValue / 1.5; - break; - // ignore: no_default_cases - default: - break; - } - } - return sizeValue; - } - - /// Returns height taking into consideration font's size. - double getHeight(PdfStringFormat? format) { - return getDescent(format) < 0 - ? (getAscent(format) - getDescent(format) + _getLineGap(format)) - : (getAscent(format) + getDescent(format) + _getLineGap(format)); - } - - /// Returns descent taking into consideration font's size. - double getDescent(PdfStringFormat? format) { - return descent * PdfFontHelper.characterSizeMultiplier * getSize(format)!; - } - - /// Returns ascent taking into consideration font's size. - double getAscent(PdfStringFormat? format) { - return ascent * PdfFontHelper.characterSizeMultiplier * getSize(format)!; - } - - /// Returns Line gap taking into consideration font's size. - double _getLineGap(PdfStringFormat? format) { - return lineGap * PdfFontHelper.characterSizeMultiplier * getSize(format)!; - } -} - -/// The base class for a width table. -abstract class WidthTable { - /// internal property - int? operator [](int index); - - /// Toes the array. - PdfArray toArray(); -} - -/// Implements a width table for standard fonts. -class StandardWidthTable extends WidthTable { - //Constructor - /// internal constructor - StandardWidthTable(List widths) : super() { - _widths = widths; - } - // Fields - List? _widths; - //Properties - @override - int? operator [](int index) => _returnValue(index); - int? _returnValue(int index) { - if (index < 0 || index >= _widths!.length) { - throw ArgumentError.value( - index, - 'The character is not supported by the font.', - ); - } - return _widths![index]; - } - - @override - PdfArray toArray() { - final PdfArray arr = PdfArray(_widths); - return arr; - } -} - -/// internal class -class CjkWidthTable extends WidthTable { - /// Initializes a new instance of the [CjkWidthTable] class. - CjkWidthTable(this.defaultWidth) { - width = []; - } - - /// Local variable to store the width. - late List width; - - /// Local variable to store the default width. - int defaultWidth; - - @override - int operator [](int index) { - int newWidth = defaultWidth; - for (final CjkWidth widths in width) { - if (index >= widths.from && index <= widths.to) { - newWidth = widths[index]; - } - } - return newWidth; - } - - /// internal method - void add(CjkWidth widths) { - width.add(widths); - } - - @override - PdfArray toArray() { - final PdfArray arr = PdfArray(); - for (final CjkWidth widths in width) { - widths.appendToArray(arr); - } - return arr; - } -} - -/// The base class of CJK widths types. -abstract class CjkWidth { - /// Gets the starting character. - int get from; - - /// Gets the ending character. - int get to; - - /// Gets the width of the specified character. - int operator [](int index); - - /// Appends internal data to a PDF array. - void appendToArray(PdfArray arr); -} - -/// Implements capabilities to control a range of character with the same width. -class CjkSameWidth extends CjkWidth { - /// internal constructor - CjkSameWidth(this.from, this.to, this.width) { - if (from > to) { - throw ArgumentError("'From' can't be grater than 'to'."); - } - } - - /// The Form - @override - int from; - - /// The to - @override - int to; - - /// The Width - int width; - - @override - int operator [](int index) { - if (index < from || index > to) { - throw RangeError('$index, Index is out of range.'); - } - return width; - } - - @override - void appendToArray(PdfArray arr) { - arr.add(PdfNumber(from)); - arr.add(PdfNumber(to)); - arr.add(PdfNumber(width)); - } -} - -/// Implements capabilities to control a sequent range of characters -/// with different width. -class CjkDifferentWidth extends CjkWidth { - /// internal constructor - CjkDifferentWidth(this.from, this.width); - - /// The form - @override - late int from; - - /// The width - late List width; - - /// Gets the ending character. - @override - int get to { - final int value = from + width.length - 1; - return value; - } - - @override - int operator [](int index) { - if (index < from || index > to) { - throw RangeError('$index, Index is out of range.'); - } - final int newWidth = width[index - from]; - return newWidth; - } - - @override - void appendToArray(PdfArray arr) { - arr.add(PdfNumber(from)); - final PdfArray widths = PdfArray(width); - arr.add(widths); - } -} +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_number.dart'; +import 'enums.dart'; +import 'pdf_font.dart'; +import 'pdf_string_format.dart'; + +/// Metrics of the font. +class PdfFontMetrics { + //Fields + /// Gets ascent of the font. + double ascent = 0; + + /// Gets descent of the font. + double descent = 0; + + /// Gets name of the font. + String name = ''; + + /// Gets PostScript Name of the font. + String? postScriptName; + + /// Gets size of the font. + double size = 0; + + /// Gets height of the font. + double height = 0; + + /// Gets a first character of the font. + int firstChar = 0; + + /// Gets a last character of the font. + int lastChar = 0; + + /// Gets line gap of the font. + int lineGap = 0; + + /// Subscript size factor. + double? subscriptSizeFactor = 0; + + /// Superscript size factor. + double? superscriptSizeFactor; + + /// internal field + WidthTable? widthTable; + + /// Indicate whether the true type font reader font has bold style. + bool? isBold; + + //Implementation + /// Calculates size of the font depending on the subscript/superscript value. + double? getSize([PdfStringFormat? format]) { + double? sizeValue = size; + if (format != null) { + switch (format.subSuperscript) { + case PdfSubSuperscript.subscript: + sizeValue = sizeValue / 1.5; + break; + case PdfSubSuperscript.superscript: + sizeValue = sizeValue / 1.5; + break; + // ignore: no_default_cases + default: + break; + } + } + return sizeValue; + } + + /// Returns height taking into consideration font's size. + double getHeight(PdfStringFormat? format) { + return getDescent(format) < 0 + ? (getAscent(format) - getDescent(format) + _getLineGap(format)) + : (getAscent(format) + getDescent(format) + _getLineGap(format)); + } + + /// Returns descent taking into consideration font's size. + double getDescent(PdfStringFormat? format) { + return descent * PdfFontHelper.characterSizeMultiplier * getSize(format)!; + } + + /// Returns ascent taking into consideration font's size. + double getAscent(PdfStringFormat? format) { + return ascent * PdfFontHelper.characterSizeMultiplier * getSize(format)!; + } + + /// Returns Line gap taking into consideration font's size. + double _getLineGap(PdfStringFormat? format) { + return lineGap * PdfFontHelper.characterSizeMultiplier * getSize(format)!; + } +} + +/// The base class for a width table. +abstract class WidthTable { + /// internal property + int? operator [](int index); + + /// Toes the array. + PdfArray toArray(); +} + +/// Implements a width table for standard fonts. +class StandardWidthTable extends WidthTable { + //Constructor + /// internal constructor + StandardWidthTable(List widths) : super() { + _widths = widths; + } + // Fields + List? _widths; + //Properties + @override + int? operator [](int index) => _returnValue(index); + int? _returnValue(int index) { + if (index < 0 || index >= _widths!.length) { + throw ArgumentError.value( + index, + 'The character is not supported by the font.', + ); + } + return _widths![index]; + } + + @override + PdfArray toArray() { + final PdfArray arr = PdfArray(_widths); + return arr; + } +} + +/// internal class +class CjkWidthTable extends WidthTable { + /// Initializes a new instance of the [CjkWidthTable] class. + CjkWidthTable(this.defaultWidth) { + width = []; + } + + /// Local variable to store the width. + late List width; + + /// Local variable to store the default width. + int defaultWidth; + + @override + int operator [](int index) { + int newWidth = defaultWidth; + for (final CjkWidth widths in width) { + if (index >= widths.from && index <= widths.to) { + newWidth = widths[index]; + } + } + return newWidth; + } + + /// internal method + void add(CjkWidth widths) { + width.add(widths); + } + + @override + PdfArray toArray() { + final PdfArray arr = PdfArray(); + for (final CjkWidth widths in width) { + widths.appendToArray(arr); + } + return arr; + } +} + +/// The base class of CJK widths types. +abstract class CjkWidth { + /// Gets the starting character. + int get from; + + /// Gets the ending character. + int get to; + + /// Gets the width of the specified character. + int operator [](int index); + + /// Appends internal data to a PDF array. + void appendToArray(PdfArray arr); +} + +/// Implements capabilities to control a range of character with the same width. +class CjkSameWidth extends CjkWidth { + /// internal constructor + CjkSameWidth(this.from, this.to, this.width) { + if (from > to) { + throw ArgumentError("'From' can't be grater than 'to'."); + } + } + + /// The Form + @override + int from; + + /// The to + @override + int to; + + /// The Width + int width; + + @override + int operator [](int index) { + if (index < from || index > to) { + throw RangeError('$index, Index is out of range.'); + } + return width; + } + + @override + void appendToArray(PdfArray arr) { + arr.add(PdfNumber(from)); + arr.add(PdfNumber(to)); + arr.add(PdfNumber(width)); + } +} + +/// Implements capabilities to control a sequent range of characters +/// with different width. +class CjkDifferentWidth extends CjkWidth { + /// internal constructor + CjkDifferentWidth(this.from, this.width); + + /// The form + @override + late int from; + + /// The width + late List width; + + /// Gets the ending character. + @override + int get to { + final int value = from + width.length - 1; + return value; + } + + @override + int operator [](int index) { + if (index < from || index > to) { + throw RangeError('$index, Index is out of range.'); + } + final int newWidth = width[index - from]; + return newWidth; + } + + @override + void appendToArray(PdfArray arr) { + arr.add(PdfNumber(from)); + final PdfArray widths = PdfArray(width); + arr.add(widths); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font.dart index 345a92bb2..88a1af933 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font.dart @@ -1,477 +1,477 @@ -import '../../../interfaces/pdf_interface.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import 'enums.dart'; -import 'pdf_font.dart'; -import 'pdf_standard_font_metrics_factory.dart'; -import 'pdf_string_format.dart'; - -/// Represents one of the 14 standard PDF fonts. -/// It's used to create a standard PDF font to draw the text in to the PDF -/// -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// brush: PdfBrushes.black); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -class PdfStandardFont extends PdfFont { - //Constructors - /// Initializes a new instance of the [PdfStandardFont] class - /// with font family, size and font style. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfStandardFont( - PdfFontFamily fontFamily, - double size, { - PdfFontStyle? style, - List? multiStyle, - }) { - _helper = PdfStandardFontHelper(this); - PdfFontHelper.getHelper( - this, - ).initialize(size, style: style, multiStyle: multiStyle); - _fontFamily = fontFamily; - _checkStyle(); - _initializeInternals(); - } - - /// Initializes a new instance of the [PdfStandardFont] class - /// with [PdfStandardFont] as prototype, size and font style. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create PDF standard font. - /// PdfFont font = PdfStandardFont.prototype( - /// PdfStandardFont(PdfFontFamily.helvetica, 12), 12); - /// //Draw the text. - /// document.pages.add().graphics.drawString( - /// 'The font family name is ${font.fontFamily}', font, - /// brush: PdfBrushes.black); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfStandardFont.prototype( - PdfStandardFont prototype, - double size, { - PdfFontStyle? style, - List? multiStyle, - }) { - _helper = PdfStandardFontHelper(this); - PdfFontHelper.getHelper( - this, - ).initialize(size, style: style, multiStyle: multiStyle); - _fontFamily = prototype.fontFamily; - if (style == null && (multiStyle == null || multiStyle.isEmpty)) { - PdfFontHelper.getHelper(this).setStyle(prototype.style, null); - } - _checkStyle(); - _initializeInternals(); - } - - //Fields - late PdfStandardFontHelper _helper; - - /// FontFamily of the font. - PdfFontFamily _fontFamily = PdfFontFamily.helvetica; - - /// First character position. - static const int _charOffset = 32; - - //Properties - /// Gets the font family. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create PDF standard font. - /// PdfStandardFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); - /// //Draw the text. - /// document.pages.add().graphics.drawString( - /// 'The font family name is ${font.fontFamily}', font, - /// brush: PdfBrushes.black); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfFontFamily get fontFamily => _fontFamily; - - //Implementation - /// Checks font style of the font. - void _checkStyle() { - if (fontFamily == PdfFontFamily.symbol || - fontFamily == PdfFontFamily.zapfDingbats) { - PdfFontHelper.getHelper(this).fontStyle = - PdfFontHelper.getHelper(this).fontStyle & - ~(PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) | - PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)); - PdfFontHelper.getHelper(this).style = PdfFontStyle.regular; - } - } - - /// Initializes font internals. - void _initializeInternals() { - PdfFontHelper.getHelper( - this, - ).metrics = PdfStandardFontMetricsFactory.getMetrics( - _fontFamily, - PdfFontHelper.getHelper(this).fontStyle, - size, - ); - PdfFontHelper.getHelper(this).fontInternals = _createInternals(); - } - - /// Creates font's dictionary. - PdfDictionary _createInternals() { - final PdfDictionary dictionary = PdfDictionary(); - dictionary[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.font, - ); - dictionary[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.type1, - ); - dictionary[PdfDictionaryProperties.baseFont] = PdfName( - PdfFontHelper.getHelper(this).metrics!.postScriptName, - ); - if (fontFamily != PdfFontFamily.symbol && - fontFamily != PdfFontFamily.zapfDingbats) { - dictionary[PdfDictionaryProperties.encoding] = PdfName('WinAnsiEncoding'); - } - return dictionary; - } -} - -/// [PdfStandardFont] helper -class PdfStandardFontHelper { - /// internal constructor - PdfStandardFontHelper(this.base); - - /// internal field - PdfStandardFont base; - List? _windows1252MapTable; - - List? get _windowsMapTable { - _windows1252MapTable ??= [ - '\u0000', - '\u0001', - '\u0002', - '\u0003', - '\u0004', - '\u0005', - '\u0006', - '\u0007', - '\b', - '\t', - '\n', - '\v', - '\f', - '\r', - '\u000e', - '\u000f', - '\u0010', - '\u0011', - '\u0012', - '\u0013', - '\u0014', - '\u0015', - '\u0016', - '\u0017', - '\u0018', - '\u0019', - '\u001a', - '\u001b', - '\u001c', - '\u001d', - '\u001e', - '\u001f', - ' ', - '!', - '"', - '#', - r'$', - '%', - '&', - "'", - '(', - ')', - '*', - '+', - ',', - '-', - '.', - '/', - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - ':', - ';', - '<', - '=', - '>', - '?', - '@', - 'A', - 'B', - 'C', - 'D', - 'E', - 'F', - 'G', - 'H', - 'I', - 'J', - 'K', - 'L', - 'M', - 'N', - 'O', - 'P', - 'Q', - 'R', - 'S', - 'T', - 'U', - 'V', - 'W', - 'X', - 'Y', - 'Z', - '[', - r'\', - ']', - '^', - '_', - '`', - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', - 'g', - 'h', - 'i', - 'j', - 'k', - 'l', - 'm', - 'n', - 'o', - 'p', - 'q', - 'r', - 's', - 't', - 'u', - 'v', - 'w', - 'x', - 'y', - 'z', - '{', - '|', - '}', - '~', - '\u007f', - '€', - '\u0081', - '‚', - 'ƒ', - '„', - '…', - '†', - '‡', - 'ˆ', - '‰', - 'Š', - '‹', - 'Œ', - '\u008d', - 'Ž', - '\u008f', - '\u0090', - '‘', - '’', - '“', - '”', - '•', - '–', - '—', - '˜', - '™', - 'š', - '›', - 'œ', - '\u009d', - 'ž', - 'Ÿ', - ' ', - '¡', - '¢', - '£', - '¤', - '¥', - '¦', - '§', - '¨', - '©', - 'ª', - '«', - '¬', - '­', - '®', - '¯', - '°', - '±', - '²', - '³', - '´', - 'µ', - '¶', - '·', - '¸', - '¹', - 'º', - '»', - '¼', - '½', - '¾', - '¿', - 'À', - 'Á', - 'Â', - 'Ã', - 'Ä', - 'Å', - 'Æ', - 'Ç', - 'È', - 'É', - 'Ê', - 'Ë', - 'Ì', - 'Í', - 'Î', - 'Ï', - 'Ð', - 'Ñ', - 'Ò', - 'Ó', - 'Ô', - 'Õ', - 'Ö', - '×', - 'Ø', - 'Ù', - 'Ú', - 'Û', - 'Ü', - 'Ý', - 'Þ', - 'ß', - 'à', - 'á', - 'â', - 'ã', - 'ä', - 'å', - 'æ', - 'ç', - 'è', - 'é', - 'ê', - 'ë', - 'ì', - 'í', - 'î', - 'ï', - 'ð', - 'ñ', - 'ò', - 'ó', - 'ô', - 'õ', - 'ö', - '÷', - 'ø', - 'ú', - 'û', - 'ü', - 'ý', - 'þ', - 'ÿ', - ]; - return _windows1252MapTable; - } - - /// internal method - static PdfStandardFontHelper getHelper(PdfStandardFont base) { - return base._helper; - } - - /// internal method - /// Returns width of the char. - /// This methods doesn't takes into consideration font's size. - double getCharWidthInternal(String charCode) { - int code = 0; - code = charCode.codeUnitAt(0); - if (code >= 256 && _windowsMapTable!.contains(charCode)) { - code = _windowsMapTable!.indexOf(charCode); - } - if (PdfFontHelper.standardFontNames.contains(base.name)) { - code = code - PdfStandardFont._charOffset; - } - code = (code >= 0 && code != 128) ? code : 0; - return PdfFontHelper.getHelper(base).metrics!.widthTable![code]!.toDouble(); - } - - /// internal property - IPdfPrimitive? get element => PdfFontHelper.getHelper(base).fontInternals; - - //ignore: unused_element - set element(IPdfPrimitive? value) { - PdfFontHelper.getHelper(base).fontInternals = value; - } - - /// Returns width of the line. - double getLineWidth(String line, [PdfStringFormat? format]) { - double width = 0; - for (int i = 0; i < line.length; i++) { - final String character = line[i]; - final double charWidth = getCharWidthInternal(character); - width += charWidth; - } - final double size = PdfFontHelper.getHelper(base).metrics!.getSize(format)!; - width *= PdfFontHelper.characterSizeMultiplier * size; - width = PdfFontHelper.applyFormatSettings(base, line, format, width); - return width; - } -} +import '../../../interfaces/pdf_interface.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import 'enums.dart'; +import 'pdf_font.dart'; +import 'pdf_standard_font_metrics_factory.dart'; +import 'pdf_string_format.dart'; + +/// Represents one of the 14 standard PDF fonts. +/// It's used to create a standard PDF font to draw the text in to the PDF +/// +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// brush: PdfBrushes.black); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +class PdfStandardFont extends PdfFont { + //Constructors + /// Initializes a new instance of the [PdfStandardFont] class + /// with font family, size and font style. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfStandardFont( + PdfFontFamily fontFamily, + double size, { + PdfFontStyle? style, + List? multiStyle, + }) { + _helper = PdfStandardFontHelper(this); + PdfFontHelper.getHelper( + this, + ).initialize(size, style: style, multiStyle: multiStyle); + _fontFamily = fontFamily; + _checkStyle(); + _initializeInternals(); + } + + /// Initializes a new instance of the [PdfStandardFont] class + /// with [PdfStandardFont] as prototype, size and font style. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create PDF standard font. + /// PdfFont font = PdfStandardFont.prototype( + /// PdfStandardFont(PdfFontFamily.helvetica, 12), 12); + /// //Draw the text. + /// document.pages.add().graphics.drawString( + /// 'The font family name is ${font.fontFamily}', font, + /// brush: PdfBrushes.black); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfStandardFont.prototype( + PdfStandardFont prototype, + double size, { + PdfFontStyle? style, + List? multiStyle, + }) { + _helper = PdfStandardFontHelper(this); + PdfFontHelper.getHelper( + this, + ).initialize(size, style: style, multiStyle: multiStyle); + _fontFamily = prototype.fontFamily; + if (style == null && (multiStyle == null || multiStyle.isEmpty)) { + PdfFontHelper.getHelper(this).setStyle(prototype.style, null); + } + _checkStyle(); + _initializeInternals(); + } + + //Fields + late PdfStandardFontHelper _helper; + + /// FontFamily of the font. + PdfFontFamily _fontFamily = PdfFontFamily.helvetica; + + /// First character position. + static const int _charOffset = 32; + + //Properties + /// Gets the font family. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create PDF standard font. + /// PdfStandardFont font = PdfStandardFont(PdfFontFamily.helvetica, 12); + /// //Draw the text. + /// document.pages.add().graphics.drawString( + /// 'The font family name is ${font.fontFamily}', font, + /// brush: PdfBrushes.black); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfFontFamily get fontFamily => _fontFamily; + + //Implementation + /// Checks font style of the font. + void _checkStyle() { + if (fontFamily == PdfFontFamily.symbol || + fontFamily == PdfFontFamily.zapfDingbats) { + PdfFontHelper.getHelper(this).fontStyle = + PdfFontHelper.getHelper(this).fontStyle & + ~(PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) | + PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic)); + PdfFontHelper.getHelper(this).style = PdfFontStyle.regular; + } + } + + /// Initializes font internals. + void _initializeInternals() { + PdfFontHelper.getHelper( + this, + ).metrics = PdfStandardFontMetricsFactory.getMetrics( + _fontFamily, + PdfFontHelper.getHelper(this).fontStyle, + size, + ); + PdfFontHelper.getHelper(this).fontInternals = _createInternals(); + } + + /// Creates font's dictionary. + PdfDictionary _createInternals() { + final PdfDictionary dictionary = PdfDictionary(); + dictionary[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.font, + ); + dictionary[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.type1, + ); + dictionary[PdfDictionaryProperties.baseFont] = PdfName( + PdfFontHelper.getHelper(this).metrics!.postScriptName, + ); + if (fontFamily != PdfFontFamily.symbol && + fontFamily != PdfFontFamily.zapfDingbats) { + dictionary[PdfDictionaryProperties.encoding] = PdfName('WinAnsiEncoding'); + } + return dictionary; + } +} + +/// [PdfStandardFont] helper +class PdfStandardFontHelper { + /// internal constructor + PdfStandardFontHelper(this.base); + + /// internal field + PdfStandardFont base; + List? _windows1252MapTable; + + List? get _windowsMapTable { + _windows1252MapTable ??= [ + '\u0000', + '\u0001', + '\u0002', + '\u0003', + '\u0004', + '\u0005', + '\u0006', + '\u0007', + '\b', + '\t', + '\n', + '\v', + '\f', + '\r', + '\u000e', + '\u000f', + '\u0010', + '\u0011', + '\u0012', + '\u0013', + '\u0014', + '\u0015', + '\u0016', + '\u0017', + '\u0018', + '\u0019', + '\u001a', + '\u001b', + '\u001c', + '\u001d', + '\u001e', + '\u001f', + ' ', + '!', + '"', + '#', + r'$', + '%', + '&', + "'", + '(', + ')', + '*', + '+', + ',', + '-', + '.', + '/', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + ':', + ';', + '<', + '=', + '>', + '?', + '@', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '[', + r'\', + ']', + '^', + '_', + '`', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + '{', + '|', + '}', + '~', + '\u007f', + '€', + '\u0081', + '‚', + 'ƒ', + '„', + '…', + '†', + '‡', + 'ˆ', + '‰', + 'Š', + '‹', + 'Œ', + '\u008d', + 'Ž', + '\u008f', + '\u0090', + '‘', + '’', + '“', + '”', + '•', + '–', + '—', + '˜', + '™', + 'š', + '›', + 'œ', + '\u009d', + 'ž', + 'Ÿ', + ' ', + '¡', + '¢', + '£', + '¤', + '¥', + '¦', + '§', + '¨', + '©', + 'ª', + '«', + '¬', + '­', + '®', + '¯', + '°', + '±', + '²', + '³', + '´', + 'µ', + '¶', + '·', + '¸', + '¹', + 'º', + '»', + '¼', + '½', + '¾', + '¿', + 'À', + 'Á', + 'Â', + 'Ã', + 'Ä', + 'Å', + 'Æ', + 'Ç', + 'È', + 'É', + 'Ê', + 'Ë', + 'Ì', + 'Í', + 'Î', + 'Ï', + 'Ð', + 'Ñ', + 'Ò', + 'Ó', + 'Ô', + 'Õ', + 'Ö', + '×', + 'Ø', + 'Ù', + 'Ú', + 'Û', + 'Ü', + 'Ý', + 'Þ', + 'ß', + 'à', + 'á', + 'â', + 'ã', + 'ä', + 'å', + 'æ', + 'ç', + 'è', + 'é', + 'ê', + 'ë', + 'ì', + 'í', + 'î', + 'ï', + 'ð', + 'ñ', + 'ò', + 'ó', + 'ô', + 'õ', + 'ö', + '÷', + 'ø', + 'ú', + 'û', + 'ü', + 'ý', + 'þ', + 'ÿ', + ]; + return _windows1252MapTable; + } + + /// internal method + static PdfStandardFontHelper getHelper(PdfStandardFont base) { + return base._helper; + } + + /// internal method + /// Returns width of the char. + /// This methods doesn't takes into consideration font's size. + double getCharWidthInternal(String charCode) { + int code = 0; + code = charCode.codeUnitAt(0); + if (code >= 256 && _windowsMapTable!.contains(charCode)) { + code = _windowsMapTable!.indexOf(charCode); + } + if (PdfFontHelper.standardFontNames.contains(base.name)) { + code = code - PdfStandardFont._charOffset; + } + code = (code >= 0 && code != 128) ? code : 0; + return PdfFontHelper.getHelper(base).metrics!.widthTable![code]!.toDouble(); + } + + /// internal property + IPdfPrimitive? get element => PdfFontHelper.getHelper(base).fontInternals; + + //ignore: unused_element + set element(IPdfPrimitive? value) { + PdfFontHelper.getHelper(base).fontInternals = value; + } + + /// Returns width of the line. + double getLineWidth(String line, [PdfStringFormat? format]) { + double width = 0; + for (int i = 0; i < line.length; i++) { + final String character = line[i]; + final double charWidth = getCharWidthInternal(character); + width += charWidth; + } + final double size = PdfFontHelper.getHelper(base).metrics!.getSize(format)!; + width *= PdfFontHelper.characterSizeMultiplier * size; + width = PdfFontHelper.applyFormatSettings(base, line, format, width); + return width; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font_metrics_factory.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font_metrics_factory.dart index e4bccec6c..39a3f5927 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font_metrics_factory.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_standard_font_metrics_factory.dart @@ -1,2330 +1,2330 @@ -import 'enums.dart'; -import 'pdf_font.dart'; -import 'pdf_font_metrics.dart'; - -/// Factory of the standard fonts metrics. -class PdfStandardFontMetricsFactory { - /// internal constructor - PdfStandardFontMetricsFactory(); - - /// Multiplier os subscript superscript. - static const double _subSuperscriptFactor = 1.52; - - /// Ascender value for the font. - static const double _helveticaAscent = 931; - - /// Ascender value for the font. - static const double _helveticaDescent = -225; - - /// Font type - static const String _helveticaName = 'Helvetica'; - - /// Ascender value for the font. - static const double _helveticaBoldAscent = 962; - - /// Ascender value for the font. - final double _helveticaBoldDescent = -228; - - /// Font type - static const String _helveticaBoldName = 'Helvetica-Bold'; - - /// Ascender value for the font. - static const double _helveticaItalicAscent = 931; - - /// Ascender value for the font. - static const double _helveticaItalicDescent = -225; - - /// Font type - static const String _helveticaItalicName = 'Helvetica-Oblique'; - - /// Ascender value for the font. - static const double _helveticaBoldItalicAscent = 962; - - /// Ascender value for the font. - static const double _helveticaBoldItalicDescent = -228; - - /// Font type - static const String _helveticaBoldItalicName = 'Helvetica-BoldOblique'; - - /// Ascender value for the font. - static const double _courierAscent = 805; - - /// Ascender value for the font. - static const double _courierDescent = -250; - - /// Font type. - static const String _courierName = 'Courier'; - - /// Ascender value for the font. - static const double _courierBoldAscent = 801; - - /// Ascender value for the font. - static const double _courierBoldDescent = -250; - - /// Font type. - static const String _courierBoldName = 'Courier-Bold'; - - /// Ascender value for the font. - static const double _courierItalicAscent = 805; - - /// Ascender value for the font. - static const double _courierItalicDescent = -250; - - /// Font type. - static const String _courierItalicName = 'Courier-Oblique'; - - /// Ascender value for the font. - static const double _courierBoldItalicAscent = 801; - - /// Ascender value for the font. - static const double _courierBoldItalicDescent = -250; - - /// Font type. - static const String _courierBoldItalicName = 'Courier-BoldOblique'; - - /// Ascender value for the font. - static const double _timesAscent = 898; - - /// Ascender value for the font. - static const double _timesDescent = -218; - - /// Font type. - static const String _timesName = 'Times-Roman'; - - /// Ascender value for the font. - static const double _timesBoldAscent = 935; - - /// Ascender value for the font. - static const double _timesBoldDescent = -218; - - /// Font type. - static const String _timesBoldName = 'Times-Bold'; - - /// Ascender value for the font. - static const double _timesItalicAscent = 883; - - /// Ascender value for the font. - static const double _timesItalicDescent = -217; - - /// Font type. - static const String _timesItalicName = 'Times-Italic'; - - /// Ascender value for the font. - static const double _timesBoldItalicAscent = 921; - - /// Ascender value for the font. - static const double _timesBoldItalicDescent = -218; - - /// Font type. - static const String _timesBoldItalicName = 'Times-BoldItalic'; - - /// Ascender value for the font. - static const double _symbolAscent = 1010; - - /// Ascender value for the font. - static const double _symbolDescent = -293; - - /// Font type. - static const String _symbolName = 'Symbol'; - - /// Ascender value for the font. - static const double _zapfDingbatsAscent = 820; - - /// Ascender value for the font. - static const double _zapfDingbatsDescent = -143; - - /// Font type. - static const String _zapfDingbatsName = 'ZapfDingbats'; - - /// Returns metrics of the font. - static PdfFontMetrics getMetrics( - PdfFontFamily? fontFamily, - int? fontStyle, - double size, - ) { - PdfFontMetrics metrics; - switch (fontFamily) { - case PdfFontFamily.helvetica: - metrics = _getHelveticaMetrics(fontFamily, fontStyle!, size); - break; - case PdfFontFamily.courier: - metrics = _getCourierMetrics(fontFamily, fontStyle!, size); - break; - case PdfFontFamily.timesRoman: - metrics = _getTimesMetrics(fontFamily, fontStyle!, size); - break; - case PdfFontFamily.symbol: - metrics = _getSymbolMetrics(fontFamily, size); - break; - case PdfFontFamily.zapfDingbats: - metrics = _getZapfDingbatsMetrics(fontFamily, size); - break; - // ignore: no_default_cases - default: - metrics = _getHelveticaMetrics( - PdfFontFamily.helvetica, - fontStyle!, - size, - ); - break; - } - metrics.name = PdfFontHelper.standardFontNames[fontFamily!.index]; - metrics.subscriptSizeFactor = _subSuperscriptFactor; - metrics.superscriptSizeFactor = _subSuperscriptFactor; - return metrics; - } - - /// Creates Helvetica font metrics. - static PdfFontMetrics _getHelveticaMetrics( - PdfFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - final PdfStandardFontMetricsFactory standardFontMetricsFactory = - PdfStandardFontMetricsFactory(); - if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > 0 && - fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > 0) { - metrics.ascent = _helveticaBoldItalicAscent; - metrics.descent = _helveticaBoldItalicDescent; - metrics.postScriptName = _helveticaBoldItalicName; - metrics.size = size; - metrics.widthTable = StandardWidthTable( - _StandardFontWidth._arialBoldWidth, - ); - metrics.height = metrics.ascent - metrics.descent; - } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > - 0) { - metrics.ascent = _helveticaBoldAscent; - metrics.descent = standardFontMetricsFactory._helveticaBoldDescent; - metrics.postScriptName = _helveticaBoldName; - metrics.size = size; - metrics.widthTable = StandardWidthTable( - _StandardFontWidth._arialBoldWidth, - ); - metrics.height = metrics.ascent - metrics.descent; - } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > - 0) { - metrics.ascent = _helveticaItalicAscent; - metrics.descent = _helveticaItalicDescent; - metrics.postScriptName = _helveticaItalicName; - metrics.size = size; - metrics.widthTable = StandardWidthTable(_StandardFontWidth._arialWidth); - metrics.height = metrics.ascent - metrics.descent; - } else { - metrics.ascent = _helveticaAscent; - metrics.descent = _helveticaDescent; - metrics.postScriptName = _helveticaName; - metrics.size = size; - metrics.widthTable = StandardWidthTable(_StandardFontWidth._arialWidth); - metrics.height = metrics.ascent - metrics.descent; - } - return metrics; - } - - /// Creates Courier font metrics. - static PdfFontMetrics _getCourierMetrics( - PdfFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > 0 && - fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > 0) { - metrics.ascent = _courierBoldItalicAscent; - metrics.descent = _courierBoldItalicDescent; - metrics.postScriptName = _courierBoldItalicName; - metrics.size = size; - metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); - metrics.height = metrics.ascent - metrics.descent; - } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > - 0) { - metrics.ascent = _courierBoldAscent; - metrics.descent = _courierBoldDescent; - metrics.postScriptName = _courierBoldName; - metrics.size = size; - metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); - metrics.height = metrics.ascent - metrics.descent; - } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > - 0) { - metrics.ascent = _courierItalicAscent; - metrics.descent = _courierItalicDescent; - metrics.postScriptName = _courierItalicName; - metrics.size = size; - metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); - metrics.height = metrics.ascent - metrics.descent; - } else { - metrics.ascent = _courierAscent; - metrics.descent = _courierDescent; - metrics.postScriptName = _courierName; - metrics.size = size; - metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); - metrics.height = metrics.ascent - metrics.descent; - } - return metrics; - } - - /// Creates Times font metrics. - static PdfFontMetrics _getTimesMetrics( - PdfFontFamily? fontFamily, - int fontStyle, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > 0 && - fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > 0) { - metrics.ascent = _timesBoldItalicAscent; - metrics.descent = _timesBoldItalicDescent; - metrics.postScriptName = _timesBoldItalicName; - metrics.size = size; - metrics.widthTable = StandardWidthTable( - _StandardFontWidth._timesRomanBoldItalicWidth, - ); - metrics.height = metrics.ascent - metrics.descent; - } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > - 0) { - metrics.ascent = _timesBoldAscent; - metrics.descent = _timesBoldDescent; - metrics.postScriptName = _timesBoldName; - metrics.size = size; - metrics.widthTable = StandardWidthTable( - _StandardFontWidth._timesRomanBoldWidth, - ); - metrics.height = metrics.ascent - metrics.descent; - } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > - 0) { - metrics.ascent = _timesItalicAscent; - metrics.descent = _timesItalicDescent; - metrics.postScriptName = _timesItalicName; - metrics.size = size; - metrics.widthTable = StandardWidthTable( - _StandardFontWidth._timesRomanItalicWidth, - ); - metrics.height = metrics.ascent - metrics.descent; - } else { - metrics.ascent = _timesAscent; - metrics.descent = _timesDescent; - metrics.postScriptName = _timesName; - metrics.size = size; - metrics.widthTable = StandardWidthTable( - _StandardFontWidth._timesRomanWidth, - ); - metrics.height = metrics.ascent - metrics.descent; - } - return metrics; - } - - /// Creates Symbol font metrics. - static PdfFontMetrics _getSymbolMetrics( - PdfFontFamily? fontFamily, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - - metrics.ascent = _symbolAscent; - metrics.descent = _symbolDescent; - metrics.postScriptName = _symbolName; - metrics.size = size; - metrics.widthTable = StandardWidthTable(_StandardFontWidth._symbolWidth); - metrics.height = metrics.ascent - metrics.descent; - return metrics; - } - - /// Creates ZapfDingbats font metrics. - static PdfFontMetrics _getZapfDingbatsMetrics( - PdfFontFamily? fontFamily, - double size, - ) { - final PdfFontMetrics metrics = PdfFontMetrics(); - metrics.ascent = _zapfDingbatsAscent; - metrics.descent = _zapfDingbatsDescent; - metrics.postScriptName = _zapfDingbatsName; - metrics.size = size; - metrics.widthTable = StandardWidthTable( - _StandardFontWidth._zapfDingbatsWidth, - ); - metrics.height = metrics.ascent - metrics.descent; - return metrics; - } -} - -class _StandardFontWidth { - static const List _arialWidth = [ - 278, - 278, - 355, - 556, - 556, - 889, - 667, - 191, - 333, - 333, - 389, - 584, - 278, - 333, - 278, - 278, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 278, - 278, - 584, - 584, - 584, - 556, - 1015, - 667, - 667, - 722, - 722, - 667, - 611, - 778, - 722, - 278, - 500, - 667, - 556, - 833, - 722, - 778, - 667, - 778, - 722, - 667, - 611, - 722, - 667, - 944, - 667, - 667, - 611, - 278, - 278, - 278, - 469, - 556, - 333, - 556, - 556, - 500, - 556, - 556, - 278, - 556, - 556, - 222, - 222, - 500, - 222, - 833, - 556, - 556, - 556, - 556, - 333, - 500, - 278, - 556, - 500, - 722, - 500, - 500, - 500, - 334, - 260, - 334, - 584, - 0, - 556, - 0, - 222, - 556, - 333, - 1000, - 556, - 556, - 333, - 1000, - 667, - 333, - 1000, - 0, - 611, - 0, - 0, - 222, - 222, - 333, - 333, - 350, - 556, - 1000, - 333, - 1000, - 500, - 333, - 944, - 0, - 500, - 667, - 0, - 333, - 556, - 556, - 556, - 556, - 260, - 556, - 333, - 737, - 370, - 556, - 584, - 0, - 737, - 333, - 400, - 584, - 333, - 333, - 333, - 556, - 537, - 278, - 333, - 333, - 365, - 556, - 834, - 834, - 834, - 611, - 667, - 667, - 667, - 667, - 667, - 667, - 1000, - 722, - 667, - 667, - 667, - 667, - 278, - 278, - 278, - 278, - 722, - 722, - 778, - 778, - 778, - 778, - 778, - 584, - 778, - 722, - 722, - 722, - 722, - 667, - 667, - 611, - 556, - 556, - 556, - 556, - 556, - 556, - 889, - 500, - 556, - 556, - 556, - 556, - 278, - 278, - 278, - 278, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 584, - 611, - 556, - 556, - 556, - 556, - 500, - 556, - 500, - ]; - static const List _arialBoldWidth = [ - 278, - 333, - 474, - 556, - 556, - 889, - 722, - 238, - 333, - 333, - 389, - 584, - 278, - 333, - 278, - 278, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 556, - 333, - 333, - 584, - 584, - 584, - 611, - 975, - 722, - 722, - 722, - 722, - 667, - 611, - 778, - 722, - 278, - 556, - 722, - 611, - 833, - 722, - 778, - 667, - 778, - 722, - 667, - 611, - 722, - 667, - 944, - 667, - 667, - 611, - 333, - 278, - 333, - 584, - 556, - 333, - 556, - 611, - 556, - 611, - 556, - 333, - 611, - 611, - 278, - 278, - 556, - 278, - 889, - 611, - 611, - 611, - 611, - 389, - 556, - 333, - 611, - 556, - 778, - 556, - 556, - 500, - 389, - 280, - 389, - 584, - 0, - 556, - 0, - 278, - 556, - 500, - 1000, - 556, - 556, - 333, - 1000, - 667, - 333, - 1000, - 0, - 611, - 0, - 0, - 278, - 278, - 500, - 500, - 350, - 556, - 1000, - 333, - 1000, - 556, - 333, - 944, - 0, - 500, - 667, - 0, - 333, - 556, - 556, - 556, - 556, - 280, - 556, - 333, - 737, - 370, - 556, - 584, - 0, - 737, - 333, - 400, - 584, - 333, - 333, - 333, - 611, - 556, - 278, - 333, - 333, - 365, - 556, - 834, - 834, - 834, - 611, - 722, - 722, - 722, - 722, - 722, - 722, - 1000, - 722, - 667, - 667, - 667, - 667, - 278, - 278, - 278, - 278, - 722, - 722, - 778, - 778, - 778, - 778, - 778, - 584, - 778, - 722, - 722, - 722, - 722, - 667, - 667, - 611, - 556, - 556, - 556, - 556, - 556, - 556, - 889, - 556, - 556, - 556, - 556, - 556, - 278, - 278, - 278, - 278, - 611, - 611, - 611, - 611, - 611, - 611, - 611, - 584, - 611, - 611, - 611, - 611, - 611, - 556, - 611, - 556, - ]; - static const List _fixedWidth = [ - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - 600, - ]; - static const List _timesRomanWidth = [ - 250, - 333, - 408, - 500, - 500, - 833, - 778, - 180, - 333, - 333, - 500, - 564, - 250, - 333, - 250, - 278, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 278, - 278, - 564, - 564, - 564, - 444, - 921, - 722, - 667, - 667, - 722, - 611, - 556, - 722, - 722, - 333, - 389, - 722, - 611, - 889, - 722, - 722, - 556, - 722, - 667, - 556, - 611, - 722, - 722, - 944, - 722, - 722, - 611, - 333, - 278, - 333, - 469, - 500, - 333, - 444, - 500, - 444, - 500, - 444, - 333, - 500, - 500, - 278, - 278, - 500, - 278, - 778, - 500, - 500, - 500, - 500, - 333, - 389, - 278, - 500, - 500, - 722, - 500, - 500, - 444, - 480, - 200, - 480, - 541, - 000, - 500, - 000, - 333, - 500, - 444, - 1000, - 500, - 500, - 333, - 1000, - 556, - 333, - 889, - 0, - 611, - 000, - 000, - 333, - 333, - 444, - 444, - 350, - 500, - 1000, - 333, - 980, - 389, - 333, - 722, - 0, - 444, - 722, - 000, - 333, - 500, - 500, - 500, - 500, - 200, - 500, - 333, - 760, - 276, - 500, - 564, - 0, - 760, - 333, - 400, - 564, - 300, - 300, - 333, - 500, - 453, - 250, - 333, - 300, - 310, - 500, - 750, - 750, - 750, - 444, - 722, - 722, - 722, - 722, - 722, - 722, - 889, - 667, - 611, - 611, - 611, - 611, - 333, - 333, - 333, - 333, - 722, - 722, - 722, - 722, - 722, - 722, - 722, - 564, - 722, - 722, - 722, - 722, - 722, - 722, - 556, - 500, - 444, - 444, - 444, - 444, - 444, - 444, - 667, - 444, - 444, - 444, - 444, - 444, - 278, - 278, - 278, - 278, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 564, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - ]; - static const List _timesRomanBoldWidth = [ - 250, - 333, - 555, - 500, - 500, - 1000, - 833, - 278, - 333, - 333, - 500, - 570, - 250, - 333, - 250, - 278, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 333, - 333, - 570, - 570, - 570, - 500, - 930, - 722, - 667, - 722, - 722, - 667, - 611, - 778, - 778, - 389, - 500, - 778, - 667, - 944, - 722, - 778, - 611, - 778, - 722, - 556, - 667, - 722, - 722, - 1000, - 722, - 722, - 667, - 333, - 278, - 333, - 581, - 500, - 333, - 500, - 556, - 444, - 556, - 444, - 333, - 500, - 556, - 278, - 333, - 556, - 278, - 833, - 556, - 500, - 556, - 556, - 444, - 389, - 333, - 556, - 500, - 722, - 500, - 500, - 444, - 394, - 220, - 394, - 520, - 0, - 500, - 0, - 333, - 500, - 500, - 1000, - 500, - 500, - 333, - 1000, - 556, - 333, - 1000, - 0, - 667, - 0, - 0, - 333, - 333, - 500, - 500, - 350, - 500, - 1000, - 333, - 1000, - 389, - 333, - 722, - 0, - 444, - 722, - 0, - 333, - 500, - 500, - 500, - 500, - 220, - 500, - 333, - 747, - 300, - 500, - 570, - 0, - 747, - 333, - 400, - 570, - 300, - 300, - 333, - 556, - 540, - 250, - 333, - 300, - 330, - 500, - 750, - 750, - 750, - 500, - 722, - 722, - 722, - 722, - 722, - 722, - 1000, - 722, - 667, - 667, - 667, - 667, - 389, - 389, - 389, - 389, - 722, - 722, - 778, - 778, - 778, - 778, - 778, - 570, - 778, - 722, - 722, - 722, - 722, - 722, - 611, - 556, - 500, - 500, - 500, - 500, - 500, - 500, - 722, - 444, - 444, - 444, - 444, - 444, - 278, - 278, - 278, - 278, - 500, - 556, - 500, - 500, - 500, - 500, - 500, - 570, - 500, - 556, - 556, - 556, - 556, - 500, - 556, - 500, - ]; - static const List _timesRomanItalicWidth = [ - 250, - 333, - 420, - 500, - 500, - 833, - 778, - 214, - 333, - 333, - 500, - 675, - 250, - 333, - 250, - 278, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 333, - 333, - 675, - 675, - 675, - 500, - 920, - 611, - 611, - 667, - 722, - 611, - 611, - 722, - 722, - 333, - 444, - 667, - 556, - 833, - 667, - 722, - 611, - 722, - 611, - 500, - 556, - 722, - 611, - 833, - 611, - 556, - 556, - 389, - 278, - 389, - 422, - 500, - 333, - 500, - 500, - 444, - 500, - 444, - 278, - 500, - 500, - 278, - 278, - 444, - 278, - 722, - 500, - 500, - 500, - 500, - 389, - 389, - 278, - 500, - 444, - 667, - 444, - 444, - 389, - 400, - 275, - 400, - 541, - 0, - 500, - 0, - 333, - 500, - 556, - 889, - 500, - 500, - 333, - 1000, - 500, - 333, - 944, - 0, - 556, - 0, - 0, - 333, - 333, - 556, - 556, - 350, - 500, - 889, - 333, - 980, - 389, - 333, - 667, - 0, - 389, - 556, - 0, - 389, - 500, - 500, - 500, - 500, - 275, - 500, - 333, - 760, - 276, - 500, - 675, - 0, - 760, - 333, - 400, - 675, - 300, - 300, - 333, - 500, - 523, - 250, - 333, - 300, - 310, - 500, - 750, - 750, - 750, - 500, - 611, - 611, - 611, - 611, - 611, - 611, - 889, - 667, - 611, - 611, - 611, - 611, - 333, - 333, - 333, - 333, - 722, - 667, - 722, - 722, - 722, - 722, - 722, - 675, - 722, - 722, - 722, - 722, - 722, - 556, - 611, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 667, - 444, - 444, - 444, - 444, - 444, - 278, - 278, - 278, - 278, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 675, - 500, - 500, - 500, - 500, - 500, - 444, - 500, - 444, - ]; - static const List _timesRomanBoldItalicWidth = [ - 250, - 389, - 555, - 500, - 500, - 833, - 778, - 278, - 333, - 333, - 500, - 570, - 250, - 333, - 250, - 278, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 333, - 333, - 570, - 570, - 570, - 500, - 832, - 667, - 667, - 667, - 722, - 667, - 667, - 722, - 778, - 389, - 500, - 667, - 611, - 889, - 722, - 722, - 611, - 722, - 667, - 556, - 611, - 722, - 667, - 889, - 667, - 611, - 611, - 333, - 278, - 333, - 570, - 500, - 333, - 500, - 500, - 444, - 500, - 444, - 333, - 500, - 556, - 278, - 278, - 500, - 278, - 778, - 556, - 500, - 500, - 500, - 389, - 389, - 278, - 556, - 444, - 667, - 500, - 444, - 389, - 348, - 220, - 348, - 570, - 0, - 500, - 0, - 333, - 500, - 500, - 1000, - 500, - 500, - 333, - 1000, - 556, - 333, - 944, - 0, - 611, - 0, - 0, - 333, - 333, - 500, - 500, - 350, - 500, - 1000, - 333, - 1000, - 389, - 333, - 722, - 0, - 389, - 611, - 0, - 389, - 500, - 500, - 500, - 500, - 220, - 500, - 333, - 747, - 266, - 500, - 606, - 0, - 747, - 333, - 400, - 570, - 300, - 300, - 333, - 576, - 500, - 250, - 333, - 300, - 300, - 500, - 750, - 750, - 750, - 500, - 667, - 667, - 667, - 667, - 667, - 667, - 944, - 667, - 667, - 667, - 667, - 667, - 389, - 389, - 389, - 389, - 722, - 722, - 722, - 722, - 722, - 722, - 722, - 570, - 722, - 722, - 722, - 722, - 722, - 611, - 611, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 722, - 444, - 444, - 444, - 444, - 444, - 278, - 278, - 278, - 278, - 500, - 556, - 500, - 500, - 500, - 500, - 500, - 570, - 500, - 556, - 556, - 556, - 556, - 444, - 500, - 444, - ]; - static const List _symbolWidth = [ - 250, - 333, - 713, - 500, - 549, - 833, - 778, - 439, - 333, - 333, - 500, - 549, - 250, - 549, - 250, - 278, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 500, - 278, - 278, - 549, - 549, - 549, - 444, - 549, - 722, - 667, - 722, - 612, - 611, - 763, - 603, - 722, - 333, - 631, - 722, - 686, - 889, - 722, - 722, - 768, - 741, - 556, - 592, - 611, - 690, - 439, - 768, - 645, - 795, - 611, - 333, - 863, - 333, - 658, - 500, - 500, - 631, - 549, - 549, - 494, - 439, - 521, - 411, - 603, - 329, - 603, - 549, - 549, - 576, - 521, - 549, - 549, - 521, - 549, - 603, - 439, - 576, - 713, - 686, - 493, - 686, - 494, - 480, - 200, - 480, - 549, - 750, - 620, - 247, - 549, - 167, - 713, - 500, - 753, - 753, - 753, - 753, - 1042, - 987, - 603, - 987, - 603, - 400, - 549, - 411, - 549, - 549, - 713, - 494, - 460, - 549, - 549, - 549, - 549, - 1000, - 603, - 1000, - 658, - 823, - 686, - 795, - 987, - 768, - 768, - 823, - 768, - 768, - 713, - 713, - 713, - 713, - 713, - 713, - 713, - 768, - 713, - 790, - 790, - 890, - 823, - 549, - 250, - 713, - 603, - 603, - 1042, - 987, - 603, - 987, - 603, - 494, - 329, - 790, - 790, - 786, - 713, - 384, - 384, - 384, - 384, - 384, - 384, - 494, - 494, - 494, - 494, - 329, - 274, - 686, - 686, - 686, - 384, - 384, - 384, - 384, - 384, - 384, - 494, - 494, - 494, - -1, - ]; - static const List _zapfDingbatsWidth = [ - 278, - 974, - 961, - 974, - 980, - 719, - 789, - 790, - 791, - 690, - 960, - 939, - 549, - 855, - 911, - 933, - 911, - 945, - 974, - 755, - 846, - 762, - 761, - 571, - 677, - 763, - 760, - 759, - 754, - 494, - 552, - 537, - 577, - 692, - 786, - 788, - 788, - 790, - 793, - 794, - 816, - 823, - 789, - 841, - 823, - 833, - 816, - 831, - 923, - 744, - 723, - 749, - 790, - 792, - 695, - 776, - 768, - 792, - 759, - 707, - 708, - 682, - 701, - 826, - 815, - 789, - 789, - 707, - 687, - 696, - 689, - 786, - 787, - 713, - 791, - 785, - 791, - 873, - 761, - 762, - 762, - 759, - 759, - 892, - 892, - 788, - 784, - 438, - 138, - 277, - 415, - 392, - 392, - 668, - 668, - 390, - 390, - 317, - 317, - 276, - 276, - 509, - 509, - 410, - 410, - 234, - 234, - 334, - 334, - 732, - 544, - 544, - 910, - 667, - 760, - 760, - 776, - 595, - 694, - 626, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 788, - 894, - 838, - 1016, - 458, - 748, - 924, - 748, - 918, - 927, - 928, - 928, - 834, - 873, - 828, - 924, - 924, - 917, - 930, - 931, - 463, - 883, - 836, - 836, - 867, - 867, - 696, - 696, - 874, - 874, - 760, - 946, - 771, - 865, - 771, - 888, - 967, - 888, - 831, - 873, - 927, - 970, - 918, - ]; -} +import 'enums.dart'; +import 'pdf_font.dart'; +import 'pdf_font_metrics.dart'; + +/// Factory of the standard fonts metrics. +class PdfStandardFontMetricsFactory { + /// internal constructor + PdfStandardFontMetricsFactory(); + + /// Multiplier os subscript superscript. + static const double _subSuperscriptFactor = 1.52; + + /// Ascender value for the font. + static const double _helveticaAscent = 931; + + /// Ascender value for the font. + static const double _helveticaDescent = -225; + + /// Font type + static const String _helveticaName = 'Helvetica'; + + /// Ascender value for the font. + static const double _helveticaBoldAscent = 962; + + /// Ascender value for the font. + final double _helveticaBoldDescent = -228; + + /// Font type + static const String _helveticaBoldName = 'Helvetica-Bold'; + + /// Ascender value for the font. + static const double _helveticaItalicAscent = 931; + + /// Ascender value for the font. + static const double _helveticaItalicDescent = -225; + + /// Font type + static const String _helveticaItalicName = 'Helvetica-Oblique'; + + /// Ascender value for the font. + static const double _helveticaBoldItalicAscent = 962; + + /// Ascender value for the font. + static const double _helveticaBoldItalicDescent = -228; + + /// Font type + static const String _helveticaBoldItalicName = 'Helvetica-BoldOblique'; + + /// Ascender value for the font. + static const double _courierAscent = 805; + + /// Ascender value for the font. + static const double _courierDescent = -250; + + /// Font type. + static const String _courierName = 'Courier'; + + /// Ascender value for the font. + static const double _courierBoldAscent = 801; + + /// Ascender value for the font. + static const double _courierBoldDescent = -250; + + /// Font type. + static const String _courierBoldName = 'Courier-Bold'; + + /// Ascender value for the font. + static const double _courierItalicAscent = 805; + + /// Ascender value for the font. + static const double _courierItalicDescent = -250; + + /// Font type. + static const String _courierItalicName = 'Courier-Oblique'; + + /// Ascender value for the font. + static const double _courierBoldItalicAscent = 801; + + /// Ascender value for the font. + static const double _courierBoldItalicDescent = -250; + + /// Font type. + static const String _courierBoldItalicName = 'Courier-BoldOblique'; + + /// Ascender value for the font. + static const double _timesAscent = 898; + + /// Ascender value for the font. + static const double _timesDescent = -218; + + /// Font type. + static const String _timesName = 'Times-Roman'; + + /// Ascender value for the font. + static const double _timesBoldAscent = 935; + + /// Ascender value for the font. + static const double _timesBoldDescent = -218; + + /// Font type. + static const String _timesBoldName = 'Times-Bold'; + + /// Ascender value for the font. + static const double _timesItalicAscent = 883; + + /// Ascender value for the font. + static const double _timesItalicDescent = -217; + + /// Font type. + static const String _timesItalicName = 'Times-Italic'; + + /// Ascender value for the font. + static const double _timesBoldItalicAscent = 921; + + /// Ascender value for the font. + static const double _timesBoldItalicDescent = -218; + + /// Font type. + static const String _timesBoldItalicName = 'Times-BoldItalic'; + + /// Ascender value for the font. + static const double _symbolAscent = 1010; + + /// Ascender value for the font. + static const double _symbolDescent = -293; + + /// Font type. + static const String _symbolName = 'Symbol'; + + /// Ascender value for the font. + static const double _zapfDingbatsAscent = 820; + + /// Ascender value for the font. + static const double _zapfDingbatsDescent = -143; + + /// Font type. + static const String _zapfDingbatsName = 'ZapfDingbats'; + + /// Returns metrics of the font. + static PdfFontMetrics getMetrics( + PdfFontFamily? fontFamily, + int? fontStyle, + double size, + ) { + PdfFontMetrics metrics; + switch (fontFamily) { + case PdfFontFamily.helvetica: + metrics = _getHelveticaMetrics(fontFamily, fontStyle!, size); + break; + case PdfFontFamily.courier: + metrics = _getCourierMetrics(fontFamily, fontStyle!, size); + break; + case PdfFontFamily.timesRoman: + metrics = _getTimesMetrics(fontFamily, fontStyle!, size); + break; + case PdfFontFamily.symbol: + metrics = _getSymbolMetrics(fontFamily, size); + break; + case PdfFontFamily.zapfDingbats: + metrics = _getZapfDingbatsMetrics(fontFamily, size); + break; + // ignore: no_default_cases + default: + metrics = _getHelveticaMetrics( + PdfFontFamily.helvetica, + fontStyle!, + size, + ); + break; + } + metrics.name = PdfFontHelper.standardFontNames[fontFamily!.index]; + metrics.subscriptSizeFactor = _subSuperscriptFactor; + metrics.superscriptSizeFactor = _subSuperscriptFactor; + return metrics; + } + + /// Creates Helvetica font metrics. + static PdfFontMetrics _getHelveticaMetrics( + PdfFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + final PdfStandardFontMetricsFactory standardFontMetricsFactory = + PdfStandardFontMetricsFactory(); + if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > 0 && + fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > 0) { + metrics.ascent = _helveticaBoldItalicAscent; + metrics.descent = _helveticaBoldItalicDescent; + metrics.postScriptName = _helveticaBoldItalicName; + metrics.size = size; + metrics.widthTable = StandardWidthTable( + _StandardFontWidth._arialBoldWidth, + ); + metrics.height = metrics.ascent - metrics.descent; + } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > + 0) { + metrics.ascent = _helveticaBoldAscent; + metrics.descent = standardFontMetricsFactory._helveticaBoldDescent; + metrics.postScriptName = _helveticaBoldName; + metrics.size = size; + metrics.widthTable = StandardWidthTable( + _StandardFontWidth._arialBoldWidth, + ); + metrics.height = metrics.ascent - metrics.descent; + } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > + 0) { + metrics.ascent = _helveticaItalicAscent; + metrics.descent = _helveticaItalicDescent; + metrics.postScriptName = _helveticaItalicName; + metrics.size = size; + metrics.widthTable = StandardWidthTable(_StandardFontWidth._arialWidth); + metrics.height = metrics.ascent - metrics.descent; + } else { + metrics.ascent = _helveticaAscent; + metrics.descent = _helveticaDescent; + metrics.postScriptName = _helveticaName; + metrics.size = size; + metrics.widthTable = StandardWidthTable(_StandardFontWidth._arialWidth); + metrics.height = metrics.ascent - metrics.descent; + } + return metrics; + } + + /// Creates Courier font metrics. + static PdfFontMetrics _getCourierMetrics( + PdfFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > 0 && + fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > 0) { + metrics.ascent = _courierBoldItalicAscent; + metrics.descent = _courierBoldItalicDescent; + metrics.postScriptName = _courierBoldItalicName; + metrics.size = size; + metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); + metrics.height = metrics.ascent - metrics.descent; + } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > + 0) { + metrics.ascent = _courierBoldAscent; + metrics.descent = _courierBoldDescent; + metrics.postScriptName = _courierBoldName; + metrics.size = size; + metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); + metrics.height = metrics.ascent - metrics.descent; + } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > + 0) { + metrics.ascent = _courierItalicAscent; + metrics.descent = _courierItalicDescent; + metrics.postScriptName = _courierItalicName; + metrics.size = size; + metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); + metrics.height = metrics.ascent - metrics.descent; + } else { + metrics.ascent = _courierAscent; + metrics.descent = _courierDescent; + metrics.postScriptName = _courierName; + metrics.size = size; + metrics.widthTable = StandardWidthTable(_StandardFontWidth._fixedWidth); + metrics.height = metrics.ascent - metrics.descent; + } + return metrics; + } + + /// Creates Times font metrics. + static PdfFontMetrics _getTimesMetrics( + PdfFontFamily? fontFamily, + int fontStyle, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > 0 && + fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > 0) { + metrics.ascent = _timesBoldItalicAscent; + metrics.descent = _timesBoldItalicDescent; + metrics.postScriptName = _timesBoldItalicName; + metrics.size = size; + metrics.widthTable = StandardWidthTable( + _StandardFontWidth._timesRomanBoldItalicWidth, + ); + metrics.height = metrics.ascent - metrics.descent; + } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.bold) > + 0) { + metrics.ascent = _timesBoldAscent; + metrics.descent = _timesBoldDescent; + metrics.postScriptName = _timesBoldName; + metrics.size = size; + metrics.widthTable = StandardWidthTable( + _StandardFontWidth._timesRomanBoldWidth, + ); + metrics.height = metrics.ascent - metrics.descent; + } else if (fontStyle & PdfFontHelper.getPdfFontStyle(PdfFontStyle.italic) > + 0) { + metrics.ascent = _timesItalicAscent; + metrics.descent = _timesItalicDescent; + metrics.postScriptName = _timesItalicName; + metrics.size = size; + metrics.widthTable = StandardWidthTable( + _StandardFontWidth._timesRomanItalicWidth, + ); + metrics.height = metrics.ascent - metrics.descent; + } else { + metrics.ascent = _timesAscent; + metrics.descent = _timesDescent; + metrics.postScriptName = _timesName; + metrics.size = size; + metrics.widthTable = StandardWidthTable( + _StandardFontWidth._timesRomanWidth, + ); + metrics.height = metrics.ascent - metrics.descent; + } + return metrics; + } + + /// Creates Symbol font metrics. + static PdfFontMetrics _getSymbolMetrics( + PdfFontFamily? fontFamily, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + + metrics.ascent = _symbolAscent; + metrics.descent = _symbolDescent; + metrics.postScriptName = _symbolName; + metrics.size = size; + metrics.widthTable = StandardWidthTable(_StandardFontWidth._symbolWidth); + metrics.height = metrics.ascent - metrics.descent; + return metrics; + } + + /// Creates ZapfDingbats font metrics. + static PdfFontMetrics _getZapfDingbatsMetrics( + PdfFontFamily? fontFamily, + double size, + ) { + final PdfFontMetrics metrics = PdfFontMetrics(); + metrics.ascent = _zapfDingbatsAscent; + metrics.descent = _zapfDingbatsDescent; + metrics.postScriptName = _zapfDingbatsName; + metrics.size = size; + metrics.widthTable = StandardWidthTable( + _StandardFontWidth._zapfDingbatsWidth, + ); + metrics.height = metrics.ascent - metrics.descent; + return metrics; + } +} + +class _StandardFontWidth { + static const List _arialWidth = [ + 278, + 278, + 355, + 556, + 556, + 889, + 667, + 191, + 333, + 333, + 389, + 584, + 278, + 333, + 278, + 278, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 278, + 278, + 584, + 584, + 584, + 556, + 1015, + 667, + 667, + 722, + 722, + 667, + 611, + 778, + 722, + 278, + 500, + 667, + 556, + 833, + 722, + 778, + 667, + 778, + 722, + 667, + 611, + 722, + 667, + 944, + 667, + 667, + 611, + 278, + 278, + 278, + 469, + 556, + 333, + 556, + 556, + 500, + 556, + 556, + 278, + 556, + 556, + 222, + 222, + 500, + 222, + 833, + 556, + 556, + 556, + 556, + 333, + 500, + 278, + 556, + 500, + 722, + 500, + 500, + 500, + 334, + 260, + 334, + 584, + 0, + 556, + 0, + 222, + 556, + 333, + 1000, + 556, + 556, + 333, + 1000, + 667, + 333, + 1000, + 0, + 611, + 0, + 0, + 222, + 222, + 333, + 333, + 350, + 556, + 1000, + 333, + 1000, + 500, + 333, + 944, + 0, + 500, + 667, + 0, + 333, + 556, + 556, + 556, + 556, + 260, + 556, + 333, + 737, + 370, + 556, + 584, + 0, + 737, + 333, + 400, + 584, + 333, + 333, + 333, + 556, + 537, + 278, + 333, + 333, + 365, + 556, + 834, + 834, + 834, + 611, + 667, + 667, + 667, + 667, + 667, + 667, + 1000, + 722, + 667, + 667, + 667, + 667, + 278, + 278, + 278, + 278, + 722, + 722, + 778, + 778, + 778, + 778, + 778, + 584, + 778, + 722, + 722, + 722, + 722, + 667, + 667, + 611, + 556, + 556, + 556, + 556, + 556, + 556, + 889, + 500, + 556, + 556, + 556, + 556, + 278, + 278, + 278, + 278, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 584, + 611, + 556, + 556, + 556, + 556, + 500, + 556, + 500, + ]; + static const List _arialBoldWidth = [ + 278, + 333, + 474, + 556, + 556, + 889, + 722, + 238, + 333, + 333, + 389, + 584, + 278, + 333, + 278, + 278, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 556, + 333, + 333, + 584, + 584, + 584, + 611, + 975, + 722, + 722, + 722, + 722, + 667, + 611, + 778, + 722, + 278, + 556, + 722, + 611, + 833, + 722, + 778, + 667, + 778, + 722, + 667, + 611, + 722, + 667, + 944, + 667, + 667, + 611, + 333, + 278, + 333, + 584, + 556, + 333, + 556, + 611, + 556, + 611, + 556, + 333, + 611, + 611, + 278, + 278, + 556, + 278, + 889, + 611, + 611, + 611, + 611, + 389, + 556, + 333, + 611, + 556, + 778, + 556, + 556, + 500, + 389, + 280, + 389, + 584, + 0, + 556, + 0, + 278, + 556, + 500, + 1000, + 556, + 556, + 333, + 1000, + 667, + 333, + 1000, + 0, + 611, + 0, + 0, + 278, + 278, + 500, + 500, + 350, + 556, + 1000, + 333, + 1000, + 556, + 333, + 944, + 0, + 500, + 667, + 0, + 333, + 556, + 556, + 556, + 556, + 280, + 556, + 333, + 737, + 370, + 556, + 584, + 0, + 737, + 333, + 400, + 584, + 333, + 333, + 333, + 611, + 556, + 278, + 333, + 333, + 365, + 556, + 834, + 834, + 834, + 611, + 722, + 722, + 722, + 722, + 722, + 722, + 1000, + 722, + 667, + 667, + 667, + 667, + 278, + 278, + 278, + 278, + 722, + 722, + 778, + 778, + 778, + 778, + 778, + 584, + 778, + 722, + 722, + 722, + 722, + 667, + 667, + 611, + 556, + 556, + 556, + 556, + 556, + 556, + 889, + 556, + 556, + 556, + 556, + 556, + 278, + 278, + 278, + 278, + 611, + 611, + 611, + 611, + 611, + 611, + 611, + 584, + 611, + 611, + 611, + 611, + 611, + 556, + 611, + 556, + ]; + static const List _fixedWidth = [ + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + 600, + ]; + static const List _timesRomanWidth = [ + 250, + 333, + 408, + 500, + 500, + 833, + 778, + 180, + 333, + 333, + 500, + 564, + 250, + 333, + 250, + 278, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 278, + 278, + 564, + 564, + 564, + 444, + 921, + 722, + 667, + 667, + 722, + 611, + 556, + 722, + 722, + 333, + 389, + 722, + 611, + 889, + 722, + 722, + 556, + 722, + 667, + 556, + 611, + 722, + 722, + 944, + 722, + 722, + 611, + 333, + 278, + 333, + 469, + 500, + 333, + 444, + 500, + 444, + 500, + 444, + 333, + 500, + 500, + 278, + 278, + 500, + 278, + 778, + 500, + 500, + 500, + 500, + 333, + 389, + 278, + 500, + 500, + 722, + 500, + 500, + 444, + 480, + 200, + 480, + 541, + 000, + 500, + 000, + 333, + 500, + 444, + 1000, + 500, + 500, + 333, + 1000, + 556, + 333, + 889, + 0, + 611, + 000, + 000, + 333, + 333, + 444, + 444, + 350, + 500, + 1000, + 333, + 980, + 389, + 333, + 722, + 0, + 444, + 722, + 000, + 333, + 500, + 500, + 500, + 500, + 200, + 500, + 333, + 760, + 276, + 500, + 564, + 0, + 760, + 333, + 400, + 564, + 300, + 300, + 333, + 500, + 453, + 250, + 333, + 300, + 310, + 500, + 750, + 750, + 750, + 444, + 722, + 722, + 722, + 722, + 722, + 722, + 889, + 667, + 611, + 611, + 611, + 611, + 333, + 333, + 333, + 333, + 722, + 722, + 722, + 722, + 722, + 722, + 722, + 564, + 722, + 722, + 722, + 722, + 722, + 722, + 556, + 500, + 444, + 444, + 444, + 444, + 444, + 444, + 667, + 444, + 444, + 444, + 444, + 444, + 278, + 278, + 278, + 278, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 564, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + ]; + static const List _timesRomanBoldWidth = [ + 250, + 333, + 555, + 500, + 500, + 1000, + 833, + 278, + 333, + 333, + 500, + 570, + 250, + 333, + 250, + 278, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 333, + 333, + 570, + 570, + 570, + 500, + 930, + 722, + 667, + 722, + 722, + 667, + 611, + 778, + 778, + 389, + 500, + 778, + 667, + 944, + 722, + 778, + 611, + 778, + 722, + 556, + 667, + 722, + 722, + 1000, + 722, + 722, + 667, + 333, + 278, + 333, + 581, + 500, + 333, + 500, + 556, + 444, + 556, + 444, + 333, + 500, + 556, + 278, + 333, + 556, + 278, + 833, + 556, + 500, + 556, + 556, + 444, + 389, + 333, + 556, + 500, + 722, + 500, + 500, + 444, + 394, + 220, + 394, + 520, + 0, + 500, + 0, + 333, + 500, + 500, + 1000, + 500, + 500, + 333, + 1000, + 556, + 333, + 1000, + 0, + 667, + 0, + 0, + 333, + 333, + 500, + 500, + 350, + 500, + 1000, + 333, + 1000, + 389, + 333, + 722, + 0, + 444, + 722, + 0, + 333, + 500, + 500, + 500, + 500, + 220, + 500, + 333, + 747, + 300, + 500, + 570, + 0, + 747, + 333, + 400, + 570, + 300, + 300, + 333, + 556, + 540, + 250, + 333, + 300, + 330, + 500, + 750, + 750, + 750, + 500, + 722, + 722, + 722, + 722, + 722, + 722, + 1000, + 722, + 667, + 667, + 667, + 667, + 389, + 389, + 389, + 389, + 722, + 722, + 778, + 778, + 778, + 778, + 778, + 570, + 778, + 722, + 722, + 722, + 722, + 722, + 611, + 556, + 500, + 500, + 500, + 500, + 500, + 500, + 722, + 444, + 444, + 444, + 444, + 444, + 278, + 278, + 278, + 278, + 500, + 556, + 500, + 500, + 500, + 500, + 500, + 570, + 500, + 556, + 556, + 556, + 556, + 500, + 556, + 500, + ]; + static const List _timesRomanItalicWidth = [ + 250, + 333, + 420, + 500, + 500, + 833, + 778, + 214, + 333, + 333, + 500, + 675, + 250, + 333, + 250, + 278, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 333, + 333, + 675, + 675, + 675, + 500, + 920, + 611, + 611, + 667, + 722, + 611, + 611, + 722, + 722, + 333, + 444, + 667, + 556, + 833, + 667, + 722, + 611, + 722, + 611, + 500, + 556, + 722, + 611, + 833, + 611, + 556, + 556, + 389, + 278, + 389, + 422, + 500, + 333, + 500, + 500, + 444, + 500, + 444, + 278, + 500, + 500, + 278, + 278, + 444, + 278, + 722, + 500, + 500, + 500, + 500, + 389, + 389, + 278, + 500, + 444, + 667, + 444, + 444, + 389, + 400, + 275, + 400, + 541, + 0, + 500, + 0, + 333, + 500, + 556, + 889, + 500, + 500, + 333, + 1000, + 500, + 333, + 944, + 0, + 556, + 0, + 0, + 333, + 333, + 556, + 556, + 350, + 500, + 889, + 333, + 980, + 389, + 333, + 667, + 0, + 389, + 556, + 0, + 389, + 500, + 500, + 500, + 500, + 275, + 500, + 333, + 760, + 276, + 500, + 675, + 0, + 760, + 333, + 400, + 675, + 300, + 300, + 333, + 500, + 523, + 250, + 333, + 300, + 310, + 500, + 750, + 750, + 750, + 500, + 611, + 611, + 611, + 611, + 611, + 611, + 889, + 667, + 611, + 611, + 611, + 611, + 333, + 333, + 333, + 333, + 722, + 667, + 722, + 722, + 722, + 722, + 722, + 675, + 722, + 722, + 722, + 722, + 722, + 556, + 611, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 667, + 444, + 444, + 444, + 444, + 444, + 278, + 278, + 278, + 278, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 675, + 500, + 500, + 500, + 500, + 500, + 444, + 500, + 444, + ]; + static const List _timesRomanBoldItalicWidth = [ + 250, + 389, + 555, + 500, + 500, + 833, + 778, + 278, + 333, + 333, + 500, + 570, + 250, + 333, + 250, + 278, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 333, + 333, + 570, + 570, + 570, + 500, + 832, + 667, + 667, + 667, + 722, + 667, + 667, + 722, + 778, + 389, + 500, + 667, + 611, + 889, + 722, + 722, + 611, + 722, + 667, + 556, + 611, + 722, + 667, + 889, + 667, + 611, + 611, + 333, + 278, + 333, + 570, + 500, + 333, + 500, + 500, + 444, + 500, + 444, + 333, + 500, + 556, + 278, + 278, + 500, + 278, + 778, + 556, + 500, + 500, + 500, + 389, + 389, + 278, + 556, + 444, + 667, + 500, + 444, + 389, + 348, + 220, + 348, + 570, + 0, + 500, + 0, + 333, + 500, + 500, + 1000, + 500, + 500, + 333, + 1000, + 556, + 333, + 944, + 0, + 611, + 0, + 0, + 333, + 333, + 500, + 500, + 350, + 500, + 1000, + 333, + 1000, + 389, + 333, + 722, + 0, + 389, + 611, + 0, + 389, + 500, + 500, + 500, + 500, + 220, + 500, + 333, + 747, + 266, + 500, + 606, + 0, + 747, + 333, + 400, + 570, + 300, + 300, + 333, + 576, + 500, + 250, + 333, + 300, + 300, + 500, + 750, + 750, + 750, + 500, + 667, + 667, + 667, + 667, + 667, + 667, + 944, + 667, + 667, + 667, + 667, + 667, + 389, + 389, + 389, + 389, + 722, + 722, + 722, + 722, + 722, + 722, + 722, + 570, + 722, + 722, + 722, + 722, + 722, + 611, + 611, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 722, + 444, + 444, + 444, + 444, + 444, + 278, + 278, + 278, + 278, + 500, + 556, + 500, + 500, + 500, + 500, + 500, + 570, + 500, + 556, + 556, + 556, + 556, + 444, + 500, + 444, + ]; + static const List _symbolWidth = [ + 250, + 333, + 713, + 500, + 549, + 833, + 778, + 439, + 333, + 333, + 500, + 549, + 250, + 549, + 250, + 278, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 500, + 278, + 278, + 549, + 549, + 549, + 444, + 549, + 722, + 667, + 722, + 612, + 611, + 763, + 603, + 722, + 333, + 631, + 722, + 686, + 889, + 722, + 722, + 768, + 741, + 556, + 592, + 611, + 690, + 439, + 768, + 645, + 795, + 611, + 333, + 863, + 333, + 658, + 500, + 500, + 631, + 549, + 549, + 494, + 439, + 521, + 411, + 603, + 329, + 603, + 549, + 549, + 576, + 521, + 549, + 549, + 521, + 549, + 603, + 439, + 576, + 713, + 686, + 493, + 686, + 494, + 480, + 200, + 480, + 549, + 750, + 620, + 247, + 549, + 167, + 713, + 500, + 753, + 753, + 753, + 753, + 1042, + 987, + 603, + 987, + 603, + 400, + 549, + 411, + 549, + 549, + 713, + 494, + 460, + 549, + 549, + 549, + 549, + 1000, + 603, + 1000, + 658, + 823, + 686, + 795, + 987, + 768, + 768, + 823, + 768, + 768, + 713, + 713, + 713, + 713, + 713, + 713, + 713, + 768, + 713, + 790, + 790, + 890, + 823, + 549, + 250, + 713, + 603, + 603, + 1042, + 987, + 603, + 987, + 603, + 494, + 329, + 790, + 790, + 786, + 713, + 384, + 384, + 384, + 384, + 384, + 384, + 494, + 494, + 494, + 494, + 329, + 274, + 686, + 686, + 686, + 384, + 384, + 384, + 384, + 384, + 384, + 494, + 494, + 494, + -1, + ]; + static const List _zapfDingbatsWidth = [ + 278, + 974, + 961, + 974, + 980, + 719, + 789, + 790, + 791, + 690, + 960, + 939, + 549, + 855, + 911, + 933, + 911, + 945, + 974, + 755, + 846, + 762, + 761, + 571, + 677, + 763, + 760, + 759, + 754, + 494, + 552, + 537, + 577, + 692, + 786, + 788, + 788, + 790, + 793, + 794, + 816, + 823, + 789, + 841, + 823, + 833, + 816, + 831, + 923, + 744, + 723, + 749, + 790, + 792, + 695, + 776, + 768, + 792, + 759, + 707, + 708, + 682, + 701, + 826, + 815, + 789, + 789, + 707, + 687, + 696, + 689, + 786, + 787, + 713, + 791, + 785, + 791, + 873, + 761, + 762, + 762, + 759, + 759, + 892, + 892, + 788, + 784, + 438, + 138, + 277, + 415, + 392, + 392, + 668, + 668, + 390, + 390, + 317, + 317, + 276, + 276, + 509, + 509, + 410, + 410, + 234, + 234, + 334, + 334, + 732, + 544, + 544, + 910, + 667, + 760, + 760, + 776, + 595, + 694, + 626, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 788, + 894, + 838, + 1016, + 458, + 748, + 924, + 748, + 918, + 927, + 928, + 928, + 834, + 873, + 828, + 924, + 924, + 917, + 930, + 931, + 463, + 883, + 836, + 836, + 867, + 867, + 696, + 696, + 874, + 874, + 760, + 946, + 771, + 865, + 771, + 888, + 967, + 888, + 831, + 873, + 927, + 970, + 918, + ]; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_format.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_format.dart index 8a729da0f..3f4883047 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_format.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_format.dart @@ -1,376 +1,376 @@ -import '../enums.dart'; -import 'enums.dart'; - -/// Represents the text layout information on PDF -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// //Create a new PDF string format instance. -/// format: PdfStringFormat( -/// alignment: PdfTextAlignment.left, -/// lineAlignment: PdfVerticalAlignment.top, -/// textDirection: PdfTextDirection.leftToRight, -/// characterSpacing: 0.5, -/// wordSpacing: 0.5, -/// lineSpacing: 0.5, -/// subSuperscript: PdfSubSuperscript.superscript, -/// paragraphIndent: 10, -/// measureTrailingSpaces: true, -/// wordWrap: PdfWordWrapType.word)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Close the document. -/// document.dispose(); -/// ``` -class PdfStringFormat { - //Constructor - /// Initializes a new instance of the [PdfStringFormat] class - /// with horizontal alignment and vertical alignment of text. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// //Create a new PDF string format instance. - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.left, - /// lineAlignment: PdfVerticalAlignment.top, - /// textDirection: PdfTextDirection.leftToRight, - /// characterSpacing: 0.5, - /// wordSpacing: 0.5, - /// lineSpacing: 0.5, - /// subSuperscript: PdfSubSuperscript.superscript, - /// paragraphIndent: 10, - /// measureTrailingSpaces: true, - /// wordWrap: PdfWordWrapType.word)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfStringFormat({ - PdfTextAlignment alignment = PdfTextAlignment.left, - PdfVerticalAlignment lineAlignment = PdfVerticalAlignment.top, - PdfTextDirection textDirection = PdfTextDirection.none, - double characterSpacing = 0, - double wordSpacing = 0, - double lineSpacing = 0, - PdfSubSuperscript subSuperscript = PdfSubSuperscript.none, - double paragraphIndent = 0, - bool measureTrailingSpaces = false, - PdfWordWrapType wordWrap = PdfWordWrapType.word, - }) { - _helper = PdfStringFormatHelper(); - _initialize( - alignment, - lineAlignment, - textDirection, - characterSpacing, - wordSpacing, - lineSpacing, - subSuperscript, - paragraphIndent, - measureTrailingSpaces, - wordWrap, - ); - } - - //Fields - late PdfStringFormatHelper _helper; - - /// Gets and sets Horizontal text alignment. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(alignment: PdfTextAlignment.left)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late PdfTextAlignment alignment; - - /// Gets and sets Vertical text alignment. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.top)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late PdfVerticalAlignment lineAlignment; - - /// Gets and sets text rendering direction. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(textDirection: PdfTextDirection.rightToLeft)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late PdfTextDirection textDirection; - - /// Gets and sets Character spacing value. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Draw the text. - /// document.pages - /// .add() - /// .graphics - /// .drawString('Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(characterSpacing: 0.5)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late double characterSpacing; - - /// Gets and sets Word spacing value. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Draw the text. - /// document.pages - /// .add() - /// .graphics - /// .drawString('Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(wordSpacing: 0.5)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late double wordSpacing; - - /// Gets and sets Text leading or Line spacing. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Draw the text. - /// document.pages - /// .add() - /// .graphics - /// .drawString('Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(lineSpacing: 0.5)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late double lineSpacing; - - /// Gets and sets if the text should be a part of the current clipping path. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// bounds: Rect.fromLTWH(0, 0, 200, 100), - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle, - /// characterSpacing: 1) - /// //Set the clip path. - /// ..clipPath = true); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - bool clipPath = false; - - /// Gets and sets whether the text is in subscript or superscript mode. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// bounds: Rect.fromLTWH(0, 0, 200, 100), - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle, - /// characterSpacing: 1, - /// subSuperscript: PdfSubSuperscript.subscript)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late PdfSubSuperscript subSuperscript; - - /// Gets and sets whether entire lines are laid out in the - /// formatting rectangle only or not. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// bounds: Rect.fromLTWH(0, 0, 200, 100), - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle, - /// characterSpacing: 1, - /// lineSpacing: 1.1, - /// measureTrailingSpaces: true, - /// paragraphIndent: 2.1, - /// wordSpacing: 1.5, - /// wordWrap: PdfWordWrapType.word, - /// subSuperscript: PdfSubSuperscript.subscript) - /// ..clipPath = true - /// ..noClip = true - /// //Set line limit. - /// ..lineLimit = true); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - bool lineLimit = true; - - /// Gets and sets whether spaces at the end of the line should be - /// left or removed. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(measureTrailingSpaces: true)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late bool measureTrailingSpaces; - - /// Gets and sets whether the text region should be clipped or not. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// bounds: Rect.fromLTWH(0, 0, 200, 100), - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.middle, - /// characterSpacing: 1, - /// lineSpacing: 1.1, - /// measureTrailingSpaces: true, - /// paragraphIndent: 2.1, - /// wordSpacing: 1.5, - /// wordWrap: PdfWordWrapType.word, - /// subSuperscript: PdfSubSuperscript.subscript) - /// ..clipPath = true - /// //Set no clip. - /// ..noClip = true - /// ..lineLimit = true); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - bool noClip = false; - - /// Gets and sets text wrapping type. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(wordWrap: PdfWordWrapType.word)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - late PdfWordWrapType wordWrap; - - //Indent of the first line in the paragraph. - late double _paragraphIndent; - - //Properties - /// Gets or sets the indent of the first line in the paragraph. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// format: PdfStringFormat(paragraphIndent: 2.1)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - double get paragraphIndent => _paragraphIndent; - set paragraphIndent(double value) { - _paragraphIndent = value; - _helper.firstLineIndent = value; - } - - //Implementation - void _initialize( - PdfTextAlignment textAlignment, - PdfVerticalAlignment verticalAlignment, - PdfTextDirection textDirection, - double characterSpacing, - double wordSpacing, - double lineSpacing, - PdfSubSuperscript subSuperscript, - double paragraphIndent, - bool measureTrailingSpaces, - PdfWordWrapType wordWrap, - ) { - alignment = textAlignment; - lineAlignment = verticalAlignment; - this.characterSpacing = characterSpacing; - this.lineSpacing = lineSpacing; - this.measureTrailingSpaces = measureTrailingSpaces; - this.paragraphIndent = paragraphIndent; - this.subSuperscript = subSuperscript; - this.textDirection = textDirection; - this.wordSpacing = wordSpacing; - this.wordWrap = wordWrap; - } -} - -/// [PdfStringFormat] helper -class PdfStringFormatHelper { - /// internal method - static PdfStringFormatHelper getHelper(PdfStringFormat format) { - return format._helper; - } - - /// internal field - double scalingFactor = 100; - - /// internal field - late double firstLineIndent; -} +import '../enums.dart'; +import 'enums.dart'; + +/// Represents the text layout information on PDF +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// //Create a new PDF string format instance. +/// format: PdfStringFormat( +/// alignment: PdfTextAlignment.left, +/// lineAlignment: PdfVerticalAlignment.top, +/// textDirection: PdfTextDirection.leftToRight, +/// characterSpacing: 0.5, +/// wordSpacing: 0.5, +/// lineSpacing: 0.5, +/// subSuperscript: PdfSubSuperscript.superscript, +/// paragraphIndent: 10, +/// measureTrailingSpaces: true, +/// wordWrap: PdfWordWrapType.word)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Close the document. +/// document.dispose(); +/// ``` +class PdfStringFormat { + //Constructor + /// Initializes a new instance of the [PdfStringFormat] class + /// with horizontal alignment and vertical alignment of text. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// //Create a new PDF string format instance. + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.left, + /// lineAlignment: PdfVerticalAlignment.top, + /// textDirection: PdfTextDirection.leftToRight, + /// characterSpacing: 0.5, + /// wordSpacing: 0.5, + /// lineSpacing: 0.5, + /// subSuperscript: PdfSubSuperscript.superscript, + /// paragraphIndent: 10, + /// measureTrailingSpaces: true, + /// wordWrap: PdfWordWrapType.word)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfStringFormat({ + PdfTextAlignment alignment = PdfTextAlignment.left, + PdfVerticalAlignment lineAlignment = PdfVerticalAlignment.top, + PdfTextDirection textDirection = PdfTextDirection.none, + double characterSpacing = 0, + double wordSpacing = 0, + double lineSpacing = 0, + PdfSubSuperscript subSuperscript = PdfSubSuperscript.none, + double paragraphIndent = 0, + bool measureTrailingSpaces = false, + PdfWordWrapType wordWrap = PdfWordWrapType.word, + }) { + _helper = PdfStringFormatHelper(); + _initialize( + alignment, + lineAlignment, + textDirection, + characterSpacing, + wordSpacing, + lineSpacing, + subSuperscript, + paragraphIndent, + measureTrailingSpaces, + wordWrap, + ); + } + + //Fields + late PdfStringFormatHelper _helper; + + /// Gets and sets Horizontal text alignment. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(alignment: PdfTextAlignment.left)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late PdfTextAlignment alignment; + + /// Gets and sets Vertical text alignment. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(lineAlignment: PdfVerticalAlignment.top)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late PdfVerticalAlignment lineAlignment; + + /// Gets and sets text rendering direction. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(textDirection: PdfTextDirection.rightToLeft)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late PdfTextDirection textDirection; + + /// Gets and sets Character spacing value. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Draw the text. + /// document.pages + /// .add() + /// .graphics + /// .drawString('Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(characterSpacing: 0.5)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late double characterSpacing; + + /// Gets and sets Word spacing value. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Draw the text. + /// document.pages + /// .add() + /// .graphics + /// .drawString('Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(wordSpacing: 0.5)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late double wordSpacing; + + /// Gets and sets Text leading or Line spacing. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Draw the text. + /// document.pages + /// .add() + /// .graphics + /// .drawString('Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(lineSpacing: 0.5)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late double lineSpacing; + + /// Gets and sets if the text should be a part of the current clipping path. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// bounds: Rect.fromLTWH(0, 0, 200, 100), + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle, + /// characterSpacing: 1) + /// //Set the clip path. + /// ..clipPath = true); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + bool clipPath = false; + + /// Gets and sets whether the text is in subscript or superscript mode. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// bounds: Rect.fromLTWH(0, 0, 200, 100), + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle, + /// characterSpacing: 1, + /// subSuperscript: PdfSubSuperscript.subscript)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late PdfSubSuperscript subSuperscript; + + /// Gets and sets whether entire lines are laid out in the + /// formatting rectangle only or not. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// bounds: Rect.fromLTWH(0, 0, 200, 100), + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle, + /// characterSpacing: 1, + /// lineSpacing: 1.1, + /// measureTrailingSpaces: true, + /// paragraphIndent: 2.1, + /// wordSpacing: 1.5, + /// wordWrap: PdfWordWrapType.word, + /// subSuperscript: PdfSubSuperscript.subscript) + /// ..clipPath = true + /// ..noClip = true + /// //Set line limit. + /// ..lineLimit = true); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + bool lineLimit = true; + + /// Gets and sets whether spaces at the end of the line should be + /// left or removed. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(measureTrailingSpaces: true)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late bool measureTrailingSpaces; + + /// Gets and sets whether the text region should be clipped or not. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// bounds: Rect.fromLTWH(0, 0, 200, 100), + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.middle, + /// characterSpacing: 1, + /// lineSpacing: 1.1, + /// measureTrailingSpaces: true, + /// paragraphIndent: 2.1, + /// wordSpacing: 1.5, + /// wordWrap: PdfWordWrapType.word, + /// subSuperscript: PdfSubSuperscript.subscript) + /// ..clipPath = true + /// //Set no clip. + /// ..noClip = true + /// ..lineLimit = true); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + bool noClip = false; + + /// Gets and sets text wrapping type. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(wordWrap: PdfWordWrapType.word)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + late PdfWordWrapType wordWrap; + + //Indent of the first line in the paragraph. + late double _paragraphIndent; + + //Properties + /// Gets or sets the indent of the first line in the paragraph. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// format: PdfStringFormat(paragraphIndent: 2.1)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + double get paragraphIndent => _paragraphIndent; + set paragraphIndent(double value) { + _paragraphIndent = value; + _helper.firstLineIndent = value; + } + + //Implementation + void _initialize( + PdfTextAlignment textAlignment, + PdfVerticalAlignment verticalAlignment, + PdfTextDirection textDirection, + double characterSpacing, + double wordSpacing, + double lineSpacing, + PdfSubSuperscript subSuperscript, + double paragraphIndent, + bool measureTrailingSpaces, + PdfWordWrapType wordWrap, + ) { + alignment = textAlignment; + lineAlignment = verticalAlignment; + this.characterSpacing = characterSpacing; + this.lineSpacing = lineSpacing; + this.measureTrailingSpaces = measureTrailingSpaces; + this.paragraphIndent = paragraphIndent; + this.subSuperscript = subSuperscript; + this.textDirection = textDirection; + this.wordSpacing = wordSpacing; + this.wordWrap = wordWrap; + } +} + +/// [PdfStringFormat] helper +class PdfStringFormatHelper { + /// internal method + static PdfStringFormatHelper getHelper(PdfStringFormat format) { + return format._helper; + } + + /// internal field + double scalingFactor = 100; + + /// internal field + late double firstLineIndent; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layout_result.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layout_result.dart index 7e8f4f08f..6cce20146 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layout_result.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layout_result.dart @@ -1,30 +1,30 @@ -import '../../drawing/drawing.dart'; -import 'pdf_string_layouter.dart'; - -/// internal class -class PdfStringLayoutResult { - /// internal constructor - PdfStringLayoutResult() { - lineHeight = 0; - size = PdfSize.empty; - } - - /// internal field - late double lineHeight; - - /// internal field - late PdfSize size; - - /// internal field - List? lines; - - /// internal field - //ignore:unused_field - String? remainder; - - /// internal property - bool get isEmpty => lines == null || (lines != null && lines!.isEmpty); - - /// internal property - int get lineCount => (!isEmpty) ? lines!.length : 0; -} +import '../../drawing/drawing.dart'; +import 'pdf_string_layouter.dart'; + +/// internal class +class PdfStringLayoutResult { + /// internal constructor + PdfStringLayoutResult() { + lineHeight = 0; + size = PdfSize.empty; + } + + /// internal field + late double lineHeight; + + /// internal field + late PdfSize size; + + /// internal field + List? lines; + + /// internal field + //ignore:unused_field + String? remainder; + + /// internal property + bool get isEmpty => lines == null || (lines != null && lines!.isEmpty); + + /// internal property + int get lineCount => (!isEmpty) ? lines!.length : 0; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layouter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layouter.dart index 8c787352e..714b18eba 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layouter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_string_layouter.dart @@ -1,398 +1,398 @@ -import '../../drawing/drawing.dart'; -import '../enums.dart'; -import 'enums.dart'; -import 'pdf_font.dart'; -import 'pdf_string_format.dart'; -import 'pdf_string_layout_result.dart'; -import 'string_tokenizer.dart'; - -/// Class lay outing the text. -class PdfStringLayouter { - //Constructor - /// internal constructor - PdfStringLayouter() { - _size = PdfSize.empty; - _rectangle = PdfRectangle.empty; - } - - //Fields - //ignore: unused_field - String? _text; - PdfFont? _font; - PdfStringFormat? _format; - late PdfSize _size; - late PdfRectangle _rectangle; - late double _pageHeight; - StringTokenizer? _reader; - int _tabOccuranceCount = 0; - bool _isTabReplaced = false; - - //Implementation - /// internal method - PdfStringLayoutResult layout( - String text, - PdfFont font, - PdfStringFormat? format, { - double? width, - double? height, - PdfRectangle? bounds, - double? pageHeight, - }) { - _text = text; - _font = font; - _format = format; - _size = bounds == null ? PdfSize(width!, height!) : bounds.size; - _rectangle = bounds ?? PdfRectangle(0, 0, width!, height!); - _pageHeight = pageHeight ?? 0; - _reader = StringTokenizer(text); - final PdfStringLayoutResult result = _doLayout(); - _clear(); - return result; - } - - PdfStringLayoutResult _doLayout() { - final PdfStringLayoutResult result = PdfStringLayoutResult(); - PdfStringLayoutResult lineResult = PdfStringLayoutResult(); - final List lines = []; - String? line = _reader!.peekLine(); - double? lineIndent = _getLineIndent(true); - while (line != null) { - lineResult = _layoutLine(line, lineIndent!); - int? numSymbolsInserted = 0; - final Map returnedValue = - _copyToResult(result, lineResult, lines, numSymbolsInserted) - as Map; - final bool success = returnedValue['success'] as bool; - numSymbolsInserted = returnedValue['numInserted'] as int?; - if (!success) { - _reader!.read(numSymbolsInserted); - break; - } - _reader!.readLine(); - line = _reader!.peekLine(); - lineIndent = _getLineIndent(false); - } - _finalizeResult(result, lines); - return result; - } - - void _finalizeResult(PdfStringLayoutResult result, List lines) { - result.lines = lines.toList(); - result.lineHeight = _getLineHeight(); - if (!_reader!.isEndOfFile) { - result.remainder = _reader!.readToEnd(); - } - lines.length = 0; - } - - double? _getLineIndent(bool firstLine) { - double? lineIndent = 0; - if (_format != null) { - lineIndent = - firstLine - ? PdfStringFormatHelper.getHelper(_format!).firstLineIndent - : _format!.paragraphIndent; - lineIndent = - (_size.width > 0) - ? (_size.width <= lineIndent ? _size.width : lineIndent) - : lineIndent; - } - return lineIndent; - } - - PdfStringLayoutResult _layoutLine(String line, double lineIndent) { - if (line.contains('\t')) { - _tabOccuranceCount = 0; - int i = 0; - const String tab = '\t'; - while ((i = line.indexOf(tab, i)) != -1) { - i += tab.length; - _tabOccuranceCount++; - } - line = line.replaceAll('\t', ' '); - _isTabReplaced = true; - } - final PdfStringLayoutResult lineResult = PdfStringLayoutResult(); - lineResult.lineHeight = _getLineHeight(); - final List lines = []; - final double maxWidth = _size.width; - double lineWidth = _getLineWidth(line) + lineIndent; - LineType lineType = LineType.firstParagraphLine; - bool readWord = true; - if (maxWidth <= 0 || - lineWidth.roundToDouble() <= maxWidth.roundToDouble()) { - _addToLineResult( - lineResult, - lines, - line, - lineWidth, - getLineTypeValue(LineType.newLineBreak)! | getLineTypeValue(lineType)!, - ); - } else { - String builder = ''; - String curLine = ''; - lineWidth = lineIndent; - double curIndent = lineIndent; - final StringTokenizer reader = StringTokenizer(line); - String? word = reader.peekWord(); - if (word!.length != reader.length) { - if (word == ' ') { - curLine = curLine + word; - builder = builder + word; - reader.position = reader.position! + 1; - word = reader.peekWord(); - } - } - while (word != null) { - curLine += word; - double curLineWidth = _getLineWidth(curLine) + curIndent; - if (curLine == ' ') { - curLine = ''; - curLineWidth = 0; - } - if (curLineWidth > maxWidth) { - if (_getWrapType() == PdfWordWrapType.none) { - break; - } - if (curLine.length == word.length) { - if (_getWrapType() == PdfWordWrapType.wordOnly) { - lineResult.remainder = line.substring(reader.position!); - break; - } else if (curLine.length == 1) { - builder += word; - break; - } else { - readWord = false; - curLine = ''; - word = reader.peek(); - continue; - } - } else { - if (_getWrapType() != PdfWordWrapType.character || !readWord) { - final String ln = builder; - if (ln != ' ') { - _addToLineResult( - lineResult, - lines, - ln, - lineWidth, - getLineTypeValue(LineType.layoutBreak)! | - getLineTypeValue(lineType)!, - ); - } - curLine = ''; - builder = ''; - lineWidth = 0; - curIndent = 0; - curLineWidth = 0; - lineType = LineType.none; - word = readWord ? word : reader.peekWord()!; - readWord = true; - } else { - readWord = false; - curLine = builder; - word = reader.peek(); - } - continue; - } - } - builder += word; - lineWidth = curLineWidth; - if (readWord) { - reader.readWord(); - word = reader.peekWord(); - } else { - reader.read(); - word = reader.peek(); - } - } - if (builder.isNotEmpty) { - final String ln = builder; - _addToLineResult( - lineResult, - lines, - ln, - lineWidth, - getLineTypeValue(LineType.newLineBreak)! | - getLineTypeValue(LineType.lastParagraphLine)!, - ); - } - reader.close(); - } - lineResult.lines = lines.toList(); - lines.length = 0; - return lineResult; - } - - void _addToLineResult( - PdfStringLayoutResult lineResult, - List lines, - String line, - double lineWidth, - int breakType, - ) { - final LineInfo info = LineInfo(); - info.text = line; - info.width = lineWidth; - info.lineType = breakType; - info.lineTypeList = _getLineType(breakType); - lines.add(info); - final PdfSize size = lineResult.size; - size.height += _getLineHeight(); - size.width = size.width >= lineWidth ? size.width : lineWidth; - lineResult.size = size; - } - - List _getLineType(int breakType) { - final List result = []; - if ((breakType & getLineTypeValue(LineType.none)!) > 0) { - result.add(LineType.none); - } - if ((breakType & getLineTypeValue(LineType.newLineBreak)!) > 0) { - result.add(LineType.newLineBreak); - } - if ((breakType & getLineTypeValue(LineType.layoutBreak)!) > 0) { - result.add(LineType.layoutBreak); - } - if (breakType & getLineTypeValue(LineType.firstParagraphLine)! > 0) { - result.add(LineType.firstParagraphLine); - } - if (breakType & getLineTypeValue(LineType.lastParagraphLine)! > 0) { - result.add(LineType.lastParagraphLine); - } - return result; - } - - double _getLineHeight() { - return (_format != null && _format!.lineSpacing != 0) - ? _format!.lineSpacing + _font!.height - : _font!.height; - } - - double _getLineWidth(String line) { - return PdfFontHelper.getLineWidth(_font!, line, _format); - } - - PdfWordWrapType? _getWrapType() { - return _format != null ? _format!.wordWrap : PdfWordWrapType.word; - } - - dynamic _copyToResult( - PdfStringLayoutResult result, - PdfStringLayoutResult lineResult, - List lines, - int? numInserted, - ) { - bool success = true; - final bool allowPartialLines = _format != null && !_format!.lineLimit; - double? height = result.size.height; - double? maxHeight = _size.height; - if ((_pageHeight > 0) && (maxHeight + _rectangle.y > _pageHeight)) { - maxHeight = _rectangle.y - _pageHeight; - maxHeight = maxHeight >= -maxHeight ? maxHeight : -maxHeight; - } - numInserted = 0; - if (lineResult.lines != null) { - for (int i = 0; i < lineResult.lines!.length; i++) { - final double expHeight = height! + lineResult.lineHeight; - if (expHeight <= maxHeight || - maxHeight <= 0 || - allowPartialLines || - (expHeight - maxHeight).abs() < 0.001) { - LineInfo info = lineResult.lines![i]; - if (!_isTabReplaced) { - numInserted = numInserted! + info.text!.length; - } else { - numInserted = - numInserted! + info.text!.length - (_tabOccuranceCount * 3); - _isTabReplaced = false; - } - info = _trimLine(info, lines.isEmpty); - lines.add(info); - final PdfSize size = result.size; - size.width = (size.width >= info.width!) ? size.width : info.width!; - result.size = size; - height = expHeight; - } else { - success = false; - break; - } - } - } - if (height != result.size.height) { - final PdfSize size = result.size; - size.height = height!; - result.size = size; - } - return {'success': success, 'numInserted': numInserted}; - } - - LineInfo _trimLine(LineInfo info, bool firstLine) { - String line = info.text.toString(); - double? lineWidth = info.width; - final bool start = - _format == null || - _format!.textDirection != PdfTextDirection.rightToLeft; - if (!info.lineTypeList.contains(LineType.firstParagraphLine)) { - line = start ? line.trimLeft() : line.trimRight(); - } - if (_format == null || !_format!.measureTrailingSpaces) { - line = start ? line.trimRight() : line.trimLeft(); - } - if (line.length != info.text!.length) { - lineWidth = _getLineWidth(line); - if (info.lineType & getLineTypeValue(LineType.firstParagraphLine)! > 0) { - lineWidth += _getLineIndent(firstLine)!; - } - } - info.text = line; - info.width = lineWidth; - return info; - } - - void _clear() { - _font = null; - _format = null; - _reader!.close(); - _reader = null; - _text = null; - } - - /// internal method - static int? getLineTypeValue(LineType type) { - int? value; - switch (type) { - case LineType.none: - value = 0; - break; - case LineType.newLineBreak: - value = 0x0001; - break; - case LineType.layoutBreak: - value = 0x0002; - break; - case LineType.firstParagraphLine: - value = 0x0004; - break; - case LineType.lastParagraphLine: - value = 0x0008; - break; - } - return value; - } -} - -/// Provides a line information -class LineInfo { - /// internal field - String? text; - - /// internal field - double? width; - - /// internal field - List lineTypeList = []; - - /// internal field - late int lineType; -} +import '../../drawing/drawing.dart'; +import '../enums.dart'; +import 'enums.dart'; +import 'pdf_font.dart'; +import 'pdf_string_format.dart'; +import 'pdf_string_layout_result.dart'; +import 'string_tokenizer.dart'; + +/// Class lay outing the text. +class PdfStringLayouter { + //Constructor + /// internal constructor + PdfStringLayouter() { + _size = PdfSize.empty; + _rectangle = PdfRectangle.empty; + } + + //Fields + //ignore: unused_field + String? _text; + PdfFont? _font; + PdfStringFormat? _format; + late PdfSize _size; + late PdfRectangle _rectangle; + late double _pageHeight; + StringTokenizer? _reader; + int _tabOccuranceCount = 0; + bool _isTabReplaced = false; + + //Implementation + /// internal method + PdfStringLayoutResult layout( + String text, + PdfFont font, + PdfStringFormat? format, { + double? width, + double? height, + PdfRectangle? bounds, + double? pageHeight, + }) { + _text = text; + _font = font; + _format = format; + _size = bounds == null ? PdfSize(width!, height!) : bounds.size; + _rectangle = bounds ?? PdfRectangle(0, 0, width!, height!); + _pageHeight = pageHeight ?? 0; + _reader = StringTokenizer(text); + final PdfStringLayoutResult result = _doLayout(); + _clear(); + return result; + } + + PdfStringLayoutResult _doLayout() { + final PdfStringLayoutResult result = PdfStringLayoutResult(); + PdfStringLayoutResult lineResult = PdfStringLayoutResult(); + final List lines = []; + String? line = _reader!.peekLine(); + double? lineIndent = _getLineIndent(true); + while (line != null) { + lineResult = _layoutLine(line, lineIndent!); + int? numSymbolsInserted = 0; + final Map returnedValue = + _copyToResult(result, lineResult, lines, numSymbolsInserted) + as Map; + final bool success = returnedValue['success'] as bool; + numSymbolsInserted = returnedValue['numInserted'] as int?; + if (!success) { + _reader!.read(numSymbolsInserted); + break; + } + _reader!.readLine(); + line = _reader!.peekLine(); + lineIndent = _getLineIndent(false); + } + _finalizeResult(result, lines); + return result; + } + + void _finalizeResult(PdfStringLayoutResult result, List lines) { + result.lines = lines.toList(); + result.lineHeight = _getLineHeight(); + if (!_reader!.isEndOfFile) { + result.remainder = _reader!.readToEnd(); + } + lines.length = 0; + } + + double? _getLineIndent(bool firstLine) { + double? lineIndent = 0; + if (_format != null) { + lineIndent = + firstLine + ? PdfStringFormatHelper.getHelper(_format!).firstLineIndent + : _format!.paragraphIndent; + lineIndent = + (_size.width > 0) + ? (_size.width <= lineIndent ? _size.width : lineIndent) + : lineIndent; + } + return lineIndent; + } + + PdfStringLayoutResult _layoutLine(String line, double lineIndent) { + if (line.contains('\t')) { + _tabOccuranceCount = 0; + int i = 0; + const String tab = '\t'; + while ((i = line.indexOf(tab, i)) != -1) { + i += tab.length; + _tabOccuranceCount++; + } + line = line.replaceAll('\t', ' '); + _isTabReplaced = true; + } + final PdfStringLayoutResult lineResult = PdfStringLayoutResult(); + lineResult.lineHeight = _getLineHeight(); + final List lines = []; + final double maxWidth = _size.width; + double lineWidth = _getLineWidth(line) + lineIndent; + LineType lineType = LineType.firstParagraphLine; + bool readWord = true; + if (maxWidth <= 0 || + lineWidth.roundToDouble() <= maxWidth.roundToDouble()) { + _addToLineResult( + lineResult, + lines, + line, + lineWidth, + getLineTypeValue(LineType.newLineBreak)! | getLineTypeValue(lineType)!, + ); + } else { + String builder = ''; + String curLine = ''; + lineWidth = lineIndent; + double curIndent = lineIndent; + final StringTokenizer reader = StringTokenizer(line); + String? word = reader.peekWord(); + if (word!.length != reader.length) { + if (word == ' ') { + curLine = curLine + word; + builder = builder + word; + reader.position = reader.position! + 1; + word = reader.peekWord(); + } + } + while (word != null) { + curLine += word; + double curLineWidth = _getLineWidth(curLine) + curIndent; + if (curLine == ' ') { + curLine = ''; + curLineWidth = 0; + } + if (curLineWidth > maxWidth) { + if (_getWrapType() == PdfWordWrapType.none) { + break; + } + if (curLine.length == word.length) { + if (_getWrapType() == PdfWordWrapType.wordOnly) { + lineResult.remainder = line.substring(reader.position!); + break; + } else if (curLine.length == 1) { + builder += word; + break; + } else { + readWord = false; + curLine = ''; + word = reader.peek(); + continue; + } + } else { + if (_getWrapType() != PdfWordWrapType.character || !readWord) { + final String ln = builder; + if (ln != ' ') { + _addToLineResult( + lineResult, + lines, + ln, + lineWidth, + getLineTypeValue(LineType.layoutBreak)! | + getLineTypeValue(lineType)!, + ); + } + curLine = ''; + builder = ''; + lineWidth = 0; + curIndent = 0; + curLineWidth = 0; + lineType = LineType.none; + word = readWord ? word : reader.peekWord()!; + readWord = true; + } else { + readWord = false; + curLine = builder; + word = reader.peek(); + } + continue; + } + } + builder += word; + lineWidth = curLineWidth; + if (readWord) { + reader.readWord(); + word = reader.peekWord(); + } else { + reader.read(); + word = reader.peek(); + } + } + if (builder.isNotEmpty) { + final String ln = builder; + _addToLineResult( + lineResult, + lines, + ln, + lineWidth, + getLineTypeValue(LineType.newLineBreak)! | + getLineTypeValue(LineType.lastParagraphLine)!, + ); + } + reader.close(); + } + lineResult.lines = lines.toList(); + lines.length = 0; + return lineResult; + } + + void _addToLineResult( + PdfStringLayoutResult lineResult, + List lines, + String line, + double lineWidth, + int breakType, + ) { + final LineInfo info = LineInfo(); + info.text = line; + info.width = lineWidth; + info.lineType = breakType; + info.lineTypeList = _getLineType(breakType); + lines.add(info); + final PdfSize size = lineResult.size; + size.height += _getLineHeight(); + size.width = size.width >= lineWidth ? size.width : lineWidth; + lineResult.size = size; + } + + List _getLineType(int breakType) { + final List result = []; + if ((breakType & getLineTypeValue(LineType.none)!) > 0) { + result.add(LineType.none); + } + if ((breakType & getLineTypeValue(LineType.newLineBreak)!) > 0) { + result.add(LineType.newLineBreak); + } + if ((breakType & getLineTypeValue(LineType.layoutBreak)!) > 0) { + result.add(LineType.layoutBreak); + } + if (breakType & getLineTypeValue(LineType.firstParagraphLine)! > 0) { + result.add(LineType.firstParagraphLine); + } + if (breakType & getLineTypeValue(LineType.lastParagraphLine)! > 0) { + result.add(LineType.lastParagraphLine); + } + return result; + } + + double _getLineHeight() { + return (_format != null && _format!.lineSpacing != 0) + ? _format!.lineSpacing + _font!.height + : _font!.height; + } + + double _getLineWidth(String line) { + return PdfFontHelper.getLineWidth(_font!, line, _format); + } + + PdfWordWrapType? _getWrapType() { + return _format != null ? _format!.wordWrap : PdfWordWrapType.word; + } + + dynamic _copyToResult( + PdfStringLayoutResult result, + PdfStringLayoutResult lineResult, + List lines, + int? numInserted, + ) { + bool success = true; + final bool allowPartialLines = _format != null && !_format!.lineLimit; + double? height = result.size.height; + double? maxHeight = _size.height; + if ((_pageHeight > 0) && (maxHeight + _rectangle.y > _pageHeight)) { + maxHeight = _rectangle.y - _pageHeight; + maxHeight = maxHeight >= -maxHeight ? maxHeight : -maxHeight; + } + numInserted = 0; + if (lineResult.lines != null) { + for (int i = 0; i < lineResult.lines!.length; i++) { + final double expHeight = height! + lineResult.lineHeight; + if (expHeight <= maxHeight || + maxHeight <= 0 || + allowPartialLines || + (expHeight - maxHeight).abs() < 0.001) { + LineInfo info = lineResult.lines![i]; + if (!_isTabReplaced) { + numInserted = numInserted! + info.text!.length; + } else { + numInserted = + numInserted! + info.text!.length - (_tabOccuranceCount * 3); + _isTabReplaced = false; + } + info = _trimLine(info, lines.isEmpty); + lines.add(info); + final PdfSize size = result.size; + size.width = (size.width >= info.width!) ? size.width : info.width!; + result.size = size; + height = expHeight; + } else { + success = false; + break; + } + } + } + if (height != result.size.height) { + final PdfSize size = result.size; + size.height = height!; + result.size = size; + } + return {'success': success, 'numInserted': numInserted}; + } + + LineInfo _trimLine(LineInfo info, bool firstLine) { + String line = info.text.toString(); + double? lineWidth = info.width; + final bool start = + _format == null || + _format!.textDirection != PdfTextDirection.rightToLeft; + if (!info.lineTypeList.contains(LineType.firstParagraphLine)) { + line = start ? line.trimLeft() : line.trimRight(); + } + if (_format == null || !_format!.measureTrailingSpaces) { + line = start ? line.trimRight() : line.trimLeft(); + } + if (line.length != info.text!.length) { + lineWidth = _getLineWidth(line); + if (info.lineType & getLineTypeValue(LineType.firstParagraphLine)! > 0) { + lineWidth += _getLineIndent(firstLine)!; + } + } + info.text = line; + info.width = lineWidth; + return info; + } + + void _clear() { + _font = null; + _format = null; + _reader!.close(); + _reader = null; + _text = null; + } + + /// internal method + static int? getLineTypeValue(LineType type) { + int? value; + switch (type) { + case LineType.none: + value = 0; + break; + case LineType.newLineBreak: + value = 0x0001; + break; + case LineType.layoutBreak: + value = 0x0002; + break; + case LineType.firstParagraphLine: + value = 0x0004; + break; + case LineType.lastParagraphLine: + value = 0x0008; + break; + } + return value; + } +} + +/// Provides a line information +class LineInfo { + /// internal field + String? text; + + /// internal field + double? width; + + /// internal field + List lineTypeList = []; + + /// internal field + late int lineType; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_true_type_font.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_true_type_font.dart index 2dccc099a..bea177925 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_true_type_font.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/pdf_true_type_font.dart @@ -1,195 +1,195 @@ -import 'dart:convert'; - -import '../../../interfaces/pdf_interface.dart'; -import '../enums.dart'; -import 'enums.dart'; -import 'pdf_font.dart'; -import 'pdf_string_format.dart'; -import 'rtl/arabic_shape_renderer.dart'; -import 'unicode_true_type_font.dart'; - -/// Represents TrueType font. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new PDF true type font instance and draw string to PDF page. -/// document.pages.add().graphics.drawString( -/// 'Hello World!', -/// PdfTrueTypeFont(fontStream, 12), -/// brush: PdfBrushes.black, -/// bounds: Rect.fromLTWH(0, 0, 100, 50)); -/// //Saves the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfTrueTypeFont extends PdfFont { - /// Initializes a new instance of the [PdfTrueTypeFont] class. - /// - /// fontData represents the font sream formated as list of bytes. - /// size represents the font size to draw the text. - /// style and multistyle are used to set font styles. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF true type font instance and draw string to PDF page. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', - /// PdfTrueTypeFont(fontStream, 12), - /// brush: PdfBrushes.black, - /// bounds: Rect.fromLTWH(0, 0, 100, 50)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfTrueTypeFont( - List fontData, - double size, { - PdfFontStyle? style, - List? multiStyle, - }) { - _helper = PdfTrueTypeFontHelper(this); - _initializeFont(fontData, size, style, multiStyle); - } - - /// Initializes a new instance of the [PdfTrueTypeFont] class. - /// - /// fontdata represents the font stream as base64 string format. - /// size represents the font size to draw the text. - /// style and multistyle are used to set font styles. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Font stream in base64 string format - /// String base64 = 'AAEAAAATAQAABAAwRFNJRzlPG+EAASMQAAAdgKMbEAAAAAy/k2Tw=='; - /// //Create a new PDF true type font instance with font data as base64 string. - /// PdfFont font = PdfTrueTypeFont(base64, 12); - /// //Draw string to PDF page. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', - /// font, - /// brush: PdfBrushes.black, - /// bounds: Rect.fromLTWH(0, 0, 100, 50)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - PdfTrueTypeFont.fromBase64String( - String fontData, - double size, { - PdfFontStyle? style, - List? multiStyle, - }) { - _helper = PdfTrueTypeFontHelper(this); - if (fontData.isEmpty) { - throw ArgumentError.value(fontData, 'fontData', 'Invalid font data'); - } - _initializeFont(base64.decode(fontData), size, style, multiStyle); - } - - //Fields - late PdfTrueTypeFontHelper _helper; - - //Implementation - void _initializeFont( - List fontData, - double size, - PdfFontStyle? style, - List? multiStyle, - ) { - PdfFontHelper.getHelper( - this, - ).initialize(size, style: style, multiStyle: multiStyle); - _helper.unicode = true; - _createFontInternals(fontData); - } - - void _createFontInternals(List fontData) { - _helper.fontInternal = UnicodeTrueTypeFont(fontData, size); - _calculateStyle(style); - _initializeInternals(); - } - - void _calculateStyle(PdfFontStyle style) { - int? iStyle = _helper.fontInternal.ttfMetrics!.macStyle; - if (PdfFontHelper.getHelper(this).isUnderline) { - iStyle = iStyle! | PdfFontHelper.getPdfFontStyle(PdfFontStyle.underline); - } - if (PdfFontHelper.getHelper(this).isStrikeout) { - iStyle = - iStyle! | PdfFontHelper.getPdfFontStyle(PdfFontStyle.strikethrough); - } - PdfFontHelper.getHelper(this).fontStyle = iStyle!; - } - - void _initializeInternals() { - _helper.fontInternal.createInternals(); - final IPdfPrimitive? internals = _helper.fontInternal.fontDictionary; - PdfFontHelper.getHelper(this).metrics = _helper.fontInternal.metrics; - if (internals == null) { - throw ArgumentError.value(internals, 'font internal cannot be null'); - } - PdfFontHelper.getHelper(this).fontInternals = internals; - } -} - -/// [PdfTrueTypeFont] helper -class PdfTrueTypeFontHelper { - /// internal constructor - PdfTrueTypeFontHelper(this.base); - - /// internal field - PdfTrueTypeFont base; - - /// internal field - late UnicodeTrueTypeFont fontInternal; - - /// internal field - bool? unicode; - - /// internal method - static PdfTrueTypeFontHelper getHelper(PdfTrueTypeFont base) { - return base._helper; - } - - /// internal property - IPdfPrimitive? get element => PdfFontHelper.getHelper(base).fontInternals; - - //ignore: unused_element - set element(IPdfPrimitive? value) { - PdfFontHelper.getHelper(base).fontInternals = value; - } - - /// internal method - double getLineWidth(String line, PdfStringFormat? format) { - double width = 0; - String text = line; - if (format != null && format.textDirection != PdfTextDirection.none) { - final ArabicShapeRenderer renderer = ArabicShapeRenderer(); - text = renderer.shape(line.split(''), 0); - } - width = fontInternal.getLineWidth(text); - final double size = PdfFontHelper.getHelper(base).metrics!.getSize(format)!; - width *= 0.001 * size; - width = PdfFontHelper.applyFormatSettings(base, text, format, width); - return width; - } - - /// internal method - void setSymbols(String text, List? internalUsedChars) { - fontInternal.setSymbols(text, internalUsedChars); - } - - /// internal method - double getCharWidth(String charCode, PdfStringFormat? format) { - double codeWidth = fontInternal.getCharWidth(charCode); - codeWidth *= - 0.001 * PdfFontHelper.getHelper(base).metrics!.getSize(format)!; - return codeWidth; - } -} +import 'dart:convert'; + +import '../../../interfaces/pdf_interface.dart'; +import '../enums.dart'; +import 'enums.dart'; +import 'pdf_font.dart'; +import 'pdf_string_format.dart'; +import 'rtl/arabic_shape_renderer.dart'; +import 'unicode_true_type_font.dart'; + +/// Represents TrueType font. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new PDF true type font instance and draw string to PDF page. +/// document.pages.add().graphics.drawString( +/// 'Hello World!', +/// PdfTrueTypeFont(fontStream, 12), +/// brush: PdfBrushes.black, +/// bounds: Rect.fromLTWH(0, 0, 100, 50)); +/// //Saves the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfTrueTypeFont extends PdfFont { + /// Initializes a new instance of the [PdfTrueTypeFont] class. + /// + /// fontData represents the font sream formated as list of bytes. + /// size represents the font size to draw the text. + /// style and multistyle are used to set font styles. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF true type font instance and draw string to PDF page. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', + /// PdfTrueTypeFont(fontStream, 12), + /// brush: PdfBrushes.black, + /// bounds: Rect.fromLTWH(0, 0, 100, 50)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfTrueTypeFont( + List fontData, + double size, { + PdfFontStyle? style, + List? multiStyle, + }) { + _helper = PdfTrueTypeFontHelper(this); + _initializeFont(fontData, size, style, multiStyle); + } + + /// Initializes a new instance of the [PdfTrueTypeFont] class. + /// + /// fontdata represents the font stream as base64 string format. + /// size represents the font size to draw the text. + /// style and multistyle are used to set font styles. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Font stream in base64 string format + /// String base64 = 'AAEAAAATAQAABAAwRFNJRzlPG+EAASMQAAAdgKMbEAAAAAy/k2Tw=='; + /// //Create a new PDF true type font instance with font data as base64 string. + /// PdfFont font = PdfTrueTypeFont(base64, 12); + /// //Draw string to PDF page. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', + /// font, + /// brush: PdfBrushes.black, + /// bounds: Rect.fromLTWH(0, 0, 100, 50)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + PdfTrueTypeFont.fromBase64String( + String fontData, + double size, { + PdfFontStyle? style, + List? multiStyle, + }) { + _helper = PdfTrueTypeFontHelper(this); + if (fontData.isEmpty) { + throw ArgumentError.value(fontData, 'fontData', 'Invalid font data'); + } + _initializeFont(base64.decode(fontData), size, style, multiStyle); + } + + //Fields + late PdfTrueTypeFontHelper _helper; + + //Implementation + void _initializeFont( + List fontData, + double size, + PdfFontStyle? style, + List? multiStyle, + ) { + PdfFontHelper.getHelper( + this, + ).initialize(size, style: style, multiStyle: multiStyle); + _helper.unicode = true; + _createFontInternals(fontData); + } + + void _createFontInternals(List fontData) { + _helper.fontInternal = UnicodeTrueTypeFont(fontData, size); + _calculateStyle(style); + _initializeInternals(); + } + + void _calculateStyle(PdfFontStyle style) { + int? iStyle = _helper.fontInternal.ttfMetrics!.macStyle; + if (PdfFontHelper.getHelper(this).isUnderline) { + iStyle = iStyle! | PdfFontHelper.getPdfFontStyle(PdfFontStyle.underline); + } + if (PdfFontHelper.getHelper(this).isStrikeout) { + iStyle = + iStyle! | PdfFontHelper.getPdfFontStyle(PdfFontStyle.strikethrough); + } + PdfFontHelper.getHelper(this).fontStyle = iStyle!; + } + + void _initializeInternals() { + _helper.fontInternal.createInternals(); + final IPdfPrimitive? internals = _helper.fontInternal.fontDictionary; + PdfFontHelper.getHelper(this).metrics = _helper.fontInternal.metrics; + if (internals == null) { + throw ArgumentError.value(internals, 'font internal cannot be null'); + } + PdfFontHelper.getHelper(this).fontInternals = internals; + } +} + +/// [PdfTrueTypeFont] helper +class PdfTrueTypeFontHelper { + /// internal constructor + PdfTrueTypeFontHelper(this.base); + + /// internal field + PdfTrueTypeFont base; + + /// internal field + late UnicodeTrueTypeFont fontInternal; + + /// internal field + bool? unicode; + + /// internal method + static PdfTrueTypeFontHelper getHelper(PdfTrueTypeFont base) { + return base._helper; + } + + /// internal property + IPdfPrimitive? get element => PdfFontHelper.getHelper(base).fontInternals; + + //ignore: unused_element + set element(IPdfPrimitive? value) { + PdfFontHelper.getHelper(base).fontInternals = value; + } + + /// internal method + double getLineWidth(String line, PdfStringFormat? format) { + double width = 0; + String text = line; + if (format != null && format.textDirection != PdfTextDirection.none) { + final ArabicShapeRenderer renderer = ArabicShapeRenderer(); + text = renderer.shape(line.split(''), 0); + } + width = fontInternal.getLineWidth(text); + final double size = PdfFontHelper.getHelper(base).metrics!.getSize(format)!; + width *= 0.001 * size; + width = PdfFontHelper.applyFormatSettings(base, text, format, width); + return width; + } + + /// internal method + void setSymbols(String text, List? internalUsedChars) { + fontInternal.setSymbols(text, internalUsedChars); + } + + /// internal method + double getCharWidth(String charCode, PdfStringFormat? format) { + double codeWidth = fontInternal.getCharWidth(charCode); + codeWidth *= + 0.001 * PdfFontHelper.getHelper(base).metrics!.getSize(format)!; + return codeWidth; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/arabic_shape_renderer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/arabic_shape_renderer.dart index b282ee41d..9f9c43e46 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/arabic_shape_renderer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/arabic_shape_renderer.dart @@ -1,383 +1,383 @@ -/// Utility class for arabic shape rendering. -class ArabicShapeRenderer { - // Constructor. - /// internal constructor - ArabicShapeRenderer() { - for (int i = 0; i < arabicCharTable.length; i++) { - arabicMapTable[arabicCharTable[i][0]] = arabicCharTable[i]; - } - } - - // Constants and Fields. - /// internal field - final List> arabicCharTable = >[ - ['\u0621', '\uFE80'], - ['\u0622', '\uFE81', '\uFE82'], - ['\u0623', '\uFE83', '\uFE84'], - ['\u0624', '\uFE85', '\uFE86'], - ['\u0625', '\uFE87', '\uFE88'], - ['\u0626', '\uFE89', '\uFE8A', '\uFE8B', '\uFE8C'], - ['\u0627', '\uFE8D', '\uFE8E'], - ['\u0628', '\uFE8F', '\uFE90', '\uFE91', '\uFE92'], - ['\u0629', '\uFE93', '\uFE94'], - ['\u062A', '\uFE95', '\uFE96', '\uFE97', '\uFE98'], - ['\u062B', '\uFE99', '\uFE9A', '\uFE9B', '\uFE9C'], - ['\u062C', '\uFE9D', '\uFE9E', '\uFE9F', '\uFEA0'], - ['\u062D', '\uFEA1', '\uFEA2', '\uFEA3', '\uFEA4'], - ['\u062E', '\uFEA5', '\uFEA6', '\uFEA7', '\uFEA8'], - ['\u062F', '\uFEA9', '\uFEAA'], - ['\u0630', '\uFEAB', '\uFEAC'], - ['\u0631', '\uFEAD', '\uFEAE'], - ['\u0632', '\uFEAF', '\uFEB0'], - ['\u0633', '\uFEB1', '\uFEB2', '\uFEB3', '\uFEB4'], - ['\u0634', '\uFEB5', '\uFEB6', '\uFEB7', '\uFEB8'], - ['\u0635', '\uFEB9', '\uFEBA', '\uFEBB', '\uFEBC'], - ['\u0636', '\uFEBD', '\uFEBE', '\uFEBF', '\uFEC0'], - ['\u0637', '\uFEC1', '\uFEC2', '\uFEC3', '\uFEC4'], - ['\u0638', '\uFEC5', '\uFEC6', '\uFEC7', '\uFEC8'], - ['\u0639', '\uFEC9', '\uFECA', '\uFECB', '\uFECC'], - ['\u063A', '\uFECD', '\uFECE', '\uFECF', '\uFED0'], - ['\u0640', '\u0640', '\u0640', '\u0640', '\u0640'], - ['\u0641', '\uFED1', '\uFED2', '\uFED3', '\uFED4'], - ['\u0642', '\uFED5', '\uFED6', '\uFED7', '\uFED8'], - ['\u0643', '\uFED9', '\uFEDA', '\uFEDB', '\uFEDC'], - ['\u0644', '\uFEDD', '\uFEDE', '\uFEDF', '\uFEE0'], - ['\u0645', '\uFEE1', '\uFEE2', '\uFEE3', '\uFEE4'], - ['\u0646', '\uFEE5', '\uFEE6', '\uFEE7', '\uFEE8'], - ['\u0647', '\uFEE9', '\uFEEA', '\uFEEB', '\uFEEC'], - ['\u0648', '\uFEED', '\uFEEE'], - ['\u0649', '\uFEEF', '\uFEF0', '\uFBE8', '\uFBE9'], - ['\u064A', '\uFEF1', '\uFEF2', '\uFEF3', '\uFEF4'], - ['\u0671', '\uFB50', '\uFB51'], - ['\u0679', '\uFB66', '\uFB67', '\uFB68', '\uFB69'], - ['\u067A', '\uFB5E', '\uFB5F', '\uFB60', '\uFB61'], - ['\u067B', '\uFB52', '\uFB53', '\uFB54', '\uFB55'], - ['\u067E', '\uFB56', '\uFB57', '\uFB58', '\uFB59'], - ['\u067F', '\uFB62', '\uFB63', '\uFB64', '\uFB65'], - ['\u0680', '\uFB5A', '\uFB5B', '\uFB5C', '\uFB5D'], - ['\u0683', '\uFB76', '\uFB77', '\uFB78', '\uFB79'], - ['\u0684', '\uFB72', '\uFB73', '\uFB74', '\uFB75'], - ['\u0686', '\uFB7A', '\uFB7B', '\uFB7C', '\uFB7D'], - ['\u0687', '\uFB7E', '\uFB7F', '\uFB80', '\uFB81'], - ['\u0688', '\uFB88', '\uFB89'], - ['\u068C', '\uFB84', '\uFB85'], - ['\u068D', '\uFB82', '\uFB83'], - ['\u068E', '\uFB86', '\uFB87'], - ['\u0691', '\uFB8C', '\uFB8D'], - ['\u0698', '\uFB8A', '\uFB8B'], - ['\u06A4', '\uFB6A', '\uFB6B', '\uFB6C', '\uFB6D'], - ['\u06A6', '\uFB6E', '\uFB6F', '\uFB70', '\uFB71'], - ['\u06A9', '\uFB8E', '\uFB8F', '\uFB90', '\uFB91'], - ['\u06AD', '\uFBD3', '\uFBD4', '\uFBD5', '\uFBD6'], - ['\u06AF', '\uFB92', '\uFB93', '\uFB94', '\uFB95'], - ['\u06B1', '\uFB9A', '\uFB9B', '\uFB9C', '\uFB9D'], - ['\u06B3', '\uFB96', '\uFB97', '\uFB98', '\uFB99'], - ['\u06BA', '\uFB9E', '\uFB9F'], - ['\u06BB', '\uFBA0', '\uFBA1', '\uFBA2', '\uFBA3'], - ['\u06BE', '\uFBAA', '\uFBAB', '\uFBAC', '\uFBAD'], - ['\u06C0', '\uFBA4', '\uFBA5'], - ['\u06C1', '\uFBA6', '\uFBA7', '\uFBA8', '\uFBA9'], - ['\u06C5', '\uFBE0', '\uFBE1'], - ['\u06C6', '\uFBD9', '\uFBDA'], - ['\u06C7', '\uFBD7', '\uFBD8'], - ['\u06C8', '\uFBDB', '\uFBDC'], - ['\u06C9', '\uFBE2', '\uFBE3'], - ['\u06CB', '\uFBDE', '\uFBDF'], - ['\u06CC', '\uFBFC', '\uFBFD', '\uFBFE', '\uFBFF'], - ['\u06D0', '\uFBE4', '\uFBE5', '\uFBE6', '\uFBE7'], - ['\u06D2', '\uFBAE', '\uFBAF'], - ['\u06D3', '\uFBB0', '\uFBB1'], - ]; - - /// internal field - static const String alef = '\u0627'; - - /// internal field - static const String alefHamza = '\u0623'; - - /// internal field - static const String alefHamzaBelow = '\u0625'; - - /// internal field - static const String alefMadda = '\u0622'; - - /// internal field - static const String lam = '\u0644'; - - /// internal field - static const String hamza = '\u0621'; - - /// internal field - static const String zeroWidthJoiner = '\u200D'; - - /// internal field - static const String hamzaAbove = '\u0654'; - - /// internal field - static const String hamzaBelow = '\u0655'; - - /// internal field - static const String wawHamza = '\u0624'; - - /// internal field - static const String yehHamza = '\u0626'; - - /// internal field - static const String waw = '\u0648'; - - /// internal field - static const String alefMaksura = '\u0649'; - - /// internal field - static const String yeh = '\u064A'; - - /// internal field - static const String farsiYeh = '\u06CC'; - - /// internal field - static const String shadda = '\u0651'; - - /// internal field - static const String madda = '\u0653'; - - /// internal field - static const String lwa = '\uFEFB'; - - /// internal field - static const String lwawh = '\uFEF7'; - - /// internal field - static const String lwawhb = '\uFEF9'; - - /// internal field - static const String lwawm = '\uFEF5'; - - /// internal field - static const String bwhb = '\u06D3'; - - /// internal field - static const String fathatan = '\u064B'; - - /// internal field - static const String superscriptAlef = '\u0670'; - - /// internal field - static const int vowel = 0x1; - - /// internal field - Map> arabicMapTable = >{}; - - // Implementations. - /// internal method - String shape(List text, int level) { - final StringBuffer buffer = StringBuffer(); - StringBuffer str2 = StringBuffer(); - for (int i = 0; i < text.length; i++) { - final String c = text[i]; - if (c.codeUnitAt(0) >= 0x0600 && c.codeUnitAt(0) <= 0x06ff) { - str2.write(c); - } else { - if (str2.length > 0) { - final String st = doShape(str2.toString().split(''), 0); - buffer.write(st); - str2 = StringBuffer(); - } - buffer.write(c); - } - } - if (str2.length > 0) { - final String st = doShape(str2.toString().split(''), 0); - buffer.write(st); - } - return buffer.toString(); - } - - /// internal method - String doShape(List input, int level) { - final StringBuffer str = StringBuffer(); - int ligature, len, i = 0; - String next; - ArabicShape previous = ArabicShape(); - ArabicShape present = ArabicShape(); - while (i < input.length) { - next = input[i++]; - ligature = this.ligature(next, present); - if (ligature == 0) { - final int shapeCount = getShapeCount(next); - len = (shapeCount == 1) ? 0 : 2; - if (previous.shapes > 2) { - len += 1; - } - len = len % (present.shapes); - present.value = getCharacterShape(present.value, len); - append(str, previous, level); - previous = present; - present = ArabicShape(); - present.value = next; - present.shapes = shapeCount; - present.ligature++; - } - } - len = (previous.shapes > 2) ? 1 : 0; - len = len % (present.shapes); - present.value = getCharacterShape(present.value, len); - append(str, previous, level); - append(str, present, level); - return str.toString(); - } - - /// internal method - void append(StringBuffer buffer, ArabicShape shape, int level) { - if (shape.value != '') { - buffer.write(shape.value); - shape.ligature -= 1; - if (shape.type != '') { - if ((level & vowel) == 0) { - buffer.write(shape.type); - shape.ligature -= 1; - } else { - shape.ligature -= 1; - } - } - if (shape.vowel != '') { - if ((level & vowel) == 0) { - buffer.write(shape.vowel); - shape.ligature -= 1; - } else { - shape.ligature -= 1; - } - } - } - } - - /// internal method - int ligature(String value, ArabicShape shape) { - if (shape.value != '') { - int result = 0; - if ((value.codeUnitAt(0) >= fathatan.codeUnitAt(0) && - value.codeUnitAt(0) <= hamzaBelow.codeUnitAt(0)) || - value == superscriptAlef) { - result = 1; - if ((shape.vowel != '') && (value != shadda)) { - result = 2; - } - if (value == shadda) { - if (shape.type == '') { - shape.type = shadda; - } else { - return 0; - } - } else if (value == hamzaBelow) { - if (shape.value == alef) { - shape.value = alefHamzaBelow; - result = 2; - } else if (value == lwa) { - shape.value = lwawhb; - result = 2; - } else { - shape.type = hamzaBelow; - } - } else if (value == hamzaAbove) { - if (shape.value == alef) { - shape.value = alefHamza; - result = 2; - } else if (shape.value == lwa) { - shape.value = lwawh; - result = 2; - } else if (shape.value == waw) { - shape.value = wawHamza; - result = 2; - } else if (shape.value == yeh || - shape.value == alefMaksura || - shape.value == farsiYeh) { - shape.value = yehHamza; - result = 2; - } else { - shape.type = hamzaAbove; - } - } else if (value == madda) { - if (shape.value == alef) { - shape.value = alefMadda; - result = 2; - } - } else { - shape.vowel = value; - } - if (result == 1) { - shape.ligature++; - } - return result; - } - if (shape.vowel != '') { - return 0; - } - if (shape.value == lam) { - if (value == alef) { - shape.value = lwa; - shape.shapes = 2; - result = 3; - } else if (value == alefHamza) { - shape.value = lwawh; - shape.shapes = 2; - result = 3; - } else if (value == alefHamzaBelow) { - shape.value = lwawhb; - shape.shapes = 2; - result = 3; - } else if (value == alefMadda) { - shape.value = lwawm; - shape.shapes = 2; - result = 3; - } - } else if (shape.value == '') { - shape.value = value; - shape.shapes = getShapeCount(value); - result = 1; - } - return result; - } else { - return 0; - } - } - - /// internal method - String getCharacterShape(String input, int index) { - final int inputCode = input == '' ? 0 : input.codeUnitAt(0); - if (inputCode >= hamza.codeUnitAt(0) && inputCode <= bwhb.codeUnitAt(0)) { - final List? value = arabicMapTable[input]; - if (value != null) { - return value[index + 1]; - } - } else if (inputCode >= lwawm.codeUnitAt(0) && - inputCode <= lwa.codeUnitAt(0)) { - return String.fromCharCode(inputCode + index); - } - return input; - } - - /// internal method - int getShapeCount(String shape) { - final int value = shape.codeUnitAt(0); - if ((value >= hamza.codeUnitAt(0)) && - (value <= bwhb.codeUnitAt(0)) && - !((value >= fathatan.codeUnitAt(0) && - value <= hamzaBelow.codeUnitAt(0)) || - shape == superscriptAlef)) { - final List? c = arabicMapTable[shape]; - if (c != null) { - return c.length - 1; - } - } else if (shape == zeroWidthJoiner) { - return 4; - } - return 1; - } -} - -class ArabicShape { - String value = ''; - String type = ''; - String vowel = ''; - int ligature = 0; - int shapes = 1; -} +/// Utility class for arabic shape rendering. +class ArabicShapeRenderer { + // Constructor. + /// internal constructor + ArabicShapeRenderer() { + for (int i = 0; i < arabicCharTable.length; i++) { + arabicMapTable[arabicCharTable[i][0]] = arabicCharTable[i]; + } + } + + // Constants and Fields. + /// internal field + final List> arabicCharTable = >[ + ['\u0621', '\uFE80'], + ['\u0622', '\uFE81', '\uFE82'], + ['\u0623', '\uFE83', '\uFE84'], + ['\u0624', '\uFE85', '\uFE86'], + ['\u0625', '\uFE87', '\uFE88'], + ['\u0626', '\uFE89', '\uFE8A', '\uFE8B', '\uFE8C'], + ['\u0627', '\uFE8D', '\uFE8E'], + ['\u0628', '\uFE8F', '\uFE90', '\uFE91', '\uFE92'], + ['\u0629', '\uFE93', '\uFE94'], + ['\u062A', '\uFE95', '\uFE96', '\uFE97', '\uFE98'], + ['\u062B', '\uFE99', '\uFE9A', '\uFE9B', '\uFE9C'], + ['\u062C', '\uFE9D', '\uFE9E', '\uFE9F', '\uFEA0'], + ['\u062D', '\uFEA1', '\uFEA2', '\uFEA3', '\uFEA4'], + ['\u062E', '\uFEA5', '\uFEA6', '\uFEA7', '\uFEA8'], + ['\u062F', '\uFEA9', '\uFEAA'], + ['\u0630', '\uFEAB', '\uFEAC'], + ['\u0631', '\uFEAD', '\uFEAE'], + ['\u0632', '\uFEAF', '\uFEB0'], + ['\u0633', '\uFEB1', '\uFEB2', '\uFEB3', '\uFEB4'], + ['\u0634', '\uFEB5', '\uFEB6', '\uFEB7', '\uFEB8'], + ['\u0635', '\uFEB9', '\uFEBA', '\uFEBB', '\uFEBC'], + ['\u0636', '\uFEBD', '\uFEBE', '\uFEBF', '\uFEC0'], + ['\u0637', '\uFEC1', '\uFEC2', '\uFEC3', '\uFEC4'], + ['\u0638', '\uFEC5', '\uFEC6', '\uFEC7', '\uFEC8'], + ['\u0639', '\uFEC9', '\uFECA', '\uFECB', '\uFECC'], + ['\u063A', '\uFECD', '\uFECE', '\uFECF', '\uFED0'], + ['\u0640', '\u0640', '\u0640', '\u0640', '\u0640'], + ['\u0641', '\uFED1', '\uFED2', '\uFED3', '\uFED4'], + ['\u0642', '\uFED5', '\uFED6', '\uFED7', '\uFED8'], + ['\u0643', '\uFED9', '\uFEDA', '\uFEDB', '\uFEDC'], + ['\u0644', '\uFEDD', '\uFEDE', '\uFEDF', '\uFEE0'], + ['\u0645', '\uFEE1', '\uFEE2', '\uFEE3', '\uFEE4'], + ['\u0646', '\uFEE5', '\uFEE6', '\uFEE7', '\uFEE8'], + ['\u0647', '\uFEE9', '\uFEEA', '\uFEEB', '\uFEEC'], + ['\u0648', '\uFEED', '\uFEEE'], + ['\u0649', '\uFEEF', '\uFEF0', '\uFBE8', '\uFBE9'], + ['\u064A', '\uFEF1', '\uFEF2', '\uFEF3', '\uFEF4'], + ['\u0671', '\uFB50', '\uFB51'], + ['\u0679', '\uFB66', '\uFB67', '\uFB68', '\uFB69'], + ['\u067A', '\uFB5E', '\uFB5F', '\uFB60', '\uFB61'], + ['\u067B', '\uFB52', '\uFB53', '\uFB54', '\uFB55'], + ['\u067E', '\uFB56', '\uFB57', '\uFB58', '\uFB59'], + ['\u067F', '\uFB62', '\uFB63', '\uFB64', '\uFB65'], + ['\u0680', '\uFB5A', '\uFB5B', '\uFB5C', '\uFB5D'], + ['\u0683', '\uFB76', '\uFB77', '\uFB78', '\uFB79'], + ['\u0684', '\uFB72', '\uFB73', '\uFB74', '\uFB75'], + ['\u0686', '\uFB7A', '\uFB7B', '\uFB7C', '\uFB7D'], + ['\u0687', '\uFB7E', '\uFB7F', '\uFB80', '\uFB81'], + ['\u0688', '\uFB88', '\uFB89'], + ['\u068C', '\uFB84', '\uFB85'], + ['\u068D', '\uFB82', '\uFB83'], + ['\u068E', '\uFB86', '\uFB87'], + ['\u0691', '\uFB8C', '\uFB8D'], + ['\u0698', '\uFB8A', '\uFB8B'], + ['\u06A4', '\uFB6A', '\uFB6B', '\uFB6C', '\uFB6D'], + ['\u06A6', '\uFB6E', '\uFB6F', '\uFB70', '\uFB71'], + ['\u06A9', '\uFB8E', '\uFB8F', '\uFB90', '\uFB91'], + ['\u06AD', '\uFBD3', '\uFBD4', '\uFBD5', '\uFBD6'], + ['\u06AF', '\uFB92', '\uFB93', '\uFB94', '\uFB95'], + ['\u06B1', '\uFB9A', '\uFB9B', '\uFB9C', '\uFB9D'], + ['\u06B3', '\uFB96', '\uFB97', '\uFB98', '\uFB99'], + ['\u06BA', '\uFB9E', '\uFB9F'], + ['\u06BB', '\uFBA0', '\uFBA1', '\uFBA2', '\uFBA3'], + ['\u06BE', '\uFBAA', '\uFBAB', '\uFBAC', '\uFBAD'], + ['\u06C0', '\uFBA4', '\uFBA5'], + ['\u06C1', '\uFBA6', '\uFBA7', '\uFBA8', '\uFBA9'], + ['\u06C5', '\uFBE0', '\uFBE1'], + ['\u06C6', '\uFBD9', '\uFBDA'], + ['\u06C7', '\uFBD7', '\uFBD8'], + ['\u06C8', '\uFBDB', '\uFBDC'], + ['\u06C9', '\uFBE2', '\uFBE3'], + ['\u06CB', '\uFBDE', '\uFBDF'], + ['\u06CC', '\uFBFC', '\uFBFD', '\uFBFE', '\uFBFF'], + ['\u06D0', '\uFBE4', '\uFBE5', '\uFBE6', '\uFBE7'], + ['\u06D2', '\uFBAE', '\uFBAF'], + ['\u06D3', '\uFBB0', '\uFBB1'], + ]; + + /// internal field + static const String alef = '\u0627'; + + /// internal field + static const String alefHamza = '\u0623'; + + /// internal field + static const String alefHamzaBelow = '\u0625'; + + /// internal field + static const String alefMadda = '\u0622'; + + /// internal field + static const String lam = '\u0644'; + + /// internal field + static const String hamza = '\u0621'; + + /// internal field + static const String zeroWidthJoiner = '\u200D'; + + /// internal field + static const String hamzaAbove = '\u0654'; + + /// internal field + static const String hamzaBelow = '\u0655'; + + /// internal field + static const String wawHamza = '\u0624'; + + /// internal field + static const String yehHamza = '\u0626'; + + /// internal field + static const String waw = '\u0648'; + + /// internal field + static const String alefMaksura = '\u0649'; + + /// internal field + static const String yeh = '\u064A'; + + /// internal field + static const String farsiYeh = '\u06CC'; + + /// internal field + static const String shadda = '\u0651'; + + /// internal field + static const String madda = '\u0653'; + + /// internal field + static const String lwa = '\uFEFB'; + + /// internal field + static const String lwawh = '\uFEF7'; + + /// internal field + static const String lwawhb = '\uFEF9'; + + /// internal field + static const String lwawm = '\uFEF5'; + + /// internal field + static const String bwhb = '\u06D3'; + + /// internal field + static const String fathatan = '\u064B'; + + /// internal field + static const String superscriptAlef = '\u0670'; + + /// internal field + static const int vowel = 0x1; + + /// internal field + Map> arabicMapTable = >{}; + + // Implementations. + /// internal method + String shape(List text, int level) { + final StringBuffer buffer = StringBuffer(); + StringBuffer str2 = StringBuffer(); + for (int i = 0; i < text.length; i++) { + final String c = text[i]; + if (c.codeUnitAt(0) >= 0x0600 && c.codeUnitAt(0) <= 0x06ff) { + str2.write(c); + } else { + if (str2.length > 0) { + final String st = doShape(str2.toString().split(''), 0); + buffer.write(st); + str2 = StringBuffer(); + } + buffer.write(c); + } + } + if (str2.length > 0) { + final String st = doShape(str2.toString().split(''), 0); + buffer.write(st); + } + return buffer.toString(); + } + + /// internal method + String doShape(List input, int level) { + final StringBuffer str = StringBuffer(); + int ligature, len, i = 0; + String next; + ArabicShape previous = ArabicShape(); + ArabicShape present = ArabicShape(); + while (i < input.length) { + next = input[i++]; + ligature = this.ligature(next, present); + if (ligature == 0) { + final int shapeCount = getShapeCount(next); + len = (shapeCount == 1) ? 0 : 2; + if (previous.shapes > 2) { + len += 1; + } + len = len % (present.shapes); + present.value = getCharacterShape(present.value, len); + append(str, previous, level); + previous = present; + present = ArabicShape(); + present.value = next; + present.shapes = shapeCount; + present.ligature++; + } + } + len = (previous.shapes > 2) ? 1 : 0; + len = len % (present.shapes); + present.value = getCharacterShape(present.value, len); + append(str, previous, level); + append(str, present, level); + return str.toString(); + } + + /// internal method + void append(StringBuffer buffer, ArabicShape shape, int level) { + if (shape.value != '') { + buffer.write(shape.value); + shape.ligature -= 1; + if (shape.type != '') { + if ((level & vowel) == 0) { + buffer.write(shape.type); + shape.ligature -= 1; + } else { + shape.ligature -= 1; + } + } + if (shape.vowel != '') { + if ((level & vowel) == 0) { + buffer.write(shape.vowel); + shape.ligature -= 1; + } else { + shape.ligature -= 1; + } + } + } + } + + /// internal method + int ligature(String value, ArabicShape shape) { + if (shape.value != '') { + int result = 0; + if ((value.codeUnitAt(0) >= fathatan.codeUnitAt(0) && + value.codeUnitAt(0) <= hamzaBelow.codeUnitAt(0)) || + value == superscriptAlef) { + result = 1; + if ((shape.vowel != '') && (value != shadda)) { + result = 2; + } + if (value == shadda) { + if (shape.type == '') { + shape.type = shadda; + } else { + return 0; + } + } else if (value == hamzaBelow) { + if (shape.value == alef) { + shape.value = alefHamzaBelow; + result = 2; + } else if (value == lwa) { + shape.value = lwawhb; + result = 2; + } else { + shape.type = hamzaBelow; + } + } else if (value == hamzaAbove) { + if (shape.value == alef) { + shape.value = alefHamza; + result = 2; + } else if (shape.value == lwa) { + shape.value = lwawh; + result = 2; + } else if (shape.value == waw) { + shape.value = wawHamza; + result = 2; + } else if (shape.value == yeh || + shape.value == alefMaksura || + shape.value == farsiYeh) { + shape.value = yehHamza; + result = 2; + } else { + shape.type = hamzaAbove; + } + } else if (value == madda) { + if (shape.value == alef) { + shape.value = alefMadda; + result = 2; + } + } else { + shape.vowel = value; + } + if (result == 1) { + shape.ligature++; + } + return result; + } + if (shape.vowel != '') { + return 0; + } + if (shape.value == lam) { + if (value == alef) { + shape.value = lwa; + shape.shapes = 2; + result = 3; + } else if (value == alefHamza) { + shape.value = lwawh; + shape.shapes = 2; + result = 3; + } else if (value == alefHamzaBelow) { + shape.value = lwawhb; + shape.shapes = 2; + result = 3; + } else if (value == alefMadda) { + shape.value = lwawm; + shape.shapes = 2; + result = 3; + } + } else if (shape.value == '') { + shape.value = value; + shape.shapes = getShapeCount(value); + result = 1; + } + return result; + } else { + return 0; + } + } + + /// internal method + String getCharacterShape(String input, int index) { + final int inputCode = input == '' ? 0 : input.codeUnitAt(0); + if (inputCode >= hamza.codeUnitAt(0) && inputCode <= bwhb.codeUnitAt(0)) { + final List? value = arabicMapTable[input]; + if (value != null) { + return value[index + 1]; + } + } else if (inputCode >= lwawm.codeUnitAt(0) && + inputCode <= lwa.codeUnitAt(0)) { + return String.fromCharCode(inputCode + index); + } + return input; + } + + /// internal method + int getShapeCount(String shape) { + final int value = shape.codeUnitAt(0); + if ((value >= hamza.codeUnitAt(0)) && + (value <= bwhb.codeUnitAt(0)) && + !((value >= fathatan.codeUnitAt(0) && + value <= hamzaBelow.codeUnitAt(0)) || + shape == superscriptAlef)) { + final List? c = arabicMapTable[shape]; + if (c != null) { + return c.length - 1; + } + } else if (shape == zeroWidthJoiner) { + return 4; + } + return 1; + } +} + +class ArabicShape { + String value = ''; + String type = ''; + String vowel = ''; + int ligature = 0; + int shapes = 1; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/bidi.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/bidi.dart index 4f79df994..760507da8 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/bidi.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/rtl/bidi.dart @@ -1,2694 +1,2694 @@ -import 'dart:math'; - -/// Utility class for Bidirectional/Rtl text. -class Bidi { - // Constructor. - /// internal constructor - Bidi() { - update(); - } - - // Fields. - /// internal field - late List indexes; - - /// internal field - late List indexLevels; - - /// internal field - Map mirroringShapeCharacters = {}; - - late Map> _ranges; - - /// internal field - bool isVisualOrder = true; - - // Implementations. - /// internal method - Map getLogicalToVisualString(String inputText, bool isRTL) { - indexLevels = List.filled(inputText.length, 0, growable: true); - indexes = List.filled(inputText.length, 0, growable: true); - _ranges = >{}; - final _RTLCharacters rtlCharacters = _RTLCharacters(); - indexLevels = rtlCharacters.getVisualOrder(inputText, isRTL); - setDefaultIndexLevel(); - if (isVisualOrder) { - doBidiOrder(0, indexLevels.length - 1); - if (_ranges.isNotEmpty) { - _ranges.forEach((int key, List value) { - if (_ranges.entries.last.key != key) { - while (value[0] - 1 != -1 && - (rtlCharacters.types[value[0] - 1] == 17 || - rtlCharacters.types[value[0] - 1] == 18 || - rtlCharacters.types[value[0] - 1] == 12)) { - value[0] = value[0] - 1; - } - while (value[1] != _ranges.entries.last.value[1] + 1 && - value[1] < rtlCharacters.types.length && - (rtlCharacters.types[value.last] == 17 || - rtlCharacters.types[value.last] == 18 || - rtlCharacters.types[value.last] == 12)) { - value[1] = value.last + 1; - } - } - }); - if (_ranges.length == 1) { - reArrange(_ranges[0]![0], _ranges[0]![1]); - } else { - int start = 0; - for (int i = 0; i < _ranges.length - 1; i++) { - final List range = _ranges[i]!; - if (range[0] == 0) { - start = range[1]; - } else { - reArrange(start, range[0]); - start = range[1]; - } - } - if (start != indexLevels.length) { - reArrange(start, indexLevels.length); - } - } - } - } else { - doOrder(0, indexLevels.length - 1); - } - final String text = doMirrorShaping(inputText); - final StringBuffer resultBuffer = StringBuffer(); - for (int i = 0; i < indexes.length; i++) { - final int index = indexes[i]; - resultBuffer.write(text[index]); - } - String renderedString = resultBuffer.toString(); - if (isVisualOrder) { - final List tempList = renderedString.split(''); - _ranges.forEach((int key, List value) { - if (_ranges.keys.last != key) { - String tempText = tempList.getRange(value[0], value[1]).join(); - if (tempText.contains(')')) { - tempText = tempText.replaceAll(')', '('); - tempList.replaceRange(value[0], value[1], tempText.split('')); - renderedString = tempList.join(); - } - } - }); - } - return { - 'rtlText': renderedString, - 'orderedIndexes': indexes, - }; - } - - /// internal method - void doBidiOrder(int sIndex, int eIndex) { - int max = indexLevels[sIndex].toUnsigned(8); - int min = max; - int odd = max; - int even = max; - for (int i = sIndex + 1; i <= eIndex; ++i) { - final int data = indexLevels[i]; - if (data > max) { - max = data; - } else if (data < min) { - min = data; - } - odd &= data; - even |= data; - } - if ((even & 1) == 0) { - return; - } - if ((odd & 1) == 1) { - _ranges[_ranges.length] = [sIndex, eIndex + 1]; - return; - } - min |= 1; - while (max >= min) { - int pstart = sIndex; - while (true) { - while (pstart <= eIndex) { - if (indexLevels[pstart] >= max) { - break; - } - pstart += 1; - } - if (pstart > eIndex) { - break; - } - int pend = pstart + 1; - while (pend <= eIndex) { - if (indexLevels[pend] < max) { - break; - } - pend += 1; - } - _ranges[_ranges.length] = [pstart, pend]; - pstart = pend + 1; - } - max -= 1; - } - } - - /// internal method - String doMirrorShaping(String text) { - final StringBuffer result = StringBuffer(); - for (int i = 0; i < text.length; i++) { - if (((indexLevels[i] & 1) == 1) && - mirroringShapeCharacters.containsKey(text[i].codeUnitAt(0))) { - result.write( - String.fromCharCode(mirroringShapeCharacters[text[i].codeUnitAt(0)]!), - ); - } else { - result.write(text[i]); - } - } - return result.toString(); - } - - /// internal method - void setDefaultIndexLevel() { - for (int i = 0; i < indexLevels.length; i++) { - indexes[i] = i; - } - } - - /// internal method - void doOrder(int sIndex, int eIndex) { - int max = indexLevels[sIndex].toUnsigned(8); - int min = max; - int odd = max; - int even = max; - for (int i = sIndex + 1; i <= eIndex; ++i) { - final int data = indexLevels[i]; - if (data > max) { - max = data; - } else if (data < min) { - min = data; - } - odd &= data; - even |= data; - } - if ((even & 1) == 0) { - return; - } - if ((odd & 1) == 1) { - reArrange(sIndex, eIndex + 1); - return; - } - min |= 1; - while (max >= min) { - int pstart = sIndex; - while (true) { - while (pstart <= eIndex) { - if (indexLevels[pstart] >= max) { - break; - } - pstart += 1; - } - if (pstart > eIndex) { - break; - } - int pend = pstart + 1; - while (pend <= eIndex) { - if (indexLevels[pend] < max) { - break; - } - pend += 1; - } - reArrange(pstart, pend); - pstart = pend + 1; - } - max -= 1; - } - } - - /// internal method - void reArrange(int i, int j) { - final int length = (i + j) ~/ 2; - --j; - for (; i < length; ++i, --j) { - final int temp = indexes[i]; - indexes[i] = indexes[j]; - indexes[j] = temp; - } - } - - /// internal method - void update() { - mirroringShapeCharacters[40] = 41; - mirroringShapeCharacters[41] = 40; - mirroringShapeCharacters[60] = 62; - mirroringShapeCharacters[62] = 60; - mirroringShapeCharacters[91] = 93; - mirroringShapeCharacters[93] = 91; - mirroringShapeCharacters[123] = 125; - mirroringShapeCharacters[125] = 123; - mirroringShapeCharacters[171] = 187; - mirroringShapeCharacters[187] = 171; - mirroringShapeCharacters[8249] = 8250; - mirroringShapeCharacters[8250] = 8249; - mirroringShapeCharacters[8261] = 8262; - mirroringShapeCharacters[8262] = 8261; - mirroringShapeCharacters[8317] = 8318; - mirroringShapeCharacters[8318] = 8317; - mirroringShapeCharacters[8333] = 8334; - mirroringShapeCharacters[8334] = 8333; - mirroringShapeCharacters[8712] = 8715; - mirroringShapeCharacters[8713] = 8716; - mirroringShapeCharacters[8714] = 8717; - mirroringShapeCharacters[8715] = 8712; - mirroringShapeCharacters[8716] = 8713; - mirroringShapeCharacters[8717] = 8714; - mirroringShapeCharacters[8725] = 10741; - mirroringShapeCharacters[8764] = 8765; - mirroringShapeCharacters[8765] = 8764; - mirroringShapeCharacters[8771] = 8909; - mirroringShapeCharacters[8786] = 8787; - mirroringShapeCharacters[8787] = 8786; - mirroringShapeCharacters[8788] = 8789; - mirroringShapeCharacters[8789] = 8788; - mirroringShapeCharacters[8804] = 8805; - mirroringShapeCharacters[8805] = 8804; - mirroringShapeCharacters[8806] = 8807; - mirroringShapeCharacters[8807] = 8806; - mirroringShapeCharacters[8808] = 8809; - mirroringShapeCharacters[8809] = 8808; - mirroringShapeCharacters[8810] = 8811; - mirroringShapeCharacters[8811] = 8810; - mirroringShapeCharacters[8814] = 8815; - mirroringShapeCharacters[8815] = 8814; - mirroringShapeCharacters[8816] = 8817; - mirroringShapeCharacters[8817] = 8816; - mirroringShapeCharacters[8818] = 8819; - mirroringShapeCharacters[8819] = 8818; - mirroringShapeCharacters[8820] = 8821; - mirroringShapeCharacters[8821] = 8820; - mirroringShapeCharacters[8822] = 8823; - mirroringShapeCharacters[8823] = 8822; - mirroringShapeCharacters[8824] = 8825; - mirroringShapeCharacters[8825] = 8824; - mirroringShapeCharacters[8826] = 8827; - mirroringShapeCharacters[8827] = 8826; - mirroringShapeCharacters[8828] = 8829; - mirroringShapeCharacters[8829] = 8828; - mirroringShapeCharacters[8830] = 8831; - mirroringShapeCharacters[8831] = 8830; - mirroringShapeCharacters[8832] = 8833; - mirroringShapeCharacters[8833] = 8832; - mirroringShapeCharacters[8834] = 8835; - mirroringShapeCharacters[8835] = 8834; - mirroringShapeCharacters[8836] = 8837; - mirroringShapeCharacters[8837] = 8836; - mirroringShapeCharacters[8838] = 8839; - mirroringShapeCharacters[8839] = 8838; - mirroringShapeCharacters[8840] = 8841; - mirroringShapeCharacters[8841] = 8840; - mirroringShapeCharacters[8842] = 8843; - mirroringShapeCharacters[8843] = 8842; - mirroringShapeCharacters[8847] = 8848; - mirroringShapeCharacters[8848] = 8847; - mirroringShapeCharacters[8849] = 8850; - mirroringShapeCharacters[8850] = 8849; - mirroringShapeCharacters[8856] = 10680; - mirroringShapeCharacters[8866] = 8867; - mirroringShapeCharacters[8867] = 8866; - mirroringShapeCharacters[8870] = 10974; - mirroringShapeCharacters[8872] = 10980; - mirroringShapeCharacters[8873] = 10979; - mirroringShapeCharacters[8875] = 10981; - mirroringShapeCharacters[8880] = 8881; - mirroringShapeCharacters[8881] = 8880; - mirroringShapeCharacters[8882] = 8883; - mirroringShapeCharacters[8883] = 8882; - mirroringShapeCharacters[8884] = 8885; - mirroringShapeCharacters[8885] = 8884; - mirroringShapeCharacters[8886] = 8887; - mirroringShapeCharacters[8887] = 8886; - mirroringShapeCharacters[8905] = 8906; - mirroringShapeCharacters[8906] = 8905; - mirroringShapeCharacters[8907] = 8908; - mirroringShapeCharacters[8908] = 8907; - mirroringShapeCharacters[8909] = 8771; - mirroringShapeCharacters[8912] = 8913; - mirroringShapeCharacters[8913] = 8912; - mirroringShapeCharacters[8918] = 8919; - mirroringShapeCharacters[8919] = 8918; - mirroringShapeCharacters[8920] = 8921; - mirroringShapeCharacters[8921] = 8920; - mirroringShapeCharacters[8922] = 8923; - mirroringShapeCharacters[8923] = 8922; - mirroringShapeCharacters[8924] = 8925; - mirroringShapeCharacters[8925] = 8924; - mirroringShapeCharacters[8926] = 8927; - mirroringShapeCharacters[8927] = 8926; - mirroringShapeCharacters[8928] = 8929; - mirroringShapeCharacters[8929] = 8928; - mirroringShapeCharacters[8930] = 8931; - mirroringShapeCharacters[8931] = 8930; - mirroringShapeCharacters[8932] = 8933; - mirroringShapeCharacters[8933] = 8932; - mirroringShapeCharacters[8934] = 8935; - mirroringShapeCharacters[8935] = 8934; - mirroringShapeCharacters[8936] = 8937; - mirroringShapeCharacters[8937] = 8936; - mirroringShapeCharacters[8938] = 8939; - mirroringShapeCharacters[8939] = 8938; - mirroringShapeCharacters[8940] = 8941; - mirroringShapeCharacters[8941] = 8940; - mirroringShapeCharacters[8944] = 8945; - mirroringShapeCharacters[8945] = 8944; - mirroringShapeCharacters[8946] = 8954; - mirroringShapeCharacters[8947] = 8955; - mirroringShapeCharacters[8948] = 8956; - mirroringShapeCharacters[8950] = 8957; - mirroringShapeCharacters[8951] = 8958; - mirroringShapeCharacters[8954] = 8946; - mirroringShapeCharacters[8955] = 8947; - mirroringShapeCharacters[8956] = 8948; - mirroringShapeCharacters[8957] = 8950; - mirroringShapeCharacters[8958] = 8951; - mirroringShapeCharacters[8968] = 8969; - mirroringShapeCharacters[8969] = 8968; - mirroringShapeCharacters[8970] = 8971; - mirroringShapeCharacters[8971] = 8970; - mirroringShapeCharacters[9001] = 9002; - mirroringShapeCharacters[9002] = 9001; - mirroringShapeCharacters[10088] = 10089; - mirroringShapeCharacters[10089] = 10088; - mirroringShapeCharacters[10090] = 10091; - mirroringShapeCharacters[10091] = 10090; - mirroringShapeCharacters[10092] = 10093; - mirroringShapeCharacters[10093] = 10092; - mirroringShapeCharacters[10094] = 10095; - mirroringShapeCharacters[10095] = 10094; - mirroringShapeCharacters[10096] = 10097; - mirroringShapeCharacters[10097] = 10096; - mirroringShapeCharacters[10098] = 10099; - mirroringShapeCharacters[10099] = 10098; - mirroringShapeCharacters[10100] = 10101; - mirroringShapeCharacters[10101] = 10100; - mirroringShapeCharacters[10197] = 10198; - mirroringShapeCharacters[10198] = 10197; - mirroringShapeCharacters[10205] = 10206; - mirroringShapeCharacters[10206] = 10205; - mirroringShapeCharacters[10210] = 10211; - mirroringShapeCharacters[10211] = 10210; - mirroringShapeCharacters[10212] = 10213; - mirroringShapeCharacters[10213] = 10212; - mirroringShapeCharacters[10214] = 10215; - mirroringShapeCharacters[10215] = 10214; - mirroringShapeCharacters[10216] = 10217; - mirroringShapeCharacters[10217] = 10216; - mirroringShapeCharacters[10218] = 10219; - mirroringShapeCharacters[10219] = 10218; - mirroringShapeCharacters[10627] = 10628; - mirroringShapeCharacters[10628] = 10627; - mirroringShapeCharacters[10629] = 10630; - mirroringShapeCharacters[10630] = 10629; - mirroringShapeCharacters[10631] = 10632; - mirroringShapeCharacters[10632] = 10631; - mirroringShapeCharacters[10633] = 10634; - mirroringShapeCharacters[10634] = 10633; - mirroringShapeCharacters[10635] = 10636; - mirroringShapeCharacters[10636] = 10635; - mirroringShapeCharacters[10637] = 10640; - mirroringShapeCharacters[10638] = 10639; - mirroringShapeCharacters[10639] = 10638; - mirroringShapeCharacters[10640] = 10637; - mirroringShapeCharacters[10641] = 10642; - mirroringShapeCharacters[10642] = 10641; - mirroringShapeCharacters[10643] = 10644; - mirroringShapeCharacters[10644] = 10643; - mirroringShapeCharacters[10645] = 10646; - mirroringShapeCharacters[10646] = 10645; - mirroringShapeCharacters[10647] = 10648; - mirroringShapeCharacters[10648] = 10647; - mirroringShapeCharacters[10680] = 8856; - mirroringShapeCharacters[10688] = 10689; - mirroringShapeCharacters[10689] = 10688; - mirroringShapeCharacters[10692] = 10693; - mirroringShapeCharacters[10693] = 10692; - mirroringShapeCharacters[10703] = 10704; - mirroringShapeCharacters[10704] = 10703; - mirroringShapeCharacters[10705] = 10706; - mirroringShapeCharacters[10706] = 10705; - mirroringShapeCharacters[10708] = 10709; - mirroringShapeCharacters[10709] = 10708; - mirroringShapeCharacters[10712] = 10713; - mirroringShapeCharacters[10713] = 10712; - mirroringShapeCharacters[10714] = 10715; - mirroringShapeCharacters[10715] = 10714; - mirroringShapeCharacters[10741] = 8725; - mirroringShapeCharacters[10744] = 10745; - mirroringShapeCharacters[10745] = 10744; - mirroringShapeCharacters[10748] = 10749; - mirroringShapeCharacters[10749] = 10748; - mirroringShapeCharacters[10795] = 10796; - mirroringShapeCharacters[10796] = 10795; - mirroringShapeCharacters[10797] = 10796; - mirroringShapeCharacters[10798] = 10797; - mirroringShapeCharacters[10804] = 10805; - mirroringShapeCharacters[10805] = 10804; - mirroringShapeCharacters[10812] = 10813; - mirroringShapeCharacters[10813] = 10812; - mirroringShapeCharacters[10852] = 10853; - mirroringShapeCharacters[10853] = 10852; - mirroringShapeCharacters[10873] = 10874; - mirroringShapeCharacters[10874] = 10873; - mirroringShapeCharacters[10877] = 10878; - mirroringShapeCharacters[10878] = 10877; - mirroringShapeCharacters[10879] = 10880; - mirroringShapeCharacters[10880] = 10879; - mirroringShapeCharacters[10881] = 10882; - mirroringShapeCharacters[10882] = 10881; - mirroringShapeCharacters[10883] = 10884; - mirroringShapeCharacters[10884] = 10883; - mirroringShapeCharacters[10891] = 10892; - mirroringShapeCharacters[10892] = 10891; - mirroringShapeCharacters[10897] = 10898; - mirroringShapeCharacters[10898] = 10897; - mirroringShapeCharacters[10899] = 10900; - mirroringShapeCharacters[10900] = 10899; - mirroringShapeCharacters[10901] = 10902; - mirroringShapeCharacters[10902] = 10901; - mirroringShapeCharacters[10903] = 10904; - mirroringShapeCharacters[10904] = 10903; - mirroringShapeCharacters[10905] = 10906; - mirroringShapeCharacters[10906] = 10905; - mirroringShapeCharacters[10907] = 10908; - mirroringShapeCharacters[10908] = 10907; - mirroringShapeCharacters[10913] = 10914; - mirroringShapeCharacters[10914] = 10913; - mirroringShapeCharacters[10918] = 10919; - mirroringShapeCharacters[10919] = 10918; - mirroringShapeCharacters[10920] = 10921; - mirroringShapeCharacters[10921] = 10920; - mirroringShapeCharacters[10922] = 10923; - mirroringShapeCharacters[10923] = 10922; - mirroringShapeCharacters[10924] = 10925; - mirroringShapeCharacters[10925] = 10924; - mirroringShapeCharacters[10927] = 10928; - mirroringShapeCharacters[10928] = 10927; - mirroringShapeCharacters[10931] = 10932; - mirroringShapeCharacters[10932] = 10931; - mirroringShapeCharacters[10939] = 10940; - mirroringShapeCharacters[10940] = 10939; - mirroringShapeCharacters[10941] = 10942; - mirroringShapeCharacters[10942] = 10941; - mirroringShapeCharacters[10943] = 10944; - mirroringShapeCharacters[10944] = 10943; - mirroringShapeCharacters[10945] = 10946; - mirroringShapeCharacters[10946] = 10945; - mirroringShapeCharacters[10947] = 10948; - mirroringShapeCharacters[10948] = 10947; - mirroringShapeCharacters[10949] = 10950; - mirroringShapeCharacters[10950] = 10949; - mirroringShapeCharacters[10957] = 10958; - mirroringShapeCharacters[10958] = 10957; - mirroringShapeCharacters[10959] = 10960; - mirroringShapeCharacters[10960] = 10959; - mirroringShapeCharacters[10961] = 10962; - mirroringShapeCharacters[10962] = 10961; - mirroringShapeCharacters[10963] = 10964; - mirroringShapeCharacters[10964] = 10963; - mirroringShapeCharacters[10965] = 10966; - mirroringShapeCharacters[10966] = 10965; - mirroringShapeCharacters[10974] = 8870; - mirroringShapeCharacters[10979] = 8873; - mirroringShapeCharacters[10980] = 8872; - mirroringShapeCharacters[10981] = 8875; - mirroringShapeCharacters[10988] = 10989; - mirroringShapeCharacters[10989] = 10988; - mirroringShapeCharacters[10999] = 11000; - mirroringShapeCharacters[11000] = 10999; - mirroringShapeCharacters[11001] = 11002; - mirroringShapeCharacters[11002] = 11001; - mirroringShapeCharacters[12296] = 12297; - mirroringShapeCharacters[12297] = 12296; - mirroringShapeCharacters[12298] = 12299; - mirroringShapeCharacters[12299] = 12298; - mirroringShapeCharacters[12300] = 12301; - mirroringShapeCharacters[12301] = 12300; - mirroringShapeCharacters[12302] = 12303; - mirroringShapeCharacters[12303] = 12302; - mirroringShapeCharacters[12304] = 12305; - mirroringShapeCharacters[12305] = 12304; - mirroringShapeCharacters[12308] = 12309; - mirroringShapeCharacters[12309] = 12308; - mirroringShapeCharacters[12310] = 12311; - mirroringShapeCharacters[12311] = 12310; - mirroringShapeCharacters[12312] = 12313; - mirroringShapeCharacters[12313] = 12312; - mirroringShapeCharacters[12314] = 12315; - mirroringShapeCharacters[12315] = 12314; - mirroringShapeCharacters[65288] = 65289; - mirroringShapeCharacters[65289] = 65288; - mirroringShapeCharacters[65308] = 65310; - mirroringShapeCharacters[65310] = 65308; - mirroringShapeCharacters[65339] = 65341; - mirroringShapeCharacters[65341] = 65339; - mirroringShapeCharacters[65371] = 65373; - mirroringShapeCharacters[65373] = 65371; - mirroringShapeCharacters[65375] = 65376; - mirroringShapeCharacters[65376] = 65375; - mirroringShapeCharacters[65378] = 65379; - mirroringShapeCharacters[65379] = 65378; - } -} - -class _RTLCharacters { - // Constructor. - _RTLCharacters() { - for (int i = 0; i < charTypes.length; ++i) { - int start = charTypes[i]; - final int end = charTypes[++i]; - final int b = charTypes[++i].toSigned(8); - while (start <= end) { - rtlCharacterTypes[start++] = b; - } - } - } - - // Constants and Fields - // Specifies the character types. - late List types; //sbyte - // Specifies the text order (RTL or LTR). - int textOrder = -1; //sbyte - // Specifies the text length. - int? length; - // Specifies the resultant types. - late List result; //sbyte - // Specifies the resultant levels. - late List levels; //sbyte - // Specifies the RTL character types. - List rtlCharacterTypes = List.filled( - 65536, - 0, - growable: true, - ); //sbyte - - // Left-to-Right (Non-European or non-Arabic digits). - static const int l = 0; - // Left-to-Right Embedding - static const int lre = 1; - // Left-to-Right Override - static const int lro = 2; - // Right-to-Left (Hebrew alphabet, and related punctuation). - static const int r = 3; - // Right-to-Left Arabic - static const int al = 4; - // Right-to-Left Embedding. - static const int rle = 5; - // Right-to-Left Override - static const int rlo = 6; - // Pop Directional Format - static const int pdf = 7; - // European Number (European digits, Eastern Arabic-Indic digits). - static const int en = 8; - // European Number Separator (Plus sign, Minus sign). - static const int es = 9; - // European Number Terminator (Degree sign, currency symbols). - static const int et = 10; - // Arabic Number (Arabic-Indic digits, - // Arabic decimal and thousands separators). - static const int an = 11; - // Common Number Separator (Colon, Comma, Full Stop, No-Break Space. - static const int cs = 12; - // Nonspacing Mark (Characters with the General_Category values). - static const int nsm = 13; - // Boundary Neutral (Default ignorables, non-characters, - // and control characters, other than those explicitly given other types.) - static const int bn = 14; - // Paragraph Separator (Paragraph separator, appropriate Newline Functions, - // higher-level protocol paragraph determination). - static const int b = 15; - // Segment Separator (tab). - static const int s = 16; - // Whitespace (Space, Figure space, Line separator, - // Form feed, General Punctuation spaces). - static const int ws = 17; - // Other Neutrals (All other characters, - // including object replacement character). - static const int otn = 18; - - List charTypes = [ - l, - en, - bn, - es, - es, - s, - et, - et, - b, - an, - an, - s, - cs, - cs, - ws, - nsm, - nsm, - b, - bn, - 27, - bn, - 28, - 30, - b, - 31, - 31, - s, - 32, - 32, - ws, - 33, - 34, - otn, - 35, - 37, - et, - 38, - 42, - otn, - 43, - 43, - es, - 44, - 44, - cs, - 45, - 45, - es, - 46, - 46, - cs, - 47, - 47, - cs, - 48, - 57, - en, - 58, - 58, - cs, - 59, - 64, - otn, - 65, - 90, - l, - 91, - 96, - otn, - 97, - 122, - l, - 123, - 126, - otn, - 127, - 132, - bn, - 133, - 133, - b, - 134, - 159, - bn, - 160, - 160, - cs, - 161, - 161, - otn, - 162, - 165, - et, - 166, - 169, - otn, - 170, - 170, - l, - 171, - 175, - otn, - 176, - 177, - et, - 178, - 179, - en, - 180, - 180, - otn, - 181, - 181, - l, - 182, - 184, - otn, - 185, - 185, - en, - 186, - 186, - l, - 187, - 191, - otn, - 192, - 214, - l, - 215, - 215, - otn, - 216, - 246, - l, - 247, - 247, - otn, - 248, - 696, - l, - 697, - 698, - otn, - 699, - 705, - l, - 706, - 719, - otn, - 720, - 721, - l, - 722, - 735, - otn, - 736, - 740, - l, - 741, - 749, - otn, - 750, - 750, - l, - 751, - 767, - otn, - 768, - 855, - nsm, - 856, - 860, - l, - 861, - 879, - nsm, - 880, - 883, - l, - 884, - 885, - otn, - 886, - 893, - l, - 894, - 894, - otn, - 895, - 899, - l, - 900, - 901, - otn, - 902, - 902, - l, - 903, - 903, - otn, - 904, - 1013, - l, - 1014, - 1014, - otn, - 1015, - 1154, - l, - 1155, - 1158, - nsm, - 1159, - 1159, - l, - 1160, - 1161, - nsm, - 1162, - 1417, - l, - 1418, - 1418, - otn, - 1419, - 1424, - l, - 1425, - 1441, - nsm, - 1442, - 1442, - l, - 1443, - 1465, - nsm, - 1466, - 1466, - l, - 1467, - 1469, - nsm, - 1470, - 1470, - r, - 1471, - 1471, - nsm, - 1472, - 1472, - r, - 1473, - 1474, - nsm, - 1475, - 1475, - r, - 1476, - 1476, - nsm, - 1477, - 1487, - l, - 1488, - 1514, - r, - 1515, - 1519, - l, - 1520, - 1524, - r, - 1525, - 1535, - l, - 1536, - 1539, - al, - 1540, - 1547, - l, - 1548, - 1548, - cs, - 1549, - 1549, - al, - 1550, - 1551, - otn, - 1552, - 1557, - nsm, - 1558, - 1562, - l, - 1563, - 1563, - al, - 1564, - 1566, - l, - 1567, - 1567, - al, - 1568, - 1568, - l, - 1569, - 1594, - al, - 1595, - 1599, - l, - 1600, - 1610, - al, - 1611, - 1624, - nsm, - 1625, - 1631, - l, - 1632, - 1641, - an, - 1642, - 1642, - et, - 1643, - 1644, - an, - 1645, - 1647, - al, - 1648, - 1648, - nsm, - 1649, - 1749, - al, - 1750, - 1756, - nsm, - 1757, - 1757, - al, - 1758, - 1764, - nsm, - 1765, - 1766, - al, - 1767, - 1768, - nsm, - 1769, - 1769, - otn, - 1770, - 1773, - nsm, - 1774, - 1775, - al, - 1776, - 1785, - en, - 1786, - 1805, - al, - 1806, - 1806, - l, - 1807, - 1807, - bn, - 1808, - 1808, - al, - 1809, - 1809, - nsm, - 1810, - 1839, - al, - 1840, - 1866, - nsm, - 1867, - 1868, - l, - 1869, - 1871, - al, - 1872, - 1919, - l, - 1920, - 1957, - al, - 1958, - 1968, - nsm, - 1969, - 1969, - al, - 1970, - 2304, - l, - 2305, - 2306, - nsm, - 2307, - 2363, - l, - 2364, - 2364, - nsm, - 2365, - 2368, - l, - 2369, - 2376, - nsm, - 2377, - 2380, - l, - 2381, - 2381, - nsm, - 2382, - 2384, - l, - 2385, - 2388, - nsm, - 2389, - 2401, - l, - 2402, - 2403, - nsm, - 2404, - 2432, - l, - 2433, - 2433, - nsm, - 2434, - 2491, - l, - 2492, - 2492, - nsm, - 2493, - 2496, - l, - 2497, - 2500, - nsm, - 2501, - 2508, - l, - 2509, - 2509, - nsm, - 2510, - 2529, - l, - 2530, - 2531, - nsm, - 2532, - 2545, - l, - 2546, - 2547, - et, - 2548, - 2560, - l, - 2561, - 2562, - nsm, - 2563, - 2619, - l, - 2620, - 2620, - nsm, - 2621, - 2624, - l, - 2625, - 2626, - nsm, - 2627, - 2630, - l, - 2631, - 2632, - nsm, - 2633, - 2634, - l, - 2635, - 2637, - nsm, - 2638, - 2671, - l, - 2672, - 2673, - nsm, - 2674, - 2688, - l, - 2689, - 2690, - nsm, - 2691, - 2747, - l, - 2748, - 2748, - nsm, - 2749, - 2752, - l, - 2753, - 2757, - nsm, - 2758, - 2758, - l, - 2759, - 2760, - nsm, - 2761, - 2764, - l, - 2765, - 2765, - nsm, - 2766, - 2785, - l, - 2786, - 2787, - nsm, - 2788, - 2800, - l, - 2801, - 2801, - et, - 2802, - 2816, - l, - 2817, - 2817, - nsm, - 2818, - 2875, - l, - 2876, - 2876, - nsm, - 2877, - 2878, - l, - 2879, - 2879, - nsm, - 2880, - 2880, - l, - 2881, - 2883, - nsm, - 2884, - 2892, - l, - 2893, - 2893, - nsm, - 2894, - 2901, - l, - 2902, - 2902, - nsm, - 2903, - 2945, - l, - 2946, - 2946, - nsm, - 2947, - 3007, - l, - 3008, - 3008, - nsm, - 3009, - 3020, - l, - 3021, - 3021, - nsm, - 3022, - 3058, - l, - 3059, - 3064, - otn, - 3065, - 3065, - et, - 3066, - 3066, - otn, - 3067, - 3133, - l, - 3134, - 3136, - nsm, - 3137, - 3141, - l, - 3142, - 3144, - nsm, - 3145, - 3145, - l, - 3146, - 3149, - nsm, - 3150, - 3156, - l, - 3157, - 3158, - nsm, - 3159, - 3259, - l, - 3260, - 3260, - nsm, - 3261, - 3275, - l, - 3276, - 3277, - nsm, - 3278, - 3392, - l, - 3393, - 3395, - nsm, - 3396, - 3404, - l, - 3405, - 3405, - nsm, - 3406, - 3529, - l, - 3530, - 3530, - nsm, - 3531, - 3537, - l, - 3538, - 3540, - nsm, - 3541, - 3541, - l, - 3542, - 3542, - nsm, - 3543, - 3632, - l, - 3633, - 3633, - nsm, - 3634, - 3635, - l, - 3636, - 3642, - nsm, - 3643, - 3646, - l, - 3647, - 3647, - et, - 3648, - 3654, - l, - 3655, - 3662, - nsm, - 3663, - 3760, - l, - 3761, - 3761, - nsm, - 3762, - 3763, - l, - 3764, - 3769, - nsm, - 3770, - 3770, - l, - 3771, - 3772, - nsm, - 3773, - 3783, - l, - 3784, - 3789, - nsm, - 3790, - 3863, - l, - 3864, - 3865, - nsm, - 3866, - 3892, - l, - 3893, - 3893, - nsm, - 3894, - 3894, - l, - 3895, - 3895, - nsm, - 3896, - 3896, - l, - 3897, - 3897, - nsm, - 3898, - 3901, - otn, - 3902, - 3952, - l, - 3953, - 3966, - nsm, - 3967, - 3967, - l, - 3968, - 3972, - nsm, - 3973, - 3973, - l, - 3974, - 3975, - nsm, - 3976, - 3983, - l, - 3984, - 3991, - nsm, - 3992, - 3992, - l, - 3993, - 4028, - nsm, - 4029, - 4037, - l, - 4038, - 4038, - nsm, - 4039, - 4140, - l, - 4141, - 4144, - nsm, - 4145, - 4145, - l, - 4146, - 4146, - nsm, - 4147, - 4149, - l, - 4150, - 4151, - nsm, - 4152, - 4152, - l, - 4153, - 4153, - nsm, - 4154, - 4183, - l, - 4184, - 4185, - nsm, - 4186, - 5759, - l, - 5760, - 5760, - ws, - 5761, - 5786, - l, - 5787, - 5788, - otn, - 5789, - 5905, - l, - 5906, - 5908, - nsm, - 5909, - 5937, - l, - 5938, - 5940, - nsm, - 5941, - 5969, - l, - 5970, - 5971, - nsm, - 5972, - 6001, - l, - 6002, - 6003, - nsm, - 6004, - 6070, - l, - 6071, - 6077, - nsm, - 6078, - 6085, - l, - 6086, - 6086, - nsm, - 6087, - 6088, - l, - 6089, - 6099, - nsm, - 6100, - 6106, - l, - 6107, - 6107, - et, - 6108, - 6108, - l, - 6109, - 6109, - nsm, - 6110, - 6127, - l, - 6128, - 6137, - otn, - 6138, - 6143, - l, - 6144, - 6154, - otn, - 6155, - 6157, - nsm, - 6158, - 6158, - ws, - 6159, - 6312, - l, - 6313, - 6313, - nsm, - 6314, - 6431, - l, - 6432, - 6434, - nsm, - 6435, - 6438, - l, - 6439, - 6443, - nsm, - 6444, - 6449, - l, - 6450, - 6450, - nsm, - 6451, - 6456, - l, - 6457, - 6459, - nsm, - 6460, - 6463, - l, - 6464, - 6464, - otn, - 6465, - 6467, - l, - 6468, - 6469, - otn, - 6470, - 6623, - l, - 6624, - 6655, - otn, - 6656, - 8124, - l, - 8125, - 8125, - otn, - 8126, - 8126, - l, - 8127, - 8129, - otn, - 8130, - 8140, - l, - 8141, - 8143, - otn, - 8144, - 8156, - l, - 8157, - 8159, - otn, - 8160, - 8172, - l, - 8173, - 8175, - otn, - 8176, - 8188, - l, - 8189, - 8190, - otn, - 8191, - 8191, - l, - 8192, - 8202, - ws, - 8203, - 8205, - bn, - 8206, - 8206, - l, - 8207, - 8207, - r, - 8208, - 8231, - otn, - 8232, - 8232, - ws, - 8233, - 8233, - b, - 8234, - 8234, - lre, - 8235, - 8235, - rle, - 8236, - 8236, - pdf, - 8237, - 8237, - lro, - 8238, - 8238, - rlo, - 8239, - 8239, - ws, - 8240, - 8244, - et, - 8245, - 8276, - otn, - 8277, - 8278, - l, - 8279, - 8279, - otn, - 8280, - 8286, - l, - 8287, - 8287, - ws, - 8288, - 8291, - bn, - 8292, - 8297, - l, - 8298, - 8303, - bn, - 8304, - 8304, - en, - 8305, - 8307, - l, - 8308, - 8313, - en, - 8314, - 8315, - et, - 8316, - 8318, - otn, - 8319, - 8319, - l, - 8320, - 8329, - en, - 8330, - 8331, - et, - 8332, - 8334, - otn, - 8335, - 8351, - l, - 8352, - 8369, - et, - 8370, - 8399, - l, - 8400, - 8426, - nsm, - 8427, - 8447, - l, - 8448, - 8449, - otn, - 8450, - 8450, - l, - 8451, - 8454, - otn, - 8455, - 8455, - l, - 8456, - 8457, - otn, - 8458, - 8467, - l, - 8468, - 8468, - otn, - 8469, - 8469, - l, - 8470, - 8472, - otn, - 8473, - 8477, - l, - 8478, - 8483, - otn, - 8484, - 8484, - l, - 8485, - 8485, - otn, - 8486, - 8486, - l, - 8487, - 8487, - otn, - 8488, - 8488, - l, - 8489, - 8489, - otn, - 8490, - 8493, - l, - 8494, - 8494, - et, - 8495, - 8497, - l, - 8498, - 8498, - otn, - 8499, - 8505, - l, - 8506, - 8507, - otn, - 8508, - 8511, - l, - 8512, - 8516, - otn, - 8517, - 8521, - l, - 8522, - 8523, - otn, - 8524, - 8530, - l, - 8531, - 8543, - otn, - 8544, - 8591, - l, - 8592, - 8721, - otn, - 8722, - 8723, - et, - 8724, - 9013, - otn, - 9014, - 9082, - l, - 9083, - 9108, - otn, - 9109, - 9109, - l, - 9110, - 9168, - otn, - 9169, - 9215, - l, - 9216, - 9254, - otn, - 9255, - 9279, - l, - 9280, - 9290, - otn, - 9291, - 9311, - l, - 9312, - 9371, - en, - 9372, - 9449, - l, - 9450, - 9450, - en, - 9451, - 9751, - otn, - 9752, - 9752, - l, - 9753, - 9853, - otn, - 9854, - 9855, - l, - 9856, - 9873, - otn, - 9874, - 9887, - l, - 9888, - 9889, - otn, - 9890, - 9984, - l, - 9985, - 9988, - otn, - 9989, - 9989, - l, - 9990, - 9993, - otn, - 9994, - 9995, - l, - 9996, - 10023, - otn, - 10024, - 10024, - l, - 10025, - 10059, - otn, - 10060, - 10060, - l, - 10061, - 10061, - otn, - 10062, - 10062, - l, - 10063, - 10066, - otn, - 10067, - 10069, - l, - 10070, - 10070, - otn, - 10071, - 10071, - l, - 10072, - 10078, - otn, - 10079, - 10080, - l, - 10081, - 10132, - otn, - 10133, - 10135, - l, - 10136, - 10159, - otn, - 10160, - 10160, - l, - 10161, - 10174, - otn, - 10175, - 10191, - l, - 10192, - 10219, - otn, - 10220, - 10223, - l, - 10224, - 11021, - otn, - 11022, - 11903, - l, - 11904, - 11929, - otn, - 11930, - 11930, - l, - 11931, - 12019, - otn, - 12020, - 12031, - l, - 12032, - 12245, - otn, - 12246, - 12271, - l, - 12272, - 12283, - otn, - 12284, - 12287, - l, - 12288, - 12288, - ws, - 12289, - 12292, - otn, - 12293, - 12295, - l, - 12296, - 12320, - otn, - 12321, - 12329, - l, - 12330, - 12335, - nsm, - 12336, - 12336, - otn, - 12337, - 12341, - l, - 12342, - 12343, - otn, - 12344, - 12348, - l, - 12349, - 12351, - otn, - 12352, - 12440, - l, - 12441, - 12442, - nsm, - 12443, - 12444, - otn, - 12445, - 12447, - l, - 12448, - 12448, - otn, - 12449, - 12538, - l, - 12539, - 12539, - otn, - 12540, - 12828, - l, - 12829, - 12830, - otn, - 12831, - 12879, - l, - 12880, - 12895, - otn, - 12896, - 12923, - l, - 12924, - 12925, - otn, - 12926, - 12976, - l, - 12977, - 12991, - otn, - 12992, - 13003, - l, - 13004, - 13007, - otn, - 13008, - 13174, - l, - 13175, - 13178, - otn, - 13179, - 13277, - l, - 13278, - 13279, - otn, - 13280, - 13310, - l, - 13311, - 13311, - otn, - 13312, - 19903, - l, - 19904, - 19967, - otn, - 19968, - 42127, - l, - 42128, - 42182, - otn, - 42183, - 64284, - l, - 64285, - 64285, - r, - 64286, - 64286, - nsm, - 64287, - 64296, - r, - 64297, - 64297, - et, - 64298, - 64310, - r, - 64311, - 64311, - l, - 64312, - 64316, - r, - 64317, - 64317, - l, - 64318, - 64318, - r, - 64319, - 64319, - l, - 64320, - 64321, - r, - 64322, - 64322, - l, - 64323, - 64324, - r, - 64325, - 64325, - l, - 64326, - 64335, - r, - 64336, - 64433, - al, - 64434, - 64466, - l, - 64467, - 64829, - al, - 64830, - 64831, - otn, - 64832, - 64847, - l, - 64848, - 64911, - al, - 64912, - 64913, - l, - 64914, - 64967, - al, - 64968, - 65007, - l, - 65008, - 65020, - al, - 65021, - 65021, - otn, - 65022, - 65023, - l, - 65024, - 65039, - nsm, - 65040, - 65055, - l, - 65056, - 65059, - nsm, - 65060, - 65071, - l, - 65072, - 65103, - otn, - 65104, - 65104, - cs, - 65105, - 65105, - otn, - 65106, - 65106, - cs, - 65107, - 65107, - l, - 65108, - 65108, - otn, - 65109, - 65109, - cs, - 65110, - 65118, - otn, - 65119, - 65119, - et, - 65120, - 65121, - otn, - 65122, - 65123, - et, - 65124, - 65126, - otn, - 65127, - 65127, - l, - 65128, - 65128, - otn, - 65129, - 65130, - et, - 65131, - 65131, - otn, - 65132, - 65135, - l, - 65136, - 65140, - al, - 65141, - 65141, - l, - 65142, - 65276, - al, - 65277, - 65278, - l, - 65279, - 65279, - bn, - 65280, - 65280, - l, - 65281, - 65282, - otn, - 65283, - 65285, - et, - 65286, - 65290, - otn, - 65291, - 65291, - et, - 65292, - 65292, - cs, - 65293, - 65293, - et, - 65294, - 65294, - cs, - 65295, - 65295, - es, - 65296, - 65305, - en, - 65306, - 65306, - cs, - 65307, - 65312, - otn, - 65313, - 65338, - l, - 65339, - 65344, - otn, - 65345, - 65370, - l, - 65371, - 65381, - otn, - 65382, - 65503, - l, - 65504, - 65505, - et, - 65506, - 65508, - otn, - 65509, - 65510, - et, - 65511, - 65511, - l, - 65512, - 65518, - otn, - 65519, - 65528, - l, - 65529, - 65531, - bn, - 65532, - 65533, - otn, - 65534, - 65535, - l, - ]; - - // Implementations. - List getVisualOrder(String inputText, bool isRTL) { - types = getCharacterCode(inputText); - textOrder = isRTL ? lre : l; - doVisualOrder(); - final List result = List.filled( - this.result.length, - 0, - growable: true, - ); - for (int i = 0; i < levels.length; i++) { - result[i] = levels[i].toUnsigned(8); - } - return result; - } - - List getCharacterCode(String text) { - final List characterCodes = List.filled( - text.length, - 0, - growable: true, - ); - for (int i = 0; i < text.length; i++) { - characterCodes[i] = rtlCharacterTypes[text[i].codeUnitAt(0)]; - } - return characterCodes; - } - - void doVisualOrder() { - length = types.length; - //ignore:prefer_spread_collections - result = []..addAll(types); - levels = List.filled(length!, 0, growable: true); - setLevels(); - length = getEmbeddedCharactersLength(); - int preview = textOrder; - int i = 0; - while (i < length!) { - final int level = levels[i]; - final int preType = - (([preview, level].reduce(max) & 0x1) == 0) ? l : r; - int lengths = i + 1; - while (lengths < length! && levels[lengths] == level) { - ++lengths; - } - final int success = lengths < length! ? levels[lengths] : textOrder; - final int type = (([success, level].reduce(max) & 0x1) == 0) ? l : r; - checkNSM(i, length!, level, preType, type); - updateLevels(i, level, length); - preview = level; - i = length!; - } - checkEmbeddedCharacters(length); - } - - void updateLevels(int index, int level, int? length) { - if ((level & 1) == 0) { - for (int i = index; i < length!; ++i) { - if (result[i] == r) { - levels[i] += 1; - } else if (result[i] != l) { - levels[i] += 2; - } - } - } else { - for (int i = index; i < length!; ++i) { - if (result[i] != r) { - levels[i] += 1; - } - } - } - } - - void setLevels() { - setDefaultLevels(); - for (int n = 0; n < length!; ++n) { - int level = levels[n].toUnsigned(8); - if ((level & 0x80) != 0) { - level &= 0x7f; - result[n] = ((level & 0x1) == 0) ? l : r; - } - levels[n] = level; - } - } - - void setDefaultLevels() { - for (int i = 0; i < length!; i++) { - levels[i] = textOrder; - } - } - - int getEmbeddedCharactersLength() { - int index = 0; - for (int i = 0; i < length!; ++i) { - if (!(types[i] == lre || - types[i] == rle || - types[i] == lro || - types[i] == rlo || - types[i] == pdf || - types[i] == bn)) { - result[index] = result[i]; - levels[index] = levels[i]; - index++; - } - } - return index; - } - - void checkEmbeddedCharacters(int? length) { - for (int i = types.length - 1; i >= 0; --i) { - if (types[i] == lre || - types[i] == rle || - types[i] == lro || - types[i] == rlo || - types[i] == pdf || - types[i] == bn) { - result[i] = types[i]; - levels[i] = -1; - } else { - length = length! - 1; - result[i] = result[length]; - levels[i] = levels[length]; - } - } - for (int i = 0; i < types.length; i++) { - if (levels[i] == -1) { - if (i == 0) { - levels[i] = textOrder; - } else { - levels[i] = levels[i - 1]; - } - } - } - } - - void checkNSM(int index, int length, int level, int startType, int endType) { - int charType = startType.toSigned(8); - for (int i = index; i < length; ++i) { - if (result[i] == nsm) { - result[i] = charType; - } else { - charType = result[i]; - } - } - checkEuropeanDigits(index, length, level, startType, endType); - } - - void checkEuropeanDigits( - int index, - int length, - int level, - int startType, - int endType, - ) { - for (int i = index; i < length; ++i) { - if (result[i] == en) { - for (int j = i - 1; j >= index; --j) { - if (result[j] == l || result[j] == r || result[j] == al) { - if (result[j] == al) { - result[i] = an; - } - break; - } - } - } - } - checkArabicCharacters(index, length, level, startType, endType); - } - - void checkArabicCharacters( - int index, - int length, - int level, - int startType, - int endType, - ) { - for (int i = index; i < length; ++i) { - if (result[i] == al) { - result[i] = r; - } - } - checkEuropeanNumberSeparator(index, length, level, startType, endType); - } - - void checkEuropeanNumberSeparator( - int index, - int length, - int level, - int startType, - int endType, - ) { - for (int i = index + 1; i < length - 1; ++i) { - if (result[i] == es || result[i] == cs) { - final int preview = result[i - 1]; - final int success = result[i + 1]; - if (preview == en && success == en) { - result[i] = en; - } else if (result[i] == cs && preview == an && success == an) { - result[i] = an; - } - } - } - checkEuropeanNumberTerminator(index, length, level, startType, endType); - } - - void checkEuropeanNumberTerminator( - int index, - int length, - int level, - int startType, - int endType, - ) { - for (int i = index; i < length; ++i) { - if (result[i] == et) { - final int s = i; - final int l = getLength(s, length, [et]); - int data = s == index ? startType : result[s - 1]; - if (data != en) { - data = (l == length) ? endType : result[l]; - } - if (data == en) { - for (int j = s; j < l; ++j) { - result[j] = en; - } - } - i = l; - } - } - checkOtherNeutrals(index, length, level, startType, endType); - } - - int getLength(int index, int length, List validSet) { - --index; - while (++index < length) { - final int t = result[index]; - for (int i = 0; i < validSet.length; ++i) { - if (t == validSet[i]) { - index = getLength(++index, length, validSet); - } - } - return index; - } - return length; - } - - void checkOtherNeutrals( - int index, - int length, - int level, - int startType, - int endType, - ) { - for (int i = index; i < length; ++i) { - if (result[i] == es || result[i] == et || result[i] == cs) { - result[i] = otn; - } - } - checkOtherCharacters(index, length, level, startType, endType); - } - - void checkOtherCharacters( - int index, - int length, - int level, - int startType, - int endType, - ) { - for (int i = index; i < length; ++i) { - if (result[i] == en) { - int pst = startType; - for (int j = i - 1; j >= index; --j) { - if (result[j] == l || result[j] == r) { - pst = result[j]; - break; - } - } - if (pst == l) { - result[i] = l; - } - } - } - checkCommanCharacters(index, length, level, startType, endType); - } - - void checkCommanCharacters( - int index, - int length, - int level, - int startType, - int endType, - ) { - for (int i = index; i < length; ++i) { - if (result[i] == ws || - result[i] == otn || - result[i] == b || - result[i] == s) { - final int m = i; - final int len = getLength(m, length, [b, s, ws, otn]); - int lt, tt, rt; - if (m == index) { - lt = startType; - } else { - lt = result[m - 1]; - if (lt == an) { - lt = r; - } else if (lt == en) { - lt = r; - } - } - if (len == length) { - tt = endType; - } else { - tt = result[len]; - if (tt == an) { - tt = r; - } else if (tt == en) { - tt = r; - } - } - if (lt == tt) { - rt = lt; - } else { - rt = ((level & 0x1) == 0) ? l : r; - } - - for (int j = m; j < len; ++j) { - result[j] = rt; - } - i = len; - } - } - } -} +import 'dart:math'; + +/// Utility class for Bidirectional/Rtl text. +class Bidi { + // Constructor. + /// internal constructor + Bidi() { + update(); + } + + // Fields. + /// internal field + late List indexes; + + /// internal field + late List indexLevels; + + /// internal field + Map mirroringShapeCharacters = {}; + + late Map> _ranges; + + /// internal field + bool isVisualOrder = true; + + // Implementations. + /// internal method + Map getLogicalToVisualString(String inputText, bool isRTL) { + indexLevels = List.filled(inputText.length, 0, growable: true); + indexes = List.filled(inputText.length, 0, growable: true); + _ranges = >{}; + final _RTLCharacters rtlCharacters = _RTLCharacters(); + indexLevels = rtlCharacters.getVisualOrder(inputText, isRTL); + setDefaultIndexLevel(); + if (isVisualOrder) { + doBidiOrder(0, indexLevels.length - 1); + if (_ranges.isNotEmpty) { + _ranges.forEach((int key, List value) { + if (_ranges.entries.last.key != key) { + while (value[0] - 1 != -1 && + (rtlCharacters.types[value[0] - 1] == 17 || + rtlCharacters.types[value[0] - 1] == 18 || + rtlCharacters.types[value[0] - 1] == 12)) { + value[0] = value[0] - 1; + } + while (value[1] != _ranges.entries.last.value[1] + 1 && + value[1] < rtlCharacters.types.length && + (rtlCharacters.types[value.last] == 17 || + rtlCharacters.types[value.last] == 18 || + rtlCharacters.types[value.last] == 12)) { + value[1] = value.last + 1; + } + } + }); + if (_ranges.length == 1) { + reArrange(_ranges[0]![0], _ranges[0]![1]); + } else { + int start = 0; + for (int i = 0; i < _ranges.length - 1; i++) { + final List range = _ranges[i]!; + if (range[0] == 0) { + start = range[1]; + } else { + reArrange(start, range[0]); + start = range[1]; + } + } + if (start != indexLevels.length) { + reArrange(start, indexLevels.length); + } + } + } + } else { + doOrder(0, indexLevels.length - 1); + } + final String text = doMirrorShaping(inputText); + final StringBuffer resultBuffer = StringBuffer(); + for (int i = 0; i < indexes.length; i++) { + final int index = indexes[i]; + resultBuffer.write(text[index]); + } + String renderedString = resultBuffer.toString(); + if (isVisualOrder) { + final List tempList = renderedString.split(''); + _ranges.forEach((int key, List value) { + if (_ranges.keys.last != key) { + String tempText = tempList.getRange(value[0], value[1]).join(); + if (tempText.contains(')')) { + tempText = tempText.replaceAll(')', '('); + tempList.replaceRange(value[0], value[1], tempText.split('')); + renderedString = tempList.join(); + } + } + }); + } + return { + 'rtlText': renderedString, + 'orderedIndexes': indexes, + }; + } + + /// internal method + void doBidiOrder(int sIndex, int eIndex) { + int max = indexLevels[sIndex].toUnsigned(8); + int min = max; + int odd = max; + int even = max; + for (int i = sIndex + 1; i <= eIndex; ++i) { + final int data = indexLevels[i]; + if (data > max) { + max = data; + } else if (data < min) { + min = data; + } + odd &= data; + even |= data; + } + if ((even & 1) == 0) { + return; + } + if ((odd & 1) == 1) { + _ranges[_ranges.length] = [sIndex, eIndex + 1]; + return; + } + min |= 1; + while (max >= min) { + int pstart = sIndex; + while (true) { + while (pstart <= eIndex) { + if (indexLevels[pstart] >= max) { + break; + } + pstart += 1; + } + if (pstart > eIndex) { + break; + } + int pend = pstart + 1; + while (pend <= eIndex) { + if (indexLevels[pend] < max) { + break; + } + pend += 1; + } + _ranges[_ranges.length] = [pstart, pend]; + pstart = pend + 1; + } + max -= 1; + } + } + + /// internal method + String doMirrorShaping(String text) { + final StringBuffer result = StringBuffer(); + for (int i = 0; i < text.length; i++) { + if (((indexLevels[i] & 1) == 1) && + mirroringShapeCharacters.containsKey(text[i].codeUnitAt(0))) { + result.write( + String.fromCharCode(mirroringShapeCharacters[text[i].codeUnitAt(0)]!), + ); + } else { + result.write(text[i]); + } + } + return result.toString(); + } + + /// internal method + void setDefaultIndexLevel() { + for (int i = 0; i < indexLevels.length; i++) { + indexes[i] = i; + } + } + + /// internal method + void doOrder(int sIndex, int eIndex) { + int max = indexLevels[sIndex].toUnsigned(8); + int min = max; + int odd = max; + int even = max; + for (int i = sIndex + 1; i <= eIndex; ++i) { + final int data = indexLevels[i]; + if (data > max) { + max = data; + } else if (data < min) { + min = data; + } + odd &= data; + even |= data; + } + if ((even & 1) == 0) { + return; + } + if ((odd & 1) == 1) { + reArrange(sIndex, eIndex + 1); + return; + } + min |= 1; + while (max >= min) { + int pstart = sIndex; + while (true) { + while (pstart <= eIndex) { + if (indexLevels[pstart] >= max) { + break; + } + pstart += 1; + } + if (pstart > eIndex) { + break; + } + int pend = pstart + 1; + while (pend <= eIndex) { + if (indexLevels[pend] < max) { + break; + } + pend += 1; + } + reArrange(pstart, pend); + pstart = pend + 1; + } + max -= 1; + } + } + + /// internal method + void reArrange(int i, int j) { + final int length = (i + j) ~/ 2; + --j; + for (; i < length; ++i, --j) { + final int temp = indexes[i]; + indexes[i] = indexes[j]; + indexes[j] = temp; + } + } + + /// internal method + void update() { + mirroringShapeCharacters[40] = 41; + mirroringShapeCharacters[41] = 40; + mirroringShapeCharacters[60] = 62; + mirroringShapeCharacters[62] = 60; + mirroringShapeCharacters[91] = 93; + mirroringShapeCharacters[93] = 91; + mirroringShapeCharacters[123] = 125; + mirroringShapeCharacters[125] = 123; + mirroringShapeCharacters[171] = 187; + mirroringShapeCharacters[187] = 171; + mirroringShapeCharacters[8249] = 8250; + mirroringShapeCharacters[8250] = 8249; + mirroringShapeCharacters[8261] = 8262; + mirroringShapeCharacters[8262] = 8261; + mirroringShapeCharacters[8317] = 8318; + mirroringShapeCharacters[8318] = 8317; + mirroringShapeCharacters[8333] = 8334; + mirroringShapeCharacters[8334] = 8333; + mirroringShapeCharacters[8712] = 8715; + mirroringShapeCharacters[8713] = 8716; + mirroringShapeCharacters[8714] = 8717; + mirroringShapeCharacters[8715] = 8712; + mirroringShapeCharacters[8716] = 8713; + mirroringShapeCharacters[8717] = 8714; + mirroringShapeCharacters[8725] = 10741; + mirroringShapeCharacters[8764] = 8765; + mirroringShapeCharacters[8765] = 8764; + mirroringShapeCharacters[8771] = 8909; + mirroringShapeCharacters[8786] = 8787; + mirroringShapeCharacters[8787] = 8786; + mirroringShapeCharacters[8788] = 8789; + mirroringShapeCharacters[8789] = 8788; + mirroringShapeCharacters[8804] = 8805; + mirroringShapeCharacters[8805] = 8804; + mirroringShapeCharacters[8806] = 8807; + mirroringShapeCharacters[8807] = 8806; + mirroringShapeCharacters[8808] = 8809; + mirroringShapeCharacters[8809] = 8808; + mirroringShapeCharacters[8810] = 8811; + mirroringShapeCharacters[8811] = 8810; + mirroringShapeCharacters[8814] = 8815; + mirroringShapeCharacters[8815] = 8814; + mirroringShapeCharacters[8816] = 8817; + mirroringShapeCharacters[8817] = 8816; + mirroringShapeCharacters[8818] = 8819; + mirroringShapeCharacters[8819] = 8818; + mirroringShapeCharacters[8820] = 8821; + mirroringShapeCharacters[8821] = 8820; + mirroringShapeCharacters[8822] = 8823; + mirroringShapeCharacters[8823] = 8822; + mirroringShapeCharacters[8824] = 8825; + mirroringShapeCharacters[8825] = 8824; + mirroringShapeCharacters[8826] = 8827; + mirroringShapeCharacters[8827] = 8826; + mirroringShapeCharacters[8828] = 8829; + mirroringShapeCharacters[8829] = 8828; + mirroringShapeCharacters[8830] = 8831; + mirroringShapeCharacters[8831] = 8830; + mirroringShapeCharacters[8832] = 8833; + mirroringShapeCharacters[8833] = 8832; + mirroringShapeCharacters[8834] = 8835; + mirroringShapeCharacters[8835] = 8834; + mirroringShapeCharacters[8836] = 8837; + mirroringShapeCharacters[8837] = 8836; + mirroringShapeCharacters[8838] = 8839; + mirroringShapeCharacters[8839] = 8838; + mirroringShapeCharacters[8840] = 8841; + mirroringShapeCharacters[8841] = 8840; + mirroringShapeCharacters[8842] = 8843; + mirroringShapeCharacters[8843] = 8842; + mirroringShapeCharacters[8847] = 8848; + mirroringShapeCharacters[8848] = 8847; + mirroringShapeCharacters[8849] = 8850; + mirroringShapeCharacters[8850] = 8849; + mirroringShapeCharacters[8856] = 10680; + mirroringShapeCharacters[8866] = 8867; + mirroringShapeCharacters[8867] = 8866; + mirroringShapeCharacters[8870] = 10974; + mirroringShapeCharacters[8872] = 10980; + mirroringShapeCharacters[8873] = 10979; + mirroringShapeCharacters[8875] = 10981; + mirroringShapeCharacters[8880] = 8881; + mirroringShapeCharacters[8881] = 8880; + mirroringShapeCharacters[8882] = 8883; + mirroringShapeCharacters[8883] = 8882; + mirroringShapeCharacters[8884] = 8885; + mirroringShapeCharacters[8885] = 8884; + mirroringShapeCharacters[8886] = 8887; + mirroringShapeCharacters[8887] = 8886; + mirroringShapeCharacters[8905] = 8906; + mirroringShapeCharacters[8906] = 8905; + mirroringShapeCharacters[8907] = 8908; + mirroringShapeCharacters[8908] = 8907; + mirroringShapeCharacters[8909] = 8771; + mirroringShapeCharacters[8912] = 8913; + mirroringShapeCharacters[8913] = 8912; + mirroringShapeCharacters[8918] = 8919; + mirroringShapeCharacters[8919] = 8918; + mirroringShapeCharacters[8920] = 8921; + mirroringShapeCharacters[8921] = 8920; + mirroringShapeCharacters[8922] = 8923; + mirroringShapeCharacters[8923] = 8922; + mirroringShapeCharacters[8924] = 8925; + mirroringShapeCharacters[8925] = 8924; + mirroringShapeCharacters[8926] = 8927; + mirroringShapeCharacters[8927] = 8926; + mirroringShapeCharacters[8928] = 8929; + mirroringShapeCharacters[8929] = 8928; + mirroringShapeCharacters[8930] = 8931; + mirroringShapeCharacters[8931] = 8930; + mirroringShapeCharacters[8932] = 8933; + mirroringShapeCharacters[8933] = 8932; + mirroringShapeCharacters[8934] = 8935; + mirroringShapeCharacters[8935] = 8934; + mirroringShapeCharacters[8936] = 8937; + mirroringShapeCharacters[8937] = 8936; + mirroringShapeCharacters[8938] = 8939; + mirroringShapeCharacters[8939] = 8938; + mirroringShapeCharacters[8940] = 8941; + mirroringShapeCharacters[8941] = 8940; + mirroringShapeCharacters[8944] = 8945; + mirroringShapeCharacters[8945] = 8944; + mirroringShapeCharacters[8946] = 8954; + mirroringShapeCharacters[8947] = 8955; + mirroringShapeCharacters[8948] = 8956; + mirroringShapeCharacters[8950] = 8957; + mirroringShapeCharacters[8951] = 8958; + mirroringShapeCharacters[8954] = 8946; + mirroringShapeCharacters[8955] = 8947; + mirroringShapeCharacters[8956] = 8948; + mirroringShapeCharacters[8957] = 8950; + mirroringShapeCharacters[8958] = 8951; + mirroringShapeCharacters[8968] = 8969; + mirroringShapeCharacters[8969] = 8968; + mirroringShapeCharacters[8970] = 8971; + mirroringShapeCharacters[8971] = 8970; + mirroringShapeCharacters[9001] = 9002; + mirroringShapeCharacters[9002] = 9001; + mirroringShapeCharacters[10088] = 10089; + mirroringShapeCharacters[10089] = 10088; + mirroringShapeCharacters[10090] = 10091; + mirroringShapeCharacters[10091] = 10090; + mirroringShapeCharacters[10092] = 10093; + mirroringShapeCharacters[10093] = 10092; + mirroringShapeCharacters[10094] = 10095; + mirroringShapeCharacters[10095] = 10094; + mirroringShapeCharacters[10096] = 10097; + mirroringShapeCharacters[10097] = 10096; + mirroringShapeCharacters[10098] = 10099; + mirroringShapeCharacters[10099] = 10098; + mirroringShapeCharacters[10100] = 10101; + mirroringShapeCharacters[10101] = 10100; + mirroringShapeCharacters[10197] = 10198; + mirroringShapeCharacters[10198] = 10197; + mirroringShapeCharacters[10205] = 10206; + mirroringShapeCharacters[10206] = 10205; + mirroringShapeCharacters[10210] = 10211; + mirroringShapeCharacters[10211] = 10210; + mirroringShapeCharacters[10212] = 10213; + mirroringShapeCharacters[10213] = 10212; + mirroringShapeCharacters[10214] = 10215; + mirroringShapeCharacters[10215] = 10214; + mirroringShapeCharacters[10216] = 10217; + mirroringShapeCharacters[10217] = 10216; + mirroringShapeCharacters[10218] = 10219; + mirroringShapeCharacters[10219] = 10218; + mirroringShapeCharacters[10627] = 10628; + mirroringShapeCharacters[10628] = 10627; + mirroringShapeCharacters[10629] = 10630; + mirroringShapeCharacters[10630] = 10629; + mirroringShapeCharacters[10631] = 10632; + mirroringShapeCharacters[10632] = 10631; + mirroringShapeCharacters[10633] = 10634; + mirroringShapeCharacters[10634] = 10633; + mirroringShapeCharacters[10635] = 10636; + mirroringShapeCharacters[10636] = 10635; + mirroringShapeCharacters[10637] = 10640; + mirroringShapeCharacters[10638] = 10639; + mirroringShapeCharacters[10639] = 10638; + mirroringShapeCharacters[10640] = 10637; + mirroringShapeCharacters[10641] = 10642; + mirroringShapeCharacters[10642] = 10641; + mirroringShapeCharacters[10643] = 10644; + mirroringShapeCharacters[10644] = 10643; + mirroringShapeCharacters[10645] = 10646; + mirroringShapeCharacters[10646] = 10645; + mirroringShapeCharacters[10647] = 10648; + mirroringShapeCharacters[10648] = 10647; + mirroringShapeCharacters[10680] = 8856; + mirroringShapeCharacters[10688] = 10689; + mirroringShapeCharacters[10689] = 10688; + mirroringShapeCharacters[10692] = 10693; + mirroringShapeCharacters[10693] = 10692; + mirroringShapeCharacters[10703] = 10704; + mirroringShapeCharacters[10704] = 10703; + mirroringShapeCharacters[10705] = 10706; + mirroringShapeCharacters[10706] = 10705; + mirroringShapeCharacters[10708] = 10709; + mirroringShapeCharacters[10709] = 10708; + mirroringShapeCharacters[10712] = 10713; + mirroringShapeCharacters[10713] = 10712; + mirroringShapeCharacters[10714] = 10715; + mirroringShapeCharacters[10715] = 10714; + mirroringShapeCharacters[10741] = 8725; + mirroringShapeCharacters[10744] = 10745; + mirroringShapeCharacters[10745] = 10744; + mirroringShapeCharacters[10748] = 10749; + mirroringShapeCharacters[10749] = 10748; + mirroringShapeCharacters[10795] = 10796; + mirroringShapeCharacters[10796] = 10795; + mirroringShapeCharacters[10797] = 10796; + mirroringShapeCharacters[10798] = 10797; + mirroringShapeCharacters[10804] = 10805; + mirroringShapeCharacters[10805] = 10804; + mirroringShapeCharacters[10812] = 10813; + mirroringShapeCharacters[10813] = 10812; + mirroringShapeCharacters[10852] = 10853; + mirroringShapeCharacters[10853] = 10852; + mirroringShapeCharacters[10873] = 10874; + mirroringShapeCharacters[10874] = 10873; + mirroringShapeCharacters[10877] = 10878; + mirroringShapeCharacters[10878] = 10877; + mirroringShapeCharacters[10879] = 10880; + mirroringShapeCharacters[10880] = 10879; + mirroringShapeCharacters[10881] = 10882; + mirroringShapeCharacters[10882] = 10881; + mirroringShapeCharacters[10883] = 10884; + mirroringShapeCharacters[10884] = 10883; + mirroringShapeCharacters[10891] = 10892; + mirroringShapeCharacters[10892] = 10891; + mirroringShapeCharacters[10897] = 10898; + mirroringShapeCharacters[10898] = 10897; + mirroringShapeCharacters[10899] = 10900; + mirroringShapeCharacters[10900] = 10899; + mirroringShapeCharacters[10901] = 10902; + mirroringShapeCharacters[10902] = 10901; + mirroringShapeCharacters[10903] = 10904; + mirroringShapeCharacters[10904] = 10903; + mirroringShapeCharacters[10905] = 10906; + mirroringShapeCharacters[10906] = 10905; + mirroringShapeCharacters[10907] = 10908; + mirroringShapeCharacters[10908] = 10907; + mirroringShapeCharacters[10913] = 10914; + mirroringShapeCharacters[10914] = 10913; + mirroringShapeCharacters[10918] = 10919; + mirroringShapeCharacters[10919] = 10918; + mirroringShapeCharacters[10920] = 10921; + mirroringShapeCharacters[10921] = 10920; + mirroringShapeCharacters[10922] = 10923; + mirroringShapeCharacters[10923] = 10922; + mirroringShapeCharacters[10924] = 10925; + mirroringShapeCharacters[10925] = 10924; + mirroringShapeCharacters[10927] = 10928; + mirroringShapeCharacters[10928] = 10927; + mirroringShapeCharacters[10931] = 10932; + mirroringShapeCharacters[10932] = 10931; + mirroringShapeCharacters[10939] = 10940; + mirroringShapeCharacters[10940] = 10939; + mirroringShapeCharacters[10941] = 10942; + mirroringShapeCharacters[10942] = 10941; + mirroringShapeCharacters[10943] = 10944; + mirroringShapeCharacters[10944] = 10943; + mirroringShapeCharacters[10945] = 10946; + mirroringShapeCharacters[10946] = 10945; + mirroringShapeCharacters[10947] = 10948; + mirroringShapeCharacters[10948] = 10947; + mirroringShapeCharacters[10949] = 10950; + mirroringShapeCharacters[10950] = 10949; + mirroringShapeCharacters[10957] = 10958; + mirroringShapeCharacters[10958] = 10957; + mirroringShapeCharacters[10959] = 10960; + mirroringShapeCharacters[10960] = 10959; + mirroringShapeCharacters[10961] = 10962; + mirroringShapeCharacters[10962] = 10961; + mirroringShapeCharacters[10963] = 10964; + mirroringShapeCharacters[10964] = 10963; + mirroringShapeCharacters[10965] = 10966; + mirroringShapeCharacters[10966] = 10965; + mirroringShapeCharacters[10974] = 8870; + mirroringShapeCharacters[10979] = 8873; + mirroringShapeCharacters[10980] = 8872; + mirroringShapeCharacters[10981] = 8875; + mirroringShapeCharacters[10988] = 10989; + mirroringShapeCharacters[10989] = 10988; + mirroringShapeCharacters[10999] = 11000; + mirroringShapeCharacters[11000] = 10999; + mirroringShapeCharacters[11001] = 11002; + mirroringShapeCharacters[11002] = 11001; + mirroringShapeCharacters[12296] = 12297; + mirroringShapeCharacters[12297] = 12296; + mirroringShapeCharacters[12298] = 12299; + mirroringShapeCharacters[12299] = 12298; + mirroringShapeCharacters[12300] = 12301; + mirroringShapeCharacters[12301] = 12300; + mirroringShapeCharacters[12302] = 12303; + mirroringShapeCharacters[12303] = 12302; + mirroringShapeCharacters[12304] = 12305; + mirroringShapeCharacters[12305] = 12304; + mirroringShapeCharacters[12308] = 12309; + mirroringShapeCharacters[12309] = 12308; + mirroringShapeCharacters[12310] = 12311; + mirroringShapeCharacters[12311] = 12310; + mirroringShapeCharacters[12312] = 12313; + mirroringShapeCharacters[12313] = 12312; + mirroringShapeCharacters[12314] = 12315; + mirroringShapeCharacters[12315] = 12314; + mirroringShapeCharacters[65288] = 65289; + mirroringShapeCharacters[65289] = 65288; + mirroringShapeCharacters[65308] = 65310; + mirroringShapeCharacters[65310] = 65308; + mirroringShapeCharacters[65339] = 65341; + mirroringShapeCharacters[65341] = 65339; + mirroringShapeCharacters[65371] = 65373; + mirroringShapeCharacters[65373] = 65371; + mirroringShapeCharacters[65375] = 65376; + mirroringShapeCharacters[65376] = 65375; + mirroringShapeCharacters[65378] = 65379; + mirroringShapeCharacters[65379] = 65378; + } +} + +class _RTLCharacters { + // Constructor. + _RTLCharacters() { + for (int i = 0; i < charTypes.length; ++i) { + int start = charTypes[i]; + final int end = charTypes[++i]; + final int b = charTypes[++i].toSigned(8); + while (start <= end) { + rtlCharacterTypes[start++] = b; + } + } + } + + // Constants and Fields + // Specifies the character types. + late List types; //sbyte + // Specifies the text order (RTL or LTR). + int textOrder = -1; //sbyte + // Specifies the text length. + int? length; + // Specifies the resultant types. + late List result; //sbyte + // Specifies the resultant levels. + late List levels; //sbyte + // Specifies the RTL character types. + List rtlCharacterTypes = List.filled( + 65536, + 0, + growable: true, + ); //sbyte + + // Left-to-Right (Non-European or non-Arabic digits). + static const int l = 0; + // Left-to-Right Embedding + static const int lre = 1; + // Left-to-Right Override + static const int lro = 2; + // Right-to-Left (Hebrew alphabet, and related punctuation). + static const int r = 3; + // Right-to-Left Arabic + static const int al = 4; + // Right-to-Left Embedding. + static const int rle = 5; + // Right-to-Left Override + static const int rlo = 6; + // Pop Directional Format + static const int pdf = 7; + // European Number (European digits, Eastern Arabic-Indic digits). + static const int en = 8; + // European Number Separator (Plus sign, Minus sign). + static const int es = 9; + // European Number Terminator (Degree sign, currency symbols). + static const int et = 10; + // Arabic Number (Arabic-Indic digits, + // Arabic decimal and thousands separators). + static const int an = 11; + // Common Number Separator (Colon, Comma, Full Stop, No-Break Space. + static const int cs = 12; + // Nonspacing Mark (Characters with the General_Category values). + static const int nsm = 13; + // Boundary Neutral (Default ignorables, non-characters, + // and control characters, other than those explicitly given other types.) + static const int bn = 14; + // Paragraph Separator (Paragraph separator, appropriate Newline Functions, + // higher-level protocol paragraph determination). + static const int b = 15; + // Segment Separator (tab). + static const int s = 16; + // Whitespace (Space, Figure space, Line separator, + // Form feed, General Punctuation spaces). + static const int ws = 17; + // Other Neutrals (All other characters, + // including object replacement character). + static const int otn = 18; + + List charTypes = [ + l, + en, + bn, + es, + es, + s, + et, + et, + b, + an, + an, + s, + cs, + cs, + ws, + nsm, + nsm, + b, + bn, + 27, + bn, + 28, + 30, + b, + 31, + 31, + s, + 32, + 32, + ws, + 33, + 34, + otn, + 35, + 37, + et, + 38, + 42, + otn, + 43, + 43, + es, + 44, + 44, + cs, + 45, + 45, + es, + 46, + 46, + cs, + 47, + 47, + cs, + 48, + 57, + en, + 58, + 58, + cs, + 59, + 64, + otn, + 65, + 90, + l, + 91, + 96, + otn, + 97, + 122, + l, + 123, + 126, + otn, + 127, + 132, + bn, + 133, + 133, + b, + 134, + 159, + bn, + 160, + 160, + cs, + 161, + 161, + otn, + 162, + 165, + et, + 166, + 169, + otn, + 170, + 170, + l, + 171, + 175, + otn, + 176, + 177, + et, + 178, + 179, + en, + 180, + 180, + otn, + 181, + 181, + l, + 182, + 184, + otn, + 185, + 185, + en, + 186, + 186, + l, + 187, + 191, + otn, + 192, + 214, + l, + 215, + 215, + otn, + 216, + 246, + l, + 247, + 247, + otn, + 248, + 696, + l, + 697, + 698, + otn, + 699, + 705, + l, + 706, + 719, + otn, + 720, + 721, + l, + 722, + 735, + otn, + 736, + 740, + l, + 741, + 749, + otn, + 750, + 750, + l, + 751, + 767, + otn, + 768, + 855, + nsm, + 856, + 860, + l, + 861, + 879, + nsm, + 880, + 883, + l, + 884, + 885, + otn, + 886, + 893, + l, + 894, + 894, + otn, + 895, + 899, + l, + 900, + 901, + otn, + 902, + 902, + l, + 903, + 903, + otn, + 904, + 1013, + l, + 1014, + 1014, + otn, + 1015, + 1154, + l, + 1155, + 1158, + nsm, + 1159, + 1159, + l, + 1160, + 1161, + nsm, + 1162, + 1417, + l, + 1418, + 1418, + otn, + 1419, + 1424, + l, + 1425, + 1441, + nsm, + 1442, + 1442, + l, + 1443, + 1465, + nsm, + 1466, + 1466, + l, + 1467, + 1469, + nsm, + 1470, + 1470, + r, + 1471, + 1471, + nsm, + 1472, + 1472, + r, + 1473, + 1474, + nsm, + 1475, + 1475, + r, + 1476, + 1476, + nsm, + 1477, + 1487, + l, + 1488, + 1514, + r, + 1515, + 1519, + l, + 1520, + 1524, + r, + 1525, + 1535, + l, + 1536, + 1539, + al, + 1540, + 1547, + l, + 1548, + 1548, + cs, + 1549, + 1549, + al, + 1550, + 1551, + otn, + 1552, + 1557, + nsm, + 1558, + 1562, + l, + 1563, + 1563, + al, + 1564, + 1566, + l, + 1567, + 1567, + al, + 1568, + 1568, + l, + 1569, + 1594, + al, + 1595, + 1599, + l, + 1600, + 1610, + al, + 1611, + 1624, + nsm, + 1625, + 1631, + l, + 1632, + 1641, + an, + 1642, + 1642, + et, + 1643, + 1644, + an, + 1645, + 1647, + al, + 1648, + 1648, + nsm, + 1649, + 1749, + al, + 1750, + 1756, + nsm, + 1757, + 1757, + al, + 1758, + 1764, + nsm, + 1765, + 1766, + al, + 1767, + 1768, + nsm, + 1769, + 1769, + otn, + 1770, + 1773, + nsm, + 1774, + 1775, + al, + 1776, + 1785, + en, + 1786, + 1805, + al, + 1806, + 1806, + l, + 1807, + 1807, + bn, + 1808, + 1808, + al, + 1809, + 1809, + nsm, + 1810, + 1839, + al, + 1840, + 1866, + nsm, + 1867, + 1868, + l, + 1869, + 1871, + al, + 1872, + 1919, + l, + 1920, + 1957, + al, + 1958, + 1968, + nsm, + 1969, + 1969, + al, + 1970, + 2304, + l, + 2305, + 2306, + nsm, + 2307, + 2363, + l, + 2364, + 2364, + nsm, + 2365, + 2368, + l, + 2369, + 2376, + nsm, + 2377, + 2380, + l, + 2381, + 2381, + nsm, + 2382, + 2384, + l, + 2385, + 2388, + nsm, + 2389, + 2401, + l, + 2402, + 2403, + nsm, + 2404, + 2432, + l, + 2433, + 2433, + nsm, + 2434, + 2491, + l, + 2492, + 2492, + nsm, + 2493, + 2496, + l, + 2497, + 2500, + nsm, + 2501, + 2508, + l, + 2509, + 2509, + nsm, + 2510, + 2529, + l, + 2530, + 2531, + nsm, + 2532, + 2545, + l, + 2546, + 2547, + et, + 2548, + 2560, + l, + 2561, + 2562, + nsm, + 2563, + 2619, + l, + 2620, + 2620, + nsm, + 2621, + 2624, + l, + 2625, + 2626, + nsm, + 2627, + 2630, + l, + 2631, + 2632, + nsm, + 2633, + 2634, + l, + 2635, + 2637, + nsm, + 2638, + 2671, + l, + 2672, + 2673, + nsm, + 2674, + 2688, + l, + 2689, + 2690, + nsm, + 2691, + 2747, + l, + 2748, + 2748, + nsm, + 2749, + 2752, + l, + 2753, + 2757, + nsm, + 2758, + 2758, + l, + 2759, + 2760, + nsm, + 2761, + 2764, + l, + 2765, + 2765, + nsm, + 2766, + 2785, + l, + 2786, + 2787, + nsm, + 2788, + 2800, + l, + 2801, + 2801, + et, + 2802, + 2816, + l, + 2817, + 2817, + nsm, + 2818, + 2875, + l, + 2876, + 2876, + nsm, + 2877, + 2878, + l, + 2879, + 2879, + nsm, + 2880, + 2880, + l, + 2881, + 2883, + nsm, + 2884, + 2892, + l, + 2893, + 2893, + nsm, + 2894, + 2901, + l, + 2902, + 2902, + nsm, + 2903, + 2945, + l, + 2946, + 2946, + nsm, + 2947, + 3007, + l, + 3008, + 3008, + nsm, + 3009, + 3020, + l, + 3021, + 3021, + nsm, + 3022, + 3058, + l, + 3059, + 3064, + otn, + 3065, + 3065, + et, + 3066, + 3066, + otn, + 3067, + 3133, + l, + 3134, + 3136, + nsm, + 3137, + 3141, + l, + 3142, + 3144, + nsm, + 3145, + 3145, + l, + 3146, + 3149, + nsm, + 3150, + 3156, + l, + 3157, + 3158, + nsm, + 3159, + 3259, + l, + 3260, + 3260, + nsm, + 3261, + 3275, + l, + 3276, + 3277, + nsm, + 3278, + 3392, + l, + 3393, + 3395, + nsm, + 3396, + 3404, + l, + 3405, + 3405, + nsm, + 3406, + 3529, + l, + 3530, + 3530, + nsm, + 3531, + 3537, + l, + 3538, + 3540, + nsm, + 3541, + 3541, + l, + 3542, + 3542, + nsm, + 3543, + 3632, + l, + 3633, + 3633, + nsm, + 3634, + 3635, + l, + 3636, + 3642, + nsm, + 3643, + 3646, + l, + 3647, + 3647, + et, + 3648, + 3654, + l, + 3655, + 3662, + nsm, + 3663, + 3760, + l, + 3761, + 3761, + nsm, + 3762, + 3763, + l, + 3764, + 3769, + nsm, + 3770, + 3770, + l, + 3771, + 3772, + nsm, + 3773, + 3783, + l, + 3784, + 3789, + nsm, + 3790, + 3863, + l, + 3864, + 3865, + nsm, + 3866, + 3892, + l, + 3893, + 3893, + nsm, + 3894, + 3894, + l, + 3895, + 3895, + nsm, + 3896, + 3896, + l, + 3897, + 3897, + nsm, + 3898, + 3901, + otn, + 3902, + 3952, + l, + 3953, + 3966, + nsm, + 3967, + 3967, + l, + 3968, + 3972, + nsm, + 3973, + 3973, + l, + 3974, + 3975, + nsm, + 3976, + 3983, + l, + 3984, + 3991, + nsm, + 3992, + 3992, + l, + 3993, + 4028, + nsm, + 4029, + 4037, + l, + 4038, + 4038, + nsm, + 4039, + 4140, + l, + 4141, + 4144, + nsm, + 4145, + 4145, + l, + 4146, + 4146, + nsm, + 4147, + 4149, + l, + 4150, + 4151, + nsm, + 4152, + 4152, + l, + 4153, + 4153, + nsm, + 4154, + 4183, + l, + 4184, + 4185, + nsm, + 4186, + 5759, + l, + 5760, + 5760, + ws, + 5761, + 5786, + l, + 5787, + 5788, + otn, + 5789, + 5905, + l, + 5906, + 5908, + nsm, + 5909, + 5937, + l, + 5938, + 5940, + nsm, + 5941, + 5969, + l, + 5970, + 5971, + nsm, + 5972, + 6001, + l, + 6002, + 6003, + nsm, + 6004, + 6070, + l, + 6071, + 6077, + nsm, + 6078, + 6085, + l, + 6086, + 6086, + nsm, + 6087, + 6088, + l, + 6089, + 6099, + nsm, + 6100, + 6106, + l, + 6107, + 6107, + et, + 6108, + 6108, + l, + 6109, + 6109, + nsm, + 6110, + 6127, + l, + 6128, + 6137, + otn, + 6138, + 6143, + l, + 6144, + 6154, + otn, + 6155, + 6157, + nsm, + 6158, + 6158, + ws, + 6159, + 6312, + l, + 6313, + 6313, + nsm, + 6314, + 6431, + l, + 6432, + 6434, + nsm, + 6435, + 6438, + l, + 6439, + 6443, + nsm, + 6444, + 6449, + l, + 6450, + 6450, + nsm, + 6451, + 6456, + l, + 6457, + 6459, + nsm, + 6460, + 6463, + l, + 6464, + 6464, + otn, + 6465, + 6467, + l, + 6468, + 6469, + otn, + 6470, + 6623, + l, + 6624, + 6655, + otn, + 6656, + 8124, + l, + 8125, + 8125, + otn, + 8126, + 8126, + l, + 8127, + 8129, + otn, + 8130, + 8140, + l, + 8141, + 8143, + otn, + 8144, + 8156, + l, + 8157, + 8159, + otn, + 8160, + 8172, + l, + 8173, + 8175, + otn, + 8176, + 8188, + l, + 8189, + 8190, + otn, + 8191, + 8191, + l, + 8192, + 8202, + ws, + 8203, + 8205, + bn, + 8206, + 8206, + l, + 8207, + 8207, + r, + 8208, + 8231, + otn, + 8232, + 8232, + ws, + 8233, + 8233, + b, + 8234, + 8234, + lre, + 8235, + 8235, + rle, + 8236, + 8236, + pdf, + 8237, + 8237, + lro, + 8238, + 8238, + rlo, + 8239, + 8239, + ws, + 8240, + 8244, + et, + 8245, + 8276, + otn, + 8277, + 8278, + l, + 8279, + 8279, + otn, + 8280, + 8286, + l, + 8287, + 8287, + ws, + 8288, + 8291, + bn, + 8292, + 8297, + l, + 8298, + 8303, + bn, + 8304, + 8304, + en, + 8305, + 8307, + l, + 8308, + 8313, + en, + 8314, + 8315, + et, + 8316, + 8318, + otn, + 8319, + 8319, + l, + 8320, + 8329, + en, + 8330, + 8331, + et, + 8332, + 8334, + otn, + 8335, + 8351, + l, + 8352, + 8369, + et, + 8370, + 8399, + l, + 8400, + 8426, + nsm, + 8427, + 8447, + l, + 8448, + 8449, + otn, + 8450, + 8450, + l, + 8451, + 8454, + otn, + 8455, + 8455, + l, + 8456, + 8457, + otn, + 8458, + 8467, + l, + 8468, + 8468, + otn, + 8469, + 8469, + l, + 8470, + 8472, + otn, + 8473, + 8477, + l, + 8478, + 8483, + otn, + 8484, + 8484, + l, + 8485, + 8485, + otn, + 8486, + 8486, + l, + 8487, + 8487, + otn, + 8488, + 8488, + l, + 8489, + 8489, + otn, + 8490, + 8493, + l, + 8494, + 8494, + et, + 8495, + 8497, + l, + 8498, + 8498, + otn, + 8499, + 8505, + l, + 8506, + 8507, + otn, + 8508, + 8511, + l, + 8512, + 8516, + otn, + 8517, + 8521, + l, + 8522, + 8523, + otn, + 8524, + 8530, + l, + 8531, + 8543, + otn, + 8544, + 8591, + l, + 8592, + 8721, + otn, + 8722, + 8723, + et, + 8724, + 9013, + otn, + 9014, + 9082, + l, + 9083, + 9108, + otn, + 9109, + 9109, + l, + 9110, + 9168, + otn, + 9169, + 9215, + l, + 9216, + 9254, + otn, + 9255, + 9279, + l, + 9280, + 9290, + otn, + 9291, + 9311, + l, + 9312, + 9371, + en, + 9372, + 9449, + l, + 9450, + 9450, + en, + 9451, + 9751, + otn, + 9752, + 9752, + l, + 9753, + 9853, + otn, + 9854, + 9855, + l, + 9856, + 9873, + otn, + 9874, + 9887, + l, + 9888, + 9889, + otn, + 9890, + 9984, + l, + 9985, + 9988, + otn, + 9989, + 9989, + l, + 9990, + 9993, + otn, + 9994, + 9995, + l, + 9996, + 10023, + otn, + 10024, + 10024, + l, + 10025, + 10059, + otn, + 10060, + 10060, + l, + 10061, + 10061, + otn, + 10062, + 10062, + l, + 10063, + 10066, + otn, + 10067, + 10069, + l, + 10070, + 10070, + otn, + 10071, + 10071, + l, + 10072, + 10078, + otn, + 10079, + 10080, + l, + 10081, + 10132, + otn, + 10133, + 10135, + l, + 10136, + 10159, + otn, + 10160, + 10160, + l, + 10161, + 10174, + otn, + 10175, + 10191, + l, + 10192, + 10219, + otn, + 10220, + 10223, + l, + 10224, + 11021, + otn, + 11022, + 11903, + l, + 11904, + 11929, + otn, + 11930, + 11930, + l, + 11931, + 12019, + otn, + 12020, + 12031, + l, + 12032, + 12245, + otn, + 12246, + 12271, + l, + 12272, + 12283, + otn, + 12284, + 12287, + l, + 12288, + 12288, + ws, + 12289, + 12292, + otn, + 12293, + 12295, + l, + 12296, + 12320, + otn, + 12321, + 12329, + l, + 12330, + 12335, + nsm, + 12336, + 12336, + otn, + 12337, + 12341, + l, + 12342, + 12343, + otn, + 12344, + 12348, + l, + 12349, + 12351, + otn, + 12352, + 12440, + l, + 12441, + 12442, + nsm, + 12443, + 12444, + otn, + 12445, + 12447, + l, + 12448, + 12448, + otn, + 12449, + 12538, + l, + 12539, + 12539, + otn, + 12540, + 12828, + l, + 12829, + 12830, + otn, + 12831, + 12879, + l, + 12880, + 12895, + otn, + 12896, + 12923, + l, + 12924, + 12925, + otn, + 12926, + 12976, + l, + 12977, + 12991, + otn, + 12992, + 13003, + l, + 13004, + 13007, + otn, + 13008, + 13174, + l, + 13175, + 13178, + otn, + 13179, + 13277, + l, + 13278, + 13279, + otn, + 13280, + 13310, + l, + 13311, + 13311, + otn, + 13312, + 19903, + l, + 19904, + 19967, + otn, + 19968, + 42127, + l, + 42128, + 42182, + otn, + 42183, + 64284, + l, + 64285, + 64285, + r, + 64286, + 64286, + nsm, + 64287, + 64296, + r, + 64297, + 64297, + et, + 64298, + 64310, + r, + 64311, + 64311, + l, + 64312, + 64316, + r, + 64317, + 64317, + l, + 64318, + 64318, + r, + 64319, + 64319, + l, + 64320, + 64321, + r, + 64322, + 64322, + l, + 64323, + 64324, + r, + 64325, + 64325, + l, + 64326, + 64335, + r, + 64336, + 64433, + al, + 64434, + 64466, + l, + 64467, + 64829, + al, + 64830, + 64831, + otn, + 64832, + 64847, + l, + 64848, + 64911, + al, + 64912, + 64913, + l, + 64914, + 64967, + al, + 64968, + 65007, + l, + 65008, + 65020, + al, + 65021, + 65021, + otn, + 65022, + 65023, + l, + 65024, + 65039, + nsm, + 65040, + 65055, + l, + 65056, + 65059, + nsm, + 65060, + 65071, + l, + 65072, + 65103, + otn, + 65104, + 65104, + cs, + 65105, + 65105, + otn, + 65106, + 65106, + cs, + 65107, + 65107, + l, + 65108, + 65108, + otn, + 65109, + 65109, + cs, + 65110, + 65118, + otn, + 65119, + 65119, + et, + 65120, + 65121, + otn, + 65122, + 65123, + et, + 65124, + 65126, + otn, + 65127, + 65127, + l, + 65128, + 65128, + otn, + 65129, + 65130, + et, + 65131, + 65131, + otn, + 65132, + 65135, + l, + 65136, + 65140, + al, + 65141, + 65141, + l, + 65142, + 65276, + al, + 65277, + 65278, + l, + 65279, + 65279, + bn, + 65280, + 65280, + l, + 65281, + 65282, + otn, + 65283, + 65285, + et, + 65286, + 65290, + otn, + 65291, + 65291, + et, + 65292, + 65292, + cs, + 65293, + 65293, + et, + 65294, + 65294, + cs, + 65295, + 65295, + es, + 65296, + 65305, + en, + 65306, + 65306, + cs, + 65307, + 65312, + otn, + 65313, + 65338, + l, + 65339, + 65344, + otn, + 65345, + 65370, + l, + 65371, + 65381, + otn, + 65382, + 65503, + l, + 65504, + 65505, + et, + 65506, + 65508, + otn, + 65509, + 65510, + et, + 65511, + 65511, + l, + 65512, + 65518, + otn, + 65519, + 65528, + l, + 65529, + 65531, + bn, + 65532, + 65533, + otn, + 65534, + 65535, + l, + ]; + + // Implementations. + List getVisualOrder(String inputText, bool isRTL) { + types = getCharacterCode(inputText); + textOrder = isRTL ? lre : l; + doVisualOrder(); + final List result = List.filled( + this.result.length, + 0, + growable: true, + ); + for (int i = 0; i < levels.length; i++) { + result[i] = levels[i].toUnsigned(8); + } + return result; + } + + List getCharacterCode(String text) { + final List characterCodes = List.filled( + text.length, + 0, + growable: true, + ); + for (int i = 0; i < text.length; i++) { + characterCodes[i] = rtlCharacterTypes[text[i].codeUnitAt(0)]; + } + return characterCodes; + } + + void doVisualOrder() { + length = types.length; + //ignore:prefer_spread_collections + result = []..addAll(types); + levels = List.filled(length!, 0, growable: true); + setLevels(); + length = getEmbeddedCharactersLength(); + int preview = textOrder; + int i = 0; + while (i < length!) { + final int level = levels[i]; + final int preType = + (([preview, level].reduce(max) & 0x1) == 0) ? l : r; + int lengths = i + 1; + while (lengths < length! && levels[lengths] == level) { + ++lengths; + } + final int success = lengths < length! ? levels[lengths] : textOrder; + final int type = (([success, level].reduce(max) & 0x1) == 0) ? l : r; + checkNSM(i, length!, level, preType, type); + updateLevels(i, level, length); + preview = level; + i = length!; + } + checkEmbeddedCharacters(length); + } + + void updateLevels(int index, int level, int? length) { + if ((level & 1) == 0) { + for (int i = index; i < length!; ++i) { + if (result[i] == r) { + levels[i] += 1; + } else if (result[i] != l) { + levels[i] += 2; + } + } + } else { + for (int i = index; i < length!; ++i) { + if (result[i] != r) { + levels[i] += 1; + } + } + } + } + + void setLevels() { + setDefaultLevels(); + for (int n = 0; n < length!; ++n) { + int level = levels[n].toUnsigned(8); + if ((level & 0x80) != 0) { + level &= 0x7f; + result[n] = ((level & 0x1) == 0) ? l : r; + } + levels[n] = level; + } + } + + void setDefaultLevels() { + for (int i = 0; i < length!; i++) { + levels[i] = textOrder; + } + } + + int getEmbeddedCharactersLength() { + int index = 0; + for (int i = 0; i < length!; ++i) { + if (!(types[i] == lre || + types[i] == rle || + types[i] == lro || + types[i] == rlo || + types[i] == pdf || + types[i] == bn)) { + result[index] = result[i]; + levels[index] = levels[i]; + index++; + } + } + return index; + } + + void checkEmbeddedCharacters(int? length) { + for (int i = types.length - 1; i >= 0; --i) { + if (types[i] == lre || + types[i] == rle || + types[i] == lro || + types[i] == rlo || + types[i] == pdf || + types[i] == bn) { + result[i] = types[i]; + levels[i] = -1; + } else { + length = length! - 1; + result[i] = result[length]; + levels[i] = levels[length]; + } + } + for (int i = 0; i < types.length; i++) { + if (levels[i] == -1) { + if (i == 0) { + levels[i] = textOrder; + } else { + levels[i] = levels[i - 1]; + } + } + } + } + + void checkNSM(int index, int length, int level, int startType, int endType) { + int charType = startType.toSigned(8); + for (int i = index; i < length; ++i) { + if (result[i] == nsm) { + result[i] = charType; + } else { + charType = result[i]; + } + } + checkEuropeanDigits(index, length, level, startType, endType); + } + + void checkEuropeanDigits( + int index, + int length, + int level, + int startType, + int endType, + ) { + for (int i = index; i < length; ++i) { + if (result[i] == en) { + for (int j = i - 1; j >= index; --j) { + if (result[j] == l || result[j] == r || result[j] == al) { + if (result[j] == al) { + result[i] = an; + } + break; + } + } + } + } + checkArabicCharacters(index, length, level, startType, endType); + } + + void checkArabicCharacters( + int index, + int length, + int level, + int startType, + int endType, + ) { + for (int i = index; i < length; ++i) { + if (result[i] == al) { + result[i] = r; + } + } + checkEuropeanNumberSeparator(index, length, level, startType, endType); + } + + void checkEuropeanNumberSeparator( + int index, + int length, + int level, + int startType, + int endType, + ) { + for (int i = index + 1; i < length - 1; ++i) { + if (result[i] == es || result[i] == cs) { + final int preview = result[i - 1]; + final int success = result[i + 1]; + if (preview == en && success == en) { + result[i] = en; + } else if (result[i] == cs && preview == an && success == an) { + result[i] = an; + } + } + } + checkEuropeanNumberTerminator(index, length, level, startType, endType); + } + + void checkEuropeanNumberTerminator( + int index, + int length, + int level, + int startType, + int endType, + ) { + for (int i = index; i < length; ++i) { + if (result[i] == et) { + final int s = i; + final int l = getLength(s, length, [et]); + int data = s == index ? startType : result[s - 1]; + if (data != en) { + data = (l == length) ? endType : result[l]; + } + if (data == en) { + for (int j = s; j < l; ++j) { + result[j] = en; + } + } + i = l; + } + } + checkOtherNeutrals(index, length, level, startType, endType); + } + + int getLength(int index, int length, List validSet) { + --index; + while (++index < length) { + final int t = result[index]; + for (int i = 0; i < validSet.length; ++i) { + if (t == validSet[i]) { + index = getLength(++index, length, validSet); + } + } + return index; + } + return length; + } + + void checkOtherNeutrals( + int index, + int length, + int level, + int startType, + int endType, + ) { + for (int i = index; i < length; ++i) { + if (result[i] == es || result[i] == et || result[i] == cs) { + result[i] = otn; + } + } + checkOtherCharacters(index, length, level, startType, endType); + } + + void checkOtherCharacters( + int index, + int length, + int level, + int startType, + int endType, + ) { + for (int i = index; i < length; ++i) { + if (result[i] == en) { + int pst = startType; + for (int j = i - 1; j >= index; --j) { + if (result[j] == l || result[j] == r) { + pst = result[j]; + break; + } + } + if (pst == l) { + result[i] = l; + } + } + } + checkCommanCharacters(index, length, level, startType, endType); + } + + void checkCommanCharacters( + int index, + int length, + int level, + int startType, + int endType, + ) { + for (int i = index; i < length; ++i) { + if (result[i] == ws || + result[i] == otn || + result[i] == b || + result[i] == s) { + final int m = i; + final int len = getLength(m, length, [b, s, ws, otn]); + int lt, tt, rt; + if (m == index) { + lt = startType; + } else { + lt = result[m - 1]; + if (lt == an) { + lt = r; + } else if (lt == en) { + lt = r; + } + } + if (len == length) { + tt = endType; + } else { + tt = result[len]; + if (tt == an) { + tt = r; + } else if (tt == en) { + tt = r; + } + } + if (lt == tt) { + rt = lt; + } else { + rt = ((level & 0x1) == 0) ? l : r; + } + + for (int j = m; j < len; ++j) { + result[j] = rt; + } + i = len; + } + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/string_tokenizer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/string_tokenizer.dart index ea692396c..571eaf634 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/string_tokenizer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/string_tokenizer.dart @@ -1,179 +1,179 @@ -/// Utility class for working with strings. -class StringTokenizer { - //Constructor - /// internal constructor - StringTokenizer(String text) { - _text = text; - position = 0; - } - - //Constants - /// internal field - static const String _tab = '\t'; - - /// internal field - static const String whiteSpace = ' '; - - /// internal field - static const List spaces = [whiteSpace, _tab]; - - //Fields - String? _text; - - /// internal field - int? position; - - //Properties - /// internal property - bool get isEndOfFile => position == _text!.length; - - /// internal property - int get length => _text!.length; - - //Implementation - /// internal method - String? peekLine() { - final int? tempPosition = position; - final String? line = readLine(); - position = tempPosition; - return line; - } - - /// internal method - String? readLine() { - int tempPosition = position!; - while (tempPosition < length) { - final String character = _text![tempPosition]; - switch (character) { - case '\r': - case '\n': - { - final String text = _text!.substring(position!, tempPosition); - position = tempPosition + 1; - if (((character == '\r') && (position! < length)) && - (_text![position!] == '\n')) { - position = position! + 1; - } - return text; - } - } - tempPosition++; - } - if (tempPosition > position!) { - final String result = _text!.substring(position!, tempPosition); - position = tempPosition; - return result; - } - return null; - } - - /// internal method - String? peekWord() { - final int? tempPosition = position; - final String? word = readWord(); - position = tempPosition; - return word; - } - - /// internal method - String? readWord() { - int tempPosition = position!; - while (tempPosition < length) { - final String character = _text![tempPosition]; - switch (character) { - case '\r': - case '\n': - { - final String text = _text!.substring(position!, tempPosition); - position = tempPosition + 1; - if (((character == '\r') && (position! < length)) && - (_text![position!] == '\n')) { - position = position! + 1; - } - return text; - } - case ' ': - case '\t': - { - if (tempPosition == position) { - tempPosition++; - } - final String text = _text!.substring(position!, tempPosition); - position = tempPosition; - return text; - } - } - tempPosition++; - } - if (tempPosition > position!) { - final String result = _text!.substring(position!, tempPosition); - position = tempPosition; - return result; - } - return null; - } - - /// internal method - String peek() { - return (!isEndOfFile) ? _text![position!] : '\u0000'; - } - - /// internal method - String read([int? count]) { - if (count != null) { - int tempLength = 0; - String builder = ''; - while (!isEndOfFile && tempLength < count) { - final String character = read(); - builder += character; - tempLength++; - } - return builder; - } else { - String character = '\u0000'; - if (!isEndOfFile) { - character = _text![position!]; - position = position! + 1; - } - return character; - } - } - - /// internal method - void close() { - _text = null; - position = null; - } - - /// internal method - static int getCharacterCount(String text, List symbols) { - int count = 0; - for (int i = 0; i < text.length; i++) { - final String character = text[i]; - if (contains(symbols, character)) { - count++; - } - } - return count; - } - - /// internal method - static bool contains(List array, String symbol) { - bool contains = false; - for (int i = 0; i < array.length; i++) { - if (array[i] == symbol) { - contains = true; - break; - } - } - return contains; - } - - /// internal method - String? readToEnd() { - final String? text = - position == 0 ? _text : _text!.substring(position!, length); - position = length; - return text; - } -} +/// Utility class for working with strings. +class StringTokenizer { + //Constructor + /// internal constructor + StringTokenizer(String text) { + _text = text; + position = 0; + } + + //Constants + /// internal field + static const String _tab = '\t'; + + /// internal field + static const String whiteSpace = ' '; + + /// internal field + static const List spaces = [whiteSpace, _tab]; + + //Fields + String? _text; + + /// internal field + int? position; + + //Properties + /// internal property + bool get isEndOfFile => position == _text!.length; + + /// internal property + int get length => _text!.length; + + //Implementation + /// internal method + String? peekLine() { + final int? tempPosition = position; + final String? line = readLine(); + position = tempPosition; + return line; + } + + /// internal method + String? readLine() { + int tempPosition = position!; + while (tempPosition < length) { + final String character = _text![tempPosition]; + switch (character) { + case '\r': + case '\n': + { + final String text = _text!.substring(position!, tempPosition); + position = tempPosition + 1; + if (((character == '\r') && (position! < length)) && + (_text![position!] == '\n')) { + position = position! + 1; + } + return text; + } + } + tempPosition++; + } + if (tempPosition > position!) { + final String result = _text!.substring(position!, tempPosition); + position = tempPosition; + return result; + } + return null; + } + + /// internal method + String? peekWord() { + final int? tempPosition = position; + final String? word = readWord(); + position = tempPosition; + return word; + } + + /// internal method + String? readWord() { + int tempPosition = position!; + while (tempPosition < length) { + final String character = _text![tempPosition]; + switch (character) { + case '\r': + case '\n': + { + final String text = _text!.substring(position!, tempPosition); + position = tempPosition + 1; + if (((character == '\r') && (position! < length)) && + (_text![position!] == '\n')) { + position = position! + 1; + } + return text; + } + case ' ': + case '\t': + { + if (tempPosition == position) { + tempPosition++; + } + final String text = _text!.substring(position!, tempPosition); + position = tempPosition; + return text; + } + } + tempPosition++; + } + if (tempPosition > position!) { + final String result = _text!.substring(position!, tempPosition); + position = tempPosition; + return result; + } + return null; + } + + /// internal method + String peek() { + return (!isEndOfFile) ? _text![position!] : '\u0000'; + } + + /// internal method + String read([int? count]) { + if (count != null) { + int tempLength = 0; + String builder = ''; + while (!isEndOfFile && tempLength < count) { + final String character = read(); + builder += character; + tempLength++; + } + return builder; + } else { + String character = '\u0000'; + if (!isEndOfFile) { + character = _text![position!]; + position = position! + 1; + } + return character; + } + } + + /// internal method + void close() { + _text = null; + position = null; + } + + /// internal method + static int getCharacterCount(String text, List symbols) { + int count = 0; + for (int i = 0; i < text.length; i++) { + final String character = text[i]; + if (contains(symbols, character)) { + count++; + } + } + return count; + } + + /// internal method + static bool contains(List array, String symbol) { + bool contains = false; + for (int i = 0; i < array.length; i++) { + if (array[i] == symbol) { + contains = true; + break; + } + } + return contains; + } + + /// internal method + String? readToEnd() { + final String? text = + position == 0 ? _text : _text!.substring(position!, length); + position = length; + return text; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_metrics.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_metrics.dart index 5e39c5c80..1aef93b5b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_metrics.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_metrics.dart @@ -1,67 +1,67 @@ -import '../../drawing/drawing.dart'; - -/// internal class -class TtfMetrics { - /// internal field - int? lineGap; - - /// internal field - bool? contains; - - /// internal field - late bool isSymbol; - - /// internal field - late PdfRectangle fontBox; - - /// internal field - late bool isFixedPitch; - - /// internal field - double? italicAngle; - - /// internal field - String? postScriptName; - - /// internal field - String? fontFamily; - - /// internal field - late double capHeight; - - /// internal field - late double leading; - - /// internal field - double macAscent = 0; - - /// internal field - double macDescent = 0; - - /// internal field - late double winDescent; - - /// internal field - late double winAscent; - - /// internal field - late double stemV; - - /// internal field - late List widthTable; - - /// internal field - int? macStyle; - - /// internal field - double? subscriptSizeFactor; - - /// internal field - double? superscriptSizeFactor; - //Properties - /// internal property - bool get isItalic => macStyle! & 2 != 0; - - /// internal property - bool get isBold => macStyle! & 1 != 0; -} +import '../../drawing/drawing.dart'; + +/// internal class +class TtfMetrics { + /// internal field + int? lineGap; + + /// internal field + bool? contains; + + /// internal field + late bool isSymbol; + + /// internal field + late PdfRectangle fontBox; + + /// internal field + late bool isFixedPitch; + + /// internal field + double? italicAngle; + + /// internal field + String? postScriptName; + + /// internal field + String? fontFamily; + + /// internal field + late double capHeight; + + /// internal field + late double leading; + + /// internal field + double macAscent = 0; + + /// internal field + double macDescent = 0; + + /// internal field + late double winDescent; + + /// internal field + late double winAscent; + + /// internal field + late double stemV; + + /// internal field + late List widthTable; + + /// internal field + int? macStyle; + + /// internal field + double? subscriptSizeFactor; + + /// internal field + double? superscriptSizeFactor; + //Properties + /// internal property + bool get isItalic => macStyle! & 2 != 0; + + /// internal property + bool get isBold => macStyle! & 1 != 0; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_reader.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_reader.dart index 07c26cfef..0cca50409 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_reader.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/ttf_reader.dart @@ -1,1819 +1,1819 @@ -import 'dart:math'; - -import '../../drawing/drawing.dart'; -import '../../io/big_endian_writer.dart'; -import 'ttf_metrics.dart'; - -/// internal class -class TtfReader { - /// internal constructor - TtfReader(List fontData) { - _fontData = fontData; - _initialize(); - } - - //Constants - final int _int32Size = 4; - final List _tableNames = [ - 'cvt ', - 'fpgm', - 'glyf', - 'head', - 'hhea', - 'hmtx', - 'loca', - 'maxp', - 'prep', - ]; - final List _entrySelectors = [ - 0, - 0, - 1, - 1, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 4, - 4, - 4, - 4, - 4, - ]; - - //Fields - late List _fontData; - - /// internal field - TtfMetrics? metrics; - - /// internal field - int? currentOffset; - late bool _isMacTtf; - late bool _isTtcFont; - Map? _tableDirectory; - Map? _macintoshDirectory; - Map? _microsoftDirectory; - Map? _macintoshGlyphInfoCollection; - Map? _microsoftGlyphInfoCollection; - Map? _unicodeUCS4GlyphCollection; - int? _lowestPosition; - late bool _isLocaShort; - late List _width; - int _surrogateHigh = 0; - int? _maxMacIndex; - String _surrogateHighChar = ''; - - /// internal field - List? internalUsedChars; - - /// internal field - List get usedChars { - internalUsedChars ??= []; - return internalUsedChars!; - } - - //Properties - Map? get _macintosh { - _macintoshDirectory ??= {}; - return _macintoshDirectory; - } - - Map? get _microsoft { - _microsoftDirectory ??= {}; - return _microsoftDirectory; - } - - Map? get _macintoshGlyphs { - _macintoshGlyphInfoCollection ??= {}; - return _macintoshGlyphInfoCollection; - } - - Map? get _microsoftGlyphs { - _microsoftGlyphInfoCollection ??= {}; - return _microsoftGlyphInfoCollection; - } - - Map? get _unicodeUcs4Glyph { - _unicodeUCS4GlyphCollection ??= {}; - return _unicodeUCS4GlyphCollection; - } - - //Implementation - void _initialize() { - _isMacTtf = false; - _isTtcFont = false; - metrics = TtfMetrics(); - _readFontDictionary(); - final _TtfNameTable nameTable = _readNameTable(); - final _TtfHeadTable headTable = _readHeadTable(); - _initializeFontName(nameTable); - metrics!.macStyle = headTable.macStyle; - } - - void _readFontDictionary() { - currentOffset = 0; - _checkPreambula(); - final int numTables = _readInt16(currentOffset!); - //searchRange - _readInt16(currentOffset!); - //entrySelector - _readInt16(currentOffset!); - //rangeShift - _readInt16(currentOffset!); - _tableDirectory ??= {}; - for (int i = 0; i < numTables; ++i) { - final _TtfTableInfo table = _TtfTableInfo(); - final String tableKey = _readString(_int32Size); - table.checksum = _readInt32(currentOffset!); - table.offset = _readInt32(currentOffset!); - table.length = _readInt32(currentOffset!); - _tableDirectory![tableKey] = table; - } - _lowestPosition = currentOffset; - if (!_isTtcFont) { - _fixOffsets(); - } - } - - void _checkPreambula() { - final int version = _readInt32(currentOffset!); - _isMacTtf = version == 0x74727565; - if (version != 0x10000 && !_isMacTtf && version != 0x4f54544f) { - _isTtcFont = true; - currentOffset = 0; - if (_readString(4) != 'ttcf') { - throw UnsupportedError('Can not read TTF font data'); - } - currentOffset = currentOffset! + 4; - if (_readInt32(currentOffset!) < 0) { - throw UnsupportedError('Can not read TTF font data'); - } - //Offset for version - currentOffset = _readInt32(currentOffset!); - //Version - _readInt32(currentOffset!); - } - } - - void _fixOffsets() { - int minOffset = pow(2, 53) as int; - // Search for a smallest offset and compare it - // with the lowest position found. - final List keys = _tableDirectory!.keys.toList(); - for (int i = 0; i < keys.length; i++) { - final int offset = _tableDirectory![keys[i]]!.offset!; - if (minOffset > offset) { - minOffset = offset; - if (minOffset <= _lowestPosition!) { - break; - } - } - } - final int shift = minOffset - _lowestPosition!; - if (shift != 0) { - final Map table = {}; - for (int i = 0; i < keys.length; i++) { - final _TtfTableInfo value = _tableDirectory![keys[i]]!; - value.offset = value.offset! - shift; - table[keys[i]] = value; - } - _tableDirectory = table; - } - } - - _TtfNameTable _readNameTable() { - final _TtfTableInfo tableInfo = _getTable('name')!; - currentOffset = tableInfo.offset; - final _TtfNameTable table = _TtfNameTable(); - table.formatSelector = _readUInt16(currentOffset!); - table.recordsCount = _readUInt16(currentOffset!); - table.offset = _readUInt16(currentOffset!); - table.nameRecords = <_TtfNameRecord>[]; - const int recordSize = 12; - int? position = currentOffset; - for (int i = 0; i < table.recordsCount; i++) { - currentOffset = position; - final _TtfNameRecord record = _TtfNameRecord(); - record.platformID = _readUInt16(currentOffset!); - record.encodingID = _readUInt16(currentOffset!); - record.languageID = _readUInt16(currentOffset!); - record.nameID = _readUInt16(currentOffset!); - record.length = _readUInt16(currentOffset!); - record.offset = _readUInt16(currentOffset!); - currentOffset = tableInfo.offset! + table.offset + record.offset; - final bool isUnicode = record.platformID == 0 || record.platformID == 3; - record.name = _readString(record.length, isUnicode); - table.nameRecords.add(record); - position = position! + recordSize; - } - return table; - } - - _TtfHeadTable _readHeadTable() { - final _TtfTableInfo tableInfo = _getTable('head')!; - currentOffset = tableInfo.offset; - final _TtfHeadTable table = _TtfHeadTable(); - table.version = _readFixed(currentOffset!); - table.fontRevision = _readFixed(currentOffset!); - table.checkSumAdjustment = _readUInt32(currentOffset!); - table.magicNumber = _readUInt32(currentOffset!); - table.flags = _readUInt16(currentOffset!); - table.unitsPerEm = _readUInt16(currentOffset!); - table.created = _readInt64(currentOffset!); - table.modified = _readInt64(currentOffset!); - table.xMin = _readInt16(currentOffset!); - table.yMin = _readInt16(currentOffset!); - table.xMax = _readInt16(currentOffset!); - table.yMax = _readInt16(currentOffset!); - table.macStyle = _readUInt16(currentOffset!); - table.lowestReadableSize = _readUInt16(currentOffset!); - table.fontDirectionHint = _readInt16(currentOffset!); - table.indexToLocalFormat = _readInt16(currentOffset!); - table.glyphDataFormat = _readInt16(currentOffset!); - return table; - } - - _TtfHorizontalHeaderTable _readHorizontalHeaderTable() { - final _TtfTableInfo tableInfo = _getTable('hhea')!; - currentOffset = tableInfo.offset; - final _TtfHorizontalHeaderTable table = _TtfHorizontalHeaderTable(); - table.version = _readFixed(currentOffset!); - table.ascender = _readInt16(currentOffset!); - table.descender = _readInt16(currentOffset!); - table.lineGap = _readInt16(currentOffset!); - table.advanceWidthMax = _readUInt16(currentOffset!); - table.minLeftSideBearing = _readInt16(currentOffset!); - table.minRightSideBearing = _readInt16(currentOffset!); - table.xMaxExtent = _readInt16(currentOffset!); - table.caretSlopeRise = _readInt16(currentOffset!); - table.caretSlopeRun = _readInt16(currentOffset!); - currentOffset = currentOffset! + 10; - table.metricDataFormat = _readInt16(currentOffset!); - table.numberOfHMetrics = _readUInt16(currentOffset!); - return table; - } - - _TtfOS2Table _readOS2Table() { - final _TtfTableInfo tableInfo = _getTable('OS/2')!; - currentOffset = tableInfo.offset; - final _TtfOS2Table table = _TtfOS2Table(); - table.version = _readUInt16(currentOffset!); - table.xAvgCharWidth = _readInt16(currentOffset!); - table.usWeightClass = _readUInt16(currentOffset!); - table.usWidthClass = _readUInt16(currentOffset!); - table.fsType = _readInt16(currentOffset!); - table.ySubscriptXSize = _readInt16(currentOffset!); - table.ySubscriptYSize = _readInt16(currentOffset!); - table.ySubscriptXOffset = _readInt16(currentOffset!); - table.ySubscriptYOffset = _readInt16(currentOffset!); - table.ySuperscriptXSize = _readInt16(currentOffset!); - table.ySuperscriptYSize = _readInt16(currentOffset!); - table.ySuperscriptXOffset = _readInt16(currentOffset!); - table.ySuperscriptYOffset = _readInt16(currentOffset!); - table.yStrikeoutSize = _readInt16(currentOffset!); - table.yStrikeoutPosition = _readInt16(currentOffset!); - table.sFamilyClass = _readInt16(currentOffset!); - table.panose = _readBytes(10); - table.ulUnicodeRange1 = _readUInt32(currentOffset!); - table.ulUnicodeRange2 = _readUInt32(currentOffset!); - table.ulUnicodeRange3 = _readUInt32(currentOffset!); - table.ulUnicodeRange4 = _readUInt32(currentOffset!); - table.vendorIdentifier = _readBytes(4); - table.fsSelection = _readUInt16(currentOffset!); - table.usFirstCharIndex = _readUInt16(currentOffset!); - table.usLastCharIndex = _readUInt16(currentOffset!); - table.sTypoAscender = _readInt16(currentOffset!); - table.sTypoDescender = _readInt16(currentOffset!); - table.sTypoLineGap = _readInt16(currentOffset!); - table.usWinAscent = _readUInt16(currentOffset!); - table.usWinDescent = _readUInt16(currentOffset!); - table.ulCodePageRange1 = _readUInt32(currentOffset!); - table.ulCodePageRange2 = _readUInt32(currentOffset!); - if (table.version > 1) { - table.sxHeight = _readInt16(currentOffset!); - table.sCapHeight = _readInt16(currentOffset!); - table.usDefaultChar = _readUInt16(currentOffset!); - table.usBreakChar = _readUInt16(currentOffset!); - table.usMaxContext = _readUInt16(currentOffset!); - } else { - table.sxHeight = 0; - table.sCapHeight = 0; - table.usDefaultChar = 0; - table.usBreakChar = 0; - table.usMaxContext = 0; - } - return table; - } - - _TtfPostTable _readPostTable() { - final _TtfTableInfo tableInfo = _getTable('post')!; - currentOffset = tableInfo.offset; - final _TtfPostTable table = _TtfPostTable(); - table.formatType = _readFixed(currentOffset!); - table.italicAngle = _readFixed(currentOffset!); - table.underlinePosition = _readInt16(currentOffset!); - table.underlineThickness = _readInt16(currentOffset!); - table.isFixedPitch = _readUInt32(currentOffset!); - table.minType42 = _readUInt32(currentOffset!); - table.maxType42 = _readUInt32(currentOffset!); - table.minType1 = _readUInt32(currentOffset!); - table.maxType1 = _readUInt32(currentOffset!); - return table; - } - - List _readWidthTable(int glyphCount, int? unitsPerEm) { - final _TtfTableInfo tableInfo = _getTable('hmtx')!; - currentOffset = tableInfo.offset; - final List width = List.filled(glyphCount, 0, growable: true); - for (int i = 0; i < glyphCount; i++) { - final _TtfLongHorMetric glyph = _TtfLongHorMetric(); - glyph.advanceWidth = _readUInt16(currentOffset!); - glyph.lsb = _readInt16(currentOffset!); - final double glyphWidth = glyph.advanceWidth * 1000 / unitsPerEm!; - width[i] = glyphWidth.floor(); - } - return width; - } - - void _initializeMetrics( - _TtfNameTable nameTable, - _TtfHeadTable headTable, - _TtfHorizontalHeaderTable horizontalHeadTable, - _TtfOS2Table os2Table, - _TtfPostTable postTable, - List<_TtfCmapSubTable> cmapTables, - ) { - _initializeFontName(nameTable); - bool bSymbol = false; - for (int i = 0; i < cmapTables.length; i++) { - final _TtfCmapSubTable subTable = cmapTables[i]; - final _TtfCmapEncoding encoding = _getCmapEncoding( - subTable.platformID, - subTable.encodingID, - ); - if (encoding == _TtfCmapEncoding.symbol) { - bSymbol = true; - break; - } - } - metrics!.isSymbol = bSymbol; - metrics!.macStyle = headTable.macStyle; - metrics!.isFixedPitch = postTable.isFixedPitch != 0; - metrics!.italicAngle = postTable.italicAngle; - final double factor = 1000 / headTable.unitsPerEm!; - metrics!.winAscent = os2Table.sTypoAscender * factor; - metrics!.macAscent = horizontalHeadTable.ascender * factor; - metrics!.capHeight = - (os2Table.sCapHeight != 0) - ? os2Table.sCapHeight!.toDouble() - : 0.7 * headTable.unitsPerEm! * factor; - metrics!.winDescent = os2Table.sTypoDescender * factor; - metrics!.macDescent = horizontalHeadTable.descender * factor; - metrics!.leading = - (os2Table.sTypoAscender - - os2Table.sTypoDescender + - os2Table.sTypoLineGap) * - factor; - metrics!.lineGap = (horizontalHeadTable.lineGap * factor).ceil(); - final double left = headTable.xMin * factor; - final double top = (metrics!.macAscent + metrics!.lineGap!).ceilToDouble(); - final double right = headTable.xMax * factor; - final double bottom = metrics!.macDescent; - metrics!.fontBox = PdfRectangle(left, top, right - left, bottom - top); - metrics!.stemV = 80; - metrics!.widthTable = _updateWidth(); - metrics!.contains = _tableDirectory!.containsKey('CFF'); - metrics!.subscriptSizeFactor = - headTable.unitsPerEm! / os2Table.ySubscriptYSize; - metrics!.superscriptSizeFactor = - headTable.unitsPerEm! / os2Table.ySuperscriptYSize; - } - - List<_TtfCmapSubTable> _readCmapTable() { - final _TtfTableInfo tableInfo = _getTable('cmap')!; - currentOffset = tableInfo.offset; - final _TtfCmapTable table = _TtfCmapTable(); - table.version = _readUInt16(currentOffset!); - table.tablesCount = _readUInt16(currentOffset!); - int? position = currentOffset; - final List<_TtfCmapSubTable> subTables = <_TtfCmapSubTable>[]; - for (int i = 0; i < table.tablesCount; i++) { - currentOffset = position; - final _TtfCmapSubTable subTable = _TtfCmapSubTable(); - subTable.platformID = _readUInt16(currentOffset!); - subTable.encodingID = _readUInt16(currentOffset!); - subTable.offset = _readUInt32(currentOffset!); - position = currentOffset; - _readCmapSubTable(subTable); - subTables.add(subTable); - } - return subTables; - } - - void _readCmapSubTable(_TtfCmapSubTable subTable) { - final _TtfTableInfo tableInfo = _getTable('cmap')!; - currentOffset = tableInfo.offset! + subTable.offset; - final _TtfCmapFormat format = _getCmapFormat(_readUInt16(currentOffset!)); - final _TtfCmapEncoding encoding = _getCmapEncoding( - subTable.platformID, - subTable.encodingID, - ); - if (encoding != _TtfCmapEncoding.unknown) { - switch (format) { - case _TtfCmapFormat.apple: - _readAppleCmapTable(subTable, encoding); - break; - case _TtfCmapFormat.microsoft: - _readMicrosoftCmapTable(subTable, encoding); - break; - case _TtfCmapFormat.trimmed: - _readTrimmedCmapTable(subTable, encoding); - break; - case _TtfCmapFormat.microsoftExt: - _readUCS4CmapTable(subTable, encoding); - break; - } - } - } - - void _readUCS4CmapTable( - _TtfCmapSubTable subTable, - _TtfCmapEncoding encoding, - ) { - final _TtfTableInfo tableInfo = _getTable('cmap')!; - currentOffset = tableInfo.offset! + subTable.offset + 12; - final int count = _readInt32(currentOffset!); - for (int i = 0; i < count; ++i) { - final int start = _readInt32(currentOffset!); - final int end = _readInt32(currentOffset!); - int glyphID = _readInt32(currentOffset!); - for (int j = start; j <= end; j++) { - final TtfGlyphInfo glyphInfo = TtfGlyphInfo(); - glyphInfo.charCode = j; - glyphInfo.width = _getWidth(glyphID); - glyphInfo.index = glyphID; - _addReverseGlyph(glyphInfo, encoding); - glyphID++; - } - } - } - - void _readAppleCmapTable( - _TtfCmapSubTable subTable, - _TtfCmapEncoding encoding, - ) { - final _TtfTableInfo tableInfo = _getTable('cmap')!; - currentOffset = tableInfo.offset! + subTable.offset; - final _TtfAppleCmapSubTable table = _TtfAppleCmapSubTable(); - table.format = _readUInt16(currentOffset!); - table.length = _readUInt16(currentOffset!); - table.version = _readUInt16(currentOffset!); - _maxMacIndex ??= 0; - for (int i = 0; i < 256; ++i) { - final TtfGlyphInfo glyphInfo = TtfGlyphInfo(); - glyphInfo.index = _fontData[currentOffset!]; - currentOffset = currentOffset! + 1; - glyphInfo.width = _getWidth(glyphInfo.index); - glyphInfo.charCode = i; - _macintosh![i] = glyphInfo; - _addGlyph(glyphInfo, encoding); - _maxMacIndex = i >= _maxMacIndex! ? i : _maxMacIndex; - } - } - - void _readMicrosoftCmapTable( - _TtfCmapSubTable subTable, - _TtfCmapEncoding encoding, - ) { - final _TtfTableInfo tableInfo = _getTable('cmap')!; - currentOffset = tableInfo.offset! + subTable.offset; - final Map? collection = - encoding == _TtfCmapEncoding.unicode ? _microsoft : _macintosh; - final _TtfMicrosoftCmapSubTable table = _TtfMicrosoftCmapSubTable(); - table.format = _readUInt16(currentOffset!); - table.length = _readUInt16(currentOffset!); - table.version = _readUInt16(currentOffset!); - table.segCountX2 = _readUInt16(currentOffset!); - table.searchRange = _readUInt16(currentOffset!); - table.entrySelector = _readUInt16(currentOffset!); - table.rangeShift = _readUInt16(currentOffset!); - final int segCount = table.segCountX2 ~/ 2; - table.endCount = _readUshortArray(segCount); - table.reservedPad = _readUInt16(currentOffset!); - table.startCount = _readUshortArray(segCount); - table.idDelta = _readUshortArray(segCount); - table.idRangeOffset = _readUshortArray(segCount); - final int length = ((table.length / 2 - 8) - (segCount * 4)).toInt(); - table.glyphID = _readUshortArray(length); - // Process glyphIdArray array. - int codeOffset = 0; - int index = 0; - for (int j = 0; j < segCount; j++) { - for ( - int k = table.startCount[j]; - k <= table.endCount[j] && k != 65535; - k++ - ) { - if (table.idRangeOffset[j] == 0) { - codeOffset = (k + table.idDelta[j]) & 65535; - } else { - index = - (j + - table.idRangeOffset[j] / 2 - - segCount + - k - - table.startCount[j]) - .toInt(); - if (index >= table.glyphID.length) { - continue; - } - codeOffset = (table.glyphID[index] + table.idDelta[j]) & 65535; - } - final TtfGlyphInfo glyph = TtfGlyphInfo(); - glyph.index = codeOffset; - glyph.width = _getWidth(glyph.index); - final int id = - (encoding == _TtfCmapEncoding.symbol) - ? ((k & 0xff00) == 0xf000 ? k & 0xff : k) - : k; - glyph.charCode = id; - collection![id] = glyph; - _addGlyph(glyph, encoding); - } - } - } - - void _readTrimmedCmapTable( - _TtfCmapSubTable subTable, - _TtfCmapEncoding encoding, - ) { - final _TtfTableInfo tableInfo = _getTable('cmap')!; - currentOffset = tableInfo.offset! + subTable.offset; - final _TtfTrimmedCmapSubTable table = _TtfTrimmedCmapSubTable(); - table.format = _readUInt16(currentOffset!); - table.length = _readUInt16(currentOffset!); - table.version = _readUInt16(currentOffset!); - table.firstCode = _readUInt16(currentOffset!); - table.entryCount = _readUInt16(currentOffset!); - _maxMacIndex ??= 0; - for (int i = 0; i < table.entryCount; ++i) { - final TtfGlyphInfo glyphInfo = TtfGlyphInfo(); - glyphInfo.index = _readUInt16(currentOffset!); - glyphInfo.width = _getWidth(glyphInfo.index); - glyphInfo.charCode = i + table.firstCode; - _macintosh![i] = glyphInfo; - _addGlyph(glyphInfo, encoding); - _maxMacIndex = i >= _maxMacIndex! ? i : _maxMacIndex; - } - } - - _TtfTableInfo? _getTable(String name) { - _TtfTableInfo? table = _TtfTableInfo(); - if (_tableDirectory!.containsKey(name)) { - table = _tableDirectory![name]; - } - return table; - } - - int _getWidth(int glyphCode) { - glyphCode = (glyphCode < _width.length) ? glyphCode : _width.length - 1; - return _width[glyphCode]; - } - - List _updateWidth() { - const int count = 256; - if (metrics!.isSymbol) { - final List bytes = List.filled(count, 0, growable: true); - for (int i = 0; i < count; i++) { - final TtfGlyphInfo glyphInfo = getGlyph(char: String.fromCharCode(i))!; - bytes[i] = (glyphInfo.empty) ? 0 : glyphInfo.width; - } - return bytes; - } else { - final List bytes = List.filled(count, 0, growable: true); - final List byteToProcess = List.filled(1, 0); - final String space = String.fromCharCode(32); - for (int i = 0; i < count; i++) { - byteToProcess[0] = i; - String text = ''; - for (int index = 0; index < byteToProcess.length; index++) { - text += String.fromCharCode(byteToProcess[index + 0]); - } - final String ch = text.isNotEmpty ? text[0] : '?'; - TtfGlyphInfo glyphInfo = getGlyph(char: ch)!; - if (!glyphInfo.empty) { - bytes[i] = glyphInfo.width; - } else { - glyphInfo = getGlyph(char: space)!; - bytes[i] = (glyphInfo.empty) ? 0 : glyphInfo.width; - } - } - return bytes; - } - } - - /// internal method - double getCharWidth(String code) { - TtfGlyphInfo? glyphInfo = getGlyph(char: code); - glyphInfo = - (glyphInfo != null && !glyphInfo.empty) - ? glyphInfo - : _getDefaultGlyph(); - return (!glyphInfo!.empty) ? glyphInfo.width.toDouble() : 0; - } - - /// internal method - TtfGlyphInfo? getGlyph({ - int? charCode, - String? char, - bool? isSetSymbol = false, - }) { - if (charCode != null) { - TtfGlyphInfo? glyphInfo; - if (!metrics!.isSymbol && _microsoftGlyphs != null) { - if (_microsoftGlyphs!.containsKey(charCode)) { - glyphInfo = _microsoftGlyphs![charCode]; - } - } else if (metrics!.isSymbol && _macintoshGlyphs != null) { - if (_macintoshGlyphs!.containsKey(charCode)) { - glyphInfo = _macintoshGlyphs![charCode]; - } - } - if (glyphInfo == null && - _unicodeUCS4GlyphCollection != null && - _unicodeUCS4GlyphCollection!.containsKey(charCode)) { - glyphInfo = _unicodeUCS4GlyphCollection![charCode]; - } - return glyphInfo ?? _getDefaultGlyph(); - } else if (char != null) { - TtfGlyphInfo? glyphInfo; - int code = char.codeUnitAt(0); - if (!metrics!.isSymbol && _microsoft != null) { - if (_microsoft!.containsKey(code)) { - glyphInfo = _microsoft![code]; - } else if (char != ' ') { - if (_unicodeUCS4GlyphCollection != null && _isSurrogate(code)) { - TtfGlyphInfo newGlyph = TtfGlyphInfo(); - if (_isHighSurrogate(code)) { - _surrogateHighChar = char; - _surrogateHigh = code; - newGlyph.width = 0; - } - if (_isLowSurrogate(code)) { - if (_isSurrogatePair(_surrogateHigh, code)) { - code = - (((_surrogateHigh >> 6) & ((1 << 5) - 1)) + 1) << 16 | - ((_surrogateHigh & ((1 << 6) - 1)) << 10 | - code & ((1 << 10) - 1)); - if (_unicodeUCS4GlyphCollection!.containsKey(code)) { - newGlyph = _unicodeUCS4GlyphCollection![code]!; - if (isSetSymbol!) { - usedChars.add(_surrogateHighChar + char); - } - } - } - } - return newGlyph; - } - } - } else if (metrics!.isSymbol && _macintosh != null || _isMacTtf) { - if (_maxMacIndex != 0) { - code %= _maxMacIndex! + 1; - } else { - code = (code & 0xff00) == 0xf000 ? code & 0xff : code; - } - if (_macintosh!.containsKey(code)) { - glyphInfo = _macintosh![code]; - } - } - if (char == ' ' && glyphInfo == null) { - glyphInfo = TtfGlyphInfo(); - } - return glyphInfo ?? _getDefaultGlyph(); - } - return null; - } - - TtfGlyphInfo? _getDefaultGlyph() { - return getGlyph(char: ' '); - } - - bool _isHighSurrogate(int charCode) { - return charCode >= 55296 && charCode <= 56319; - } - - bool _isLowSurrogate(int charCode) { - return charCode >= 56320 && charCode <= 57343; - } - - bool _isSurrogate(int charCode) { - return charCode >= 55296 && charCode <= 57343; - } - - bool _isSurrogatePair(int highSurrogate, int lowSurrogate) { - return _isHighSurrogate(highSurrogate) && _isLowSurrogate(lowSurrogate); - } - - void _initializeFontName(_TtfNameTable nameTable) { - for (int i = 0; i < nameTable.recordsCount; i++) { - final _TtfNameRecord record = nameTable.nameRecords[i]; - if (record.nameID == 1) { - //font family - metrics!.fontFamily = record.name; - } else if (record.nameID == 6) { - //post script name - metrics!.postScriptName = record.name; - } - if (metrics!.fontFamily != null && metrics!.postScriptName != null) { - break; - } - } - } - - /// internal method - void createInternals() { - metrics = TtfMetrics(); - final _TtfNameTable nameTable = _readNameTable(); - final _TtfHeadTable headTable = _readHeadTable(); - _isLocaShort = headTable.indexToLocalFormat == 0; - final _TtfHorizontalHeaderTable horizontalHeadTable = - _readHorizontalHeaderTable(); - final _TtfOS2Table os2Table = _readOS2Table(); - final _TtfPostTable postTable = _readPostTable(); - _width = _readWidthTable( - horizontalHeadTable.numberOfHMetrics, - headTable.unitsPerEm, - ); - final List<_TtfCmapSubTable> subTables = _readCmapTable(); - _initializeMetrics( - nameTable, - headTable, - horizontalHeadTable, - os2Table, - postTable, - subTables, - ); - } - - _TtfCmapFormat _getCmapFormat(int format) { - if (format == 4) { - return _TtfCmapFormat.microsoft; - } else if (format == 6) { - return _TtfCmapFormat.trimmed; - } else if (format == 12) { - return _TtfCmapFormat.microsoftExt; - } else { - return _TtfCmapFormat.apple; - } - } - - _TtfPlatformID _getPlatformID(int? platformID) { - switch (platformID) { - case 1: - return _TtfPlatformID.macintosh; - case 2: - return _TtfPlatformID.iso; - case 3: - return _TtfPlatformID.microsoft; - default: - return _TtfPlatformID.appleUnicode; - } - } - - _TtfMicrosoftEncodingID _getMicrosoftEncodingID(int? encodingID) { - switch (encodingID) { - case 1: - return _TtfMicrosoftEncodingID.unicode; - case 10: - return _TtfMicrosoftEncodingID.unicodeUCS4; - default: - return _TtfMicrosoftEncodingID.undefined; - } - } - - _TtfMacintoshEncodingID _getMacintoshEncodingID(int? encodingID) { - switch (encodingID) { - case 1: - return _TtfMacintoshEncodingID.japanese; - case 2: - return _TtfMacintoshEncodingID.chinese; - default: - return _TtfMacintoshEncodingID.roman; - } - } - - _TtfCmapEncoding _getCmapEncoding(int? platformID, int? encodingID) { - _TtfCmapEncoding format = _TtfCmapEncoding.unknown; - if (_getPlatformID(platformID) == _TtfPlatformID.microsoft && - _getMicrosoftEncodingID(encodingID) == - _TtfMicrosoftEncodingID.undefined) { - format = _TtfCmapEncoding.symbol; - } else if (_getPlatformID(platformID) == _TtfPlatformID.microsoft && - _getMicrosoftEncodingID(encodingID) == - _TtfMicrosoftEncodingID.unicode) { - format = _TtfCmapEncoding.unicode; - } else if (_getPlatformID(platformID) == _TtfPlatformID.macintosh && - _getMacintoshEncodingID(encodingID) == _TtfMacintoshEncodingID.roman) { - format = _TtfCmapEncoding.macintosh; - } else if (_getPlatformID(platformID) == _TtfPlatformID.microsoft && - _getMicrosoftEncodingID(encodingID) == - _TtfMicrosoftEncodingID.unicodeUCS4) { - format = _TtfCmapEncoding.unicodeUCS4; - } - return format; - } - - void _addReverseGlyph(TtfGlyphInfo glyph, _TtfCmapEncoding encoding) { - Map? collection; - switch (encoding) { - case _TtfCmapEncoding.unicode: - collection = _microsoftGlyphs; - break; - case _TtfCmapEncoding.macintosh: - case _TtfCmapEncoding.symbol: - collection = _macintoshGlyphs; - break; - case _TtfCmapEncoding.unicodeUCS4: - collection = _unicodeUcs4Glyph; - break; - case _TtfCmapEncoding.unknown: - break; - } - collection![glyph.charCode] = glyph; - } - - void _addGlyph(TtfGlyphInfo glyph, _TtfCmapEncoding encoding) { - Map? collection; - switch (encoding) { - case _TtfCmapEncoding.unicode: - collection = _microsoftGlyphs; - break; - case _TtfCmapEncoding.macintosh: - case _TtfCmapEncoding.symbol: - collection = _macintoshGlyphs; - break; - case _TtfCmapEncoding.unknown: - case _TtfCmapEncoding.unicodeUCS4: - break; - } - collection![glyph.index] = glyph; - } - - /// internal method - Map getGlyphChars(List chars) { - final Map dictionary = {}; - for (int i = 0; i < chars.length; i++) { - final String ch = chars[i]; - final TtfGlyphInfo glyph = getGlyph(char: ch)!; - if (!glyph.empty) { - dictionary[glyph.index] = ch.codeUnitAt(0); - } - } - return dictionary; - } - - /// internal method - List? readFontProgram(List chars) { - final Map glyphChars = getGlyphChars(chars); - final List offsets = _readLocaTable(_isLocaShort); - _updateGlyphChars(glyphChars, offsets); - final Map returnedValue = - _generateGlyphTable(glyphChars, offsets, null, null) - as Map; - final int? glyphTableSize = returnedValue['glyphTableSize'] as int?; - final List newLocaTable = returnedValue['newLocaTable'] as List; - final List newGlyphTable = returnedValue['newGlyphTable'] as List; - final Map result = - _updateLocaTable(newLocaTable, _isLocaShort, null) - as Map; - final int? newLocaSize = result['newLocaSize'] as int?; - final List newLocaUpdated = result['newLocaUpdated'] as List; - final List? fontProgram = _getFontProgram( - newLocaUpdated, - newGlyphTable, - glyphTableSize, - newLocaSize, - ); - return fontProgram; - } - - List _readLocaTable(bool isShort) { - final _TtfTableInfo tableInfo = _getTable('loca')!; - currentOffset = tableInfo.offset; - List buffer; - if (isShort) { - final int len = tableInfo.length! ~/ 2; - buffer = List.filled(len, 0, growable: true); - for (int i = 0; i < len; i++) { - buffer[i] = _readUInt16(currentOffset!) * 2; - } - } else { - final int len = tableInfo.length! ~/ 4; - buffer = List.filled(len, 0, growable: true); - for (int i = 0; i < len; i++) { - buffer[i] = _readUInt32(currentOffset!); - } - } - return buffer; - } - - dynamic _updateLocaTable( - List newLocaTable, - bool isLocaShort, - List? newLocaTableOut, - ) { - final int size = - isLocaShort ? newLocaTable.length * 2 : newLocaTable.length * 4; - final int count = _align(size); - final BigEndianWriter writer = BigEndianWriter(count); - for (int i = 0; i < newLocaTable.length; i++) { - int value = newLocaTable[i]; - if (isLocaShort) { - value ~/= 2; - writer.writeShort(value); - } else { - writer.writeInt(value); - } - } - return { - 'newLocaUpdated': writer.data, - 'newLocaSize': size, - }; - } - - void _updateGlyphChars(Map glyphChars, List offsets) { - if (!glyphChars.containsKey(0)) { - glyphChars[0] = 0; - } - final List glyphCharKeys = glyphChars.keys.toList(); - final Map clone = {}; - for (int i = 0; i < glyphCharKeys.length; i++) { - clone[glyphCharKeys[i]] = glyphChars[glyphCharKeys[i]]!; - } - for (int i = 0; i < glyphCharKeys.length; i++) { - _processCompositeGlyph(glyphChars, glyphCharKeys[i], offsets); - } - } - - void _processCompositeGlyph( - Map glyphChars, - int glyph, - List offsets, - ) { - if (glyph < offsets.length - 1) { - final int glyphOffset = offsets[glyph]; - if (glyphOffset != offsets[glyph + 1]) { - final _TtfTableInfo tableInfo = _getTable('glyf')!; - currentOffset = tableInfo.offset! + glyphOffset; - final _TtfGlyphHeader glyphHeader = _TtfGlyphHeader(); - glyphHeader.numberOfContours = _readInt16(currentOffset!); - glyphHeader.xMin = _readInt16(currentOffset!); - glyphHeader.yMin = _readInt16(currentOffset!); - glyphHeader.xMax = _readInt16(currentOffset!); - glyphHeader.yMax = _readInt16(currentOffset!); - if (glyphHeader.numberOfContours < 0) { - int skipBytes = 0; - while (true) { - final int flags = _readUInt16(currentOffset!); - final int glyphIndex = _readUInt16(currentOffset!); - if (!glyphChars.containsKey(glyphIndex)) { - glyphChars[glyphIndex] = 0; - } - if ((flags & 0x0020) == 0) { - break; - } - skipBytes = (flags & 0x0001) != 0 ? 4 : 2; - if (flags & 0x0008 != 0) { - skipBytes += 2; - } else if (flags & 0x0040 != 0) { - skipBytes += 4; - } else if (flags & 0x0080 != 0) { - skipBytes += 2 * 4; - } - currentOffset = currentOffset! + skipBytes; - } - } - } - } - } - - dynamic _generateGlyphTable( - Map glyphChars, - List offsets, - List? newLocaTable, - List? newGlyphTable, - ) { - newLocaTable = []; - final List activeGlyphs = glyphChars.keys.toList(); - activeGlyphs.sort((int a, int b) => a - b); - int glyphSize = 0; - for (int i = 0; i < activeGlyphs.length; i++) { - if (offsets.isNotEmpty) { - glyphSize += offsets[activeGlyphs[i] + 1] - offsets[activeGlyphs[i]]; - } - } - final int glyphSizeAligned = _align(glyphSize); - newGlyphTable = []; - for (int i = 0; i < glyphSizeAligned; i++) { - newGlyphTable.add(0); - } - int nextGlyphOffset = 0; - int nextGlyphIndex = 0; - final _TtfTableInfo? table = _getTable('glyf'); - for (int i = 0; i < offsets.length; i++) { - newLocaTable.add(nextGlyphOffset); - if (nextGlyphIndex < activeGlyphs.length && - activeGlyphs[nextGlyphIndex] == i) { - ++nextGlyphIndex; - newLocaTable[i] = nextGlyphOffset; - final int oldGlyphOffset = offsets[i]; - final int oldNextGlyphOffset = offsets[i + 1] - oldGlyphOffset; - if (oldNextGlyphOffset > 0) { - currentOffset = table!.offset! + oldGlyphOffset; - final Map result = - _read(newGlyphTable!, nextGlyphOffset, oldNextGlyphOffset) - as Map; - newGlyphTable = result['buffer'] as List?; - nextGlyphOffset += oldNextGlyphOffset; - } - } - } - return { - 'glyphTableSize': glyphSize, - 'newLocaTable': newLocaTable, - 'newGlyphTable': newGlyphTable, - }; - } - - int _align(int value) { - return (value + 3) & (~3); - } - - List? _getFontProgram( - List newLocaTableOut, - List newGlyphTable, - int? glyphTableSize, - int? locaTableSize, - ) { - final dynamic result = _getFontProgramLength( - newLocaTableOut, - newGlyphTable, - 0, - ); - final int fontProgramLength = result['fontProgramLength'] as int; - final int numTables = result['numTables'] as int; - final BigEndianWriter writer = BigEndianWriter(fontProgramLength); - writer.writeInt(0x10000); - writer.writeShort(numTables); - final int entrySelector = _entrySelectors[numTables]; - writer.writeShort((1 << (entrySelector & 31)) * 16); - writer.writeShort(entrySelector); - writer.writeShort((numTables - (1 << (entrySelector & 31))) * 16); - _writeCheckSums( - writer, - numTables, - newLocaTableOut, - newGlyphTable, - glyphTableSize, - locaTableSize, - ); - _writeGlyphs(writer, newLocaTableOut, newGlyphTable); - return writer.data; - } - - dynamic _getFontProgramLength( - List newLocaTableOut, - List newGlyphTable, - int numTables, - ) { - numTables = 2; - final List tableNames = _tableNames; - int fontProgramLength = 0; - for (int i = 0; i < tableNames.length; i++) { - final String tableName = tableNames[i]; - if (tableName != 'glyf' && tableName != 'loca') { - final _TtfTableInfo table = _getTable(tableName)!; - if (!table.empty) { - ++numTables; - fontProgramLength += _align(table.length!); - } - } - } - fontProgramLength += newLocaTableOut.length; - fontProgramLength += newGlyphTable.length; - final int usedTablesSize = numTables * 16 + (3 * 4); - fontProgramLength += usedTablesSize; - return { - 'fontProgramLength': fontProgramLength, - 'numTables': numTables, - }; - } - - void _writeCheckSums( - BigEndianWriter writer, - int numTables, - List newLocaTableOut, - List newGlyphTable, - int? glyphTableSize, - int? locaTableSize, - ) { - final List tableNames = _tableNames; - int usedTablesSize = numTables * 16 + (3 * 4); - int? nextTableSize = 0; - for (int i = 0; i < tableNames.length; i++) { - final String tableName = tableNames[i]; - final _TtfTableInfo tableInfo = _getTable(tableName)!; - if (tableInfo.empty) { - continue; - } - writer.writeString(tableName); - if (tableName == 'glyf') { - final int checksum = _calculateCheckSum(newGlyphTable); - writer.writeInt(checksum); - nextTableSize = glyphTableSize; - } else if (tableName == 'loca') { - final int checksum = _calculateCheckSum(newLocaTableOut); - writer.writeInt(checksum); - nextTableSize = locaTableSize; - } else { - writer.writeInt(tableInfo.checksum!); - nextTableSize = tableInfo.length; - } - writer.writeUInt(usedTablesSize); - writer.writeUInt(nextTableSize!); - usedTablesSize += _align(nextTableSize); - } - } - - int _calculateCheckSum(List bytes) { - int pos = 0; - int byte1 = 0; - int byte2 = 0; - int byte3 = 0; - int byte4 = 0; - for (int i = 0; i < ((bytes.length + 1) ~/ 4); i++) { - byte4 += bytes[pos++] & 255; - byte3 += bytes[pos++] & 255; - byte2 += bytes[pos++] & 255; - byte1 += bytes[pos++] & 255; - } - return byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24); - } - - void _writeGlyphs( - BigEndianWriter writer, - List newLocaTable, - List newGlyphTable, - ) { - final List tableNames = _tableNames; - for (int i = 0; i < tableNames.length; i++) { - final String tableName = tableNames[i]; - final _TtfTableInfo tableInfo = _getTable(tableName)!; - if (tableInfo.empty) { - continue; - } - if (tableName == 'glyf') { - writer.writeBytes(newGlyphTable); - } else if (tableName == 'loca') { - writer.writeBytes(newLocaTable); - } else { - final int count = _align(tableInfo.length!); - final List buff = List.filled(count, 0, growable: true); - currentOffset = tableInfo.offset; - final dynamic result = _read(buff, 0, tableInfo.length!); - writer.writeBytes(result['buffer']); - } - } - } - - /// internal method - String convertString(String text) { - String glyph = ''; - for (int k = 0; k < text.length; k++) { - final String char = text[k]; - final TtfGlyphInfo glyphInfo = getGlyph(char: char, isSetSymbol: true)!; - if (!glyphInfo.empty) { - glyph += String.fromCharCode(glyphInfo.index); - } - } - return glyph; - } - - int _readInt16(int offset) { - int result = (_fontData[offset] << 8) + _fontData[offset + 1]; - result = (result & (1 << 15) != 0) ? result - 0x10000 : result; - currentOffset = currentOffset! + 2; - return result; - } - - int _readUInt16(int offset) { - final int i1 = _fontData[offset]; - final int i2 = _fontData[offset + 1]; - currentOffset = currentOffset! + 2; - return (i1 << 8) | i2; - } - - int _readInt32(int offset) { - final int i1 = _fontData[offset + 3]; - final int i2 = _fontData[offset + 2]; - final int i3 = _fontData[offset + 1]; - final int i4 = _fontData[offset]; - currentOffset = currentOffset! + 4; - return i1 + (i2 << 8) + (i3 << 16) + (i4 << 24); - } - - int _readUInt32(int offset) { - final int i1 = _fontData[offset + 3]; - final int i2 = _fontData[offset + 2]; - final int i3 = _fontData[offset + 1]; - final int i4 = _fontData[offset]; - currentOffset = currentOffset! + 4; - return i1 | (i2 << 8) | (i3 << 16) | (i4 << 24); - } - - int _readInt64(int offset) { - final int low = _readInt32(offset + 4); - int n = _readInt32(offset) * 4294967296 + low; - if (low < 0) { - n += 4294967296; - } - return n; - } - - double _readFixed(int offset) { - return _readInt16(offset) + (_readInt16(offset + 2) / 16384); - } - - String _readString(int? length, [bool? isUnicode]) { - if (isUnicode == null) { - return _readString(length, false); - } else { - String result = ''; - if (isUnicode) { - for (int i = 0; i < length!; i++) { - if (i % 2 != 0) { - result += String.fromCharCode(_fontData[currentOffset!]); - } - currentOffset = currentOffset! + 1; - } - } else { - for (int i = 0; i < length!; i++) { - result += String.fromCharCode(_fontData[currentOffset!]); - currentOffset = currentOffset! + 1; - } - } - return result; - } - } - - List _readBytes(int length) { - final List result = List.filled(length, 0, growable: true); - for (int i = 0; i < length; i++) { - result[i] = _fontData[currentOffset!]; - currentOffset = currentOffset! + 1; - } - return result; - } - - List _readUshortArray(int length) { - final List buffer = List.filled(length, 0, growable: true); - for (int i = 0; i < length; i++) { - buffer[i] = _readUInt16(currentOffset!); - } - return buffer; - } - - dynamic _read(List buffer, int index, int count) { - int written = 0; - int read = 0; - do { - for ( - int i = 0; - i < count - written && currentOffset! + i < _fontData.length; - i++ - ) { - buffer[index + i] = _fontData[currentOffset! + i]; - } - read = count - written; - currentOffset = currentOffset! + read; - written += read; - } while (written < count); - return {'buffer': buffer, 'written': written}; - } -} - -class _TtfHeadTable { - /// Modified: International date (8-byte field). - int? modified; - - /// Created: International date (8-byte field). - int? created; - - /// MagicNumber: Set to 0x5F0F3CF5. - int? magicNumber; - - /// CheckSumAdjustment: To compute: set it to 0, sum the entire font as ULONG, - /// then store 0xB1B0AFBA - sum. - int? checkSumAdjustment; - - /// FontRevision: Set by font manufacturer. - double? fontRevision; - - /// Table version number: 0x00010000 for version 1.0. - double? version; - - /// Minimum x for all glyph bounding boxes. - late int xMin; - - /// Minimum y for all glyph bounding boxes. - int? yMin; - - /// Valid range is from 16 to 16384. - int? unitsPerEm; - - /// Maximum y for all glyph bounding boxes. - int? yMax; - - /// Maximum x for all glyph bounding boxes. - late int xMax; - - /// Regular: 0 - /// Bold: 1 - /// Italic: 2 - /// Bold Italic: 3 - /// Bit 0 - bold (if set to 1) - /// Bit 1 - italic (if set to 1) - /// Bits 2-15 - reserved (set to 0) - /// NOTE: - /// Note that macStyle bits must agree with the 'OS/2' table fsSelection bits. - /// The fsSelection bits are used over the macStyle bits in Microsoft Windows. - /// The PANOSE values and 'post' table values are ignored - /// for determining bold or italic fonts. - int? macStyle; - - /// Bit 0 - baseline for font at y=0 - /// Bit 1 - left SideBearing at x=0 - /// Bit 2 - instructions may depend on point size - /// Bit 3 - force ppem to integer values for all private scaler math; - /// may use fractional ppem sizes if this bit is clear - /// Bit 4 - instructions may alter advance width - /// (the advance widths might not scale linearly) - /// Note: All other bits must be zero. - int? flags; - - /// LowestRecPPEM: Smallest readable size in pixels. - int? lowestReadableSize; - - /// FontDirectionHint: - /// 0 Fully mixed directional glyphs - /// 1 Only strongly left to right - /// 2 Like 1 but also contains neutrals - /// -1 Only strongly right to left - /// -2 Like -1 but also contains neutrals. - int? fontDirectionHint; - - /// 0 for short offsets, 1 for long. - int? indexToLocalFormat; - - /// 0 for current format. - int? glyphDataFormat; -} - -class _TtfHorizontalHeaderTable { - /// Version. - double? version; - - /// Typographic ascent. - late int ascender; - - /// Maximum advance width value in HTML table. - int? advanceWidthMax; - - /// Typographic descent. - late int descender; - - /// Number of hMetric entries in HTML table; - /// may be smaller than the total number of glyphs in the font. - late int numberOfHMetrics; - - /// Typographic line gap. - /// Negative LineGap values are treated as DEF_TABLE_CHECKSUM - /// in Windows 3.1, System 6, and System 7. - late int lineGap; - - /// Minimum left SideBearing value in HTML table. - int? minLeftSideBearing; - - /// Minimum right SideBearing value; - /// calculated as Min(aw - lsb - (xMax - xMin)). - int? minRightSideBearing; - - /// Max(lsb + (xMax - xMin)). - int? xMaxExtent; - - /// Used to calculate the slope of the cursor (rise/run); 1 for vertical. - int? caretSlopeRise; - - /// 0 for vertical. - int? caretSlopeRun; - - /// 0 for current format. - int? metricDataFormat; -} - -/// name ttf table. -class _TtfNameTable { - /// Local variable to store Format Selector. - int? formatSelector; - - /// Local variable to store Records Count. - late int recordsCount; - - /// Local variable to store Offset. - late int offset; - - /// Local variable to store Name Records. - late List<_TtfNameRecord> nameRecords; -} - -class _TtfNameRecord { - /// The PlatformID. - int? platformID; - - /// The EncodingID. - int? encodingID; - - /// The PlatformIDLanguageID - int? languageID; - - /// The NameID. - int? nameID; - - /// The Length. - int? length; - - /// The Offset. - late int offset; - - /// The Name. - String? name; -} - -class _TtfOS2Table { - late int version; - - /// The Average Character Width parameter specifies - /// the arithmetic average of the escapement (width) - /// of all of the 26 lowercase letters a through z of the Latin alphabet - /// and the space character. If any of the 26 lowercase letters are not - /// present, this parameter should equal the weighted average of all - /// glyphs in the font. - /// For non-UGL (platform 3, encoding 0) fonts, use the unweighted average. - int? xAvgCharWidth; - - /// Indicates the visual weight (degree of blackness or thickness of strokes) - /// of the characters in the font. - int? usWeightClass; - - /// Indicates a relative change from the normal aspect ratio (width to - /// height ratio) as specified by a font designer for the glyphs in a font. - int? usWidthClass; - - /// Indicates font embedding licensing rights for the font. - /// Embeddable fonts may be stored in a document. - /// When a document with embedded fonts is opened on a system that - /// does not have the font installed (the remote system), - /// the embedded font may be loaded for temporary - /// (and in some cases, permanent) use on that system by an embedding-aware - /// application. - /// Embedding licensing rights are granted by the vendor of the font. - int? fsType; - - /// The recommended horizontal size in font design units - /// for subscripts for this font. - int? ySubscriptXSize; - - /// The recommended vertical size in font design units - /// for subscripts for this font. - late int ySubscriptYSize; - - /// The recommended horizontal offset in font design units - /// for subscripts for this font. - int? ySubscriptXOffset; - - /// The recommended vertical offset in font design units from the baseline - /// for subscripts for this font. - int? ySubscriptYOffset; - - /// The recommended horizontal size in font design units - /// for superscripts for this font. - int? ySuperscriptXSize; - - /// The recommended vertical size in font design units - /// for superscripts for this font. - late int ySuperscriptYSize; - - /// The recommended horizontal offset in font design units - /// for superscripts for this font. - int? ySuperscriptXOffset; - - /// The recommended vertical offset in font design units from the baseline - /// for superscripts for this font. - int? ySuperscriptYOffset; - - /// Width of the strikethrough stroke in font design units. - int? yStrikeoutSize; - - /// The position of the strikethrough stroke relative to the baseline - /// in font design units. - int? yStrikeoutPosition; - - /// This parameter is a classification of font-family design. - int? sFamilyClass; - - /// This 10 byte series of numbers are used to describe the visual - /// characteristics of a given typeface. - /// These characteristics are then used to associate the font with - /// other fonts of similar appearance having different names. - /// The variables for each digit are listed below. - /// The specifications for each variable can be obtained in the specification - /// PANOSE v2.0 Numerical Evaluation from Microsoft or Elseware Corporation. - List? panose; - - int? ulUnicodeRange1; - int? ulUnicodeRange2; - int? ulUnicodeRange3; - int? ulUnicodeRange4; - - /// The four character identifier for the vendor of the given type face. - List? vendorIdentifier; - - /// Information concerning the nature of the font patterns. - int? fsSelection; - - /// The minimum Unicode index (character code) in this font, - /// according to the cmap subtable for platform ID 3 and encoding ID 0 or 1. - /// For most fonts supporting Win-ANSI or other character sets, - /// this value would be 0x0020. - int? usFirstCharIndex; - - /// usLastCharIndex: The maximum Unicode index (character code) in this font, - /// according to the cmap subtable for platform ID 3 and encoding ID 0 or 1. - /// This value depends on which character sets the font supports. - int? usLastCharIndex; - - /// The typographic ascender for this font. - /// Remember that this is not the same as the Ascender value - /// in the 'hhea' table, which Apple defines in a far different manner. - /// DEF_TABLE_OFFSET good source for usTypoAscender is the Ascender value - /// from an AFM file. - late int sTypoAscender; - - /// The typographic descender for this font. - /// Remember that this is not the same as the Descender value - /// in the 'hhea' table, - /// which Apple defines in a far different manner. - /// DEF_TABLE_OFFSET good source for usTypoDescender is the Descender value - /// from an AFM file. - late int sTypoDescender; - - /// The typographic line gap for this font. - /// Remember that this is not the same as the LineGap value in the - /// 'hhea' table, which Apple defines in a far different manner. - late int sTypoLineGap; - - /// The ascender metric for Windows. - /// This too is distinct from Apple's Ascender value and from the - /// usTypoAscender values, usWinAscent is computed as the yMax for all - /// characters in the Windows ANSI character set. - /// usTypoAscent is used to compute the Windows font height and - /// default line spacing. - /// For platform 3 encoding 0 fonts, it is the same as yMax. - int? usWinAscent; - - /// The descender metric for Windows. - /// This too is distinct from Apple's Descender value and - /// from the usTypoDescender values. - /// usWinDescent is computed as the -yMin for all characters - /// in the Windows ANSI character set. - /// usTypoAscent is used to compute the Windows font height and - /// default line spacing. - /// For platform 3 encoding 0 fonts, it is the same as -yMin. - int? usWinDescent; - - /// This field is used to specify the code pages encompassed - /// by the font file in the 'cmap' subtable for platform 3, - /// encoding ID 1 (Microsoft platform). - /// If the font file is encoding ID 0, then the Symbol Character Set bit - /// should be set. - /// If the bit is set (1) then the code page is considered functional. - /// If the bit is clear (0) then the code page is not considered functional. - /// Each of the bits is treated as an independent flag and the bits can be - /// set in any combination. - /// The determination of "functional" is left up to the font designer, - /// although character set selection should attempt to be functional - /// by code pages if at all possible. - int? ulCodePageRange1; - - /// This field is used to specify the code pages encompassed - /// by the font file in the 'cmap' subtable for platform 3, - /// encoding ID 1 (Microsoft platform). - /// If the font file is encoding ID 0, then the Symbol Character Set - /// bit should be set. - /// If the bit is set (1) then the code page is considered functional. - /// If the bit is clear (0) then the code page is not considered functional. - /// Each of the bits is treated as an independent flag and the bits can be - /// set in any combination. - /// The determination of "functional" is left up to the font designer, - /// although character set selection should attempt to be functional by - /// code pages if at all possible. - int? ulCodePageRange2; - - int? sxHeight; - int? sCapHeight; - int? usDefaultChar; - int? usBreakChar; - int? usMaxContext; -} - -class _TtfTableInfo { - /// Gets or sets ofset from beginning of TrueType font file. - int? offset; - - /// Gets or sets length of this table. - int? length; - - /// Gets or sets table checksum. - int? checksum; - - /// Gets a value indicating whether this [_TtfTableInfo] is empty. - /// true if empty, otherwise false - bool get empty => - offset == length && - length == checksum && - (checksum == 0 || checksum == null); -} - -class _TtfPostTable { - double? formatType; - double? italicAngle; - int? underlinePosition; - int? underlineThickness; - int? isFixedPitch; - int? minType42; - int? maxType42; - int? minType1; - int? maxType1; -} - -class _TtfCmapSubTable { - int? platformID; - int? encodingID; - late int offset; -} - -class _TtfCmapTable { - int? version; - late int tablesCount; -} - -class _TtfLongHorMetric { - late int advanceWidth; - int? lsb; -} - -class _TtfAppleCmapSubTable { - int? format; - int? length; - int? version; -} - -/// internal class -class TtfGlyphInfo { - /// Holds glyph index. - int index = 0; - - /// Holds character's width. - int width = 0; - - /// Code of the char symbol. - int charCode = 0; - - /// Gets a value indicating whether [TtfGlyphInfo] is empty. - bool get empty { - return index == width && width == charCode && charCode == 0; - } -} - -class _TtfMicrosoftCmapSubTable { - int? format; - late int length; - int? version; - late int segCountX2; - int? searchRange; - int? entrySelector; - int? rangeShift; - late List endCount; - int? reservedPad; - late List startCount; - late List idDelta; - late List idRangeOffset; - late List glyphID; -} - -class _TtfTrimmedCmapSubTable { - int? format; - int? length; - int? version; - late int firstCode; - late int entryCount; -} - -class _TtfGlyphHeader { - late int numberOfContours; - int? xMin; - int? yMin; - int? xMax; - int? yMax; -} - -/// Enumerator that implements CMAP formats. -enum _TtfCmapFormat { - /// This is the Apple standard character to glyph index mapping table. - apple, - - /// This is the Microsoft standard character to glyph index mapping table. - microsoft, - - /// Format 6: Trimmed table mapping. - trimmed, - - /// This is the Microsoft standard character-to-glyph-index mapping table for fonts supporting Unicode supplementary-plane characters (U+10000 to U+10FFFF). - microsoftExt, -} - -/// Enumerator that implements CMAP encodings. -enum _TtfCmapEncoding { - /// Unknown encoding. - unknown, - - /// When building a symbol font for Windows. - symbol, - - /// When building a Unicode font for Windows. - unicode, - - /// For font that will be used on a Macintosh. - macintosh, - - /// When building a Unicode font for Windows (plane characters). - unicodeUCS4, -} - -/// Ttf platform ID. -enum _TtfPlatformID { - /// Apple platform. - appleUnicode, - - /// Macintosh platform. - macintosh, - - /// Iso platform. - iso, - - /// Microsoft platform. - microsoft, -} - -/// Microsoft encoding ID. -enum _TtfMicrosoftEncodingID { - /// Undefined encoding. - undefined, - - /// Unicode encoding. - unicode, - - /// Unicode UCS4. - unicodeUCS4, -} - -/// Macintosh encoding ID. -enum _TtfMacintoshEncodingID { - /// Roman encoding. - roman, - - /// Japanese encoding. - japanese, - - /// Chinese encoding. - chinese, -} +import 'dart:math'; + +import '../../drawing/drawing.dart'; +import '../../io/big_endian_writer.dart'; +import 'ttf_metrics.dart'; + +/// internal class +class TtfReader { + /// internal constructor + TtfReader(List fontData) { + _fontData = fontData; + _initialize(); + } + + //Constants + final int _int32Size = 4; + final List _tableNames = [ + 'cvt ', + 'fpgm', + 'glyf', + 'head', + 'hhea', + 'hmtx', + 'loca', + 'maxp', + 'prep', + ]; + final List _entrySelectors = [ + 0, + 0, + 1, + 1, + 2, + 2, + 2, + 2, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + 4, + 4, + ]; + + //Fields + late List _fontData; + + /// internal field + TtfMetrics? metrics; + + /// internal field + int? currentOffset; + late bool _isMacTtf; + late bool _isTtcFont; + Map? _tableDirectory; + Map? _macintoshDirectory; + Map? _microsoftDirectory; + Map? _macintoshGlyphInfoCollection; + Map? _microsoftGlyphInfoCollection; + Map? _unicodeUCS4GlyphCollection; + int? _lowestPosition; + late bool _isLocaShort; + late List _width; + int _surrogateHigh = 0; + int? _maxMacIndex; + String _surrogateHighChar = ''; + + /// internal field + List? internalUsedChars; + + /// internal field + List get usedChars { + internalUsedChars ??= []; + return internalUsedChars!; + } + + //Properties + Map? get _macintosh { + _macintoshDirectory ??= {}; + return _macintoshDirectory; + } + + Map? get _microsoft { + _microsoftDirectory ??= {}; + return _microsoftDirectory; + } + + Map? get _macintoshGlyphs { + _macintoshGlyphInfoCollection ??= {}; + return _macintoshGlyphInfoCollection; + } + + Map? get _microsoftGlyphs { + _microsoftGlyphInfoCollection ??= {}; + return _microsoftGlyphInfoCollection; + } + + Map? get _unicodeUcs4Glyph { + _unicodeUCS4GlyphCollection ??= {}; + return _unicodeUCS4GlyphCollection; + } + + //Implementation + void _initialize() { + _isMacTtf = false; + _isTtcFont = false; + metrics = TtfMetrics(); + _readFontDictionary(); + final _TtfNameTable nameTable = _readNameTable(); + final _TtfHeadTable headTable = _readHeadTable(); + _initializeFontName(nameTable); + metrics!.macStyle = headTable.macStyle; + } + + void _readFontDictionary() { + currentOffset = 0; + _checkPreambula(); + final int numTables = _readInt16(currentOffset!); + //searchRange + _readInt16(currentOffset!); + //entrySelector + _readInt16(currentOffset!); + //rangeShift + _readInt16(currentOffset!); + _tableDirectory ??= {}; + for (int i = 0; i < numTables; ++i) { + final _TtfTableInfo table = _TtfTableInfo(); + final String tableKey = _readString(_int32Size); + table.checksum = _readInt32(currentOffset!); + table.offset = _readInt32(currentOffset!); + table.length = _readInt32(currentOffset!); + _tableDirectory![tableKey] = table; + } + _lowestPosition = currentOffset; + if (!_isTtcFont) { + _fixOffsets(); + } + } + + void _checkPreambula() { + final int version = _readInt32(currentOffset!); + _isMacTtf = version == 0x74727565; + if (version != 0x10000 && !_isMacTtf && version != 0x4f54544f) { + _isTtcFont = true; + currentOffset = 0; + if (_readString(4) != 'ttcf') { + throw UnsupportedError('Can not read TTF font data'); + } + currentOffset = currentOffset! + 4; + if (_readInt32(currentOffset!) < 0) { + throw UnsupportedError('Can not read TTF font data'); + } + //Offset for version + currentOffset = _readInt32(currentOffset!); + //Version + _readInt32(currentOffset!); + } + } + + void _fixOffsets() { + int minOffset = pow(2, 53) as int; + // Search for a smallest offset and compare it + // with the lowest position found. + final List keys = _tableDirectory!.keys.toList(); + for (int i = 0; i < keys.length; i++) { + final int offset = _tableDirectory![keys[i]]!.offset!; + if (minOffset > offset) { + minOffset = offset; + if (minOffset <= _lowestPosition!) { + break; + } + } + } + final int shift = minOffset - _lowestPosition!; + if (shift != 0) { + final Map table = {}; + for (int i = 0; i < keys.length; i++) { + final _TtfTableInfo value = _tableDirectory![keys[i]]!; + value.offset = value.offset! - shift; + table[keys[i]] = value; + } + _tableDirectory = table; + } + } + + _TtfNameTable _readNameTable() { + final _TtfTableInfo tableInfo = _getTable('name')!; + currentOffset = tableInfo.offset; + final _TtfNameTable table = _TtfNameTable(); + table.formatSelector = _readUInt16(currentOffset!); + table.recordsCount = _readUInt16(currentOffset!); + table.offset = _readUInt16(currentOffset!); + table.nameRecords = <_TtfNameRecord>[]; + const int recordSize = 12; + int? position = currentOffset; + for (int i = 0; i < table.recordsCount; i++) { + currentOffset = position; + final _TtfNameRecord record = _TtfNameRecord(); + record.platformID = _readUInt16(currentOffset!); + record.encodingID = _readUInt16(currentOffset!); + record.languageID = _readUInt16(currentOffset!); + record.nameID = _readUInt16(currentOffset!); + record.length = _readUInt16(currentOffset!); + record.offset = _readUInt16(currentOffset!); + currentOffset = tableInfo.offset! + table.offset + record.offset; + final bool isUnicode = record.platformID == 0 || record.platformID == 3; + record.name = _readString(record.length, isUnicode); + table.nameRecords.add(record); + position = position! + recordSize; + } + return table; + } + + _TtfHeadTable _readHeadTable() { + final _TtfTableInfo tableInfo = _getTable('head')!; + currentOffset = tableInfo.offset; + final _TtfHeadTable table = _TtfHeadTable(); + table.version = _readFixed(currentOffset!); + table.fontRevision = _readFixed(currentOffset!); + table.checkSumAdjustment = _readUInt32(currentOffset!); + table.magicNumber = _readUInt32(currentOffset!); + table.flags = _readUInt16(currentOffset!); + table.unitsPerEm = _readUInt16(currentOffset!); + table.created = _readInt64(currentOffset!); + table.modified = _readInt64(currentOffset!); + table.xMin = _readInt16(currentOffset!); + table.yMin = _readInt16(currentOffset!); + table.xMax = _readInt16(currentOffset!); + table.yMax = _readInt16(currentOffset!); + table.macStyle = _readUInt16(currentOffset!); + table.lowestReadableSize = _readUInt16(currentOffset!); + table.fontDirectionHint = _readInt16(currentOffset!); + table.indexToLocalFormat = _readInt16(currentOffset!); + table.glyphDataFormat = _readInt16(currentOffset!); + return table; + } + + _TtfHorizontalHeaderTable _readHorizontalHeaderTable() { + final _TtfTableInfo tableInfo = _getTable('hhea')!; + currentOffset = tableInfo.offset; + final _TtfHorizontalHeaderTable table = _TtfHorizontalHeaderTable(); + table.version = _readFixed(currentOffset!); + table.ascender = _readInt16(currentOffset!); + table.descender = _readInt16(currentOffset!); + table.lineGap = _readInt16(currentOffset!); + table.advanceWidthMax = _readUInt16(currentOffset!); + table.minLeftSideBearing = _readInt16(currentOffset!); + table.minRightSideBearing = _readInt16(currentOffset!); + table.xMaxExtent = _readInt16(currentOffset!); + table.caretSlopeRise = _readInt16(currentOffset!); + table.caretSlopeRun = _readInt16(currentOffset!); + currentOffset = currentOffset! + 10; + table.metricDataFormat = _readInt16(currentOffset!); + table.numberOfHMetrics = _readUInt16(currentOffset!); + return table; + } + + _TtfOS2Table _readOS2Table() { + final _TtfTableInfo tableInfo = _getTable('OS/2')!; + currentOffset = tableInfo.offset; + final _TtfOS2Table table = _TtfOS2Table(); + table.version = _readUInt16(currentOffset!); + table.xAvgCharWidth = _readInt16(currentOffset!); + table.usWeightClass = _readUInt16(currentOffset!); + table.usWidthClass = _readUInt16(currentOffset!); + table.fsType = _readInt16(currentOffset!); + table.ySubscriptXSize = _readInt16(currentOffset!); + table.ySubscriptYSize = _readInt16(currentOffset!); + table.ySubscriptXOffset = _readInt16(currentOffset!); + table.ySubscriptYOffset = _readInt16(currentOffset!); + table.ySuperscriptXSize = _readInt16(currentOffset!); + table.ySuperscriptYSize = _readInt16(currentOffset!); + table.ySuperscriptXOffset = _readInt16(currentOffset!); + table.ySuperscriptYOffset = _readInt16(currentOffset!); + table.yStrikeoutSize = _readInt16(currentOffset!); + table.yStrikeoutPosition = _readInt16(currentOffset!); + table.sFamilyClass = _readInt16(currentOffset!); + table.panose = _readBytes(10); + table.ulUnicodeRange1 = _readUInt32(currentOffset!); + table.ulUnicodeRange2 = _readUInt32(currentOffset!); + table.ulUnicodeRange3 = _readUInt32(currentOffset!); + table.ulUnicodeRange4 = _readUInt32(currentOffset!); + table.vendorIdentifier = _readBytes(4); + table.fsSelection = _readUInt16(currentOffset!); + table.usFirstCharIndex = _readUInt16(currentOffset!); + table.usLastCharIndex = _readUInt16(currentOffset!); + table.sTypoAscender = _readInt16(currentOffset!); + table.sTypoDescender = _readInt16(currentOffset!); + table.sTypoLineGap = _readInt16(currentOffset!); + table.usWinAscent = _readUInt16(currentOffset!); + table.usWinDescent = _readUInt16(currentOffset!); + table.ulCodePageRange1 = _readUInt32(currentOffset!); + table.ulCodePageRange2 = _readUInt32(currentOffset!); + if (table.version > 1) { + table.sxHeight = _readInt16(currentOffset!); + table.sCapHeight = _readInt16(currentOffset!); + table.usDefaultChar = _readUInt16(currentOffset!); + table.usBreakChar = _readUInt16(currentOffset!); + table.usMaxContext = _readUInt16(currentOffset!); + } else { + table.sxHeight = 0; + table.sCapHeight = 0; + table.usDefaultChar = 0; + table.usBreakChar = 0; + table.usMaxContext = 0; + } + return table; + } + + _TtfPostTable _readPostTable() { + final _TtfTableInfo tableInfo = _getTable('post')!; + currentOffset = tableInfo.offset; + final _TtfPostTable table = _TtfPostTable(); + table.formatType = _readFixed(currentOffset!); + table.italicAngle = _readFixed(currentOffset!); + table.underlinePosition = _readInt16(currentOffset!); + table.underlineThickness = _readInt16(currentOffset!); + table.isFixedPitch = _readUInt32(currentOffset!); + table.minType42 = _readUInt32(currentOffset!); + table.maxType42 = _readUInt32(currentOffset!); + table.minType1 = _readUInt32(currentOffset!); + table.maxType1 = _readUInt32(currentOffset!); + return table; + } + + List _readWidthTable(int glyphCount, int? unitsPerEm) { + final _TtfTableInfo tableInfo = _getTable('hmtx')!; + currentOffset = tableInfo.offset; + final List width = List.filled(glyphCount, 0, growable: true); + for (int i = 0; i < glyphCount; i++) { + final _TtfLongHorMetric glyph = _TtfLongHorMetric(); + glyph.advanceWidth = _readUInt16(currentOffset!); + glyph.lsb = _readInt16(currentOffset!); + final double glyphWidth = glyph.advanceWidth * 1000 / unitsPerEm!; + width[i] = glyphWidth.floor(); + } + return width; + } + + void _initializeMetrics( + _TtfNameTable nameTable, + _TtfHeadTable headTable, + _TtfHorizontalHeaderTable horizontalHeadTable, + _TtfOS2Table os2Table, + _TtfPostTable postTable, + List<_TtfCmapSubTable> cmapTables, + ) { + _initializeFontName(nameTable); + bool bSymbol = false; + for (int i = 0; i < cmapTables.length; i++) { + final _TtfCmapSubTable subTable = cmapTables[i]; + final _TtfCmapEncoding encoding = _getCmapEncoding( + subTable.platformID, + subTable.encodingID, + ); + if (encoding == _TtfCmapEncoding.symbol) { + bSymbol = true; + break; + } + } + metrics!.isSymbol = bSymbol; + metrics!.macStyle = headTable.macStyle; + metrics!.isFixedPitch = postTable.isFixedPitch != 0; + metrics!.italicAngle = postTable.italicAngle; + final double factor = 1000 / headTable.unitsPerEm!; + metrics!.winAscent = os2Table.sTypoAscender * factor; + metrics!.macAscent = horizontalHeadTable.ascender * factor; + metrics!.capHeight = + (os2Table.sCapHeight != 0) + ? os2Table.sCapHeight!.toDouble() + : 0.7 * headTable.unitsPerEm! * factor; + metrics!.winDescent = os2Table.sTypoDescender * factor; + metrics!.macDescent = horizontalHeadTable.descender * factor; + metrics!.leading = + (os2Table.sTypoAscender - + os2Table.sTypoDescender + + os2Table.sTypoLineGap) * + factor; + metrics!.lineGap = (horizontalHeadTable.lineGap * factor).ceil(); + final double left = headTable.xMin * factor; + final double top = (metrics!.macAscent + metrics!.lineGap!).ceilToDouble(); + final double right = headTable.xMax * factor; + final double bottom = metrics!.macDescent; + metrics!.fontBox = PdfRectangle(left, top, right - left, bottom - top); + metrics!.stemV = 80; + metrics!.widthTable = _updateWidth(); + metrics!.contains = _tableDirectory!.containsKey('CFF'); + metrics!.subscriptSizeFactor = + headTable.unitsPerEm! / os2Table.ySubscriptYSize; + metrics!.superscriptSizeFactor = + headTable.unitsPerEm! / os2Table.ySuperscriptYSize; + } + + List<_TtfCmapSubTable> _readCmapTable() { + final _TtfTableInfo tableInfo = _getTable('cmap')!; + currentOffset = tableInfo.offset; + final _TtfCmapTable table = _TtfCmapTable(); + table.version = _readUInt16(currentOffset!); + table.tablesCount = _readUInt16(currentOffset!); + int? position = currentOffset; + final List<_TtfCmapSubTable> subTables = <_TtfCmapSubTable>[]; + for (int i = 0; i < table.tablesCount; i++) { + currentOffset = position; + final _TtfCmapSubTable subTable = _TtfCmapSubTable(); + subTable.platformID = _readUInt16(currentOffset!); + subTable.encodingID = _readUInt16(currentOffset!); + subTable.offset = _readUInt32(currentOffset!); + position = currentOffset; + _readCmapSubTable(subTable); + subTables.add(subTable); + } + return subTables; + } + + void _readCmapSubTable(_TtfCmapSubTable subTable) { + final _TtfTableInfo tableInfo = _getTable('cmap')!; + currentOffset = tableInfo.offset! + subTable.offset; + final _TtfCmapFormat format = _getCmapFormat(_readUInt16(currentOffset!)); + final _TtfCmapEncoding encoding = _getCmapEncoding( + subTable.platformID, + subTable.encodingID, + ); + if (encoding != _TtfCmapEncoding.unknown) { + switch (format) { + case _TtfCmapFormat.apple: + _readAppleCmapTable(subTable, encoding); + break; + case _TtfCmapFormat.microsoft: + _readMicrosoftCmapTable(subTable, encoding); + break; + case _TtfCmapFormat.trimmed: + _readTrimmedCmapTable(subTable, encoding); + break; + case _TtfCmapFormat.microsoftExt: + _readUCS4CmapTable(subTable, encoding); + break; + } + } + } + + void _readUCS4CmapTable( + _TtfCmapSubTable subTable, + _TtfCmapEncoding encoding, + ) { + final _TtfTableInfo tableInfo = _getTable('cmap')!; + currentOffset = tableInfo.offset! + subTable.offset + 12; + final int count = _readInt32(currentOffset!); + for (int i = 0; i < count; ++i) { + final int start = _readInt32(currentOffset!); + final int end = _readInt32(currentOffset!); + int glyphID = _readInt32(currentOffset!); + for (int j = start; j <= end; j++) { + final TtfGlyphInfo glyphInfo = TtfGlyphInfo(); + glyphInfo.charCode = j; + glyphInfo.width = _getWidth(glyphID); + glyphInfo.index = glyphID; + _addReverseGlyph(glyphInfo, encoding); + glyphID++; + } + } + } + + void _readAppleCmapTable( + _TtfCmapSubTable subTable, + _TtfCmapEncoding encoding, + ) { + final _TtfTableInfo tableInfo = _getTable('cmap')!; + currentOffset = tableInfo.offset! + subTable.offset; + final _TtfAppleCmapSubTable table = _TtfAppleCmapSubTable(); + table.format = _readUInt16(currentOffset!); + table.length = _readUInt16(currentOffset!); + table.version = _readUInt16(currentOffset!); + _maxMacIndex ??= 0; + for (int i = 0; i < 256; ++i) { + final TtfGlyphInfo glyphInfo = TtfGlyphInfo(); + glyphInfo.index = _fontData[currentOffset!]; + currentOffset = currentOffset! + 1; + glyphInfo.width = _getWidth(glyphInfo.index); + glyphInfo.charCode = i; + _macintosh![i] = glyphInfo; + _addGlyph(glyphInfo, encoding); + _maxMacIndex = i >= _maxMacIndex! ? i : _maxMacIndex; + } + } + + void _readMicrosoftCmapTable( + _TtfCmapSubTable subTable, + _TtfCmapEncoding encoding, + ) { + final _TtfTableInfo tableInfo = _getTable('cmap')!; + currentOffset = tableInfo.offset! + subTable.offset; + final Map? collection = + encoding == _TtfCmapEncoding.unicode ? _microsoft : _macintosh; + final _TtfMicrosoftCmapSubTable table = _TtfMicrosoftCmapSubTable(); + table.format = _readUInt16(currentOffset!); + table.length = _readUInt16(currentOffset!); + table.version = _readUInt16(currentOffset!); + table.segCountX2 = _readUInt16(currentOffset!); + table.searchRange = _readUInt16(currentOffset!); + table.entrySelector = _readUInt16(currentOffset!); + table.rangeShift = _readUInt16(currentOffset!); + final int segCount = table.segCountX2 ~/ 2; + table.endCount = _readUshortArray(segCount); + table.reservedPad = _readUInt16(currentOffset!); + table.startCount = _readUshortArray(segCount); + table.idDelta = _readUshortArray(segCount); + table.idRangeOffset = _readUshortArray(segCount); + final int length = ((table.length / 2 - 8) - (segCount * 4)).toInt(); + table.glyphID = _readUshortArray(length); + // Process glyphIdArray array. + int codeOffset = 0; + int index = 0; + for (int j = 0; j < segCount; j++) { + for ( + int k = table.startCount[j]; + k <= table.endCount[j] && k != 65535; + k++ + ) { + if (table.idRangeOffset[j] == 0) { + codeOffset = (k + table.idDelta[j]) & 65535; + } else { + index = + (j + + table.idRangeOffset[j] / 2 - + segCount + + k - + table.startCount[j]) + .toInt(); + if (index >= table.glyphID.length) { + continue; + } + codeOffset = (table.glyphID[index] + table.idDelta[j]) & 65535; + } + final TtfGlyphInfo glyph = TtfGlyphInfo(); + glyph.index = codeOffset; + glyph.width = _getWidth(glyph.index); + final int id = + (encoding == _TtfCmapEncoding.symbol) + ? ((k & 0xff00) == 0xf000 ? k & 0xff : k) + : k; + glyph.charCode = id; + collection![id] = glyph; + _addGlyph(glyph, encoding); + } + } + } + + void _readTrimmedCmapTable( + _TtfCmapSubTable subTable, + _TtfCmapEncoding encoding, + ) { + final _TtfTableInfo tableInfo = _getTable('cmap')!; + currentOffset = tableInfo.offset! + subTable.offset; + final _TtfTrimmedCmapSubTable table = _TtfTrimmedCmapSubTable(); + table.format = _readUInt16(currentOffset!); + table.length = _readUInt16(currentOffset!); + table.version = _readUInt16(currentOffset!); + table.firstCode = _readUInt16(currentOffset!); + table.entryCount = _readUInt16(currentOffset!); + _maxMacIndex ??= 0; + for (int i = 0; i < table.entryCount; ++i) { + final TtfGlyphInfo glyphInfo = TtfGlyphInfo(); + glyphInfo.index = _readUInt16(currentOffset!); + glyphInfo.width = _getWidth(glyphInfo.index); + glyphInfo.charCode = i + table.firstCode; + _macintosh![i] = glyphInfo; + _addGlyph(glyphInfo, encoding); + _maxMacIndex = i >= _maxMacIndex! ? i : _maxMacIndex; + } + } + + _TtfTableInfo? _getTable(String name) { + _TtfTableInfo? table = _TtfTableInfo(); + if (_tableDirectory!.containsKey(name)) { + table = _tableDirectory![name]; + } + return table; + } + + int _getWidth(int glyphCode) { + glyphCode = (glyphCode < _width.length) ? glyphCode : _width.length - 1; + return _width[glyphCode]; + } + + List _updateWidth() { + const int count = 256; + if (metrics!.isSymbol) { + final List bytes = List.filled(count, 0, growable: true); + for (int i = 0; i < count; i++) { + final TtfGlyphInfo glyphInfo = getGlyph(char: String.fromCharCode(i))!; + bytes[i] = (glyphInfo.empty) ? 0 : glyphInfo.width; + } + return bytes; + } else { + final List bytes = List.filled(count, 0, growable: true); + final List byteToProcess = List.filled(1, 0); + final String space = String.fromCharCode(32); + for (int i = 0; i < count; i++) { + byteToProcess[0] = i; + String text = ''; + for (int index = 0; index < byteToProcess.length; index++) { + text += String.fromCharCode(byteToProcess[index + 0]); + } + final String ch = text.isNotEmpty ? text[0] : '?'; + TtfGlyphInfo glyphInfo = getGlyph(char: ch)!; + if (!glyphInfo.empty) { + bytes[i] = glyphInfo.width; + } else { + glyphInfo = getGlyph(char: space)!; + bytes[i] = (glyphInfo.empty) ? 0 : glyphInfo.width; + } + } + return bytes; + } + } + + /// internal method + double getCharWidth(String code) { + TtfGlyphInfo? glyphInfo = getGlyph(char: code); + glyphInfo = + (glyphInfo != null && !glyphInfo.empty) + ? glyphInfo + : _getDefaultGlyph(); + return (!glyphInfo!.empty) ? glyphInfo.width.toDouble() : 0; + } + + /// internal method + TtfGlyphInfo? getGlyph({ + int? charCode, + String? char, + bool? isSetSymbol = false, + }) { + if (charCode != null) { + TtfGlyphInfo? glyphInfo; + if (!metrics!.isSymbol && _microsoftGlyphs != null) { + if (_microsoftGlyphs!.containsKey(charCode)) { + glyphInfo = _microsoftGlyphs![charCode]; + } + } else if (metrics!.isSymbol && _macintoshGlyphs != null) { + if (_macintoshGlyphs!.containsKey(charCode)) { + glyphInfo = _macintoshGlyphs![charCode]; + } + } + if (glyphInfo == null && + _unicodeUCS4GlyphCollection != null && + _unicodeUCS4GlyphCollection!.containsKey(charCode)) { + glyphInfo = _unicodeUCS4GlyphCollection![charCode]; + } + return glyphInfo ?? _getDefaultGlyph(); + } else if (char != null) { + TtfGlyphInfo? glyphInfo; + int code = char.codeUnitAt(0); + if (!metrics!.isSymbol && _microsoft != null) { + if (_microsoft!.containsKey(code)) { + glyphInfo = _microsoft![code]; + } else if (char != ' ') { + if (_unicodeUCS4GlyphCollection != null && _isSurrogate(code)) { + TtfGlyphInfo newGlyph = TtfGlyphInfo(); + if (_isHighSurrogate(code)) { + _surrogateHighChar = char; + _surrogateHigh = code; + newGlyph.width = 0; + } + if (_isLowSurrogate(code)) { + if (_isSurrogatePair(_surrogateHigh, code)) { + code = + (((_surrogateHigh >> 6) & ((1 << 5) - 1)) + 1) << 16 | + ((_surrogateHigh & ((1 << 6) - 1)) << 10 | + code & ((1 << 10) - 1)); + if (_unicodeUCS4GlyphCollection!.containsKey(code)) { + newGlyph = _unicodeUCS4GlyphCollection![code]!; + if (isSetSymbol!) { + usedChars.add(_surrogateHighChar + char); + } + } + } + } + return newGlyph; + } + } + } else if (metrics!.isSymbol && _macintosh != null || _isMacTtf) { + if (_maxMacIndex != 0) { + code %= _maxMacIndex! + 1; + } else { + code = (code & 0xff00) == 0xf000 ? code & 0xff : code; + } + if (_macintosh!.containsKey(code)) { + glyphInfo = _macintosh![code]; + } + } + if (char == ' ' && glyphInfo == null) { + glyphInfo = TtfGlyphInfo(); + } + return glyphInfo ?? _getDefaultGlyph(); + } + return null; + } + + TtfGlyphInfo? _getDefaultGlyph() { + return getGlyph(char: ' '); + } + + bool _isHighSurrogate(int charCode) { + return charCode >= 55296 && charCode <= 56319; + } + + bool _isLowSurrogate(int charCode) { + return charCode >= 56320 && charCode <= 57343; + } + + bool _isSurrogate(int charCode) { + return charCode >= 55296 && charCode <= 57343; + } + + bool _isSurrogatePair(int highSurrogate, int lowSurrogate) { + return _isHighSurrogate(highSurrogate) && _isLowSurrogate(lowSurrogate); + } + + void _initializeFontName(_TtfNameTable nameTable) { + for (int i = 0; i < nameTable.recordsCount; i++) { + final _TtfNameRecord record = nameTable.nameRecords[i]; + if (record.nameID == 1) { + //font family + metrics!.fontFamily = record.name; + } else if (record.nameID == 6) { + //post script name + metrics!.postScriptName = record.name; + } + if (metrics!.fontFamily != null && metrics!.postScriptName != null) { + break; + } + } + } + + /// internal method + void createInternals() { + metrics = TtfMetrics(); + final _TtfNameTable nameTable = _readNameTable(); + final _TtfHeadTable headTable = _readHeadTable(); + _isLocaShort = headTable.indexToLocalFormat == 0; + final _TtfHorizontalHeaderTable horizontalHeadTable = + _readHorizontalHeaderTable(); + final _TtfOS2Table os2Table = _readOS2Table(); + final _TtfPostTable postTable = _readPostTable(); + _width = _readWidthTable( + horizontalHeadTable.numberOfHMetrics, + headTable.unitsPerEm, + ); + final List<_TtfCmapSubTable> subTables = _readCmapTable(); + _initializeMetrics( + nameTable, + headTable, + horizontalHeadTable, + os2Table, + postTable, + subTables, + ); + } + + _TtfCmapFormat _getCmapFormat(int format) { + if (format == 4) { + return _TtfCmapFormat.microsoft; + } else if (format == 6) { + return _TtfCmapFormat.trimmed; + } else if (format == 12) { + return _TtfCmapFormat.microsoftExt; + } else { + return _TtfCmapFormat.apple; + } + } + + _TtfPlatformID _getPlatformID(int? platformID) { + switch (platformID) { + case 1: + return _TtfPlatformID.macintosh; + case 2: + return _TtfPlatformID.iso; + case 3: + return _TtfPlatformID.microsoft; + default: + return _TtfPlatformID.appleUnicode; + } + } + + _TtfMicrosoftEncodingID _getMicrosoftEncodingID(int? encodingID) { + switch (encodingID) { + case 1: + return _TtfMicrosoftEncodingID.unicode; + case 10: + return _TtfMicrosoftEncodingID.unicodeUCS4; + default: + return _TtfMicrosoftEncodingID.undefined; + } + } + + _TtfMacintoshEncodingID _getMacintoshEncodingID(int? encodingID) { + switch (encodingID) { + case 1: + return _TtfMacintoshEncodingID.japanese; + case 2: + return _TtfMacintoshEncodingID.chinese; + default: + return _TtfMacintoshEncodingID.roman; + } + } + + _TtfCmapEncoding _getCmapEncoding(int? platformID, int? encodingID) { + _TtfCmapEncoding format = _TtfCmapEncoding.unknown; + if (_getPlatformID(platformID) == _TtfPlatformID.microsoft && + _getMicrosoftEncodingID(encodingID) == + _TtfMicrosoftEncodingID.undefined) { + format = _TtfCmapEncoding.symbol; + } else if (_getPlatformID(platformID) == _TtfPlatformID.microsoft && + _getMicrosoftEncodingID(encodingID) == + _TtfMicrosoftEncodingID.unicode) { + format = _TtfCmapEncoding.unicode; + } else if (_getPlatformID(platformID) == _TtfPlatformID.macintosh && + _getMacintoshEncodingID(encodingID) == _TtfMacintoshEncodingID.roman) { + format = _TtfCmapEncoding.macintosh; + } else if (_getPlatformID(platformID) == _TtfPlatformID.microsoft && + _getMicrosoftEncodingID(encodingID) == + _TtfMicrosoftEncodingID.unicodeUCS4) { + format = _TtfCmapEncoding.unicodeUCS4; + } + return format; + } + + void _addReverseGlyph(TtfGlyphInfo glyph, _TtfCmapEncoding encoding) { + Map? collection; + switch (encoding) { + case _TtfCmapEncoding.unicode: + collection = _microsoftGlyphs; + break; + case _TtfCmapEncoding.macintosh: + case _TtfCmapEncoding.symbol: + collection = _macintoshGlyphs; + break; + case _TtfCmapEncoding.unicodeUCS4: + collection = _unicodeUcs4Glyph; + break; + case _TtfCmapEncoding.unknown: + break; + } + collection![glyph.charCode] = glyph; + } + + void _addGlyph(TtfGlyphInfo glyph, _TtfCmapEncoding encoding) { + Map? collection; + switch (encoding) { + case _TtfCmapEncoding.unicode: + collection = _microsoftGlyphs; + break; + case _TtfCmapEncoding.macintosh: + case _TtfCmapEncoding.symbol: + collection = _macintoshGlyphs; + break; + case _TtfCmapEncoding.unknown: + case _TtfCmapEncoding.unicodeUCS4: + break; + } + collection![glyph.index] = glyph; + } + + /// internal method + Map getGlyphChars(List chars) { + final Map dictionary = {}; + for (int i = 0; i < chars.length; i++) { + final String ch = chars[i]; + final TtfGlyphInfo glyph = getGlyph(char: ch)!; + if (!glyph.empty) { + dictionary[glyph.index] = ch.codeUnitAt(0); + } + } + return dictionary; + } + + /// internal method + List? readFontProgram(List chars) { + final Map glyphChars = getGlyphChars(chars); + final List offsets = _readLocaTable(_isLocaShort); + _updateGlyphChars(glyphChars, offsets); + final Map returnedValue = + _generateGlyphTable(glyphChars, offsets, null, null) + as Map; + final int? glyphTableSize = returnedValue['glyphTableSize'] as int?; + final List newLocaTable = returnedValue['newLocaTable'] as List; + final List newGlyphTable = returnedValue['newGlyphTable'] as List; + final Map result = + _updateLocaTable(newLocaTable, _isLocaShort, null) + as Map; + final int? newLocaSize = result['newLocaSize'] as int?; + final List newLocaUpdated = result['newLocaUpdated'] as List; + final List? fontProgram = _getFontProgram( + newLocaUpdated, + newGlyphTable, + glyphTableSize, + newLocaSize, + ); + return fontProgram; + } + + List _readLocaTable(bool isShort) { + final _TtfTableInfo tableInfo = _getTable('loca')!; + currentOffset = tableInfo.offset; + List buffer; + if (isShort) { + final int len = tableInfo.length! ~/ 2; + buffer = List.filled(len, 0, growable: true); + for (int i = 0; i < len; i++) { + buffer[i] = _readUInt16(currentOffset!) * 2; + } + } else { + final int len = tableInfo.length! ~/ 4; + buffer = List.filled(len, 0, growable: true); + for (int i = 0; i < len; i++) { + buffer[i] = _readUInt32(currentOffset!); + } + } + return buffer; + } + + dynamic _updateLocaTable( + List newLocaTable, + bool isLocaShort, + List? newLocaTableOut, + ) { + final int size = + isLocaShort ? newLocaTable.length * 2 : newLocaTable.length * 4; + final int count = _align(size); + final BigEndianWriter writer = BigEndianWriter(count); + for (int i = 0; i < newLocaTable.length; i++) { + int value = newLocaTable[i]; + if (isLocaShort) { + value ~/= 2; + writer.writeShort(value); + } else { + writer.writeInt(value); + } + } + return { + 'newLocaUpdated': writer.data, + 'newLocaSize': size, + }; + } + + void _updateGlyphChars(Map glyphChars, List offsets) { + if (!glyphChars.containsKey(0)) { + glyphChars[0] = 0; + } + final List glyphCharKeys = glyphChars.keys.toList(); + final Map clone = {}; + for (int i = 0; i < glyphCharKeys.length; i++) { + clone[glyphCharKeys[i]] = glyphChars[glyphCharKeys[i]]!; + } + for (int i = 0; i < glyphCharKeys.length; i++) { + _processCompositeGlyph(glyphChars, glyphCharKeys[i], offsets); + } + } + + void _processCompositeGlyph( + Map glyphChars, + int glyph, + List offsets, + ) { + if (glyph < offsets.length - 1) { + final int glyphOffset = offsets[glyph]; + if (glyphOffset != offsets[glyph + 1]) { + final _TtfTableInfo tableInfo = _getTable('glyf')!; + currentOffset = tableInfo.offset! + glyphOffset; + final _TtfGlyphHeader glyphHeader = _TtfGlyphHeader(); + glyphHeader.numberOfContours = _readInt16(currentOffset!); + glyphHeader.xMin = _readInt16(currentOffset!); + glyphHeader.yMin = _readInt16(currentOffset!); + glyphHeader.xMax = _readInt16(currentOffset!); + glyphHeader.yMax = _readInt16(currentOffset!); + if (glyphHeader.numberOfContours < 0) { + int skipBytes = 0; + while (true) { + final int flags = _readUInt16(currentOffset!); + final int glyphIndex = _readUInt16(currentOffset!); + if (!glyphChars.containsKey(glyphIndex)) { + glyphChars[glyphIndex] = 0; + } + if ((flags & 0x0020) == 0) { + break; + } + skipBytes = (flags & 0x0001) != 0 ? 4 : 2; + if (flags & 0x0008 != 0) { + skipBytes += 2; + } else if (flags & 0x0040 != 0) { + skipBytes += 4; + } else if (flags & 0x0080 != 0) { + skipBytes += 2 * 4; + } + currentOffset = currentOffset! + skipBytes; + } + } + } + } + } + + dynamic _generateGlyphTable( + Map glyphChars, + List offsets, + List? newLocaTable, + List? newGlyphTable, + ) { + newLocaTable = []; + final List activeGlyphs = glyphChars.keys.toList(); + activeGlyphs.sort((int a, int b) => a - b); + int glyphSize = 0; + for (int i = 0; i < activeGlyphs.length; i++) { + if (offsets.isNotEmpty) { + glyphSize += offsets[activeGlyphs[i] + 1] - offsets[activeGlyphs[i]]; + } + } + final int glyphSizeAligned = _align(glyphSize); + newGlyphTable = []; + for (int i = 0; i < glyphSizeAligned; i++) { + newGlyphTable.add(0); + } + int nextGlyphOffset = 0; + int nextGlyphIndex = 0; + final _TtfTableInfo? table = _getTable('glyf'); + for (int i = 0; i < offsets.length; i++) { + newLocaTable.add(nextGlyphOffset); + if (nextGlyphIndex < activeGlyphs.length && + activeGlyphs[nextGlyphIndex] == i) { + ++nextGlyphIndex; + newLocaTable[i] = nextGlyphOffset; + final int oldGlyphOffset = offsets[i]; + final int oldNextGlyphOffset = offsets[i + 1] - oldGlyphOffset; + if (oldNextGlyphOffset > 0) { + currentOffset = table!.offset! + oldGlyphOffset; + final Map result = + _read(newGlyphTable!, nextGlyphOffset, oldNextGlyphOffset) + as Map; + newGlyphTable = result['buffer'] as List?; + nextGlyphOffset += oldNextGlyphOffset; + } + } + } + return { + 'glyphTableSize': glyphSize, + 'newLocaTable': newLocaTable, + 'newGlyphTable': newGlyphTable, + }; + } + + int _align(int value) { + return (value + 3) & (~3); + } + + List? _getFontProgram( + List newLocaTableOut, + List newGlyphTable, + int? glyphTableSize, + int? locaTableSize, + ) { + final dynamic result = _getFontProgramLength( + newLocaTableOut, + newGlyphTable, + 0, + ); + final int fontProgramLength = result['fontProgramLength'] as int; + final int numTables = result['numTables'] as int; + final BigEndianWriter writer = BigEndianWriter(fontProgramLength); + writer.writeInt(0x10000); + writer.writeShort(numTables); + final int entrySelector = _entrySelectors[numTables]; + writer.writeShort((1 << (entrySelector & 31)) * 16); + writer.writeShort(entrySelector); + writer.writeShort((numTables - (1 << (entrySelector & 31))) * 16); + _writeCheckSums( + writer, + numTables, + newLocaTableOut, + newGlyphTable, + glyphTableSize, + locaTableSize, + ); + _writeGlyphs(writer, newLocaTableOut, newGlyphTable); + return writer.data; + } + + dynamic _getFontProgramLength( + List newLocaTableOut, + List newGlyphTable, + int numTables, + ) { + numTables = 2; + final List tableNames = _tableNames; + int fontProgramLength = 0; + for (int i = 0; i < tableNames.length; i++) { + final String tableName = tableNames[i]; + if (tableName != 'glyf' && tableName != 'loca') { + final _TtfTableInfo table = _getTable(tableName)!; + if (!table.empty) { + ++numTables; + fontProgramLength += _align(table.length!); + } + } + } + fontProgramLength += newLocaTableOut.length; + fontProgramLength += newGlyphTable.length; + final int usedTablesSize = numTables * 16 + (3 * 4); + fontProgramLength += usedTablesSize; + return { + 'fontProgramLength': fontProgramLength, + 'numTables': numTables, + }; + } + + void _writeCheckSums( + BigEndianWriter writer, + int numTables, + List newLocaTableOut, + List newGlyphTable, + int? glyphTableSize, + int? locaTableSize, + ) { + final List tableNames = _tableNames; + int usedTablesSize = numTables * 16 + (3 * 4); + int? nextTableSize = 0; + for (int i = 0; i < tableNames.length; i++) { + final String tableName = tableNames[i]; + final _TtfTableInfo tableInfo = _getTable(tableName)!; + if (tableInfo.empty) { + continue; + } + writer.writeString(tableName); + if (tableName == 'glyf') { + final int checksum = _calculateCheckSum(newGlyphTable); + writer.writeInt(checksum); + nextTableSize = glyphTableSize; + } else if (tableName == 'loca') { + final int checksum = _calculateCheckSum(newLocaTableOut); + writer.writeInt(checksum); + nextTableSize = locaTableSize; + } else { + writer.writeInt(tableInfo.checksum!); + nextTableSize = tableInfo.length; + } + writer.writeUInt(usedTablesSize); + writer.writeUInt(nextTableSize!); + usedTablesSize += _align(nextTableSize); + } + } + + int _calculateCheckSum(List bytes) { + int pos = 0; + int byte1 = 0; + int byte2 = 0; + int byte3 = 0; + int byte4 = 0; + for (int i = 0; i < ((bytes.length + 1) ~/ 4); i++) { + byte4 += bytes[pos++] & 255; + byte3 += bytes[pos++] & 255; + byte2 += bytes[pos++] & 255; + byte1 += bytes[pos++] & 255; + } + return byte1 + (byte2 << 8) + (byte3 << 16) + (byte4 << 24); + } + + void _writeGlyphs( + BigEndianWriter writer, + List newLocaTable, + List newGlyphTable, + ) { + final List tableNames = _tableNames; + for (int i = 0; i < tableNames.length; i++) { + final String tableName = tableNames[i]; + final _TtfTableInfo tableInfo = _getTable(tableName)!; + if (tableInfo.empty) { + continue; + } + if (tableName == 'glyf') { + writer.writeBytes(newGlyphTable); + } else if (tableName == 'loca') { + writer.writeBytes(newLocaTable); + } else { + final int count = _align(tableInfo.length!); + final List buff = List.filled(count, 0, growable: true); + currentOffset = tableInfo.offset; + final dynamic result = _read(buff, 0, tableInfo.length!); + writer.writeBytes(result['buffer']); + } + } + } + + /// internal method + String convertString(String text) { + String glyph = ''; + for (int k = 0; k < text.length; k++) { + final String char = text[k]; + final TtfGlyphInfo glyphInfo = getGlyph(char: char, isSetSymbol: true)!; + if (!glyphInfo.empty) { + glyph += String.fromCharCode(glyphInfo.index); + } + } + return glyph; + } + + int _readInt16(int offset) { + int result = (_fontData[offset] << 8) + _fontData[offset + 1]; + result = (result & (1 << 15) != 0) ? result - 0x10000 : result; + currentOffset = currentOffset! + 2; + return result; + } + + int _readUInt16(int offset) { + final int i1 = _fontData[offset]; + final int i2 = _fontData[offset + 1]; + currentOffset = currentOffset! + 2; + return (i1 << 8) | i2; + } + + int _readInt32(int offset) { + final int i1 = _fontData[offset + 3]; + final int i2 = _fontData[offset + 2]; + final int i3 = _fontData[offset + 1]; + final int i4 = _fontData[offset]; + currentOffset = currentOffset! + 4; + return i1 + (i2 << 8) + (i3 << 16) + (i4 << 24); + } + + int _readUInt32(int offset) { + final int i1 = _fontData[offset + 3]; + final int i2 = _fontData[offset + 2]; + final int i3 = _fontData[offset + 1]; + final int i4 = _fontData[offset]; + currentOffset = currentOffset! + 4; + return i1 | (i2 << 8) | (i3 << 16) | (i4 << 24); + } + + int _readInt64(int offset) { + final int low = _readInt32(offset + 4); + int n = _readInt32(offset) * 4294967296 + low; + if (low < 0) { + n += 4294967296; + } + return n; + } + + double _readFixed(int offset) { + return _readInt16(offset) + (_readInt16(offset + 2) / 16384); + } + + String _readString(int? length, [bool? isUnicode]) { + if (isUnicode == null) { + return _readString(length, false); + } else { + String result = ''; + if (isUnicode) { + for (int i = 0; i < length!; i++) { + if (i % 2 != 0) { + result += String.fromCharCode(_fontData[currentOffset!]); + } + currentOffset = currentOffset! + 1; + } + } else { + for (int i = 0; i < length!; i++) { + result += String.fromCharCode(_fontData[currentOffset!]); + currentOffset = currentOffset! + 1; + } + } + return result; + } + } + + List _readBytes(int length) { + final List result = List.filled(length, 0, growable: true); + for (int i = 0; i < length; i++) { + result[i] = _fontData[currentOffset!]; + currentOffset = currentOffset! + 1; + } + return result; + } + + List _readUshortArray(int length) { + final List buffer = List.filled(length, 0, growable: true); + for (int i = 0; i < length; i++) { + buffer[i] = _readUInt16(currentOffset!); + } + return buffer; + } + + dynamic _read(List buffer, int index, int count) { + int written = 0; + int read = 0; + do { + for ( + int i = 0; + i < count - written && currentOffset! + i < _fontData.length; + i++ + ) { + buffer[index + i] = _fontData[currentOffset! + i]; + } + read = count - written; + currentOffset = currentOffset! + read; + written += read; + } while (written < count); + return {'buffer': buffer, 'written': written}; + } +} + +class _TtfHeadTable { + /// Modified: International date (8-byte field). + int? modified; + + /// Created: International date (8-byte field). + int? created; + + /// MagicNumber: Set to 0x5F0F3CF5. + int? magicNumber; + + /// CheckSumAdjustment: To compute: set it to 0, sum the entire font as ULONG, + /// then store 0xB1B0AFBA - sum. + int? checkSumAdjustment; + + /// FontRevision: Set by font manufacturer. + double? fontRevision; + + /// Table version number: 0x00010000 for version 1.0. + double? version; + + /// Minimum x for all glyph bounding boxes. + late int xMin; + + /// Minimum y for all glyph bounding boxes. + int? yMin; + + /// Valid range is from 16 to 16384. + int? unitsPerEm; + + /// Maximum y for all glyph bounding boxes. + int? yMax; + + /// Maximum x for all glyph bounding boxes. + late int xMax; + + /// Regular: 0 + /// Bold: 1 + /// Italic: 2 + /// Bold Italic: 3 + /// Bit 0 - bold (if set to 1) + /// Bit 1 - italic (if set to 1) + /// Bits 2-15 - reserved (set to 0) + /// NOTE: + /// Note that macStyle bits must agree with the 'OS/2' table fsSelection bits. + /// The fsSelection bits are used over the macStyle bits in Microsoft Windows. + /// The PANOSE values and 'post' table values are ignored + /// for determining bold or italic fonts. + int? macStyle; + + /// Bit 0 - baseline for font at y=0 + /// Bit 1 - left SideBearing at x=0 + /// Bit 2 - instructions may depend on point size + /// Bit 3 - force ppem to integer values for all private scaler math; + /// may use fractional ppem sizes if this bit is clear + /// Bit 4 - instructions may alter advance width + /// (the advance widths might not scale linearly) + /// Note: All other bits must be zero. + int? flags; + + /// LowestRecPPEM: Smallest readable size in pixels. + int? lowestReadableSize; + + /// FontDirectionHint: + /// 0 Fully mixed directional glyphs + /// 1 Only strongly left to right + /// 2 Like 1 but also contains neutrals + /// -1 Only strongly right to left + /// -2 Like -1 but also contains neutrals. + int? fontDirectionHint; + + /// 0 for short offsets, 1 for long. + int? indexToLocalFormat; + + /// 0 for current format. + int? glyphDataFormat; +} + +class _TtfHorizontalHeaderTable { + /// Version. + double? version; + + /// Typographic ascent. + late int ascender; + + /// Maximum advance width value in HTML table. + int? advanceWidthMax; + + /// Typographic descent. + late int descender; + + /// Number of hMetric entries in HTML table; + /// may be smaller than the total number of glyphs in the font. + late int numberOfHMetrics; + + /// Typographic line gap. + /// Negative LineGap values are treated as DEF_TABLE_CHECKSUM + /// in Windows 3.1, System 6, and System 7. + late int lineGap; + + /// Minimum left SideBearing value in HTML table. + int? minLeftSideBearing; + + /// Minimum right SideBearing value; + /// calculated as Min(aw - lsb - (xMax - xMin)). + int? minRightSideBearing; + + /// Max(lsb + (xMax - xMin)). + int? xMaxExtent; + + /// Used to calculate the slope of the cursor (rise/run); 1 for vertical. + int? caretSlopeRise; + + /// 0 for vertical. + int? caretSlopeRun; + + /// 0 for current format. + int? metricDataFormat; +} + +/// name ttf table. +class _TtfNameTable { + /// Local variable to store Format Selector. + int? formatSelector; + + /// Local variable to store Records Count. + late int recordsCount; + + /// Local variable to store Offset. + late int offset; + + /// Local variable to store Name Records. + late List<_TtfNameRecord> nameRecords; +} + +class _TtfNameRecord { + /// The PlatformID. + int? platformID; + + /// The EncodingID. + int? encodingID; + + /// The PlatformIDLanguageID + int? languageID; + + /// The NameID. + int? nameID; + + /// The Length. + int? length; + + /// The Offset. + late int offset; + + /// The Name. + String? name; +} + +class _TtfOS2Table { + late int version; + + /// The Average Character Width parameter specifies + /// the arithmetic average of the escapement (width) + /// of all of the 26 lowercase letters a through z of the Latin alphabet + /// and the space character. If any of the 26 lowercase letters are not + /// present, this parameter should equal the weighted average of all + /// glyphs in the font. + /// For non-UGL (platform 3, encoding 0) fonts, use the unweighted average. + int? xAvgCharWidth; + + /// Indicates the visual weight (degree of blackness or thickness of strokes) + /// of the characters in the font. + int? usWeightClass; + + /// Indicates a relative change from the normal aspect ratio (width to + /// height ratio) as specified by a font designer for the glyphs in a font. + int? usWidthClass; + + /// Indicates font embedding licensing rights for the font. + /// Embeddable fonts may be stored in a document. + /// When a document with embedded fonts is opened on a system that + /// does not have the font installed (the remote system), + /// the embedded font may be loaded for temporary + /// (and in some cases, permanent) use on that system by an embedding-aware + /// application. + /// Embedding licensing rights are granted by the vendor of the font. + int? fsType; + + /// The recommended horizontal size in font design units + /// for subscripts for this font. + int? ySubscriptXSize; + + /// The recommended vertical size in font design units + /// for subscripts for this font. + late int ySubscriptYSize; + + /// The recommended horizontal offset in font design units + /// for subscripts for this font. + int? ySubscriptXOffset; + + /// The recommended vertical offset in font design units from the baseline + /// for subscripts for this font. + int? ySubscriptYOffset; + + /// The recommended horizontal size in font design units + /// for superscripts for this font. + int? ySuperscriptXSize; + + /// The recommended vertical size in font design units + /// for superscripts for this font. + late int ySuperscriptYSize; + + /// The recommended horizontal offset in font design units + /// for superscripts for this font. + int? ySuperscriptXOffset; + + /// The recommended vertical offset in font design units from the baseline + /// for superscripts for this font. + int? ySuperscriptYOffset; + + /// Width of the strikethrough stroke in font design units. + int? yStrikeoutSize; + + /// The position of the strikethrough stroke relative to the baseline + /// in font design units. + int? yStrikeoutPosition; + + /// This parameter is a classification of font-family design. + int? sFamilyClass; + + /// This 10 byte series of numbers are used to describe the visual + /// characteristics of a given typeface. + /// These characteristics are then used to associate the font with + /// other fonts of similar appearance having different names. + /// The variables for each digit are listed below. + /// The specifications for each variable can be obtained in the specification + /// PANOSE v2.0 Numerical Evaluation from Microsoft or Elseware Corporation. + List? panose; + + int? ulUnicodeRange1; + int? ulUnicodeRange2; + int? ulUnicodeRange3; + int? ulUnicodeRange4; + + /// The four character identifier for the vendor of the given type face. + List? vendorIdentifier; + + /// Information concerning the nature of the font patterns. + int? fsSelection; + + /// The minimum Unicode index (character code) in this font, + /// according to the cmap subtable for platform ID 3 and encoding ID 0 or 1. + /// For most fonts supporting Win-ANSI or other character sets, + /// this value would be 0x0020. + int? usFirstCharIndex; + + /// usLastCharIndex: The maximum Unicode index (character code) in this font, + /// according to the cmap subtable for platform ID 3 and encoding ID 0 or 1. + /// This value depends on which character sets the font supports. + int? usLastCharIndex; + + /// The typographic ascender for this font. + /// Remember that this is not the same as the Ascender value + /// in the 'hhea' table, which Apple defines in a far different manner. + /// DEF_TABLE_OFFSET good source for usTypoAscender is the Ascender value + /// from an AFM file. + late int sTypoAscender; + + /// The typographic descender for this font. + /// Remember that this is not the same as the Descender value + /// in the 'hhea' table, + /// which Apple defines in a far different manner. + /// DEF_TABLE_OFFSET good source for usTypoDescender is the Descender value + /// from an AFM file. + late int sTypoDescender; + + /// The typographic line gap for this font. + /// Remember that this is not the same as the LineGap value in the + /// 'hhea' table, which Apple defines in a far different manner. + late int sTypoLineGap; + + /// The ascender metric for Windows. + /// This too is distinct from Apple's Ascender value and from the + /// usTypoAscender values, usWinAscent is computed as the yMax for all + /// characters in the Windows ANSI character set. + /// usTypoAscent is used to compute the Windows font height and + /// default line spacing. + /// For platform 3 encoding 0 fonts, it is the same as yMax. + int? usWinAscent; + + /// The descender metric for Windows. + /// This too is distinct from Apple's Descender value and + /// from the usTypoDescender values. + /// usWinDescent is computed as the -yMin for all characters + /// in the Windows ANSI character set. + /// usTypoAscent is used to compute the Windows font height and + /// default line spacing. + /// For platform 3 encoding 0 fonts, it is the same as -yMin. + int? usWinDescent; + + /// This field is used to specify the code pages encompassed + /// by the font file in the 'cmap' subtable for platform 3, + /// encoding ID 1 (Microsoft platform). + /// If the font file is encoding ID 0, then the Symbol Character Set bit + /// should be set. + /// If the bit is set (1) then the code page is considered functional. + /// If the bit is clear (0) then the code page is not considered functional. + /// Each of the bits is treated as an independent flag and the bits can be + /// set in any combination. + /// The determination of "functional" is left up to the font designer, + /// although character set selection should attempt to be functional + /// by code pages if at all possible. + int? ulCodePageRange1; + + /// This field is used to specify the code pages encompassed + /// by the font file in the 'cmap' subtable for platform 3, + /// encoding ID 1 (Microsoft platform). + /// If the font file is encoding ID 0, then the Symbol Character Set + /// bit should be set. + /// If the bit is set (1) then the code page is considered functional. + /// If the bit is clear (0) then the code page is not considered functional. + /// Each of the bits is treated as an independent flag and the bits can be + /// set in any combination. + /// The determination of "functional" is left up to the font designer, + /// although character set selection should attempt to be functional by + /// code pages if at all possible. + int? ulCodePageRange2; + + int? sxHeight; + int? sCapHeight; + int? usDefaultChar; + int? usBreakChar; + int? usMaxContext; +} + +class _TtfTableInfo { + /// Gets or sets ofset from beginning of TrueType font file. + int? offset; + + /// Gets or sets length of this table. + int? length; + + /// Gets or sets table checksum. + int? checksum; + + /// Gets a value indicating whether this [_TtfTableInfo] is empty. + /// true if empty, otherwise false + bool get empty => + offset == length && + length == checksum && + (checksum == 0 || checksum == null); +} + +class _TtfPostTable { + double? formatType; + double? italicAngle; + int? underlinePosition; + int? underlineThickness; + int? isFixedPitch; + int? minType42; + int? maxType42; + int? minType1; + int? maxType1; +} + +class _TtfCmapSubTable { + int? platformID; + int? encodingID; + late int offset; +} + +class _TtfCmapTable { + int? version; + late int tablesCount; +} + +class _TtfLongHorMetric { + late int advanceWidth; + int? lsb; +} + +class _TtfAppleCmapSubTable { + int? format; + int? length; + int? version; +} + +/// internal class +class TtfGlyphInfo { + /// Holds glyph index. + int index = 0; + + /// Holds character's width. + int width = 0; + + /// Code of the char symbol. + int charCode = 0; + + /// Gets a value indicating whether [TtfGlyphInfo] is empty. + bool get empty { + return index == width && width == charCode && charCode == 0; + } +} + +class _TtfMicrosoftCmapSubTable { + int? format; + late int length; + int? version; + late int segCountX2; + int? searchRange; + int? entrySelector; + int? rangeShift; + late List endCount; + int? reservedPad; + late List startCount; + late List idDelta; + late List idRangeOffset; + late List glyphID; +} + +class _TtfTrimmedCmapSubTable { + int? format; + int? length; + int? version; + late int firstCode; + late int entryCount; +} + +class _TtfGlyphHeader { + late int numberOfContours; + int? xMin; + int? yMin; + int? xMax; + int? yMax; +} + +/// Enumerator that implements CMAP formats. +enum _TtfCmapFormat { + /// This is the Apple standard character to glyph index mapping table. + apple, + + /// This is the Microsoft standard character to glyph index mapping table. + microsoft, + + /// Format 6: Trimmed table mapping. + trimmed, + + /// This is the Microsoft standard character-to-glyph-index mapping table for fonts supporting Unicode supplementary-plane characters (U+10000 to U+10FFFF). + microsoftExt, +} + +/// Enumerator that implements CMAP encodings. +enum _TtfCmapEncoding { + /// Unknown encoding. + unknown, + + /// When building a symbol font for Windows. + symbol, + + /// When building a Unicode font for Windows. + unicode, + + /// For font that will be used on a Macintosh. + macintosh, + + /// When building a Unicode font for Windows (plane characters). + unicodeUCS4, +} + +/// Ttf platform ID. +enum _TtfPlatformID { + /// Apple platform. + appleUnicode, + + /// Macintosh platform. + macintosh, + + /// Iso platform. + iso, + + /// Microsoft platform. + microsoft, +} + +/// Microsoft encoding ID. +enum _TtfMicrosoftEncodingID { + /// Undefined encoding. + undefined, + + /// Unicode encoding. + unicode, + + /// Unicode UCS4. + unicodeUCS4, +} + +/// Macintosh encoding ID. +enum _TtfMacintoshEncodingID { + /// Roman encoding. + roman, + + /// Japanese encoding. + japanese, + + /// Chinese encoding. + chinese, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/unicode_true_type_font.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/unicode_true_type_font.dart index 11eb4c6f7..b1218c3a3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/unicode_true_type_font.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/fonts/unicode_true_type_font.dart @@ -1,493 +1,493 @@ -import 'dart:math'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../drawing/drawing.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_number.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_stream.dart'; -import '../../primitives/pdf_string.dart'; -import 'pdf_font_metrics.dart'; -import 'ttf_metrics.dart'; -import 'ttf_reader.dart'; - -/// internal class -class UnicodeTrueTypeFont { - /// internal constructor - UnicodeTrueTypeFont(List fontData, double size) { - _initialize(fontData, size); - } - - //Constants - final String _cmapPrefix = - '/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap${PdfOperators.newLine}/CIDSystemInfo << /Registry (Adobe)/Ordering (UCS)/Supplement 0>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange${PdfOperators.newLine}'; - - /// Cmap table's start suffix. - final String _cmapEndCodespaceRange = - 'endcodespacerange${PdfOperators.newLine}'; - - /// Cmap's begin range marker. - final String _cmapBeginRange = 'beginbfrange${PdfOperators.newLine}'; - - /// Cmap's end range marker. - final String _cmapEndRange = 'endbfrange${PdfOperators.newLine}'; - - /// Cmap table's end - final String _cmapSuffix = - 'endbfrange\nendcmap\nCMapName currentdict /CMap defineresource pop\nend end${PdfOperators.newLine}'; - - //Fields - /// internal field - late List fontData; - - /// internal field - late double _size; - - /// internal field - late TtfReader reader; - - /// internal field - TtfMetrics? ttfMetrics; - - /// internal field - late PdfFontMetrics metrics; - - /// internal field - PdfDictionary? fontDictionary; - PdfStream? _fontProgram; - PdfStream? _cmap; - PdfDictionary? _descendantFont; - String? _subsetName; - List? _usedChars; - List? _surrogateChars; - PdfDictionary? _fontDescriptor; - PdfStream? _cidStream; - - //Implementation - void _initialize(List fontData, double size) { - this.fontData = fontData; - _size = size; - reader = TtfReader(this.fontData); - ttfMetrics = reader.metrics; - } - - /// internal method - void createInternals() { - fontDictionary = PdfDictionary(); - _fontProgram = PdfStream(); - _cmap = PdfStream(); - _descendantFont = PdfDictionary(); - metrics = PdfFontMetrics(); - reader.createInternals(); - ttfMetrics = reader.metrics; - _initializeMetrics(); - _subsetName = _getFontName(reader.metrics!.postScriptName!); - _createDescendantFont(); - _createCmap(); - _createFontDictionary(); - _createFontProgram(); - } - - void _initializeMetrics() { - final TtfMetrics ttfMetrics = reader.metrics!; - metrics.ascent = ttfMetrics.macAscent; - metrics.descent = ttfMetrics.macDescent; - metrics.height = - ttfMetrics.macAscent - ttfMetrics.macDescent + ttfMetrics.lineGap!; - metrics.name = ttfMetrics.fontFamily!; - metrics.postScriptName = ttfMetrics.postScriptName; - metrics.size = _size; - metrics.widthTable = StandardWidthTable(ttfMetrics.widthTable); - metrics.lineGap = ttfMetrics.lineGap!; - metrics.subscriptSizeFactor = ttfMetrics.subscriptSizeFactor; - metrics.superscriptSizeFactor = ttfMetrics.superscriptSizeFactor; - metrics.isBold = ttfMetrics.isBold; - } - - String _getFontName(String postScriptName) { - const String nameString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - String builder = ''; - for (int i = 0; i < postScriptName.length; i++) { - switch (postScriptName[i]) { - case '(': - builder += '#28'; - break; - case ')': - builder += '#29'; - break; - case '[': - builder += '#5B'; - break; - case ']': - builder += '#5D'; - break; - case '<': - builder += '#3C'; - break; - case '>': - builder += '#3E'; - break; - case '{': - builder += '#7B'; - break; - case '}': - builder += '#7D'; - break; - case '/': - builder += '#2F'; - break; - case '%': - builder += '#25'; - break; - case ' ': - builder += '#20'; - break; - default: - builder += postScriptName[i]; - } - } - String name = ''; - for (int i = 0; i < 6; i++) { - name += nameString[Random().nextInt(26)]; - } - return '$name+$builder'; - } - - void _createDescendantFont() { - _descendantFont!.beginSave = _descendantFontBeginSave; - _descendantFont![PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.font, - ); - _descendantFont![PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.cidFontType2, - ); - _descendantFont![PdfDictionaryProperties.baseFont] = PdfName(_subsetName); - _descendantFont![PdfDictionaryProperties.cidToGIDMap] = PdfName( - PdfDictionaryProperties.identity, - ); - _descendantFont![PdfDictionaryProperties.dw] = PdfNumber(1000); - _fontDescriptor = _createFontDescriptor(); - _descendantFont![PdfDictionaryProperties - .fontDescriptor] = PdfReferenceHolder(_fontDescriptor); - _descendantFont![PdfDictionaryProperties.cidSystemInfo] = - _createSystemInfo(); - } - - PdfDictionary _createFontDescriptor() { - final PdfDictionary descriptor = PdfDictionary(); - final TtfMetrics metrics = reader.metrics!; - descriptor[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.fontDescriptor, - ); - descriptor[PdfDictionaryProperties.fontName] = PdfName(_subsetName); - descriptor[PdfDictionaryProperties.flags] = PdfNumber( - _getDescriptorFlags(), - ); - final PdfRectangle rect = reader.metrics!.fontBox; - descriptor[PdfDictionaryProperties.fontBBox] = PdfArray([ - rect.x, - rect.y + rect.height, - rect.width, - -rect.height, - ]); - descriptor[PdfDictionaryProperties.missingWidth] = PdfNumber( - metrics.widthTable[32], - ); - descriptor[PdfDictionaryProperties.stemV] = PdfNumber(metrics.stemV); - descriptor[PdfDictionaryProperties.italicAngle] = PdfNumber( - metrics.italicAngle!, - ); - descriptor[PdfDictionaryProperties.capHeight] = PdfNumber( - metrics.capHeight, - ); - descriptor[PdfDictionaryProperties.ascent] = PdfNumber(metrics.winAscent); - descriptor[PdfDictionaryProperties.descent] = PdfNumber(metrics.winDescent); - descriptor[PdfDictionaryProperties.leading] = PdfNumber(metrics.leading); - descriptor[PdfDictionaryProperties.avgWidth] = PdfNumber( - metrics.widthTable[32], - ); - descriptor[PdfDictionaryProperties.fontFile2] = PdfReferenceHolder( - _fontProgram, - ); - descriptor[PdfDictionaryProperties.maxWidth] = PdfNumber( - metrics.widthTable[32], - ); - descriptor[PdfDictionaryProperties.xHeight] = PdfNumber(0); - descriptor[PdfDictionaryProperties.stemH] = PdfNumber(0); - return descriptor; - } - - int _getDescriptorFlags() { - int flags = 0; - final TtfMetrics metrics = reader.metrics!; - if (metrics.isFixedPitch) { - flags |= 1; - } - if (metrics.isSymbol) { - flags |= 4; - } else { - flags |= 32; - } - if (metrics.isItalic) { - flags |= 64; - } - if (metrics.isBold) { - flags |= 0x40000; - } - return flags; - } - - IPdfPrimitive _createSystemInfo() { - final PdfDictionary systemInfo = PdfDictionary(); - systemInfo[PdfDictionaryProperties.registry] = PdfString('Adobe'); - systemInfo[PdfDictionaryProperties.ordering] = PdfString( - PdfDictionaryProperties.identity, - ); - systemInfo[PdfDictionaryProperties.supplement] = PdfNumber(0); - return systemInfo; - } - - void _descendantFontBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (_usedChars != null && _usedChars!.isNotEmpty) { - final PdfArray width = _getDescendantWidth(); - _descendantFont![PdfDictionaryProperties.w] = width; - } - } - - void _createCmap() { - _cmap!.beginSave = _cmapBeginSave; - } - - void _cmapBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - _generateCmap(); - } - - void _createFontDictionary() { - fontDictionary!.beginSave = _fontDictionaryBeginSave; - fontDictionary![PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.font, - ); - fontDictionary![PdfDictionaryProperties.baseFont] = PdfName(_subsetName); - fontDictionary![PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.type0, - ); - fontDictionary![PdfDictionaryProperties.encoding] = PdfName( - PdfDictionaryProperties.identityH, - ); - final PdfArray descFonts = PdfArray(); - final PdfReferenceHolder reference = PdfReferenceHolder(_descendantFont); - descFonts.add(reference); - fontDictionary![PdfDictionaryProperties.descendantFonts] = descFonts; - } - - void _fontDictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (_usedChars != null && - _usedChars!.isNotEmpty && - !fontDictionary!.containsKey(PdfDictionaryProperties.toUnicode)) { - fontDictionary![PdfDictionaryProperties.toUnicode] = PdfReferenceHolder( - _cmap, - ); - } - } - - PdfArray _getDescendantWidth() { - final PdfArray array = PdfArray(); - if (_usedChars != null && _usedChars!.isNotEmpty) { - final List glyphInfo = []; - for (int i = 0; i < _usedChars!.length; i++) { - final String chLen = _usedChars![i]; - final TtfGlyphInfo glyph = reader.getGlyph(char: chLen)!; - if (glyph.empty) { - continue; - } - glyphInfo.add(glyph); - } - glyphInfo.sort( - (TtfGlyphInfo a, TtfGlyphInfo b) => a.index.compareTo(b.index), - ); - int firstGlyphIndex = 0; - int lastGlyphIndex = 0; - bool firstGlyphIndexWasSet = false; - PdfArray widthDetails = PdfArray(); - for (int i = 0; i < glyphInfo.length; i++) { - final TtfGlyphInfo glyph = glyphInfo[i]; - if (!firstGlyphIndexWasSet) { - firstGlyphIndexWasSet = true; - firstGlyphIndex = glyph.index; - lastGlyphIndex = glyph.index - 1; - } - if ((lastGlyphIndex + 1 != glyph.index || - (i + 1 == glyphInfo.length)) && - glyphInfo.length > 1) { - array.add(PdfNumber(firstGlyphIndex)); - if (i != 0) { - array.add(widthDetails); - } - firstGlyphIndex = glyph.index; - widthDetails = PdfArray(); - } - widthDetails.add(PdfNumber(glyph.width)); - if (i + 1 == glyphInfo.length) { - array.add(PdfNumber(firstGlyphIndex)); - array.add(widthDetails); - } - lastGlyphIndex = glyph.index; - } - } - return array; - } - - void _generateCmap() { - if (_usedChars != null && _usedChars!.isNotEmpty) { - final Map glyphChars = reader.getGlyphChars(_usedChars!); - if (glyphChars.isNotEmpty) { - final List keys = glyphChars.keys.toList(); - keys.sort(); - final int first = keys[0]; - final int last = keys[keys.length - 1]; - final String middlePart = - _getHexString(first, false) + - _getHexString(last, false) + - PdfOperators.newLine; - String builder = ''; - builder += _cmapPrefix; - builder += middlePart; - builder += _cmapEndCodespaceRange; - int nextRange = 0; - for (int i = 0; i < keys.length; i++) { - if (nextRange == 0) { - if (i != 0) { - builder += _cmapEndRange; - } - nextRange = 100 <= keys.length - i ? 100 : keys.length - i; - builder += nextRange.toString(); - builder += PdfOperators.whiteSpace; - builder += _cmapBeginRange; - } - nextRange -= 1; - final int key = keys[i]; - builder += - '${_getHexString(key, true)}${_getHexString(key, true)}${_getHexString(glyphChars[key]!, true)}\n'; - } - builder += _cmapSuffix; - _cmap!.clearStream(); - _cmap!.write(builder); - } - } - } - - void _createFontProgram() { - _fontProgram!.beginSave = _fontProgramBeginSave; - } - - void _fontProgramBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - _generateFontProgram(); - } - - void _generateFontProgram() { - List? fontProgram; - _usedChars ??= []; - reader.currentOffset = 0; - fontProgram = reader.readFontProgram(_usedChars!); - _fontProgram!.clearStream(); - _fontProgram!.write(fontProgram); - } - - String _getHexString(int n, bool isCaseChange) { - String s = n.toRadixString(16); - if (isCaseChange) { - s = s.toUpperCase(); - } - return '${'<0000'.substring(0, 5 - s.length)}$s>'; - } - - /// internal method - double getLineWidth(String line) { - double width = 0; - for (int i = 0; i < line.length; i++) { - width += reader.getCharWidth(line[i]); - } - return width; - } - - /// internal method - void setSymbols(String text, List? usedChars) { - _usedChars ??= []; - if (usedChars != null && usedChars.isNotEmpty) { - _surrogateChars ??= []; - for (final String surrogateChar in usedChars) { - if (!_surrogateChars!.contains(surrogateChar)) { - _surrogateChars!.add(surrogateChar); - _usedChars!.add(surrogateChar[0]); - _usedChars!.add(surrogateChar[1]); - } - } - } - for (int i = 0; i < text.length; i++) { - if (!_usedChars!.contains(text[i])) { - _usedChars!.add(text[i]); - } - } - _getDescendantWidth(); - } - - /// internal method - double getCharWidth(String charCode) { - return reader.getCharWidth(charCode); - } - - /// internal method - void initializeCidSet() { - _cidStream = PdfStream(); - _cidStream!.beginSave = _cidBeginSave; - _fontDescriptor!.beginSave = _fontDescriptorBeginSave; - } - - //Runs before Cid will be saved. - void _cidBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - _generateCidSet(); - } - - //Runs before font Dictionary will be saved. - void _fontDescriptorBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if ((_usedChars != null && _usedChars!.isNotEmpty) && - !_fontDescriptor!.containsKey(PdfDictionaryProperties.cidSet)) { - _fontDescriptor![PdfDictionaryProperties.cidSet] = PdfReferenceHolder( - _cidStream, - ); - } - } - - //This is important for PDF/A conformance validation - void _generateCidSet() { - final List dummyBits = [ - 0x80, - 0x40, - 0x20, - 0x10, - 0x08, - 0x04, - 0x02, - 0x01, - ]; - if (_usedChars != null && _usedChars!.isNotEmpty) { - final Map glyphChars = reader.getGlyphChars(_usedChars!); - List? charBytes; - if (glyphChars.isNotEmpty) { - final List cidChars = glyphChars.keys.toList(); - cidChars.sort(); - final int last = cidChars[cidChars.length - 1]; - charBytes = List.filled((last ~/ 8) + 1, 0, growable: true); - charBytes.fillRange(0, (last ~/ 8) + 1, 0); - for (int i = 0; i < cidChars.length; i++) { - final int cid = cidChars[i]; - charBytes[cid ~/ 8] |= dummyBits[cid % 8]; - } - } - _cidStream!.write(charBytes); - } - } -} +import 'dart:math'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../drawing/drawing.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_number.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_stream.dart'; +import '../../primitives/pdf_string.dart'; +import 'pdf_font_metrics.dart'; +import 'ttf_metrics.dart'; +import 'ttf_reader.dart'; + +/// internal class +class UnicodeTrueTypeFont { + /// internal constructor + UnicodeTrueTypeFont(List fontData, double size) { + _initialize(fontData, size); + } + + //Constants + final String _cmapPrefix = + '/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap${PdfOperators.newLine}/CIDSystemInfo << /Registry (Adobe)/Ordering (UCS)/Supplement 0>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange${PdfOperators.newLine}'; + + /// Cmap table's start suffix. + final String _cmapEndCodespaceRange = + 'endcodespacerange${PdfOperators.newLine}'; + + /// Cmap's begin range marker. + final String _cmapBeginRange = 'beginbfrange${PdfOperators.newLine}'; + + /// Cmap's end range marker. + final String _cmapEndRange = 'endbfrange${PdfOperators.newLine}'; + + /// Cmap table's end + final String _cmapSuffix = + 'endbfrange\nendcmap\nCMapName currentdict /CMap defineresource pop\nend end${PdfOperators.newLine}'; + + //Fields + /// internal field + late List fontData; + + /// internal field + late double _size; + + /// internal field + late TtfReader reader; + + /// internal field + TtfMetrics? ttfMetrics; + + /// internal field + late PdfFontMetrics metrics; + + /// internal field + PdfDictionary? fontDictionary; + PdfStream? _fontProgram; + PdfStream? _cmap; + PdfDictionary? _descendantFont; + String? _subsetName; + List? _usedChars; + List? _surrogateChars; + PdfDictionary? _fontDescriptor; + PdfStream? _cidStream; + + //Implementation + void _initialize(List fontData, double size) { + this.fontData = fontData; + _size = size; + reader = TtfReader(this.fontData); + ttfMetrics = reader.metrics; + } + + /// internal method + void createInternals() { + fontDictionary = PdfDictionary(); + _fontProgram = PdfStream(); + _cmap = PdfStream(); + _descendantFont = PdfDictionary(); + metrics = PdfFontMetrics(); + reader.createInternals(); + ttfMetrics = reader.metrics; + _initializeMetrics(); + _subsetName = _getFontName(reader.metrics!.postScriptName!); + _createDescendantFont(); + _createCmap(); + _createFontDictionary(); + _createFontProgram(); + } + + void _initializeMetrics() { + final TtfMetrics ttfMetrics = reader.metrics!; + metrics.ascent = ttfMetrics.macAscent; + metrics.descent = ttfMetrics.macDescent; + metrics.height = + ttfMetrics.macAscent - ttfMetrics.macDescent + ttfMetrics.lineGap!; + metrics.name = ttfMetrics.fontFamily!; + metrics.postScriptName = ttfMetrics.postScriptName; + metrics.size = _size; + metrics.widthTable = StandardWidthTable(ttfMetrics.widthTable); + metrics.lineGap = ttfMetrics.lineGap!; + metrics.subscriptSizeFactor = ttfMetrics.subscriptSizeFactor; + metrics.superscriptSizeFactor = ttfMetrics.superscriptSizeFactor; + metrics.isBold = ttfMetrics.isBold; + } + + String _getFontName(String postScriptName) { + const String nameString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + String builder = ''; + for (int i = 0; i < postScriptName.length; i++) { + switch (postScriptName[i]) { + case '(': + builder += '#28'; + break; + case ')': + builder += '#29'; + break; + case '[': + builder += '#5B'; + break; + case ']': + builder += '#5D'; + break; + case '<': + builder += '#3C'; + break; + case '>': + builder += '#3E'; + break; + case '{': + builder += '#7B'; + break; + case '}': + builder += '#7D'; + break; + case '/': + builder += '#2F'; + break; + case '%': + builder += '#25'; + break; + case ' ': + builder += '#20'; + break; + default: + builder += postScriptName[i]; + } + } + String name = ''; + for (int i = 0; i < 6; i++) { + name += nameString[Random().nextInt(26)]; + } + return '$name+$builder'; + } + + void _createDescendantFont() { + _descendantFont!.beginSave = _descendantFontBeginSave; + _descendantFont![PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.font, + ); + _descendantFont![PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.cidFontType2, + ); + _descendantFont![PdfDictionaryProperties.baseFont] = PdfName(_subsetName); + _descendantFont![PdfDictionaryProperties.cidToGIDMap] = PdfName( + PdfDictionaryProperties.identity, + ); + _descendantFont![PdfDictionaryProperties.dw] = PdfNumber(1000); + _fontDescriptor = _createFontDescriptor(); + _descendantFont![PdfDictionaryProperties + .fontDescriptor] = PdfReferenceHolder(_fontDescriptor); + _descendantFont![PdfDictionaryProperties.cidSystemInfo] = + _createSystemInfo(); + } + + PdfDictionary _createFontDescriptor() { + final PdfDictionary descriptor = PdfDictionary(); + final TtfMetrics metrics = reader.metrics!; + descriptor[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.fontDescriptor, + ); + descriptor[PdfDictionaryProperties.fontName] = PdfName(_subsetName); + descriptor[PdfDictionaryProperties.flags] = PdfNumber( + _getDescriptorFlags(), + ); + final PdfRectangle rect = reader.metrics!.fontBox; + descriptor[PdfDictionaryProperties.fontBBox] = PdfArray([ + rect.x, + rect.y + rect.height, + rect.width, + -rect.height, + ]); + descriptor[PdfDictionaryProperties.missingWidth] = PdfNumber( + metrics.widthTable[32], + ); + descriptor[PdfDictionaryProperties.stemV] = PdfNumber(metrics.stemV); + descriptor[PdfDictionaryProperties.italicAngle] = PdfNumber( + metrics.italicAngle!, + ); + descriptor[PdfDictionaryProperties.capHeight] = PdfNumber( + metrics.capHeight, + ); + descriptor[PdfDictionaryProperties.ascent] = PdfNumber(metrics.winAscent); + descriptor[PdfDictionaryProperties.descent] = PdfNumber(metrics.winDescent); + descriptor[PdfDictionaryProperties.leading] = PdfNumber(metrics.leading); + descriptor[PdfDictionaryProperties.avgWidth] = PdfNumber( + metrics.widthTable[32], + ); + descriptor[PdfDictionaryProperties.fontFile2] = PdfReferenceHolder( + _fontProgram, + ); + descriptor[PdfDictionaryProperties.maxWidth] = PdfNumber( + metrics.widthTable[32], + ); + descriptor[PdfDictionaryProperties.xHeight] = PdfNumber(0); + descriptor[PdfDictionaryProperties.stemH] = PdfNumber(0); + return descriptor; + } + + int _getDescriptorFlags() { + int flags = 0; + final TtfMetrics metrics = reader.metrics!; + if (metrics.isFixedPitch) { + flags |= 1; + } + if (metrics.isSymbol) { + flags |= 4; + } else { + flags |= 32; + } + if (metrics.isItalic) { + flags |= 64; + } + if (metrics.isBold) { + flags |= 0x40000; + } + return flags; + } + + IPdfPrimitive _createSystemInfo() { + final PdfDictionary systemInfo = PdfDictionary(); + systemInfo[PdfDictionaryProperties.registry] = PdfString('Adobe'); + systemInfo[PdfDictionaryProperties.ordering] = PdfString( + PdfDictionaryProperties.identity, + ); + systemInfo[PdfDictionaryProperties.supplement] = PdfNumber(0); + return systemInfo; + } + + void _descendantFontBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (_usedChars != null && _usedChars!.isNotEmpty) { + final PdfArray width = _getDescendantWidth(); + _descendantFont![PdfDictionaryProperties.w] = width; + } + } + + void _createCmap() { + _cmap!.beginSave = _cmapBeginSave; + } + + void _cmapBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + _generateCmap(); + } + + void _createFontDictionary() { + fontDictionary!.beginSave = _fontDictionaryBeginSave; + fontDictionary![PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.font, + ); + fontDictionary![PdfDictionaryProperties.baseFont] = PdfName(_subsetName); + fontDictionary![PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.type0, + ); + fontDictionary![PdfDictionaryProperties.encoding] = PdfName( + PdfDictionaryProperties.identityH, + ); + final PdfArray descFonts = PdfArray(); + final PdfReferenceHolder reference = PdfReferenceHolder(_descendantFont); + descFonts.add(reference); + fontDictionary![PdfDictionaryProperties.descendantFonts] = descFonts; + } + + void _fontDictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (_usedChars != null && + _usedChars!.isNotEmpty && + !fontDictionary!.containsKey(PdfDictionaryProperties.toUnicode)) { + fontDictionary![PdfDictionaryProperties.toUnicode] = PdfReferenceHolder( + _cmap, + ); + } + } + + PdfArray _getDescendantWidth() { + final PdfArray array = PdfArray(); + if (_usedChars != null && _usedChars!.isNotEmpty) { + final List glyphInfo = []; + for (int i = 0; i < _usedChars!.length; i++) { + final String chLen = _usedChars![i]; + final TtfGlyphInfo glyph = reader.getGlyph(char: chLen)!; + if (glyph.empty) { + continue; + } + glyphInfo.add(glyph); + } + glyphInfo.sort( + (TtfGlyphInfo a, TtfGlyphInfo b) => a.index.compareTo(b.index), + ); + int firstGlyphIndex = 0; + int lastGlyphIndex = 0; + bool firstGlyphIndexWasSet = false; + PdfArray widthDetails = PdfArray(); + for (int i = 0; i < glyphInfo.length; i++) { + final TtfGlyphInfo glyph = glyphInfo[i]; + if (!firstGlyphIndexWasSet) { + firstGlyphIndexWasSet = true; + firstGlyphIndex = glyph.index; + lastGlyphIndex = glyph.index - 1; + } + if ((lastGlyphIndex + 1 != glyph.index || + (i + 1 == glyphInfo.length)) && + glyphInfo.length > 1) { + array.add(PdfNumber(firstGlyphIndex)); + if (i != 0) { + array.add(widthDetails); + } + firstGlyphIndex = glyph.index; + widthDetails = PdfArray(); + } + widthDetails.add(PdfNumber(glyph.width)); + if (i + 1 == glyphInfo.length) { + array.add(PdfNumber(firstGlyphIndex)); + array.add(widthDetails); + } + lastGlyphIndex = glyph.index; + } + } + return array; + } + + void _generateCmap() { + if (_usedChars != null && _usedChars!.isNotEmpty) { + final Map glyphChars = reader.getGlyphChars(_usedChars!); + if (glyphChars.isNotEmpty) { + final List keys = glyphChars.keys.toList(); + keys.sort(); + final int first = keys[0]; + final int last = keys[keys.length - 1]; + final String middlePart = + _getHexString(first, false) + + _getHexString(last, false) + + PdfOperators.newLine; + String builder = ''; + builder += _cmapPrefix; + builder += middlePart; + builder += _cmapEndCodespaceRange; + int nextRange = 0; + for (int i = 0; i < keys.length; i++) { + if (nextRange == 0) { + if (i != 0) { + builder += _cmapEndRange; + } + nextRange = 100 <= keys.length - i ? 100 : keys.length - i; + builder += nextRange.toString(); + builder += PdfOperators.whiteSpace; + builder += _cmapBeginRange; + } + nextRange -= 1; + final int key = keys[i]; + builder += + '${_getHexString(key, true)}${_getHexString(key, true)}${_getHexString(glyphChars[key]!, true)}\n'; + } + builder += _cmapSuffix; + _cmap!.clearStream(); + _cmap!.write(builder); + } + } + } + + void _createFontProgram() { + _fontProgram!.beginSave = _fontProgramBeginSave; + } + + void _fontProgramBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + _generateFontProgram(); + } + + void _generateFontProgram() { + List? fontProgram; + _usedChars ??= []; + reader.currentOffset = 0; + fontProgram = reader.readFontProgram(_usedChars!); + _fontProgram!.clearStream(); + _fontProgram!.write(fontProgram); + } + + String _getHexString(int n, bool isCaseChange) { + String s = n.toRadixString(16); + if (isCaseChange) { + s = s.toUpperCase(); + } + return '${'<0000'.substring(0, 5 - s.length)}$s>'; + } + + /// internal method + double getLineWidth(String line) { + double width = 0; + for (int i = 0; i < line.length; i++) { + width += reader.getCharWidth(line[i]); + } + return width; + } + + /// internal method + void setSymbols(String text, List? usedChars) { + _usedChars ??= []; + if (usedChars != null && usedChars.isNotEmpty) { + _surrogateChars ??= []; + for (final String surrogateChar in usedChars) { + if (!_surrogateChars!.contains(surrogateChar)) { + _surrogateChars!.add(surrogateChar); + _usedChars!.add(surrogateChar[0]); + _usedChars!.add(surrogateChar[1]); + } + } + } + for (int i = 0; i < text.length; i++) { + if (!_usedChars!.contains(text[i])) { + _usedChars!.add(text[i]); + } + } + _getDescendantWidth(); + } + + /// internal method + double getCharWidth(String charCode) { + return reader.getCharWidth(charCode); + } + + /// internal method + void initializeCidSet() { + _cidStream = PdfStream(); + _cidStream!.beginSave = _cidBeginSave; + _fontDescriptor!.beginSave = _fontDescriptorBeginSave; + } + + //Runs before Cid will be saved. + void _cidBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + _generateCidSet(); + } + + //Runs before font Dictionary will be saved. + void _fontDescriptorBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if ((_usedChars != null && _usedChars!.isNotEmpty) && + !_fontDescriptor!.containsKey(PdfDictionaryProperties.cidSet)) { + _fontDescriptor![PdfDictionaryProperties.cidSet] = PdfReferenceHolder( + _cidStream, + ); + } + } + + //This is important for PDF/A conformance validation + void _generateCidSet() { + final List dummyBits = [ + 0x80, + 0x40, + 0x20, + 0x10, + 0x08, + 0x04, + 0x02, + 0x01, + ]; + if (_usedChars != null && _usedChars!.isNotEmpty) { + final Map glyphChars = reader.getGlyphChars(_usedChars!); + List? charBytes; + if (glyphChars.isNotEmpty) { + final List cidChars = glyphChars.keys.toList(); + cidChars.sort(); + final int last = cidChars[cidChars.length - 1]; + charBytes = List.filled((last ~/ 8) + 1, 0, growable: true); + charBytes.fillRange(0, (last ~/ 8) + 1, 0); + for (int i = 0; i < cidChars.length; i++) { + final int cid = cidChars[i]; + charBytes[cid ~/ 8] |= dummyBits[cid % 8]; + } + } + _cidStream!.write(charBytes); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/image_decoder.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/image_decoder.dart index 8d9044d54..3878737bb 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/image_decoder.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/image_decoder.dart @@ -1,155 +1,155 @@ -import '../../../primitives/pdf_stream.dart'; -import '../enum.dart'; -import 'jpeg_decoder.dart'; -import 'png_decoder.dart'; - -/// internal class -abstract class ImageDecoder { - //Fields - /// internal field - late List imageData; - - /// internal field - int width = 0; - - /// internal field - int height = 0; - - /// internal field - ImageType? format; - - /// internal field - late int offset; - - /// internal field - int? bitsPerComponent; - - /// internal field - double? jpegDecoderOrientationAngle; - - //Static methods - /// internal method - static ImageDecoder? getDecoder(List data) { - ImageDecoder? decoder; - if (_isPng(data)) { - decoder = PngDecoder(data, _pngSignature.length); - } else if (_isJpeg(data)) { - decoder = JpegDecoder(data); - } - return decoder; - } - - //Implementation - /// internal method - int readByte() { - if (offset < imageData.length) { - final int value = imageData[offset]; - offset = offset + 1; - return value; - } else { - throw RangeError('invalid offset'); - } - } - - /// internal method - void reset() { - offset = 0; - } - - /// internal method - void seek(int increment) { - offset = offset + increment; - } - - /// internal method - List readBytes(int count) { - final List value = []; - for (int i = 0; i < count; i++) { - value.add(readByte()); - } - return value; - } - - /// internal method - int readUInt16(List data, int offset) { - final int i1 = data[offset]; - final int i2 = data[offset + 1]; - return (i1 << 8) | i2; - } - - /// internal method - int readUInt32(List data, int offset) { - final int i1 = data[offset + 3]; - final int i2 = data[offset + 2]; - final int i3 = data[offset + 1]; - final int i4 = data[offset]; - return i1 | (i2 << 8) | (i3 << 16) | (i4 << 24); - } - - /// internal method - String readString(List? imageData, int len) { - String result = ''; - for (int i = 0; i < len; i++) { - result += String.fromCharCode(readByte()); - } - return result; - } - - /// internal method - Map read( - List stream, - int? streamOffset, - List? buffer, - int length, - ) { - int result = 0; - if (length <= stream.length && stream.length - streamOffset! >= length) { - for (int i = 0; i < length; i++) { - buffer![i] = stream[streamOffset!]; - streamOffset++; - result++; - } - } - return { - 'offset': streamOffset, - 'outputBuffer': buffer, - 'length': result, - }; - } - - //Abstract methods - /// internal method - void readHeader(); - - /// internal method - PdfStream? getImageDictionary(); - - //Utilities - static const List _jpegSignature = [255, 216]; - static const List _pngSignature = [137, 80, 78, 71, 13, 10, 26, 10]; - static bool _isPng(List imageData) { - if (imageData.length >= _pngSignature.length) { - for (int i = 0; i < _pngSignature.length; i++) { - if (_pngSignature[i] != imageData[i]) { - return false; - } - } - return true; - } else { - return false; - } - } - - static bool _isJpeg(List imageData) { - if (imageData.length >= _jpegSignature.length) { - for (int i = 0; i < _jpegSignature.length; i++) { - if (_jpegSignature[i] != imageData[i]) { - return false; - } - } - return true; - } else { - return false; - } - } -} +import '../../../primitives/pdf_stream.dart'; +import '../enum.dart'; +import 'jpeg_decoder.dart'; +import 'png_decoder.dart'; + +/// internal class +abstract class ImageDecoder { + //Fields + /// internal field + late List imageData; + + /// internal field + int width = 0; + + /// internal field + int height = 0; + + /// internal field + ImageType? format; + + /// internal field + late int offset; + + /// internal field + int? bitsPerComponent; + + /// internal field + double? jpegDecoderOrientationAngle; + + //Static methods + /// internal method + static ImageDecoder? getDecoder(List data) { + ImageDecoder? decoder; + if (_isPng(data)) { + decoder = PngDecoder(data, _pngSignature.length); + } else if (_isJpeg(data)) { + decoder = JpegDecoder(data); + } + return decoder; + } + + //Implementation + /// internal method + int readByte() { + if (offset < imageData.length) { + final int value = imageData[offset]; + offset = offset + 1; + return value; + } else { + throw RangeError('invalid offset'); + } + } + + /// internal method + void reset() { + offset = 0; + } + + /// internal method + void seek(int increment) { + offset = offset + increment; + } + + /// internal method + List readBytes(int count) { + final List value = []; + for (int i = 0; i < count; i++) { + value.add(readByte()); + } + return value; + } + + /// internal method + int readUInt16(List data, int offset) { + final int i1 = data[offset]; + final int i2 = data[offset + 1]; + return (i1 << 8) | i2; + } + + /// internal method + int readUInt32(List data, int offset) { + final int i1 = data[offset + 3]; + final int i2 = data[offset + 2]; + final int i3 = data[offset + 1]; + final int i4 = data[offset]; + return i1 | (i2 << 8) | (i3 << 16) | (i4 << 24); + } + + /// internal method + String readString(List? imageData, int len) { + String result = ''; + for (int i = 0; i < len; i++) { + result += String.fromCharCode(readByte()); + } + return result; + } + + /// internal method + Map read( + List stream, + int? streamOffset, + List? buffer, + int length, + ) { + int result = 0; + if (length <= stream.length && stream.length - streamOffset! >= length) { + for (int i = 0; i < length; i++) { + buffer![i] = stream[streamOffset!]; + streamOffset++; + result++; + } + } + return { + 'offset': streamOffset, + 'outputBuffer': buffer, + 'length': result, + }; + } + + //Abstract methods + /// internal method + void readHeader(); + + /// internal method + PdfStream? getImageDictionary(); + + //Utilities + static const List _jpegSignature = [255, 216]; + static const List _pngSignature = [137, 80, 78, 71, 13, 10, 26, 10]; + static bool _isPng(List imageData) { + if (imageData.length >= _pngSignature.length) { + for (int i = 0; i < _pngSignature.length; i++) { + if (_pngSignature[i] != imageData[i]) { + return false; + } + } + return true; + } else { + return false; + } + } + + static bool _isJpeg(List imageData) { + if (imageData.length >= _jpegSignature.length) { + for (int i = 0; i < _jpegSignature.length; i++) { + if (_jpegSignature[i] != imageData[i]) { + return false; + } + } + return true; + } else { + return false; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/jpeg_decoder.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/jpeg_decoder.dart index c03d15622..79e560864 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/jpeg_decoder.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/jpeg_decoder.dart @@ -1,390 +1,390 @@ -import 'dart:convert'; - -import '../../../io/pdf_constants.dart'; -import '../../../primitives/pdf_boolean.dart'; -import '../../../primitives/pdf_dictionary.dart'; -import '../../../primitives/pdf_name.dart'; -import '../../../primitives/pdf_number.dart'; -import '../../../primitives/pdf_stream.dart'; -import '../enum.dart'; -import 'image_decoder.dart'; - -/// internal class -class JpegDecoder extends ImageDecoder { - //Constructors - /// internal constructor - JpegDecoder(List imageData) { - _isContainsLittleEndian = false; - this.imageData = List.from(imageData); - format = ImageType.jpeg; - readHeader(); - } - - //Constants - /// internal field - final List jpegSegmentPreambleBytes = [ - 104, - 116, - 116, - 112, - 58, - 47, - 47, - 110, - 115, - 46, - 97, - 100, - 111, - 98, - 101, - 46, - 99, - 111, - 109, - 47, - 120, - 97, - 112, - 47, - 49, - 46, - 48, - 47, - 0, - ]; - - //Fields - PdfStream? _imageStream; - late bool _isContainsLittleEndian; - int? _noOfComponents = -1; - - //Implementation - @override - void readHeader() { - reset(); - bitsPerComponent = 8; - int? imageOrientation = 0; - final Map returnValue = _checkForExifData(); - final bool hasOrientation = returnValue['hasOrientation'] as bool; - imageOrientation = returnValue['imageOrientation'] as int?; - jpegDecoderOrientationAngle = 0; - if (hasOrientation) { - switch (imageOrientation) { - case 3: - jpegDecoderOrientationAngle = 180; - break; - case 6: - jpegDecoderOrientationAngle = 90; - break; - case 8: - jpegDecoderOrientationAngle = 270; - break; - default: - jpegDecoderOrientationAngle = 0; - break; - } - } - reset(); - bitsPerComponent = 8; - int i = 4; - bool isLengthExceed = false; - int length = imageData[i] * 256 + imageData[i + 1]; - while (i < imageData.length) { - i += length; - if (i < imageData.length) { - if (imageData[i + 1] == 192) { - width = imageData[i + 7] * 256 + imageData[i + 8]; - height = imageData[i + 5] * 256 + imageData[i + 6]; - _noOfComponents = imageData[i + 9]; - if (width != 0 && height != 0) { - return; - } - } else { - i += 2; - length = imageData[i] * 256 + imageData[i + 1]; - } - } else { - isLengthExceed = true; - break; - } - } - if (isLengthExceed) { - reset(); - seek(2); - _readExceededJpegImage(); - } - } - - @override - PdfStream? getImageDictionary() { - _imageStream = PdfStream(); - _imageStream!.data = imageData; - _imageStream!.compress = false; - - _imageStream![PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.xObject, - ); - _imageStream![PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.image, - ); - _imageStream![PdfDictionaryProperties.width] = PdfNumber(width); - _imageStream![PdfDictionaryProperties.height] = PdfNumber(height); - _imageStream![PdfDictionaryProperties.bitsPerComponent] = PdfNumber( - bitsPerComponent!, - ); - _imageStream![PdfDictionaryProperties.filter] = PdfName( - PdfDictionaryProperties.dctDecode, - ); - _imageStream![PdfDictionaryProperties.colorSpace] = PdfName( - _getColorSpace(), - ); - _imageStream![PdfDictionaryProperties.decodeParms] = _getDecodeParams(); - - return _imageStream; - } - - PdfDictionary _getDecodeParams() { - final PdfDictionary decodeParams = PdfDictionary(); - decodeParams[PdfDictionaryProperties.columns] = PdfNumber(width); - decodeParams[PdfDictionaryProperties.blackIs1] = PdfBoolean(true); - decodeParams[PdfDictionaryProperties.k] = PdfNumber(-1); - decodeParams[PdfDictionaryProperties.predictor] = PdfNumber(15); - decodeParams[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( - bitsPerComponent!, - ); - return decodeParams; - } - - Map _checkForExifData() { - int? imageOrientation = 0; - reset(); - if (_convertToUShort(_readJpegBytes(2)) != 0xFFD8) { - return { - 'hasOrientation': false, - 'imageOrientation': imageOrientation, - }; - } - int? jpegMarkerStart; - int? jpegMarkerNum = 0; - while ((jpegMarkerStart = readByte()) == 0xFF && - (jpegMarkerNum = readByte()) != 0xE1) { - final int jpegDataLength = _convertToUShort(_readJpegBytes(2)); - final int jpegOffset = jpegDataLength - 2; - final int jpegPosition = offset + jpegOffset; - seek(jpegOffset); - if (offset != jpegPosition || offset > imageData.length) { - return { - 'hasOrientation': false, - 'imageOrientation': imageOrientation, - }; - } - } - if (jpegMarkerStart != 0xFF || jpegMarkerNum != 0xE1) { - return { - 'hasOrientation': false, - 'imageOrientation': imageOrientation, - }; - } else { - seek(2); - if (utf8.decode(_readJpegBytes(4)) != 'Exif' || - _convertToUShort(_readJpegBytes(2)) != 0) { - return { - 'hasOrientation': false, - 'imageOrientation': imageOrientation, - }; - } - final int tiffTypeHeaderStart = offset; - final List byteData = _readJpegBytes(2); - _isContainsLittleEndian = utf8.decode(byteData) == 'II'; - if (_convertToUShort(_readJpegBytes(2)) != 0x002A) { - return { - 'hasOrientation': false, - 'imageOrientation': imageOrientation, - }; - } - offset = _convertToUInt(_readJpegBytes(4)) + tiffTypeHeaderStart; - final int ifdEntryCount = _convertToUShort(_readJpegBytes(2)); - int orientationPosition = 0; - for ( - int currentIfdEntry = 0; - currentIfdEntry < ifdEntryCount; - currentIfdEntry++ - ) { - if (_convertToUShort(_readJpegBytes(2)) == 274) { - orientationPosition = offset - 2; - } - seek(10); - } - if (orientationPosition >= 0) { - offset = orientationPosition; - if (_convertToUShort(_readJpegBytes(2)) != 274) { - return { - 'hasOrientation': false, - 'imageOrientation': imageOrientation, - }; - } - seek(6); - final List orientationData = _readJpegBytes(4); - int? orientationAngle = 0; - for (int i = 0; i < orientationData.length; i++) { - if (orientationData[i] != 0) { - orientationAngle = orientationData[i]; - break; - } - } - if (orientationAngle == 0) { - return { - 'hasOrientation': false, - 'imageOrientation': imageOrientation, - }; - } else { - imageOrientation = orientationAngle; - } - } - } - return { - 'hasOrientation': true, - 'imageOrientation': imageOrientation, - }; - } - - void _readExceededJpegImage() { - bool isContinueReading = true; - while (isContinueReading) { - final int marker = _getMarker(); - switch (marker) { - case 0x00C0: - case 0x00C1: - case 0x00C2: - case 0x00C3: - case 0x00C5: - case 0x00C6: - case 0x00C7: - case 0x00C9: - case 0x00CA: - case 0x00CB: - case 0x00CD: - case 0x00CE: - case 0x00CF: - seek(3); - height = imageData[offset] << 8 | imageData[offset + 1]; - seek(2); - width = imageData[offset] << 8 | imageData[offset + 1]; - _noOfComponents = imageData[offset + 2]; - seek(1); - isContinueReading = false; - break; - default: - _skipStream(); - break; - } - } - } - - int _convertToUShort(List data) { - if (_isContainsLittleEndian) { - data = List.from(data.reversed); - } - return readUInt16(data, 0); - } - - int _convertToUInt(List data) { - if (_isContainsLittleEndian) { - data = List.from(data.reversed); - } - return readUInt32(data, 0); - } - - List _readJpegBytes(int byteCount) { - final List value = readBytes(byteCount); - if (value.length != byteCount) { - throw RangeError('Invalid count'); - } - return value; - } - - int _getMarker() { - int skippedByte = 0; - int? marker = readByte(); - while (marker != 255) { - skippedByte++; - marker = readByte(); - } - do { - marker = readByte(); - } while (marker == 255); - if (skippedByte != 0) { - throw UnsupportedError('Error decoding JPEG image'); - } - return marker.toUnsigned(16); - } - - void _skipStream() { - final int length = imageData[offset] << 8 | imageData[offset + 1]; - seek(2); - if (length < 2) { - throw UnsupportedError('Error decoding JPEG image'); - } else if (length > 0) { - seek(length - 2); - } - } - - String _getColorSpace() { - const String colorSpace = PdfDictionaryProperties.deviceRGB; - if (_noOfComponents == 1 || _noOfComponents == 3 || _noOfComponents == 4) { - switch (_noOfComponents) { - case 1: - return PdfDictionaryProperties.deviceGray; - case 3: - return PdfDictionaryProperties.deviceRGB; - case 4: - return PdfDictionaryProperties.deviceCMYK; - } - } else { - int i = 0; - const int step = 2; - final int soi = _convertToUShort([imageData[i + 1], imageData[i]]); - if (soi == 0xD8FF) { - i += step; - int jfif = _convertToUShort([imageData[i + 1], imageData[i]]); - jfif &= 0xF0FF; - if (jfif == 0xE0FF) { - while (true) { - i += step; - int markerLength = _convertToUShort([ - imageData[i + 1], - imageData[i], - ]).toSigned(32); - markerLength = (markerLength >> 8) | (markerLength << 8) & 0xFFFF; - i += markerLength; - final int marker = _convertToUShort([ - imageData[i + 1], - imageData[i], - ]); - if (marker == 0xDAFF) { - i += step + 2; - switch (imageData[i]) { - case 1: - String result; - if (bitsPerComponent == 8) { - result = colorSpace; - } else { - result = PdfDictionaryProperties.deviceGray; - } - return result; - case 3: - return colorSpace; - case 4: - return PdfDictionaryProperties.deviceCMYK; - } - } else if (marker == 0xD9FF) { - break; - } - } - } - } - } - return colorSpace; - } -} +import 'dart:convert'; + +import '../../../io/pdf_constants.dart'; +import '../../../primitives/pdf_boolean.dart'; +import '../../../primitives/pdf_dictionary.dart'; +import '../../../primitives/pdf_name.dart'; +import '../../../primitives/pdf_number.dart'; +import '../../../primitives/pdf_stream.dart'; +import '../enum.dart'; +import 'image_decoder.dart'; + +/// internal class +class JpegDecoder extends ImageDecoder { + //Constructors + /// internal constructor + JpegDecoder(List imageData) { + _isContainsLittleEndian = false; + this.imageData = List.from(imageData); + format = ImageType.jpeg; + readHeader(); + } + + //Constants + /// internal field + final List jpegSegmentPreambleBytes = [ + 104, + 116, + 116, + 112, + 58, + 47, + 47, + 110, + 115, + 46, + 97, + 100, + 111, + 98, + 101, + 46, + 99, + 111, + 109, + 47, + 120, + 97, + 112, + 47, + 49, + 46, + 48, + 47, + 0, + ]; + + //Fields + PdfStream? _imageStream; + late bool _isContainsLittleEndian; + int? _noOfComponents = -1; + + //Implementation + @override + void readHeader() { + reset(); + bitsPerComponent = 8; + int? imageOrientation = 0; + final Map returnValue = _checkForExifData(); + final bool hasOrientation = returnValue['hasOrientation'] as bool; + imageOrientation = returnValue['imageOrientation'] as int?; + jpegDecoderOrientationAngle = 0; + if (hasOrientation) { + switch (imageOrientation) { + case 3: + jpegDecoderOrientationAngle = 180; + break; + case 6: + jpegDecoderOrientationAngle = 90; + break; + case 8: + jpegDecoderOrientationAngle = 270; + break; + default: + jpegDecoderOrientationAngle = 0; + break; + } + } + reset(); + bitsPerComponent = 8; + int i = 4; + bool isLengthExceed = false; + int length = imageData[i] * 256 + imageData[i + 1]; + while (i < imageData.length) { + i += length; + if (i < imageData.length) { + if (imageData[i + 1] == 192) { + width = imageData[i + 7] * 256 + imageData[i + 8]; + height = imageData[i + 5] * 256 + imageData[i + 6]; + _noOfComponents = imageData[i + 9]; + if (width != 0 && height != 0) { + return; + } + } else { + i += 2; + length = imageData[i] * 256 + imageData[i + 1]; + } + } else { + isLengthExceed = true; + break; + } + } + if (isLengthExceed) { + reset(); + seek(2); + _readExceededJpegImage(); + } + } + + @override + PdfStream? getImageDictionary() { + _imageStream = PdfStream(); + _imageStream!.data = imageData; + _imageStream!.compress = false; + + _imageStream![PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.xObject, + ); + _imageStream![PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.image, + ); + _imageStream![PdfDictionaryProperties.width] = PdfNumber(width); + _imageStream![PdfDictionaryProperties.height] = PdfNumber(height); + _imageStream![PdfDictionaryProperties.bitsPerComponent] = PdfNumber( + bitsPerComponent!, + ); + _imageStream![PdfDictionaryProperties.filter] = PdfName( + PdfDictionaryProperties.dctDecode, + ); + _imageStream![PdfDictionaryProperties.colorSpace] = PdfName( + _getColorSpace(), + ); + _imageStream![PdfDictionaryProperties.decodeParms] = _getDecodeParams(); + + return _imageStream; + } + + PdfDictionary _getDecodeParams() { + final PdfDictionary decodeParams = PdfDictionary(); + decodeParams[PdfDictionaryProperties.columns] = PdfNumber(width); + decodeParams[PdfDictionaryProperties.blackIs1] = PdfBoolean(true); + decodeParams[PdfDictionaryProperties.k] = PdfNumber(-1); + decodeParams[PdfDictionaryProperties.predictor] = PdfNumber(15); + decodeParams[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( + bitsPerComponent!, + ); + return decodeParams; + } + + Map _checkForExifData() { + int? imageOrientation = 0; + reset(); + if (_convertToUShort(_readJpegBytes(2)) != 0xFFD8) { + return { + 'hasOrientation': false, + 'imageOrientation': imageOrientation, + }; + } + int? jpegMarkerStart; + int? jpegMarkerNum = 0; + while ((jpegMarkerStart = readByte()) == 0xFF && + (jpegMarkerNum = readByte()) != 0xE1) { + final int jpegDataLength = _convertToUShort(_readJpegBytes(2)); + final int jpegOffset = jpegDataLength - 2; + final int jpegPosition = offset + jpegOffset; + seek(jpegOffset); + if (offset != jpegPosition || offset > imageData.length) { + return { + 'hasOrientation': false, + 'imageOrientation': imageOrientation, + }; + } + } + if (jpegMarkerStart != 0xFF || jpegMarkerNum != 0xE1) { + return { + 'hasOrientation': false, + 'imageOrientation': imageOrientation, + }; + } else { + seek(2); + if (utf8.decode(_readJpegBytes(4)) != 'Exif' || + _convertToUShort(_readJpegBytes(2)) != 0) { + return { + 'hasOrientation': false, + 'imageOrientation': imageOrientation, + }; + } + final int tiffTypeHeaderStart = offset; + final List byteData = _readJpegBytes(2); + _isContainsLittleEndian = utf8.decode(byteData) == 'II'; + if (_convertToUShort(_readJpegBytes(2)) != 0x002A) { + return { + 'hasOrientation': false, + 'imageOrientation': imageOrientation, + }; + } + offset = _convertToUInt(_readJpegBytes(4)) + tiffTypeHeaderStart; + final int ifdEntryCount = _convertToUShort(_readJpegBytes(2)); + int orientationPosition = 0; + for ( + int currentIfdEntry = 0; + currentIfdEntry < ifdEntryCount; + currentIfdEntry++ + ) { + if (_convertToUShort(_readJpegBytes(2)) == 274) { + orientationPosition = offset - 2; + } + seek(10); + } + if (orientationPosition >= 0) { + offset = orientationPosition; + if (_convertToUShort(_readJpegBytes(2)) != 274) { + return { + 'hasOrientation': false, + 'imageOrientation': imageOrientation, + }; + } + seek(6); + final List orientationData = _readJpegBytes(4); + int? orientationAngle = 0; + for (int i = 0; i < orientationData.length; i++) { + if (orientationData[i] != 0) { + orientationAngle = orientationData[i]; + break; + } + } + if (orientationAngle == 0) { + return { + 'hasOrientation': false, + 'imageOrientation': imageOrientation, + }; + } else { + imageOrientation = orientationAngle; + } + } + } + return { + 'hasOrientation': true, + 'imageOrientation': imageOrientation, + }; + } + + void _readExceededJpegImage() { + bool isContinueReading = true; + while (isContinueReading) { + final int marker = _getMarker(); + switch (marker) { + case 0x00C0: + case 0x00C1: + case 0x00C2: + case 0x00C3: + case 0x00C5: + case 0x00C6: + case 0x00C7: + case 0x00C9: + case 0x00CA: + case 0x00CB: + case 0x00CD: + case 0x00CE: + case 0x00CF: + seek(3); + height = imageData[offset] << 8 | imageData[offset + 1]; + seek(2); + width = imageData[offset] << 8 | imageData[offset + 1]; + _noOfComponents = imageData[offset + 2]; + seek(1); + isContinueReading = false; + break; + default: + _skipStream(); + break; + } + } + } + + int _convertToUShort(List data) { + if (_isContainsLittleEndian) { + data = List.from(data.reversed); + } + return readUInt16(data, 0); + } + + int _convertToUInt(List data) { + if (_isContainsLittleEndian) { + data = List.from(data.reversed); + } + return readUInt32(data, 0); + } + + List _readJpegBytes(int byteCount) { + final List value = readBytes(byteCount); + if (value.length != byteCount) { + throw RangeError('Invalid count'); + } + return value; + } + + int _getMarker() { + int skippedByte = 0; + int? marker = readByte(); + while (marker != 255) { + skippedByte++; + marker = readByte(); + } + do { + marker = readByte(); + } while (marker == 255); + if (skippedByte != 0) { + throw UnsupportedError('Error decoding JPEG image'); + } + return marker.toUnsigned(16); + } + + void _skipStream() { + final int length = imageData[offset] << 8 | imageData[offset + 1]; + seek(2); + if (length < 2) { + throw UnsupportedError('Error decoding JPEG image'); + } else if (length > 0) { + seek(length - 2); + } + } + + String _getColorSpace() { + const String colorSpace = PdfDictionaryProperties.deviceRGB; + if (_noOfComponents == 1 || _noOfComponents == 3 || _noOfComponents == 4) { + switch (_noOfComponents) { + case 1: + return PdfDictionaryProperties.deviceGray; + case 3: + return PdfDictionaryProperties.deviceRGB; + case 4: + return PdfDictionaryProperties.deviceCMYK; + } + } else { + int i = 0; + const int step = 2; + final int soi = _convertToUShort([imageData[i + 1], imageData[i]]); + if (soi == 0xD8FF) { + i += step; + int jfif = _convertToUShort([imageData[i + 1], imageData[i]]); + jfif &= 0xF0FF; + if (jfif == 0xE0FF) { + while (true) { + i += step; + int markerLength = _convertToUShort([ + imageData[i + 1], + imageData[i], + ]).toSigned(32); + markerLength = (markerLength >> 8) | (markerLength << 8) & 0xFFFF; + i += markerLength; + final int marker = _convertToUShort([ + imageData[i + 1], + imageData[i], + ]); + if (marker == 0xDAFF) { + i += step + 2; + switch (imageData[i]) { + case 1: + String result; + if (bitsPerComponent == 8) { + result = colorSpace; + } else { + result = PdfDictionaryProperties.deviceGray; + } + return result; + case 3: + return colorSpace; + case 4: + return PdfDictionaryProperties.deviceCMYK; + } + } else if (marker == 0xD9FF) { + break; + } + } + } + } + } + return colorSpace; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/png_decoder.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/png_decoder.dart index f29f5aba0..6d2a5317f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/png_decoder.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/decoders/png_decoder.dart @@ -1,820 +1,820 @@ -import '../../../../interfaces/pdf_interface.dart'; -import '../../../compression/deflate/deflate_stream.dart'; -import '../../../io/pdf_constants.dart'; -import '../../../primitives/pdf_array.dart'; -import '../../../primitives/pdf_dictionary.dart'; -import '../../../primitives/pdf_name.dart'; -import '../../../primitives/pdf_number.dart'; -import '../../../primitives/pdf_reference_holder.dart'; -import '../../../primitives/pdf_stream.dart'; -import '../../../primitives/pdf_string.dart'; -import '../enum.dart'; -import 'image_decoder.dart'; - -/// internal class -class PngDecoder extends ImageDecoder { - /// internal constructor - PngDecoder(List imageData, int offset) { - this.imageData = List.from(imageData); - format = ImageType.png; - _issRGB = false; - isDecode = false; - _shades = false; - _ideateDecode = true; - _colors = 0; - _bitsPerPixel = 0; - _idatLength = 0; - _inputBands = 0; - this.offset = offset; - _initialize(); - jpegDecoderOrientationAngle = 0; - } - - //Fields - late int _currentChunkLength; - late _PngHeader _header; - late bool _issRGB; - late bool _shades; - late bool _ideateDecode; - late int _colors; - late int _bitsPerPixel; - late int _idatLength; - late int _inputBands; - List? _maskData; - late List _alpha; - List? _iDatStream; - late List _dataStream; - int? _dataStreamOffset; - List? _decodedImageData; - - /// internal field - PdfArray? colorSpace; - - /// internal field - late bool isDecode; - - //Implementation - void _initialize() { - _PngChunkTypes? header; - dynamic result = _hasValidChunkType(header); - while (result['hasValidChunk'] as bool) { - header = result['type'] as _PngChunkTypes?; - switch (header) { - case _PngChunkTypes.iHDR: - readHeader(); - break; - case _PngChunkTypes.iDAT: - _readImageData(); - break; - case _PngChunkTypes.sRGB: - _issRGB = true; - _ignoreChunk(); - break; - case _PngChunkTypes.pLTE: - _readPLTE(); - break; - case _PngChunkTypes.iEND: - _decodeImageData(); - break; - case _PngChunkTypes.tRNS: - _readTRNS(); - break; - case _PngChunkTypes.tEXt: - case _PngChunkTypes.iTXt: - case _PngChunkTypes.zTXt: - case _PngChunkTypes.hIST: - case _PngChunkTypes.sBIT: - case _PngChunkTypes.iCCP: - case _PngChunkTypes.pHYs: - case _PngChunkTypes.tIME: - case _PngChunkTypes.bKGD: - case _PngChunkTypes.gAMA: - case _PngChunkTypes.cHRM: - case _PngChunkTypes.unknown: - _ignoreChunk(); - break; - // ignore: no_default_cases - default: - break; - } - result = _hasValidChunkType(header); - } - } - - Map _hasValidChunkType(_PngChunkTypes? type) { - type = _PngChunkTypes.unknown; - if (offset + 8 <= imageData.length) { - _currentChunkLength = readUInt32(imageData, offset); - seek(4); - final String chunk = readString(imageData, 4); - final _PngChunkTypes? header = _getChunkType(chunk); - if (header != null) { - type = header; - return {'type': type, 'hasValidChunk': true}; - } - if (imageData.length == offset) { - return {'type': type, 'hasValidChunk': false}; - } else { - return {'type': type, 'hasValidChunk': true}; - } - } else { - return {'type': type, 'hasValidChunk': false}; - } - } - - _PngChunkTypes? _getChunkType(String chunk) { - switch (chunk) { - case 'IHDR': - return _PngChunkTypes.iHDR; - case 'PLTE': - return _PngChunkTypes.pLTE; - case 'IDAT': - return _PngChunkTypes.iDAT; - case 'IEND': - return _PngChunkTypes.iEND; - case 'bKGD': - return _PngChunkTypes.bKGD; - case 'cHRM': - return _PngChunkTypes.cHRM; - case 'gAMA': - return _PngChunkTypes.gAMA; - case 'hIST': - return _PngChunkTypes.hIST; - case 'pHYs': - return _PngChunkTypes.pHYs; - case 'sBIT': - return _PngChunkTypes.sBIT; - case 'tEXt': - return _PngChunkTypes.tEXt; - case 'tIME': - return _PngChunkTypes.tIME; - case 'tRNS': - return _PngChunkTypes.tRNS; - case 'zTXt': - return _PngChunkTypes.zTXt; - case 'sRGB': - return _PngChunkTypes.sRGB; - case 'iCCP': - return _PngChunkTypes.iCCP; - case 'iTXt': - return _PngChunkTypes.iTXt; - case 'Unknown': - return _PngChunkTypes.unknown; - default: - return null; - } - } - - _PngFilterTypes _getFilterType(int? type) { - switch (type) { - case 1: - return _PngFilterTypes.sub; - case 2: - return _PngFilterTypes.up; - case 3: - return _PngFilterTypes.average; - case 4: - return _PngFilterTypes.paeth; - default: - return _PngFilterTypes.none; - } - } - - void _initializeBase() { - width = _header.width; - height = _header.height; - bitsPerComponent = _header.bitDepth; - } - - void _setBitsPerPixel() { - _bitsPerPixel = _header.bitDepth == 16 ? 2 : 1; - if (_header.colorType == 0) { - _idatLength = ((bitsPerComponent! * width + 7) / 8 * height).toInt(); - _inputBands = 1; - } else if (_header.colorType == 2) { - _idatLength = width * height * 3; - _inputBands = 3; - _bitsPerPixel *= 3; - } else if (_header.colorType == 3) { - if (_header.interlace == 1) { - _idatLength = ((_header.bitDepth * width + 7) / 8 * height).toInt(); - } - _inputBands = 1; - _bitsPerPixel = 1; - } else if (_header.colorType == 4) { - _idatLength = width * height; - _inputBands = 2; - _bitsPerPixel *= 2; - } else if (_header.colorType == 6) { - _idatLength = width * 3 * height; - _inputBands = 4; - _bitsPerPixel *= 4; - } - } - - void _ignoreChunk() { - if (_currentChunkLength > 0) { - seek(_currentChunkLength + 4); - } - } - - void _readImageData() { - _iDatStream ??= []; - if (_currentChunkLength <= imageData.length && - imageData.length - offset >= _currentChunkLength) { - for (int i = 0; i < _currentChunkLength; i++) { - _iDatStream!.add(imageData[offset]); - offset = offset + 1; - } - } - seek(4); - } - - void _decodeImageData() { - isDecode = - (_header.interlace == 1) || - (_header.bitDepth == 16) || - ((_header.colorType & 4) != 0) || - _shades; - if (isDecode) { - if ((_header.colorType & 4) != 0 || _shades) { - final int length = width * height; - _maskData = []; - for (int i = 0; i < length; i++) { - _maskData!.add(0); - } - } - if (_iDatStream != null) { - _dataStream = _getDeflatedData(_iDatStream!); - _dataStreamOffset = 0; - } - _decodedImageData = List.filled(_idatLength, 0, growable: true); - _readDecodeData(); - - if (_decodedImageData != null && _decodedImageData!.isEmpty && _shades) { - _ideateDecode = false; - _decodedImageData = _iDatStream!.toList(growable: true); - } - } else { - _ideateDecode = false; - _decodedImageData = _iDatStream!.toList(growable: true); - } - } - - List _getDeflatedData(List data) { - final List idatData = data.sublist(2, data.length - 4); - final DeflateStream deflateStream = DeflateStream(idatData, 0, true); - List buffer = List.filled(4096, 0); - int? numRead = 0; - final List outputData = []; - do { - final Map result = deflateStream.read( - buffer, - 0, - buffer.length, - ); - numRead = result['count'] as int?; - buffer = result['data'] as List; - for (int i = 0; i < numRead!; i++) { - outputData.add(buffer[i]); - } - } while (numRead > 0); - return outputData; - } - - void _readDecodeData() { - if (_header.interlace != 1) { - _decodeData(0, 0, 1, 1, width, height); - } else { - _decodeData(0, 0, 8, 8, (width + 7) ~/ 8, (height + 7) ~/ 8); - _decodeData(4, 0, 8, 8, (width + 3) ~/ 8, (height + 7) ~/ 8); - _decodeData(0, 4, 4, 8, (width + 3) ~/ 4, (height + 3) ~/ 8); - _decodeData(2, 0, 4, 4, (width + 1) ~/ 4, (height + 3) ~/ 4); - _decodeData(0, 2, 2, 4, (width + 1) ~/ 2, (height + 1) ~/ 4); - _decodeData(1, 0, 2, 2, width ~/ 2, (height + 1) ~/ 2); - _decodeData(0, 1, 1, 2, width, height ~/ 2); - } - } - - void _decodeData( - int xOffset, - int yOffset, - int xStep, - int yStep, - int? width, - int? height, - ) { - if ((width == 0) || (height == 0)) { - return; - } else { - final int bytesPerRow = - (_inputBands * width! * _header.bitDepth + 7) ~/ 8; - List current = List.filled(bytesPerRow, 0); - List prior = List.filled(bytesPerRow, 0); - for ( - int sourceY = 0, destinationY = yOffset; - sourceY < height!; - sourceY++, destinationY += yStep - ) { - final int filter = _dataStream[_dataStreamOffset!]; - _dataStreamOffset = _dataStreamOffset! + 1; - _dataStreamOffset = _readStream( - _dataStream, - _dataStreamOffset, - current, - bytesPerRow, - ); - switch (_getFilterType(filter)) { - case _PngFilterTypes.none: - break; - case _PngFilterTypes.sub: - _decompressSub(current, bytesPerRow, _bitsPerPixel); - break; - case _PngFilterTypes.up: - _decompressUp(current, prior, bytesPerRow); - break; - case _PngFilterTypes.average: - _decompressAverage(current, prior, bytesPerRow, _bitsPerPixel); - break; - case _PngFilterTypes.paeth: - _decompressPaeth(current, prior, bytesPerRow, _bitsPerPixel); - break; - } - _processPixels(current, xOffset, xStep, destinationY, width); - final List tmp = prior; - prior = current; - current = tmp; - } - } - } - - int? _readStream( - List stream, - int? streamOffset, - List? data, - int count, - ) { - final dynamic result = read(stream, streamOffset, data, count); - data = result['outputBuffer'] as List?; - streamOffset = result['offset'] as int?; - final int n = result['length'] as int; - if (n <= 0) { - throw Exception('Insufficient data'); - } - return streamOffset; - } - - void _processPixels(List data, int x, int step, int y, int? width) { - int sourceX, destX, size = 0; - final List pixel = _getPixel(data); - if (_header.colorType == 0 || - _header.colorType == 3 || - _header.colorType == 4) { - size = 1; - } else if (_header.colorType == 2 || _header.colorType == 6) { - size = 3; - } - if (_decodedImageData != null && _decodedImageData!.isNotEmpty) { - destX = x; - final int depth = (_header.bitDepth == 16) ? 8 : _header.bitDepth; - final int yStep = (size * width! * depth + 7) ~/ 8; - for (sourceX = 0; sourceX < width; sourceX++) { - _decodedImageData = _setPixel( - _decodedImageData, - pixel, - _inputBands * sourceX, - size, - destX, - y, - _header.bitDepth, - yStep, - ); - destX += step; - } - } - final bool shades = (_header.colorType & 4) != 0 || _shades; - if (shades) { - if ((_header.colorType & 4) != 0) { - if (_header.bitDepth == 16) { - for (int i = 0; i < width!; ++i) { - final int temp = i * _inputBands + size; - pixel[temp] = (pixel[temp].toUnsigned(32) >> 8).toSigned(32); - } - } - final int? yStep = width; - destX = x; - for (sourceX = 0; sourceX < width!; sourceX++) { - _maskData = _setPixel( - _maskData, - pixel, - _inputBands * sourceX + size, - 1, - destX, - y, - 8, - yStep, - ); - destX += step; - } - } else { - final int? yStep = width; - final List dt = List.filled(1, 0, growable: true); - destX = x; - for (sourceX = 0; sourceX < width!; sourceX++) { - final int index = pixel[sourceX]; - if (index < _alpha.length) { - dt[0] = _alpha[index]; - } else { - dt[0] = 255; - } - _maskData = _setPixel(_maskData, dt, 0, 1, destX, y, 8, yStep); - destX += step; - } - } - } - } - - List _getPixel(List data) { - if (_header.bitDepth == 8) { - final List pixel = List.filled(data.length, 0, growable: true); - for (int i = 0; i < pixel.length; ++i) { - pixel[i] = data[i] & 0xff; - } - return pixel; - } else if (_header.bitDepth == 16) { - final List pixel = List.filled( - data.length ~/ 2, - 0, - growable: true, - ); - for (int i = 0; i < pixel.length; ++i) { - pixel[i] = ((data[i * 2] & 0xff) << 8) + (data[i * 2 + 1] & 0xff); - } - return pixel; - } else { - final List pixel = List.filled( - data.length * 8 ~/ _header.bitDepth, - 0, - growable: true, - ); - int index = 0; - final int p = 8 ~/ _header.bitDepth; - final int mask = (1 << _header.bitDepth) - 1; - for (int n = 0; n < data.length; ++n) { - for (int i = p - 1; i >= 0; --i) { - final int hb = _header.bitDepth * i; - final int d = data[n]; - pixel[index++] = - ((hb < 1) ? d : (d.toUnsigned(32) >> hb).toSigned(32)) & mask; - } - } - return pixel; - } - } - - List? _setPixel( - List? imageData, - List data, - int offset, - int size, - int x, - int y, - int? bitDepth, - int? bpr, - ) { - if (bitDepth == 8) { - final int position = bpr! * y + size * x; - for (int i = 0; i < size; ++i) { - imageData![position + i] = data[i + offset].toUnsigned(8); - } - } else if (bitDepth == 16) { - final int position = bpr! * y + size * x; - for (int i = 0; i < size; ++i) { - imageData![position + i] = (data[i + offset] >> 8).toUnsigned(8); - } - } else { - final int position = bpr! * y + x ~/ (8 / bitDepth!); - final int t = - data[offset] << - (8 - bitDepth * (x % (8 / bitDepth)) - bitDepth).toInt(); - imageData![position] = imageData[position] | t.toUnsigned(8); - } - return imageData; - } - - void _decompressSub(List data, int count, int bpp) { - for (int i = bpp; i < count; i++) { - int val = 0; - val = data[i] & 0xff; - val += data[i - bpp] & 0xff; - data[i] = val.toUnsigned(8); - } - } - - void _decompressUp(List data, List pData, int count) { - for (int i = 0; i < count; i++) { - data[i] = ((data[i] & 0xff) + (pData[i] & 0xff)).toUnsigned(8); - } - } - - void _decompressAverage(List data, List pData, int count, int bpp) { - int val, pp, pr; - for (int i = 0; i < bpp; i++) { - data[i] = ((data[i] & 0xff) + (pData[i] & 0xff) ~/ 2).toUnsigned(8); - } - for (int i = bpp; i < count; i++) { - val = data[i] & 0xff; - pp = data[i - bpp] & 0xff; - pr = pData[i] & 0xff; - data[i] = (val + (pp + pr) ~/ 2).toUnsigned(8); - } - } - - int _paethPredictor(int a, int b, int c) { - final int p = a + b - c; - final int pa = (p - a).abs(); - final int pb = (p - b).abs(); - final int pc = (p - c).abs(); - if ((pa <= pb) && (pa <= pc)) { - return a; - } else if (pb <= pc) { - return b; - } else { - return c; - } - } - - void _decompressPaeth(List data, List pData, int count, int bpp) { - int val, pp, pr, prp; - for (int i = 0; i < bpp; i++) { - val = data[i] & 0xff; - pr = pData[i] & 0xff; - data[i] = (val + pr).toUnsigned(8); - } - for (int i = bpp; i < count; i++) { - val = data[i] & 0xff; - pp = data[i - bpp] & 0xff; - pr = pData[i] & 0xff; - prp = pData[i - bpp] & 0xff; - data[i] = (val + _paethPredictor(pp, pr, prp)).toUnsigned(8); - } - } - - void _readPLTE() { - if (_header.colorType == 3) { - colorSpace = PdfArray(); - colorSpace!.add(PdfName(PdfDictionaryProperties.indexed)); - colorSpace!.add(_getPngColorSpace()); - colorSpace!.add(PdfNumber(_currentChunkLength / 3 - 1)); - colorSpace!.add(PdfString.fromBytes(readBytes(_currentChunkLength))); - seek(4); - } else { - _ignoreChunk(); - } - } - - void _readTRNS() { - if (_header.colorType == 3) { - final List alpha = readBytes(_currentChunkLength); - seek(4); - _alpha = List.filled(alpha.length, 0, growable: true); - for (int i = 0; i < alpha.length; i++) { - _alpha[i] = alpha[i]; - final int sh = alpha[i] & 0xff; - if (sh != 0 && sh != 255) { - _shades = true; - } - } - } else { - _ignoreChunk(); - } - } - - IPdfPrimitive _getPngColorSpace() { - if (!_issRGB) { - if ((_header.colorType & 2) == 0) { - return PdfName(PdfDictionaryProperties.deviceGray); - } else { - return PdfName(PdfDictionaryProperties.deviceRGB); - } - } else { - final PdfArray colorspace = PdfArray(); - final PdfDictionary calRGB = PdfDictionary(); - PdfArray whitePoint = PdfArray(); - whitePoint.add(PdfNumber(1)); - whitePoint.add(PdfNumber(1)); - whitePoint.add(PdfNumber(1)); - final PdfArray gammaArray = PdfArray(); - gammaArray.add(PdfNumber(2.2)); - gammaArray.add(PdfNumber(2.2)); - gammaArray.add(PdfNumber(2.2)); - calRGB.setProperty(PdfName(PdfDictionaryProperties.gamma), gammaArray); - if (_issRGB) { - const double wpX = 0.3127; - const double wpY = 0.329; - const double redX = 0.64; - const double redY = 0.33; - const double greenX = 0.3; - const double greenY = 0.6; - const double bX = 0.15; - const double bY = 0.06; - const double t = - wpY * - ((greenX - bX) * redY - - (redX - bX) * greenY + - (redX - greenX) * bY); - const double alphaY = - redY * - ((greenX - bX) * wpY - (wpX - bX) * greenY + (wpX - greenX) * bY) / - t; - const double alphaX = alphaY * redX / redY; - const double alphaZ = alphaY * ((1 - redX) / redY - 1); - const double blueY = - -greenY * - ((redX - bX) * wpY - (wpX - bX) * redY + (wpX - redX) * bY) / - t; - const double blueX = blueY * greenX / greenY; - const double blueZ = blueY * ((1 - greenX) / greenY - 1); - const double colorY = - bY * - ((redX - greenX) * wpY - - (wpX - greenX) * wpY + - (wpX - redX) * greenY) / - t; - const double colorX = colorY * bX / bY; - const double colorZ = colorY * ((1 - bX) / bY - 1); - const double whiteX = alphaX + blueX + colorX; - const double whiteY = 1; - const double whiteZ = alphaZ + blueZ + colorZ; - final PdfArray whitePointArray = PdfArray(); - whitePointArray.add(PdfNumber(whiteX)); - whitePointArray.add(PdfNumber(whiteY)); - whitePointArray.add(PdfNumber(whiteZ)); - whitePoint = whitePointArray; - final PdfArray matrix = PdfArray(); - matrix.add(PdfNumber(alphaX)); - matrix.add(PdfNumber(alphaY)); - matrix.add(PdfNumber(alphaZ)); - matrix.add(PdfNumber(blueX)); - matrix.add(PdfNumber(blueY)); - matrix.add(PdfNumber(blueZ)); - matrix.add(PdfNumber(colorX)); - matrix.add(PdfNumber(colorY)); - matrix.add(PdfNumber(colorZ)); - calRGB.setProperty(PdfName(PdfDictionaryProperties.matrix), matrix); - } - calRGB.setProperty( - PdfName(PdfDictionaryProperties.whitePoint), - whitePoint, - ); - colorspace.add(PdfName(PdfDictionaryProperties.calRGB)); - colorspace.add(calRGB); - return colorspace; - } - } - - void _setMask(PdfStream imageStream) { - if (_maskData != null && _maskData!.isNotEmpty) { - final PdfStream stream = PdfStream(); - stream.data = _maskData; - stream[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.xObject, - ); - stream[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.image, - ); - stream[PdfDictionaryProperties.width] = PdfNumber(width); - stream[PdfDictionaryProperties.height] = PdfNumber(height); - if (bitsPerComponent == 16) { - stream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber(8); - } else { - stream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( - bitsPerComponent!, - ); - } - stream[PdfDictionaryProperties.colorSpace] = PdfName( - PdfDictionaryProperties.deviceGray, - ); - imageStream.setProperty( - PdfName(PdfDictionaryProperties.sMask), - PdfReferenceHolder(stream), - ); - } - } - - PdfDictionary _getDecodeParams() { - final PdfDictionary decodeParams = PdfDictionary(); - decodeParams[PdfDictionaryProperties.columns] = PdfNumber(width); - decodeParams[PdfDictionaryProperties.colors] = PdfNumber(_colors); - decodeParams[PdfDictionaryProperties.predictor] = PdfNumber(15); - decodeParams[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( - bitsPerComponent!, - ); - return decodeParams; - } - - @override - void readHeader() { - _header = _PngHeader(); - _header.width = readUInt32(imageData, offset); - seek(4); - _header.height = readUInt32(imageData, offset); - seek(4); - _header.bitDepth = readByte(); - _header.colorType = readByte(); - _header.compression = readByte(); - _header.filter = _getFilterType(readByte()); - _header.interlace = readByte(); - _colors = (_header.colorType == 3 || (_header.colorType & 2) == 0) ? 1 : 3; - _initializeBase(); - _setBitsPerPixel(); - seek(4); - } - - @override - PdfStream getImageDictionary() { - final PdfStream imageStream = PdfStream(); - imageStream.data = _decodedImageData; - if (isDecode && _ideateDecode) { - imageStream.compress = true; - } else { - imageStream.compress = false; - } - imageStream[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.xObject, - ); - imageStream[PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.image, - ); - imageStream[PdfDictionaryProperties.width] = PdfNumber(width); - imageStream[PdfDictionaryProperties.height] = PdfNumber(height); - if (bitsPerComponent == 16) { - imageStream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber(8); - } else { - imageStream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( - bitsPerComponent!, - ); - } - if (!isDecode || !_ideateDecode) { - imageStream[PdfDictionaryProperties.filter] = PdfName( - PdfDictionaryProperties.flateDecode, - ); - } - if ((_header.colorType & 2) == 0) { - imageStream[PdfDictionaryProperties.colorSpace] = PdfName( - PdfDictionaryProperties.deviceGray, - ); - } else { - imageStream[PdfDictionaryProperties.colorSpace] = PdfName( - PdfDictionaryProperties.deviceRGB, - ); - } - if (!isDecode || _shades && !_ideateDecode) { - imageStream[PdfDictionaryProperties.decodeParms] = _getDecodeParams(); - } - _setMask(imageStream); - return imageStream; - } -} - -class _PngHeader { - _PngHeader() { - width = 0; - height = 0; - colorType = 0; - compression = 0; - bitDepth = 0; - interlace = 0; - filter = _PngFilterTypes.none; - } - late int width; - late int height; - late int colorType; - late int compression; - late int bitDepth; - late _PngFilterTypes filter; - late int interlace; -} - -enum _PngChunkTypes { - iHDR, - pLTE, - iDAT, - iEND, - bKGD, - cHRM, - gAMA, - hIST, - pHYs, - sBIT, - tEXt, - tIME, - tRNS, - zTXt, - sRGB, - iCCP, - iTXt, - unknown, -} - -enum _PngFilterTypes { none, sub, up, average, paeth } +import '../../../../interfaces/pdf_interface.dart'; +import '../../../compression/deflate/deflate_stream.dart'; +import '../../../io/pdf_constants.dart'; +import '../../../primitives/pdf_array.dart'; +import '../../../primitives/pdf_dictionary.dart'; +import '../../../primitives/pdf_name.dart'; +import '../../../primitives/pdf_number.dart'; +import '../../../primitives/pdf_reference_holder.dart'; +import '../../../primitives/pdf_stream.dart'; +import '../../../primitives/pdf_string.dart'; +import '../enum.dart'; +import 'image_decoder.dart'; + +/// internal class +class PngDecoder extends ImageDecoder { + /// internal constructor + PngDecoder(List imageData, int offset) { + this.imageData = List.from(imageData); + format = ImageType.png; + _issRGB = false; + isDecode = false; + _shades = false; + _ideateDecode = true; + _colors = 0; + _bitsPerPixel = 0; + _idatLength = 0; + _inputBands = 0; + this.offset = offset; + _initialize(); + jpegDecoderOrientationAngle = 0; + } + + //Fields + late int _currentChunkLength; + late _PngHeader _header; + late bool _issRGB; + late bool _shades; + late bool _ideateDecode; + late int _colors; + late int _bitsPerPixel; + late int _idatLength; + late int _inputBands; + List? _maskData; + late List _alpha; + List? _iDatStream; + late List _dataStream; + int? _dataStreamOffset; + List? _decodedImageData; + + /// internal field + PdfArray? colorSpace; + + /// internal field + late bool isDecode; + + //Implementation + void _initialize() { + _PngChunkTypes? header; + dynamic result = _hasValidChunkType(header); + while (result['hasValidChunk'] as bool) { + header = result['type'] as _PngChunkTypes?; + switch (header) { + case _PngChunkTypes.iHDR: + readHeader(); + break; + case _PngChunkTypes.iDAT: + _readImageData(); + break; + case _PngChunkTypes.sRGB: + _issRGB = true; + _ignoreChunk(); + break; + case _PngChunkTypes.pLTE: + _readPLTE(); + break; + case _PngChunkTypes.iEND: + _decodeImageData(); + break; + case _PngChunkTypes.tRNS: + _readTRNS(); + break; + case _PngChunkTypes.tEXt: + case _PngChunkTypes.iTXt: + case _PngChunkTypes.zTXt: + case _PngChunkTypes.hIST: + case _PngChunkTypes.sBIT: + case _PngChunkTypes.iCCP: + case _PngChunkTypes.pHYs: + case _PngChunkTypes.tIME: + case _PngChunkTypes.bKGD: + case _PngChunkTypes.gAMA: + case _PngChunkTypes.cHRM: + case _PngChunkTypes.unknown: + _ignoreChunk(); + break; + // ignore: no_default_cases + default: + break; + } + result = _hasValidChunkType(header); + } + } + + Map _hasValidChunkType(_PngChunkTypes? type) { + type = _PngChunkTypes.unknown; + if (offset + 8 <= imageData.length) { + _currentChunkLength = readUInt32(imageData, offset); + seek(4); + final String chunk = readString(imageData, 4); + final _PngChunkTypes? header = _getChunkType(chunk); + if (header != null) { + type = header; + return {'type': type, 'hasValidChunk': true}; + } + if (imageData.length == offset) { + return {'type': type, 'hasValidChunk': false}; + } else { + return {'type': type, 'hasValidChunk': true}; + } + } else { + return {'type': type, 'hasValidChunk': false}; + } + } + + _PngChunkTypes? _getChunkType(String chunk) { + switch (chunk) { + case 'IHDR': + return _PngChunkTypes.iHDR; + case 'PLTE': + return _PngChunkTypes.pLTE; + case 'IDAT': + return _PngChunkTypes.iDAT; + case 'IEND': + return _PngChunkTypes.iEND; + case 'bKGD': + return _PngChunkTypes.bKGD; + case 'cHRM': + return _PngChunkTypes.cHRM; + case 'gAMA': + return _PngChunkTypes.gAMA; + case 'hIST': + return _PngChunkTypes.hIST; + case 'pHYs': + return _PngChunkTypes.pHYs; + case 'sBIT': + return _PngChunkTypes.sBIT; + case 'tEXt': + return _PngChunkTypes.tEXt; + case 'tIME': + return _PngChunkTypes.tIME; + case 'tRNS': + return _PngChunkTypes.tRNS; + case 'zTXt': + return _PngChunkTypes.zTXt; + case 'sRGB': + return _PngChunkTypes.sRGB; + case 'iCCP': + return _PngChunkTypes.iCCP; + case 'iTXt': + return _PngChunkTypes.iTXt; + case 'Unknown': + return _PngChunkTypes.unknown; + default: + return null; + } + } + + _PngFilterTypes _getFilterType(int? type) { + switch (type) { + case 1: + return _PngFilterTypes.sub; + case 2: + return _PngFilterTypes.up; + case 3: + return _PngFilterTypes.average; + case 4: + return _PngFilterTypes.paeth; + default: + return _PngFilterTypes.none; + } + } + + void _initializeBase() { + width = _header.width; + height = _header.height; + bitsPerComponent = _header.bitDepth; + } + + void _setBitsPerPixel() { + _bitsPerPixel = _header.bitDepth == 16 ? 2 : 1; + if (_header.colorType == 0) { + _idatLength = ((bitsPerComponent! * width + 7) / 8 * height).toInt(); + _inputBands = 1; + } else if (_header.colorType == 2) { + _idatLength = width * height * 3; + _inputBands = 3; + _bitsPerPixel *= 3; + } else if (_header.colorType == 3) { + if (_header.interlace == 1) { + _idatLength = ((_header.bitDepth * width + 7) / 8 * height).toInt(); + } + _inputBands = 1; + _bitsPerPixel = 1; + } else if (_header.colorType == 4) { + _idatLength = width * height; + _inputBands = 2; + _bitsPerPixel *= 2; + } else if (_header.colorType == 6) { + _idatLength = width * 3 * height; + _inputBands = 4; + _bitsPerPixel *= 4; + } + } + + void _ignoreChunk() { + if (_currentChunkLength > 0) { + seek(_currentChunkLength + 4); + } + } + + void _readImageData() { + _iDatStream ??= []; + if (_currentChunkLength <= imageData.length && + imageData.length - offset >= _currentChunkLength) { + for (int i = 0; i < _currentChunkLength; i++) { + _iDatStream!.add(imageData[offset]); + offset = offset + 1; + } + } + seek(4); + } + + void _decodeImageData() { + isDecode = + (_header.interlace == 1) || + (_header.bitDepth == 16) || + ((_header.colorType & 4) != 0) || + _shades; + if (isDecode) { + if ((_header.colorType & 4) != 0 || _shades) { + final int length = width * height; + _maskData = []; + for (int i = 0; i < length; i++) { + _maskData!.add(0); + } + } + if (_iDatStream != null) { + _dataStream = _getDeflatedData(_iDatStream!); + _dataStreamOffset = 0; + } + _decodedImageData = List.filled(_idatLength, 0, growable: true); + _readDecodeData(); + + if (_decodedImageData != null && _decodedImageData!.isEmpty && _shades) { + _ideateDecode = false; + _decodedImageData = _iDatStream!.toList(growable: true); + } + } else { + _ideateDecode = false; + _decodedImageData = _iDatStream!.toList(growable: true); + } + } + + List _getDeflatedData(List data) { + final List idatData = data.sublist(2, data.length - 4); + final DeflateStream deflateStream = DeflateStream(idatData, 0, true); + List buffer = List.filled(4096, 0); + int? numRead = 0; + final List outputData = []; + do { + final Map result = deflateStream.read( + buffer, + 0, + buffer.length, + ); + numRead = result['count'] as int?; + buffer = result['data'] as List; + for (int i = 0; i < numRead!; i++) { + outputData.add(buffer[i]); + } + } while (numRead > 0); + return outputData; + } + + void _readDecodeData() { + if (_header.interlace != 1) { + _decodeData(0, 0, 1, 1, width, height); + } else { + _decodeData(0, 0, 8, 8, (width + 7) ~/ 8, (height + 7) ~/ 8); + _decodeData(4, 0, 8, 8, (width + 3) ~/ 8, (height + 7) ~/ 8); + _decodeData(0, 4, 4, 8, (width + 3) ~/ 4, (height + 3) ~/ 8); + _decodeData(2, 0, 4, 4, (width + 1) ~/ 4, (height + 3) ~/ 4); + _decodeData(0, 2, 2, 4, (width + 1) ~/ 2, (height + 1) ~/ 4); + _decodeData(1, 0, 2, 2, width ~/ 2, (height + 1) ~/ 2); + _decodeData(0, 1, 1, 2, width, height ~/ 2); + } + } + + void _decodeData( + int xOffset, + int yOffset, + int xStep, + int yStep, + int? width, + int? height, + ) { + if ((width == 0) || (height == 0)) { + return; + } else { + final int bytesPerRow = + (_inputBands * width! * _header.bitDepth + 7) ~/ 8; + List current = List.filled(bytesPerRow, 0); + List prior = List.filled(bytesPerRow, 0); + for ( + int sourceY = 0, destinationY = yOffset; + sourceY < height!; + sourceY++, destinationY += yStep + ) { + final int filter = _dataStream[_dataStreamOffset!]; + _dataStreamOffset = _dataStreamOffset! + 1; + _dataStreamOffset = _readStream( + _dataStream, + _dataStreamOffset, + current, + bytesPerRow, + ); + switch (_getFilterType(filter)) { + case _PngFilterTypes.none: + break; + case _PngFilterTypes.sub: + _decompressSub(current, bytesPerRow, _bitsPerPixel); + break; + case _PngFilterTypes.up: + _decompressUp(current, prior, bytesPerRow); + break; + case _PngFilterTypes.average: + _decompressAverage(current, prior, bytesPerRow, _bitsPerPixel); + break; + case _PngFilterTypes.paeth: + _decompressPaeth(current, prior, bytesPerRow, _bitsPerPixel); + break; + } + _processPixels(current, xOffset, xStep, destinationY, width); + final List tmp = prior; + prior = current; + current = tmp; + } + } + } + + int? _readStream( + List stream, + int? streamOffset, + List? data, + int count, + ) { + final dynamic result = read(stream, streamOffset, data, count); + data = result['outputBuffer'] as List?; + streamOffset = result['offset'] as int?; + final int n = result['length'] as int; + if (n <= 0) { + throw Exception('Insufficient data'); + } + return streamOffset; + } + + void _processPixels(List data, int x, int step, int y, int? width) { + int sourceX, destX, size = 0; + final List pixel = _getPixel(data); + if (_header.colorType == 0 || + _header.colorType == 3 || + _header.colorType == 4) { + size = 1; + } else if (_header.colorType == 2 || _header.colorType == 6) { + size = 3; + } + if (_decodedImageData != null && _decodedImageData!.isNotEmpty) { + destX = x; + final int depth = (_header.bitDepth == 16) ? 8 : _header.bitDepth; + final int yStep = (size * width! * depth + 7) ~/ 8; + for (sourceX = 0; sourceX < width; sourceX++) { + _decodedImageData = _setPixel( + _decodedImageData, + pixel, + _inputBands * sourceX, + size, + destX, + y, + _header.bitDepth, + yStep, + ); + destX += step; + } + } + final bool shades = (_header.colorType & 4) != 0 || _shades; + if (shades) { + if ((_header.colorType & 4) != 0) { + if (_header.bitDepth == 16) { + for (int i = 0; i < width!; ++i) { + final int temp = i * _inputBands + size; + pixel[temp] = (pixel[temp].toUnsigned(32) >> 8).toSigned(32); + } + } + final int? yStep = width; + destX = x; + for (sourceX = 0; sourceX < width!; sourceX++) { + _maskData = _setPixel( + _maskData, + pixel, + _inputBands * sourceX + size, + 1, + destX, + y, + 8, + yStep, + ); + destX += step; + } + } else { + final int? yStep = width; + final List dt = List.filled(1, 0, growable: true); + destX = x; + for (sourceX = 0; sourceX < width!; sourceX++) { + final int index = pixel[sourceX]; + if (index < _alpha.length) { + dt[0] = _alpha[index]; + } else { + dt[0] = 255; + } + _maskData = _setPixel(_maskData, dt, 0, 1, destX, y, 8, yStep); + destX += step; + } + } + } + } + + List _getPixel(List data) { + if (_header.bitDepth == 8) { + final List pixel = List.filled(data.length, 0, growable: true); + for (int i = 0; i < pixel.length; ++i) { + pixel[i] = data[i] & 0xff; + } + return pixel; + } else if (_header.bitDepth == 16) { + final List pixel = List.filled( + data.length ~/ 2, + 0, + growable: true, + ); + for (int i = 0; i < pixel.length; ++i) { + pixel[i] = ((data[i * 2] & 0xff) << 8) + (data[i * 2 + 1] & 0xff); + } + return pixel; + } else { + final List pixel = List.filled( + data.length * 8 ~/ _header.bitDepth, + 0, + growable: true, + ); + int index = 0; + final int p = 8 ~/ _header.bitDepth; + final int mask = (1 << _header.bitDepth) - 1; + for (int n = 0; n < data.length; ++n) { + for (int i = p - 1; i >= 0; --i) { + final int hb = _header.bitDepth * i; + final int d = data[n]; + pixel[index++] = + ((hb < 1) ? d : (d.toUnsigned(32) >> hb).toSigned(32)) & mask; + } + } + return pixel; + } + } + + List? _setPixel( + List? imageData, + List data, + int offset, + int size, + int x, + int y, + int? bitDepth, + int? bpr, + ) { + if (bitDepth == 8) { + final int position = bpr! * y + size * x; + for (int i = 0; i < size; ++i) { + imageData![position + i] = data[i + offset].toUnsigned(8); + } + } else if (bitDepth == 16) { + final int position = bpr! * y + size * x; + for (int i = 0; i < size; ++i) { + imageData![position + i] = (data[i + offset] >> 8).toUnsigned(8); + } + } else { + final int position = bpr! * y + x ~/ (8 / bitDepth!); + final int t = + data[offset] << + (8 - bitDepth * (x % (8 / bitDepth)) - bitDepth).toInt(); + imageData![position] = imageData[position] | t.toUnsigned(8); + } + return imageData; + } + + void _decompressSub(List data, int count, int bpp) { + for (int i = bpp; i < count; i++) { + int val = 0; + val = data[i] & 0xff; + val += data[i - bpp] & 0xff; + data[i] = val.toUnsigned(8); + } + } + + void _decompressUp(List data, List pData, int count) { + for (int i = 0; i < count; i++) { + data[i] = ((data[i] & 0xff) + (pData[i] & 0xff)).toUnsigned(8); + } + } + + void _decompressAverage(List data, List pData, int count, int bpp) { + int val, pp, pr; + for (int i = 0; i < bpp; i++) { + data[i] = ((data[i] & 0xff) + (pData[i] & 0xff) ~/ 2).toUnsigned(8); + } + for (int i = bpp; i < count; i++) { + val = data[i] & 0xff; + pp = data[i - bpp] & 0xff; + pr = pData[i] & 0xff; + data[i] = (val + (pp + pr) ~/ 2).toUnsigned(8); + } + } + + int _paethPredictor(int a, int b, int c) { + final int p = a + b - c; + final int pa = (p - a).abs(); + final int pb = (p - b).abs(); + final int pc = (p - c).abs(); + if ((pa <= pb) && (pa <= pc)) { + return a; + } else if (pb <= pc) { + return b; + } else { + return c; + } + } + + void _decompressPaeth(List data, List pData, int count, int bpp) { + int val, pp, pr, prp; + for (int i = 0; i < bpp; i++) { + val = data[i] & 0xff; + pr = pData[i] & 0xff; + data[i] = (val + pr).toUnsigned(8); + } + for (int i = bpp; i < count; i++) { + val = data[i] & 0xff; + pp = data[i - bpp] & 0xff; + pr = pData[i] & 0xff; + prp = pData[i - bpp] & 0xff; + data[i] = (val + _paethPredictor(pp, pr, prp)).toUnsigned(8); + } + } + + void _readPLTE() { + if (_header.colorType == 3) { + colorSpace = PdfArray(); + colorSpace!.add(PdfName(PdfDictionaryProperties.indexed)); + colorSpace!.add(_getPngColorSpace()); + colorSpace!.add(PdfNumber(_currentChunkLength / 3 - 1)); + colorSpace!.add(PdfString.fromBytes(readBytes(_currentChunkLength))); + seek(4); + } else { + _ignoreChunk(); + } + } + + void _readTRNS() { + if (_header.colorType == 3) { + final List alpha = readBytes(_currentChunkLength); + seek(4); + _alpha = List.filled(alpha.length, 0, growable: true); + for (int i = 0; i < alpha.length; i++) { + _alpha[i] = alpha[i]; + final int sh = alpha[i] & 0xff; + if (sh != 0 && sh != 255) { + _shades = true; + } + } + } else { + _ignoreChunk(); + } + } + + IPdfPrimitive _getPngColorSpace() { + if (!_issRGB) { + if ((_header.colorType & 2) == 0) { + return PdfName(PdfDictionaryProperties.deviceGray); + } else { + return PdfName(PdfDictionaryProperties.deviceRGB); + } + } else { + final PdfArray colorspace = PdfArray(); + final PdfDictionary calRGB = PdfDictionary(); + PdfArray whitePoint = PdfArray(); + whitePoint.add(PdfNumber(1)); + whitePoint.add(PdfNumber(1)); + whitePoint.add(PdfNumber(1)); + final PdfArray gammaArray = PdfArray(); + gammaArray.add(PdfNumber(2.2)); + gammaArray.add(PdfNumber(2.2)); + gammaArray.add(PdfNumber(2.2)); + calRGB.setProperty(PdfName(PdfDictionaryProperties.gamma), gammaArray); + if (_issRGB) { + const double wpX = 0.3127; + const double wpY = 0.329; + const double redX = 0.64; + const double redY = 0.33; + const double greenX = 0.3; + const double greenY = 0.6; + const double bX = 0.15; + const double bY = 0.06; + const double t = + wpY * + ((greenX - bX) * redY - + (redX - bX) * greenY + + (redX - greenX) * bY); + const double alphaY = + redY * + ((greenX - bX) * wpY - (wpX - bX) * greenY + (wpX - greenX) * bY) / + t; + const double alphaX = alphaY * redX / redY; + const double alphaZ = alphaY * ((1 - redX) / redY - 1); + const double blueY = + -greenY * + ((redX - bX) * wpY - (wpX - bX) * redY + (wpX - redX) * bY) / + t; + const double blueX = blueY * greenX / greenY; + const double blueZ = blueY * ((1 - greenX) / greenY - 1); + const double colorY = + bY * + ((redX - greenX) * wpY - + (wpX - greenX) * wpY + + (wpX - redX) * greenY) / + t; + const double colorX = colorY * bX / bY; + const double colorZ = colorY * ((1 - bX) / bY - 1); + const double whiteX = alphaX + blueX + colorX; + const double whiteY = 1; + const double whiteZ = alphaZ + blueZ + colorZ; + final PdfArray whitePointArray = PdfArray(); + whitePointArray.add(PdfNumber(whiteX)); + whitePointArray.add(PdfNumber(whiteY)); + whitePointArray.add(PdfNumber(whiteZ)); + whitePoint = whitePointArray; + final PdfArray matrix = PdfArray(); + matrix.add(PdfNumber(alphaX)); + matrix.add(PdfNumber(alphaY)); + matrix.add(PdfNumber(alphaZ)); + matrix.add(PdfNumber(blueX)); + matrix.add(PdfNumber(blueY)); + matrix.add(PdfNumber(blueZ)); + matrix.add(PdfNumber(colorX)); + matrix.add(PdfNumber(colorY)); + matrix.add(PdfNumber(colorZ)); + calRGB.setProperty(PdfName(PdfDictionaryProperties.matrix), matrix); + } + calRGB.setProperty( + PdfName(PdfDictionaryProperties.whitePoint), + whitePoint, + ); + colorspace.add(PdfName(PdfDictionaryProperties.calRGB)); + colorspace.add(calRGB); + return colorspace; + } + } + + void _setMask(PdfStream imageStream) { + if (_maskData != null && _maskData!.isNotEmpty) { + final PdfStream stream = PdfStream(); + stream.data = _maskData; + stream[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.xObject, + ); + stream[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.image, + ); + stream[PdfDictionaryProperties.width] = PdfNumber(width); + stream[PdfDictionaryProperties.height] = PdfNumber(height); + if (bitsPerComponent == 16) { + stream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber(8); + } else { + stream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( + bitsPerComponent!, + ); + } + stream[PdfDictionaryProperties.colorSpace] = PdfName( + PdfDictionaryProperties.deviceGray, + ); + imageStream.setProperty( + PdfName(PdfDictionaryProperties.sMask), + PdfReferenceHolder(stream), + ); + } + } + + PdfDictionary _getDecodeParams() { + final PdfDictionary decodeParams = PdfDictionary(); + decodeParams[PdfDictionaryProperties.columns] = PdfNumber(width); + decodeParams[PdfDictionaryProperties.colors] = PdfNumber(_colors); + decodeParams[PdfDictionaryProperties.predictor] = PdfNumber(15); + decodeParams[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( + bitsPerComponent!, + ); + return decodeParams; + } + + @override + void readHeader() { + _header = _PngHeader(); + _header.width = readUInt32(imageData, offset); + seek(4); + _header.height = readUInt32(imageData, offset); + seek(4); + _header.bitDepth = readByte(); + _header.colorType = readByte(); + _header.compression = readByte(); + _header.filter = _getFilterType(readByte()); + _header.interlace = readByte(); + _colors = (_header.colorType == 3 || (_header.colorType & 2) == 0) ? 1 : 3; + _initializeBase(); + _setBitsPerPixel(); + seek(4); + } + + @override + PdfStream getImageDictionary() { + final PdfStream imageStream = PdfStream(); + imageStream.data = _decodedImageData; + if (isDecode && _ideateDecode) { + imageStream.compress = true; + } else { + imageStream.compress = false; + } + imageStream[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.xObject, + ); + imageStream[PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.image, + ); + imageStream[PdfDictionaryProperties.width] = PdfNumber(width); + imageStream[PdfDictionaryProperties.height] = PdfNumber(height); + if (bitsPerComponent == 16) { + imageStream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber(8); + } else { + imageStream[PdfDictionaryProperties.bitsPerComponent] = PdfNumber( + bitsPerComponent!, + ); + } + if (!isDecode || !_ideateDecode) { + imageStream[PdfDictionaryProperties.filter] = PdfName( + PdfDictionaryProperties.flateDecode, + ); + } + if ((_header.colorType & 2) == 0) { + imageStream[PdfDictionaryProperties.colorSpace] = PdfName( + PdfDictionaryProperties.deviceGray, + ); + } else { + imageStream[PdfDictionaryProperties.colorSpace] = PdfName( + PdfDictionaryProperties.deviceRGB, + ); + } + if (!isDecode || _shades && !_ideateDecode) { + imageStream[PdfDictionaryProperties.decodeParms] = _getDecodeParams(); + } + _setMask(imageStream); + return imageStream; + } +} + +class _PngHeader { + _PngHeader() { + width = 0; + height = 0; + colorType = 0; + compression = 0; + bitDepth = 0; + interlace = 0; + filter = _PngFilterTypes.none; + } + late int width; + late int height; + late int colorType; + late int compression; + late int bitDepth; + late _PngFilterTypes filter; + late int interlace; +} + +enum _PngChunkTypes { + iHDR, + pLTE, + iDAT, + iEND, + bKGD, + cHRM, + gAMA, + hIST, + pHYs, + sBIT, + tEXt, + tIME, + tRNS, + zTXt, + sRGB, + iCCP, + iTXt, + unknown, +} + +enum _PngFilterTypes { none, sub, up, average, paeth } diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/enum.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/enum.dart index 9c06b0129..23b70e19d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/enum.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/enum.dart @@ -1,8 +1,8 @@ -/// Image format -enum ImageType { - /// JPEG image format - jpeg, - - /// PNG image format - png, -} +/// Image format +enum ImageType { + /// JPEG image format + jpeg, + + /// PNG image format + png, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_bitmap.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_bitmap.dart index 8743c97f1..b3572dfa3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_bitmap.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_bitmap.dart @@ -1,309 +1,309 @@ -import 'dart:convert'; -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_stream.dart'; -import '../enums.dart'; -import 'decoders/image_decoder.dart'; -import 'decoders/png_decoder.dart'; -import 'enum.dart'; -import 'pdf_image.dart'; - -/// The [PdfBitmap] contains methods and properties to handle the Bitmap images -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Draw the image. -/// doc.pages -/// .add() -/// .graphics -/// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); -/// //Saves the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -class PdfBitmap extends PdfImage { - //Constructors - /// Initializes a new instance of the [PdfBitmap] class - /// from the image data as list of bytes - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw the image. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - PdfBitmap(List imageData) { - _helper = PdfBitmapHelper(this); - _initialize(imageData); - } - - /// Initializes a new instance of the [PdfBitmap] class - /// from the image data as base64 string - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw the image. - /// document.pages.add().graphics.drawImage( - /// PdfBitmap.fromBase64String(imageData), Rect.fromLTWH(10, 10, 400, 250)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - PdfBitmap.fromBase64String(String imageData) { - if (imageData.isEmpty) { - ArgumentError.value(imageData, 'image data', 'image data cannot be null'); - } - _helper = PdfBitmapHelper(this); - _initialize(base64.decode(imageData)); - } - - //Fields - late PdfBitmapHelper _helper; - ImageDecoder? _decoder; - late int _height; - late int _width; - // ignore: prefer_final_fields - double _horizontalResolution = 0; - // ignore: prefer_final_fields - double _verticalResolution = 0; - bool _imageStatus = true; - - //Properties - /// Width of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Draw the image with image's width and height. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - @override - int get width => _width; - - /// Height of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Draw the image with image's width and height. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - @override - int get height => _height; - - /// Horizontal Resolution of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Gets horizontal resolution - /// double horizontalResolution = image.horizontalResolution; - /// //Draw the image. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - @override - double get horizontalResolution => _horizontalResolution; - - /// Vertical Resolution of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Gets vertical resolution - /// double verticalResolution = image.verticalResolution; - /// //Draw the image. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - @override - double get verticalResolution => _verticalResolution; - - //Implementation - void _initialize(List imageData) { - if (imageData.isEmpty) { - ArgumentError.value(imageData, 'image data', 'image data cannot be null'); - } - _helper.colorSpace = PdfColorSpace.rgb; - final ImageDecoder? decoder = ImageDecoder.getDecoder(imageData); - if (decoder != null) { - _decoder = decoder; - if (_decoder!.jpegDecoderOrientationAngle == 90 || - _decoder!.jpegDecoderOrientationAngle == 270) { - _height = _decoder!.width; - _width = _decoder!.height; - } else { - _height = _decoder!.height; - _width = _decoder!.width; - } - PdfImageHelper.setJpegOrientationAngle( - this, - _decoder!.jpegDecoderOrientationAngle, - ); - _imageStatus = false; - } else { - throw UnsupportedError('Invalid/Unsupported image stream'); - } - } - - void _setColorSpace() { - final PdfStream stream = PdfImageHelper.getImageStream(this)!; - final PdfName? color = - stream[PdfDictionaryProperties.colorSpace] as PdfName?; - if (color!.name == PdfDictionaryProperties.deviceCMYK) { - _helper.colorSpace = PdfColorSpace.cmyk; - } else if (color.name == PdfDictionaryProperties.deviceGray) { - _helper.colorSpace = PdfColorSpace.grayScale; - } - if (_decoder is PngDecoder && - (_decoder! as PngDecoder).colorSpace != null) { - _helper.colorSpace = PdfColorSpace.indexed; - } - switch (_helper.colorSpace) { - case PdfColorSpace.cmyk: - stream[PdfDictionaryProperties.decode] = PdfArray([ - 1.0, - 0.0, - 1.0, - 0.0, - 1.0, - 0.0, - 1.0, - 0.0, - ]); - stream[PdfDictionaryProperties.colorSpace] = PdfName( - PdfDictionaryProperties.deviceCMYK, - ); - break; - case PdfColorSpace.grayScale: - stream[PdfDictionaryProperties.decode] = PdfArray([0.0, 1.0]); - stream[PdfDictionaryProperties.colorSpace] = PdfName( - PdfDictionaryProperties.deviceGray, - ); - break; - case PdfColorSpace.rgb: - stream[PdfDictionaryProperties.decode] = PdfArray([ - 0.0, - 1.0, - 0.0, - 1.0, - 0.0, - 1.0, - ]); - stream[PdfDictionaryProperties.colorSpace] = PdfName( - PdfDictionaryProperties.deviceRGB, - ); - break; - case PdfColorSpace.indexed: - stream[PdfDictionaryProperties.colorSpace] = - (_decoder! as PngDecoder).colorSpace; - break; - // ignore: no_default_cases - default: - break; - } - } -} - -/// [PdfBitmap] helper -class PdfBitmapHelper { - /// internal constructor - PdfBitmapHelper(this.bitmap); - - /// internal field - late PdfBitmap bitmap; - - /// internal method - static PdfBitmapHelper getHelper(PdfBitmap bitmap) { - return bitmap._helper; - } - - /// internal method - PdfColorSpace? colorSpace; - - /// internal method - void save() { - if (!bitmap._imageStatus) { - bitmap._imageStatus = true; - PdfImageHelper.setImageStream( - bitmap, - bitmap._decoder!.getImageDictionary(), - ); - if (bitmap._decoder!.format == ImageType.png) { - final PngDecoder? decoder = bitmap._decoder as PngDecoder?; - if (decoder != null && decoder.isDecode) { - if (decoder.colorSpace != null) { - bitmap._setColorSpace(); - } - } else { - bitmap._setColorSpace(); - } - } else { - bitmap._setColorSpace(); - } - } - } - - /// internal method - void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { - graphics.drawImage( - bitmap, - Rect.fromLTWH(0, 0, bitmap._width * 0.75, bitmap._height * 0.75), - ); - } - - /// internal method - PdfRectangle getBoundsInternal() { - return PdfRectangle(0, 0, bitmap.width * 0.75, bitmap.height * 0.75); - } -} +import 'dart:convert'; +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_stream.dart'; +import '../enums.dart'; +import 'decoders/image_decoder.dart'; +import 'decoders/png_decoder.dart'; +import 'enum.dart'; +import 'pdf_image.dart'; + +/// The [PdfBitmap] contains methods and properties to handle the Bitmap images +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Draw the image. +/// doc.pages +/// .add() +/// .graphics +/// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); +/// //Saves the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +class PdfBitmap extends PdfImage { + //Constructors + /// Initializes a new instance of the [PdfBitmap] class + /// from the image data as list of bytes + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw the image. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + PdfBitmap(List imageData) { + _helper = PdfBitmapHelper(this); + _initialize(imageData); + } + + /// Initializes a new instance of the [PdfBitmap] class + /// from the image data as base64 string + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw the image. + /// document.pages.add().graphics.drawImage( + /// PdfBitmap.fromBase64String(imageData), Rect.fromLTWH(10, 10, 400, 250)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + PdfBitmap.fromBase64String(String imageData) { + if (imageData.isEmpty) { + ArgumentError.value(imageData, 'image data', 'image data cannot be null'); + } + _helper = PdfBitmapHelper(this); + _initialize(base64.decode(imageData)); + } + + //Fields + late PdfBitmapHelper _helper; + ImageDecoder? _decoder; + late int _height; + late int _width; + // ignore: prefer_final_fields + double _horizontalResolution = 0; + // ignore: prefer_final_fields + double _verticalResolution = 0; + bool _imageStatus = true; + + //Properties + /// Width of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Draw the image with image's width and height. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + @override + int get width => _width; + + /// Height of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Draw the image with image's width and height. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + @override + int get height => _height; + + /// Horizontal Resolution of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Gets horizontal resolution + /// double horizontalResolution = image.horizontalResolution; + /// //Draw the image. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + @override + double get horizontalResolution => _horizontalResolution; + + /// Vertical Resolution of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Gets vertical resolution + /// double verticalResolution = image.verticalResolution; + /// //Draw the image. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + @override + double get verticalResolution => _verticalResolution; + + //Implementation + void _initialize(List imageData) { + if (imageData.isEmpty) { + ArgumentError.value(imageData, 'image data', 'image data cannot be null'); + } + _helper.colorSpace = PdfColorSpace.rgb; + final ImageDecoder? decoder = ImageDecoder.getDecoder(imageData); + if (decoder != null) { + _decoder = decoder; + if (_decoder!.jpegDecoderOrientationAngle == 90 || + _decoder!.jpegDecoderOrientationAngle == 270) { + _height = _decoder!.width; + _width = _decoder!.height; + } else { + _height = _decoder!.height; + _width = _decoder!.width; + } + PdfImageHelper.setJpegOrientationAngle( + this, + _decoder!.jpegDecoderOrientationAngle, + ); + _imageStatus = false; + } else { + throw UnsupportedError('Invalid/Unsupported image stream'); + } + } + + void _setColorSpace() { + final PdfStream stream = PdfImageHelper.getImageStream(this)!; + final PdfName? color = + stream[PdfDictionaryProperties.colorSpace] as PdfName?; + if (color!.name == PdfDictionaryProperties.deviceCMYK) { + _helper.colorSpace = PdfColorSpace.cmyk; + } else if (color.name == PdfDictionaryProperties.deviceGray) { + _helper.colorSpace = PdfColorSpace.grayScale; + } + if (_decoder is PngDecoder && + (_decoder! as PngDecoder).colorSpace != null) { + _helper.colorSpace = PdfColorSpace.indexed; + } + switch (_helper.colorSpace) { + case PdfColorSpace.cmyk: + stream[PdfDictionaryProperties.decode] = PdfArray([ + 1.0, + 0.0, + 1.0, + 0.0, + 1.0, + 0.0, + 1.0, + 0.0, + ]); + stream[PdfDictionaryProperties.colorSpace] = PdfName( + PdfDictionaryProperties.deviceCMYK, + ); + break; + case PdfColorSpace.grayScale: + stream[PdfDictionaryProperties.decode] = PdfArray([0.0, 1.0]); + stream[PdfDictionaryProperties.colorSpace] = PdfName( + PdfDictionaryProperties.deviceGray, + ); + break; + case PdfColorSpace.rgb: + stream[PdfDictionaryProperties.decode] = PdfArray([ + 0.0, + 1.0, + 0.0, + 1.0, + 0.0, + 1.0, + ]); + stream[PdfDictionaryProperties.colorSpace] = PdfName( + PdfDictionaryProperties.deviceRGB, + ); + break; + case PdfColorSpace.indexed: + stream[PdfDictionaryProperties.colorSpace] = + (_decoder! as PngDecoder).colorSpace; + break; + // ignore: no_default_cases + default: + break; + } + } +} + +/// [PdfBitmap] helper +class PdfBitmapHelper { + /// internal constructor + PdfBitmapHelper(this.bitmap); + + /// internal field + late PdfBitmap bitmap; + + /// internal method + static PdfBitmapHelper getHelper(PdfBitmap bitmap) { + return bitmap._helper; + } + + /// internal method + PdfColorSpace? colorSpace; + + /// internal method + void save() { + if (!bitmap._imageStatus) { + bitmap._imageStatus = true; + PdfImageHelper.setImageStream( + bitmap, + bitmap._decoder!.getImageDictionary(), + ); + if (bitmap._decoder!.format == ImageType.png) { + final PngDecoder? decoder = bitmap._decoder as PngDecoder?; + if (decoder != null && decoder.isDecode) { + if (decoder.colorSpace != null) { + bitmap._setColorSpace(); + } + } else { + bitmap._setColorSpace(); + } + } else { + bitmap._setColorSpace(); + } + } + } + + /// internal method + void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { + graphics.drawImage( + bitmap, + Rect.fromLTWH(0, 0, bitmap._width * 0.75, bitmap._height * 0.75), + ); + } + + /// internal method + PdfRectangle getBoundsInternal() { + return PdfRectangle(0, 0, bitmap.width * 0.75, bitmap.height * 0.75); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_image.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_image.dart index 30a75ab47..8b2f83c0a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_image.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/images/pdf_image.dart @@ -1,174 +1,174 @@ -import 'dart:ui'; -import '../../../interfaces/pdf_interface.dart'; -import '../../primitives/pdf_stream.dart'; -import '../figures/base/pdf_shape_element.dart'; -import 'pdf_bitmap.dart'; - -/// Represents the base class for images -/// and provides functionality for the [PdfBitmap] class -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Draw the image. -/// doc.pages -/// .add() -/// .graphics -/// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); -/// //Saves the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -abstract class PdfImage extends PdfShapeElement implements IPdfWrapper { - //Fields - double? _jpegOrientationAngle; - PdfStream? _imageStream; - - //Properties - /// Width of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Draw the image with image's width and height. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - int get width; - - /// Height of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Draw the image with image's width and height. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - int get height; - - /// Horizontal Resolution of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Gets horizontal resolution - /// double horizontalResolution = image.horizontalResolution; - /// //Draw the image. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - double get horizontalResolution; - - /// Vertical Resolution of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Gets vertical resolution - /// double verticalResolution = image.verticalResolution; - /// //Draw the image. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - double get verticalResolution; - - /// Size of an image - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF image instance. - /// PdfImage image = PdfBitmap(imageData); - /// //Gets the size of an image - /// Size size = image.physicalDimension; - /// //Draw the image with image's width and height. - /// doc.pages - /// .add() - /// .graphics - /// .drawImage(image, Rect.fromLTWH(0, 0, size.width, size.height)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - Size get physicalDimension => Size(width.toDouble(), height.toDouble()); - - IPdfPrimitive? get _element => _imageStream; - // ignore: unused_element - set _element(IPdfPrimitive? value) { - _imageStream = value as PdfStream?; - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfImage] helper -class PdfImageHelper { - /// internal method - static IPdfPrimitive? getElement(PdfImage image) { - return image._element; - } - - /// internal method - static void setElement(PdfImage image, IPdfPrimitive? element) { - image._element = element; - } - - /// internal method - static double? getJpegOrientationAngle(PdfImage image) { - return image._jpegOrientationAngle; - } - - /// internal method - static void setJpegOrientationAngle(PdfImage image, double? value) { - image._jpegOrientationAngle = value; - } - - /// internal method - static PdfStream? getImageStream(PdfImage image) { - return image._imageStream; - } - - /// internal method - static void setImageStream(PdfImage image, PdfStream? value) { - image._imageStream = value; - } - - /// internal method - static void save(PdfImage image) { - PdfBitmapHelper.getHelper(image as PdfBitmap).save(); - } -} +import 'dart:ui'; +import '../../../interfaces/pdf_interface.dart'; +import '../../primitives/pdf_stream.dart'; +import '../figures/base/pdf_shape_element.dart'; +import 'pdf_bitmap.dart'; + +/// Represents the base class for images +/// and provides functionality for the [PdfBitmap] class +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Draw the image. +/// doc.pages +/// .add() +/// .graphics +/// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); +/// //Saves the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +abstract class PdfImage extends PdfShapeElement implements IPdfWrapper { + //Fields + double? _jpegOrientationAngle; + PdfStream? _imageStream; + + //Properties + /// Width of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Draw the image with image's width and height. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + int get width; + + /// Height of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Draw the image with image's width and height. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, image.width, image.height)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + int get height; + + /// Horizontal Resolution of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Gets horizontal resolution + /// double horizontalResolution = image.horizontalResolution; + /// //Draw the image. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + double get horizontalResolution; + + /// Vertical Resolution of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Gets vertical resolution + /// double verticalResolution = image.verticalResolution; + /// //Draw the image. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, 100, 100)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + double get verticalResolution; + + /// Size of an image + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF image instance. + /// PdfImage image = PdfBitmap(imageData); + /// //Gets the size of an image + /// Size size = image.physicalDimension; + /// //Draw the image with image's width and height. + /// doc.pages + /// .add() + /// .graphics + /// .drawImage(image, Rect.fromLTWH(0, 0, size.width, size.height)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + Size get physicalDimension => Size(width.toDouble(), height.toDouble()); + + IPdfPrimitive? get _element => _imageStream; + // ignore: unused_element + set _element(IPdfPrimitive? value) { + _imageStream = value as PdfStream?; + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfImage] helper +class PdfImageHelper { + /// internal method + static IPdfPrimitive? getElement(PdfImage image) { + return image._element; + } + + /// internal method + static void setElement(PdfImage image, IPdfPrimitive? element) { + image._element = element; + } + + /// internal method + static double? getJpegOrientationAngle(PdfImage image) { + return image._jpegOrientationAngle; + } + + /// internal method + static void setJpegOrientationAngle(PdfImage image, double? value) { + image._jpegOrientationAngle = value; + } + + /// internal method + static PdfStream? getImageStream(PdfImage image) { + return image._imageStream; + } + + /// internal method + static void setImageStream(PdfImage image, PdfStream? value) { + image._imageStream = value; + } + + /// internal method + static void save(PdfImage image) { + PdfBitmapHelper.getHelper(image as PdfBitmap).save(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_color.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_color.dart index 1a3316352..b81d390f5 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_color.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_color.dart @@ -1,408 +1,408 @@ -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_number.dart'; -import 'enums.dart'; - -/// Implements structures and routines working with color. -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument document = PdfDocument() -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), -/// //Using PDF color set pen. -/// pen: PdfPen(PdfColor(200, 120, 80))); -/// //Saves the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfColor { - /// Initializes a new instance of the [PdfColor] class - /// with Red, Green, Blue and Alpha channels. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// //Using PDF color set pen. - /// pen: PdfPen(PdfColor(200, 120, 80))); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfColor(int red, int green, int blue, [int alpha = 255]) { - _helper = PdfColorHelper(this); - _black = 0; - _cyan = 0; - _magenta = 0; - _yellow = 0; - _gray = 0; - _red = red; - _green = green; - _blue = blue; - _helper.alpha = alpha; - _helper.isFilled = _helper.alpha != 0; - _assignCMYK(_red, _green, _blue); - } - - /// Initializes a new instance of the [PdfColor] class - /// with Cyan, Magenta, Yellow and Black channels. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// //Using PDF color set pen. - /// pen: PdfPen(PdfColor.fromCMYK(200, 120, 80, 40))); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfColor.fromCMYK(double cyan, double magenta, double yellow, double black) { - _helper = PdfColorHelper(this); - _red = 0; - _cyan = cyan; - _green = 0; - _magenta = magenta; - _blue = 0; - _yellow = yellow; - _black = black; - _gray = 0; - _helper.alpha = _maxColourChannelValue.toInt(); - _helper.isFilled = true; - _assignRGB(cyan, magenta, yellow, black); - } - - PdfColor._fromGray(double gray) { - _helper = PdfColorHelper(this); - if (gray < 0) { - gray = 0; - } - if (gray > 1) { - gray = 1; - } - _red = (gray * _maxColourChannelValue).round().toUnsigned(8); - _green = (gray * _maxColourChannelValue).round().toUnsigned(8); - _blue = (gray * _maxColourChannelValue).round().toUnsigned(8); - _cyan = gray; - _magenta = gray; - _yellow = gray; - _black = gray; - _gray = gray; - _helper.alpha = _maxColourChannelValue.round().toUnsigned(8); - _helper.isFilled = true; - } - - PdfColor._empty() { - _helper = PdfColorHelper(this); - _red = 0; - _cyan = 0; - _green = 0; - _magenta = 0; - _blue = 0; - _yellow = 0; - _black = 0; - _gray = 0; - _helper.alpha = 0; - _helper.isFilled = false; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is PdfColor && - _red == other._red && - _cyan == other._cyan && - _green == other._green && - _magenta == other._magenta && - _blue == other._blue && - _yellow == other._yellow && - _black == other._black && - _gray == other._gray && - _helper.alpha == other._helper.alpha && - _helper.isFilled == other._helper.isFilled; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _helper.alpha.hashCode; - - /// Gets the empty(null) color. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// //Create PDF color. - /// pen: PdfPen(PdfColor.empty)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - static PdfColor get empty { - return PdfColor._empty(); - } - - //Fields - late PdfColorHelper _helper; - - /// Holds RGB colors converted into strings. - final Map _rgbStrings = {}; - - /// Value of Red channel. - late int _red; - - /// Value of Cyan channel. - late double _cyan; - - /// Value of Green channel. - late int _green; - - /// Value of Magenta channel. - late double _magenta; - - /// Value of Blue channel. - late int _blue; - - /// Value of Yellow channel. - late double _yellow; - - /// Value of Black channel. - late double _black; - - /// Value of Gray channel. - late double _gray; - - /// Max value of color channel. - final double _maxColourChannelValue = 255.0; - - //Properties - /// Gets or sets Red channel value. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //sets the red channel value. - /// pen: PdfPen(PdfColor(0, 0, 0)..r = 255), - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - int get r => _red; - set r(int value) { - _red = value; - _assignCMYK(_red, _green, _blue); - _helper.isFilled = true; - } - - /// Gets or sets Green channel value. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //sets the green channel value. - /// pen: PdfPen(PdfColor(0, 0, 0)..g = 255), - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - int get g => _green; - set g(int value) { - _green = value; - _assignCMYK(_red, _green, _blue); - _helper.isFilled = true; - } - - /// Gets or sets Blue channel value. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //sets the blue channel value. - /// pen: PdfPen(PdfColor(0, 0, 0)..b = 255), - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - int get b => _blue; - set b(int value) { - _blue = value; - _assignCMYK(_red, _green, _blue); - _helper.isFilled = true; - } - - /// Gets whether the PDFColor is Empty or not. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF pen instance. - /// PdfColor color = PdfColor.empty; - /// //Draw rectangle with the pen. - /// document.pages.add().graphics.drawString('Color present: ${color.isEmpty}', - /// PdfStandardFont(PdfFontFamily.helvetica, 12), - /// pen: PdfPen(color)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - bool get isEmpty => !_helper.isFilled; - - //Implementation - /// Converts RGB to CMYK. - void _assignCMYK(int r, int g, int b) { - final double red = r / _maxColourChannelValue; - final double green = g / _maxColourChannelValue; - final double blue = b / _maxColourChannelValue; - final double black = _min(1 - red, 1 - green, 1 - blue); - final double cyan = black == 1.0 ? 0 : (1 - red - black) / (1 - black); - final double magenta = black == 1.0 ? 0 : (1 - green - black) / (1 - black); - final double yellow = black == 1.0 ? 0 : (1 - blue - black) / (1 - black); - _black = black; - _cyan = cyan; - _magenta = magenta; - _yellow = yellow; - } - - /// Converts CMYK to RGB. - void _assignRGB(double c, double m, double y, double k) { - final double black = k * _maxColourChannelValue; - final double red = (c * (_maxColourChannelValue - black)) + black; - final double green = (m * (_maxColourChannelValue - black)) + black; - final double blue = (y * (_maxColourChannelValue - black)) + black; - _red = (_maxColourChannelValue - - (_maxColourChannelValue <= red ? _maxColourChannelValue : red)) - .toInt() - .toUnsigned(8); - _green = (_maxColourChannelValue - - (_maxColourChannelValue <= green ? _maxColourChannelValue : green)) - .toInt() - .toUnsigned(8); - _blue = (_maxColourChannelValue - - (_maxColourChannelValue <= blue ? _maxColourChannelValue : blue)) - .toInt() - .toUnsigned(8); - } - - /// Gets minimum from RGB color values. - double _min(double r, double g, double b) { - final double min = r <= g ? r : g; - return b <= min ? b : min; - } - - PdfArray _toArray([PdfColorSpace colorSpace = PdfColorSpace.rgb]) { - final PdfArray array = PdfArray(); - switch (colorSpace) { - case PdfColorSpace.cmyk: - array.add(PdfNumber(_cyan)); - array.add(PdfNumber(_magenta)); - array.add(PdfNumber(_yellow)); - array.add(PdfNumber(_black)); - break; - case PdfColorSpace.grayScale: - array.add(PdfNumber(_gray / _maxColourChannelValue)); - break; - case PdfColorSpace.rgb: - array.add(PdfNumber(_red / _maxColourChannelValue)); - array.add(PdfNumber(_green / _maxColourChannelValue)); - array.add(PdfNumber(_blue / _maxColourChannelValue)); - break; - // ignore: no_default_cases - default: - throw ArgumentError.value('Unsupported colour space.'); - } - return array; - } -} - -/// [PdfColor] helper -class PdfColorHelper { - /// internal constructor - PdfColorHelper(this.base); - - /// internal field - late PdfColor base; - - /// internal method - static PdfColorHelper getHelper(PdfColor base) { - return base._helper; - } - - /// internal method - static PdfColor fromGray(double gray) { - return PdfColor._fromGray(gray); - } - - /// internal method - static PdfArray toArray( - PdfColor color, [ - PdfColorSpace colorSpace = PdfColorSpace.rgb, - ]) { - return color._toArray(colorSpace); - } - - /// Value of alpha channel. - late int alpha; - - /// Shows if the color is empty. - bool isFilled = false; - - /// internal method - /// Converts [PdfColor] to PDF string representation. - String getString(PdfColorSpace? colorSpace, bool stroke) { - if (base.isEmpty) { - return ''; - } - return _rgbToString(stroke); - } - - /// Sets RGB color. - String _rgbToString(bool ifStroking) { - int key = (base.r << 16) + (base.g << 8) + base.b; - if (ifStroking) { - key += 1 << 24; - } - String colour; - Object? obj; - if (base._rgbStrings.containsKey(key)) { - obj = base._rgbStrings[key]; - } - if (obj == null) { - dynamic red = base.r / base._maxColourChannelValue; - dynamic green = base.g / base._maxColourChannelValue; - dynamic blue = base.b / base._maxColourChannelValue; - red = red % 1 == 0 ? red.toInt() : red; - green = green % 1 == 0 ? green.toInt() : green; - blue = blue % 1 == 0 ? blue.toInt() : blue; - colour = - '${_trimEnd(red.toString())} ${_trimEnd(green.toString())} ${_trimEnd(blue.toString())}${ifStroking ? ' RG' : ' rg'}'; - base._rgbStrings[key] = colour; - } else { - colour = obj.toString(); - } - return colour; - } - - String _trimEnd(String color) { - if (color.endsWith('.00')) { - color = color.substring(0, color.length - 3); - } - return color.isEmpty ? '0' : color; - } -} +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_number.dart'; +import 'enums.dart'; + +/// Implements structures and routines working with color. +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument document = PdfDocument() +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), +/// //Using PDF color set pen. +/// pen: PdfPen(PdfColor(200, 120, 80))); +/// //Saves the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfColor { + /// Initializes a new instance of the [PdfColor] class + /// with Red, Green, Blue and Alpha channels. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// //Using PDF color set pen. + /// pen: PdfPen(PdfColor(200, 120, 80))); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfColor(int red, int green, int blue, [int alpha = 255]) { + _helper = PdfColorHelper(this); + _black = 0; + _cyan = 0; + _magenta = 0; + _yellow = 0; + _gray = 0; + _red = red; + _green = green; + _blue = blue; + _helper.alpha = alpha; + _helper.isFilled = _helper.alpha != 0; + _assignCMYK(_red, _green, _blue); + } + + /// Initializes a new instance of the [PdfColor] class + /// with Cyan, Magenta, Yellow and Black channels. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// //Using PDF color set pen. + /// pen: PdfPen(PdfColor.fromCMYK(200, 120, 80, 40))); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfColor.fromCMYK(double cyan, double magenta, double yellow, double black) { + _helper = PdfColorHelper(this); + _red = 0; + _cyan = cyan; + _green = 0; + _magenta = magenta; + _blue = 0; + _yellow = yellow; + _black = black; + _gray = 0; + _helper.alpha = _maxColourChannelValue.toInt(); + _helper.isFilled = true; + _assignRGB(cyan, magenta, yellow, black); + } + + PdfColor._fromGray(double gray) { + _helper = PdfColorHelper(this); + if (gray < 0) { + gray = 0; + } + if (gray > 1) { + gray = 1; + } + _red = (gray * _maxColourChannelValue).round().toUnsigned(8); + _green = (gray * _maxColourChannelValue).round().toUnsigned(8); + _blue = (gray * _maxColourChannelValue).round().toUnsigned(8); + _cyan = gray; + _magenta = gray; + _yellow = gray; + _black = gray; + _gray = gray; + _helper.alpha = _maxColourChannelValue.round().toUnsigned(8); + _helper.isFilled = true; + } + + PdfColor._empty() { + _helper = PdfColorHelper(this); + _red = 0; + _cyan = 0; + _green = 0; + _magenta = 0; + _blue = 0; + _yellow = 0; + _black = 0; + _gray = 0; + _helper.alpha = 0; + _helper.isFilled = false; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is PdfColor && + _red == other._red && + _cyan == other._cyan && + _green == other._green && + _magenta == other._magenta && + _blue == other._blue && + _yellow == other._yellow && + _black == other._black && + _gray == other._gray && + _helper.alpha == other._helper.alpha && + _helper.isFilled == other._helper.isFilled; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _helper.alpha.hashCode; + + /// Gets the empty(null) color. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// //Create PDF color. + /// pen: PdfPen(PdfColor.empty)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + static PdfColor get empty { + return PdfColor._empty(); + } + + //Fields + late PdfColorHelper _helper; + + /// Holds RGB colors converted into strings. + final Map _rgbStrings = {}; + + /// Value of Red channel. + late int _red; + + /// Value of Cyan channel. + late double _cyan; + + /// Value of Green channel. + late int _green; + + /// Value of Magenta channel. + late double _magenta; + + /// Value of Blue channel. + late int _blue; + + /// Value of Yellow channel. + late double _yellow; + + /// Value of Black channel. + late double _black; + + /// Value of Gray channel. + late double _gray; + + /// Max value of color channel. + final double _maxColourChannelValue = 255.0; + + //Properties + /// Gets or sets Red channel value. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //sets the red channel value. + /// pen: PdfPen(PdfColor(0, 0, 0)..r = 255), + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + int get r => _red; + set r(int value) { + _red = value; + _assignCMYK(_red, _green, _blue); + _helper.isFilled = true; + } + + /// Gets or sets Green channel value. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //sets the green channel value. + /// pen: PdfPen(PdfColor(0, 0, 0)..g = 255), + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + int get g => _green; + set g(int value) { + _green = value; + _assignCMYK(_red, _green, _blue); + _helper.isFilled = true; + } + + /// Gets or sets Blue channel value. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //sets the blue channel value. + /// pen: PdfPen(PdfColor(0, 0, 0)..b = 255), + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + int get b => _blue; + set b(int value) { + _blue = value; + _assignCMYK(_red, _green, _blue); + _helper.isFilled = true; + } + + /// Gets whether the PDFColor is Empty or not. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF pen instance. + /// PdfColor color = PdfColor.empty; + /// //Draw rectangle with the pen. + /// document.pages.add().graphics.drawString('Color present: ${color.isEmpty}', + /// PdfStandardFont(PdfFontFamily.helvetica, 12), + /// pen: PdfPen(color)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + bool get isEmpty => !_helper.isFilled; + + //Implementation + /// Converts RGB to CMYK. + void _assignCMYK(int r, int g, int b) { + final double red = r / _maxColourChannelValue; + final double green = g / _maxColourChannelValue; + final double blue = b / _maxColourChannelValue; + final double black = _min(1 - red, 1 - green, 1 - blue); + final double cyan = black == 1.0 ? 0 : (1 - red - black) / (1 - black); + final double magenta = black == 1.0 ? 0 : (1 - green - black) / (1 - black); + final double yellow = black == 1.0 ? 0 : (1 - blue - black) / (1 - black); + _black = black; + _cyan = cyan; + _magenta = magenta; + _yellow = yellow; + } + + /// Converts CMYK to RGB. + void _assignRGB(double c, double m, double y, double k) { + final double black = k * _maxColourChannelValue; + final double red = (c * (_maxColourChannelValue - black)) + black; + final double green = (m * (_maxColourChannelValue - black)) + black; + final double blue = (y * (_maxColourChannelValue - black)) + black; + _red = (_maxColourChannelValue - + (_maxColourChannelValue <= red ? _maxColourChannelValue : red)) + .toInt() + .toUnsigned(8); + _green = (_maxColourChannelValue - + (_maxColourChannelValue <= green ? _maxColourChannelValue : green)) + .toInt() + .toUnsigned(8); + _blue = (_maxColourChannelValue - + (_maxColourChannelValue <= blue ? _maxColourChannelValue : blue)) + .toInt() + .toUnsigned(8); + } + + /// Gets minimum from RGB color values. + double _min(double r, double g, double b) { + final double min = r <= g ? r : g; + return b <= min ? b : min; + } + + PdfArray _toArray([PdfColorSpace colorSpace = PdfColorSpace.rgb]) { + final PdfArray array = PdfArray(); + switch (colorSpace) { + case PdfColorSpace.cmyk: + array.add(PdfNumber(_cyan)); + array.add(PdfNumber(_magenta)); + array.add(PdfNumber(_yellow)); + array.add(PdfNumber(_black)); + break; + case PdfColorSpace.grayScale: + array.add(PdfNumber(_gray / _maxColourChannelValue)); + break; + case PdfColorSpace.rgb: + array.add(PdfNumber(_red / _maxColourChannelValue)); + array.add(PdfNumber(_green / _maxColourChannelValue)); + array.add(PdfNumber(_blue / _maxColourChannelValue)); + break; + // ignore: no_default_cases + default: + throw ArgumentError.value('Unsupported colour space.'); + } + return array; + } +} + +/// [PdfColor] helper +class PdfColorHelper { + /// internal constructor + PdfColorHelper(this.base); + + /// internal field + late PdfColor base; + + /// internal method + static PdfColorHelper getHelper(PdfColor base) { + return base._helper; + } + + /// internal method + static PdfColor fromGray(double gray) { + return PdfColor._fromGray(gray); + } + + /// internal method + static PdfArray toArray( + PdfColor color, [ + PdfColorSpace colorSpace = PdfColorSpace.rgb, + ]) { + return color._toArray(colorSpace); + } + + /// Value of alpha channel. + late int alpha; + + /// Shows if the color is empty. + bool isFilled = false; + + /// internal method + /// Converts [PdfColor] to PDF string representation. + String getString(PdfColorSpace? colorSpace, bool stroke) { + if (base.isEmpty) { + return ''; + } + return _rgbToString(stroke); + } + + /// Sets RGB color. + String _rgbToString(bool ifStroking) { + int key = (base.r << 16) + (base.g << 8) + base.b; + if (ifStroking) { + key += 1 << 24; + } + String colour; + Object? obj; + if (base._rgbStrings.containsKey(key)) { + obj = base._rgbStrings[key]; + } + if (obj == null) { + dynamic red = base.r / base._maxColourChannelValue; + dynamic green = base.g / base._maxColourChannelValue; + dynamic blue = base.b / base._maxColourChannelValue; + red = red % 1 == 0 ? red.toInt() : red; + green = green % 1 == 0 ? green.toInt() : green; + blue = blue % 1 == 0 ? blue.toInt() : blue; + colour = + '${_trimEnd(red.toString())} ${_trimEnd(green.toString())} ${_trimEnd(blue.toString())}${ifStroking ? ' RG' : ' rg'}'; + base._rgbStrings[key] = colour; + } else { + colour = obj.toString(); + } + return colour; + } + + String _trimEnd(String color) { + if (color.endsWith('.00')) { + color = color.substring(0, color.length - 3); + } + return color.isEmpty ? '0' : color; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_graphics.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_graphics.dart index a9e2d520a..4f363f316 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_graphics.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_graphics.dart @@ -1,2639 +1,2639 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../drawing/drawing.dart'; -import '../general/pdf_collection.dart'; -import '../general/windows1252encoding.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_stream_writer.dart'; -import '../pages/pdf_layer.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_layer.dart'; -import '../pages/pdf_section.dart'; -import '../pdf_document/automatic_fields/pdf_automatic_field.dart'; -import '../pdf_document/automatic_fields/pdf_automatic_field_info.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'brushes/pdf_solid_brush.dart'; -import 'enums.dart'; -import 'figures/enums.dart'; -import 'figures/pdf_path.dart'; -import 'figures/pdf_template.dart'; -import 'fonts/enums.dart'; -import 'fonts/pdf_cjk_standard_font.dart'; -import 'fonts/pdf_font.dart'; -import 'fonts/pdf_standard_font.dart'; -import 'fonts/pdf_string_format.dart'; -import 'fonts/pdf_string_layout_result.dart'; -import 'fonts/pdf_string_layouter.dart'; -import 'fonts/pdf_true_type_font.dart'; -import 'fonts/rtl/arabic_shape_renderer.dart'; -import 'fonts/rtl/bidi.dart'; -import 'fonts/string_tokenizer.dart'; -import 'fonts/ttf_reader.dart'; -import 'fonts/unicode_true_type_font.dart'; -import 'images/pdf_image.dart'; -import 'pdf_color.dart'; -import 'pdf_pen.dart'; -import 'pdf_resources.dart'; -import 'pdf_transformation_matrix.dart'; -import 'pdf_transparency.dart'; - -/// Represents a graphics context of the objects. -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument doc = PdfDocument() -/// ..pages -/// .add() -/// //PDF graphics for the page. -/// .graphics -/// .drawRectangle( -/// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 515, 762)); -/// //Saves the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -class PdfGraphics { - //Constructor - /// Initializes a new instance of the [PdfGraphics] class. - PdfGraphics._(Size size, Function getResources, PdfStream stream) { - _helper = PdfGraphicsHelper(this); - _helper.streamWriter = PdfStreamWriter(stream); - _helper._getResources = getResources; - _canvasSize = size; - _initialize(); - } - - //Fields - late PdfGraphicsHelper _helper; - late Size _canvasSize; - late bool _isStateSaved; - int? _previousTextRenderingMode = _TextRenderingMode.fill; - double? _previousCharacterSpacing; - double? _previousWordSpacing; - late List _graphicsState; - - //Properties - /// Gets or sets the current color space of the document. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page - /// doc.pages.add().graphics - /// ..colorSpace = PdfColorSpace.grayScale - /// ..drawRectangle( - /// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 515, 762)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - late PdfColorSpace colorSpace; - - /// Gets the size of the canvas. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page. - /// PdfGraphics graphics = doc.pages.add().graphics; - /// //Draw string to PDF page graphics. - /// graphics.drawString( - /// //Get the graphics canvas size. - /// 'Canvas size: ${graphics.size}', - /// PdfStandardFont(PdfFontFamily.courier, 12)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - Size get size => _canvasSize; - - /// Gets the size of the canvas reduced by margins and page templates. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page - /// PdfGraphics graphics = doc.pages.add().graphics; - /// //Draw rectangle to PDF page graphics. - /// graphics.drawRectangle( - /// brush: PdfBrushes.red, - /// //Get the graphics client size. - /// bounds: Rect.fromLTWH( - /// 0, 0, graphics.clientSize.width, graphics.clientSize.height)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - Size get clientSize => - Size(_helper.clipBounds.width, _helper.clipBounds.height); - - //Public methods - /// Changes the origin of the coordinate system - /// by prepending the specified translation - /// to the transformation matrix of this Graphics. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page - /// doc.pages.add().graphics - /// ..save() - /// //Set graphics translate transform. - /// ..translateTransform(100, 100) - /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.red) - /// ..restore(); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void translateTransform(double offsetX, double offsetY) { - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - matrix.translate(offsetX, -offsetY); - _helper.streamWriter!.modifyCurrentMatrix(matrix); - _helper.matrix.multiply(matrix); - } - - /// Applies the specified rotation - /// to the transformation matrix of this Graphics. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Adds a page to the PDF document. - /// doc.pages.add().graphics - /// //Set rotate transform - /// ..rotateTransform(-90) - /// //Draws the text into PDF graphics in -90 degree rotation. - /// ..drawString('Hello world.', PdfStandardFont(PdfFontFamily.courier, 14), - /// bounds: Rect.fromLTWH(-100, 0, 200, 50)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void rotateTransform(double angle) { - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - matrix.rotate(-angle); - _helper.streamWriter!.modifyCurrentMatrix(matrix); - _helper.matrix.multiply(matrix); - } - - /// Saves the current state of this Graphics - /// and identifies the saved state with a GraphicsState. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page - /// PdfGraphics graphics = doc.pages.add().graphics; - /// //Save the graphics. - /// PdfGraphicsState state = graphics.save(); - /// //Set graphics translate transform. - /// graphics - /// ..translateTransform(100, 100) - /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.red) - /// //Restore the graphics. - /// ..restore(state); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - PdfGraphicsState save() { - final PdfGraphicsState state = PdfGraphicsState._(this, _helper.matrix); - state._brush = _helper._currentBrush; - state._pen = _helper._currentPen; - state._font = _helper._currentFont; - state._colorSpace = colorSpace; - state._characterSpacing = _previousCharacterSpacing!; - state._wordSpacing = _previousWordSpacing!; - state._textScaling = _helper._previousTextScaling!; - state._textRenderingMode = _previousTextRenderingMode!; - _graphicsState.add(state); - if (_isStateSaved) { - _helper.streamWriter!.restoreGraphicsState(); - _isStateSaved = false; - } - _helper.streamWriter!.saveGraphicsState(); - return state; - } - - /// Restores the state of this Graphics to the state represented - /// by a GraphicsState. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page - /// PdfGraphics graphics = doc.pages.add().graphics; - /// //Save the graphics. - /// PdfGraphicsState state = graphics.save(); - /// //Set graphics translate transform. - /// graphics - /// ..translateTransform(100, 100) - /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.red) - /// //Restore the graphics. - /// ..restore(state); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void restore([PdfGraphicsState? state]) { - if (state == null) { - if (_graphicsState.isNotEmpty) { - _doRestoreState(); - } - } else { - if (state._graphics != this) { - throw ArgumentError.value( - this, - 'The graphics state belongs to another graphics object', - ); - } - if (_graphicsState.contains(state)) { - while (true) { - if (_graphicsState.isEmpty) { - break; - } - final PdfGraphicsState popState = _doRestoreState(); - if (popState == state) { - break; - } - } - } - } - } - - /// Draws the specified text string at the specified location. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw string to PDF page graphics. - /// .drawString( - /// 'Hello world!', - /// PdfStandardFont(PdfFontFamily.helvetica, 12, - /// style: PdfFontStyle.bold), - /// bounds: Rect.fromLTWH(0, 0, 200, 50), - /// brush: PdfBrushes.red, - /// pen: PdfPens.blue, - /// format: PdfStringFormat(alignment: PdfTextAlignment.left)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawString( - String s, - PdfFont font, { - PdfPen? pen, - PdfBrush? brush, - Rect? bounds, - PdfStringFormat? format, - }) { - PdfRectangle layoutRectangle; - if (bounds != null) { - layoutRectangle = PdfRectangle.fromRect(bounds); - } else { - layoutRectangle = PdfRectangle.empty; - } - if (pen == null && brush == null) { - brush = PdfSolidBrush(PdfColor(0, 0, 0)); - } - - s = _normalizeText(font, s); - - _helper.layoutString( - s, - font, - pen: pen, - brush: brush, - layoutRectangle: layoutRectangle, - format: format, - ); - } - - /// Draws a line connecting the two points specified by the coordinate pairs. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw line. - /// .drawLine(PdfPens.black, Offset(100, 100), Offset(200, 100)); - /// // Save the document. - /// List bytes = doc.save(); - /// // Dispose the document. - /// doc.dispose(); - /// ``` - void drawLine(PdfPen pen, Offset point1, Offset point2) { - _helper._beginMarkContent(); - _helper._stateControl(pen, null, null, null); - _helper.streamWriter!.beginPath(point1.dx, point1.dy); - _helper.streamWriter!.appendLineSegment(point2.dx, point2.dy); - _helper.streamWriter!.strokePath(); - _helper.endMarkContent(); - (_helper._getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.pdf, - ); - } - - /// Draws a rectangle specified by a pen, a brush and a Rect structure. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw rectangle. - /// .drawRectangle( - /// pen: PdfPens.black, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// // Save the document. - /// List bytes = doc.save(); - /// // Dispose the document. - /// doc.dispose(); - /// ``` - void drawRectangle({PdfPen? pen, PdfBrush? brush, required Rect bounds}) { - _helper._beginMarkContent(); - _helper._stateControl(pen, brush, null, null); - _helper.streamWriter!.appendRectangle( - bounds.left, - bounds.top, - bounds.width, - bounds.height, - ); - _drawPath(pen, brush, PdfFillMode.winding, false); - _helper.endMarkContent(); - (_helper._getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.pdf, - ); - } - - /// Draws a template at the specified location and size. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create a PDF Template. - /// PdfTemplate template = PdfTemplate(200, 100) - /// ..graphics!.drawRectangle( - /// brush: PdfSolidBrush(PdfColor(255, 0, 0)), - /// bounds: Rect.fromLTWH(0, 20, 200, 50)) - /// ..graphics!.drawString( - /// 'This is PDF template.', PdfStandardFont(PdfFontFamily.courier, 14)); - /// //Draws the template into the page graphics of the document. - /// doc.pages.add().graphics.drawPdfTemplate(template, Offset(100, 100)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawPdfTemplate(PdfTemplate template, Offset location, [Size? size]) { - size ??= template.size; - _drawTemplate(template, location, size); - } - - /// Draws an image into PDF graphics. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw image. - /// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawImage(PdfImage image, Rect bounds) { - _drawImage(image, bounds); - } - - /// Sets the transparency of this graphics. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page - /// doc.pages.add().graphics - /// //Set transparancy. - /// ..setTransparency(0.5, alphaBrush: 0.5, mode: PdfBlendMode.hardLight) - /// ..drawString('Hello world!', - /// PdfStandardFont(PdfFontFamily.helvetica, 12, style: PdfFontStyle.bold), - /// brush: PdfBrushes.red, pen: PdfPens.black); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void setTransparency( - double alpha, { - double? alphaBrush, - PdfBlendMode mode = PdfBlendMode.normal, - }) { - if (alpha < 0 || alpha > 1) { - ArgumentError.value(alpha, 'alpha', 'invalid alpha value'); - } - alphaBrush ??= alpha; - _helper.applyTransparency(alpha, alphaBrush, mode); - } - - /// Sets the clipping region of this Graphics to the result of the - /// specified operation combining the current clip region and the - /// rectangle specified by a RectangleF structure. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Create PDF graphics for the page - /// doc.pages.add().graphics - /// //set clip. - /// ..setClip(bounds: Rect.fromLTWH(0, 0, 50, 12), mode: PdfFillMode.alternate) - /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// pen: PdfPens.red); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void setClip({Rect? bounds, PdfPath? path, PdfFillMode? mode}) { - if (bounds != null) { - mode ??= PdfFillMode.winding; - _helper.streamWriter!.appendRectangle( - bounds.left, - bounds.top, - bounds.width, - bounds.height, - ); - _helper.streamWriter!.clipPath(mode == PdfFillMode.alternate); - } else if (path != null) { - mode ??= PdfPathHelper.getHelper(path).fillMode; - _buildUpPath( - PdfPathHelper.getHelper(path).points, - PdfPathHelper.getHelper(path).pathTypes, - ); - _helper.streamWriter!.clipPath(mode == PdfFillMode.alternate); - } - } - - /// Draws a Bezier spline defined by four [Offset] structures. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw Bezier - /// .drawBezier( - /// Offset(10, 10), Offset(10, 50), Offset(50, 80), Offset(80, 10), - /// pen: PdfPens.brown); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawBezier( - Offset startPoint, - Offset firstControlPoint, - Offset secondControlPoint, - Offset endPoint, { - PdfPen? pen, - }) { - _helper._beginMarkContent(); - _helper._stateControl(pen, null, null, null); - final PdfStreamWriter sw = _helper.streamWriter!; - sw.beginPath(startPoint.dx, startPoint.dy); - sw.appendBezierSegment( - firstControlPoint.dx, - firstControlPoint.dy, - secondControlPoint.dx, - secondControlPoint.dy, - endPoint.dx, - endPoint.dy, - ); - sw.strokePath(); - _helper.endMarkContent(); - } - - /// Draws a GraphicsPath defined by a pen, a brush and path. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw Paths - /// .drawPath( - /// PdfPath() - /// ..addRectangle(Rect.fromLTWH(10, 10, 100, 100)) - /// ..addEllipse(Rect.fromLTWH(100, 100, 100, 100)), - /// pen: PdfPens.black, - /// brush: PdfBrushes.red); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawPath(PdfPath path, {PdfPen? pen, PdfBrush? brush}) { - _helper._beginMarkContent(); - _helper._stateControl(pen, brush, null, null); - _buildUpPath( - PdfPathHelper.getHelper(path).points, - PdfPathHelper.getHelper(path).pathTypes, - ); - _drawPath(pen, brush, PdfPathHelper.getHelper(path).fillMode, false); - _helper.endMarkContent(); - } - - /// Draws a pie shape defined by an ellipse specified by a Rect structure - /// uiand two radial lines. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw Pie - /// .drawPie(Rect.fromLTWH(10, 10, 100, 200), 90, 270, - /// pen: PdfPens.green, brush: PdfBrushes.red); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawPie( - Rect bounds, - double startAngle, - double sweepAngle, { - PdfPen? pen, - PdfBrush? brush, - }) { - if (sweepAngle != 0) { - _helper._beginMarkContent(); - _helper._stateControl(pen, brush, null, null); - _constructArcPath( - bounds.left, - bounds.top, - bounds.left + bounds.width, - bounds.top + bounds.height, - startAngle, - sweepAngle, - ); - _helper.streamWriter!.appendLineSegment( - bounds.left + bounds.width / 2, - bounds.top + bounds.height / 2, - ); - _drawPath(pen, brush, PdfFillMode.winding, true); - _helper.endMarkContent(); - } - } - - /// Draws an ellipse specified by a bounding Rect structure. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw ellipse - /// .drawEllipse(Rect.fromLTWH(10, 10, 100, 100), - /// pen: PdfPens.black, brush: PdfBrushes.red); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawEllipse(Rect bounds, {PdfPen? pen, PdfBrush? brush}) { - _helper._beginMarkContent(); - _helper._stateControl(pen, brush, null, null); - _constructArcPath( - bounds.left, - bounds.top, - bounds.right, - bounds.bottom, - 0, - 360, - ); - _drawPath(pen, brush, PdfFillMode.winding, true); - _helper.endMarkContent(); - } - - /// Draws an arc representing a portion of an ellipse specified - /// by a Rect structure. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages - /// .add() - /// .graphics - /// //Draw Arc. - /// .drawArc(Rect.fromLTWH(10, 10, 100, 200), 90, 270, pen: PdfPens.red); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawArc( - Rect bounds, - double startAngle, - double sweepAngle, { - PdfPen? pen, - }) { - if (sweepAngle != 0) { - _helper._beginMarkContent(); - _helper._stateControl(pen, null, null, null); - _constructArcPath( - bounds.left, - bounds.top, - bounds.left + bounds.width, - bounds.top + bounds.height, - startAngle, - sweepAngle, - ); - _drawPath(pen, null, PdfFillMode.winding, false); - _helper.endMarkContent(); - } - } - - /// Draws a polygon defined by a brush, an array of [Offset] structures. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages.add().graphics.drawPolygon([ - /// Offset(10, 100), - /// Offset(10, 200), - /// Offset(100, 100), - /// Offset(100, 200), - /// Offset(55, 150) - /// ], pen: PdfPens.black, brush: PdfBrushes.red); - /// //Saves the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - void drawPolygon(List points, {PdfPen? pen, PdfBrush? brush}) { - _helper._beginMarkContent(); - if (points.isEmpty) { - return; - } - _helper._stateControl(pen, brush, null, null); - _helper.streamWriter!.beginPath( - points.elementAt(0).dx, - points.elementAt(0).dy, - ); - - for (int i = 1; i < points.length; ++i) { - _helper.streamWriter!.appendLineSegment( - points.elementAt(i).dx, - points.elementAt(i).dy, - ); - } - _drawPath(pen, brush, PdfFillMode.winding, true); - _helper.endMarkContent(); - } - - /// Skews the coordinate system axes. - /// - /// ```dart - /// //Create a PDF Document. - /// PdfDocument document = PdfDocument(); - /// document.pages.add().graphics - /// ..save() - /// //Set skew transform - /// ..skewTransform(10, 10) - /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// pen: PdfPens.red) - /// ..restore(); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void skewTransform(double angleX, double angleY) { - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - _getSkewTransform(angleX, angleY, matrix); - _helper.streamWriter!.modifyCurrentMatrix(matrix); - matrix.multiply(matrix); - } - - //Implementation - void _initialize() { - _helper.mediaBoxUpperRightBound = 0; - _isStateSaved = false; - _helper._isColorSpaceInitialized = false; - _helper._currentBrush = null; - colorSpace = PdfColorSpace.rgb; - _previousTextRenderingMode = _TextRenderingMode.fill; - _previousTextRenderingMode = -1; - _previousCharacterSpacing = -1.0; - _previousWordSpacing = -1.0; - _helper._previousTextScaling = -100.0; - _helper.clipBounds = PdfRectangle(0, 0, size.width, size.height); - _graphicsState = []; - (_helper._getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.pdf, - ); - } - - void _drawImage(PdfImage image, Rect rectangle) { - _helper._beginMarkContent(); - final PdfRectangle bounds = PdfRectangle.fromRect( - (rectangle.width <= 0 && rectangle.height <= 0) - ? Rect.fromLTWH( - rectangle.left, - rectangle.top, - image.width * 0.75, - image.height * 0.75, - ) - : rectangle, - ); - PdfGraphicsState? beforeOrientation; - final int angle = PdfImageHelper.getJpegOrientationAngle(image)!.toInt(); - if (angle > 0) { - beforeOrientation = save(); - switch (angle) { - case 90: - translateTransform(bounds.x, bounds.y); - rotateTransform(90); - bounds.x = 0; - bounds.y = -bounds.width; - final double modwidth = bounds.height; - final double modHeight = bounds.width; - bounds.width = modwidth; - bounds.height = modHeight; - break; - case 180: - translateTransform(bounds.x, bounds.y); - rotateTransform(180); - bounds.x = -bounds.width; - bounds.y = -bounds.height; - break; - case 270: - translateTransform(bounds.x, bounds.y); - rotateTransform(270); - bounds.x = -bounds.height; - bounds.y = 0; - final double modwidth2 = bounds.height; - final double modHeight2 = bounds.width; - bounds.width = modwidth2; - bounds.height = modHeight2; - break; - default: - break; - } - } - if (clientSize.height < 0) { - bounds.y += clientSize.height; - } - PdfImageHelper.save(image); - final PdfGraphicsState state = save(); - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - matrix.translate(bounds.x, -(bounds.y + bounds.height)); - matrix.scale(bounds.width, bounds.height); - _helper.streamWriter!.modifyCurrentMatrix(matrix); - final PdfResources resources = _helper._getResources!() as PdfResources; - final PdfName name = resources.getName(image); - if (_helper.layer != null) { - PdfPageHelper.getHelper(_helper.page!).setResources(resources); - } - _helper.streamWriter!.executeObject(name); - restore(state); - if (beforeOrientation != null) { - restore(beforeOrientation); - } - _helper.endMarkContent(); - (_helper._getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.grayScaleImage, - ); - (_helper._getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.colorImage, - ); - (_helper._getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.indexedImage, - ); - (_helper._getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.text, - ); - } - - void _drawPath( - PdfPen? pen, - PdfBrush? brush, - PdfFillMode fillMode, - bool needClosing, - ) { - final bool isPen = - pen != null && PdfColorHelper.getHelper(pen.color).isFilled; - final bool isBrush = - brush != null && - PdfColorHelper.getHelper((brush as PdfSolidBrush).color).isFilled; - final bool isEvenOdd = fillMode == PdfFillMode.alternate; - if (isPen && isBrush) { - if (needClosing) { - _helper.streamWriter!.closeFillStrokePath(isEvenOdd); - } else { - _helper.streamWriter!.fillStrokePath(isEvenOdd); - } - } else if (!isPen && !isBrush) { - _helper.streamWriter!.endPath(); - } else if (isPen) { - if (needClosing) { - _helper.streamWriter!.closeStrokePath(); - } else { - _helper.streamWriter!.strokePath(); - } - } else if (isBrush) { - if (needClosing) { - _helper.streamWriter!.closeFillPath(isEvenOdd); - } else { - _helper.streamWriter!.fillPath(isEvenOdd); - } - } else { - throw UnsupportedError('Internal CLR error.'); - } - } - - void _drawTemplate(PdfTemplate template, Offset location, Size size) { - _helper._beginMarkContent(); - if (_helper.layer != null && - PdfPageHelper.getHelper(_helper.page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).document!, - ).conformanceLevel != - PdfConformanceLevel.none && - PdfGraphicsHelper.getHelper(template.graphics!)._currentFont != null && - (PdfGraphicsHelper.getHelper(template.graphics!)._currentFont - is PdfStandardFont || - PdfGraphicsHelper.getHelper(template.graphics!)._currentFont - is PdfCjkStandardFont)) { - throw ArgumentError( - 'All the fonts must be embedded in ${PdfDocumentHelper.getHelper(PdfPageHelper.getHelper(_helper.page!).document!).conformanceLevel} document.', - ); - } else if (_helper.layer != null && - PdfPageHelper.getHelper(_helper.page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).document!, - ).conformanceLevel == - PdfConformanceLevel.a1b && - PdfGraphicsHelper.getHelper(template.graphics!)._currentFont != null && - PdfGraphicsHelper.getHelper(template.graphics!)._currentFont - is PdfTrueTypeFont) { - PdfTrueTypeFontHelper.getHelper( - PdfGraphicsHelper.getHelper(template.graphics!)._currentFont! - as PdfTrueTypeFont, - ).fontInternal.initializeCidSet(); - } - if ((_helper.layer != null || _helper._documentLayer != null) && - PdfTemplateHelper.getHelper(template).isLoadedPageTemplate) { - PdfCrossTable? crossTable; - if (PdfPageHelper.getHelper(_helper.page!).isLoadedPage) { - if (PdfPageHelper.getHelper(_helper.page!).section != null) { - crossTable = - PdfDocumentHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).section!, - ).document!, - ).crossTable; - } else { - crossTable = - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).document!, - ).crossTable; - } - } else { - if (PdfPageHelper.getHelper(_helper.page!).section != null) { - crossTable = - (PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).section!, - ).document != - null) - ? PdfDocumentHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).section!, - ).document!, - ).crossTable - : PdfDocumentHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).section!, - ).pdfDocument!, - ).crossTable; - } else { - crossTable = - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_helper.page!).document!, - ).crossTable; - } - } - if ((PdfTemplateHelper.getHelper(template).isReadonly) || - (PdfTemplateHelper.getHelper(template).isLoadedPageTemplate)) { - PdfTemplateHelper.getHelper(template).cloneResources(crossTable); - } - } - if (PdfTemplateHelper.getHelper(template).origin.dx > 0 && - PdfTemplateHelper.getHelper(template).origin.dy > 0 && - template.size > size) { - size = template.size; - } - final double scaleX = - (template.size.width > 0) ? size.width / template.size.width : 1; - final double scaleY = - (template.size.height > 0) ? size.height / template.size.height : 1; - final bool hasScale = !(scaleX == 1 && scaleY == 1); - final PdfGraphicsState state = save(); - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - if ((_helper.layer != null || _helper._documentLayer != null) && - _helper.page != null && - PdfTemplateHelper.getHelper(template).isLoadedPageTemplate && - PdfPageHelper.getHelper(_helper.page!).isLoadedPage) { - bool needTransformation = false; - final PdfDictionary dictionary = - PdfPageHelper.getHelper(_helper.page!).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.cropBox) && - dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { - PdfArray? cropBox; - PdfArray? mediaBox; - if (dictionary[PdfDictionaryProperties.cropBox] is PdfReferenceHolder) { - cropBox = - (dictionary[PdfDictionaryProperties.cropBox]! - as PdfReferenceHolder) - .object - as PdfArray?; - } else { - cropBox = dictionary[PdfDictionaryProperties.cropBox] as PdfArray?; - } - if (dictionary[PdfDictionaryProperties.mediaBox] - is PdfReferenceHolder) { - mediaBox = - (dictionary[PdfDictionaryProperties.mediaBox]! - as PdfReferenceHolder) - .object - as PdfArray?; - } else { - mediaBox = dictionary[PdfDictionaryProperties.mediaBox] as PdfArray?; - } - if (cropBox != null && mediaBox != null) { - if (cropBox.toRectangle() == mediaBox.toRectangle()) { - needTransformation = true; - } - } - } - if (dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { - PdfArray? mBox; - if (dictionary[PdfDictionaryProperties.mediaBox] - is PdfReferenceHolder) { - mBox = - (dictionary[PdfDictionaryProperties.mediaBox]! - as PdfReferenceHolder) - .object - as PdfArray?; - } else { - mBox = dictionary[PdfDictionaryProperties.mediaBox] as PdfArray?; - } - if (mBox != null) { - if ((mBox[3]! as PdfNumber).value == 0) { - needTransformation = true; - } - } - } - if ((PdfPageHelper.getHelper(_helper.page!).origin.dx >= 0 && - PdfPageHelper.getHelper(_helper.page!).origin.dy >= 0) || - needTransformation) { - matrix.translate(location.dx, -(location.dy + size.height)); - } else if (PdfPageHelper.getHelper(_helper.page!).origin.dx >= 0 && - PdfPageHelper.getHelper(_helper.page!).origin.dy <= 0) { - matrix.translate(location.dx, -(location.dy + size.height)); - } else { - matrix.translate(location.dx, -(location.dy + 0)); - } - } else { - if (PdfTemplateHelper.getHelper(template).origin.dx > 0 && - PdfTemplateHelper.getHelper(template).origin.dy > 0 && - location.dx == 0 && - location.dy == 0) { - matrix.translate( - location.dx - PdfTemplateHelper.getHelper(template).origin.dx, - -(location.dy + size.height), - ); - } else { - matrix.translate(location.dx, -(location.dy + size.height)); - } - } - if (hasScale) { - matrix.scale(scaleX, scaleY); - } - _helper.streamWriter!.modifyCurrentMatrix(matrix); - final PdfResources resources = _helper._getResources!() as PdfResources; - final PdfName name = resources.getName(template); - _helper.streamWriter!.executeObject(name); - restore(state); - _helper.endMarkContent(); - //Transfer automatic fields from template. - final PdfGraphics? g = template.graphics; - - if (g != null) { - for (final Object? fieldInfo - in PdfObjectCollectionHelper.getHelper( - PdfGraphicsHelper.getHelper(g).autoFields!, - ).list) { - if (fieldInfo is PdfAutomaticFieldInfo) { - final PdfPoint newLocation = PdfPoint( - fieldInfo.location.x + location.dx, - fieldInfo.location.y + location.dy, - ); - final double scalingX = - template.size.width == 0 ? 0 : size.width / template.size.width; - final double scalingY = - template.size.height == 0 - ? 0 - : size.height / template.size.height; - _helper.autoFields!.add( - PdfAutomaticFieldInfo( - fieldInfo.field, - newLocation, - scalingX, - scalingY, - ), - ); - PdfPageHelper.getHelper(_helper.page!).dictionary!.modify(); - } - } - } - resources.requireProcset(PdfDictionaryProperties.grayScaleImage); - resources.requireProcset(PdfDictionaryProperties.colorImage); - resources.requireProcset(PdfDictionaryProperties.indexedImage); - resources.requireProcset(PdfDictionaryProperties.text); - } - - PdfGraphicsState _doRestoreState() { - final PdfGraphicsState state = _graphicsState.last; - _graphicsState.remove(_graphicsState.last); - _helper._transformationMatrix = state._matrix; - _helper._currentBrush = state._brush; - _helper._currentPen = state._pen; - _helper._currentFont = state._font; - colorSpace = state._colorSpace; - _previousCharacterSpacing = state._characterSpacing; - _previousWordSpacing = state._wordSpacing; - _helper._previousTextScaling = state._textScaling; - _previousTextRenderingMode = state._textRenderingMode; - _helper.streamWriter!.restoreGraphicsState(); - return state; - } - - void _buildUpPath(List points, List types) { - for (int i = 0; i < points.length; ++i) { - final dynamic typeValue = types[i]; - final Offset point = points[i]; - switch (typeValue as PathPointType) { - case PathPointType.start: - _helper.streamWriter!.beginPath(point.dx, point.dy); - break; - - case PathPointType.bezier3: - Offset? p2, p3; - final Map returnValue = _getBezierPoints( - points, - types, - i, - p2, - p3, - ); - i = returnValue['i'] as int; - final List p = returnValue['points'] as List; - p2 = p.first; - p3 = p.last; - _helper.streamWriter!.appendBezierSegment( - point.dx, - point.dy, - p2.dx, - p2.dy, - p3.dx, - p3.dy, - ); - break; - - case PathPointType.line: - _helper.streamWriter!.appendLineSegment(point.dx, point.dy); - break; - - case PathPointType.closeSubpath: - _helper.streamWriter!.closePath(); - break; - } - } - } - - Map _getBezierPoints( - List points, - List types, - int i, - Offset? p2, - Offset? p3, - ) { - const String errorMsg = 'Malforming path.'; - ++i; - if (types[i] == PathPointType.bezier3) { - p2 = points[i]; - ++i; - if (types[i] == PathPointType.bezier3) { - p3 = points[i]; - } else { - throw ArgumentError(errorMsg); - } - } else { - throw ArgumentError(errorMsg); - } - return { - 'i': i, - 'points': [p2, p3], - }; - } - - void _constructArcPath( - double x1, - double y1, - double x2, - double y2, - double startAng, - double sweepAngle, - ) { - final List> points = _getBezierArcPoints( - x1, - y1, - x2, - y2, - startAng, - sweepAngle, - ); - if (points.isEmpty) { - return; - } - List pt = points[0]; - _helper.streamWriter!.beginPath(pt[0], pt[1]); - for (int i = 0; i < points.length; ++i) { - pt = points.elementAt(i); - _helper.streamWriter!.appendBezierSegment( - pt[2], - pt[3], - pt[4], - pt[5], - pt[6], - pt[7], - ); - } - } - - static List> _getBezierArcPoints( - double x1, - double y1, - double x2, - double y2, - double startAng, - double extent, - ) { - if (x1 > x2) { - double tmp; - tmp = x1; - x1 = x2; - x2 = tmp; - } - if (y2 > y1) { - double tmp; - tmp = y1; - y1 = y2; - y2 = tmp; - } - double fragAngle; - int numFragments; - - if (extent.abs() <= 90) { - fragAngle = extent; - numFragments = 1; - } else { - numFragments = (extent.abs() / 90).ceil(); - fragAngle = extent / numFragments; - } - final double xCen = (x1 + x2) / 2; - final double yCen = (y1 + y2) / 2; - final double rx = (x2 - x1) / 2; - final double ry = (y2 - y1) / 2; - final double halfAng = fragAngle * pi / 360.0; - final double kappa = - (4.0 / 3.0 * (1.0 - cos(halfAng)) / sin(halfAng)).abs(); - final List> pointList = >[]; - for (int i = 0; i < numFragments; ++i) { - final double theta0 = (startAng + i * fragAngle) * pi / 180.0; - final double theta1 = (startAng + (i + 1) * fragAngle) * pi / 180.0; - final double cos0 = cos(theta0); - final double cos1 = cos(theta1); - final double sin0 = sin(theta0); - final double sin1 = sin(theta1); - if (fragAngle > 0) { - pointList.add([ - xCen + rx * cos0, - yCen - ry * sin0, - xCen + rx * (cos0 - kappa * sin0), - yCen - ry * (sin0 + kappa * cos0), - xCen + rx * (cos1 + kappa * sin1), - yCen - ry * (sin1 - kappa * cos1), - xCen + rx * cos1, - yCen - ry * sin1, - ]); - } else { - pointList.add([ - xCen + rx * cos0, - yCen - ry * sin0, - xCen + rx * (cos0 + kappa * sin0), - yCen - ry * (sin0 - kappa * cos0), - xCen + rx * (cos1 - kappa * sin1), - yCen - ry * (sin1 + kappa * cos1), - xCen + rx * cos1, - yCen - ry * sin1, - ]); - } - } - return pointList; - } - - PdfTransformationMatrix _getSkewTransform( - double angleX, - double angleY, - PdfTransformationMatrix input, - ) { - input.skew(-angleX, -angleY); - return input; - } - - String _normalizeText(PdfFont font, String text) { - if (font is PdfStandardFont) { - text = _convert(text); - } - return text; - } - - String _convert(String text) { - final Windows1252Encoding encoding = Windows1252Encoding(); - final List encodedBytes = encoding.getBytes(text); - return String.fromCharCodes(encodedBytes); - } -} - -/// Represents the state of a Graphics object. \ -/// This object is returned by a call to the Save methods. -class PdfGraphicsState { - // Constructors - /// Initializes a new instance of the [PdfGraphicsState] class. - PdfGraphicsState._(PdfGraphics graphics, PdfTransformationMatrix matrix) { - _graphics = graphics; - _matrix = matrix; - _initialize(); - } - - //Fields - late PdfGraphics _graphics; - late PdfTransformationMatrix _matrix; - late double _characterSpacing; - late double _wordSpacing; - late double _textScaling; - PdfPen? _pen; - PdfBrush? _brush; - PdfFont? _font; - late PdfColorSpace _colorSpace; - late int _textRenderingMode; - - //Implementation - void _initialize() { - _textRenderingMode = _TextRenderingMode.fill; - _colorSpace = PdfColorSpace.rgb; - _characterSpacing = 0.0; - _wordSpacing = 0.0; - _textScaling = 100.0; - } -} - -class _TransparencyData { - //Constructor - const _TransparencyData(this.alphaPen, this.alphaBrush, this.blendMode); - //Fields - final double? alphaPen; - final double? alphaBrush; - final PdfBlendMode? blendMode; - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is _TransparencyData && - other.alphaPen == alphaPen && - alphaBrush == other.alphaBrush && - blendMode == other.blendMode; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => - alphaPen.hashCode + alphaBrush.hashCode + blendMode.hashCode; -} - -/// Specifies the text rendering mode. -class _TextRenderingMode { - /// Fill text. - static const int fill = 0; - - /// Stroke text. - static const int stroke = 1; - - /// Fill, then stroke text. - static const int fillStroke = 2; - - /// Neither fill nor stroke text (invisible). - static const int none = 3; - - /// The flag showing that the text should be a part of a clipping path. - static const int clipFlag = 4; -} - -class PdfAutomaticFieldInfoCollection extends PdfObjectCollection { - // constructor - PdfAutomaticFieldInfoCollection() : super() { - _helper = PdfAutomaticFieldInfoCollectionHelper(this); - } - - late PdfAutomaticFieldInfoCollectionHelper _helper; - - // implementaion - int add(PdfAutomaticFieldInfo fieldInfo) { - return _helper.add(fieldInfo); - } -} - -class PdfAutomaticFieldInfoCollectionHelper extends PdfObjectCollectionHelper { - // constructor - PdfAutomaticFieldInfoCollectionHelper(this.base) : super(base); - PdfAutomaticFieldInfoCollection base; - - // implementaion - int add(PdfAutomaticFieldInfo fieldInfo) { - list.add(fieldInfo); - return base.count - 1; - } -} - -/// [PdfGraphics] helper -class PdfGraphicsHelper { - /// internal constructor - PdfGraphicsHelper(this.base); - - /// internal field - late PdfGraphics base; - - /// internal method - static PdfGraphicsHelper getHelper(PdfGraphics base) { - return base._helper; - } - - /// internal method - static PdfGraphics load(Size size, Function getResources, PdfStream stream) { - return PdfGraphics._(size, getResources, stream); - } - - /// internal field - bool _colorSpaceChanged = false; - - /// internal field - PdfStreamWriter? streamWriter; - - /// internal field - late PdfRectangle clipBounds; - - /// internal field - final bool hasTransparencyBrush = false; - - /// internal field - PdfArray? cropBox; - - /// internal field - double? mediaBoxUpperRightBound; - - /// internal field - PdfPageLayer? layer; - - /// internal field - PdfStringLayoutResult? stringLayoutResult; - - /// internal field - PdfStringFormat? currentStringFormat; - bool _isColorSpaceInitialized = false; - PdfFont? _currentFont; - PdfBrush? _currentBrush; - PdfTransformationMatrix? _transformationMatrix; - PdfLayer? _documentLayer; - PdfAutomaticFieldInfoCollection? _automaticFields; - Map<_TransparencyData, PdfTransparency>? _trasparencies; - Function? _getResources; - double? _previousTextScaling; - final Map _colorSpaces = { - PdfColorSpace.rgb: 'RGB', - PdfColorSpace.cmyk: 'CMYK', - PdfColorSpace.grayScale: 'GrayScale', - PdfColorSpace.indexed: 'Indexed', - }; - PdfPen? _currentPen; - bool _isItalic = false; - - /// internal property - PdfTransformationMatrix get matrix { - _transformationMatrix ??= PdfTransformationMatrix(); - return _transformationMatrix!; - } - - /// internal method - PdfPage? get page { - if (_documentLayer != null) { - return PdfLayerHelper.getHelper(_documentLayer!).page; - } else { - return layer!.page; - } - } - - /// Gets the automatic fields. - PdfAutomaticFieldInfoCollection? get autoFields { - _automaticFields ??= PdfAutomaticFieldInfoCollection(); - return _automaticFields; - } - - /// internal method - void applyTransparency(double alpha, double alphaBrush, PdfBlendMode mode) { - _trasparencies ??= <_TransparencyData, PdfTransparency>{}; - PdfTransparency? transparency; - final _TransparencyData transparencyData = _TransparencyData( - alpha, - alphaBrush, - mode, - ); - if (_trasparencies!.containsKey(transparencyData)) { - transparency = _trasparencies![transparencyData]; - } - if (transparency == null) { - transparency = PdfTransparency( - alpha, - alphaBrush, - mode, - conformance: - layer != null && - PdfPageHelper.getHelper(page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(page!).document!, - ).conformanceLevel == - PdfConformanceLevel.a1b, - ); - _trasparencies![transparencyData] = transparency; - } - final PdfResources resources = _getResources!() as PdfResources; - final PdfName name = resources.getName(transparency); - if (layer != null) { - PdfPageHelper.getHelper(page!).setResources(resources); - } - streamWriter!.setGraphicsState(name); - } - - /// internal method - void layoutString( - String s, - PdfFont font, { - PdfPen? pen, - PdfBrush? brush, - required PdfRectangle layoutRectangle, - PdfStringFormat? format, - }) { - final PdfStringLayouter layouter = PdfStringLayouter(); - PdfStringLayoutResult result; - result = layouter.layout( - s, - font, - format, - width: layoutRectangle.width, - height: layoutRectangle.height, - ); - if (!result.isEmpty) { - final PdfRectangle rectangle = checkCorrectLayoutRectangle( - result.size, - layoutRectangle.x, - layoutRectangle.y, - format, - ); - if (layoutRectangle.width <= 0) { - layoutRectangle.x = rectangle.x; - layoutRectangle.width = rectangle.width; - } - if (layoutRectangle.height <= 0) { - layoutRectangle.y = rectangle.y; - layoutRectangle.height = rectangle.height; - } - if (base.clientSize.height < 0) { - layoutRectangle.y += base.clientSize.height; - } - drawStringLayoutResult(result, font, pen, brush, layoutRectangle, format); - stringLayoutResult = result; - (_getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.text, - ); - } - } - - /// internal method - void drawStringLayoutResult( - PdfStringLayoutResult result, - PdfFont font, - PdfPen? pen, - PdfBrush? brush, - PdfRectangle layoutRectangle, - PdfStringFormat? format, - ) { - if (!result.isEmpty) { - _beginMarkContent(); - PdfGraphicsState? gState; - if (font is PdfTrueTypeFont && - PdfTrueTypeFontHelper.getHelper(font).fontInternal.ttfMetrics != - null && - !PdfTrueTypeFontHelper.getHelper( - font, - ).fontInternal.ttfMetrics!.isItalic && - PdfFontHelper.getHelper(font).isItalic) { - gState = base.save(); - _isItalic = true; - } - _applyStringSettings(font, pen, brush, format, layoutRectangle); - final double textScaling = - format != null - ? PdfStringFormatHelper.getHelper(format).scalingFactor - : 100.0; - if (textScaling != _previousTextScaling) { - streamWriter!.setTextScaling(textScaling); - _previousTextScaling = textScaling; - } - double verticalAlignShift = getTextVerticalAlignShift( - result.size.height, - layoutRectangle.height, - format, - ); - double? height; - if (_isItalic) { - height = - (format == null || format.lineSpacing == 0) - ? font.height - : format.lineSpacing + font.height; - final bool subScript = - format != null && - format.subSuperscript == PdfSubSuperscript.subscript; - final double shift = - subScript - ? height - - (font.height + - PdfFontHelper.getHelper( - font, - ).metrics!.getDescent(format)) - : (height - - PdfFontHelper.getHelper(font).metrics!.getAscent(format)); - base.translateTransform( - layoutRectangle.left + font.size / 5, - layoutRectangle.top - shift + verticalAlignShift, - ); - base.skewTransform(0, -11); - } - if (!_isItalic) { - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - matrix.translate( - layoutRectangle.x, - (-(layoutRectangle.y + font.height) - - (PdfFontHelper.getHelper(font).metrics!.getDescent(format) > 0 - ? -PdfFontHelper.getHelper( - font, - ).metrics!.getDescent(format) - : PdfFontHelper.getHelper( - font, - ).metrics!.getDescent(format))) - - verticalAlignShift, - ); - streamWriter!.modifyTransformationMatrix(matrix); - } else { - streamWriter!.startNextLine(0, 0); - } - if (_isItalic && height != null && height >= font.size) { - streamWriter!.stream!.write(height.toString()); - streamWriter!.stream!.write(PdfOperators.whiteSpace); - streamWriter!.writeOperator(PdfOperators.setTextLeading); - } - if (layoutRectangle.height < font.size) { - if ((result.size.height - layoutRectangle.height) < - (font.size / 2) - 1) { - verticalAlignShift = 0.0; - } - } - _drawLayoutResult(result, font, format, layoutRectangle); - if (verticalAlignShift != 0) { - streamWriter!.startNextLine( - 0, - -(verticalAlignShift - result.lineHeight), - ); - } - streamWriter!.endText(); - if (gState != null) { - base.restore(gState); - _isItalic = false; - } - _underlineStrikeoutText( - pen, - brush, - result, - font, - layoutRectangle, - format, - ); - endMarkContent(); - } - } - - void _drawLayoutResult( - PdfStringLayoutResult result, - PdfFont font, - PdfStringFormat? format, - PdfRectangle layoutRectangle, - ) { - bool? unicode = false; - if (font is PdfTrueTypeFont) { - unicode = PdfTrueTypeFontHelper.getHelper(font).unicode; - } - final List lines = result.lines!; - final double height = - (format == null || format.lineSpacing == 0) - ? font.height - : format.lineSpacing + font.height; - for (int i = 0; i < lines.length; i++) { - final LineInfo lineInfo = lines[i]; - final String? line = lineInfo.text; - final double? lineWidth = lineInfo.width; - if ((line == null || line.isEmpty) && !_isItalic) { - final double verticalAlignShift = getTextVerticalAlignShift( - result.size.height, - layoutRectangle.height, - format, - ); - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - double baseline = - (-(layoutRectangle.y + font.height) - - PdfFontHelper.getHelper(font).metrics!.getDescent(format)) - - verticalAlignShift; - baseline -= height * (i + 1); - matrix.translate(layoutRectangle.x, baseline); - streamWriter!.modifyTransformationMatrix(matrix); - } else { - double horizontalAlignShift = _getHorizontalAlignShift( - lineWidth, - layoutRectangle.width, - format, - ); - final double? lineIndent = _getLineIndent( - lineInfo, - format, - layoutRectangle, - i == 0, - ); - horizontalAlignShift += (!_rightToLeft(format)) ? lineIndent! : 0; - - if (horizontalAlignShift != 0) { - streamWriter!.startNextLine(horizontalAlignShift, 0); - } - if (font is PdfCjkStandardFont) { - _drawCjkString(lineInfo, layoutRectangle, font, format); - } else if (unicode!) { - _drawUnicodeLine(lineInfo, layoutRectangle, font, format); - } else { - _drawAsciiLine(lineInfo, layoutRectangle, font, format); - } - - if (i + 1 != lines.length) { - if (!_isItalic) { - final double verticalAlignShift = getTextVerticalAlignShift( - result.size.height, - layoutRectangle.height, - format, - ); - final PdfTransformationMatrix matrix = PdfTransformationMatrix(); - double baseline = - (-(layoutRectangle.y + font.height) - - PdfFontHelper.getHelper(font).metrics!.getDescent(format)) - - verticalAlignShift; - baseline -= height * (i + 1); - matrix.translate(layoutRectangle.x, baseline); - streamWriter!.modifyTransformationMatrix(matrix); - } else { - //tan(11) = 0.19486, theta value for italic skewAngle (11 degree). - streamWriter!.startNextLine( - font.height * 0.19486 - horizontalAlignShift, - 0, - ); - } - } - } - } - (_getResources!() as PdfResources).requireProcset( - PdfDictionaryProperties.text, - ); - } - - bool _rightToLeft(PdfStringFormat? format) { - bool rtl = - format != null && format.textDirection == PdfTextDirection.rightToLeft; - if (format != null && format.textDirection != PdfTextDirection.none) { - rtl = true; - } - return rtl; - } - - double _getHorizontalAlignShift( - double? lineWidth, - double boundsWidth, - PdfStringFormat? format, - ) { - double shift = 0; - if (boundsWidth >= 0 && - format != null && - format.alignment != PdfTextAlignment.left) { - switch (format.alignment) { - case PdfTextAlignment.center: - shift = (boundsWidth - lineWidth!) / 2; - break; - case PdfTextAlignment.right: - shift = boundsWidth - lineWidth!; - break; - case PdfTextAlignment.left: - case PdfTextAlignment.justify: - break; - } - } - return shift; - } - - void _drawAsciiLine( - LineInfo lineInfo, - PdfRectangle layoutRectangle, - PdfFont font, - PdfStringFormat? format, - ) { - _justifyLine(lineInfo, layoutRectangle.width, format); - final PdfString str = PdfString(lineInfo.text!); - str.isAsciiEncode = true; - streamWriter!.showNextLineText(str); - } - - void _drawCjkString( - LineInfo lineInfo, - PdfRectangle layoutRectangle, - PdfFont font, - PdfStringFormat? format, - ) { - _justifyLine(lineInfo, layoutRectangle.width, format); - final String line = lineInfo.text!; - final List str = _getCjkString(line); - streamWriter!.showNextLineText(str); - } - - String _addChars(PdfTrueTypeFont font, String line, PdfStringFormat? format) { - String text = line; - final UnicodeTrueTypeFont internalFont = - PdfTrueTypeFontHelper.getHelper(font).fontInternal; - final TtfReader ttfReader = internalFont.reader; - // Reconvert string according to unicode standard. - text = ttfReader.convertString(text); - if (format != null) { - internalFont.setSymbols(line, ttfReader.internalUsedChars); - } else { - PdfTrueTypeFontHelper.getHelper( - font, - ).setSymbols(text, ttfReader.internalUsedChars); - } - ttfReader.internalUsedChars = null; - final List bytes = PdfString.toUnicodeArray(text); - text = PdfString.byteToString(bytes); - return text; - } - - void _drawUnicodeLine( - LineInfo lineInfo, - PdfRectangle layoutRectangle, - PdfFont font, - PdfStringFormat? format, - ) { - final String? line = lineInfo.text; - final bool useWordSpace = - format != null && - (format.wordSpacing != 0 || - format.alignment == PdfTextAlignment.justify); - final PdfTrueTypeFont ttfFont = font as PdfTrueTypeFont; - final double wordSpacing = _justifyLine( - lineInfo, - layoutRectangle.width, - format, - ); - if (format != null && format.textDirection != PdfTextDirection.none) { - final ArabicShapeRenderer renderer = ArabicShapeRenderer(); - final String txt = renderer.shape(line!.split(''), 0); - final Bidi bidi = Bidi(); - bidi.isVisualOrder = false; - final String result = - bidi.getLogicalToVisualString( - txt, - format.textDirection == PdfTextDirection.rightToLeft, - )['rtlText'] - as String; - bidi.isVisualOrder = true; - final List blocks = []; - if (useWordSpace) { - final List words = result.split(' '); - for (int i = 0; i < words.length; i++) { - blocks.add(_addChars(font, words[i], format)); - } - } else { - blocks.add(_addChars(font, result, format)); - } - List words = []; - if (blocks.length > 1) { - words = result.split(' '); - } else { - words.add(result); - } - _drawUnicodeBlocks(blocks, words, ttfFont, format, wordSpacing); - } else if (useWordSpace) { - final dynamic result = _breakUnicodeLine(line!, ttfFont, null); - final List blocks = result['tokens'] as List; - final List words = result['words']! as List; - _drawUnicodeBlocks(blocks, words, ttfFont, format, wordSpacing); - } else { - final String token = _convertToUnicode(line!, ttfFont)!; - final PdfString value = _getUnicodeString(token); - streamWriter!.showNextLineText(value); - } - } - - void _drawUnicodeBlocks( - List blocks, - List words, - PdfTrueTypeFont font, - PdfStringFormat? format, - double wordSpacing, - ) { - streamWriter!.startNextLine(); - double x = 0; - double xShift = 0; - double firstLineIndent = 0; - double paragraphIndent = 0; - try { - if (format != null) { - firstLineIndent = - PdfStringFormatHelper.getHelper(format).firstLineIndent; - paragraphIndent = format.paragraphIndent; - PdfStringFormatHelper.getHelper(format).firstLineIndent = 0; - format.paragraphIndent = 0; - } - double spaceWidth = - PdfTrueTypeFontHelper.getHelper(font).getCharWidth(' ', format) + - wordSpacing; - final double characterSpacing = - format != null ? format.characterSpacing : 0; - final double wordSpace = - format != null && wordSpacing == 0 ? format.wordSpacing : 0; - spaceWidth += characterSpacing + wordSpace; - for (int i = 0; i < blocks.length; i++) { - final String token = blocks[i]; - final String word = words[i]; - double tokenWidth = 0; - if (x != 0.0) { - streamWriter!.startNextLine(x, 0); - } - if (word.isNotEmpty) { - tokenWidth += font.measureString(word, format: format).width; - tokenWidth += characterSpacing; - final PdfString val = _getUnicodeString(token); - streamWriter!.showText(val); - } - if (i != blocks.length - 1) { - x = tokenWidth + spaceWidth; - xShift += x; - } - } - // Rolback current line position. - if (xShift > 0) { - streamWriter!.startNextLine(-xShift, 0); - } - } finally { - if (format != null) { - PdfStringFormatHelper.getHelper(format).firstLineIndent = - firstLineIndent; - format.paragraphIndent = paragraphIndent; - } - } - } - - dynamic _breakUnicodeLine( - String line, - PdfTrueTypeFont ttfFont, - List? words, - ) { - words = line.split(' '); - final List tokens = []; - for (int i = 0; i < words.length; i++) { - final String word = words[i]; - final String? token = _convertToUnicode(word, ttfFont); - if (token != null) { - tokens.add(token); - } - } - return {'tokens': tokens, 'words': words}; - } - - PdfString _getUnicodeString(String token) { - final PdfString val = PdfString(token); - val.isAsciiEncode = true; - return val; - } - - int _getTextRenderingMode( - PdfPen? pen, - PdfBrush? brush, - PdfStringFormat? format, - ) { - int tm = _TextRenderingMode.none; - if (pen != null && brush != null) { - tm = _TextRenderingMode.fillStroke; - } else if (pen != null) { - tm = _TextRenderingMode.stroke; - } else { - tm = _TextRenderingMode.fill; - } - if (format != null && format.clipPath) { - tm |= _TextRenderingMode.clipFlag; - } - return tm; - } - - void _applyStringSettings( - PdfFont font, - PdfPen? pen, - PdfBrush? brush, - PdfStringFormat? format, - PdfRectangle bounds, - ) { - int renderingMode = _getTextRenderingMode(pen, brush, format); - bool setLineWidth = false; - if (font is PdfTrueTypeFont && - PdfTrueTypeFontHelper.getHelper(font).fontInternal.ttfMetrics != null && - !PdfTrueTypeFontHelper.getHelper( - font, - ).fontInternal.ttfMetrics!.isBold && - PdfFontHelper.getHelper(font).isBold) { - if (pen == null && brush != null && brush is PdfSolidBrush) { - pen = PdfPen(brush.color); - } - renderingMode = 2; - setLineWidth = true; - } - streamWriter!.writeOperator(PdfOperators.beginText); - _stateControl(pen, brush, font, format); - if (setLineWidth) { - streamWriter!.setLineWidth(font.size / 30); - } - if (renderingMode != base._previousTextRenderingMode) { - streamWriter!.setTextRenderingMode(renderingMode); - base._previousTextRenderingMode = renderingMode; - } - final double characterSpace = - (format != null) ? format.characterSpacing : 0; - if (characterSpace != base._previousCharacterSpacing) { - streamWriter!.setCharacterSpacing(characterSpace); - base._previousCharacterSpacing = characterSpace; - } - final double wordSpace = (format != null) ? format.wordSpacing : 0; - if (wordSpace != base._previousWordSpacing) { - streamWriter!.setWordSpacing(wordSpace); - base._previousWordSpacing = wordSpace; - } - } - - void _stateControl( - PdfPen? pen, - PdfBrush? brush, - PdfFont? font, - PdfStringFormat? format, - ) { - if (brush != null) { - if (layer != null) { - if (!PdfPageHelper.getHelper(page!).isLoadedPage && - !PdfDocumentHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page!).section!, - ).pdfDocument!, - ).isLoadedDocument) { - if (_colorSpaceChanged == false) { - if (page != null) { - base.colorSpace = - PdfPageHelper.getHelper(page!).document!.colorSpace; - } - _colorSpaceChanged = true; - } - } - } - _initCurrentColorSpace(base.colorSpace); - } else if (pen != null) { - if (layer != null) { - if (!PdfPageHelper.getHelper(page!).isLoadedPage && - !PdfDocumentHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page!).section!, - ).pdfDocument!, - ).isLoadedDocument) { - base.colorSpace = PdfPageHelper.getHelper(page!).document!.colorSpace; - } - } - _initCurrentColorSpace(base.colorSpace); - } - _penControl(pen, false); - _brushControl(brush, false); - _fontControl(font, format, false); - } - - void _initCurrentColorSpace(PdfColorSpace? colorspace) { - if (!_isColorSpaceInitialized) { - streamWriter!.setColorSpace( - PdfName('Device${_colorSpaces[base.colorSpace]!}'), - true, - ); - streamWriter!.setColorSpace( - PdfName('Device${_colorSpaces[base.colorSpace]!}'), - false, - ); - _isColorSpaceInitialized = true; - } - } - - void _penControl(PdfPen? pen, bool saveState) { - if (pen != null) { - _currentPen = pen; - base.colorSpace = PdfColorSpace.rgb; - PdfPenHelper.getHelper(pen).monitorChanges( - _currentPen, - streamWriter!, - _getResources, - saveState, - base.colorSpace, - matrix, - ); - _currentPen = pen; - } - } - - void _brushControl(PdfBrush? brush, bool saveState) { - if (brush != null) { - PdfBrushHelper.monitorChanges( - brush as PdfSolidBrush, - _currentBrush, - streamWriter, - _getResources, - saveState, - base.colorSpace, - ); - _currentBrush = brush; - brush = null; - } - } - - void _fontControl(PdfFont? font, PdfStringFormat? format, bool saveState) { - if (font != null) { - if ((font is PdfStandardFont || font is PdfCjkStandardFont) && - layer != null && - PdfPageHelper.getHelper(page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(page!).document!, - ).conformanceLevel != - PdfConformanceLevel.none) { - throw ArgumentError( - 'All the fonts must be embedded in ${PdfDocumentHelper.getHelper(PdfPageHelper.getHelper(page!).document!).conformanceLevel} document.', - ); - } else if (font is PdfTrueTypeFont && - layer != null && - PdfPageHelper.getHelper(page!).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(page!).document!, - ).conformanceLevel == - PdfConformanceLevel.a1b) { - PdfTrueTypeFontHelper.getHelper(font).fontInternal.initializeCidSet(); - } - final PdfSubSuperscript current = - format != null ? format.subSuperscript : PdfSubSuperscript.none; - final PdfSubSuperscript privious = - currentStringFormat != null - ? currentStringFormat!.subSuperscript - : PdfSubSuperscript.none; - if (saveState || font != _currentFont || current != privious) { - final PdfResources resources = _getResources!() as PdfResources; - _currentFont = font; - currentStringFormat = format; - streamWriter!.setFont( - font, - resources.getName(font), - PdfFontHelper.getHelper(font).metrics!.getSize(format)!, - ); - } - } - } - - void _beginMarkContent() { - if (_documentLayer != null) { - PdfLayerHelper.getHelper(_documentLayer!).beginLayer(base); - } - } - - /// internal method - void endMarkContent() { - if (_documentLayer != null) { - if (PdfLayerHelper.getHelper(_documentLayer!).isEndState && - PdfLayerHelper.getHelper(_documentLayer!).parentLayer.isNotEmpty) { - for ( - int i = 0; - i < PdfLayerHelper.getHelper(_documentLayer!).parentLayer.length; - i++ - ) { - streamWriter!.write('EMC\n'); - } - } - if (PdfLayerHelper.getHelper(_documentLayer!).isEndState) { - streamWriter!.write('EMC\n'); - } - } - } - - /// internal method - PdfRectangle checkCorrectLayoutRectangle( - PdfSize textSize, - double? x, - double? y, - PdfStringFormat? format, - ) { - final PdfRectangle layoutedRectangle = PdfRectangle( - x!, - y!, - textSize.width, - textSize.width, - ); - if (format != null) { - switch (format.alignment) { - case PdfTextAlignment.center: - layoutedRectangle.x -= layoutedRectangle.width / 2; - break; - case PdfTextAlignment.right: - layoutedRectangle.x -= layoutedRectangle.width; - break; - case PdfTextAlignment.left: - case PdfTextAlignment.justify: - break; - } - switch (format.lineAlignment) { - case PdfVerticalAlignment.middle: - layoutedRectangle.y -= layoutedRectangle.height / 2; - break; - case PdfVerticalAlignment.bottom: - layoutedRectangle.y -= layoutedRectangle.height; - break; - case PdfVerticalAlignment.top: - break; - } - } - return layoutedRectangle; - } - - void _underlineStrikeoutText( - PdfPen? pen, - PdfBrush? brush, - PdfStringLayoutResult result, - PdfFont font, - PdfRectangle layoutRectangle, - PdfStringFormat? format, - ) { - if (PdfFontHelper.getHelper(font).isUnderline | - PdfFontHelper.getHelper(font).isStrikeout) { - final PdfPen? linePen = _createUnderlineStikeoutPen( - pen, - brush, - font, - format, - ); - if (linePen != null) { - final double verticalShift = getTextVerticalAlignShift( - result.size.height, - layoutRectangle.height, - format, - ); - double underlineYOffset = - layoutRectangle.y + - verticalShift + - PdfFontHelper.getHelper(font).metrics!.getAscent(format) + - 1.5 * linePen.width; - double strikeoutYOffset = - layoutRectangle.y + - verticalShift + - PdfFontHelper.getHelper(font).metrics!.getHeight(format) / 2 + - 1.5 * linePen.width; - final List? lines = result.lines; - for (int i = 0; i < result.lines!.length; i++) { - final LineInfo lineInfo = lines![i]; - final double? lineWidth = lineInfo.width; - double horizontalShift = _getHorizontalAlignShift( - lineWidth, - layoutRectangle.width, - format, - ); - final double? lineIndent = _getLineIndent( - lineInfo, - format, - layoutRectangle, - i == 0, - ); - horizontalShift += (!_rightToLeft(format)) ? lineIndent! : 0; - final double x1 = layoutRectangle.x + horizontalShift; - final double x2 = - (!_shouldJustify(lineInfo, layoutRectangle.width, format)) - ? x1 + lineWidth! - lineIndent! - : x1 + layoutRectangle.width - lineIndent!; - if (PdfFontHelper.getHelper(font).isUnderline) { - base.drawLine( - linePen, - Offset(x1, underlineYOffset), - Offset(x2, underlineYOffset), - ); - underlineYOffset += result.lineHeight; - } - if (PdfFontHelper.getHelper(font).isStrikeout) { - base.drawLine( - linePen, - Offset(x1, strikeoutYOffset), - Offset(x2, strikeoutYOffset), - ); - strikeoutYOffset += result.lineHeight; - } - } - } - } - } - - PdfPen? _createUnderlineStikeoutPen( - PdfPen? pen, - PdfBrush? brush, - PdfFont font, - PdfStringFormat? format, - ) { - final double lineWidth = - PdfFontHelper.getHelper(font).metrics!.getSize(format)! / 20; - PdfPen? linePen; - if (pen != null) { - linePen = PdfPen(pen.color, width: lineWidth); - } else if (brush != null) { - linePen = PdfPen.fromBrush(brush, width: lineWidth); - } - return linePen; - } - - /// internal method - void initializeCoordinates() { - streamWriter!.writeComment('Change co-ordinate system to left/top.'); - if (mediaBoxUpperRightBound != -base.size.height) { - if (cropBox == null) { - _translate(); - } else { - final double cropX = (cropBox![0]! as PdfNumber).value!.toDouble(); - final double cropY = (cropBox![1]! as PdfNumber).value!.toDouble(); - final double cropW = (cropBox![2]! as PdfNumber).value!.toDouble(); - final double cropH = (cropBox![3]! as PdfNumber).value!.toDouble(); - if (cropX != 0 || - cropY != 0 || - base.size.width == cropW || - base.size.height == cropH) { - base.translateTransform(cropX, -cropH); - } else { - _translate(); - } - } - } - } - - void _translate() { - if (mediaBoxUpperRightBound == base.size.height || - mediaBoxUpperRightBound == 0) { - base.translateTransform(0, -base.size.height); - } else { - base.translateTransform(0, -mediaBoxUpperRightBound!); - } - } - - /// internal method - void clipTranslateMarginsWithBounds(PdfRectangle clipBounds) { - this.clipBounds = clipBounds; - streamWriter!.writeComment('Clip margins.'); - streamWriter!.appendRectangle( - clipBounds.x, - clipBounds.y, - clipBounds.width, - clipBounds.height, - ); - streamWriter!.closePath(); - streamWriter!.clipPath(false); - streamWriter!.writeComment('Translate co-ordinate system.'); - base.translateTransform(clipBounds.x, clipBounds.y); - } - - /// internal method - void clipTranslateMargins( - double x, - double y, - double left, - double top, - double right, - double bottom, - ) { - final PdfRectangle clipArea = PdfRectangle( - left, - top, - base.size.width - left - right, - base.size.height - top - bottom, - ); - clipBounds = clipArea; - streamWriter!.writeComment('Clip margins.'); - streamWriter!.appendRectangle( - clipBounds.x, - clipBounds.y, - clipBounds.width, - clipBounds.height, - ); - streamWriter!.closePath(); - streamWriter!.clipPath(false); - streamWriter!.writeComment('Translate co-ordinate system.'); - base.translateTransform(x, y); - } - - /// internal method - void setLayer(PdfPageLayer? pageLayer, [PdfLayer? pdfLayer]) { - PdfPage? page; - if (pageLayer != null) { - layer = pageLayer; - page = pageLayer.page; - } else if (pdfLayer != null) { - _documentLayer = pdfLayer; - page = PdfLayerHelper.getHelper(pdfLayer).page; - } - if (page != null) { - PdfPageHelper.getHelper(page).beginSave = () { - if (_automaticFields != null) { - for (final Object? fieldInfo - in PdfObjectCollectionHelper.getHelper(_automaticFields!).list) { - if (fieldInfo is PdfAutomaticFieldInfo) { - PdfAutomaticFieldHelper.getHelper(fieldInfo.field).performDraw( - base, - fieldInfo.location, - fieldInfo.scalingX, - fieldInfo.scalingY, - ); - } - } - } - }; - } - } - - /// internal method - void setTransparencyGroup(PdfPage page) { - final PdfDictionary group = PdfDictionary(); - group[PdfDictionaryProperties.colorSpace] = PdfName('DeviceRGB'); - group[PdfDictionaryProperties.k] = PdfBoolean(false); - group[PdfDictionaryProperties.s] = PdfName('Transparency'); - group[PdfDictionaryProperties.i] = PdfBoolean(false); - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties.group] = - group; - } - - /// internal method - void reset(Size size) { - base._canvasSize = size; - streamWriter!.clear(); - base._initialize(); - initializeCoordinates(); - } - - /// internal method - double getTextVerticalAlignShift( - double? textHeight, - double boundsHeight, - PdfStringFormat? format, - ) { - double shift = 0; - if (boundsHeight >= 0 && - format != null && - format.lineAlignment != PdfVerticalAlignment.top) { - switch (format.lineAlignment) { - case PdfVerticalAlignment.middle: - shift = (boundsHeight - textHeight!) / 2; - break; - case PdfVerticalAlignment.bottom: - shift = boundsHeight - textHeight!; - break; - case PdfVerticalAlignment.top: - break; - } - } - return shift; - } - - /// internal method - Rect getLineBounds( - int lineIndex, - PdfStringLayoutResult result, - PdfFont font, - PdfRectangle layoutRectangle, - PdfStringFormat? format, - ) { - PdfRectangle bounds = PdfRectangle.empty; - if (!result.isEmpty && lineIndex < result.lineCount && lineIndex >= 0) { - final LineInfo line = result.lines![lineIndex]; - final double verticalShift = getTextVerticalAlignShift( - result.size.height, - layoutRectangle.height, - format, - ); - final double y = - verticalShift + layoutRectangle.y + (result.lineHeight * lineIndex); - final double? lineWidth = line.width; - double horizontalShift = _getHorizontalAlignShift( - lineWidth, - layoutRectangle.width, - format, - ); - final double? lineIndent = _getLineIndent( - line, - format, - layoutRectangle, - lineIndex == 0, - ); - horizontalShift += (!_rightToLeft(format)) ? lineIndent! : 0; - final double x = layoutRectangle.x + horizontalShift; - final double width = - (!_shouldJustify(line, layoutRectangle.width, format)) - ? lineWidth! - lineIndent! - : layoutRectangle.width - lineIndent!; - final double height = result.lineHeight; - bounds = PdfRectangle(x, y, width, height); - } - return bounds.rect; - } - - double? _getLineIndent( - LineInfo lineInfo, - PdfStringFormat? format, - PdfRectangle layoutBounds, - bool firstLine, - ) { - double? lineIndent = 0; - final bool firstParagraphLine = - (lineInfo.lineType & - PdfStringLayouter.getLineTypeValue(LineType.firstParagraphLine)!) > - 0; - if (format != null && firstParagraphLine) { - lineIndent = - firstLine - ? PdfStringFormatHelper.getHelper(format).firstLineIndent - : format.paragraphIndent; - lineIndent = - (layoutBounds.width > 0) - ? (layoutBounds.width <= lineIndent - ? layoutBounds.width - : lineIndent) - : lineIndent; - } - return lineIndent; - } - - String? _convertToUnicode(String text, PdfTrueTypeFont font) { - String? token; - final TtfReader ttfReader = - PdfTrueTypeFontHelper.getHelper(font).fontInternal.reader; - token = ttfReader.convertString(text); - PdfTrueTypeFontHelper.getHelper( - font, - ).setSymbols(text, ttfReader.internalUsedChars); - ttfReader.internalUsedChars = null; - final List bytes = PdfString.toUnicodeArray(token); - token = PdfString.byteToString(bytes); - return token; - } - - List _getCjkString(String line) { - List value = PdfString.toUnicodeArray(line); - value = PdfString.escapeSymbols(value); - return value; - } - - double _justifyLine( - LineInfo lineInfo, - double boundsWidth, - PdfStringFormat? format, - ) { - final String line = lineInfo.text!; - double? lineWidth = lineInfo.width; - final bool shouldJustify = _shouldJustify(lineInfo, boundsWidth, format); - final bool hasWordSpacing = format != null && format.wordSpacing != 0; - final int whitespacesCount = StringTokenizer.getCharacterCount( - line, - StringTokenizer.spaces, - ); - double wordSpace = 0; - if (shouldJustify) { - if (hasWordSpacing) { - lineWidth = lineWidth! - (whitespacesCount * format.wordSpacing); - } - final double difference = boundsWidth - lineWidth!; - wordSpace = difference / whitespacesCount; - streamWriter!.setWordSpacing(wordSpace); - } else if (format != null && format.alignment == PdfTextAlignment.justify) { - streamWriter!.setWordSpacing(0); - } - return wordSpace; - } - - bool _shouldJustify( - LineInfo lineInfo, - double boundsWidth, - PdfStringFormat? format, - ) { - final String line = lineInfo.text!; - final double? lineWidth = lineInfo.width; - final bool justifyStyle = - format != null && format.alignment == PdfTextAlignment.justify; - final bool goodWidth = boundsWidth >= 0 && lineWidth! < boundsWidth; - final int whitespacesCount = StringTokenizer.getCharacterCount( - line, - StringTokenizer.spaces, - ); - final bool hasSpaces = - whitespacesCount > 0 && line[0] != StringTokenizer.whiteSpace; - final bool goodLineBreakStyle = - (lineInfo.lineType & - PdfStringLayouter.getLineTypeValue(LineType.layoutBreak)!) > - 0; - final bool shouldJustify = - justifyStyle && goodWidth && hasSpaces && goodLineBreakStyle; - return shouldJustify; - } - - /// internal method - static List> getBezierArcPoints( - double x1, - double y1, - double x2, - double y2, - double startAng, - double extent, - ) { - return PdfGraphics._getBezierArcPoints(x1, y1, x2, y2, startAng, extent); - } -} +import 'dart:math'; +import 'dart:ui'; + +import '../drawing/drawing.dart'; +import '../general/pdf_collection.dart'; +import '../general/windows1252encoding.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_stream_writer.dart'; +import '../pages/pdf_layer.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_layer.dart'; +import '../pages/pdf_section.dart'; +import '../pdf_document/automatic_fields/pdf_automatic_field.dart'; +import '../pdf_document/automatic_fields/pdf_automatic_field_info.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'brushes/pdf_solid_brush.dart'; +import 'enums.dart'; +import 'figures/enums.dart'; +import 'figures/pdf_path.dart'; +import 'figures/pdf_template.dart'; +import 'fonts/enums.dart'; +import 'fonts/pdf_cjk_standard_font.dart'; +import 'fonts/pdf_font.dart'; +import 'fonts/pdf_standard_font.dart'; +import 'fonts/pdf_string_format.dart'; +import 'fonts/pdf_string_layout_result.dart'; +import 'fonts/pdf_string_layouter.dart'; +import 'fonts/pdf_true_type_font.dart'; +import 'fonts/rtl/arabic_shape_renderer.dart'; +import 'fonts/rtl/bidi.dart'; +import 'fonts/string_tokenizer.dart'; +import 'fonts/ttf_reader.dart'; +import 'fonts/unicode_true_type_font.dart'; +import 'images/pdf_image.dart'; +import 'pdf_color.dart'; +import 'pdf_pen.dart'; +import 'pdf_resources.dart'; +import 'pdf_transformation_matrix.dart'; +import 'pdf_transparency.dart'; + +/// Represents a graphics context of the objects. +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument doc = PdfDocument() +/// ..pages +/// .add() +/// //PDF graphics for the page. +/// .graphics +/// .drawRectangle( +/// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 515, 762)); +/// //Saves the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +class PdfGraphics { + //Constructor + /// Initializes a new instance of the [PdfGraphics] class. + PdfGraphics._(Size size, Function getResources, PdfStream stream) { + _helper = PdfGraphicsHelper(this); + _helper.streamWriter = PdfStreamWriter(stream); + _helper._getResources = getResources; + _canvasSize = size; + _initialize(); + } + + //Fields + late PdfGraphicsHelper _helper; + late Size _canvasSize; + late bool _isStateSaved; + int? _previousTextRenderingMode = _TextRenderingMode.fill; + double? _previousCharacterSpacing; + double? _previousWordSpacing; + late List _graphicsState; + + //Properties + /// Gets or sets the current color space of the document. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page + /// doc.pages.add().graphics + /// ..colorSpace = PdfColorSpace.grayScale + /// ..drawRectangle( + /// brush: PdfBrushes.red, bounds: Rect.fromLTWH(0, 0, 515, 762)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + late PdfColorSpace colorSpace; + + /// Gets the size of the canvas. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page. + /// PdfGraphics graphics = doc.pages.add().graphics; + /// //Draw string to PDF page graphics. + /// graphics.drawString( + /// //Get the graphics canvas size. + /// 'Canvas size: ${graphics.size}', + /// PdfStandardFont(PdfFontFamily.courier, 12)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + Size get size => _canvasSize; + + /// Gets the size of the canvas reduced by margins and page templates. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page + /// PdfGraphics graphics = doc.pages.add().graphics; + /// //Draw rectangle to PDF page graphics. + /// graphics.drawRectangle( + /// brush: PdfBrushes.red, + /// //Get the graphics client size. + /// bounds: Rect.fromLTWH( + /// 0, 0, graphics.clientSize.width, graphics.clientSize.height)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + Size get clientSize => + Size(_helper.clipBounds.width, _helper.clipBounds.height); + + //Public methods + /// Changes the origin of the coordinate system + /// by prepending the specified translation + /// to the transformation matrix of this Graphics. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page + /// doc.pages.add().graphics + /// ..save() + /// //Set graphics translate transform. + /// ..translateTransform(100, 100) + /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.red) + /// ..restore(); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void translateTransform(double offsetX, double offsetY) { + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + matrix.translate(offsetX, -offsetY); + _helper.streamWriter!.modifyCurrentMatrix(matrix); + _helper.matrix.multiply(matrix); + } + + /// Applies the specified rotation + /// to the transformation matrix of this Graphics. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Adds a page to the PDF document. + /// doc.pages.add().graphics + /// //Set rotate transform + /// ..rotateTransform(-90) + /// //Draws the text into PDF graphics in -90 degree rotation. + /// ..drawString('Hello world.', PdfStandardFont(PdfFontFamily.courier, 14), + /// bounds: Rect.fromLTWH(-100, 0, 200, 50)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void rotateTransform(double angle) { + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + matrix.rotate(-angle); + _helper.streamWriter!.modifyCurrentMatrix(matrix); + _helper.matrix.multiply(matrix); + } + + /// Saves the current state of this Graphics + /// and identifies the saved state with a GraphicsState. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page + /// PdfGraphics graphics = doc.pages.add().graphics; + /// //Save the graphics. + /// PdfGraphicsState state = graphics.save(); + /// //Set graphics translate transform. + /// graphics + /// ..translateTransform(100, 100) + /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.red) + /// //Restore the graphics. + /// ..restore(state); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + PdfGraphicsState save() { + final PdfGraphicsState state = PdfGraphicsState._(this, _helper.matrix); + state._brush = _helper._currentBrush; + state._pen = _helper._currentPen; + state._font = _helper._currentFont; + state._colorSpace = colorSpace; + state._characterSpacing = _previousCharacterSpacing!; + state._wordSpacing = _previousWordSpacing!; + state._textScaling = _helper._previousTextScaling!; + state._textRenderingMode = _previousTextRenderingMode!; + _graphicsState.add(state); + if (_isStateSaved) { + _helper.streamWriter!.restoreGraphicsState(); + _isStateSaved = false; + } + _helper.streamWriter!.saveGraphicsState(); + return state; + } + + /// Restores the state of this Graphics to the state represented + /// by a GraphicsState. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page + /// PdfGraphics graphics = doc.pages.add().graphics; + /// //Save the graphics. + /// PdfGraphicsState state = graphics.save(); + /// //Set graphics translate transform. + /// graphics + /// ..translateTransform(100, 100) + /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.red) + /// //Restore the graphics. + /// ..restore(state); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void restore([PdfGraphicsState? state]) { + if (state == null) { + if (_graphicsState.isNotEmpty) { + _doRestoreState(); + } + } else { + if (state._graphics != this) { + throw ArgumentError.value( + this, + 'The graphics state belongs to another graphics object', + ); + } + if (_graphicsState.contains(state)) { + while (true) { + if (_graphicsState.isEmpty) { + break; + } + final PdfGraphicsState popState = _doRestoreState(); + if (popState == state) { + break; + } + } + } + } + } + + /// Draws the specified text string at the specified location. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw string to PDF page graphics. + /// .drawString( + /// 'Hello world!', + /// PdfStandardFont(PdfFontFamily.helvetica, 12, + /// style: PdfFontStyle.bold), + /// bounds: Rect.fromLTWH(0, 0, 200, 50), + /// brush: PdfBrushes.red, + /// pen: PdfPens.blue, + /// format: PdfStringFormat(alignment: PdfTextAlignment.left)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawString( + String s, + PdfFont font, { + PdfPen? pen, + PdfBrush? brush, + Rect? bounds, + PdfStringFormat? format, + }) { + PdfRectangle layoutRectangle; + if (bounds != null) { + layoutRectangle = PdfRectangle.fromRect(bounds); + } else { + layoutRectangle = PdfRectangle.empty; + } + if (pen == null && brush == null) { + brush = PdfSolidBrush(PdfColor(0, 0, 0)); + } + + s = _normalizeText(font, s); + + _helper.layoutString( + s, + font, + pen: pen, + brush: brush, + layoutRectangle: layoutRectangle, + format: format, + ); + } + + /// Draws a line connecting the two points specified by the coordinate pairs. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw line. + /// .drawLine(PdfPens.black, Offset(100, 100), Offset(200, 100)); + /// // Save the document. + /// List bytes = doc.save(); + /// // Dispose the document. + /// doc.dispose(); + /// ``` + void drawLine(PdfPen pen, Offset point1, Offset point2) { + _helper._beginMarkContent(); + _helper._stateControl(pen, null, null, null); + _helper.streamWriter!.beginPath(point1.dx, point1.dy); + _helper.streamWriter!.appendLineSegment(point2.dx, point2.dy); + _helper.streamWriter!.strokePath(); + _helper.endMarkContent(); + (_helper._getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.pdf, + ); + } + + /// Draws a rectangle specified by a pen, a brush and a Rect structure. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw rectangle. + /// .drawRectangle( + /// pen: PdfPens.black, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// // Save the document. + /// List bytes = doc.save(); + /// // Dispose the document. + /// doc.dispose(); + /// ``` + void drawRectangle({PdfPen? pen, PdfBrush? brush, required Rect bounds}) { + _helper._beginMarkContent(); + _helper._stateControl(pen, brush, null, null); + _helper.streamWriter!.appendRectangle( + bounds.left, + bounds.top, + bounds.width, + bounds.height, + ); + _drawPath(pen, brush, PdfFillMode.winding, false); + _helper.endMarkContent(); + (_helper._getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.pdf, + ); + } + + /// Draws a template at the specified location and size. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create a PDF Template. + /// PdfTemplate template = PdfTemplate(200, 100) + /// ..graphics!.drawRectangle( + /// brush: PdfSolidBrush(PdfColor(255, 0, 0)), + /// bounds: Rect.fromLTWH(0, 20, 200, 50)) + /// ..graphics!.drawString( + /// 'This is PDF template.', PdfStandardFont(PdfFontFamily.courier, 14)); + /// //Draws the template into the page graphics of the document. + /// doc.pages.add().graphics.drawPdfTemplate(template, Offset(100, 100)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawPdfTemplate(PdfTemplate template, Offset location, [Size? size]) { + size ??= template.size; + _drawTemplate(template, location, size); + } + + /// Draws an image into PDF graphics. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw image. + /// .drawImage(PdfBitmap(imageData), Rect.fromLTWH(0, 0, 100, 100)); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawImage(PdfImage image, Rect bounds) { + _drawImage(image, bounds); + } + + /// Sets the transparency of this graphics. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page + /// doc.pages.add().graphics + /// //Set transparancy. + /// ..setTransparency(0.5, alphaBrush: 0.5, mode: PdfBlendMode.hardLight) + /// ..drawString('Hello world!', + /// PdfStandardFont(PdfFontFamily.helvetica, 12, style: PdfFontStyle.bold), + /// brush: PdfBrushes.red, pen: PdfPens.black); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void setTransparency( + double alpha, { + double? alphaBrush, + PdfBlendMode mode = PdfBlendMode.normal, + }) { + if (alpha < 0 || alpha > 1) { + ArgumentError.value(alpha, 'alpha', 'invalid alpha value'); + } + alphaBrush ??= alpha; + _helper.applyTransparency(alpha, alphaBrush, mode); + } + + /// Sets the clipping region of this Graphics to the result of the + /// specified operation combining the current clip region and the + /// rectangle specified by a RectangleF structure. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Create PDF graphics for the page + /// doc.pages.add().graphics + /// //set clip. + /// ..setClip(bounds: Rect.fromLTWH(0, 0, 50, 12), mode: PdfFillMode.alternate) + /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// pen: PdfPens.red); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void setClip({Rect? bounds, PdfPath? path, PdfFillMode? mode}) { + if (bounds != null) { + mode ??= PdfFillMode.winding; + _helper.streamWriter!.appendRectangle( + bounds.left, + bounds.top, + bounds.width, + bounds.height, + ); + _helper.streamWriter!.clipPath(mode == PdfFillMode.alternate); + } else if (path != null) { + mode ??= PdfPathHelper.getHelper(path).fillMode; + _buildUpPath( + PdfPathHelper.getHelper(path).points, + PdfPathHelper.getHelper(path).pathTypes, + ); + _helper.streamWriter!.clipPath(mode == PdfFillMode.alternate); + } + } + + /// Draws a Bezier spline defined by four [Offset] structures. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw Bezier + /// .drawBezier( + /// Offset(10, 10), Offset(10, 50), Offset(50, 80), Offset(80, 10), + /// pen: PdfPens.brown); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawBezier( + Offset startPoint, + Offset firstControlPoint, + Offset secondControlPoint, + Offset endPoint, { + PdfPen? pen, + }) { + _helper._beginMarkContent(); + _helper._stateControl(pen, null, null, null); + final PdfStreamWriter sw = _helper.streamWriter!; + sw.beginPath(startPoint.dx, startPoint.dy); + sw.appendBezierSegment( + firstControlPoint.dx, + firstControlPoint.dy, + secondControlPoint.dx, + secondControlPoint.dy, + endPoint.dx, + endPoint.dy, + ); + sw.strokePath(); + _helper.endMarkContent(); + } + + /// Draws a GraphicsPath defined by a pen, a brush and path. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw Paths + /// .drawPath( + /// PdfPath() + /// ..addRectangle(Rect.fromLTWH(10, 10, 100, 100)) + /// ..addEllipse(Rect.fromLTWH(100, 100, 100, 100)), + /// pen: PdfPens.black, + /// brush: PdfBrushes.red); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawPath(PdfPath path, {PdfPen? pen, PdfBrush? brush}) { + _helper._beginMarkContent(); + _helper._stateControl(pen, brush, null, null); + _buildUpPath( + PdfPathHelper.getHelper(path).points, + PdfPathHelper.getHelper(path).pathTypes, + ); + _drawPath(pen, brush, PdfPathHelper.getHelper(path).fillMode, false); + _helper.endMarkContent(); + } + + /// Draws a pie shape defined by an ellipse specified by a Rect structure + /// uiand two radial lines. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw Pie + /// .drawPie(Rect.fromLTWH(10, 10, 100, 200), 90, 270, + /// pen: PdfPens.green, brush: PdfBrushes.red); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawPie( + Rect bounds, + double startAngle, + double sweepAngle, { + PdfPen? pen, + PdfBrush? brush, + }) { + if (sweepAngle != 0) { + _helper._beginMarkContent(); + _helper._stateControl(pen, brush, null, null); + _constructArcPath( + bounds.left, + bounds.top, + bounds.left + bounds.width, + bounds.top + bounds.height, + startAngle, + sweepAngle, + ); + _helper.streamWriter!.appendLineSegment( + bounds.left + bounds.width / 2, + bounds.top + bounds.height / 2, + ); + _drawPath(pen, brush, PdfFillMode.winding, true); + _helper.endMarkContent(); + } + } + + /// Draws an ellipse specified by a bounding Rect structure. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw ellipse + /// .drawEllipse(Rect.fromLTWH(10, 10, 100, 100), + /// pen: PdfPens.black, brush: PdfBrushes.red); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawEllipse(Rect bounds, {PdfPen? pen, PdfBrush? brush}) { + _helper._beginMarkContent(); + _helper._stateControl(pen, brush, null, null); + _constructArcPath( + bounds.left, + bounds.top, + bounds.right, + bounds.bottom, + 0, + 360, + ); + _drawPath(pen, brush, PdfFillMode.winding, true); + _helper.endMarkContent(); + } + + /// Draws an arc representing a portion of an ellipse specified + /// by a Rect structure. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages + /// .add() + /// .graphics + /// //Draw Arc. + /// .drawArc(Rect.fromLTWH(10, 10, 100, 200), 90, 270, pen: PdfPens.red); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawArc( + Rect bounds, + double startAngle, + double sweepAngle, { + PdfPen? pen, + }) { + if (sweepAngle != 0) { + _helper._beginMarkContent(); + _helper._stateControl(pen, null, null, null); + _constructArcPath( + bounds.left, + bounds.top, + bounds.left + bounds.width, + bounds.top + bounds.height, + startAngle, + sweepAngle, + ); + _drawPath(pen, null, PdfFillMode.winding, false); + _helper.endMarkContent(); + } + } + + /// Draws a polygon defined by a brush, an array of [Offset] structures. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages.add().graphics.drawPolygon([ + /// Offset(10, 100), + /// Offset(10, 200), + /// Offset(100, 100), + /// Offset(100, 200), + /// Offset(55, 150) + /// ], pen: PdfPens.black, brush: PdfBrushes.red); + /// //Saves the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + void drawPolygon(List points, {PdfPen? pen, PdfBrush? brush}) { + _helper._beginMarkContent(); + if (points.isEmpty) { + return; + } + _helper._stateControl(pen, brush, null, null); + _helper.streamWriter!.beginPath( + points.elementAt(0).dx, + points.elementAt(0).dy, + ); + + for (int i = 1; i < points.length; ++i) { + _helper.streamWriter!.appendLineSegment( + points.elementAt(i).dx, + points.elementAt(i).dy, + ); + } + _drawPath(pen, brush, PdfFillMode.winding, true); + _helper.endMarkContent(); + } + + /// Skews the coordinate system axes. + /// + /// ```dart + /// //Create a PDF Document. + /// PdfDocument document = PdfDocument(); + /// document.pages.add().graphics + /// ..save() + /// //Set skew transform + /// ..skewTransform(10, 10) + /// ..drawString('Hello world!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// pen: PdfPens.red) + /// ..restore(); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void skewTransform(double angleX, double angleY) { + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + _getSkewTransform(angleX, angleY, matrix); + _helper.streamWriter!.modifyCurrentMatrix(matrix); + matrix.multiply(matrix); + } + + //Implementation + void _initialize() { + _helper.mediaBoxUpperRightBound = 0; + _isStateSaved = false; + _helper._isColorSpaceInitialized = false; + _helper._currentBrush = null; + colorSpace = PdfColorSpace.rgb; + _previousTextRenderingMode = _TextRenderingMode.fill; + _previousTextRenderingMode = -1; + _previousCharacterSpacing = -1.0; + _previousWordSpacing = -1.0; + _helper._previousTextScaling = -100.0; + _helper.clipBounds = PdfRectangle(0, 0, size.width, size.height); + _graphicsState = []; + (_helper._getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.pdf, + ); + } + + void _drawImage(PdfImage image, Rect rectangle) { + _helper._beginMarkContent(); + final PdfRectangle bounds = PdfRectangle.fromRect( + (rectangle.width <= 0 && rectangle.height <= 0) + ? Rect.fromLTWH( + rectangle.left, + rectangle.top, + image.width * 0.75, + image.height * 0.75, + ) + : rectangle, + ); + PdfGraphicsState? beforeOrientation; + final int angle = PdfImageHelper.getJpegOrientationAngle(image)!.toInt(); + if (angle > 0) { + beforeOrientation = save(); + switch (angle) { + case 90: + translateTransform(bounds.x, bounds.y); + rotateTransform(90); + bounds.x = 0; + bounds.y = -bounds.width; + final double modwidth = bounds.height; + final double modHeight = bounds.width; + bounds.width = modwidth; + bounds.height = modHeight; + break; + case 180: + translateTransform(bounds.x, bounds.y); + rotateTransform(180); + bounds.x = -bounds.width; + bounds.y = -bounds.height; + break; + case 270: + translateTransform(bounds.x, bounds.y); + rotateTransform(270); + bounds.x = -bounds.height; + bounds.y = 0; + final double modwidth2 = bounds.height; + final double modHeight2 = bounds.width; + bounds.width = modwidth2; + bounds.height = modHeight2; + break; + default: + break; + } + } + if (clientSize.height < 0) { + bounds.y += clientSize.height; + } + PdfImageHelper.save(image); + final PdfGraphicsState state = save(); + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + matrix.translate(bounds.x, -(bounds.y + bounds.height)); + matrix.scale(bounds.width, bounds.height); + _helper.streamWriter!.modifyCurrentMatrix(matrix); + final PdfResources resources = _helper._getResources!() as PdfResources; + final PdfName name = resources.getName(image); + if (_helper.layer != null) { + PdfPageHelper.getHelper(_helper.page!).setResources(resources); + } + _helper.streamWriter!.executeObject(name); + restore(state); + if (beforeOrientation != null) { + restore(beforeOrientation); + } + _helper.endMarkContent(); + (_helper._getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.grayScaleImage, + ); + (_helper._getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.colorImage, + ); + (_helper._getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.indexedImage, + ); + (_helper._getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.text, + ); + } + + void _drawPath( + PdfPen? pen, + PdfBrush? brush, + PdfFillMode fillMode, + bool needClosing, + ) { + final bool isPen = + pen != null && PdfColorHelper.getHelper(pen.color).isFilled; + final bool isBrush = + brush != null && + PdfColorHelper.getHelper((brush as PdfSolidBrush).color).isFilled; + final bool isEvenOdd = fillMode == PdfFillMode.alternate; + if (isPen && isBrush) { + if (needClosing) { + _helper.streamWriter!.closeFillStrokePath(isEvenOdd); + } else { + _helper.streamWriter!.fillStrokePath(isEvenOdd); + } + } else if (!isPen && !isBrush) { + _helper.streamWriter!.endPath(); + } else if (isPen) { + if (needClosing) { + _helper.streamWriter!.closeStrokePath(); + } else { + _helper.streamWriter!.strokePath(); + } + } else if (isBrush) { + if (needClosing) { + _helper.streamWriter!.closeFillPath(isEvenOdd); + } else { + _helper.streamWriter!.fillPath(isEvenOdd); + } + } else { + throw UnsupportedError('Internal CLR error.'); + } + } + + void _drawTemplate(PdfTemplate template, Offset location, Size size) { + _helper._beginMarkContent(); + if (_helper.layer != null && + PdfPageHelper.getHelper(_helper.page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).document!, + ).conformanceLevel != + PdfConformanceLevel.none && + PdfGraphicsHelper.getHelper(template.graphics!)._currentFont != null && + (PdfGraphicsHelper.getHelper(template.graphics!)._currentFont + is PdfStandardFont || + PdfGraphicsHelper.getHelper(template.graphics!)._currentFont + is PdfCjkStandardFont)) { + throw ArgumentError( + 'All the fonts must be embedded in ${PdfDocumentHelper.getHelper(PdfPageHelper.getHelper(_helper.page!).document!).conformanceLevel} document.', + ); + } else if (_helper.layer != null && + PdfPageHelper.getHelper(_helper.page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).document!, + ).conformanceLevel == + PdfConformanceLevel.a1b && + PdfGraphicsHelper.getHelper(template.graphics!)._currentFont != null && + PdfGraphicsHelper.getHelper(template.graphics!)._currentFont + is PdfTrueTypeFont) { + PdfTrueTypeFontHelper.getHelper( + PdfGraphicsHelper.getHelper(template.graphics!)._currentFont! + as PdfTrueTypeFont, + ).fontInternal.initializeCidSet(); + } + if ((_helper.layer != null || _helper._documentLayer != null) && + PdfTemplateHelper.getHelper(template).isLoadedPageTemplate) { + PdfCrossTable? crossTable; + if (PdfPageHelper.getHelper(_helper.page!).isLoadedPage) { + if (PdfPageHelper.getHelper(_helper.page!).section != null) { + crossTable = + PdfDocumentHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).section!, + ).document!, + ).crossTable; + } else { + crossTable = + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).document!, + ).crossTable; + } + } else { + if (PdfPageHelper.getHelper(_helper.page!).section != null) { + crossTable = + (PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).section!, + ).document != + null) + ? PdfDocumentHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).section!, + ).document!, + ).crossTable + : PdfDocumentHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).section!, + ).pdfDocument!, + ).crossTable; + } else { + crossTable = + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_helper.page!).document!, + ).crossTable; + } + } + if ((PdfTemplateHelper.getHelper(template).isReadonly) || + (PdfTemplateHelper.getHelper(template).isLoadedPageTemplate)) { + PdfTemplateHelper.getHelper(template).cloneResources(crossTable); + } + } + if (PdfTemplateHelper.getHelper(template).origin.dx > 0 && + PdfTemplateHelper.getHelper(template).origin.dy > 0 && + template.size > size) { + size = template.size; + } + final double scaleX = + (template.size.width > 0) ? size.width / template.size.width : 1; + final double scaleY = + (template.size.height > 0) ? size.height / template.size.height : 1; + final bool hasScale = !(scaleX == 1 && scaleY == 1); + final PdfGraphicsState state = save(); + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + if ((_helper.layer != null || _helper._documentLayer != null) && + _helper.page != null && + PdfTemplateHelper.getHelper(template).isLoadedPageTemplate && + PdfPageHelper.getHelper(_helper.page!).isLoadedPage) { + bool needTransformation = false; + final PdfDictionary dictionary = + PdfPageHelper.getHelper(_helper.page!).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.cropBox) && + dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { + PdfArray? cropBox; + PdfArray? mediaBox; + if (dictionary[PdfDictionaryProperties.cropBox] is PdfReferenceHolder) { + cropBox = + (dictionary[PdfDictionaryProperties.cropBox]! + as PdfReferenceHolder) + .object + as PdfArray?; + } else { + cropBox = dictionary[PdfDictionaryProperties.cropBox] as PdfArray?; + } + if (dictionary[PdfDictionaryProperties.mediaBox] + is PdfReferenceHolder) { + mediaBox = + (dictionary[PdfDictionaryProperties.mediaBox]! + as PdfReferenceHolder) + .object + as PdfArray?; + } else { + mediaBox = dictionary[PdfDictionaryProperties.mediaBox] as PdfArray?; + } + if (cropBox != null && mediaBox != null) { + if (cropBox.toRectangle() == mediaBox.toRectangle()) { + needTransformation = true; + } + } + } + if (dictionary.containsKey(PdfDictionaryProperties.mediaBox)) { + PdfArray? mBox; + if (dictionary[PdfDictionaryProperties.mediaBox] + is PdfReferenceHolder) { + mBox = + (dictionary[PdfDictionaryProperties.mediaBox]! + as PdfReferenceHolder) + .object + as PdfArray?; + } else { + mBox = dictionary[PdfDictionaryProperties.mediaBox] as PdfArray?; + } + if (mBox != null) { + if ((mBox[3]! as PdfNumber).value == 0) { + needTransformation = true; + } + } + } + if ((PdfPageHelper.getHelper(_helper.page!).origin.dx >= 0 && + PdfPageHelper.getHelper(_helper.page!).origin.dy >= 0) || + needTransformation) { + matrix.translate(location.dx, -(location.dy + size.height)); + } else if (PdfPageHelper.getHelper(_helper.page!).origin.dx >= 0 && + PdfPageHelper.getHelper(_helper.page!).origin.dy <= 0) { + matrix.translate(location.dx, -(location.dy + size.height)); + } else { + matrix.translate(location.dx, -(location.dy + 0)); + } + } else { + if (PdfTemplateHelper.getHelper(template).origin.dx > 0 && + PdfTemplateHelper.getHelper(template).origin.dy > 0 && + location.dx == 0 && + location.dy == 0) { + matrix.translate( + location.dx - PdfTemplateHelper.getHelper(template).origin.dx, + -(location.dy + size.height), + ); + } else { + matrix.translate(location.dx, -(location.dy + size.height)); + } + } + if (hasScale) { + matrix.scale(scaleX, scaleY); + } + _helper.streamWriter!.modifyCurrentMatrix(matrix); + final PdfResources resources = _helper._getResources!() as PdfResources; + final PdfName name = resources.getName(template); + _helper.streamWriter!.executeObject(name); + restore(state); + _helper.endMarkContent(); + //Transfer automatic fields from template. + final PdfGraphics? g = template.graphics; + + if (g != null) { + for (final Object? fieldInfo + in PdfObjectCollectionHelper.getHelper( + PdfGraphicsHelper.getHelper(g).autoFields!, + ).list) { + if (fieldInfo is PdfAutomaticFieldInfo) { + final PdfPoint newLocation = PdfPoint( + fieldInfo.location.x + location.dx, + fieldInfo.location.y + location.dy, + ); + final double scalingX = + template.size.width == 0 ? 0 : size.width / template.size.width; + final double scalingY = + template.size.height == 0 + ? 0 + : size.height / template.size.height; + _helper.autoFields!.add( + PdfAutomaticFieldInfo( + fieldInfo.field, + newLocation, + scalingX, + scalingY, + ), + ); + PdfPageHelper.getHelper(_helper.page!).dictionary!.modify(); + } + } + } + resources.requireProcset(PdfDictionaryProperties.grayScaleImage); + resources.requireProcset(PdfDictionaryProperties.colorImage); + resources.requireProcset(PdfDictionaryProperties.indexedImage); + resources.requireProcset(PdfDictionaryProperties.text); + } + + PdfGraphicsState _doRestoreState() { + final PdfGraphicsState state = _graphicsState.last; + _graphicsState.remove(_graphicsState.last); + _helper._transformationMatrix = state._matrix; + _helper._currentBrush = state._brush; + _helper._currentPen = state._pen; + _helper._currentFont = state._font; + colorSpace = state._colorSpace; + _previousCharacterSpacing = state._characterSpacing; + _previousWordSpacing = state._wordSpacing; + _helper._previousTextScaling = state._textScaling; + _previousTextRenderingMode = state._textRenderingMode; + _helper.streamWriter!.restoreGraphicsState(); + return state; + } + + void _buildUpPath(List points, List types) { + for (int i = 0; i < points.length; ++i) { + final dynamic typeValue = types[i]; + final Offset point = points[i]; + switch (typeValue as PathPointType) { + case PathPointType.start: + _helper.streamWriter!.beginPath(point.dx, point.dy); + break; + + case PathPointType.bezier3: + Offset? p2, p3; + final Map returnValue = _getBezierPoints( + points, + types, + i, + p2, + p3, + ); + i = returnValue['i'] as int; + final List p = returnValue['points'] as List; + p2 = p.first; + p3 = p.last; + _helper.streamWriter!.appendBezierSegment( + point.dx, + point.dy, + p2.dx, + p2.dy, + p3.dx, + p3.dy, + ); + break; + + case PathPointType.line: + _helper.streamWriter!.appendLineSegment(point.dx, point.dy); + break; + + case PathPointType.closeSubpath: + _helper.streamWriter!.closePath(); + break; + } + } + } + + Map _getBezierPoints( + List points, + List types, + int i, + Offset? p2, + Offset? p3, + ) { + const String errorMsg = 'Malforming path.'; + ++i; + if (types[i] == PathPointType.bezier3) { + p2 = points[i]; + ++i; + if (types[i] == PathPointType.bezier3) { + p3 = points[i]; + } else { + throw ArgumentError(errorMsg); + } + } else { + throw ArgumentError(errorMsg); + } + return { + 'i': i, + 'points': [p2, p3], + }; + } + + void _constructArcPath( + double x1, + double y1, + double x2, + double y2, + double startAng, + double sweepAngle, + ) { + final List> points = _getBezierArcPoints( + x1, + y1, + x2, + y2, + startAng, + sweepAngle, + ); + if (points.isEmpty) { + return; + } + List pt = points[0]; + _helper.streamWriter!.beginPath(pt[0], pt[1]); + for (int i = 0; i < points.length; ++i) { + pt = points.elementAt(i); + _helper.streamWriter!.appendBezierSegment( + pt[2], + pt[3], + pt[4], + pt[5], + pt[6], + pt[7], + ); + } + } + + static List> _getBezierArcPoints( + double x1, + double y1, + double x2, + double y2, + double startAng, + double extent, + ) { + if (x1 > x2) { + double tmp; + tmp = x1; + x1 = x2; + x2 = tmp; + } + if (y2 > y1) { + double tmp; + tmp = y1; + y1 = y2; + y2 = tmp; + } + double fragAngle; + int numFragments; + + if (extent.abs() <= 90) { + fragAngle = extent; + numFragments = 1; + } else { + numFragments = (extent.abs() / 90).ceil(); + fragAngle = extent / numFragments; + } + final double xCen = (x1 + x2) / 2; + final double yCen = (y1 + y2) / 2; + final double rx = (x2 - x1) / 2; + final double ry = (y2 - y1) / 2; + final double halfAng = fragAngle * pi / 360.0; + final double kappa = + (4.0 / 3.0 * (1.0 - cos(halfAng)) / sin(halfAng)).abs(); + final List> pointList = >[]; + for (int i = 0; i < numFragments; ++i) { + final double theta0 = (startAng + i * fragAngle) * pi / 180.0; + final double theta1 = (startAng + (i + 1) * fragAngle) * pi / 180.0; + final double cos0 = cos(theta0); + final double cos1 = cos(theta1); + final double sin0 = sin(theta0); + final double sin1 = sin(theta1); + if (fragAngle > 0) { + pointList.add([ + xCen + rx * cos0, + yCen - ry * sin0, + xCen + rx * (cos0 - kappa * sin0), + yCen - ry * (sin0 + kappa * cos0), + xCen + rx * (cos1 + kappa * sin1), + yCen - ry * (sin1 - kappa * cos1), + xCen + rx * cos1, + yCen - ry * sin1, + ]); + } else { + pointList.add([ + xCen + rx * cos0, + yCen - ry * sin0, + xCen + rx * (cos0 + kappa * sin0), + yCen - ry * (sin0 - kappa * cos0), + xCen + rx * (cos1 - kappa * sin1), + yCen - ry * (sin1 + kappa * cos1), + xCen + rx * cos1, + yCen - ry * sin1, + ]); + } + } + return pointList; + } + + PdfTransformationMatrix _getSkewTransform( + double angleX, + double angleY, + PdfTransformationMatrix input, + ) { + input.skew(-angleX, -angleY); + return input; + } + + String _normalizeText(PdfFont font, String text) { + if (font is PdfStandardFont) { + text = _convert(text); + } + return text; + } + + String _convert(String text) { + final Windows1252Encoding encoding = Windows1252Encoding(); + final List encodedBytes = encoding.getBytes(text); + return String.fromCharCodes(encodedBytes); + } +} + +/// Represents the state of a Graphics object. \ +/// This object is returned by a call to the Save methods. +class PdfGraphicsState { + // Constructors + /// Initializes a new instance of the [PdfGraphicsState] class. + PdfGraphicsState._(PdfGraphics graphics, PdfTransformationMatrix matrix) { + _graphics = graphics; + _matrix = matrix; + _initialize(); + } + + //Fields + late PdfGraphics _graphics; + late PdfTransformationMatrix _matrix; + late double _characterSpacing; + late double _wordSpacing; + late double _textScaling; + PdfPen? _pen; + PdfBrush? _brush; + PdfFont? _font; + late PdfColorSpace _colorSpace; + late int _textRenderingMode; + + //Implementation + void _initialize() { + _textRenderingMode = _TextRenderingMode.fill; + _colorSpace = PdfColorSpace.rgb; + _characterSpacing = 0.0; + _wordSpacing = 0.0; + _textScaling = 100.0; + } +} + +class _TransparencyData { + //Constructor + const _TransparencyData(this.alphaPen, this.alphaBrush, this.blendMode); + //Fields + final double? alphaPen; + final double? alphaBrush; + final PdfBlendMode? blendMode; + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is _TransparencyData && + other.alphaPen == alphaPen && + alphaBrush == other.alphaBrush && + blendMode == other.blendMode; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => + alphaPen.hashCode + alphaBrush.hashCode + blendMode.hashCode; +} + +/// Specifies the text rendering mode. +class _TextRenderingMode { + /// Fill text. + static const int fill = 0; + + /// Stroke text. + static const int stroke = 1; + + /// Fill, then stroke text. + static const int fillStroke = 2; + + /// Neither fill nor stroke text (invisible). + static const int none = 3; + + /// The flag showing that the text should be a part of a clipping path. + static const int clipFlag = 4; +} + +class PdfAutomaticFieldInfoCollection extends PdfObjectCollection { + // constructor + PdfAutomaticFieldInfoCollection() : super() { + _helper = PdfAutomaticFieldInfoCollectionHelper(this); + } + + late PdfAutomaticFieldInfoCollectionHelper _helper; + + // implementaion + int add(PdfAutomaticFieldInfo fieldInfo) { + return _helper.add(fieldInfo); + } +} + +class PdfAutomaticFieldInfoCollectionHelper extends PdfObjectCollectionHelper { + // constructor + PdfAutomaticFieldInfoCollectionHelper(this.base) : super(base); + PdfAutomaticFieldInfoCollection base; + + // implementaion + int add(PdfAutomaticFieldInfo fieldInfo) { + list.add(fieldInfo); + return base.count - 1; + } +} + +/// [PdfGraphics] helper +class PdfGraphicsHelper { + /// internal constructor + PdfGraphicsHelper(this.base); + + /// internal field + late PdfGraphics base; + + /// internal method + static PdfGraphicsHelper getHelper(PdfGraphics base) { + return base._helper; + } + + /// internal method + static PdfGraphics load(Size size, Function getResources, PdfStream stream) { + return PdfGraphics._(size, getResources, stream); + } + + /// internal field + bool _colorSpaceChanged = false; + + /// internal field + PdfStreamWriter? streamWriter; + + /// internal field + late PdfRectangle clipBounds; + + /// internal field + final bool hasTransparencyBrush = false; + + /// internal field + PdfArray? cropBox; + + /// internal field + double? mediaBoxUpperRightBound; + + /// internal field + PdfPageLayer? layer; + + /// internal field + PdfStringLayoutResult? stringLayoutResult; + + /// internal field + PdfStringFormat? currentStringFormat; + bool _isColorSpaceInitialized = false; + PdfFont? _currentFont; + PdfBrush? _currentBrush; + PdfTransformationMatrix? _transformationMatrix; + PdfLayer? _documentLayer; + PdfAutomaticFieldInfoCollection? _automaticFields; + Map<_TransparencyData, PdfTransparency>? _trasparencies; + Function? _getResources; + double? _previousTextScaling; + final Map _colorSpaces = { + PdfColorSpace.rgb: 'RGB', + PdfColorSpace.cmyk: 'CMYK', + PdfColorSpace.grayScale: 'GrayScale', + PdfColorSpace.indexed: 'Indexed', + }; + PdfPen? _currentPen; + bool _isItalic = false; + + /// internal property + PdfTransformationMatrix get matrix { + _transformationMatrix ??= PdfTransformationMatrix(); + return _transformationMatrix!; + } + + /// internal method + PdfPage? get page { + if (_documentLayer != null) { + return PdfLayerHelper.getHelper(_documentLayer!).page; + } else { + return layer!.page; + } + } + + /// Gets the automatic fields. + PdfAutomaticFieldInfoCollection? get autoFields { + _automaticFields ??= PdfAutomaticFieldInfoCollection(); + return _automaticFields; + } + + /// internal method + void applyTransparency(double alpha, double alphaBrush, PdfBlendMode mode) { + _trasparencies ??= <_TransparencyData, PdfTransparency>{}; + PdfTransparency? transparency; + final _TransparencyData transparencyData = _TransparencyData( + alpha, + alphaBrush, + mode, + ); + if (_trasparencies!.containsKey(transparencyData)) { + transparency = _trasparencies![transparencyData]; + } + if (transparency == null) { + transparency = PdfTransparency( + alpha, + alphaBrush, + mode, + conformance: + layer != null && + PdfPageHelper.getHelper(page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(page!).document!, + ).conformanceLevel == + PdfConformanceLevel.a1b, + ); + _trasparencies![transparencyData] = transparency; + } + final PdfResources resources = _getResources!() as PdfResources; + final PdfName name = resources.getName(transparency); + if (layer != null) { + PdfPageHelper.getHelper(page!).setResources(resources); + } + streamWriter!.setGraphicsState(name); + } + + /// internal method + void layoutString( + String s, + PdfFont font, { + PdfPen? pen, + PdfBrush? brush, + required PdfRectangle layoutRectangle, + PdfStringFormat? format, + }) { + final PdfStringLayouter layouter = PdfStringLayouter(); + PdfStringLayoutResult result; + result = layouter.layout( + s, + font, + format, + width: layoutRectangle.width, + height: layoutRectangle.height, + ); + if (!result.isEmpty) { + final PdfRectangle rectangle = checkCorrectLayoutRectangle( + result.size, + layoutRectangle.x, + layoutRectangle.y, + format, + ); + if (layoutRectangle.width <= 0) { + layoutRectangle.x = rectangle.x; + layoutRectangle.width = rectangle.width; + } + if (layoutRectangle.height <= 0) { + layoutRectangle.y = rectangle.y; + layoutRectangle.height = rectangle.height; + } + if (base.clientSize.height < 0) { + layoutRectangle.y += base.clientSize.height; + } + drawStringLayoutResult(result, font, pen, brush, layoutRectangle, format); + stringLayoutResult = result; + (_getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.text, + ); + } + } + + /// internal method + void drawStringLayoutResult( + PdfStringLayoutResult result, + PdfFont font, + PdfPen? pen, + PdfBrush? brush, + PdfRectangle layoutRectangle, + PdfStringFormat? format, + ) { + if (!result.isEmpty) { + _beginMarkContent(); + PdfGraphicsState? gState; + if (font is PdfTrueTypeFont && + PdfTrueTypeFontHelper.getHelper(font).fontInternal.ttfMetrics != + null && + !PdfTrueTypeFontHelper.getHelper( + font, + ).fontInternal.ttfMetrics!.isItalic && + PdfFontHelper.getHelper(font).isItalic) { + gState = base.save(); + _isItalic = true; + } + _applyStringSettings(font, pen, brush, format, layoutRectangle); + final double textScaling = + format != null + ? PdfStringFormatHelper.getHelper(format).scalingFactor + : 100.0; + if (textScaling != _previousTextScaling) { + streamWriter!.setTextScaling(textScaling); + _previousTextScaling = textScaling; + } + double verticalAlignShift = getTextVerticalAlignShift( + result.size.height, + layoutRectangle.height, + format, + ); + double? height; + if (_isItalic) { + height = + (format == null || format.lineSpacing == 0) + ? font.height + : format.lineSpacing + font.height; + final bool subScript = + format != null && + format.subSuperscript == PdfSubSuperscript.subscript; + final double shift = + subScript + ? height - + (font.height + + PdfFontHelper.getHelper( + font, + ).metrics!.getDescent(format)) + : (height - + PdfFontHelper.getHelper(font).metrics!.getAscent(format)); + base.translateTransform( + layoutRectangle.left + font.size / 5, + layoutRectangle.top - shift + verticalAlignShift, + ); + base.skewTransform(0, -11); + } + if (!_isItalic) { + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + matrix.translate( + layoutRectangle.x, + (-(layoutRectangle.y + font.height) - + (PdfFontHelper.getHelper(font).metrics!.getDescent(format) > 0 + ? -PdfFontHelper.getHelper( + font, + ).metrics!.getDescent(format) + : PdfFontHelper.getHelper( + font, + ).metrics!.getDescent(format))) - + verticalAlignShift, + ); + streamWriter!.modifyTransformationMatrix(matrix); + } else { + streamWriter!.startNextLine(0, 0); + } + if (_isItalic && height != null && height >= font.size) { + streamWriter!.stream!.write(height.toString()); + streamWriter!.stream!.write(PdfOperators.whiteSpace); + streamWriter!.writeOperator(PdfOperators.setTextLeading); + } + if (layoutRectangle.height < font.size) { + if ((result.size.height - layoutRectangle.height) < + (font.size / 2) - 1) { + verticalAlignShift = 0.0; + } + } + _drawLayoutResult(result, font, format, layoutRectangle); + if (verticalAlignShift != 0) { + streamWriter!.startNextLine( + 0, + -(verticalAlignShift - result.lineHeight), + ); + } + streamWriter!.endText(); + if (gState != null) { + base.restore(gState); + _isItalic = false; + } + _underlineStrikeoutText( + pen, + brush, + result, + font, + layoutRectangle, + format, + ); + endMarkContent(); + } + } + + void _drawLayoutResult( + PdfStringLayoutResult result, + PdfFont font, + PdfStringFormat? format, + PdfRectangle layoutRectangle, + ) { + bool? unicode = false; + if (font is PdfTrueTypeFont) { + unicode = PdfTrueTypeFontHelper.getHelper(font).unicode; + } + final List lines = result.lines!; + final double height = + (format == null || format.lineSpacing == 0) + ? font.height + : format.lineSpacing + font.height; + for (int i = 0; i < lines.length; i++) { + final LineInfo lineInfo = lines[i]; + final String? line = lineInfo.text; + final double? lineWidth = lineInfo.width; + if ((line == null || line.isEmpty) && !_isItalic) { + final double verticalAlignShift = getTextVerticalAlignShift( + result.size.height, + layoutRectangle.height, + format, + ); + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + double baseline = + (-(layoutRectangle.y + font.height) - + PdfFontHelper.getHelper(font).metrics!.getDescent(format)) - + verticalAlignShift; + baseline -= height * (i + 1); + matrix.translate(layoutRectangle.x, baseline); + streamWriter!.modifyTransformationMatrix(matrix); + } else { + double horizontalAlignShift = _getHorizontalAlignShift( + lineWidth, + layoutRectangle.width, + format, + ); + final double? lineIndent = _getLineIndent( + lineInfo, + format, + layoutRectangle, + i == 0, + ); + horizontalAlignShift += (!_rightToLeft(format)) ? lineIndent! : 0; + + if (horizontalAlignShift != 0) { + streamWriter!.startNextLine(horizontalAlignShift, 0); + } + if (font is PdfCjkStandardFont) { + _drawCjkString(lineInfo, layoutRectangle, font, format); + } else if (unicode!) { + _drawUnicodeLine(lineInfo, layoutRectangle, font, format); + } else { + _drawAsciiLine(lineInfo, layoutRectangle, font, format); + } + + if (i + 1 != lines.length) { + if (!_isItalic) { + final double verticalAlignShift = getTextVerticalAlignShift( + result.size.height, + layoutRectangle.height, + format, + ); + final PdfTransformationMatrix matrix = PdfTransformationMatrix(); + double baseline = + (-(layoutRectangle.y + font.height) - + PdfFontHelper.getHelper(font).metrics!.getDescent(format)) - + verticalAlignShift; + baseline -= height * (i + 1); + matrix.translate(layoutRectangle.x, baseline); + streamWriter!.modifyTransformationMatrix(matrix); + } else { + //tan(11) = 0.19486, theta value for italic skewAngle (11 degree). + streamWriter!.startNextLine( + font.height * 0.19486 - horizontalAlignShift, + 0, + ); + } + } + } + } + (_getResources!() as PdfResources).requireProcset( + PdfDictionaryProperties.text, + ); + } + + bool _rightToLeft(PdfStringFormat? format) { + bool rtl = + format != null && format.textDirection == PdfTextDirection.rightToLeft; + if (format != null && format.textDirection != PdfTextDirection.none) { + rtl = true; + } + return rtl; + } + + double _getHorizontalAlignShift( + double? lineWidth, + double boundsWidth, + PdfStringFormat? format, + ) { + double shift = 0; + if (boundsWidth >= 0 && + format != null && + format.alignment != PdfTextAlignment.left) { + switch (format.alignment) { + case PdfTextAlignment.center: + shift = (boundsWidth - lineWidth!) / 2; + break; + case PdfTextAlignment.right: + shift = boundsWidth - lineWidth!; + break; + case PdfTextAlignment.left: + case PdfTextAlignment.justify: + break; + } + } + return shift; + } + + void _drawAsciiLine( + LineInfo lineInfo, + PdfRectangle layoutRectangle, + PdfFont font, + PdfStringFormat? format, + ) { + _justifyLine(lineInfo, layoutRectangle.width, format); + final PdfString str = PdfString(lineInfo.text!); + str.isAsciiEncode = true; + streamWriter!.showNextLineText(str); + } + + void _drawCjkString( + LineInfo lineInfo, + PdfRectangle layoutRectangle, + PdfFont font, + PdfStringFormat? format, + ) { + _justifyLine(lineInfo, layoutRectangle.width, format); + final String line = lineInfo.text!; + final List str = _getCjkString(line); + streamWriter!.showNextLineText(str); + } + + String _addChars(PdfTrueTypeFont font, String line, PdfStringFormat? format) { + String text = line; + final UnicodeTrueTypeFont internalFont = + PdfTrueTypeFontHelper.getHelper(font).fontInternal; + final TtfReader ttfReader = internalFont.reader; + // Reconvert string according to unicode standard. + text = ttfReader.convertString(text); + if (format != null) { + internalFont.setSymbols(line, ttfReader.internalUsedChars); + } else { + PdfTrueTypeFontHelper.getHelper( + font, + ).setSymbols(text, ttfReader.internalUsedChars); + } + ttfReader.internalUsedChars = null; + final List bytes = PdfString.toUnicodeArray(text); + text = PdfString.byteToString(bytes); + return text; + } + + void _drawUnicodeLine( + LineInfo lineInfo, + PdfRectangle layoutRectangle, + PdfFont font, + PdfStringFormat? format, + ) { + final String? line = lineInfo.text; + final bool useWordSpace = + format != null && + (format.wordSpacing != 0 || + format.alignment == PdfTextAlignment.justify); + final PdfTrueTypeFont ttfFont = font as PdfTrueTypeFont; + final double wordSpacing = _justifyLine( + lineInfo, + layoutRectangle.width, + format, + ); + if (format != null && format.textDirection != PdfTextDirection.none) { + final ArabicShapeRenderer renderer = ArabicShapeRenderer(); + final String txt = renderer.shape(line!.split(''), 0); + final Bidi bidi = Bidi(); + bidi.isVisualOrder = false; + final String result = + bidi.getLogicalToVisualString( + txt, + format.textDirection == PdfTextDirection.rightToLeft, + )['rtlText'] + as String; + bidi.isVisualOrder = true; + final List blocks = []; + if (useWordSpace) { + final List words = result.split(' '); + for (int i = 0; i < words.length; i++) { + blocks.add(_addChars(font, words[i], format)); + } + } else { + blocks.add(_addChars(font, result, format)); + } + List words = []; + if (blocks.length > 1) { + words = result.split(' '); + } else { + words.add(result); + } + _drawUnicodeBlocks(blocks, words, ttfFont, format, wordSpacing); + } else if (useWordSpace) { + final dynamic result = _breakUnicodeLine(line!, ttfFont, null); + final List blocks = result['tokens'] as List; + final List words = result['words']! as List; + _drawUnicodeBlocks(blocks, words, ttfFont, format, wordSpacing); + } else { + final String token = _convertToUnicode(line!, ttfFont)!; + final PdfString value = _getUnicodeString(token); + streamWriter!.showNextLineText(value); + } + } + + void _drawUnicodeBlocks( + List blocks, + List words, + PdfTrueTypeFont font, + PdfStringFormat? format, + double wordSpacing, + ) { + streamWriter!.startNextLine(); + double x = 0; + double xShift = 0; + double firstLineIndent = 0; + double paragraphIndent = 0; + try { + if (format != null) { + firstLineIndent = + PdfStringFormatHelper.getHelper(format).firstLineIndent; + paragraphIndent = format.paragraphIndent; + PdfStringFormatHelper.getHelper(format).firstLineIndent = 0; + format.paragraphIndent = 0; + } + double spaceWidth = + PdfTrueTypeFontHelper.getHelper(font).getCharWidth(' ', format) + + wordSpacing; + final double characterSpacing = + format != null ? format.characterSpacing : 0; + final double wordSpace = + format != null && wordSpacing == 0 ? format.wordSpacing : 0; + spaceWidth += characterSpacing + wordSpace; + for (int i = 0; i < blocks.length; i++) { + final String token = blocks[i]; + final String word = words[i]; + double tokenWidth = 0; + if (x != 0.0) { + streamWriter!.startNextLine(x, 0); + } + if (word.isNotEmpty) { + tokenWidth += font.measureString(word, format: format).width; + tokenWidth += characterSpacing; + final PdfString val = _getUnicodeString(token); + streamWriter!.showText(val); + } + if (i != blocks.length - 1) { + x = tokenWidth + spaceWidth; + xShift += x; + } + } + // Rolback current line position. + if (xShift > 0) { + streamWriter!.startNextLine(-xShift, 0); + } + } finally { + if (format != null) { + PdfStringFormatHelper.getHelper(format).firstLineIndent = + firstLineIndent; + format.paragraphIndent = paragraphIndent; + } + } + } + + dynamic _breakUnicodeLine( + String line, + PdfTrueTypeFont ttfFont, + List? words, + ) { + words = line.split(' '); + final List tokens = []; + for (int i = 0; i < words.length; i++) { + final String word = words[i]; + final String? token = _convertToUnicode(word, ttfFont); + if (token != null) { + tokens.add(token); + } + } + return {'tokens': tokens, 'words': words}; + } + + PdfString _getUnicodeString(String token) { + final PdfString val = PdfString(token); + val.isAsciiEncode = true; + return val; + } + + int _getTextRenderingMode( + PdfPen? pen, + PdfBrush? brush, + PdfStringFormat? format, + ) { + int tm = _TextRenderingMode.none; + if (pen != null && brush != null) { + tm = _TextRenderingMode.fillStroke; + } else if (pen != null) { + tm = _TextRenderingMode.stroke; + } else { + tm = _TextRenderingMode.fill; + } + if (format != null && format.clipPath) { + tm |= _TextRenderingMode.clipFlag; + } + return tm; + } + + void _applyStringSettings( + PdfFont font, + PdfPen? pen, + PdfBrush? brush, + PdfStringFormat? format, + PdfRectangle bounds, + ) { + int renderingMode = _getTextRenderingMode(pen, brush, format); + bool setLineWidth = false; + if (font is PdfTrueTypeFont && + PdfTrueTypeFontHelper.getHelper(font).fontInternal.ttfMetrics != null && + !PdfTrueTypeFontHelper.getHelper( + font, + ).fontInternal.ttfMetrics!.isBold && + PdfFontHelper.getHelper(font).isBold) { + if (pen == null && brush != null && brush is PdfSolidBrush) { + pen = PdfPen(brush.color); + } + renderingMode = 2; + setLineWidth = true; + } + streamWriter!.writeOperator(PdfOperators.beginText); + _stateControl(pen, brush, font, format); + if (setLineWidth) { + streamWriter!.setLineWidth(font.size / 30); + } + if (renderingMode != base._previousTextRenderingMode) { + streamWriter!.setTextRenderingMode(renderingMode); + base._previousTextRenderingMode = renderingMode; + } + final double characterSpace = + (format != null) ? format.characterSpacing : 0; + if (characterSpace != base._previousCharacterSpacing) { + streamWriter!.setCharacterSpacing(characterSpace); + base._previousCharacterSpacing = characterSpace; + } + final double wordSpace = (format != null) ? format.wordSpacing : 0; + if (wordSpace != base._previousWordSpacing) { + streamWriter!.setWordSpacing(wordSpace); + base._previousWordSpacing = wordSpace; + } + } + + void _stateControl( + PdfPen? pen, + PdfBrush? brush, + PdfFont? font, + PdfStringFormat? format, + ) { + if (brush != null) { + if (layer != null) { + if (!PdfPageHelper.getHelper(page!).isLoadedPage && + !PdfDocumentHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page!).section!, + ).pdfDocument!, + ).isLoadedDocument) { + if (_colorSpaceChanged == false) { + if (page != null) { + base.colorSpace = + PdfPageHelper.getHelper(page!).document!.colorSpace; + } + _colorSpaceChanged = true; + } + } + } + _initCurrentColorSpace(base.colorSpace); + } else if (pen != null) { + if (layer != null) { + if (!PdfPageHelper.getHelper(page!).isLoadedPage && + !PdfDocumentHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page!).section!, + ).pdfDocument!, + ).isLoadedDocument) { + base.colorSpace = PdfPageHelper.getHelper(page!).document!.colorSpace; + } + } + _initCurrentColorSpace(base.colorSpace); + } + _penControl(pen, false); + _brushControl(brush, false); + _fontControl(font, format, false); + } + + void _initCurrentColorSpace(PdfColorSpace? colorspace) { + if (!_isColorSpaceInitialized) { + streamWriter!.setColorSpace( + PdfName('Device${_colorSpaces[base.colorSpace]!}'), + true, + ); + streamWriter!.setColorSpace( + PdfName('Device${_colorSpaces[base.colorSpace]!}'), + false, + ); + _isColorSpaceInitialized = true; + } + } + + void _penControl(PdfPen? pen, bool saveState) { + if (pen != null) { + _currentPen = pen; + base.colorSpace = PdfColorSpace.rgb; + PdfPenHelper.getHelper(pen).monitorChanges( + _currentPen, + streamWriter!, + _getResources, + saveState, + base.colorSpace, + matrix, + ); + _currentPen = pen; + } + } + + void _brushControl(PdfBrush? brush, bool saveState) { + if (brush != null) { + PdfBrushHelper.monitorChanges( + brush as PdfSolidBrush, + _currentBrush, + streamWriter, + _getResources, + saveState, + base.colorSpace, + ); + _currentBrush = brush; + brush = null; + } + } + + void _fontControl(PdfFont? font, PdfStringFormat? format, bool saveState) { + if (font != null) { + if ((font is PdfStandardFont || font is PdfCjkStandardFont) && + layer != null && + PdfPageHelper.getHelper(page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(page!).document!, + ).conformanceLevel != + PdfConformanceLevel.none) { + throw ArgumentError( + 'All the fonts must be embedded in ${PdfDocumentHelper.getHelper(PdfPageHelper.getHelper(page!).document!).conformanceLevel} document.', + ); + } else if (font is PdfTrueTypeFont && + layer != null && + PdfPageHelper.getHelper(page!).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(page!).document!, + ).conformanceLevel == + PdfConformanceLevel.a1b) { + PdfTrueTypeFontHelper.getHelper(font).fontInternal.initializeCidSet(); + } + final PdfSubSuperscript current = + format != null ? format.subSuperscript : PdfSubSuperscript.none; + final PdfSubSuperscript privious = + currentStringFormat != null + ? currentStringFormat!.subSuperscript + : PdfSubSuperscript.none; + if (saveState || font != _currentFont || current != privious) { + final PdfResources resources = _getResources!() as PdfResources; + _currentFont = font; + currentStringFormat = format; + streamWriter!.setFont( + font, + resources.getName(font), + PdfFontHelper.getHelper(font).metrics!.getSize(format)!, + ); + } + } + } + + void _beginMarkContent() { + if (_documentLayer != null) { + PdfLayerHelper.getHelper(_documentLayer!).beginLayer(base); + } + } + + /// internal method + void endMarkContent() { + if (_documentLayer != null) { + if (PdfLayerHelper.getHelper(_documentLayer!).isEndState && + PdfLayerHelper.getHelper(_documentLayer!).parentLayer.isNotEmpty) { + for ( + int i = 0; + i < PdfLayerHelper.getHelper(_documentLayer!).parentLayer.length; + i++ + ) { + streamWriter!.write('EMC\n'); + } + } + if (PdfLayerHelper.getHelper(_documentLayer!).isEndState) { + streamWriter!.write('EMC\n'); + } + } + } + + /// internal method + PdfRectangle checkCorrectLayoutRectangle( + PdfSize textSize, + double? x, + double? y, + PdfStringFormat? format, + ) { + final PdfRectangle layoutedRectangle = PdfRectangle( + x!, + y!, + textSize.width, + textSize.width, + ); + if (format != null) { + switch (format.alignment) { + case PdfTextAlignment.center: + layoutedRectangle.x -= layoutedRectangle.width / 2; + break; + case PdfTextAlignment.right: + layoutedRectangle.x -= layoutedRectangle.width; + break; + case PdfTextAlignment.left: + case PdfTextAlignment.justify: + break; + } + switch (format.lineAlignment) { + case PdfVerticalAlignment.middle: + layoutedRectangle.y -= layoutedRectangle.height / 2; + break; + case PdfVerticalAlignment.bottom: + layoutedRectangle.y -= layoutedRectangle.height; + break; + case PdfVerticalAlignment.top: + break; + } + } + return layoutedRectangle; + } + + void _underlineStrikeoutText( + PdfPen? pen, + PdfBrush? brush, + PdfStringLayoutResult result, + PdfFont font, + PdfRectangle layoutRectangle, + PdfStringFormat? format, + ) { + if (PdfFontHelper.getHelper(font).isUnderline | + PdfFontHelper.getHelper(font).isStrikeout) { + final PdfPen? linePen = _createUnderlineStikeoutPen( + pen, + brush, + font, + format, + ); + if (linePen != null) { + final double verticalShift = getTextVerticalAlignShift( + result.size.height, + layoutRectangle.height, + format, + ); + double underlineYOffset = + layoutRectangle.y + + verticalShift + + PdfFontHelper.getHelper(font).metrics!.getAscent(format) + + 1.5 * linePen.width; + double strikeoutYOffset = + layoutRectangle.y + + verticalShift + + PdfFontHelper.getHelper(font).metrics!.getHeight(format) / 2 + + 1.5 * linePen.width; + final List? lines = result.lines; + for (int i = 0; i < result.lines!.length; i++) { + final LineInfo lineInfo = lines![i]; + final double? lineWidth = lineInfo.width; + double horizontalShift = _getHorizontalAlignShift( + lineWidth, + layoutRectangle.width, + format, + ); + final double? lineIndent = _getLineIndent( + lineInfo, + format, + layoutRectangle, + i == 0, + ); + horizontalShift += (!_rightToLeft(format)) ? lineIndent! : 0; + final double x1 = layoutRectangle.x + horizontalShift; + final double x2 = + (!_shouldJustify(lineInfo, layoutRectangle.width, format)) + ? x1 + lineWidth! - lineIndent! + : x1 + layoutRectangle.width - lineIndent!; + if (PdfFontHelper.getHelper(font).isUnderline) { + base.drawLine( + linePen, + Offset(x1, underlineYOffset), + Offset(x2, underlineYOffset), + ); + underlineYOffset += result.lineHeight; + } + if (PdfFontHelper.getHelper(font).isStrikeout) { + base.drawLine( + linePen, + Offset(x1, strikeoutYOffset), + Offset(x2, strikeoutYOffset), + ); + strikeoutYOffset += result.lineHeight; + } + } + } + } + } + + PdfPen? _createUnderlineStikeoutPen( + PdfPen? pen, + PdfBrush? brush, + PdfFont font, + PdfStringFormat? format, + ) { + final double lineWidth = + PdfFontHelper.getHelper(font).metrics!.getSize(format)! / 20; + PdfPen? linePen; + if (pen != null) { + linePen = PdfPen(pen.color, width: lineWidth); + } else if (brush != null) { + linePen = PdfPen.fromBrush(brush, width: lineWidth); + } + return linePen; + } + + /// internal method + void initializeCoordinates() { + streamWriter!.writeComment('Change co-ordinate system to left/top.'); + if (mediaBoxUpperRightBound != -base.size.height) { + if (cropBox == null) { + _translate(); + } else { + final double cropX = (cropBox![0]! as PdfNumber).value!.toDouble(); + final double cropY = (cropBox![1]! as PdfNumber).value!.toDouble(); + final double cropW = (cropBox![2]! as PdfNumber).value!.toDouble(); + final double cropH = (cropBox![3]! as PdfNumber).value!.toDouble(); + if (cropX != 0 || + cropY != 0 || + base.size.width == cropW || + base.size.height == cropH) { + base.translateTransform(cropX, -cropH); + } else { + _translate(); + } + } + } + } + + void _translate() { + if (mediaBoxUpperRightBound == base.size.height || + mediaBoxUpperRightBound == 0) { + base.translateTransform(0, -base.size.height); + } else { + base.translateTransform(0, -mediaBoxUpperRightBound!); + } + } + + /// internal method + void clipTranslateMarginsWithBounds(PdfRectangle clipBounds) { + this.clipBounds = clipBounds; + streamWriter!.writeComment('Clip margins.'); + streamWriter!.appendRectangle( + clipBounds.x, + clipBounds.y, + clipBounds.width, + clipBounds.height, + ); + streamWriter!.closePath(); + streamWriter!.clipPath(false); + streamWriter!.writeComment('Translate co-ordinate system.'); + base.translateTransform(clipBounds.x, clipBounds.y); + } + + /// internal method + void clipTranslateMargins( + double x, + double y, + double left, + double top, + double right, + double bottom, + ) { + final PdfRectangle clipArea = PdfRectangle( + left, + top, + base.size.width - left - right, + base.size.height - top - bottom, + ); + clipBounds = clipArea; + streamWriter!.writeComment('Clip margins.'); + streamWriter!.appendRectangle( + clipBounds.x, + clipBounds.y, + clipBounds.width, + clipBounds.height, + ); + streamWriter!.closePath(); + streamWriter!.clipPath(false); + streamWriter!.writeComment('Translate co-ordinate system.'); + base.translateTransform(x, y); + } + + /// internal method + void setLayer(PdfPageLayer? pageLayer, [PdfLayer? pdfLayer]) { + PdfPage? page; + if (pageLayer != null) { + layer = pageLayer; + page = pageLayer.page; + } else if (pdfLayer != null) { + _documentLayer = pdfLayer; + page = PdfLayerHelper.getHelper(pdfLayer).page; + } + if (page != null) { + PdfPageHelper.getHelper(page).beginSave = () { + if (_automaticFields != null) { + for (final Object? fieldInfo + in PdfObjectCollectionHelper.getHelper(_automaticFields!).list) { + if (fieldInfo is PdfAutomaticFieldInfo) { + PdfAutomaticFieldHelper.getHelper(fieldInfo.field).performDraw( + base, + fieldInfo.location, + fieldInfo.scalingX, + fieldInfo.scalingY, + ); + } + } + } + }; + } + } + + /// internal method + void setTransparencyGroup(PdfPage page) { + final PdfDictionary group = PdfDictionary(); + group[PdfDictionaryProperties.colorSpace] = PdfName('DeviceRGB'); + group[PdfDictionaryProperties.k] = PdfBoolean(false); + group[PdfDictionaryProperties.s] = PdfName('Transparency'); + group[PdfDictionaryProperties.i] = PdfBoolean(false); + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties.group] = + group; + } + + /// internal method + void reset(Size size) { + base._canvasSize = size; + streamWriter!.clear(); + base._initialize(); + initializeCoordinates(); + } + + /// internal method + double getTextVerticalAlignShift( + double? textHeight, + double boundsHeight, + PdfStringFormat? format, + ) { + double shift = 0; + if (boundsHeight >= 0 && + format != null && + format.lineAlignment != PdfVerticalAlignment.top) { + switch (format.lineAlignment) { + case PdfVerticalAlignment.middle: + shift = (boundsHeight - textHeight!) / 2; + break; + case PdfVerticalAlignment.bottom: + shift = boundsHeight - textHeight!; + break; + case PdfVerticalAlignment.top: + break; + } + } + return shift; + } + + /// internal method + Rect getLineBounds( + int lineIndex, + PdfStringLayoutResult result, + PdfFont font, + PdfRectangle layoutRectangle, + PdfStringFormat? format, + ) { + PdfRectangle bounds = PdfRectangle.empty; + if (!result.isEmpty && lineIndex < result.lineCount && lineIndex >= 0) { + final LineInfo line = result.lines![lineIndex]; + final double verticalShift = getTextVerticalAlignShift( + result.size.height, + layoutRectangle.height, + format, + ); + final double y = + verticalShift + layoutRectangle.y + (result.lineHeight * lineIndex); + final double? lineWidth = line.width; + double horizontalShift = _getHorizontalAlignShift( + lineWidth, + layoutRectangle.width, + format, + ); + final double? lineIndent = _getLineIndent( + line, + format, + layoutRectangle, + lineIndex == 0, + ); + horizontalShift += (!_rightToLeft(format)) ? lineIndent! : 0; + final double x = layoutRectangle.x + horizontalShift; + final double width = + (!_shouldJustify(line, layoutRectangle.width, format)) + ? lineWidth! - lineIndent! + : layoutRectangle.width - lineIndent!; + final double height = result.lineHeight; + bounds = PdfRectangle(x, y, width, height); + } + return bounds.rect; + } + + double? _getLineIndent( + LineInfo lineInfo, + PdfStringFormat? format, + PdfRectangle layoutBounds, + bool firstLine, + ) { + double? lineIndent = 0; + final bool firstParagraphLine = + (lineInfo.lineType & + PdfStringLayouter.getLineTypeValue(LineType.firstParagraphLine)!) > + 0; + if (format != null && firstParagraphLine) { + lineIndent = + firstLine + ? PdfStringFormatHelper.getHelper(format).firstLineIndent + : format.paragraphIndent; + lineIndent = + (layoutBounds.width > 0) + ? (layoutBounds.width <= lineIndent + ? layoutBounds.width + : lineIndent) + : lineIndent; + } + return lineIndent; + } + + String? _convertToUnicode(String text, PdfTrueTypeFont font) { + String? token; + final TtfReader ttfReader = + PdfTrueTypeFontHelper.getHelper(font).fontInternal.reader; + token = ttfReader.convertString(text); + PdfTrueTypeFontHelper.getHelper( + font, + ).setSymbols(text, ttfReader.internalUsedChars); + ttfReader.internalUsedChars = null; + final List bytes = PdfString.toUnicodeArray(token); + token = PdfString.byteToString(bytes); + return token; + } + + List _getCjkString(String line) { + List value = PdfString.toUnicodeArray(line); + value = PdfString.escapeSymbols(value); + return value; + } + + double _justifyLine( + LineInfo lineInfo, + double boundsWidth, + PdfStringFormat? format, + ) { + final String line = lineInfo.text!; + double? lineWidth = lineInfo.width; + final bool shouldJustify = _shouldJustify(lineInfo, boundsWidth, format); + final bool hasWordSpacing = format != null && format.wordSpacing != 0; + final int whitespacesCount = StringTokenizer.getCharacterCount( + line, + StringTokenizer.spaces, + ); + double wordSpace = 0; + if (shouldJustify) { + if (hasWordSpacing) { + lineWidth = lineWidth! - (whitespacesCount * format.wordSpacing); + } + final double difference = boundsWidth - lineWidth!; + wordSpace = difference / whitespacesCount; + streamWriter!.setWordSpacing(wordSpace); + } else if (format != null && format.alignment == PdfTextAlignment.justify) { + streamWriter!.setWordSpacing(0); + } + return wordSpace; + } + + bool _shouldJustify( + LineInfo lineInfo, + double boundsWidth, + PdfStringFormat? format, + ) { + final String line = lineInfo.text!; + final double? lineWidth = lineInfo.width; + final bool justifyStyle = + format != null && format.alignment == PdfTextAlignment.justify; + final bool goodWidth = boundsWidth >= 0 && lineWidth! < boundsWidth; + final int whitespacesCount = StringTokenizer.getCharacterCount( + line, + StringTokenizer.spaces, + ); + final bool hasSpaces = + whitespacesCount > 0 && line[0] != StringTokenizer.whiteSpace; + final bool goodLineBreakStyle = + (lineInfo.lineType & + PdfStringLayouter.getLineTypeValue(LineType.layoutBreak)!) > + 0; + final bool shouldJustify = + justifyStyle && goodWidth && hasSpaces && goodLineBreakStyle; + return shouldJustify; + } + + /// internal method + static List> getBezierArcPoints( + double x1, + double y1, + double x2, + double y2, + double startAng, + double extent, + ) { + return PdfGraphics._getBezierArcPoints(x1, y1, x2, y2, startAng, extent); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_margins.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_margins.dart index 4abe1028f..d9bd1cf22 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_margins.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_margins.dart @@ -1,218 +1,218 @@ -/// A class representing PDF page margins. -/// -/// ```dart -/// //Creates a new PDF document. -/// PdfDocument document = PdfDocument() -/// //Create and set new PDF margin. -/// ..pageSettings.margins = (PdfMargins()..all = 20) -/// ..pages.add().graphics.drawString( -/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); -/// //Saves the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfMargins { - //Constructor - /// Initializes a new instance of the [PdfMargins] class. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// //Create and set new PDF margin. - /// ..pageSettings.margins = (PdfMargins()..all = 20) - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfMargins() { - _helper = PdfMarginsHelper(this); - } - - //Fields - late PdfMarginsHelper _helper; - double _left = 0; - double _top = 0; - double _right = 0; - double _bottom = 0; - - //Properties - /// Gets or sets the left margin size. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// //Create and set new PDF margin. - /// ..pageSettings.margins = (PdfMargins() - /// ..left = 20 - /// ..right = 40 - /// ..top = 100 - /// ..bottom = 100) - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get left => _left; - set left(double value) { - if (_left != value && !_helper.isPageAdded) { - _left = value; - } - } - - /// Gets or sets the top margin size. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// //Create and set new PDF margin. - /// ..pageSettings.margins = (PdfMargins() - /// ..left = 20 - /// ..right = 40 - /// ..top = 100 - /// ..bottom = 100) - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get top => _top; - set top(double value) { - if (_top != value && !_helper.isPageAdded) { - _top = value; - } - } - - /// Gets or sets the right margin size. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// //Create and set new PDF margin. - /// ..pageSettings.margins = (PdfMargins() - /// ..left = 20 - /// ..right = 40 - /// ..top = 100 - /// ..bottom = 100) - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get right => _right; - set right(double value) { - if (_right != value && !_helper.isPageAdded) { - _right = value; - } - } - - /// Gets or sets the bottom margin size. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// //Create and set new PDF margin. - /// ..pageSettings.margins = (PdfMargins() - /// ..left = 20 - /// ..right = 40 - /// ..top = 100 - /// ..bottom = 100) - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get bottom => _bottom; - set bottom(double value) { - if (_bottom != value && !_helper.isPageAdded) { - _bottom = value; - } - } - - /// Sets the margins of all side. - /// - /// ```dart - /// //Creates a new PDF document. - /// PdfDocument document = PdfDocument() - /// //Create and set new PDF margin. - /// ..pageSettings.margins = (PdfMargins()..all = 20) - /// ..pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); - /// //Saves the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - // ignore: avoid_setters_without_getters - set all(double value) { - if (!_helper.isPageAdded) { - _helper.setMargins(value); - } - } -} - -/// [PdfMargins] helper -class PdfMarginsHelper { - /// internal constructor - PdfMarginsHelper(this.base); - - /// internal field - late PdfMargins base; - - /// internal field - // ignore: prefer_final_fields - bool isPageAdded = false; - - /// internal method - static PdfMarginsHelper getHelper(PdfMargins base) { - return base._helper; - } - - /// internal method - void setMargins(double margin) { - base.left = base.top = base.right = base.bottom = margin; - } - - /// internal method - void setMarginsLT(double leftRight, double topBottom) { - base.left = base.right = leftRight; - base.top = base.bottom = topBottom; - } - - /// internal method - void setMarginsAll(double l, double t, double r, double b) { - base.left = l; - base.right = r; - base.top = t; - base.bottom = b; - } - - /// internal method - bool equals(PdfMargins margins) { - return base._left == margins.left && - base._top == margins._top && - base._right == margins._right && - base._bottom == margins._bottom; - } - - /// internal method - PdfMargins clone() { - final PdfMargins result = PdfMargins(); - result.left = base.left; - result.right = base.right; - result.top = base.top; - result.bottom = base.bottom; - return result; - } -} +/// A class representing PDF page margins. +/// +/// ```dart +/// //Creates a new PDF document. +/// PdfDocument document = PdfDocument() +/// //Create and set new PDF margin. +/// ..pageSettings.margins = (PdfMargins()..all = 20) +/// ..pages.add().graphics.drawString( +/// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); +/// //Saves the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfMargins { + //Constructor + /// Initializes a new instance of the [PdfMargins] class. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// //Create and set new PDF margin. + /// ..pageSettings.margins = (PdfMargins()..all = 20) + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfMargins() { + _helper = PdfMarginsHelper(this); + } + + //Fields + late PdfMarginsHelper _helper; + double _left = 0; + double _top = 0; + double _right = 0; + double _bottom = 0; + + //Properties + /// Gets or sets the left margin size. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// //Create and set new PDF margin. + /// ..pageSettings.margins = (PdfMargins() + /// ..left = 20 + /// ..right = 40 + /// ..top = 100 + /// ..bottom = 100) + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get left => _left; + set left(double value) { + if (_left != value && !_helper.isPageAdded) { + _left = value; + } + } + + /// Gets or sets the top margin size. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// //Create and set new PDF margin. + /// ..pageSettings.margins = (PdfMargins() + /// ..left = 20 + /// ..right = 40 + /// ..top = 100 + /// ..bottom = 100) + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get top => _top; + set top(double value) { + if (_top != value && !_helper.isPageAdded) { + _top = value; + } + } + + /// Gets or sets the right margin size. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// //Create and set new PDF margin. + /// ..pageSettings.margins = (PdfMargins() + /// ..left = 20 + /// ..right = 40 + /// ..top = 100 + /// ..bottom = 100) + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get right => _right; + set right(double value) { + if (_right != value && !_helper.isPageAdded) { + _right = value; + } + } + + /// Gets or sets the bottom margin size. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// //Create and set new PDF margin. + /// ..pageSettings.margins = (PdfMargins() + /// ..left = 20 + /// ..right = 40 + /// ..top = 100 + /// ..bottom = 100) + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get bottom => _bottom; + set bottom(double value) { + if (_bottom != value && !_helper.isPageAdded) { + _bottom = value; + } + } + + /// Sets the margins of all side. + /// + /// ```dart + /// //Creates a new PDF document. + /// PdfDocument document = PdfDocument() + /// //Create and set new PDF margin. + /// ..pageSettings.margins = (PdfMargins()..all = 20) + /// ..pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12)); + /// //Saves the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + // ignore: avoid_setters_without_getters + set all(double value) { + if (!_helper.isPageAdded) { + _helper.setMargins(value); + } + } +} + +/// [PdfMargins] helper +class PdfMarginsHelper { + /// internal constructor + PdfMarginsHelper(this.base); + + /// internal field + late PdfMargins base; + + /// internal field + // ignore: prefer_final_fields + bool isPageAdded = false; + + /// internal method + static PdfMarginsHelper getHelper(PdfMargins base) { + return base._helper; + } + + /// internal method + void setMargins(double margin) { + base.left = base.top = base.right = base.bottom = margin; + } + + /// internal method + void setMarginsLT(double leftRight, double topBottom) { + base.left = base.right = leftRight; + base.top = base.bottom = topBottom; + } + + /// internal method + void setMarginsAll(double l, double t, double r, double b) { + base.left = l; + base.right = r; + base.top = t; + base.bottom = b; + } + + /// internal method + bool equals(PdfMargins margins) { + return base._left == margins.left && + base._top == margins._top && + base._right == margins._right && + base._bottom == margins._bottom; + } + + /// internal method + PdfMargins clone() { + final PdfMargins result = PdfMargins(); + result.left = base.left; + result.right = base.right; + result.top = base.top; + result.bottom = base.bottom; + return result; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pen.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pen.dart index 2d22693ea..e30ff95a0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pen.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pen.dart @@ -1,444 +1,444 @@ -import '../io/pdf_stream_writer.dart'; -import 'brushes/pdf_solid_brush.dart'; -import 'enums.dart'; -import 'pdf_color.dart'; -import 'pdf_transformation_matrix.dart'; - -/// A class defining settings for drawing operations, -/// that determines the color, width, and style of the drawing elements. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument doc = PdfDocument() -/// ..pages.add().graphics.drawRectangle( -/// //Create a new PDF pen instance. -/// pen: PdfPen(PdfColor(255, 0, 0)), -/// bounds: Rect.fromLTWH(0, 0, 200, 100)); -/// //Save the document. -/// List bytes = doc.save(); -/// //Close the document. -/// doc.dispose(); -/// ``` -class PdfPen { - //Constructor - /// Initializes a new instance of the [PdfPen] class. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //Create a new PDF pen instance. - /// pen: PdfPen(PdfColor(255, 0, 0)), - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Close the document. - /// doc.dispose(); - /// ``` - PdfPen( - PdfColor pdfColor, { - double width = 1.0, - PdfDashStyle dashStyle = PdfDashStyle.solid, - PdfLineCap lineCap = PdfLineCap.flat, - PdfLineJoin lineJoin = PdfLineJoin.miter, - }) { - _helper = PdfPenHelper(this); - _color = pdfColor; - _initialize(width, dashStyle, lineCap, lineJoin); - } - - /// Initializes a new instance of the [PdfPen] with [PdfBrush]. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //Create a new PDF pen instance. - /// pen: PdfPen.fromBrush(PdfBrushes.red), - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Close the document. - /// doc.dispose(); - /// ``` - PdfPen.fromBrush( - PdfBrush brush, { - double width = 1.0, - PdfDashStyle dashStyle = PdfDashStyle.solid, - PdfLineCap lineCap = PdfLineCap.flat, - PdfLineJoin lineJoin = PdfLineJoin.miter, - }) { - _helper = PdfPenHelper(this); - _setBrush(brush); - _width = width; - _initialize(width, dashStyle, lineCap, lineJoin); - } - - PdfPen._immutable(PdfColor pdfColor) { - _helper = PdfPenHelper(this); - _color = pdfColor; - _helper.isImmutable = true; - _initialize(1.0, PdfDashStyle.solid, PdfLineCap.flat, PdfLineJoin.miter); - } - - //Fields - late PdfPenHelper _helper; - //ignore:unused_field - late PdfColorSpace _colorSpace; - PdfDashStyle _dashStyle = PdfDashStyle.solid; - PdfColor _color = PdfColor(0, 0, 0); - PdfBrush? _brush; - late double _dashOffset; - late List _dashPattern; - PdfLineCap _lineCap = PdfLineCap.flat; - PdfLineJoin _lineJoin = PdfLineJoin.miter; - double _width = 1.0; - late double _miterLimit; - - //Properties - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is PdfPen && _isEqual(other); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => width.hashCode; - - /// Gets or sets the color of the pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 0, 0)), - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfColor get color => _color; - set color(PdfColor value) { - _checkImmutability(); - _color = value; - } - - /// Gets or sets the brush, which specifies the pen behavior. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //Set brush - /// pen: PdfPen(PdfColor(255, 0, 0))..brush = PdfBrushes.green, - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfBrush? get brush => _brush; - set brush(PdfBrush? value) { - _checkImmutability(); - _setBrush(value); - } - - /// Gets or sets the dash offset of the pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //Set pen dash offset. - /// pen: PdfPen(PdfColor(255, 0, 0))..dashOffset = 0.5, - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - double get dashOffset => _dashOffset; - set dashOffset(double value) { - _checkImmutability(); - _dashOffset = value; - } - - /// Gets or sets the dash pattern of the pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //Set pen dash pattern. - /// pen: PdfPen(PdfColor(255, 0, 0))..dashPattern = [4, 2, 1, 3], - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - List get dashPattern => _dashPattern; - set dashPattern(List value) { - if (dashStyle == PdfDashStyle.solid) { - UnsupportedError( - 'This operation is not allowed. Set Custom dash style to change the pattern.', - ); - } - _checkImmutability(); - _dashPattern = value; - } - - /// Gets or sets the line cap of the pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 0, 0), - /// dashStyle: PdfDashStyle.custom, lineCap: PdfLineCap.round) - /// ..dashPattern = [4, 2, 1, 3], - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfLineCap get lineCap => _lineCap; - set lineCap(PdfLineCap value) { - _checkImmutability(); - _lineCap = value; - } - - /// Gets or sets the line join style of the pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 0, 0), - /// dashStyle: PdfDashStyle.custom, lineJoin: PdfLineJoin.bevel) - /// ..dashPattern = [4, 2, 1, 3], - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfLineJoin get lineJoin => _lineJoin; - set lineJoin(PdfLineJoin value) { - _checkImmutability(); - _lineJoin = value; - } - - /// Gets or sets the width of the pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// //Set pen width. - /// pen: PdfPen(PdfColor(255, 0, 0), width: 4), - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - double get width => _width; - set width(double value) { - _checkImmutability(); - _width = value; - } - - /// Gets or sets the miter limit. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 0, 0), width: 4) - /// //Set miter limit, - /// ..miterLimit = 2, - /// bounds: Rect.fromLTWH(10, 10, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - double get miterLimit => _miterLimit; - set miterLimit(double value) { - _checkImmutability(); - _miterLimit = value; - } - - /// Gets or sets the dash style of the pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument() - /// ..pages.add().graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 0, 0), - /// dashStyle: PdfDashStyle.custom, lineJoin: PdfLineJoin.bevel) - /// ..dashPattern = [4, 2, 1, 3], - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Close the document. - /// document.dispose(); - /// ``` - PdfDashStyle get dashStyle => _dashStyle; - set dashStyle(PdfDashStyle value) { - _checkImmutability(); - _setDashStyle(value); - } - - //Implementation - bool _isEqual(PdfPen other) { - return width == other.width && - miterLimit == other.miterLimit && - lineJoin == other.lineJoin && - lineCap == other.lineCap && - dashStyle == other.dashStyle && - _hasSameDashPattern(other.dashPattern) && - brush == other.brush && - color == other.color; - } - - bool _hasSameDashPattern(List otherPattern) { - if (dashPattern.length == otherPattern.length) { - bool isSame = true; - for (int i = 0; i < dashPattern.length; i++) { - isSame &= dashPattern[0] == otherPattern[0]; - } - return isSame; - } else { - return false; - } - } - - void _checkImmutability() { - if (_helper.isImmutable) { - throw UnsupportedError("The immutable object can't be changed"); - } - } - - void _setDashStyle(PdfDashStyle? value) { - if (_dashStyle != value) { - _dashStyle = value!; - switch (_dashStyle) { - case PdfDashStyle.custom: - break; - case PdfDashStyle.dash: - _dashPattern = [3, 1]; - break; - case PdfDashStyle.dot: - _dashPattern = [1, 1]; - break; - case PdfDashStyle.dashDot: - _dashPattern = [3, 1, 1, 1]; - break; - case PdfDashStyle.dashDotDot: - _dashPattern = [3, 1, 1, 1, 1, 1]; - break; - case PdfDashStyle.solid: - _dashPattern = []; - break; - } - } - } - - void _initialize( - double width, - PdfDashStyle dashStyle, - PdfLineCap lineCap, - PdfLineJoin lineJoin, - ) { - _width = width; - _colorSpace = PdfColorSpace.rgb; - _dashOffset = 0; - _dashPattern = []; - _dashStyle = PdfDashStyle.solid; - _lineCap = lineCap; - _lineJoin = lineJoin; - _miterLimit = 0.0; - } - - void _setBrush(PdfBrush? brush) { - if (brush is PdfSolidBrush) { - _color = brush.color; - _brush = brush; - } - } -} - -/// [PdfPen] helper -class PdfPenHelper { - /// internal constructor - PdfPenHelper(this.base); - - /// internal field - late PdfPen base; - - /// internal method - static PdfPenHelper getHelper(PdfPen base) { - return base._helper; - } - - /// internal field - bool isImmutable = false; - - /// internal method - static PdfPen immutable(PdfColor pdfColor) { - return PdfPen._immutable(pdfColor); - } - - /// internal field - bool? isSkipPatternWidth; - - /// internal method - bool monitorChanges( - PdfPen? currentPen, - PdfStreamWriter streamWriter, - Function? getResources, - bool saveState, - PdfColorSpace? currentColorSpace, - PdfTransformationMatrix? matrix, - ) { - bool diff = false; - saveState = true; - if (currentPen == null) { - diff = true; - } - diff = _dashControl(currentPen, saveState, streamWriter); - streamWriter.setLineWidth(base.width); - streamWriter.setLineJoin(base.lineJoin); - streamWriter.setLineCap(base.lineCap); - if (base.miterLimit > 0) { - streamWriter.setMiterLimit(base.miterLimit); - diff = true; - } - streamWriter.setColorAndSpace(base.color, currentColorSpace, true); - diff = true; - return diff; - } - - bool _dashControl(PdfPen? pen, bool saveState, PdfStreamWriter streamWriter) { - saveState = true; - final List? pattern = _getPattern(); - streamWriter.setLineDashPattern(pattern, base.dashOffset * base.width); - return saveState; - } - - List? _getPattern() { - final List pattern = base.dashPattern; - isSkipPatternWidth ??= false; - if (!isSkipPatternWidth!) { - for (int i = 0; i < pattern.length; ++i) { - pattern[i] *= base.width; - } - } - return pattern; - } -} +import '../io/pdf_stream_writer.dart'; +import 'brushes/pdf_solid_brush.dart'; +import 'enums.dart'; +import 'pdf_color.dart'; +import 'pdf_transformation_matrix.dart'; + +/// A class defining settings for drawing operations, +/// that determines the color, width, and style of the drawing elements. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument doc = PdfDocument() +/// ..pages.add().graphics.drawRectangle( +/// //Create a new PDF pen instance. +/// pen: PdfPen(PdfColor(255, 0, 0)), +/// bounds: Rect.fromLTWH(0, 0, 200, 100)); +/// //Save the document. +/// List bytes = doc.save(); +/// //Close the document. +/// doc.dispose(); +/// ``` +class PdfPen { + //Constructor + /// Initializes a new instance of the [PdfPen] class. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //Create a new PDF pen instance. + /// pen: PdfPen(PdfColor(255, 0, 0)), + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Close the document. + /// doc.dispose(); + /// ``` + PdfPen( + PdfColor pdfColor, { + double width = 1.0, + PdfDashStyle dashStyle = PdfDashStyle.solid, + PdfLineCap lineCap = PdfLineCap.flat, + PdfLineJoin lineJoin = PdfLineJoin.miter, + }) { + _helper = PdfPenHelper(this); + _color = pdfColor; + _initialize(width, dashStyle, lineCap, lineJoin); + } + + /// Initializes a new instance of the [PdfPen] with [PdfBrush]. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //Create a new PDF pen instance. + /// pen: PdfPen.fromBrush(PdfBrushes.red), + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Close the document. + /// doc.dispose(); + /// ``` + PdfPen.fromBrush( + PdfBrush brush, { + double width = 1.0, + PdfDashStyle dashStyle = PdfDashStyle.solid, + PdfLineCap lineCap = PdfLineCap.flat, + PdfLineJoin lineJoin = PdfLineJoin.miter, + }) { + _helper = PdfPenHelper(this); + _setBrush(brush); + _width = width; + _initialize(width, dashStyle, lineCap, lineJoin); + } + + PdfPen._immutable(PdfColor pdfColor) { + _helper = PdfPenHelper(this); + _color = pdfColor; + _helper.isImmutable = true; + _initialize(1.0, PdfDashStyle.solid, PdfLineCap.flat, PdfLineJoin.miter); + } + + //Fields + late PdfPenHelper _helper; + //ignore:unused_field + late PdfColorSpace _colorSpace; + PdfDashStyle _dashStyle = PdfDashStyle.solid; + PdfColor _color = PdfColor(0, 0, 0); + PdfBrush? _brush; + late double _dashOffset; + late List _dashPattern; + PdfLineCap _lineCap = PdfLineCap.flat; + PdfLineJoin _lineJoin = PdfLineJoin.miter; + double _width = 1.0; + late double _miterLimit; + + //Properties + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is PdfPen && _isEqual(other); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => width.hashCode; + + /// Gets or sets the color of the pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 0, 0)), + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfColor get color => _color; + set color(PdfColor value) { + _checkImmutability(); + _color = value; + } + + /// Gets or sets the brush, which specifies the pen behavior. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //Set brush + /// pen: PdfPen(PdfColor(255, 0, 0))..brush = PdfBrushes.green, + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfBrush? get brush => _brush; + set brush(PdfBrush? value) { + _checkImmutability(); + _setBrush(value); + } + + /// Gets or sets the dash offset of the pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //Set pen dash offset. + /// pen: PdfPen(PdfColor(255, 0, 0))..dashOffset = 0.5, + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + double get dashOffset => _dashOffset; + set dashOffset(double value) { + _checkImmutability(); + _dashOffset = value; + } + + /// Gets or sets the dash pattern of the pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //Set pen dash pattern. + /// pen: PdfPen(PdfColor(255, 0, 0))..dashPattern = [4, 2, 1, 3], + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + List get dashPattern => _dashPattern; + set dashPattern(List value) { + if (dashStyle == PdfDashStyle.solid) { + UnsupportedError( + 'This operation is not allowed. Set Custom dash style to change the pattern.', + ); + } + _checkImmutability(); + _dashPattern = value; + } + + /// Gets or sets the line cap of the pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 0, 0), + /// dashStyle: PdfDashStyle.custom, lineCap: PdfLineCap.round) + /// ..dashPattern = [4, 2, 1, 3], + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfLineCap get lineCap => _lineCap; + set lineCap(PdfLineCap value) { + _checkImmutability(); + _lineCap = value; + } + + /// Gets or sets the line join style of the pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 0, 0), + /// dashStyle: PdfDashStyle.custom, lineJoin: PdfLineJoin.bevel) + /// ..dashPattern = [4, 2, 1, 3], + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfLineJoin get lineJoin => _lineJoin; + set lineJoin(PdfLineJoin value) { + _checkImmutability(); + _lineJoin = value; + } + + /// Gets or sets the width of the pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// //Set pen width. + /// pen: PdfPen(PdfColor(255, 0, 0), width: 4), + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + double get width => _width; + set width(double value) { + _checkImmutability(); + _width = value; + } + + /// Gets or sets the miter limit. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 0, 0), width: 4) + /// //Set miter limit, + /// ..miterLimit = 2, + /// bounds: Rect.fromLTWH(10, 10, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + double get miterLimit => _miterLimit; + set miterLimit(double value) { + _checkImmutability(); + _miterLimit = value; + } + + /// Gets or sets the dash style of the pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument() + /// ..pages.add().graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 0, 0), + /// dashStyle: PdfDashStyle.custom, lineJoin: PdfLineJoin.bevel) + /// ..dashPattern = [4, 2, 1, 3], + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Close the document. + /// document.dispose(); + /// ``` + PdfDashStyle get dashStyle => _dashStyle; + set dashStyle(PdfDashStyle value) { + _checkImmutability(); + _setDashStyle(value); + } + + //Implementation + bool _isEqual(PdfPen other) { + return width == other.width && + miterLimit == other.miterLimit && + lineJoin == other.lineJoin && + lineCap == other.lineCap && + dashStyle == other.dashStyle && + _hasSameDashPattern(other.dashPattern) && + brush == other.brush && + color == other.color; + } + + bool _hasSameDashPattern(List otherPattern) { + if (dashPattern.length == otherPattern.length) { + bool isSame = true; + for (int i = 0; i < dashPattern.length; i++) { + isSame &= dashPattern[0] == otherPattern[0]; + } + return isSame; + } else { + return false; + } + } + + void _checkImmutability() { + if (_helper.isImmutable) { + throw UnsupportedError("The immutable object can't be changed"); + } + } + + void _setDashStyle(PdfDashStyle? value) { + if (_dashStyle != value) { + _dashStyle = value!; + switch (_dashStyle) { + case PdfDashStyle.custom: + break; + case PdfDashStyle.dash: + _dashPattern = [3, 1]; + break; + case PdfDashStyle.dot: + _dashPattern = [1, 1]; + break; + case PdfDashStyle.dashDot: + _dashPattern = [3, 1, 1, 1]; + break; + case PdfDashStyle.dashDotDot: + _dashPattern = [3, 1, 1, 1, 1, 1]; + break; + case PdfDashStyle.solid: + _dashPattern = []; + break; + } + } + } + + void _initialize( + double width, + PdfDashStyle dashStyle, + PdfLineCap lineCap, + PdfLineJoin lineJoin, + ) { + _width = width; + _colorSpace = PdfColorSpace.rgb; + _dashOffset = 0; + _dashPattern = []; + _dashStyle = PdfDashStyle.solid; + _lineCap = lineCap; + _lineJoin = lineJoin; + _miterLimit = 0.0; + } + + void _setBrush(PdfBrush? brush) { + if (brush is PdfSolidBrush) { + _color = brush.color; + _brush = brush; + } + } +} + +/// [PdfPen] helper +class PdfPenHelper { + /// internal constructor + PdfPenHelper(this.base); + + /// internal field + late PdfPen base; + + /// internal method + static PdfPenHelper getHelper(PdfPen base) { + return base._helper; + } + + /// internal field + bool isImmutable = false; + + /// internal method + static PdfPen immutable(PdfColor pdfColor) { + return PdfPen._immutable(pdfColor); + } + + /// internal field + bool? isSkipPatternWidth; + + /// internal method + bool monitorChanges( + PdfPen? currentPen, + PdfStreamWriter streamWriter, + Function? getResources, + bool saveState, + PdfColorSpace? currentColorSpace, + PdfTransformationMatrix? matrix, + ) { + bool diff = false; + saveState = true; + if (currentPen == null) { + diff = true; + } + diff = _dashControl(currentPen, saveState, streamWriter); + streamWriter.setLineWidth(base.width); + streamWriter.setLineJoin(base.lineJoin); + streamWriter.setLineCap(base.lineCap); + if (base.miterLimit > 0) { + streamWriter.setMiterLimit(base.miterLimit); + diff = true; + } + streamWriter.setColorAndSpace(base.color, currentColorSpace, true); + diff = true; + return diff; + } + + bool _dashControl(PdfPen? pen, bool saveState, PdfStreamWriter streamWriter) { + saveState = true; + final List? pattern = _getPattern(); + streamWriter.setLineDashPattern(pattern, base.dashOffset * base.width); + return saveState; + } + + List? _getPattern() { + final List pattern = base.dashPattern; + isSkipPatternWidth ??= false; + if (!isSkipPatternWidth!) { + for (int i = 0; i < pattern.length; ++i) { + pattern[i] *= base.width; + } + } + return pattern; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pens.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pens.dart index 04bf34579..074514563 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pens.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_pens.dart @@ -1,3230 +1,3230 @@ -import '../drawing/color.dart'; -import 'pdf_color.dart'; -import 'pdf_pen.dart'; - -/// The collection of default pens. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument doc = PdfDocument(); -/// //Draw rectangle. -/// doc.pages -/// .add() -/// .graphics -/// .drawRectangle(pen: PdfPens.black, -/// bounds: Rect.fromLTWH(0, 0, 200, 100)); -/// //Save the document. -/// List bytes = doc.save(); -/// //Dispose the document. -/// doc.dispose(); -/// ``` -class PdfPens { - PdfPens._(); - static final Map _pens = {}; - - /// Gets the AliceBlue pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.aliceBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get aliceBlue { - if (_pens.containsKey(KnownColor.aliceBlue)) { - return _pens[KnownColor.aliceBlue]!; - } else { - return _getPen(KnownColor.aliceBlue); - } - } - - /// Gets the Antique white pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.antiqueWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get antiqueWhite { - if (_pens.containsKey(KnownColor.antiqueWhite)) { - return _pens[KnownColor.antiqueWhite]!; - } else { - return _getPen(KnownColor.antiqueWhite); - } - } - - /// Gets the Aqua default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.aqua, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get aqua { - if (_pens.containsKey(KnownColor.aqua)) { - return _pens[KnownColor.aqua]!; - } else { - return _getPen(KnownColor.aqua); - } - } - - /// Gets the Aquamarine default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.aquamarine, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get aquamarine { - if (_pens.containsKey(KnownColor.aquamarine)) { - return _pens[KnownColor.aquamarine]!; - } else { - return _getPen(KnownColor.aquamarine); - } - } - - /// Gets the Azure default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.azure, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get azure { - if (_pens.containsKey(KnownColor.azure)) { - return _pens[KnownColor.azure]!; - } else { - return _getPen(KnownColor.azure); - } - } - - /// Gets the Beige default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.beige, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get beige { - if (_pens.containsKey(KnownColor.beige)) { - return _pens[KnownColor.beige]!; - } else { - return _getPen(KnownColor.beige); - } - } - - /// Gets the Bisque default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.bisque, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get bisque { - if (_pens.containsKey(KnownColor.bisque)) { - return _pens[KnownColor.bisque]!; - } else { - return _getPen(KnownColor.bisque); - } - } - - /// Gets the Black default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.black, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get black { - if (_pens.containsKey(KnownColor.black)) { - return _pens[KnownColor.black]!; - } else { - return _getPen(KnownColor.black); - } - } - - /// Gets the BlanchedAlmond default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.blanchedAlmond, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get blanchedAlmond { - if (_pens.containsKey(KnownColor.blanchedAlmond)) { - return _pens[KnownColor.blanchedAlmond]!; - } else { - return _getPen(KnownColor.blanchedAlmond); - } - } - - /// Gets the Blue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.blue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get blue { - if (_pens.containsKey(KnownColor.blue)) { - return _pens[KnownColor.blue]!; - } else { - return _getPen(KnownColor.blue); - } - } - - /// Gets the BlueViolet default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.blueViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get blueViolet { - if (_pens.containsKey(KnownColor.blueViolet)) { - return _pens[KnownColor.blueViolet]!; - } else { - return _getPen(KnownColor.blueViolet); - } - } - - /// Gets the Brown default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.brown, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get brown { - if (_pens.containsKey(KnownColor.brown)) { - return _pens[KnownColor.brown]!; - } else { - return _getPen(KnownColor.brown); - } - } - - /// Gets the BurlyWood default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.burlyWood, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get burlyWood { - if (_pens.containsKey(KnownColor.burlyWood)) { - return _pens[KnownColor.burlyWood]!; - } else { - return _getPen(KnownColor.burlyWood); - } - } - - /// Gets the CadetBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.cadetBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get cadetBlue { - if (_pens.containsKey(KnownColor.cadetBlue)) { - return _pens[KnownColor.cadetBlue]!; - } else { - return _getPen(KnownColor.cadetBlue); - } - } - - /// Gets the Chartreuse default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.chartreuse, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get chartreuse { - if (_pens.containsKey(KnownColor.chartreuse)) { - return _pens[KnownColor.chartreuse]!; - } else { - return _getPen(KnownColor.chartreuse); - } - } - - /// Gets the Chocolate default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.chocolate, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get chocolate { - if (_pens.containsKey(KnownColor.chocolate)) { - return _pens[KnownColor.chocolate]!; - } else { - return _getPen(KnownColor.chocolate); - } - } - - /// Gets the Coral default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.coral, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get coral { - if (_pens.containsKey(KnownColor.coral)) { - return _pens[KnownColor.coral]!; - } else { - return _getPen(KnownColor.coral); - } - } - - /// Gets the CornflowerBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.cornflowerBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get cornflowerBlue { - if (_pens.containsKey(KnownColor.cornflowerBlue)) { - return _pens[KnownColor.cornflowerBlue]!; - } else { - return _getPen(KnownColor.cornflowerBlue); - } - } - - /// Gets the Corn silk default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.cornsilk, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get cornsilk { - if (_pens.containsKey(KnownColor.cornsilk)) { - return _pens[KnownColor.cornsilk]!; - } else { - return _getPen(KnownColor.cornsilk); - } - } - - /// Gets the Crimson default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.crimson, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get crimson { - if (_pens.containsKey(KnownColor.crimson)) { - return _pens[KnownColor.crimson]!; - } else { - return _getPen(KnownColor.crimson); - } - } - - /// Gets the Cyan default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.cyan, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get cyan { - if (_pens.containsKey(KnownColor.cyan)) { - return _pens[KnownColor.cyan]!; - } else { - return _getPen(KnownColor.cyan); - } - } - - /// Gets the DarkBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.darkBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkBlue { - if (_pens.containsKey(KnownColor.darkBlue)) { - return _pens[KnownColor.darkBlue]!; - } else { - return _getPen(KnownColor.darkBlue); - } - } - - /// Gets the DarkCyan default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.darkCyan, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkCyan { - if (_pens.containsKey(KnownColor.darkCyan)) { - return _pens[KnownColor.darkCyan]!; - } else { - return _getPen(KnownColor.darkCyan); - } - } - - /// Gets the DarkGoldenrod default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkGoldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkGoldenrod { - if (_pens.containsKey(KnownColor.darkGoldenrod)) { - return _pens[KnownColor.darkGoldenrod]!; - } else { - return _getPen(KnownColor.darkGoldenrod); - } - } - - /// Gets the DarkGray default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.darkGray, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkGray { - if (_pens.containsKey(KnownColor.darkGray)) { - return _pens[KnownColor.darkGray]!; - } else { - return _getPen(KnownColor.darkGray); - } - } - - /// Gets the DarkGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.darkGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkGreen { - if (_pens.containsKey(KnownColor.darkGreen)) { - return _pens[KnownColor.darkGreen]!; - } else { - return _getPen(KnownColor.darkGreen); - } - } - - /// Gets the DarkKhaki default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.darkKhaki, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkKhaki { - if (_pens.containsKey(KnownColor.darkKhaki)) { - return _pens[KnownColor.darkKhaki]!; - } else { - return _getPen(KnownColor.darkKhaki); - } - } - - /// Gets the DarkMagenta default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkMagenta, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkMagenta { - if (_pens.containsKey(KnownColor.darkMagenta)) { - return _pens[KnownColor.darkMagenta]!; - } else { - return _getPen(KnownColor.darkMagenta); - } - } - - /// Gets the DarkOliveGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkOliveGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkOliveGreen { - if (_pens.containsKey(KnownColor.darkOliveGreen)) { - return _pens[KnownColor.darkOliveGreen]!; - } else { - return _getPen(KnownColor.darkOliveGreen); - } - } - - /// Gets the DarkOrange default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkOrange, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkOrange { - if (_pens.containsKey(KnownColor.darkOrange)) { - return _pens[KnownColor.darkOrange]!; - } else { - return _getPen(KnownColor.darkOrange); - } - } - - /// Gets the DarkOrchid default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkOrchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkOrchid { - if (_pens.containsKey(KnownColor.darkOrchid)) { - return _pens[KnownColor.darkOrchid]!; - } else { - return _getPen(KnownColor.darkOrchid); - } - } - - /// Gets the DarkRed default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.darkRed, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkRed { - if (_pens.containsKey(KnownColor.darkRed)) { - return _pens[KnownColor.darkRed]!; - } else { - return _getPen(KnownColor.darkRed); - } - } - - /// Gets the DarkSalmon default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkSalmon { - if (_pens.containsKey(KnownColor.darkSalmon)) { - return _pens[KnownColor.darkSalmon]!; - } else { - return _getPen(KnownColor.darkSalmon); - } - } - - /// Gets the DarkSeaGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkSeaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkSeaGreen { - if (_pens.containsKey(KnownColor.darkSeaGreen)) { - return _pens[KnownColor.darkSeaGreen]!; - } else { - return _getPen(KnownColor.darkSeaGreen); - } - } - - /// Gets the DarkSlateBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkSlateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkSlateBlue { - if (_pens.containsKey(KnownColor.darkSlateBlue)) { - return _pens[KnownColor.darkSlateBlue]!; - } else { - return _getPen(KnownColor.darkSlateBlue); - } - } - - /// Gets the DarkSlateGray default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkSlateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkSlateGray { - if (_pens.containsKey(KnownColor.darkSlateGray)) { - return _pens[KnownColor.darkSlateGray]!; - } else { - return _getPen(KnownColor.darkSlateGray); - } - } - - /// Gets the DarkTurquoise default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkTurquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkTurquoise { - if (_pens.containsKey(KnownColor.darkTurquoise)) { - return _pens[KnownColor.darkTurquoise]!; - } else { - return _getPen(KnownColor.darkTurquoise); - } - } - - /// Gets the DarkViolet default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.darkViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get darkViolet { - if (_pens.containsKey(KnownColor.darkViolet)) { - return _pens[KnownColor.darkViolet]!; - } else { - return _getPen(KnownColor.darkViolet); - } - } - - /// Gets the DeepPink default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.deepPink, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get deepPink { - if (_pens.containsKey(KnownColor.deepPink)) { - return _pens[KnownColor.deepPink]!; - } else { - return _getPen(KnownColor.deepPink); - } - } - - /// Gets the DeepSkyBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.deepSkyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get deepSkyBlue { - if (_pens.containsKey(KnownColor.deepSkyBlue)) { - return _pens[KnownColor.deepSkyBlue]!; - } else { - return _getPen(KnownColor.deepSkyBlue); - } - } - - /// Gets the DimGray default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.dimGray, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get dimGray { - if (_pens.containsKey(KnownColor.dimGray)) { - return _pens[KnownColor.dimGray]!; - } else { - return _getPen(KnownColor.dimGray); - } - } - - /// Gets the DodgerBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.dodgerBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get dodgerBlue { - if (_pens.containsKey(KnownColor.dodgerBlue)) { - return _pens[KnownColor.dodgerBlue]!; - } else { - return _getPen(KnownColor.dodgerBlue); - } - } - - /// Gets the Firebrick default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.firebrick, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get firebrick { - if (_pens.containsKey(KnownColor.firebrick)) { - return _pens[KnownColor.firebrick]!; - } else { - return _getPen(KnownColor.firebrick); - } - } - - /// Gets the FloralWhite default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.floralWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get floralWhite { - if (_pens.containsKey(KnownColor.floralWhite)) { - return _pens[KnownColor.floralWhite]!; - } else { - return _getPen(KnownColor.floralWhite); - } - } - - /// Gets the ForestGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.forestGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get forestGreen { - if (_pens.containsKey(KnownColor.forestGreen)) { - return _pens[KnownColor.forestGreen]!; - } else { - return _getPen(KnownColor.forestGreen); - } - } - - /// Gets the Fuchsia default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.fuchsia, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get fuchsia { - if (_pens.containsKey(KnownColor.fuchsia)) { - return _pens[KnownColor.fuchsia]!; - } else { - return _getPen(KnownColor.fuchsia); - } - } - - /// Gets the Gainsborough default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.gainsboro, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get gainsboro { - if (_pens.containsKey(KnownColor.gainsboro)) { - return _pens[KnownColor.gainsboro]!; - } else { - return _getPen(KnownColor.gainsboro); - } - } - - /// Gets the GhostWhite default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.ghostWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get ghostWhite { - if (_pens.containsKey(KnownColor.ghostWhite)) { - return _pens[KnownColor.ghostWhite]!; - } else { - return _getPen(KnownColor.ghostWhite); - } - } - - /// Gets the Gold default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.gold, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get gold { - if (_pens.containsKey(KnownColor.gold)) { - return _pens[KnownColor.gold]!; - } else { - return _getPen(KnownColor.gold); - } - } - - /// Gets the Goldenrod default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.goldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get goldenrod { - if (_pens.containsKey(KnownColor.goldenrod)) { - return _pens[KnownColor.goldenrod]!; - } else { - return _getPen(KnownColor.goldenrod); - } - } - - /// Gets the Gray default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.gray, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get gray { - if (_pens.containsKey(KnownColor.gray)) { - return _pens[KnownColor.gray]!; - } else { - return _getPen(KnownColor.gray); - } - } - - /// Gets the Green default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.green, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get green { - if (_pens.containsKey(KnownColor.green)) { - return _pens[KnownColor.green]!; - } else { - return _getPen(KnownColor.green); - } - } - - /// Gets the GreenYellow default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.greenYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get greenYellow { - if (_pens.containsKey(KnownColor.greenYellow)) { - return _pens[KnownColor.greenYellow]!; - } else { - return _getPen(KnownColor.greenYellow); - } - } - - /// Gets the Honeydew default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.honeydew, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get honeydew { - if (_pens.containsKey(KnownColor.honeydew)) { - return _pens[KnownColor.honeydew]!; - } else { - return _getPen(KnownColor.honeydew); - } - } - - /// Gets the HotPink default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.hotPink, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get hotPink { - if (_pens.containsKey(KnownColor.hotPink)) { - return _pens[KnownColor.hotPink]!; - } else { - return _getPen(KnownColor.hotPink); - } - } - - /// Gets the IndianRed default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.indianRed, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get indianRed { - if (_pens.containsKey(KnownColor.indianRed)) { - return _pens[KnownColor.indianRed]!; - } else { - return _getPen(KnownColor.indianRed); - } - } - - /// Gets the Indigo default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.indigo, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get indigo { - if (_pens.containsKey(KnownColor.indigo)) { - return _pens[KnownColor.indigo]!; - } else { - return _getPen(KnownColor.indigo); - } - } - - /// Gets the Ivory default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.ivory, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get ivory { - if (_pens.containsKey(KnownColor.ivory)) { - return _pens[KnownColor.ivory]!; - } else { - return _getPen(KnownColor.ivory); - } - } - - /// Gets the Khaki default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.khaki, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get khaki { - if (_pens.containsKey(KnownColor.khaki)) { - return _pens[KnownColor.khaki]!; - } else { - return _getPen(KnownColor.khaki); - } - } - - /// Gets the Lavender default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.lavender, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lavender { - if (_pens.containsKey(KnownColor.lavender)) { - return _pens[KnownColor.lavender]!; - } else { - return _getPen(KnownColor.lavender); - } - } - - /// Gets the LavenderBlush default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lavenderBlush, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lavenderBlush { - if (_pens.containsKey(KnownColor.lavenderBlush)) { - return _pens[KnownColor.lavenderBlush]!; - } else { - return _getPen(KnownColor.lavenderBlush); - } - } - - /// Gets the LawnGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.lawnGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lawnGreen { - if (_pens.containsKey(KnownColor.lawnGreen)) { - return _pens[KnownColor.lawnGreen]!; - } else { - return _getPen(KnownColor.lawnGreen); - } - } - - /// Gets the LemonChiffon default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lemonChiffon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lemonChiffon { - if (_pens.containsKey(KnownColor.lemonChiffon)) { - return _pens[KnownColor.lemonChiffon]!; - } else { - return _getPen(KnownColor.lemonChiffon); - } - } - - /// Gets the LightBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.lightBlue, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightBlue { - if (_pens.containsKey(KnownColor.lightBlue)) { - return _pens[KnownColor.lightBlue]!; - } else { - return _getPen(KnownColor.lightBlue); - } - } - - /// Gets the LightCoral default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightCoral, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightCoral { - if (_pens.containsKey(KnownColor.lightCoral)) { - return _pens[KnownColor.lightCoral]!; - } else { - return _getPen(KnownColor.lightCoral); - } - } - - /// Gets the LightCyan default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.lightCyan, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightCyan { - if (_pens.containsKey(KnownColor.lightCyan)) { - return _pens[KnownColor.lightCyan]!; - } else { - return _getPen(KnownColor.lightCyan); - } - } - - /// Gets the LightGoldenrodYellow default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightGoldenrodYellow, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightGoldenrodYellow { - if (_pens.containsKey(KnownColor.lightGoldenrodYellow)) { - return _pens[KnownColor.lightGoldenrodYellow]!; - } else { - return _getPen(KnownColor.lightGoldenrodYellow); - } - } - - /// Gets the LightGray default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.lightGray, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightGray { - if (_pens.containsKey(KnownColor.lightGray)) { - return _pens[KnownColor.lightGray]!; - } else { - return _getPen(KnownColor.lightGray); - } - } - - /// Gets the LightGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightGreen { - if (_pens.containsKey(KnownColor.lightGreen)) { - return _pens[KnownColor.lightGreen]!; - } else { - return _getPen(KnownColor.lightGreen); - } - } - - /// Gets the LightPink default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.lightPink, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightPink { - if (_pens.containsKey(KnownColor.lightPink)) { - return _pens[KnownColor.lightPink]!; - } else { - return _getPen(KnownColor.lightPink); - } - } - - /// Gets the LightSalmon default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightSalmon { - if (_pens.containsKey(KnownColor.lightSalmon)) { - return _pens[KnownColor.lightSalmon]!; - } else { - return _getPen(KnownColor.lightSalmon); - } - } - - /// Gets the LightSeaGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightSeaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightSeaGreen { - if (_pens.containsKey(KnownColor.lightSeaGreen)) { - return _pens[KnownColor.lightSeaGreen]!; - } else { - return _getPen(KnownColor.lightSeaGreen); - } - } - - /// Gets the LightSkyBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightSkyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightSkyBlue { - if (_pens.containsKey(KnownColor.lightSkyBlue)) { - return _pens[KnownColor.lightSkyBlue]!; - } else { - return _getPen(KnownColor.lightSkyBlue); - } - } - - /// Gets the LightSlateGray default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightSlateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightSlateGray { - if (_pens.containsKey(KnownColor.lightSlateGray)) { - return _pens[KnownColor.lightSlateGray]!; - } else { - return _getPen(KnownColor.lightSlateGray); - } - } - - /// Gets the LightSteelBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightSteelBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightSteelBlue { - if (_pens.containsKey(KnownColor.lightSteelBlue)) { - return _pens[KnownColor.lightSteelBlue]!; - } else { - return _getPen(KnownColor.lightSteelBlue); - } - } - - /// Gets the LightYellow default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.lightYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lightYellow { - if (_pens.containsKey(KnownColor.lightYellow)) { - return _pens[KnownColor.lightYellow]!; - } else { - return _getPen(KnownColor.lightYellow); - } - } - - /// Gets the Lime default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.lime, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get lime { - if (_pens.containsKey(KnownColor.lime)) { - return _pens[KnownColor.lime]!; - } else { - return _getPen(KnownColor.lime); - } - } - - /// Gets the LimeGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.limeGreen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get limeGreen { - if (_pens.containsKey(KnownColor.limeGreen)) { - return _pens[KnownColor.limeGreen]!; - } else { - return _getPen(KnownColor.limeGreen); - } - } - - /// Gets the Linen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.linen, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get linen { - if (_pens.containsKey(KnownColor.linen)) { - return _pens[KnownColor.linen]!; - } else { - return _getPen(KnownColor.linen); - } - } - - /// Gets the Magenta default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.magenta, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get magenta { - if (_pens.containsKey(KnownColor.magenta)) { - return _pens[KnownColor.magenta]!; - } else { - return _getPen(KnownColor.magenta); - } - } - - /// Gets the Maroon default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.maroon, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get maroon { - if (_pens.containsKey(KnownColor.maroon)) { - return _pens[KnownColor.maroon]!; - } else { - return _getPen(KnownColor.maroon); - } - } - - /// Gets the MediumAquamarine default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumAquamarine, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumAquamarine { - if (_pens.containsKey(KnownColor.mediumAquamarine)) { - return _pens[KnownColor.mediumAquamarine]!; - } else { - return _getPen(KnownColor.mediumAquamarine); - } - } - - /// Gets the MediumBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumBlue { - if (_pens.containsKey(KnownColor.mediumBlue)) { - return _pens[KnownColor.mediumBlue]!; - } else { - return _getPen(KnownColor.mediumBlue); - } - } - - /// Gets the MediumOrchid default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumOrchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumOrchid { - if (_pens.containsKey(KnownColor.mediumOrchid)) { - return _pens[KnownColor.mediumOrchid]!; - } else { - return _getPen(KnownColor.mediumOrchid); - } - } - - /// Gets the MediumPurple default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumPurple, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumPurple { - if (_pens.containsKey(KnownColor.mediumPurple)) { - return _pens[KnownColor.mediumPurple]!; - } else { - return _getPen(KnownColor.mediumPurple); - } - } - - /// Gets the MediumSeaGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumSeaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumSeaGreen { - if (_pens.containsKey(KnownColor.mediumSeaGreen)) { - return _pens[KnownColor.mediumSeaGreen]!; - } else { - return _getPen(KnownColor.mediumSeaGreen); - } - } - - /// Gets the MediumSlateBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumSlateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumSlateBlue { - if (_pens.containsKey(KnownColor.mediumSlateBlue)) { - return _pens[KnownColor.mediumSlateBlue]!; - } else { - return _getPen(KnownColor.mediumSlateBlue); - } - } - - /// Gets the MediumSpringGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumSpringGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumSpringGreen { - if (_pens.containsKey(KnownColor.mediumSpringGreen)) { - return _pens[KnownColor.mediumSpringGreen]!; - } else { - return _getPen(KnownColor.mediumSpringGreen); - } - } - - /// Gets the MediumTurquoise default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumTurquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumTurquoise { - if (_pens.containsKey(KnownColor.mediumTurquoise)) { - return _pens[KnownColor.mediumTurquoise]!; - } else { - return _getPen(KnownColor.mediumTurquoise); - } - } - - /// Gets the MediumVioletRed default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.mediumVioletRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mediumVioletRed { - if (_pens.containsKey(KnownColor.mediumVioletRed)) { - return _pens[KnownColor.mediumVioletRed]!; - } else { - return _getPen(KnownColor.mediumVioletRed); - } - } - - /// Gets the MidnightBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.midnightBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get midnightBlue { - if (_pens.containsKey(KnownColor.midnightBlue)) { - return _pens[KnownColor.midnightBlue]!; - } else { - return _getPen(KnownColor.midnightBlue); - } - } - - /// Gets the MintCream default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.mintCream, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mintCream { - if (_pens.containsKey(KnownColor.mintCream)) { - return _pens[KnownColor.mintCream]!; - } else { - return _getPen(KnownColor.mintCream); - } - } - - /// Gets the MistyRose default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.mistyRose, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get mistyRose { - if (_pens.containsKey(KnownColor.mistyRose)) { - return _pens[KnownColor.mistyRose]!; - } else { - return _getPen(KnownColor.mistyRose); - } - } - - /// Gets the Moccasin default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.moccasin, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get moccasin { - if (_pens.containsKey(KnownColor.moccasin)) { - return _pens[KnownColor.moccasin]!; - } else { - return _getPen(KnownColor.moccasin); - } - } - - /// Gets the NavajoWhite default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.navajoWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get navajoWhite { - if (_pens.containsKey(KnownColor.navajoWhite)) { - return _pens[KnownColor.navajoWhite]!; - } else { - return _getPen(KnownColor.navajoWhite); - } - } - - /// Gets the Navy default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.navy, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get navy { - if (_pens.containsKey(KnownColor.navy)) { - return _pens[KnownColor.navy]!; - } else { - return _getPen(KnownColor.navy); - } - } - - /// Gets the OldLace default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.oldLace, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get oldLace { - if (_pens.containsKey(KnownColor.oldLace)) { - return _pens[KnownColor.oldLace]!; - } else { - return _getPen(KnownColor.oldLace); - } - } - - /// Gets the Olive default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.olive, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get olive { - if (_pens.containsKey(KnownColor.olive)) { - return _pens[KnownColor.olive]!; - } else { - return _getPen(KnownColor.olive); - } - } - - /// Gets the OliveDrab default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.oliveDrab, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get oliveDrab { - if (_pens.containsKey(KnownColor.oliveDrab)) { - return _pens[KnownColor.oliveDrab]!; - } else { - return _getPen(KnownColor.oliveDrab); - } - } - - /// Gets the Orange default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.orange, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get orange { - if (_pens.containsKey(KnownColor.orange)) { - return _pens[KnownColor.orange]!; - } else { - return _getPen(KnownColor.orange); - } - } - - /// Gets the OrangeRed default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.orangeRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get orangeRed { - if (_pens.containsKey(KnownColor.orangeRed)) { - return _pens[KnownColor.orangeRed]!; - } else { - return _getPen(KnownColor.orangeRed); - } - } - - /// Gets the Orchid default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.orchid, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get orchid { - if (_pens.containsKey(KnownColor.orchid)) { - return _pens[KnownColor.orchid]!; - } else { - return _getPen(KnownColor.orchid); - } - } - - /// Gets the PaleGoldenrod default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.paleGoldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get paleGoldenrod { - if (_pens.containsKey(KnownColor.paleGoldenrod)) { - return _pens[KnownColor.paleGoldenrod]!; - } else { - return _getPen(KnownColor.paleGoldenrod); - } - } - - /// Gets the PaleGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.paleGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get paleGreen { - if (_pens.containsKey(KnownColor.paleGreen)) { - return _pens[KnownColor.paleGreen]!; - } else { - return _getPen(KnownColor.paleGreen); - } - } - - /// Gets the PaleTurquoise default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.paleTurquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get paleTurquoise { - if (_pens.containsKey(KnownColor.paleTurquoise)) { - return _pens[KnownColor.paleTurquoise]!; - } else { - return _getPen(KnownColor.paleTurquoise); - } - } - - /// Gets the PaleVioletRed default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.paleVioletRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get paleVioletRed { - if (_pens.containsKey(KnownColor.paleVioletRed)) { - return _pens[KnownColor.paleVioletRed]!; - } else { - return _getPen(KnownColor.paleVioletRed); - } - } - - /// Gets the PapayaWhip default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.papayaWhip, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get papayaWhip { - if (_pens.containsKey(KnownColor.papayaWhip)) { - return _pens[KnownColor.papayaWhip]!; - } else { - return _getPen(KnownColor.papayaWhip); - } - } - - /// Gets the PeachPuff default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.peachPuff, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get peachPuff { - if (_pens.containsKey(KnownColor.peachPuff)) { - return _pens[KnownColor.peachPuff]!; - } else { - return _getPen(KnownColor.peachPuff); - } - } - - /// Gets the Peru default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.peru, - /// bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get peru { - if (_pens.containsKey(KnownColor.peru)) { - return _pens[KnownColor.peru]!; - } else { - return _getPen(KnownColor.peru); - } - } - - /// Gets the Pink default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.pink, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get pink { - if (_pens.containsKey(KnownColor.pink)) { - return _pens[KnownColor.pink]!; - } else { - return _getPen(KnownColor.pink); - } - } - - /// Gets the Plum default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.plum, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get plum { - if (_pens.containsKey(KnownColor.plum)) { - return _pens[KnownColor.plum]!; - } else { - return _getPen(KnownColor.plum); - } - } - - /// Gets the PowderBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.powderBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get powderBlue { - if (_pens.containsKey(KnownColor.powderBlue)) { - return _pens[KnownColor.powderBlue]!; - } else { - return _getPen(KnownColor.powderBlue); - } - } - - /// Gets the Purple default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.purple, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get purple { - if (_pens.containsKey(KnownColor.purple)) { - return _pens[KnownColor.purple]!; - } else { - return _getPen(KnownColor.purple); - } - } - - /// Gets the Red default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.red, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get red { - if (_pens.containsKey(KnownColor.red)) { - return _pens[KnownColor.red]!; - } else { - return _getPen(KnownColor.red); - } - } - - /// Gets the RosyBrown default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.rosyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get rosyBrown { - if (_pens.containsKey(KnownColor.rosyBrown)) { - return _pens[KnownColor.rosyBrown]!; - } else { - return _getPen(KnownColor.rosyBrown); - } - } - - /// Gets the RoyalBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.royalBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get royalBlue { - if (_pens.containsKey(KnownColor.royalBlue)) { - return _pens[KnownColor.royalBlue]!; - } else { - return _getPen(KnownColor.royalBlue); - } - } - - /// Gets the SaddleBrown default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.saddleBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get saddleBrown { - if (_pens.containsKey(KnownColor.saddleBrown)) { - return _pens[KnownColor.saddleBrown]!; - } else { - return _getPen(KnownColor.saddleBrown); - } - } - - /// Gets the Salmon default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.salmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get salmon { - if (_pens.containsKey(KnownColor.salmon)) { - return _pens[KnownColor.salmon]!; - } else { - return _getPen(KnownColor.salmon); - } - } - - /// Gets the SandyBrown default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.sandyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get sandyBrown { - if (_pens.containsKey(KnownColor.sandyBrown)) { - return _pens[KnownColor.sandyBrown]!; - } else { - return _getPen(KnownColor.sandyBrown); - } - } - - /// Gets the SeaGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.seaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get seaGreen { - if (_pens.containsKey(KnownColor.seaGreen)) { - return _pens[KnownColor.seaGreen]!; - } else { - return _getPen(KnownColor.seaGreen); - } - } - - /// Gets the SeaShell default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.seaShell, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get seaShell { - if (_pens.containsKey(KnownColor.seaShell)) { - return _pens[KnownColor.seaShell]!; - } else { - return _getPen(KnownColor.seaShell); - } - } - - /// Gets the Sienna default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.sienna, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get sienna { - if (_pens.containsKey(KnownColor.sienna)) { - return _pens[KnownColor.sienna]!; - } else { - return _getPen(KnownColor.sienna); - } - } - - /// Gets the Silver default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.silver, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get silver { - if (_pens.containsKey(KnownColor.silver)) { - return _pens[KnownColor.silver]!; - } else { - return _getPen(KnownColor.silver); - } - } - - /// Gets the SkyBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.skyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get skyBlue { - if (_pens.containsKey(KnownColor.skyBlue)) { - return _pens[KnownColor.skyBlue]!; - } else { - return _getPen(KnownColor.skyBlue); - } - } - - /// Gets the SlateBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.slateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get slateBlue { - if (_pens.containsKey(KnownColor.slateBlue)) { - return _pens[KnownColor.slateBlue]!; - } else { - return _getPen(KnownColor.slateBlue); - } - } - - /// Gets the SlateGray default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.slateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get slateGray { - if (_pens.containsKey(KnownColor.slateGray)) { - return _pens[KnownColor.slateGray]!; - } else { - return _getPen(KnownColor.slateGray); - } - } - - /// Gets the Snow default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.snow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get snow { - if (_pens.containsKey(KnownColor.snow)) { - return _pens[KnownColor.snow]!; - } else { - return _getPen(KnownColor.snow); - } - } - - /// Gets the SpringGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.springGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get springGreen { - if (_pens.containsKey(KnownColor.springGreen)) { - return _pens[KnownColor.springGreen]!; - } else { - return _getPen(KnownColor.springGreen); - } - } - - /// Gets the SteelBlue default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.steelBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get steelBlue { - if (_pens.containsKey(KnownColor.steelBlue)) { - return _pens[KnownColor.steelBlue]!; - } else { - return _getPen(KnownColor.steelBlue); - } - } - - /// Gets the Tan default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.tan, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get tan { - if (_pens.containsKey(KnownColor.tan)) { - return _pens[KnownColor.tan]!; - } else { - return _getPen(KnownColor.tan); - } - } - - /// Gets the Teal default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.teal, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get teal { - if (_pens.containsKey(KnownColor.teal)) { - return _pens[KnownColor.teal]!; - } else { - return _getPen(KnownColor.teal); - } - } - - /// Gets the Thistle default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.thistle, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get thistle { - if (_pens.containsKey(KnownColor.thistle)) { - return _pens[KnownColor.thistle]!; - } else { - return _getPen(KnownColor.thistle); - } - } - - /// Gets the Tomato default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.tomato, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get tomato { - if (_pens.containsKey(KnownColor.tomato)) { - return _pens[KnownColor.tomato]!; - } else { - return _getPen(KnownColor.tomato); - } - } - - /// Gets the Transparent default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.transparent, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get transparent { - if (_pens.containsKey(KnownColor.transparent)) { - return _pens[KnownColor.transparent]!; - } else { - return _getPen(KnownColor.transparent); - } - } - - /// Gets the Turquoise default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.turquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get turquoise { - if (_pens.containsKey(KnownColor.turquoise)) { - return _pens[KnownColor.turquoise]!; - } else { - return _getPen(KnownColor.turquoise); - } - } - - /// Gets the Violet default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.violet, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get violet { - if (_pens.containsKey(KnownColor.violet)) { - return _pens[KnownColor.violet]!; - } else { - return _getPen(KnownColor.violet); - } - } - - /// Gets the Wheat default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.wheat, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get wheat { - if (_pens.containsKey(KnownColor.wheat)) { - return _pens[KnownColor.wheat]!; - } else { - return _getPen(KnownColor.wheat); - } - } - - /// Gets the White default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.white, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get white { - if (_pens.containsKey(KnownColor.white)) { - return _pens[KnownColor.white]!; - } else { - return _getPen(KnownColor.white); - } - } - - /// Gets the WhiteSmoke default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.whiteSmoke, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get whiteSmoke { - if (_pens.containsKey(KnownColor.whiteSmoke)) { - return _pens[KnownColor.whiteSmoke]!; - } else { - return _getPen(KnownColor.whiteSmoke); - } - } - - /// Gets the Yellow default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages - /// .add() - /// .graphics - /// .drawRectangle(pen: PdfPens.yellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get yellow { - if (_pens.containsKey(KnownColor.yellow)) { - return _pens[KnownColor.yellow]!; - } else { - return _getPen(KnownColor.yellow); - } - } - - /// Gets the YellowGreen default pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument doc = PdfDocument(); - /// //Draw rectangle. - /// doc.pages.add().graphics.drawRectangle( - /// pen: PdfPens.yellowGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); - /// //Save the document. - /// List bytes = doc.save(); - /// //Dispose the document. - /// doc.dispose(); - /// ``` - static PdfPen get yellowGreen { - if (_pens.containsKey(KnownColor.yellowGreen)) { - return _pens[KnownColor.yellowGreen]!; - } else { - return _getPen(KnownColor.yellowGreen); - } - } - - static PdfPen _getPen(KnownColor kColor) { - final ColorHelper color = ColorHelper(kColor); - final PdfPen pen = PdfPenHelper.immutable( - PdfColor(color.r, color.g, color.b, color.a), - ); - _pens[kColor] = pen; - return pen; - } - - static void _dispose() { - _pens.clear(); - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfPens] helper -class PdfPensHelper { - /// internal method - static void dispose() { - PdfPens._dispose(); - } -} +import '../drawing/color.dart'; +import 'pdf_color.dart'; +import 'pdf_pen.dart'; + +/// The collection of default pens. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument doc = PdfDocument(); +/// //Draw rectangle. +/// doc.pages +/// .add() +/// .graphics +/// .drawRectangle(pen: PdfPens.black, +/// bounds: Rect.fromLTWH(0, 0, 200, 100)); +/// //Save the document. +/// List bytes = doc.save(); +/// //Dispose the document. +/// doc.dispose(); +/// ``` +class PdfPens { + PdfPens._(); + static final Map _pens = {}; + + /// Gets the AliceBlue pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.aliceBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get aliceBlue { + if (_pens.containsKey(KnownColor.aliceBlue)) { + return _pens[KnownColor.aliceBlue]!; + } else { + return _getPen(KnownColor.aliceBlue); + } + } + + /// Gets the Antique white pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.antiqueWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get antiqueWhite { + if (_pens.containsKey(KnownColor.antiqueWhite)) { + return _pens[KnownColor.antiqueWhite]!; + } else { + return _getPen(KnownColor.antiqueWhite); + } + } + + /// Gets the Aqua default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.aqua, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get aqua { + if (_pens.containsKey(KnownColor.aqua)) { + return _pens[KnownColor.aqua]!; + } else { + return _getPen(KnownColor.aqua); + } + } + + /// Gets the Aquamarine default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.aquamarine, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get aquamarine { + if (_pens.containsKey(KnownColor.aquamarine)) { + return _pens[KnownColor.aquamarine]!; + } else { + return _getPen(KnownColor.aquamarine); + } + } + + /// Gets the Azure default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.azure, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get azure { + if (_pens.containsKey(KnownColor.azure)) { + return _pens[KnownColor.azure]!; + } else { + return _getPen(KnownColor.azure); + } + } + + /// Gets the Beige default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.beige, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get beige { + if (_pens.containsKey(KnownColor.beige)) { + return _pens[KnownColor.beige]!; + } else { + return _getPen(KnownColor.beige); + } + } + + /// Gets the Bisque default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.bisque, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get bisque { + if (_pens.containsKey(KnownColor.bisque)) { + return _pens[KnownColor.bisque]!; + } else { + return _getPen(KnownColor.bisque); + } + } + + /// Gets the Black default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.black, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get black { + if (_pens.containsKey(KnownColor.black)) { + return _pens[KnownColor.black]!; + } else { + return _getPen(KnownColor.black); + } + } + + /// Gets the BlanchedAlmond default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.blanchedAlmond, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get blanchedAlmond { + if (_pens.containsKey(KnownColor.blanchedAlmond)) { + return _pens[KnownColor.blanchedAlmond]!; + } else { + return _getPen(KnownColor.blanchedAlmond); + } + } + + /// Gets the Blue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.blue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get blue { + if (_pens.containsKey(KnownColor.blue)) { + return _pens[KnownColor.blue]!; + } else { + return _getPen(KnownColor.blue); + } + } + + /// Gets the BlueViolet default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.blueViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get blueViolet { + if (_pens.containsKey(KnownColor.blueViolet)) { + return _pens[KnownColor.blueViolet]!; + } else { + return _getPen(KnownColor.blueViolet); + } + } + + /// Gets the Brown default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.brown, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get brown { + if (_pens.containsKey(KnownColor.brown)) { + return _pens[KnownColor.brown]!; + } else { + return _getPen(KnownColor.brown); + } + } + + /// Gets the BurlyWood default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.burlyWood, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get burlyWood { + if (_pens.containsKey(KnownColor.burlyWood)) { + return _pens[KnownColor.burlyWood]!; + } else { + return _getPen(KnownColor.burlyWood); + } + } + + /// Gets the CadetBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.cadetBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get cadetBlue { + if (_pens.containsKey(KnownColor.cadetBlue)) { + return _pens[KnownColor.cadetBlue]!; + } else { + return _getPen(KnownColor.cadetBlue); + } + } + + /// Gets the Chartreuse default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.chartreuse, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get chartreuse { + if (_pens.containsKey(KnownColor.chartreuse)) { + return _pens[KnownColor.chartreuse]!; + } else { + return _getPen(KnownColor.chartreuse); + } + } + + /// Gets the Chocolate default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.chocolate, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get chocolate { + if (_pens.containsKey(KnownColor.chocolate)) { + return _pens[KnownColor.chocolate]!; + } else { + return _getPen(KnownColor.chocolate); + } + } + + /// Gets the Coral default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.coral, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get coral { + if (_pens.containsKey(KnownColor.coral)) { + return _pens[KnownColor.coral]!; + } else { + return _getPen(KnownColor.coral); + } + } + + /// Gets the CornflowerBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.cornflowerBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get cornflowerBlue { + if (_pens.containsKey(KnownColor.cornflowerBlue)) { + return _pens[KnownColor.cornflowerBlue]!; + } else { + return _getPen(KnownColor.cornflowerBlue); + } + } + + /// Gets the Corn silk default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.cornsilk, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get cornsilk { + if (_pens.containsKey(KnownColor.cornsilk)) { + return _pens[KnownColor.cornsilk]!; + } else { + return _getPen(KnownColor.cornsilk); + } + } + + /// Gets the Crimson default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.crimson, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get crimson { + if (_pens.containsKey(KnownColor.crimson)) { + return _pens[KnownColor.crimson]!; + } else { + return _getPen(KnownColor.crimson); + } + } + + /// Gets the Cyan default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.cyan, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get cyan { + if (_pens.containsKey(KnownColor.cyan)) { + return _pens[KnownColor.cyan]!; + } else { + return _getPen(KnownColor.cyan); + } + } + + /// Gets the DarkBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.darkBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkBlue { + if (_pens.containsKey(KnownColor.darkBlue)) { + return _pens[KnownColor.darkBlue]!; + } else { + return _getPen(KnownColor.darkBlue); + } + } + + /// Gets the DarkCyan default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.darkCyan, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkCyan { + if (_pens.containsKey(KnownColor.darkCyan)) { + return _pens[KnownColor.darkCyan]!; + } else { + return _getPen(KnownColor.darkCyan); + } + } + + /// Gets the DarkGoldenrod default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkGoldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkGoldenrod { + if (_pens.containsKey(KnownColor.darkGoldenrod)) { + return _pens[KnownColor.darkGoldenrod]!; + } else { + return _getPen(KnownColor.darkGoldenrod); + } + } + + /// Gets the DarkGray default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.darkGray, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkGray { + if (_pens.containsKey(KnownColor.darkGray)) { + return _pens[KnownColor.darkGray]!; + } else { + return _getPen(KnownColor.darkGray); + } + } + + /// Gets the DarkGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.darkGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkGreen { + if (_pens.containsKey(KnownColor.darkGreen)) { + return _pens[KnownColor.darkGreen]!; + } else { + return _getPen(KnownColor.darkGreen); + } + } + + /// Gets the DarkKhaki default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.darkKhaki, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkKhaki { + if (_pens.containsKey(KnownColor.darkKhaki)) { + return _pens[KnownColor.darkKhaki]!; + } else { + return _getPen(KnownColor.darkKhaki); + } + } + + /// Gets the DarkMagenta default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkMagenta, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkMagenta { + if (_pens.containsKey(KnownColor.darkMagenta)) { + return _pens[KnownColor.darkMagenta]!; + } else { + return _getPen(KnownColor.darkMagenta); + } + } + + /// Gets the DarkOliveGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkOliveGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkOliveGreen { + if (_pens.containsKey(KnownColor.darkOliveGreen)) { + return _pens[KnownColor.darkOliveGreen]!; + } else { + return _getPen(KnownColor.darkOliveGreen); + } + } + + /// Gets the DarkOrange default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkOrange, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkOrange { + if (_pens.containsKey(KnownColor.darkOrange)) { + return _pens[KnownColor.darkOrange]!; + } else { + return _getPen(KnownColor.darkOrange); + } + } + + /// Gets the DarkOrchid default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkOrchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkOrchid { + if (_pens.containsKey(KnownColor.darkOrchid)) { + return _pens[KnownColor.darkOrchid]!; + } else { + return _getPen(KnownColor.darkOrchid); + } + } + + /// Gets the DarkRed default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.darkRed, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkRed { + if (_pens.containsKey(KnownColor.darkRed)) { + return _pens[KnownColor.darkRed]!; + } else { + return _getPen(KnownColor.darkRed); + } + } + + /// Gets the DarkSalmon default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkSalmon { + if (_pens.containsKey(KnownColor.darkSalmon)) { + return _pens[KnownColor.darkSalmon]!; + } else { + return _getPen(KnownColor.darkSalmon); + } + } + + /// Gets the DarkSeaGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkSeaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkSeaGreen { + if (_pens.containsKey(KnownColor.darkSeaGreen)) { + return _pens[KnownColor.darkSeaGreen]!; + } else { + return _getPen(KnownColor.darkSeaGreen); + } + } + + /// Gets the DarkSlateBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkSlateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkSlateBlue { + if (_pens.containsKey(KnownColor.darkSlateBlue)) { + return _pens[KnownColor.darkSlateBlue]!; + } else { + return _getPen(KnownColor.darkSlateBlue); + } + } + + /// Gets the DarkSlateGray default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkSlateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkSlateGray { + if (_pens.containsKey(KnownColor.darkSlateGray)) { + return _pens[KnownColor.darkSlateGray]!; + } else { + return _getPen(KnownColor.darkSlateGray); + } + } + + /// Gets the DarkTurquoise default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkTurquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkTurquoise { + if (_pens.containsKey(KnownColor.darkTurquoise)) { + return _pens[KnownColor.darkTurquoise]!; + } else { + return _getPen(KnownColor.darkTurquoise); + } + } + + /// Gets the DarkViolet default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.darkViolet, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get darkViolet { + if (_pens.containsKey(KnownColor.darkViolet)) { + return _pens[KnownColor.darkViolet]!; + } else { + return _getPen(KnownColor.darkViolet); + } + } + + /// Gets the DeepPink default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.deepPink, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get deepPink { + if (_pens.containsKey(KnownColor.deepPink)) { + return _pens[KnownColor.deepPink]!; + } else { + return _getPen(KnownColor.deepPink); + } + } + + /// Gets the DeepSkyBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.deepSkyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get deepSkyBlue { + if (_pens.containsKey(KnownColor.deepSkyBlue)) { + return _pens[KnownColor.deepSkyBlue]!; + } else { + return _getPen(KnownColor.deepSkyBlue); + } + } + + /// Gets the DimGray default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.dimGray, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get dimGray { + if (_pens.containsKey(KnownColor.dimGray)) { + return _pens[KnownColor.dimGray]!; + } else { + return _getPen(KnownColor.dimGray); + } + } + + /// Gets the DodgerBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.dodgerBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get dodgerBlue { + if (_pens.containsKey(KnownColor.dodgerBlue)) { + return _pens[KnownColor.dodgerBlue]!; + } else { + return _getPen(KnownColor.dodgerBlue); + } + } + + /// Gets the Firebrick default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.firebrick, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get firebrick { + if (_pens.containsKey(KnownColor.firebrick)) { + return _pens[KnownColor.firebrick]!; + } else { + return _getPen(KnownColor.firebrick); + } + } + + /// Gets the FloralWhite default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.floralWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get floralWhite { + if (_pens.containsKey(KnownColor.floralWhite)) { + return _pens[KnownColor.floralWhite]!; + } else { + return _getPen(KnownColor.floralWhite); + } + } + + /// Gets the ForestGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.forestGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get forestGreen { + if (_pens.containsKey(KnownColor.forestGreen)) { + return _pens[KnownColor.forestGreen]!; + } else { + return _getPen(KnownColor.forestGreen); + } + } + + /// Gets the Fuchsia default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.fuchsia, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get fuchsia { + if (_pens.containsKey(KnownColor.fuchsia)) { + return _pens[KnownColor.fuchsia]!; + } else { + return _getPen(KnownColor.fuchsia); + } + } + + /// Gets the Gainsborough default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.gainsboro, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get gainsboro { + if (_pens.containsKey(KnownColor.gainsboro)) { + return _pens[KnownColor.gainsboro]!; + } else { + return _getPen(KnownColor.gainsboro); + } + } + + /// Gets the GhostWhite default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.ghostWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get ghostWhite { + if (_pens.containsKey(KnownColor.ghostWhite)) { + return _pens[KnownColor.ghostWhite]!; + } else { + return _getPen(KnownColor.ghostWhite); + } + } + + /// Gets the Gold default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.gold, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get gold { + if (_pens.containsKey(KnownColor.gold)) { + return _pens[KnownColor.gold]!; + } else { + return _getPen(KnownColor.gold); + } + } + + /// Gets the Goldenrod default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.goldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get goldenrod { + if (_pens.containsKey(KnownColor.goldenrod)) { + return _pens[KnownColor.goldenrod]!; + } else { + return _getPen(KnownColor.goldenrod); + } + } + + /// Gets the Gray default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.gray, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get gray { + if (_pens.containsKey(KnownColor.gray)) { + return _pens[KnownColor.gray]!; + } else { + return _getPen(KnownColor.gray); + } + } + + /// Gets the Green default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.green, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get green { + if (_pens.containsKey(KnownColor.green)) { + return _pens[KnownColor.green]!; + } else { + return _getPen(KnownColor.green); + } + } + + /// Gets the GreenYellow default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.greenYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get greenYellow { + if (_pens.containsKey(KnownColor.greenYellow)) { + return _pens[KnownColor.greenYellow]!; + } else { + return _getPen(KnownColor.greenYellow); + } + } + + /// Gets the Honeydew default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.honeydew, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get honeydew { + if (_pens.containsKey(KnownColor.honeydew)) { + return _pens[KnownColor.honeydew]!; + } else { + return _getPen(KnownColor.honeydew); + } + } + + /// Gets the HotPink default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.hotPink, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get hotPink { + if (_pens.containsKey(KnownColor.hotPink)) { + return _pens[KnownColor.hotPink]!; + } else { + return _getPen(KnownColor.hotPink); + } + } + + /// Gets the IndianRed default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.indianRed, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get indianRed { + if (_pens.containsKey(KnownColor.indianRed)) { + return _pens[KnownColor.indianRed]!; + } else { + return _getPen(KnownColor.indianRed); + } + } + + /// Gets the Indigo default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.indigo, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get indigo { + if (_pens.containsKey(KnownColor.indigo)) { + return _pens[KnownColor.indigo]!; + } else { + return _getPen(KnownColor.indigo); + } + } + + /// Gets the Ivory default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.ivory, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get ivory { + if (_pens.containsKey(KnownColor.ivory)) { + return _pens[KnownColor.ivory]!; + } else { + return _getPen(KnownColor.ivory); + } + } + + /// Gets the Khaki default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.khaki, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get khaki { + if (_pens.containsKey(KnownColor.khaki)) { + return _pens[KnownColor.khaki]!; + } else { + return _getPen(KnownColor.khaki); + } + } + + /// Gets the Lavender default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.lavender, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lavender { + if (_pens.containsKey(KnownColor.lavender)) { + return _pens[KnownColor.lavender]!; + } else { + return _getPen(KnownColor.lavender); + } + } + + /// Gets the LavenderBlush default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lavenderBlush, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lavenderBlush { + if (_pens.containsKey(KnownColor.lavenderBlush)) { + return _pens[KnownColor.lavenderBlush]!; + } else { + return _getPen(KnownColor.lavenderBlush); + } + } + + /// Gets the LawnGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.lawnGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lawnGreen { + if (_pens.containsKey(KnownColor.lawnGreen)) { + return _pens[KnownColor.lawnGreen]!; + } else { + return _getPen(KnownColor.lawnGreen); + } + } + + /// Gets the LemonChiffon default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lemonChiffon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lemonChiffon { + if (_pens.containsKey(KnownColor.lemonChiffon)) { + return _pens[KnownColor.lemonChiffon]!; + } else { + return _getPen(KnownColor.lemonChiffon); + } + } + + /// Gets the LightBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.lightBlue, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightBlue { + if (_pens.containsKey(KnownColor.lightBlue)) { + return _pens[KnownColor.lightBlue]!; + } else { + return _getPen(KnownColor.lightBlue); + } + } + + /// Gets the LightCoral default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightCoral, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightCoral { + if (_pens.containsKey(KnownColor.lightCoral)) { + return _pens[KnownColor.lightCoral]!; + } else { + return _getPen(KnownColor.lightCoral); + } + } + + /// Gets the LightCyan default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.lightCyan, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightCyan { + if (_pens.containsKey(KnownColor.lightCyan)) { + return _pens[KnownColor.lightCyan]!; + } else { + return _getPen(KnownColor.lightCyan); + } + } + + /// Gets the LightGoldenrodYellow default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightGoldenrodYellow, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightGoldenrodYellow { + if (_pens.containsKey(KnownColor.lightGoldenrodYellow)) { + return _pens[KnownColor.lightGoldenrodYellow]!; + } else { + return _getPen(KnownColor.lightGoldenrodYellow); + } + } + + /// Gets the LightGray default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.lightGray, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightGray { + if (_pens.containsKey(KnownColor.lightGray)) { + return _pens[KnownColor.lightGray]!; + } else { + return _getPen(KnownColor.lightGray); + } + } + + /// Gets the LightGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightGreen { + if (_pens.containsKey(KnownColor.lightGreen)) { + return _pens[KnownColor.lightGreen]!; + } else { + return _getPen(KnownColor.lightGreen); + } + } + + /// Gets the LightPink default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.lightPink, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightPink { + if (_pens.containsKey(KnownColor.lightPink)) { + return _pens[KnownColor.lightPink]!; + } else { + return _getPen(KnownColor.lightPink); + } + } + + /// Gets the LightSalmon default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightSalmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightSalmon { + if (_pens.containsKey(KnownColor.lightSalmon)) { + return _pens[KnownColor.lightSalmon]!; + } else { + return _getPen(KnownColor.lightSalmon); + } + } + + /// Gets the LightSeaGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightSeaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightSeaGreen { + if (_pens.containsKey(KnownColor.lightSeaGreen)) { + return _pens[KnownColor.lightSeaGreen]!; + } else { + return _getPen(KnownColor.lightSeaGreen); + } + } + + /// Gets the LightSkyBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightSkyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightSkyBlue { + if (_pens.containsKey(KnownColor.lightSkyBlue)) { + return _pens[KnownColor.lightSkyBlue]!; + } else { + return _getPen(KnownColor.lightSkyBlue); + } + } + + /// Gets the LightSlateGray default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightSlateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightSlateGray { + if (_pens.containsKey(KnownColor.lightSlateGray)) { + return _pens[KnownColor.lightSlateGray]!; + } else { + return _getPen(KnownColor.lightSlateGray); + } + } + + /// Gets the LightSteelBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightSteelBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightSteelBlue { + if (_pens.containsKey(KnownColor.lightSteelBlue)) { + return _pens[KnownColor.lightSteelBlue]!; + } else { + return _getPen(KnownColor.lightSteelBlue); + } + } + + /// Gets the LightYellow default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.lightYellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lightYellow { + if (_pens.containsKey(KnownColor.lightYellow)) { + return _pens[KnownColor.lightYellow]!; + } else { + return _getPen(KnownColor.lightYellow); + } + } + + /// Gets the Lime default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.lime, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get lime { + if (_pens.containsKey(KnownColor.lime)) { + return _pens[KnownColor.lime]!; + } else { + return _getPen(KnownColor.lime); + } + } + + /// Gets the LimeGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.limeGreen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get limeGreen { + if (_pens.containsKey(KnownColor.limeGreen)) { + return _pens[KnownColor.limeGreen]!; + } else { + return _getPen(KnownColor.limeGreen); + } + } + + /// Gets the Linen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.linen, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get linen { + if (_pens.containsKey(KnownColor.linen)) { + return _pens[KnownColor.linen]!; + } else { + return _getPen(KnownColor.linen); + } + } + + /// Gets the Magenta default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.magenta, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get magenta { + if (_pens.containsKey(KnownColor.magenta)) { + return _pens[KnownColor.magenta]!; + } else { + return _getPen(KnownColor.magenta); + } + } + + /// Gets the Maroon default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.maroon, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get maroon { + if (_pens.containsKey(KnownColor.maroon)) { + return _pens[KnownColor.maroon]!; + } else { + return _getPen(KnownColor.maroon); + } + } + + /// Gets the MediumAquamarine default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumAquamarine, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumAquamarine { + if (_pens.containsKey(KnownColor.mediumAquamarine)) { + return _pens[KnownColor.mediumAquamarine]!; + } else { + return _getPen(KnownColor.mediumAquamarine); + } + } + + /// Gets the MediumBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumBlue { + if (_pens.containsKey(KnownColor.mediumBlue)) { + return _pens[KnownColor.mediumBlue]!; + } else { + return _getPen(KnownColor.mediumBlue); + } + } + + /// Gets the MediumOrchid default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumOrchid, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumOrchid { + if (_pens.containsKey(KnownColor.mediumOrchid)) { + return _pens[KnownColor.mediumOrchid]!; + } else { + return _getPen(KnownColor.mediumOrchid); + } + } + + /// Gets the MediumPurple default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumPurple, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumPurple { + if (_pens.containsKey(KnownColor.mediumPurple)) { + return _pens[KnownColor.mediumPurple]!; + } else { + return _getPen(KnownColor.mediumPurple); + } + } + + /// Gets the MediumSeaGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumSeaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumSeaGreen { + if (_pens.containsKey(KnownColor.mediumSeaGreen)) { + return _pens[KnownColor.mediumSeaGreen]!; + } else { + return _getPen(KnownColor.mediumSeaGreen); + } + } + + /// Gets the MediumSlateBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumSlateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumSlateBlue { + if (_pens.containsKey(KnownColor.mediumSlateBlue)) { + return _pens[KnownColor.mediumSlateBlue]!; + } else { + return _getPen(KnownColor.mediumSlateBlue); + } + } + + /// Gets the MediumSpringGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumSpringGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumSpringGreen { + if (_pens.containsKey(KnownColor.mediumSpringGreen)) { + return _pens[KnownColor.mediumSpringGreen]!; + } else { + return _getPen(KnownColor.mediumSpringGreen); + } + } + + /// Gets the MediumTurquoise default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumTurquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumTurquoise { + if (_pens.containsKey(KnownColor.mediumTurquoise)) { + return _pens[KnownColor.mediumTurquoise]!; + } else { + return _getPen(KnownColor.mediumTurquoise); + } + } + + /// Gets the MediumVioletRed default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.mediumVioletRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mediumVioletRed { + if (_pens.containsKey(KnownColor.mediumVioletRed)) { + return _pens[KnownColor.mediumVioletRed]!; + } else { + return _getPen(KnownColor.mediumVioletRed); + } + } + + /// Gets the MidnightBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.midnightBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get midnightBlue { + if (_pens.containsKey(KnownColor.midnightBlue)) { + return _pens[KnownColor.midnightBlue]!; + } else { + return _getPen(KnownColor.midnightBlue); + } + } + + /// Gets the MintCream default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.mintCream, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mintCream { + if (_pens.containsKey(KnownColor.mintCream)) { + return _pens[KnownColor.mintCream]!; + } else { + return _getPen(KnownColor.mintCream); + } + } + + /// Gets the MistyRose default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.mistyRose, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get mistyRose { + if (_pens.containsKey(KnownColor.mistyRose)) { + return _pens[KnownColor.mistyRose]!; + } else { + return _getPen(KnownColor.mistyRose); + } + } + + /// Gets the Moccasin default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.moccasin, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get moccasin { + if (_pens.containsKey(KnownColor.moccasin)) { + return _pens[KnownColor.moccasin]!; + } else { + return _getPen(KnownColor.moccasin); + } + } + + /// Gets the NavajoWhite default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.navajoWhite, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get navajoWhite { + if (_pens.containsKey(KnownColor.navajoWhite)) { + return _pens[KnownColor.navajoWhite]!; + } else { + return _getPen(KnownColor.navajoWhite); + } + } + + /// Gets the Navy default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.navy, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get navy { + if (_pens.containsKey(KnownColor.navy)) { + return _pens[KnownColor.navy]!; + } else { + return _getPen(KnownColor.navy); + } + } + + /// Gets the OldLace default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.oldLace, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get oldLace { + if (_pens.containsKey(KnownColor.oldLace)) { + return _pens[KnownColor.oldLace]!; + } else { + return _getPen(KnownColor.oldLace); + } + } + + /// Gets the Olive default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.olive, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get olive { + if (_pens.containsKey(KnownColor.olive)) { + return _pens[KnownColor.olive]!; + } else { + return _getPen(KnownColor.olive); + } + } + + /// Gets the OliveDrab default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.oliveDrab, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get oliveDrab { + if (_pens.containsKey(KnownColor.oliveDrab)) { + return _pens[KnownColor.oliveDrab]!; + } else { + return _getPen(KnownColor.oliveDrab); + } + } + + /// Gets the Orange default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.orange, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get orange { + if (_pens.containsKey(KnownColor.orange)) { + return _pens[KnownColor.orange]!; + } else { + return _getPen(KnownColor.orange); + } + } + + /// Gets the OrangeRed default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.orangeRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get orangeRed { + if (_pens.containsKey(KnownColor.orangeRed)) { + return _pens[KnownColor.orangeRed]!; + } else { + return _getPen(KnownColor.orangeRed); + } + } + + /// Gets the Orchid default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.orchid, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get orchid { + if (_pens.containsKey(KnownColor.orchid)) { + return _pens[KnownColor.orchid]!; + } else { + return _getPen(KnownColor.orchid); + } + } + + /// Gets the PaleGoldenrod default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.paleGoldenrod, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get paleGoldenrod { + if (_pens.containsKey(KnownColor.paleGoldenrod)) { + return _pens[KnownColor.paleGoldenrod]!; + } else { + return _getPen(KnownColor.paleGoldenrod); + } + } + + /// Gets the PaleGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.paleGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get paleGreen { + if (_pens.containsKey(KnownColor.paleGreen)) { + return _pens[KnownColor.paleGreen]!; + } else { + return _getPen(KnownColor.paleGreen); + } + } + + /// Gets the PaleTurquoise default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.paleTurquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get paleTurquoise { + if (_pens.containsKey(KnownColor.paleTurquoise)) { + return _pens[KnownColor.paleTurquoise]!; + } else { + return _getPen(KnownColor.paleTurquoise); + } + } + + /// Gets the PaleVioletRed default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.paleVioletRed, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get paleVioletRed { + if (_pens.containsKey(KnownColor.paleVioletRed)) { + return _pens[KnownColor.paleVioletRed]!; + } else { + return _getPen(KnownColor.paleVioletRed); + } + } + + /// Gets the PapayaWhip default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.papayaWhip, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get papayaWhip { + if (_pens.containsKey(KnownColor.papayaWhip)) { + return _pens[KnownColor.papayaWhip]!; + } else { + return _getPen(KnownColor.papayaWhip); + } + } + + /// Gets the PeachPuff default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.peachPuff, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get peachPuff { + if (_pens.containsKey(KnownColor.peachPuff)) { + return _pens[KnownColor.peachPuff]!; + } else { + return _getPen(KnownColor.peachPuff); + } + } + + /// Gets the Peru default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.peru, + /// bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get peru { + if (_pens.containsKey(KnownColor.peru)) { + return _pens[KnownColor.peru]!; + } else { + return _getPen(KnownColor.peru); + } + } + + /// Gets the Pink default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.pink, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get pink { + if (_pens.containsKey(KnownColor.pink)) { + return _pens[KnownColor.pink]!; + } else { + return _getPen(KnownColor.pink); + } + } + + /// Gets the Plum default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.plum, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get plum { + if (_pens.containsKey(KnownColor.plum)) { + return _pens[KnownColor.plum]!; + } else { + return _getPen(KnownColor.plum); + } + } + + /// Gets the PowderBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.powderBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get powderBlue { + if (_pens.containsKey(KnownColor.powderBlue)) { + return _pens[KnownColor.powderBlue]!; + } else { + return _getPen(KnownColor.powderBlue); + } + } + + /// Gets the Purple default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.purple, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get purple { + if (_pens.containsKey(KnownColor.purple)) { + return _pens[KnownColor.purple]!; + } else { + return _getPen(KnownColor.purple); + } + } + + /// Gets the Red default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.red, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get red { + if (_pens.containsKey(KnownColor.red)) { + return _pens[KnownColor.red]!; + } else { + return _getPen(KnownColor.red); + } + } + + /// Gets the RosyBrown default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.rosyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get rosyBrown { + if (_pens.containsKey(KnownColor.rosyBrown)) { + return _pens[KnownColor.rosyBrown]!; + } else { + return _getPen(KnownColor.rosyBrown); + } + } + + /// Gets the RoyalBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.royalBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get royalBlue { + if (_pens.containsKey(KnownColor.royalBlue)) { + return _pens[KnownColor.royalBlue]!; + } else { + return _getPen(KnownColor.royalBlue); + } + } + + /// Gets the SaddleBrown default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.saddleBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get saddleBrown { + if (_pens.containsKey(KnownColor.saddleBrown)) { + return _pens[KnownColor.saddleBrown]!; + } else { + return _getPen(KnownColor.saddleBrown); + } + } + + /// Gets the Salmon default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.salmon, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get salmon { + if (_pens.containsKey(KnownColor.salmon)) { + return _pens[KnownColor.salmon]!; + } else { + return _getPen(KnownColor.salmon); + } + } + + /// Gets the SandyBrown default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.sandyBrown, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get sandyBrown { + if (_pens.containsKey(KnownColor.sandyBrown)) { + return _pens[KnownColor.sandyBrown]!; + } else { + return _getPen(KnownColor.sandyBrown); + } + } + + /// Gets the SeaGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.seaGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get seaGreen { + if (_pens.containsKey(KnownColor.seaGreen)) { + return _pens[KnownColor.seaGreen]!; + } else { + return _getPen(KnownColor.seaGreen); + } + } + + /// Gets the SeaShell default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.seaShell, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get seaShell { + if (_pens.containsKey(KnownColor.seaShell)) { + return _pens[KnownColor.seaShell]!; + } else { + return _getPen(KnownColor.seaShell); + } + } + + /// Gets the Sienna default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.sienna, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get sienna { + if (_pens.containsKey(KnownColor.sienna)) { + return _pens[KnownColor.sienna]!; + } else { + return _getPen(KnownColor.sienna); + } + } + + /// Gets the Silver default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.silver, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get silver { + if (_pens.containsKey(KnownColor.silver)) { + return _pens[KnownColor.silver]!; + } else { + return _getPen(KnownColor.silver); + } + } + + /// Gets the SkyBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.skyBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get skyBlue { + if (_pens.containsKey(KnownColor.skyBlue)) { + return _pens[KnownColor.skyBlue]!; + } else { + return _getPen(KnownColor.skyBlue); + } + } + + /// Gets the SlateBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.slateBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get slateBlue { + if (_pens.containsKey(KnownColor.slateBlue)) { + return _pens[KnownColor.slateBlue]!; + } else { + return _getPen(KnownColor.slateBlue); + } + } + + /// Gets the SlateGray default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.slateGray, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get slateGray { + if (_pens.containsKey(KnownColor.slateGray)) { + return _pens[KnownColor.slateGray]!; + } else { + return _getPen(KnownColor.slateGray); + } + } + + /// Gets the Snow default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.snow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get snow { + if (_pens.containsKey(KnownColor.snow)) { + return _pens[KnownColor.snow]!; + } else { + return _getPen(KnownColor.snow); + } + } + + /// Gets the SpringGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.springGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get springGreen { + if (_pens.containsKey(KnownColor.springGreen)) { + return _pens[KnownColor.springGreen]!; + } else { + return _getPen(KnownColor.springGreen); + } + } + + /// Gets the SteelBlue default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.steelBlue, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get steelBlue { + if (_pens.containsKey(KnownColor.steelBlue)) { + return _pens[KnownColor.steelBlue]!; + } else { + return _getPen(KnownColor.steelBlue); + } + } + + /// Gets the Tan default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.tan, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get tan { + if (_pens.containsKey(KnownColor.tan)) { + return _pens[KnownColor.tan]!; + } else { + return _getPen(KnownColor.tan); + } + } + + /// Gets the Teal default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.teal, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get teal { + if (_pens.containsKey(KnownColor.teal)) { + return _pens[KnownColor.teal]!; + } else { + return _getPen(KnownColor.teal); + } + } + + /// Gets the Thistle default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.thistle, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get thistle { + if (_pens.containsKey(KnownColor.thistle)) { + return _pens[KnownColor.thistle]!; + } else { + return _getPen(KnownColor.thistle); + } + } + + /// Gets the Tomato default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.tomato, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get tomato { + if (_pens.containsKey(KnownColor.tomato)) { + return _pens[KnownColor.tomato]!; + } else { + return _getPen(KnownColor.tomato); + } + } + + /// Gets the Transparent default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.transparent, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get transparent { + if (_pens.containsKey(KnownColor.transparent)) { + return _pens[KnownColor.transparent]!; + } else { + return _getPen(KnownColor.transparent); + } + } + + /// Gets the Turquoise default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.turquoise, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get turquoise { + if (_pens.containsKey(KnownColor.turquoise)) { + return _pens[KnownColor.turquoise]!; + } else { + return _getPen(KnownColor.turquoise); + } + } + + /// Gets the Violet default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.violet, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get violet { + if (_pens.containsKey(KnownColor.violet)) { + return _pens[KnownColor.violet]!; + } else { + return _getPen(KnownColor.violet); + } + } + + /// Gets the Wheat default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.wheat, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get wheat { + if (_pens.containsKey(KnownColor.wheat)) { + return _pens[KnownColor.wheat]!; + } else { + return _getPen(KnownColor.wheat); + } + } + + /// Gets the White default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.white, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get white { + if (_pens.containsKey(KnownColor.white)) { + return _pens[KnownColor.white]!; + } else { + return _getPen(KnownColor.white); + } + } + + /// Gets the WhiteSmoke default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.whiteSmoke, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get whiteSmoke { + if (_pens.containsKey(KnownColor.whiteSmoke)) { + return _pens[KnownColor.whiteSmoke]!; + } else { + return _getPen(KnownColor.whiteSmoke); + } + } + + /// Gets the Yellow default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages + /// .add() + /// .graphics + /// .drawRectangle(pen: PdfPens.yellow, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get yellow { + if (_pens.containsKey(KnownColor.yellow)) { + return _pens[KnownColor.yellow]!; + } else { + return _getPen(KnownColor.yellow); + } + } + + /// Gets the YellowGreen default pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument doc = PdfDocument(); + /// //Draw rectangle. + /// doc.pages.add().graphics.drawRectangle( + /// pen: PdfPens.yellowGreen, bounds: Rect.fromLTWH(0, 0, 200, 100)); + /// //Save the document. + /// List bytes = doc.save(); + /// //Dispose the document. + /// doc.dispose(); + /// ``` + static PdfPen get yellowGreen { + if (_pens.containsKey(KnownColor.yellowGreen)) { + return _pens[KnownColor.yellowGreen]!; + } else { + return _getPen(KnownColor.yellowGreen); + } + } + + static PdfPen _getPen(KnownColor kColor) { + final ColorHelper color = ColorHelper(kColor); + final PdfPen pen = PdfPenHelper.immutable( + PdfColor(color.r, color.g, color.b, color.a), + ); + _pens[kColor] = pen; + return pen; + } + + static void _dispose() { + _pens.clear(); + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfPens] helper +class PdfPensHelper { + /// internal method + static void dispose() { + PdfPens._dispose(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_resources.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_resources.dart index 9054a6838..2542b7ee4 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_resources.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_resources.dart @@ -1,172 +1,172 @@ -import 'dart:math'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'figures/pdf_template.dart'; -import 'fonts/pdf_font.dart'; -import 'images/pdf_image.dart'; -import 'pdf_transparency.dart'; - -/// internal class -class PdfResources extends PdfDictionary { - //Constructor - /// Initializes a new instance of the [PdfResources] class. - PdfResources([super.baseDictionary]); - - //Fields - Map? _resourceNames; - - /// internal field - final PdfDictionary properties = PdfDictionary(); - - //Properties - Map? get _names => getNames(); - - //Implementation - /// internal method - void requireProcset(String procSetName) { - IPdfPrimitive? primitive = this[PdfDictionaryProperties.procSet]; - PdfArray? procSets; - if (primitive != null) { - if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfArray) { - procSets = primitive; - } - } else if (primitive is PdfArray) { - procSets = primitive; - } - } - if (procSets == null) { - procSets = PdfArray(); - this[PdfDictionaryProperties.procSet] = procSets; - } - final PdfName name = PdfName(procSetName); - if (!procSets.contains(name)) { - procSets.add(name); - } - } - - /// internal method - PdfName getName(IPdfWrapper resource) { - final IPdfPrimitive? primitive = IPdfWrapper.getElement(resource); - PdfName? name; - if (_names!.containsKey(primitive)) { - name = _names![primitive]; - } - if (name == null) { - final String sName = globallyUniqueIdentifier; - name = PdfName(sName); - _names![primitive] = name; - if (resource is PdfFont || - resource is PdfTemplate || - resource is PdfImage || - resource is PdfTransparency) { - add(resource, name); - } - } - return name; - } - - /// internal method - void add(IPdfWrapper? resource, PdfName name) { - if (resource is PdfFont) { - PdfDictionary? dictionary; - final IPdfPrimitive? fonts = this[PdfName(PdfDictionaryProperties.font)]; - if (fonts != null) { - if (fonts is PdfDictionary) { - dictionary = fonts; - } else if (fonts is PdfReferenceHolder) { - dictionary = PdfCrossTable.dereference(fonts) as PdfDictionary?; - } - } else { - dictionary = PdfDictionary(); - this[PdfName(PdfDictionaryProperties.font)] = dictionary; - } - dictionary![name] = PdfReferenceHolder(IPdfWrapper.getElement(resource)); - } else if (resource is PdfTransparency) { - final IPdfPrimitive? savable = IPdfWrapper.getElement(resource); - if (savable != null) { - PdfDictionary? transDic; - if (containsKey(PdfDictionaryProperties.extGState)) { - final IPdfPrimitive? primitive = - this[PdfDictionaryProperties.extGState]; - if (primitive is PdfDictionary) { - transDic = primitive; - } else if (primitive is PdfReferenceHolder) { - final PdfReferenceHolder holder = primitive; - transDic = holder.object as PdfDictionary?; - } - } - if (transDic == null) { - transDic = PdfDictionary(); - this[PdfDictionaryProperties.extGState] = transDic; - } - transDic[name] = PdfReferenceHolder(savable); - } - } else { - PdfDictionary? xObjects; - final PdfName xobjectName = PdfName(PdfDictionaryProperties.xObject); - if (this[xobjectName] is PdfReferenceHolder) { - xObjects = - (this[xobjectName] as PdfReferenceHolder?)?.object - as PdfDictionary?; - } else if (this[xobjectName] is PdfDictionary) { - xObjects = this[xobjectName] as PdfDictionary?; - } - if (xObjects == null) { - xObjects = PdfDictionary(); - this[xobjectName] = xObjects; - } - xObjects[name] = PdfReferenceHolder(IPdfWrapper.getElement(resource!)); - } - } - - /// internal method - Map? getNames() { - _resourceNames ??= {}; - final IPdfPrimitive? fonts = this[PdfDictionaryProperties.font]; - if (fonts != null) { - PdfDictionary? dictionary; - if (fonts is PdfDictionary) { - dictionary = fonts; - } else if (fonts is PdfReferenceHolder) { - dictionary = PdfCrossTable.dereference(fonts) as PdfDictionary?; - } - if (dictionary != null) { - dictionary.items!.forEach( - (PdfName? name, IPdfPrimitive? value) => _addName(name, value), - ); - } - } - return _resourceNames; - } - - void _addName(PdfName? name, IPdfPrimitive? value) { - final IPdfPrimitive? primitive = PdfCrossTable.dereference(value); - if (!_resourceNames!.containsValue(name)) { - _resourceNames![primitive] = name; - } - } - - /// internal property - static String get globallyUniqueIdentifier { - const String format = 'aaaaaaaa-aaaa-4aaa-baaa-aaaaaaaaaaaa'; - String result = ''; - for (int i = 0; i < format.length; i++) { - if (format[i] == 'a') { - result += Random().nextInt(15).toRadixString(16); - } else if (format[i] == 'b') { - result += (Random().nextInt(15) & 0x3 | 0x8).toRadixString(16); - } else { - result += format[i]; - } - } - return result; - } -} +import 'dart:math'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'figures/pdf_template.dart'; +import 'fonts/pdf_font.dart'; +import 'images/pdf_image.dart'; +import 'pdf_transparency.dart'; + +/// internal class +class PdfResources extends PdfDictionary { + //Constructor + /// Initializes a new instance of the [PdfResources] class. + PdfResources([super.baseDictionary]); + + //Fields + Map? _resourceNames; + + /// internal field + final PdfDictionary properties = PdfDictionary(); + + //Properties + Map? get _names => getNames(); + + //Implementation + /// internal method + void requireProcset(String procSetName) { + IPdfPrimitive? primitive = this[PdfDictionaryProperties.procSet]; + PdfArray? procSets; + if (primitive != null) { + if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfArray) { + procSets = primitive; + } + } else if (primitive is PdfArray) { + procSets = primitive; + } + } + if (procSets == null) { + procSets = PdfArray(); + this[PdfDictionaryProperties.procSet] = procSets; + } + final PdfName name = PdfName(procSetName); + if (!procSets.contains(name)) { + procSets.add(name); + } + } + + /// internal method + PdfName getName(IPdfWrapper resource) { + final IPdfPrimitive? primitive = IPdfWrapper.getElement(resource); + PdfName? name; + if (_names!.containsKey(primitive)) { + name = _names![primitive]; + } + if (name == null) { + final String sName = globallyUniqueIdentifier; + name = PdfName(sName); + _names![primitive] = name; + if (resource is PdfFont || + resource is PdfTemplate || + resource is PdfImage || + resource is PdfTransparency) { + add(resource, name); + } + } + return name; + } + + /// internal method + void add(IPdfWrapper? resource, PdfName name) { + if (resource is PdfFont) { + PdfDictionary? dictionary; + final IPdfPrimitive? fonts = this[PdfName(PdfDictionaryProperties.font)]; + if (fonts != null) { + if (fonts is PdfDictionary) { + dictionary = fonts; + } else if (fonts is PdfReferenceHolder) { + dictionary = PdfCrossTable.dereference(fonts) as PdfDictionary?; + } + } else { + dictionary = PdfDictionary(); + this[PdfName(PdfDictionaryProperties.font)] = dictionary; + } + dictionary![name] = PdfReferenceHolder(IPdfWrapper.getElement(resource)); + } else if (resource is PdfTransparency) { + final IPdfPrimitive? savable = IPdfWrapper.getElement(resource); + if (savable != null) { + PdfDictionary? transDic; + if (containsKey(PdfDictionaryProperties.extGState)) { + final IPdfPrimitive? primitive = + this[PdfDictionaryProperties.extGState]; + if (primitive is PdfDictionary) { + transDic = primitive; + } else if (primitive is PdfReferenceHolder) { + final PdfReferenceHolder holder = primitive; + transDic = holder.object as PdfDictionary?; + } + } + if (transDic == null) { + transDic = PdfDictionary(); + this[PdfDictionaryProperties.extGState] = transDic; + } + transDic[name] = PdfReferenceHolder(savable); + } + } else { + PdfDictionary? xObjects; + final PdfName xobjectName = PdfName(PdfDictionaryProperties.xObject); + if (this[xobjectName] is PdfReferenceHolder) { + xObjects = + (this[xobjectName] as PdfReferenceHolder?)?.object + as PdfDictionary?; + } else if (this[xobjectName] is PdfDictionary) { + xObjects = this[xobjectName] as PdfDictionary?; + } + if (xObjects == null) { + xObjects = PdfDictionary(); + this[xobjectName] = xObjects; + } + xObjects[name] = PdfReferenceHolder(IPdfWrapper.getElement(resource!)); + } + } + + /// internal method + Map? getNames() { + _resourceNames ??= {}; + final IPdfPrimitive? fonts = this[PdfDictionaryProperties.font]; + if (fonts != null) { + PdfDictionary? dictionary; + if (fonts is PdfDictionary) { + dictionary = fonts; + } else if (fonts is PdfReferenceHolder) { + dictionary = PdfCrossTable.dereference(fonts) as PdfDictionary?; + } + if (dictionary != null) { + dictionary.items!.forEach( + (PdfName? name, IPdfPrimitive? value) => _addName(name, value), + ); + } + } + return _resourceNames; + } + + void _addName(PdfName? name, IPdfPrimitive? value) { + final IPdfPrimitive? primitive = PdfCrossTable.dereference(value); + if (!_resourceNames!.containsValue(name)) { + _resourceNames![primitive] = name; + } + } + + /// internal property + static String get globallyUniqueIdentifier { + const String format = 'aaaaaaaa-aaaa-4aaa-baaa-aaaaaaaaaaaa'; + String result = ''; + for (int i = 0; i < format.length; i++) { + if (format[i] == 'a') { + result += Random().nextInt(15).toRadixString(16); + } else if (format[i] == 'b') { + result += (Random().nextInt(15) & 0x3 | 0x8).toRadixString(16); + } else { + result += format[i]; + } + } + return result; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transformation_matrix.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transformation_matrix.dart index ab629a1d3..9d4f9a638 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transformation_matrix.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transformation_matrix.dart @@ -1,134 +1,134 @@ -import 'dart:math'; -import '../drawing/drawing.dart'; - -/// Class for representing Root transformation matrix. -class PdfTransformationMatrix { - //Constructor - ///Initializes a new instance of the [PdfTransformationMatrix] class as the - PdfTransformationMatrix() { - matrix = Matrix([1, 0, 0, 1, 0, 0]); - } - - //Fields - /// internal field - late Matrix matrix; - - //Implementation - /// internal method - void translate(double offsetX, double offsetY) { - matrix.translate(offsetX, offsetY); - } - - /// internal method - void scale(double scaleX, double scaleY) { - matrix.scale(scaleX, scaleY); - } - - /// internal method - void multiply(PdfTransformationMatrix matrix) { - this.matrix.multiply(matrix.matrix); - } - - /// internal method - void rotate(double angle) { - angle = double.parse( - (angle * 3.1415926535897931 / 180).toStringAsExponential(9), - ); - matrix.elements[0] = cos(angle); - matrix.elements[1] = sin(angle); - matrix.elements[2] = -sin(angle); - matrix.elements[3] = cos(angle); - } - - /// internal method - void skew(double angleX, double angleY) { - matrix.multiply( - Matrix([ - 1, - tan((pi / 180) * angleX), - tan((pi / 180) * angleY), - 1, - 0, - 0, - ]), - ); - } - - /// internal method - String getString() { - String builder = ''; - const String whitespace = ' '; - for (int i = 0; i < matrix.elements.length; i++) { - String value = matrix.elements[i].toStringAsFixed(2); - if (value.endsWith('.00')) { - if (value.length == 3) { - value = '0'; - } else { - value = value.substring(0, value.length - 3); - } - } - builder += value + whitespace; - } - return builder; - } -} - -/// Encapsulates a 3-by-3 affine matrix that represents a geometric transform. -class Matrix { - // Constructor - /// Initializes a new instance of the [Matrix] class as the - Matrix(this.elements); - - //Fields - /// internal field - late List elements; - - // Properties - double? get _offsetX => elements[4]; - double? get _offsetY => elements[5]; - - // Implementation - /// internal field - void translate(double offsetX, double offsetY) { - elements[4] = offsetX; - elements[5] = offsetY; - } - - // ignore: unused_element - /// internal method - PdfPoint transform(PdfPoint point) { - final double x = point.x; - final double y = point.y; - final double x2 = x * elements[0] + y * elements[2] + _offsetX!; - final double y2 = x * elements[1] + y * elements[3] + _offsetY!; - return PdfPoint(x2, y2); - } - - /// internal method - void scale(double scaleX, double scaleY) { - elements[0] = scaleX; - elements[3] = scaleY; - } - - /// internal method - void multiply(Matrix matrix) { - final List tempMatrix = List.filled(6, 0, growable: true); - tempMatrix[0] = - (elements[0] * matrix.elements[0]) + (elements[1] * matrix.elements[2]); - tempMatrix[1] = - (elements[0] * matrix.elements[1]) + (elements[1] * matrix.elements[3]); - tempMatrix[2] = - (elements[2] * matrix.elements[0]) + (elements[3] * matrix.elements[2]); - tempMatrix[3] = - (elements[2] * matrix.elements[1]) + (elements[3] * matrix.elements[3]); - tempMatrix[4] = - (_offsetX! * matrix.elements[0]) + - (_offsetY! * matrix.elements[2] + matrix._offsetX!); - tempMatrix[5] = - (_offsetX! * matrix.elements[1]) + - (_offsetY! * matrix.elements[3] + matrix._offsetY!); - for (int i = 0; i < tempMatrix.length; i++) { - elements[i] = tempMatrix[i]; - } - } -} +import 'dart:math'; +import '../drawing/drawing.dart'; + +/// Class for representing Root transformation matrix. +class PdfTransformationMatrix { + //Constructor + ///Initializes a new instance of the [PdfTransformationMatrix] class as the + PdfTransformationMatrix() { + matrix = Matrix([1, 0, 0, 1, 0, 0]); + } + + //Fields + /// internal field + late Matrix matrix; + + //Implementation + /// internal method + void translate(double offsetX, double offsetY) { + matrix.translate(offsetX, offsetY); + } + + /// internal method + void scale(double scaleX, double scaleY) { + matrix.scale(scaleX, scaleY); + } + + /// internal method + void multiply(PdfTransformationMatrix matrix) { + this.matrix.multiply(matrix.matrix); + } + + /// internal method + void rotate(double angle) { + angle = double.parse( + (angle * 3.1415926535897931 / 180).toStringAsExponential(9), + ); + matrix.elements[0] = cos(angle); + matrix.elements[1] = sin(angle); + matrix.elements[2] = -sin(angle); + matrix.elements[3] = cos(angle); + } + + /// internal method + void skew(double angleX, double angleY) { + matrix.multiply( + Matrix([ + 1, + tan((pi / 180) * angleX), + tan((pi / 180) * angleY), + 1, + 0, + 0, + ]), + ); + } + + /// internal method + String getString() { + String builder = ''; + const String whitespace = ' '; + for (int i = 0; i < matrix.elements.length; i++) { + String value = matrix.elements[i].toStringAsFixed(2); + if (value.endsWith('.00')) { + if (value.length == 3) { + value = '0'; + } else { + value = value.substring(0, value.length - 3); + } + } + builder += value + whitespace; + } + return builder; + } +} + +/// Encapsulates a 3-by-3 affine matrix that represents a geometric transform. +class Matrix { + // Constructor + /// Initializes a new instance of the [Matrix] class as the + Matrix(this.elements); + + //Fields + /// internal field + late List elements; + + // Properties + double? get _offsetX => elements[4]; + double? get _offsetY => elements[5]; + + // Implementation + /// internal field + void translate(double offsetX, double offsetY) { + elements[4] = offsetX; + elements[5] = offsetY; + } + + // ignore: unused_element + /// internal method + PdfPoint transform(PdfPoint point) { + final double x = point.x; + final double y = point.y; + final double x2 = x * elements[0] + y * elements[2] + _offsetX!; + final double y2 = x * elements[1] + y * elements[3] + _offsetY!; + return PdfPoint(x2, y2); + } + + /// internal method + void scale(double scaleX, double scaleY) { + elements[0] = scaleX; + elements[3] = scaleY; + } + + /// internal method + void multiply(Matrix matrix) { + final List tempMatrix = List.filled(6, 0, growable: true); + tempMatrix[0] = + (elements[0] * matrix.elements[0]) + (elements[1] * matrix.elements[2]); + tempMatrix[1] = + (elements[0] * matrix.elements[1]) + (elements[1] * matrix.elements[3]); + tempMatrix[2] = + (elements[2] * matrix.elements[0]) + (elements[3] * matrix.elements[2]); + tempMatrix[3] = + (elements[2] * matrix.elements[1]) + (elements[3] * matrix.elements[3]); + tempMatrix[4] = + (_offsetX! * matrix.elements[0]) + + (_offsetY! * matrix.elements[2] + matrix._offsetX!); + tempMatrix[5] = + (_offsetX! * matrix.elements[1]) + + (_offsetY! * matrix.elements[3] + matrix._offsetY!); + for (int i = 0; i < tempMatrix.length; i++) { + elements[i] = tempMatrix[i]; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transparency.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transparency.dart index 087cec332..76b19e91a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transparency.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/graphics/pdf_transparency.dart @@ -1,111 +1,111 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import 'enums.dart'; - -/// internal class -class PdfTransparency implements IPdfWrapper { - //Constructor - /// internal constructor - PdfTransparency( - double stroke, - double fill, - PdfBlendMode mode, { - bool conformance = false, - }) { - dictionary = PdfDictionary(); - if (stroke < 0) { - throw ArgumentError.value( - stroke, - 'stroke', - 'The value cannot be less then zero.', - ); - } - if (fill < 0) { - throw ArgumentError.value( - fill, - 'fill', - 'The value cannot be less then zero.', - ); - } - //NOTE : This is needed to attain PDF/A conformance. Since PDF/A1B - //does not support transparency key. - if (conformance) { - stroke = 1; - fill = 1; - mode = (mode != PdfBlendMode.normal) ? PdfBlendMode.normal : mode; - } - dictionary![PdfDictionaryProperties.stroke] = PdfNumber(stroke); - dictionary![PdfDictionaryProperties.fill] = PdfNumber(fill); - dictionary![PdfDictionaryProperties.bm] = PdfName(_getBlendMode(mode)); - } - - //Fields - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - //Properties - /// internal property - double? get stroke => _getNumber(PdfDictionaryProperties.stroke); - - /// internal property - double? get fill => _getNumber(PdfDictionaryProperties.fill); - - //Implementation - double? _getNumber(String keyName) { - double? result = 0; - if (dictionary!.containsKey(keyName) && dictionary![keyName] is PdfNumber) { - final PdfNumber numb = dictionary![keyName]! as PdfNumber; - result = numb.value as double?; - } - return result; - } - - String _getBlendMode(PdfBlendMode mode) { - switch (mode) { - case PdfBlendMode.multiply: - return 'Multiply'; - case PdfBlendMode.screen: - return 'Screen'; - case PdfBlendMode.overlay: - return 'Overlay'; - case PdfBlendMode.darken: - return 'Darken'; - case PdfBlendMode.lighten: - return 'Lighten'; - case PdfBlendMode.colorDodge: - return 'ColorDodge'; - case PdfBlendMode.colorBurn: - return 'ColorBurn'; - case PdfBlendMode.hardLight: - return 'HardLight'; - case PdfBlendMode.softLight: - return 'SoftLight'; - case PdfBlendMode.difference: - return 'Difference'; - case PdfBlendMode.exclusion: - return 'Exclusion'; - case PdfBlendMode.hue: - return 'Hue'; - case PdfBlendMode.saturation: - return 'Saturation'; - case PdfBlendMode.color: - return 'Color'; - case PdfBlendMode.luminosity: - return 'Luminosity'; - case PdfBlendMode.normal: - return 'Normal'; - } - } - - /// internal property - IPdfPrimitive? get element => dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import 'enums.dart'; + +/// internal class +class PdfTransparency implements IPdfWrapper { + //Constructor + /// internal constructor + PdfTransparency( + double stroke, + double fill, + PdfBlendMode mode, { + bool conformance = false, + }) { + dictionary = PdfDictionary(); + if (stroke < 0) { + throw ArgumentError.value( + stroke, + 'stroke', + 'The value cannot be less then zero.', + ); + } + if (fill < 0) { + throw ArgumentError.value( + fill, + 'fill', + 'The value cannot be less then zero.', + ); + } + //NOTE : This is needed to attain PDF/A conformance. Since PDF/A1B + //does not support transparency key. + if (conformance) { + stroke = 1; + fill = 1; + mode = (mode != PdfBlendMode.normal) ? PdfBlendMode.normal : mode; + } + dictionary![PdfDictionaryProperties.stroke] = PdfNumber(stroke); + dictionary![PdfDictionaryProperties.fill] = PdfNumber(fill); + dictionary![PdfDictionaryProperties.bm] = PdfName(_getBlendMode(mode)); + } + + //Fields + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + //Properties + /// internal property + double? get stroke => _getNumber(PdfDictionaryProperties.stroke); + + /// internal property + double? get fill => _getNumber(PdfDictionaryProperties.fill); + + //Implementation + double? _getNumber(String keyName) { + double? result = 0; + if (dictionary!.containsKey(keyName) && dictionary![keyName] is PdfNumber) { + final PdfNumber numb = dictionary![keyName]! as PdfNumber; + result = numb.value as double?; + } + return result; + } + + String _getBlendMode(PdfBlendMode mode) { + switch (mode) { + case PdfBlendMode.multiply: + return 'Multiply'; + case PdfBlendMode.screen: + return 'Screen'; + case PdfBlendMode.overlay: + return 'Overlay'; + case PdfBlendMode.darken: + return 'Darken'; + case PdfBlendMode.lighten: + return 'Lighten'; + case PdfBlendMode.colorDodge: + return 'ColorDodge'; + case PdfBlendMode.colorBurn: + return 'ColorBurn'; + case PdfBlendMode.hardLight: + return 'HardLight'; + case PdfBlendMode.softLight: + return 'SoftLight'; + case PdfBlendMode.difference: + return 'Difference'; + case PdfBlendMode.exclusion: + return 'Exclusion'; + case PdfBlendMode.hue: + return 'Hue'; + case PdfBlendMode.saturation: + return 'Saturation'; + case PdfBlendMode.color: + return 'Color'; + case PdfBlendMode.luminosity: + return 'Luminosity'; + case PdfBlendMode.normal: + return 'Normal'; + } + } + + /// internal property + IPdfPrimitive? get element => dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/big_endian_writer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/big_endian_writer.dart index b3397f55c..3de5ef878 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/big_endian_writer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/big_endian_writer.dart @@ -1,97 +1,97 @@ -/// internal class -class BigEndianWriter { - //Constructor - /// internal constructor - BigEndianWriter(int capacity) { - _bufferLength = capacity; - _buffer = List.filled(capacity, 0, growable: true); - for (int i = 0; i < capacity; i++) { - _buffer![i] = 0; - } - } - - //Fields - late int _bufferLength; - List? _buffer; - int? _internalPosition; - - //Properties - /// internal property - List? get data { - if (_buffer!.length < _bufferLength) { - final int length = _bufferLength - _buffer!.length; - for (int i = 0; i < length; i++) { - _buffer!.add(0); - } - } - return _buffer; - } - - int? get _position { - _internalPosition ??= 0; - return _internalPosition; - } - - //Implementation - /// internal property - void writeShort(int value) { - final List bytes = [ - (value & 0x0000ff00) >> 8, - value & 0x000000ff, - ]; - _flush(bytes); - } - - /// internal property - void writeInt(int value) { - int i1 = (value & 0xff000000) >> 24; - i1 = i1 < 0 ? 256 + i1 : i1; - int i2 = (value & 0x00ff0000) >> 16; - i2 = i2 < 0 ? 256 + i2 : i2; - int i3 = (value & 0x0000ff00) >> 8; - i3 = i3 < 0 ? 256 + i3 : i3; - int i4 = value & 0x000000ff; - i4 = i4 < 0 ? 256 + i4 : i4; - final List bytes = [ - (value & 0xff000000) >> 24, - (value & 0x00ff0000) >> 16, - (value & 0x0000ff00) >> 8, - value & 0x000000ff, - ]; - _flush(bytes); - } - - /// internal property - void writeUInt(int value) { - final List buff = [ - (value & 0xff000000) >> 24, - (value & 0x00ff0000) >> 16, - (value & 0x0000ff00) >> 8, - value & 0x000000ff, - ]; - _flush(buff); - } - - /// internal property - void writeString(String value) { - final List bytes = []; - for (int i = 0; i < value.length; i++) { - bytes.add(value.codeUnitAt(i)); - } - _flush(bytes); - } - - /// internal property - void writeBytes(List value) { - _flush(value); - } - - void _flush(List buff) { - int? position = _position; - for (int i = 0; i < buff.length; i++) { - _buffer![position!] = buff[i]; - position++; - } - _internalPosition = _internalPosition! + buff.length; - } -} +/// internal class +class BigEndianWriter { + //Constructor + /// internal constructor + BigEndianWriter(int capacity) { + _bufferLength = capacity; + _buffer = List.filled(capacity, 0, growable: true); + for (int i = 0; i < capacity; i++) { + _buffer![i] = 0; + } + } + + //Fields + late int _bufferLength; + List? _buffer; + int? _internalPosition; + + //Properties + /// internal property + List? get data { + if (_buffer!.length < _bufferLength) { + final int length = _bufferLength - _buffer!.length; + for (int i = 0; i < length; i++) { + _buffer!.add(0); + } + } + return _buffer; + } + + int? get _position { + _internalPosition ??= 0; + return _internalPosition; + } + + //Implementation + /// internal property + void writeShort(int value) { + final List bytes = [ + (value & 0x0000ff00) >> 8, + value & 0x000000ff, + ]; + _flush(bytes); + } + + /// internal property + void writeInt(int value) { + int i1 = (value & 0xff000000) >> 24; + i1 = i1 < 0 ? 256 + i1 : i1; + int i2 = (value & 0x00ff0000) >> 16; + i2 = i2 < 0 ? 256 + i2 : i2; + int i3 = (value & 0x0000ff00) >> 8; + i3 = i3 < 0 ? 256 + i3 : i3; + int i4 = value & 0x000000ff; + i4 = i4 < 0 ? 256 + i4 : i4; + final List bytes = [ + (value & 0xff000000) >> 24, + (value & 0x00ff0000) >> 16, + (value & 0x0000ff00) >> 8, + value & 0x000000ff, + ]; + _flush(bytes); + } + + /// internal property + void writeUInt(int value) { + final List buff = [ + (value & 0xff000000) >> 24, + (value & 0x00ff0000) >> 16, + (value & 0x0000ff00) >> 8, + value & 0x000000ff, + ]; + _flush(buff); + } + + /// internal property + void writeString(String value) { + final List bytes = []; + for (int i = 0; i < value.length; i++) { + bytes.add(value.codeUnitAt(i)); + } + _flush(bytes); + } + + /// internal property + void writeBytes(List value) { + _flush(value); + } + + void _flush(List buff) { + int? position = _position; + for (int i = 0; i < buff.length; i++) { + _buffer![position!] = buff[i]; + position++; + } + _internalPosition = _internalPosition! + buff.length; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/cross_table.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/cross_table.dart index 08324b35a..79e137995 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/cross_table.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/cross_table.dart @@ -1,681 +1,681 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import '../security/pdf_encryptor.dart'; -import 'enums.dart'; -import 'pdf_cross_table.dart'; -import 'pdf_parser.dart'; -import 'pdf_reader.dart'; - -/// internal class -class CrossTable { - //Constructor - /// internal constructor - CrossTable(List? data, PdfCrossTable crossTable) { - if (data == null || data.isEmpty) { - ArgumentError.value(data, 'PDF data', 'PDF data cannot be null or empty'); - } - _data = data!; - _crossTable = crossTable; - _initialize(); - } - - /// internal constructor - CrossTable.fromFdf(List docStream, PdfCrossTable crossTable) { - _data = docStream; - _crossTable = crossTable; - objects = {}; - } - - //Fields - late List _data; - late PdfCrossTable _crossTable; - PdfReader? _reader; - PdfParser? _parser; - - /// internal field - late Map objects; - late Map _readersTable; - late Map _archives; - - /// internal field - int startCrossReference = 0; - - /// internal field - bool validateSyntax = false; - - /// internal field - PdfDictionary? trailer; - bool _isStructureAltered = false; - int _whiteSpace = 0; - - /// internal field - int initialNumberOfSubsection = 0; - - /// internal field - int initialSubsectionCount = 0; - - /// internal field - int totalNumberOfSubsection = 0; - int? _generationNumber; - late Map> _allTables; - PdfReferenceHolder? _documentCatalog; - PdfEncryptor? _encryptor; - - //Properties - /// internal property - ObjectInformation? operator [](int? key) => _returnValue(key); - - /// internal property - PdfReader get reader { - _reader ??= PdfReader(_data); - return _reader!; - } - - /// internal property - PdfParser get parser { - _parser ??= PdfParser(this, reader, _crossTable); - return _parser!; - } - - /// internal property - PdfReferenceHolder? get documentCatalog { - if (_documentCatalog == null) { - final PdfDictionary trailerObj = trailer!; - final IPdfPrimitive? obj = trailerObj[PdfDictionaryProperties.root]; - if (obj is PdfReferenceHolder) { - _documentCatalog = obj; - } else { - throw ArgumentError.value(obj, 'Invalid format'); - } - } - return _documentCatalog; - } - - /// internal property - PdfEncryptor? get encryptor { - return _encryptor; - } - - set encryptor(PdfEncryptor? value) { - if (value != null) { - _encryptor = value; - } - } - - //Implementation - void _initialize() { - _generationNumber = 65535; - _archives = {}; - _readersTable = {}; - _allTables = >{}; - final int startingOffset = _checkJunk(); - if (startingOffset < 0) { - ArgumentError.value( - startingOffset, - 'Could not find valid signature (%PDF-)', - ); - } - objects = {}; - PdfReader reader = this.reader; - PdfParser parser = this.parser; - reader.position = startingOffset; - reader.skipWhiteSpace(); - _whiteSpace = reader.position; - int position = reader.seekEnd()!; - checkStartXRef(); - reader.position = position; - final int endPosition = reader.searchBack(PdfOperators.endOfFileMarker); - if (endPosition != -1) { - if (position != endPosition + 5) { - reader.position = endPosition + 5; - final String token = reader.getNextToken()!; - if (token.isNotEmpty && token.codeUnitAt(0) != 0 && token[0] != '0') { - reader.position = 0; - final List buffer = reader.readBytes(endPosition + 5); - reader = PdfReader(buffer); - reader.position = buffer.length; - parser = PdfParser(this, reader, _crossTable); - _reader = reader; - _parser = parser; - } - } - } else { - reader.position = position; - } - position = reader.searchBack(PdfOperators.startCrossReference); - bool isForwardSearch = false; - if (position >= 0) { - parser.setOffset(position); - position = parser.startCrossReference(); - startCrossReference = position; - _parser!.setOffset(position); - if (_whiteSpace != 0) { - final int crossReferencePosition = reader.searchForward( - PdfOperators.crossReference, - ); - if (crossReferencePosition == -1) { - isForwardSearch = false; - position += _whiteSpace; - reader.position = position; - } else { - position = crossReferencePosition; - parser.setOffset(position); - isForwardSearch = true; - } - } - } - String tempString = reader.readLine(); - if (!tempString.contains(PdfOperators.crossReference) && - !tempString.contains(PdfOperators.obj) && - !isForwardSearch) { - final int rposition = reader.position; - final String tempS = reader.readLine(); - if (tempS.contains(PdfOperators.crossReference)) { - tempString = tempS; - position = rposition; - } else { - reader.position = rposition; - } - } - if (!tempString.contains(PdfOperators.crossReference) && - !tempString.contains(PdfOperators.obj) && - !isForwardSearch) { - if (position > reader.length!) { - position = reader.length!; - reader.position = position; - position = reader.searchBack(PdfOperators.startCrossReference); - } - final int tempOffset = reader.searchBack(PdfOperators.crossReference); - if (tempOffset != -1) { - position = tempOffset; - } - parser.setOffset(position); - } - reader.position = position; - try { - final Map tempResult = parser.parseCrossReferenceTable( - objects, - this, - ); - trailer = tempResult['object'] as PdfDictionary?; - objects = tempResult['objects'] as Map; - } catch (e) { - throw ArgumentError.value(trailer, 'Invalid cross reference table.'); - } - PdfDictionary trailerObj = trailer!; - while (trailerObj.containsKey(PdfDictionaryProperties.prev)) { - if (_whiteSpace != 0) { - final PdfNumber number = - trailerObj[PdfDictionaryProperties.prev]! as PdfNumber; - number.value = number.value! + _whiteSpace; - _isStructureAltered = true; - } - position = - (trailerObj[PdfDictionaryProperties.prev]! as PdfNumber).value! - .toInt(); - final PdfReader tokenReader = PdfReader(_reader!.streamReader.data); - tokenReader.position = position; - String? token = tokenReader.getNextToken(); - if (token != PdfDictionaryProperties.crossReference) { - token = tokenReader.getNextToken(); - //check the coditon for valid object number - final int? number = int.tryParse(token!); - if (number != null && number >= 0) { - token = tokenReader.getNextToken(); - if (token == PdfDictionaryProperties.obj) { - parser.setOffset(position); - final Map tempResults = parser - .parseCrossReferenceTable(objects, this); - trailerObj = tempResults['object'] as PdfDictionary; - objects = tempResults['objects'] as Map; - parser.setOffset(position); - continue; - } - } - parser.rebuildXrefTable(objects, this); - break; - } else { - parser.setOffset(position); - final Map tempResults = parser - .parseCrossReferenceTable(objects, this); - trailerObj = tempResults['object'] as PdfDictionary; - objects = tempResults['objects'] as Map; - if (trailerObj.containsKey(PdfDictionaryProperties.size) && - trailer!.containsKey(PdfDictionaryProperties.size)) { - if ((trailerObj[PdfDictionaryProperties.size]! as PdfNumber).value! > - (trailer![PdfDictionaryProperties.size]! as PdfNumber).value!) { - (trailer![PdfDictionaryProperties.size]! as PdfNumber).value = - (trailerObj[PdfDictionaryProperties.size]! as PdfNumber).value; - } - } - } - } - if (_whiteSpace != 0 && isForwardSearch) { - List objKey = List.filled(objects.length, 0); - objKey = objects.keys.toList(); - for (int i = 0; i < objKey.length; i++) { - final int key = objKey[i]; - final ObjectInformation info = objects[key]!; - objects[key] = ObjectInformation( - info._offset! + _whiteSpace, - null, - this, - ); - } - _isStructureAltered = true; - } else if (_whiteSpace != 0 && _whiteSpace > 0 && !_isStructureAltered) { - if (!trailerObj.containsKey(PdfDictionaryProperties.prev)) { - _isStructureAltered = true; - } - } - } - - ObjectInformation? _returnValue(int? key) { - return objects.containsKey(key) ? objects[key!] : null; - } - - /// internal method - IPdfPrimitive? getObject(IPdfPrimitive? pointer) { - if (pointer == null) { - throw ArgumentError.value(pointer, 'pointer'); - } - if (pointer is PdfReference) { - IPdfPrimitive? obj; - final PdfReference reference = pointer; - final ObjectInformation? oi = this[reference.objNum]; - if (oi == null) { - return PdfNull(); - } - final PdfParser? parser = oi.parser; - final int? position = oi.offset; - if (oi.obj != null) { - obj = oi.obj; - } else if (oi._archive == null) { - obj = parser!.parseOffset(position!); - } else { - obj = _getObjectFromPosition(parser!, position!); - if (encryptor != null) { - if (obj is PdfDictionary) { - obj.decrypted = true; - for (final dynamic element in obj.items!.values) { - if (element is PdfString) { - element.isParentDecrypted = true; - } - } - } - } - } - oi.obj = obj; - return obj; - } else { - return pointer; - } - } - - IPdfPrimitive? _getObjectFromPosition(PdfParser parser, int position) { - parser.startFrom(position); - return parser.simple(); - } - - /// internal method - Map? parseNewTable( - PdfStream? stream, - Map? objects, - ) { - if (stream == null) { - throw ArgumentError.value(stream, 'Invalid format'); - } - stream.decompress(); - final List<_SubSection> subSections = _getSections(stream); - int? ssIndex = 0; - for (int i = 0; i < subSections.length; i++) { - final _SubSection ss = subSections[i]; - final Map result = _parseWithHashTable( - stream, - ss, - objects, - ssIndex, - ); - ssIndex = result['index'] as int?; - objects = result['objects'] as Map?; - } - return objects; - } - - Map _parseWithHashTable( - PdfStream stream, - _SubSection subsection, - Map? table, - int? startIndex, - ) { - int? index = startIndex; - final IPdfPrimitive? entry = getObject(stream[PdfDictionaryProperties.w]); - if (entry is PdfArray) { - final int fields = entry.count; - final List format = List.filled(fields, 0, growable: true); - for (int i = 0; i < fields; ++i) { - final PdfNumber formatNumber = entry[i]! as PdfNumber; - format[i] = formatNumber.value!.toInt(); - } - final List reference = List.filled(fields, 0, growable: true); - final List? buf = stream.dataStream; - for (int i = 0; i < subsection.count; ++i) { - for (int j = 0; j < fields; ++j) { - int field = 0; - if (j == 0) { - if (format[j] > 0) { - field = 0; - } else { - field = 1; - } - } - for (int k = 0; k < format[j]; ++k) { - field <<= 8; - field = field + buf![index!]; - index += 1; - } - reference[j] = field; - } - int offset = 0; - ArchiveInformation? ai; - if (reference[0] == PdfObjectType.normal.index) { - if (_whiteSpace != 0) { - offset = reference[1] + _whiteSpace; - } else { - offset = reference[1]; - } - } else if (reference[0] == PdfObjectType.packed.index) { - ai = ArchiveInformation(reference[1], reference[2], _retrieveArchive); - } - ObjectInformation? oi; - // NOTE: do not store removed objects. - if (reference[0] != PdfObjectType.free.index) { - oi = ObjectInformation(offset, ai, this); - } - if (oi != null) { - final int objectOffset = subsection.startNumber + i; - if (!table!.containsKey(objectOffset)) { - table[objectOffset] = oi; - } - _addTables(objectOffset, oi); - } - } - } - return {'index': index, 'objects': table}; - } - - PdfStream _retrieveArchive(int archiveNumber) { - PdfStream? archive; - if (_archives.containsKey(archiveNumber)) { - archive = _archives[archiveNumber]; - } - if (archive == null) { - final ObjectInformation oi = this[archiveNumber]!; - final PdfParser parser = oi.parser!; - archive = parser.parseOffset(oi._offset!) as PdfStream?; - if (encryptor != null && !encryptor!.encryptAttachmentOnly!) { - archive!.decrypt(encryptor!, archiveNumber); - } - archive!.decompress(); - _archives[archiveNumber] = archive; - } - return archive; - } - - List<_SubSection> _getSections(PdfStream stream) { - final List<_SubSection> subSections = <_SubSection>[]; - int count = 0; - if (stream.containsKey(PdfDictionaryProperties.size)) { - final IPdfPrimitive? primitive = stream[PdfDictionaryProperties.size]; - if (primitive is PdfNumber) { - count = primitive.value!.toInt(); - } - } - if (count == 0) { - throw ArgumentError.value(count, 'Invalid Format'); - } - final IPdfPrimitive? obj = stream[PdfDictionaryProperties.index]; - if (obj == null) { - subSections.add(_SubSection(count)); - } else { - final IPdfPrimitive? primitive = getObject(obj); - if (primitive != null && primitive is PdfArray) { - final PdfArray indices = primitive; - if ((indices.count & 1) != 0) { - throw ArgumentError.value(count, 'Invalid Format'); - } - for (int i = 0; i < indices.count; ++i) { - int n = 0, c = 0; - n = (indices[i]! as PdfNumber).value!.toInt(); - ++i; - c = (indices[i]! as PdfNumber).value!.toInt(); - subSections.add(_SubSection(c, n)); - } - } - } - return subSections; - } - - /// internal method - void parseSubsection(PdfParser parser, Map? table) { - // Read the initial number of the subsection. - PdfNumber integer = parser.simple()! as PdfNumber; - - initialNumberOfSubsection = integer.value!.toInt(); - // Read the total number of subsection. - integer = parser.simple()! as PdfNumber; - - totalNumberOfSubsection = integer.value!.toInt(); - initialSubsectionCount = initialNumberOfSubsection; - for (int i = 0; i < totalNumberOfSubsection; ++i) { - integer = parser.simple()! as PdfNumber; - final int offset = integer.value!.toInt(); - integer = parser.simple()! as PdfNumber; - final int genNum = integer.value!.toInt(); - final String flag = parser.getObjectFlag(); - if (flag == 'n') { - final ObjectInformation oi = ObjectInformation(offset, null, this); - int objectOffset = 0; - if (initialSubsectionCount == initialNumberOfSubsection) { - objectOffset = initialNumberOfSubsection + i; - } else { - objectOffset = initialSubsectionCount + i; - } - if (!table!.containsKey(objectOffset)) { - table[objectOffset] = oi; - } - _addTables(objectOffset, oi); - } else { - if (initialNumberOfSubsection != 0 && - offset == 0 && - genNum == _generationNumber) { - initialNumberOfSubsection = initialNumberOfSubsection - 1; - if (i == 0) { - initialSubsectionCount = initialNumberOfSubsection; - } - } - } - } - } - - void _addTables(int objectOffset, ObjectInformation oi) { - if (_allTables.containsKey(objectOffset)) { - _allTables[objectOffset]!.add(oi); - } else { - _allTables[objectOffset] = [oi]; - } - } - - int _checkJunk() { - int position = 0; - int index = 0; - do { - final int length = - _data.length - position < 1024 ? (_data.length - position) : 1024; - final String header = String.fromCharCodes( - _data.sublist(position, length), - ); - index = header.indexOf('%PDF-'); - position += length; - } while (index < 0 && position != _data.length); - return index; - } - - /// internal method - void checkStartXRef() { - const int maxSize = 1024; - int pos = reader.length! - maxSize; - if (pos < 1) { - pos = 1; - } - List? data = List.filled(maxSize, 0); - while (pos > 0) { - reader.position = pos; - final Map result = reader.copyBytes(data, 0, maxSize); - data = result['buffer'] as List?; - final String start = String.fromCharCodes(data!); - final int index = start.lastIndexOf('startxref'); - if (index >= 0) { - reader.position = index; - break; - } - pos = pos - maxSize + 9; - } - } - - /// internal method - PdfParser? retrieveParser(ArchiveInformation? archive) { - if (archive == null) { - return _parser; - } else { - final PdfStream stream = archive.archive; - PdfParser? parser; - if (_readersTable.containsKey(stream)) { - parser = _readersTable[stream]; - } - if (parser == null) { - final PdfReader reader = PdfReader(stream.dataStream); - parser = PdfParser(this, reader, _crossTable); - _readersTable[stream] = parser; - } - return parser; - } - } -} - -/// internal class -class ObjectInformation { - //Constructor - /// internal constructor - ObjectInformation( - int offset, - ArchiveInformation? arciveInfo, - CrossTable? crossTable, - ) { - _offset = offset; - _archive = arciveInfo; - _crossTable = crossTable; - } - //Fields - ArchiveInformation? _archive; - PdfParser? _parser; - int? _offset; - CrossTable? _crossTable; - - /// internal Fields - IPdfPrimitive? obj; - - //Properties - /// internal property - PdfParser? get parser { - _parser ??= _crossTable!.retrieveParser(_archive); - return _parser; - } - - /// internal property - int? get offset { - if (_offset == 0) { - final PdfParser parser = this.parser!; - parser.startFrom(0); - int pairs = 0; - // Read indices. - if (_archive != null) { - final PdfNumber? archieveNumber = - _archive!.archive[PdfDictionaryProperties.n] as PdfNumber?; - if (archieveNumber != null) { - pairs = archieveNumber.value!.toInt(); - } - final List indices = List.filled( - pairs * 2, - 0, - growable: true, - ); - for (int i = 0; i < pairs; ++i) { - PdfNumber? obj = parser.simple() as PdfNumber?; - if (obj != null) { - indices[i * 2] = obj.value!.toInt(); - } - obj = parser.simple() as PdfNumber?; - if (obj != null) { - indices[i * 2 + 1] = obj.value!.toInt(); - } - } - final int index = _archive!._index; - if (index * 2 >= indices.length) { - throw ArgumentError.value( - _archive!._archiveNumber, - 'Missing indexes in archive', - ); - } - _offset = indices[index * 2 + 1]; - final int first = - (_archive!.archive[PdfDictionaryProperties.first]! as PdfNumber) - .value! - .toInt(); - _offset = _offset! + first; - } - } - return _offset; - } -} - -class ArchiveInformation { - //Constructor - ArchiveInformation(int archiveNumber, int index, GetArchive getArchive) { - _archiveNumber = archiveNumber; - _index = index; - _getArchive = getArchive; - } - - //Fields - late int _archiveNumber; - late int _index; - PdfStream? _archive; - late GetArchive _getArchive; - - //Properties - PdfStream get archive { - _archive ??= _getArchive(_archiveNumber); - return _archive!; - } -} - -typedef GetArchive = PdfStream Function(int archiveNumber); - -class _SubSection { - //constructor - _SubSection(this.count, [int? start]) { - startNumber = start ?? 0; - } - - late int startNumber; - late int count; -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import '../security/pdf_encryptor.dart'; +import 'enums.dart'; +import 'pdf_cross_table.dart'; +import 'pdf_parser.dart'; +import 'pdf_reader.dart'; + +/// internal class +class CrossTable { + //Constructor + /// internal constructor + CrossTable(List? data, PdfCrossTable crossTable) { + if (data == null || data.isEmpty) { + ArgumentError.value(data, 'PDF data', 'PDF data cannot be null or empty'); + } + _data = data!; + _crossTable = crossTable; + _initialize(); + } + + /// internal constructor + CrossTable.fromFdf(List docStream, PdfCrossTable crossTable) { + _data = docStream; + _crossTable = crossTable; + objects = {}; + } + + //Fields + late List _data; + late PdfCrossTable _crossTable; + PdfReader? _reader; + PdfParser? _parser; + + /// internal field + late Map objects; + late Map _readersTable; + late Map _archives; + + /// internal field + int startCrossReference = 0; + + /// internal field + bool validateSyntax = false; + + /// internal field + PdfDictionary? trailer; + bool _isStructureAltered = false; + int _whiteSpace = 0; + + /// internal field + int initialNumberOfSubsection = 0; + + /// internal field + int initialSubsectionCount = 0; + + /// internal field + int totalNumberOfSubsection = 0; + int? _generationNumber; + late Map> _allTables; + PdfReferenceHolder? _documentCatalog; + PdfEncryptor? _encryptor; + + //Properties + /// internal property + ObjectInformation? operator [](int? key) => _returnValue(key); + + /// internal property + PdfReader get reader { + _reader ??= PdfReader(_data); + return _reader!; + } + + /// internal property + PdfParser get parser { + _parser ??= PdfParser(this, reader, _crossTable); + return _parser!; + } + + /// internal property + PdfReferenceHolder? get documentCatalog { + if (_documentCatalog == null) { + final PdfDictionary trailerObj = trailer!; + final IPdfPrimitive? obj = trailerObj[PdfDictionaryProperties.root]; + if (obj is PdfReferenceHolder) { + _documentCatalog = obj; + } else { + throw ArgumentError.value(obj, 'Invalid format'); + } + } + return _documentCatalog; + } + + /// internal property + PdfEncryptor? get encryptor { + return _encryptor; + } + + set encryptor(PdfEncryptor? value) { + if (value != null) { + _encryptor = value; + } + } + + //Implementation + void _initialize() { + _generationNumber = 65535; + _archives = {}; + _readersTable = {}; + _allTables = >{}; + final int startingOffset = _checkJunk(); + if (startingOffset < 0) { + ArgumentError.value( + startingOffset, + 'Could not find valid signature (%PDF-)', + ); + } + objects = {}; + PdfReader reader = this.reader; + PdfParser parser = this.parser; + reader.position = startingOffset; + reader.skipWhiteSpace(); + _whiteSpace = reader.position; + int position = reader.seekEnd()!; + checkStartXRef(); + reader.position = position; + final int endPosition = reader.searchBack(PdfOperators.endOfFileMarker); + if (endPosition != -1) { + if (position != endPosition + 5) { + reader.position = endPosition + 5; + final String token = reader.getNextToken()!; + if (token.isNotEmpty && token.codeUnitAt(0) != 0 && token[0] != '0') { + reader.position = 0; + final List buffer = reader.readBytes(endPosition + 5); + reader = PdfReader(buffer); + reader.position = buffer.length; + parser = PdfParser(this, reader, _crossTable); + _reader = reader; + _parser = parser; + } + } + } else { + reader.position = position; + } + position = reader.searchBack(PdfOperators.startCrossReference); + bool isForwardSearch = false; + if (position >= 0) { + parser.setOffset(position); + position = parser.startCrossReference(); + startCrossReference = position; + _parser!.setOffset(position); + if (_whiteSpace != 0) { + final int crossReferencePosition = reader.searchForward( + PdfOperators.crossReference, + ); + if (crossReferencePosition == -1) { + isForwardSearch = false; + position += _whiteSpace; + reader.position = position; + } else { + position = crossReferencePosition; + parser.setOffset(position); + isForwardSearch = true; + } + } + } + String tempString = reader.readLine(); + if (!tempString.contains(PdfOperators.crossReference) && + !tempString.contains(PdfOperators.obj) && + !isForwardSearch) { + final int rposition = reader.position; + final String tempS = reader.readLine(); + if (tempS.contains(PdfOperators.crossReference)) { + tempString = tempS; + position = rposition; + } else { + reader.position = rposition; + } + } + if (!tempString.contains(PdfOperators.crossReference) && + !tempString.contains(PdfOperators.obj) && + !isForwardSearch) { + if (position > reader.length!) { + position = reader.length!; + reader.position = position; + position = reader.searchBack(PdfOperators.startCrossReference); + } + final int tempOffset = reader.searchBack(PdfOperators.crossReference); + if (tempOffset != -1) { + position = tempOffset; + } + parser.setOffset(position); + } + reader.position = position; + try { + final Map tempResult = parser.parseCrossReferenceTable( + objects, + this, + ); + trailer = tempResult['object'] as PdfDictionary?; + objects = tempResult['objects'] as Map; + } catch (e) { + throw ArgumentError.value(trailer, 'Invalid cross reference table.'); + } + PdfDictionary trailerObj = trailer!; + while (trailerObj.containsKey(PdfDictionaryProperties.prev)) { + if (_whiteSpace != 0) { + final PdfNumber number = + trailerObj[PdfDictionaryProperties.prev]! as PdfNumber; + number.value = number.value! + _whiteSpace; + _isStructureAltered = true; + } + position = + (trailerObj[PdfDictionaryProperties.prev]! as PdfNumber).value! + .toInt(); + final PdfReader tokenReader = PdfReader(_reader!.streamReader.data); + tokenReader.position = position; + String? token = tokenReader.getNextToken(); + if (token != PdfDictionaryProperties.crossReference) { + token = tokenReader.getNextToken(); + //check the coditon for valid object number + final int? number = int.tryParse(token!); + if (number != null && number >= 0) { + token = tokenReader.getNextToken(); + if (token == PdfDictionaryProperties.obj) { + parser.setOffset(position); + final Map tempResults = parser + .parseCrossReferenceTable(objects, this); + trailerObj = tempResults['object'] as PdfDictionary; + objects = tempResults['objects'] as Map; + parser.setOffset(position); + continue; + } + } + parser.rebuildXrefTable(objects, this); + break; + } else { + parser.setOffset(position); + final Map tempResults = parser + .parseCrossReferenceTable(objects, this); + trailerObj = tempResults['object'] as PdfDictionary; + objects = tempResults['objects'] as Map; + if (trailerObj.containsKey(PdfDictionaryProperties.size) && + trailer!.containsKey(PdfDictionaryProperties.size)) { + if ((trailerObj[PdfDictionaryProperties.size]! as PdfNumber).value! > + (trailer![PdfDictionaryProperties.size]! as PdfNumber).value!) { + (trailer![PdfDictionaryProperties.size]! as PdfNumber).value = + (trailerObj[PdfDictionaryProperties.size]! as PdfNumber).value; + } + } + } + } + if (_whiteSpace != 0 && isForwardSearch) { + List objKey = List.filled(objects.length, 0); + objKey = objects.keys.toList(); + for (int i = 0; i < objKey.length; i++) { + final int key = objKey[i]; + final ObjectInformation info = objects[key]!; + objects[key] = ObjectInformation( + info._offset! + _whiteSpace, + null, + this, + ); + } + _isStructureAltered = true; + } else if (_whiteSpace != 0 && _whiteSpace > 0 && !_isStructureAltered) { + if (!trailerObj.containsKey(PdfDictionaryProperties.prev)) { + _isStructureAltered = true; + } + } + } + + ObjectInformation? _returnValue(int? key) { + return objects.containsKey(key) ? objects[key!] : null; + } + + /// internal method + IPdfPrimitive? getObject(IPdfPrimitive? pointer) { + if (pointer == null) { + throw ArgumentError.value(pointer, 'pointer'); + } + if (pointer is PdfReference) { + IPdfPrimitive? obj; + final PdfReference reference = pointer; + final ObjectInformation? oi = this[reference.objNum]; + if (oi == null) { + return PdfNull(); + } + final PdfParser? parser = oi.parser; + final int? position = oi.offset; + if (oi.obj != null) { + obj = oi.obj; + } else if (oi._archive == null) { + obj = parser!.parseOffset(position!); + } else { + obj = _getObjectFromPosition(parser!, position!); + if (encryptor != null) { + if (obj is PdfDictionary) { + obj.decrypted = true; + for (final dynamic element in obj.items!.values) { + if (element is PdfString) { + element.isParentDecrypted = true; + } + } + } + } + } + oi.obj = obj; + return obj; + } else { + return pointer; + } + } + + IPdfPrimitive? _getObjectFromPosition(PdfParser parser, int position) { + parser.startFrom(position); + return parser.simple(); + } + + /// internal method + Map? parseNewTable( + PdfStream? stream, + Map? objects, + ) { + if (stream == null) { + throw ArgumentError.value(stream, 'Invalid format'); + } + stream.decompress(); + final List<_SubSection> subSections = _getSections(stream); + int? ssIndex = 0; + for (int i = 0; i < subSections.length; i++) { + final _SubSection ss = subSections[i]; + final Map result = _parseWithHashTable( + stream, + ss, + objects, + ssIndex, + ); + ssIndex = result['index'] as int?; + objects = result['objects'] as Map?; + } + return objects; + } + + Map _parseWithHashTable( + PdfStream stream, + _SubSection subsection, + Map? table, + int? startIndex, + ) { + int? index = startIndex; + final IPdfPrimitive? entry = getObject(stream[PdfDictionaryProperties.w]); + if (entry is PdfArray) { + final int fields = entry.count; + final List format = List.filled(fields, 0, growable: true); + for (int i = 0; i < fields; ++i) { + final PdfNumber formatNumber = entry[i]! as PdfNumber; + format[i] = formatNumber.value!.toInt(); + } + final List reference = List.filled(fields, 0, growable: true); + final List? buf = stream.dataStream; + for (int i = 0; i < subsection.count; ++i) { + for (int j = 0; j < fields; ++j) { + int field = 0; + if (j == 0) { + if (format[j] > 0) { + field = 0; + } else { + field = 1; + } + } + for (int k = 0; k < format[j]; ++k) { + field <<= 8; + field = field + buf![index!]; + index += 1; + } + reference[j] = field; + } + int offset = 0; + ArchiveInformation? ai; + if (reference[0] == PdfObjectType.normal.index) { + if (_whiteSpace != 0) { + offset = reference[1] + _whiteSpace; + } else { + offset = reference[1]; + } + } else if (reference[0] == PdfObjectType.packed.index) { + ai = ArchiveInformation(reference[1], reference[2], _retrieveArchive); + } + ObjectInformation? oi; + // NOTE: do not store removed objects. + if (reference[0] != PdfObjectType.free.index) { + oi = ObjectInformation(offset, ai, this); + } + if (oi != null) { + final int objectOffset = subsection.startNumber + i; + if (!table!.containsKey(objectOffset)) { + table[objectOffset] = oi; + } + _addTables(objectOffset, oi); + } + } + } + return {'index': index, 'objects': table}; + } + + PdfStream _retrieveArchive(int archiveNumber) { + PdfStream? archive; + if (_archives.containsKey(archiveNumber)) { + archive = _archives[archiveNumber]; + } + if (archive == null) { + final ObjectInformation oi = this[archiveNumber]!; + final PdfParser parser = oi.parser!; + archive = parser.parseOffset(oi._offset!) as PdfStream?; + if (encryptor != null && !encryptor!.encryptAttachmentOnly!) { + archive!.decrypt(encryptor!, archiveNumber); + } + archive!.decompress(); + _archives[archiveNumber] = archive; + } + return archive; + } + + List<_SubSection> _getSections(PdfStream stream) { + final List<_SubSection> subSections = <_SubSection>[]; + int count = 0; + if (stream.containsKey(PdfDictionaryProperties.size)) { + final IPdfPrimitive? primitive = stream[PdfDictionaryProperties.size]; + if (primitive is PdfNumber) { + count = primitive.value!.toInt(); + } + } + if (count == 0) { + throw ArgumentError.value(count, 'Invalid Format'); + } + final IPdfPrimitive? obj = stream[PdfDictionaryProperties.index]; + if (obj == null) { + subSections.add(_SubSection(count)); + } else { + final IPdfPrimitive? primitive = getObject(obj); + if (primitive != null && primitive is PdfArray) { + final PdfArray indices = primitive; + if ((indices.count & 1) != 0) { + throw ArgumentError.value(count, 'Invalid Format'); + } + for (int i = 0; i < indices.count; ++i) { + int n = 0, c = 0; + n = (indices[i]! as PdfNumber).value!.toInt(); + ++i; + c = (indices[i]! as PdfNumber).value!.toInt(); + subSections.add(_SubSection(c, n)); + } + } + } + return subSections; + } + + /// internal method + void parseSubsection(PdfParser parser, Map? table) { + // Read the initial number of the subsection. + PdfNumber integer = parser.simple()! as PdfNumber; + + initialNumberOfSubsection = integer.value!.toInt(); + // Read the total number of subsection. + integer = parser.simple()! as PdfNumber; + + totalNumberOfSubsection = integer.value!.toInt(); + initialSubsectionCount = initialNumberOfSubsection; + for (int i = 0; i < totalNumberOfSubsection; ++i) { + integer = parser.simple()! as PdfNumber; + final int offset = integer.value!.toInt(); + integer = parser.simple()! as PdfNumber; + final int genNum = integer.value!.toInt(); + final String flag = parser.getObjectFlag(); + if (flag == 'n') { + final ObjectInformation oi = ObjectInformation(offset, null, this); + int objectOffset = 0; + if (initialSubsectionCount == initialNumberOfSubsection) { + objectOffset = initialNumberOfSubsection + i; + } else { + objectOffset = initialSubsectionCount + i; + } + if (!table!.containsKey(objectOffset)) { + table[objectOffset] = oi; + } + _addTables(objectOffset, oi); + } else { + if (initialNumberOfSubsection != 0 && + offset == 0 && + genNum == _generationNumber) { + initialNumberOfSubsection = initialNumberOfSubsection - 1; + if (i == 0) { + initialSubsectionCount = initialNumberOfSubsection; + } + } + } + } + } + + void _addTables(int objectOffset, ObjectInformation oi) { + if (_allTables.containsKey(objectOffset)) { + _allTables[objectOffset]!.add(oi); + } else { + _allTables[objectOffset] = [oi]; + } + } + + int _checkJunk() { + int position = 0; + int index = 0; + do { + final int length = + _data.length - position < 1024 ? (_data.length - position) : 1024; + final String header = String.fromCharCodes( + _data.sublist(position, length), + ); + index = header.indexOf('%PDF-'); + position += length; + } while (index < 0 && position != _data.length); + return index; + } + + /// internal method + void checkStartXRef() { + const int maxSize = 1024; + int pos = reader.length! - maxSize; + if (pos < 1) { + pos = 1; + } + List? data = List.filled(maxSize, 0); + while (pos > 0) { + reader.position = pos; + final Map result = reader.copyBytes(data, 0, maxSize); + data = result['buffer'] as List?; + final String start = String.fromCharCodes(data!); + final int index = start.lastIndexOf('startxref'); + if (index >= 0) { + reader.position = index; + break; + } + pos = pos - maxSize + 9; + } + } + + /// internal method + PdfParser? retrieveParser(ArchiveInformation? archive) { + if (archive == null) { + return _parser; + } else { + final PdfStream stream = archive.archive; + PdfParser? parser; + if (_readersTable.containsKey(stream)) { + parser = _readersTable[stream]; + } + if (parser == null) { + final PdfReader reader = PdfReader(stream.dataStream); + parser = PdfParser(this, reader, _crossTable); + _readersTable[stream] = parser; + } + return parser; + } + } +} + +/// internal class +class ObjectInformation { + //Constructor + /// internal constructor + ObjectInformation( + int offset, + ArchiveInformation? arciveInfo, + CrossTable? crossTable, + ) { + _offset = offset; + _archive = arciveInfo; + _crossTable = crossTable; + } + //Fields + ArchiveInformation? _archive; + PdfParser? _parser; + int? _offset; + CrossTable? _crossTable; + + /// internal Fields + IPdfPrimitive? obj; + + //Properties + /// internal property + PdfParser? get parser { + _parser ??= _crossTable!.retrieveParser(_archive); + return _parser; + } + + /// internal property + int? get offset { + if (_offset == 0) { + final PdfParser parser = this.parser!; + parser.startFrom(0); + int pairs = 0; + // Read indices. + if (_archive != null) { + final PdfNumber? archieveNumber = + _archive!.archive[PdfDictionaryProperties.n] as PdfNumber?; + if (archieveNumber != null) { + pairs = archieveNumber.value!.toInt(); + } + final List indices = List.filled( + pairs * 2, + 0, + growable: true, + ); + for (int i = 0; i < pairs; ++i) { + PdfNumber? obj = parser.simple() as PdfNumber?; + if (obj != null) { + indices[i * 2] = obj.value!.toInt(); + } + obj = parser.simple() as PdfNumber?; + if (obj != null) { + indices[i * 2 + 1] = obj.value!.toInt(); + } + } + final int index = _archive!._index; + if (index * 2 >= indices.length) { + throw ArgumentError.value( + _archive!._archiveNumber, + 'Missing indexes in archive', + ); + } + _offset = indices[index * 2 + 1]; + final int first = + (_archive!.archive[PdfDictionaryProperties.first]! as PdfNumber) + .value! + .toInt(); + _offset = _offset! + first; + } + } + return _offset; + } +} + +class ArchiveInformation { + //Constructor + ArchiveInformation(int archiveNumber, int index, GetArchive getArchive) { + _archiveNumber = archiveNumber; + _index = index; + _getArchive = getArchive; + } + + //Fields + late int _archiveNumber; + late int _index; + PdfStream? _archive; + late GetArchive _getArchive; + + //Properties + PdfStream get archive { + _archive ??= _getArchive(_archiveNumber); + return _archive!; + } +} + +typedef GetArchive = PdfStream Function(int archiveNumber); + +class _SubSection { + //constructor + _SubSection(this.count, [int? start]) { + startNumber = start ?? 0; + } + + late int startNumber; + late int count; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/decode_big_endian.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/decode_big_endian.dart index 724d63a98..1ce0a2fb5 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/decode_big_endian.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/decode_big_endian.dart @@ -1,227 +1,227 @@ -/// internal method -String decodeBigEndian(List? bytes, [int offset = 0, int? length]) { - final List codeUnits = - UtfbeDecoder(bytes, offset, length).decodeRemaining(); - final List result = _convertCodeUnitsToCodePoints(codeUnits); - return String.fromCharCodes(result); -} - -List _convertCodeUnitsToCodePoints( - List codeUnits, [ - int offset = 0, - int? length, -]) { - final UtfCodeUnitDecoder decoder = UtfCodeUnitDecoder( - ByteRange(codeUnits, offset, length), - ); - final List codePoints = List.filled( - decoder.byteRange.remaining, - 0, - growable: true, - ); - int i = 0; - while (decoder.moveNext) { - codePoints[i++] = decoder._current!; - } - if (i == codePoints.length) { - return codePoints; - } else { - final List cpt = List.filled(i, 0, growable: true); - cpt.setRange(0, i, codePoints); - return cpt; - } -} - -/// internal class -class UtfbeDecoder { - /// internal constructor - UtfbeDecoder(List? encodedBytes, [int offset = 0, int? length]) { - length = length ?? encodedBytes!.length - offset; - byteRange = ByteRange(encodedBytes, offset, length); - if (isBeBom(encodedBytes, offset, length)) { - byteRange.skip(2); - } - } - - /// internal field - late ByteRange byteRange; - - /// internal field - final int rcPoint = 0xfffd; - int? _current; - - /// internal property - int get remaining => (byteRange.remaining + 1) ~/ 2; - - /// internal property - bool get moveNext { - _current = null; - final int remaining = byteRange.remaining; - if (remaining == 0) { - _current = null; - return false; - } - if (remaining == 1) { - byteRange.moveNext; - _current = rcPoint; - return true; - } - _current = decode(); - return true; - } - - /// internal method - List decodeRemaining() { - final List codeunits = List.filled(remaining, 0, growable: true); - int i = 0; - while (moveNext) { - codeunits[i++] = _current!; - } - if (i == codeunits.length) { - return codeunits; - } else { - final List tcu = List.filled(i, 0, growable: true); - tcu.setRange(0, i, codeunits); - return tcu; - } - } - - /// internal method - bool isBeBom(List? encodedBytes, [int offset = 0, int? length]) { - final int end = length != null ? offset + length : encodedBytes!.length; - return (offset + 2) <= end && - encodedBytes![offset] == 0xfe && - encodedBytes[offset + 1] == 0xff; - } - - /// internal method - int decode() { - byteRange.moveNext; - final int first = byteRange.current!; - byteRange.moveNext; - final int next = byteRange.current!; - return (first << 8) + next; - } -} - -/// internal class -class ByteRange { - /// internal constructor - ByteRange(List? source, int offset, int? length) { - length = length ?? source!.length - offset; - _source = source; - _offset = offset - 1; - _length = length; - _end = offset + _length; - } - List? _source; - late int _offset; - late int _length; - late int _end; - - /// internal property - int? get current => _source![_offset]; - - /// internal property - bool get moveNext => ++_offset < _end; - - /// internal property - int get remaining => _end - _offset - 1; - - /// internal method - void skip([int count = 1]) { - _offset += count; - } - - /// internal method - void backup([int byte = 1]) { - _offset -= byte; - } -} - -/// internal class -class UtfCodeUnitDecoder { - /// internal constructor - UtfCodeUnitDecoder(this.byteRange); - - /// internal field - final ByteRange byteRange; - - /// internal field - final int rcPoint = 0xfffd; - int? _current; - - /// internal property - bool get moveNext { - _current = null; - if (!byteRange.moveNext) { - return false; - } - int value = byteRange.current!; - if (value < 0) { - _current = rcPoint; - } else if (value < 0xd800 || (value > 0xdfff && value <= 0xffff)) { - _current = value; - } else if (value < 0xdc00 && byteRange.moveNext) { - final int nextValue = byteRange.current!; - if (nextValue >= 0xdc00 && nextValue <= 0xdfff) { - value = (value - 0xd800) << 10; - value += 0x10000 + (nextValue - 0xdc00); - _current = value; - } else { - if (nextValue >= 0xd800 && nextValue < 0xdc00) { - byteRange.backup(); - } - _current = rcPoint; - } - } else { - _current = rcPoint; - } - return true; - } -} - -/// internal method -List encodeBigEndian(String content) { - final List codeUnits = _codePointsToCodeUnits(content.codeUnits); - final List encodedBytes = List.filled( - 2 * codeUnits.length, - 0, - growable: true, - ); - int i = 0; - for (final int value in codeUnits) { - encodedBytes[i++] = (value & 0xff00) >> 8; - encodedBytes[i++] = value & 0xff; - } - return encodedBytes; -} - -List _codePointsToCodeUnits(List codePoints) { - int eLength = 0; - for (int i = 0; i < codePoints.length; i++) { - final int value = codePoints[i]; - if ((value >= 0 && value < 0xd800) || (value > 0xdfff && value <= 0xffff)) { - eLength++; - } else if (value > 0xffff && value <= 0x10ffff) { - eLength += 2; - } else { - eLength++; - } - } - final List buffer = List.filled(eLength, 0, growable: true); - int j = 0; - for (int i = 0; i < codePoints.length; i++) { - final int value = codePoints[i]; - if ((value >= 0 && value < 0xd800) || (value > 0xdfff && value <= 0xffff)) { - buffer[j++] = value; - } else if (value > 0xffff && value <= 0x10ffff) { - final int temp = value - 0x10000; - buffer[j++] = 0xd800 + ((temp & 0xffc00) >> 10); - buffer[j++] = 0xdc00 + (temp & 0x3ff); - } else { - buffer[j++] = 0xfffd; - } - } - return buffer; -} +/// internal method +String decodeBigEndian(List? bytes, [int offset = 0, int? length]) { + final List codeUnits = + UtfbeDecoder(bytes, offset, length).decodeRemaining(); + final List result = _convertCodeUnitsToCodePoints(codeUnits); + return String.fromCharCodes(result); +} + +List _convertCodeUnitsToCodePoints( + List codeUnits, [ + int offset = 0, + int? length, +]) { + final UtfCodeUnitDecoder decoder = UtfCodeUnitDecoder( + ByteRange(codeUnits, offset, length), + ); + final List codePoints = List.filled( + decoder.byteRange.remaining, + 0, + growable: true, + ); + int i = 0; + while (decoder.moveNext) { + codePoints[i++] = decoder._current!; + } + if (i == codePoints.length) { + return codePoints; + } else { + final List cpt = List.filled(i, 0, growable: true); + cpt.setRange(0, i, codePoints); + return cpt; + } +} + +/// internal class +class UtfbeDecoder { + /// internal constructor + UtfbeDecoder(List? encodedBytes, [int offset = 0, int? length]) { + length = length ?? encodedBytes!.length - offset; + byteRange = ByteRange(encodedBytes, offset, length); + if (isBeBom(encodedBytes, offset, length)) { + byteRange.skip(2); + } + } + + /// internal field + late ByteRange byteRange; + + /// internal field + final int rcPoint = 0xfffd; + int? _current; + + /// internal property + int get remaining => (byteRange.remaining + 1) ~/ 2; + + /// internal property + bool get moveNext { + _current = null; + final int remaining = byteRange.remaining; + if (remaining == 0) { + _current = null; + return false; + } + if (remaining == 1) { + byteRange.moveNext; + _current = rcPoint; + return true; + } + _current = decode(); + return true; + } + + /// internal method + List decodeRemaining() { + final List codeunits = List.filled(remaining, 0, growable: true); + int i = 0; + while (moveNext) { + codeunits[i++] = _current!; + } + if (i == codeunits.length) { + return codeunits; + } else { + final List tcu = List.filled(i, 0, growable: true); + tcu.setRange(0, i, codeunits); + return tcu; + } + } + + /// internal method + bool isBeBom(List? encodedBytes, [int offset = 0, int? length]) { + final int end = length != null ? offset + length : encodedBytes!.length; + return (offset + 2) <= end && + encodedBytes![offset] == 0xfe && + encodedBytes[offset + 1] == 0xff; + } + + /// internal method + int decode() { + byteRange.moveNext; + final int first = byteRange.current!; + byteRange.moveNext; + final int next = byteRange.current!; + return (first << 8) + next; + } +} + +/// internal class +class ByteRange { + /// internal constructor + ByteRange(List? source, int offset, int? length) { + length = length ?? source!.length - offset; + _source = source; + _offset = offset - 1; + _length = length; + _end = offset + _length; + } + List? _source; + late int _offset; + late int _length; + late int _end; + + /// internal property + int? get current => _source![_offset]; + + /// internal property + bool get moveNext => ++_offset < _end; + + /// internal property + int get remaining => _end - _offset - 1; + + /// internal method + void skip([int count = 1]) { + _offset += count; + } + + /// internal method + void backup([int byte = 1]) { + _offset -= byte; + } +} + +/// internal class +class UtfCodeUnitDecoder { + /// internal constructor + UtfCodeUnitDecoder(this.byteRange); + + /// internal field + final ByteRange byteRange; + + /// internal field + final int rcPoint = 0xfffd; + int? _current; + + /// internal property + bool get moveNext { + _current = null; + if (!byteRange.moveNext) { + return false; + } + int value = byteRange.current!; + if (value < 0) { + _current = rcPoint; + } else if (value < 0xd800 || (value > 0xdfff && value <= 0xffff)) { + _current = value; + } else if (value < 0xdc00 && byteRange.moveNext) { + final int nextValue = byteRange.current!; + if (nextValue >= 0xdc00 && nextValue <= 0xdfff) { + value = (value - 0xd800) << 10; + value += 0x10000 + (nextValue - 0xdc00); + _current = value; + } else { + if (nextValue >= 0xd800 && nextValue < 0xdc00) { + byteRange.backup(); + } + _current = rcPoint; + } + } else { + _current = rcPoint; + } + return true; + } +} + +/// internal method +List encodeBigEndian(String content) { + final List codeUnits = _codePointsToCodeUnits(content.codeUnits); + final List encodedBytes = List.filled( + 2 * codeUnits.length, + 0, + growable: true, + ); + int i = 0; + for (final int value in codeUnits) { + encodedBytes[i++] = (value & 0xff00) >> 8; + encodedBytes[i++] = value & 0xff; + } + return encodedBytes; +} + +List _codePointsToCodeUnits(List codePoints) { + int eLength = 0; + for (int i = 0; i < codePoints.length; i++) { + final int value = codePoints[i]; + if ((value >= 0 && value < 0xd800) || (value > 0xdfff && value <= 0xffff)) { + eLength++; + } else if (value > 0xffff && value <= 0x10ffff) { + eLength += 2; + } else { + eLength++; + } + } + final List buffer = List.filled(eLength, 0, growable: true); + int j = 0; + for (int i = 0; i < codePoints.length; i++) { + final int value = codePoints[i]; + if ((value >= 0 && value < 0xd800) || (value > 0xdfff && value <= 0xffff)) { + buffer[j++] = value; + } else if (value > 0xffff && value <= 0x10ffff) { + final int temp = value - 0x10000; + buffer[j++] = 0xd800 + ((temp & 0xffc00) >> 10); + buffer[j++] = 0xdc00 + (temp & 0x3ff); + } else { + buffer[j++] = 0xfffd; + } + } + return buffer; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/enums.dart index e83a88334..5be8462ae 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/enums.dart @@ -1,108 +1,108 @@ -/// Specfies the status of the IPdfPrmitive. -/// Status is registered if it has a reference or else none. -enum PdfObjectStatus { - /// internal enumerator - none, - - /// internal enumerator - registered, -} - -/// Represents a type of an object. -enum PdfObjectType { - /// internal enumerator - free, - - /// internal enumerator - normal, - // ignore: unused_field - /// internal enumerator - packed, -} - -/// internal enumerator -enum PdfTokenType { - /// internal enumerator - unknown, - - /// internal enumerator - dictionaryStart, - - /// internal enumerator - dictionaryEnd, - - /// internal enumerator - streamStart, - - /// internal enumerator - streamEnd, - - /// internal enumerator - hexStringStart, - - /// internal enumerator - hexStringEnd, - - /// internal enumerator - string, - - /// internal enumerator - unicodeString, - - /// internal enumerator - number, - - /// internal enumerator - real, - - /// internal enumerator - name, - - /// internal enumerator - arrayStart, - - /// internal enumerator - arrayEnd, - - /// internal enumerator - reference, - - /// internal enumerator - objectStart, - - /// internal enumerator - objectEnd, - - /// internal enumerator - boolean, - - /// internal enumerator - hexDigit, - - /// internal enumerator - eof, - - /// internal enumerator - trailer, - - /// internal enumerator - startXRef, - - /// internal enumerator - xRef, - - /// internal enumerator - nullType, - - /// internal enumerator - objectType, - - /// internal enumerator - hexStringWeird, - - /// internal enumerator - hexStringWeirdEscape, - - /// internal enumerator - whiteSpace, -} +/// Specfies the status of the IPdfPrmitive. +/// Status is registered if it has a reference or else none. +enum PdfObjectStatus { + /// internal enumerator + none, + + /// internal enumerator + registered, +} + +/// Represents a type of an object. +enum PdfObjectType { + /// internal enumerator + free, + + /// internal enumerator + normal, + // ignore: unused_field + /// internal enumerator + packed, +} + +/// internal enumerator +enum PdfTokenType { + /// internal enumerator + unknown, + + /// internal enumerator + dictionaryStart, + + /// internal enumerator + dictionaryEnd, + + /// internal enumerator + streamStart, + + /// internal enumerator + streamEnd, + + /// internal enumerator + hexStringStart, + + /// internal enumerator + hexStringEnd, + + /// internal enumerator + string, + + /// internal enumerator + unicodeString, + + /// internal enumerator + number, + + /// internal enumerator + real, + + /// internal enumerator + name, + + /// internal enumerator + arrayStart, + + /// internal enumerator + arrayEnd, + + /// internal enumerator + reference, + + /// internal enumerator + objectStart, + + /// internal enumerator + objectEnd, + + /// internal enumerator + boolean, + + /// internal enumerator + hexDigit, + + /// internal enumerator + eof, + + /// internal enumerator + trailer, + + /// internal enumerator + startXRef, + + /// internal enumerator + xRef, + + /// internal enumerator + nullType, + + /// internal enumerator + objectType, + + /// internal enumerator + hexStringWeird, + + /// internal enumerator + hexStringWeirdEscape, + + /// internal enumerator + whiteSpace, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/object_info.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/object_info.dart index 4f18ef9a1..4b1a5813b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/object_info.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/object_info.dart @@ -1,71 +1,71 @@ -import '../../interfaces/pdf_interface.dart'; -import '../primitives/pdf_reference.dart'; - -/// internal class -class PdfObjectInfo { - //Constructors - /// internal constructor - PdfObjectInfo(IPdfPrimitive? obj, [PdfReference? reference]) { - if (obj == null) { - ArgumentError.notNull('obj'); - } else { - object = obj; - if (reference != null) { - this.reference = reference; - } - isModified = false; - } - } - - //Fields - /// internal field - IPdfPrimitive? object; - - /// internal field - PdfReference? reference; - - /// internal field - late bool isModified; - - //Properties - /// internal property - bool? get modified { - if (object is IPdfChangable) { - isModified |= (object! as IPdfChangable).changed!; - } - return isModified; - } - - //Implementation - /// internal method - void setReference(PdfReference reference) { - if (this.reference != null) { - throw ArgumentError.value( - this.reference, - 'The object has the reference bound to it.', - ); - } - this.reference = reference; - } - - /// internal method - Future setReferenceAsync(PdfReference reference) async { - if (this.reference != null) { - throw ArgumentError.value( - this.reference, - 'The object has the reference bound to it.', - ); - } - this.reference = reference; - } - - @override - String toString() { - String reference = ''; - if (this.reference != null) { - reference = this.reference.toString(); - } - reference += ' : ${object.runtimeType}'; - return reference; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../primitives/pdf_reference.dart'; + +/// internal class +class PdfObjectInfo { + //Constructors + /// internal constructor + PdfObjectInfo(IPdfPrimitive? obj, [PdfReference? reference]) { + if (obj == null) { + ArgumentError.notNull('obj'); + } else { + object = obj; + if (reference != null) { + this.reference = reference; + } + isModified = false; + } + } + + //Fields + /// internal field + IPdfPrimitive? object; + + /// internal field + PdfReference? reference; + + /// internal field + late bool isModified; + + //Properties + /// internal property + bool? get modified { + if (object is IPdfChangable) { + isModified |= (object! as IPdfChangable).changed!; + } + return isModified; + } + + //Implementation + /// internal method + void setReference(PdfReference reference) { + if (this.reference != null) { + throw ArgumentError.value( + this.reference, + 'The object has the reference bound to it.', + ); + } + this.reference = reference; + } + + /// internal method + Future setReferenceAsync(PdfReference reference) async { + if (this.reference != null) { + throw ArgumentError.value( + this.reference, + 'The object has the reference bound to it.', + ); + } + this.reference = reference; + } + + @override + String toString() { + String reference = ''; + if (this.reference != null) { + reference = this.reference.toString(); + } + reference += ' : ${object.runtimeType}'; + return reference; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_archive_stream.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_archive_stream.dart index 366c39dbe..6cd64ec9c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_archive_stream.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_archive_stream.dart @@ -1,137 +1,137 @@ -import 'dart:convert'; - -import '../../interfaces/pdf_interface.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_stream.dart'; -import '../security/pdf_encryptor.dart'; -import '../security/pdf_security.dart'; -import 'pdf_constants.dart'; -import 'pdf_writer.dart'; - -/// internal class -class PdfArchiveStream extends PdfStream { - // Constructor - /// internal constructor - PdfArchiveStream(PdfDocument? document) : super() { - ArgumentError.notNull('document'); - _document = document; - _objects = PdfBytesBuilder(); - _indices = {}; - _objectWriter = PdfWriter(null, _objects); - _objectWriter!.document = _document; - } - - // Fields - PdfDocument? _document; - IPdfWriter? _objectWriter; - late PdfBytesBuilder _objects; - Map? _indices; - late PdfArchiveStreamWriter _writer; - - // Properties - /// internal property - int get objCount { - if (_indices == null) { - return 0; - } else { - return _indices!.length; - } - } - - /// internal method - int getIndex(int? objNumber) { - return _indices!.values.toList().indexOf(objNumber); - } - - // Implementation - @override - void save(IPdfWriter? writer) { - _writer = PdfArchiveStreamWriter([]); - _saveIndices(); - this[PdfDictionaryProperties.first] = PdfNumber(_writer.position!); - _saveObjects(); - super.data = _writer._builder!.takeBytes(); - this[PdfDictionaryProperties.n] = PdfNumber(_indices!.length); - this[PdfDictionaryProperties.type] = PdfName('ObjStm'); - super.save(writer); - } - - void _saveIndices() { - for (final Object? position in _indices!.keys) { - if (position is int) { - _writer = PdfArchiveStreamWriter(_writer._builder!.takeBytes()); - _writer.write(_indices![position]); - _writer.write(PdfOperators.whiteSpace); - _writer.write(position); - _writer.write(PdfOperators.newLine); - } - } - } - - void _saveObjects() { - _writer._builder!.add(_objects.takeBytes()); - } - - /// internal method - void saveObject(IPdfPrimitive obj, PdfReference reference) { - final int? position = _objectWriter!.position; - _indices![position] = reference.objNum; - final PdfEncryptor encryptor = - PdfSecurityHelper.getHelper(_document!.security).encryptor; - final bool state = encryptor.encrypt; - encryptor.encrypt = false; - obj.save(_objectWriter); - encryptor.encrypt = state; - _objectWriter!.write(PdfOperators.newLine); - } - - /// internal method - Future saveObjectAsync( - IPdfPrimitive obj, - PdfReference reference, - ) async { - final int? position = _objectWriter!.position; - _indices![position] = reference.objNum; - final PdfEncryptor encryptor = - PdfSecurityHelper.getHelper(_document!.security).encryptor; - final bool state = encryptor.encrypt; - encryptor.encrypt = false; - obj.save(_objectWriter); - encryptor.encrypt = state; - _objectWriter!.write(PdfOperators.newLine); - } -} - -/// internal class -class PdfArchiveStreamWriter extends IPdfWriter { - // Constructor - /// internal constructor - PdfArchiveStreamWriter(List? data) { - _builder = PdfBytesBuilder(); - if (data != null) { - _builder!.add(data); - } - length = _builder!.length; - position = _builder!.length; - } - - //Fields - PdfBytesBuilder? _builder; - - @override - // ignore: avoid_renaming_method_parameters - void write(dynamic data) { - if (data is List) { - _builder!.add(data); - length = _builder!.length; - position = _builder!.length; - } else if (data is String) { - write(utf8.encode(data)); - } else if (data is int) { - write(data.toString()); - } - } -} +import 'dart:convert'; + +import '../../interfaces/pdf_interface.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_stream.dart'; +import '../security/pdf_encryptor.dart'; +import '../security/pdf_security.dart'; +import 'pdf_constants.dart'; +import 'pdf_writer.dart'; + +/// internal class +class PdfArchiveStream extends PdfStream { + // Constructor + /// internal constructor + PdfArchiveStream(PdfDocument? document) : super() { + ArgumentError.notNull('document'); + _document = document; + _objects = PdfBytesBuilder(); + _indices = {}; + _objectWriter = PdfWriter(null, _objects); + _objectWriter!.document = _document; + } + + // Fields + PdfDocument? _document; + IPdfWriter? _objectWriter; + late PdfBytesBuilder _objects; + Map? _indices; + late PdfArchiveStreamWriter _writer; + + // Properties + /// internal property + int get objCount { + if (_indices == null) { + return 0; + } else { + return _indices!.length; + } + } + + /// internal method + int getIndex(int? objNumber) { + return _indices!.values.toList().indexOf(objNumber); + } + + // Implementation + @override + void save(IPdfWriter? writer) { + _writer = PdfArchiveStreamWriter([]); + _saveIndices(); + this[PdfDictionaryProperties.first] = PdfNumber(_writer.position!); + _saveObjects(); + super.data = _writer._builder!.takeBytes(); + this[PdfDictionaryProperties.n] = PdfNumber(_indices!.length); + this[PdfDictionaryProperties.type] = PdfName('ObjStm'); + super.save(writer); + } + + void _saveIndices() { + for (final Object? position in _indices!.keys) { + if (position is int) { + _writer = PdfArchiveStreamWriter(_writer._builder!.takeBytes()); + _writer.write(_indices![position]); + _writer.write(PdfOperators.whiteSpace); + _writer.write(position); + _writer.write(PdfOperators.newLine); + } + } + } + + void _saveObjects() { + _writer._builder!.add(_objects.takeBytes()); + } + + /// internal method + void saveObject(IPdfPrimitive obj, PdfReference reference) { + final int? position = _objectWriter!.position; + _indices![position] = reference.objNum; + final PdfEncryptor encryptor = + PdfSecurityHelper.getHelper(_document!.security).encryptor; + final bool state = encryptor.encrypt; + encryptor.encrypt = false; + obj.save(_objectWriter); + encryptor.encrypt = state; + _objectWriter!.write(PdfOperators.newLine); + } + + /// internal method + Future saveObjectAsync( + IPdfPrimitive obj, + PdfReference reference, + ) async { + final int? position = _objectWriter!.position; + _indices![position] = reference.objNum; + final PdfEncryptor encryptor = + PdfSecurityHelper.getHelper(_document!.security).encryptor; + final bool state = encryptor.encrypt; + encryptor.encrypt = false; + obj.save(_objectWriter); + encryptor.encrypt = state; + _objectWriter!.write(PdfOperators.newLine); + } +} + +/// internal class +class PdfArchiveStreamWriter extends IPdfWriter { + // Constructor + /// internal constructor + PdfArchiveStreamWriter(List? data) { + _builder = PdfBytesBuilder(); + if (data != null) { + _builder!.add(data); + } + length = _builder!.length; + position = _builder!.length; + } + + //Fields + PdfBytesBuilder? _builder; + + @override + // ignore: avoid_renaming_method_parameters + void write(dynamic data) { + if (data is List) { + _builder!.add(data); + length = _builder!.length; + position = _builder!.length; + } else if (data is String) { + write(utf8.encode(data)); + } else if (data is int) { + write(data.toString()); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_constants.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_constants.dart index 19a832977..44e6a384d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_constants.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_constants.dart @@ -1,1031 +1,1031 @@ -/// PDF dictionary properties. -class PdfDictionaryProperties { - //Constants - /// internal field - static const String length = 'Length'; - - /// internal field - static const String type = 'Type'; - - /// internal field - static const String kids = 'Kids'; - - /// internal field - static const String count = 'Count'; - - /// internal field - static const String resources = 'Resources'; - - /// internal field - static const String rotate = 'Rotate'; - - /// internal field - static const String mediaBox = 'MediaBox'; - - /// internal field - static const String pages = 'Pages'; - - /// internal field - static const String parent = 'Parent'; - - /// internal field - static const String root = 'Root'; - - /// internal field - static const String flateDecode = 'FlateDecode'; - - /// internal field - static const String filter = 'Filter'; - - /// internal field - static const String size = 'Size'; - - /// internal field - static const String contents = 'Contents'; - - /// internal field - static const String procSet = 'ProcSet'; - - /// internal field - static const String k = 'K'; - - /// internal field - static const String s = 'S'; - - /// internal field - static const String i = 'I'; - - /// internal field - static const String group = 'Group'; - - /// internal field - static const String bBox = 'BBox'; - - /// internal field - static const String xObject = 'XObject'; - - /// internal field - static const String subtype = 'Subtype'; - - /// internal field - static const String form = 'Form'; - - /// internal field - static const String font = 'Font'; - - /// internal field - static const String type1 = 'Type1'; - - /// internal field - static const String baseFont = 'BaseFont'; - - /// internal field - static const String encoding = 'Encoding'; - - /// internal field - static const String pdf = 'PDF'; - - /// internal field - static const String text = 'Text'; - - /// internal field - static const String grayScaleImage = 'ImageB'; - - /// internal field - static const String colorImage = 'ImageC'; - - /// internal field - static const String indexedImage = 'ImageI'; - - /// internal field - static const String type0 = 'Type0'; - - /// internal field - static const String descendantFonts = 'DescendantFonts'; - - /// internal field - static const String dw = 'DW'; - - /// internal field - static const String cidFontType2 = 'CIDFontType2'; - - /// internal field - static const String w = 'W'; - - /// internal field - static const String cidSystemInfo = 'CIDSystemInfo'; - - /// internal field - static const String registry = 'Registry'; - - /// internal field - static const String ordering = 'Ordering'; - - /// internal field - static const String supplement = 'Supplement'; - - /// internal field - static const String fontBBox = 'FontBBox'; - - /// internal field - static const String fontName = 'FontName'; - - /// internal field - static const String italicAngle = 'ItalicAngle'; - - /// internal field - static const String missingWidth = 'MissingWidth'; - - /// internal field - static const String fontDescriptor = 'FontDescriptor'; - - /// internal field - static const String ascent = 'Ascent'; - - /// internal field - static const String descent = 'Descent'; - - /// internal field - static const String flags = 'Flags'; - - /// internal field - static const String stemV = 'StemV'; - - /// internal field - static const String stemH = 'StemH'; - - /// internal field - static const String maxWidth = 'MaxWidth'; - - /// internal field - static const String avgWidth = 'AvgWidth'; - - /// internal field - static const String capHeight = 'CapHeight'; - - /// internal field - static const String xHeight = 'XHeight'; - - /// internal field - static const String leading = 'Leading'; - - /// internal field - static const String cidToGIDMap = 'CIDToGIDMap'; - - /// internal field - static const String identity = 'Identity'; - - /// internal field - static const String fontFile2 = 'FontFile2'; - - /// internal field - static const String identityH = 'Identity-H'; - - /// internal field - static const String toUnicode = 'ToUnicode'; - - /// internal field - static const String image = 'Image'; - - /// internal field - static const String width = 'Width'; - - /// internal field - static const String height = 'Height'; - - /// internal field - static const String bitsPerComponent = 'BitsPerComponent'; - - /// internal field - static const String dctDecode = 'DCTDecode'; - - /// internal field - static const String decodeParms = 'DecodeParms'; - - /// internal field - static const String deviceRGB = 'DeviceRGB'; - - /// internal field - static const String deviceGray = 'DeviceGray'; - - /// internal field - static const String deviceCMYK = 'DeviceCMYK'; - - /// internal field - static const String columns = 'Columns'; - - /// internal field - static const String blackIs1 = 'BlackIs1'; - - /// internal field - static const String predictor = 'Predictor'; - - /// internal field - static const String colorSpace = 'ColorSpace'; - - /// internal field - static const String decode = 'Decode'; - - /// internal field - static const String indexed = 'Indexed'; - - /// internal field - static const String gamma = 'Gamma'; - - /// internal field - static const String matrix = 'Matrix'; - - /// internal field - static const String whitePoint = 'WhitePoint'; - - /// internal field - static const String calRGB = 'CalRGB'; - - /// internal field - static const String sMask = 'SMask'; - - /// internal field - static const String colors = 'Colors'; - - /// internal field - static const String stroke = 'CA'; - - /// internal field - static const String fill = 'ca'; - - /// internal field - static const String bm = 'BM'; - - /// internal field - static const String extGState = 'ExtGState'; - - /// internal field - static const String rect = 'Rect'; - - /// internal field - static const String annots = 'Annots'; - - /// internal field - static const String annot = 'Annot'; - - /// internal field - static const String border = 'Border'; - - /// internal field - static const String ic = 'IC'; - - /// internal field - static const String link = 'Link'; - - /// internal field - static const String h = 'H'; - - /// internal field - static const String next = 'Next'; - - /// internal field - static const String action = 'Action'; - - /// internal field - static const String uri = 'URI'; - - /// internal field - static const String a = 'A'; - - /// internal field - static const String p = 'P'; - - /// internal field - static const String xyz = 'XYZ'; - - /// internal field - static const String fit = 'Fit'; - - /// internal field - static const String fitR = 'FitR'; - - /// internal field - static const String fitH = 'FitH'; - - /// internal field - static const String dest = 'Dest'; - - /// internal field - static const String f = 'F'; - - /// internal field - static const String title = 'Title'; - - /// internal field - static const String prev = 'Prev'; - - /// internal field - static const String d = 'D'; - - /// internal field - static const String goTo = 'GoTo'; - - /// internal field - static const String first = 'First'; - - /// internal field - static const String last = 'Last'; - - /// internal field - static const String outlines = 'Outlines'; - - /// internal field - static const String c = 'C'; - - /// internal field - static const String names = 'Names'; - - /// internal field - static const String dests = 'Dests'; - - /// internal field - static const String cropBox = 'CropBox'; - - /// internal field - static const String crossReference = 'xref'; - - /// internal field - static const String obj = 'obj'; - - /// internal field - static const String u = 'U'; - - /// internal field - static const String o = 'O'; - - /// internal field - static const String catalog = 'Catalog'; - - /// internal field - static const String version = 'Version'; - - /// internal field - static const String index = 'Index'; - - /// internal field - static const String crypt = 'Crypt'; - - /// internal field - static const String runLengthDecode = 'RunLengthDecode'; - - /// internal field - static const String flateDecodeShort = 'Fl'; - - /// internal field - static const String ascii85Decode = 'ASCII85Decode'; - - /// internal field - static const String ascii85DecodeShort = 'A85'; - - /// internal field - static const String n = 'N'; - - /// internal field - static const String name = 'Name'; - - /// internal field - static const String encrypt = 'Encrypt'; - - /// internal field - static const String differences = 'Differences'; - - /// internal field - static const String fields = 'Fields'; - - /// internal field - static const String fitBH = 'FitBH'; - - /// internal field - static const String circle = 'Circle'; - - /// internal field - static const String square = 'Square'; - - /// internal field - static const String line = 'Line'; - - /// internal field - static const String polygon = 'Polygon'; - - /// internal field - static const String iC = 'IC'; - - /// internal field - static const String author = 'Author'; - - /// internal field - static const String subj = 'Subj'; - - /// internal field - static const String subject = 'Subject'; - - /// internal field - static const String bs = 'BS'; - - /// internal field - static const String ap = 'AP'; - - /// internal field - static const String t = 'T'; - - /// internal field - static const String ca = 'CA'; - - /// internal field - static const String modificationDate = 'ModDate'; - - /// internal field - static const String m = 'M'; - - /// internal field - static const String popup = 'Popup'; - - /// internal field - static const String ll = 'LL'; - - /// internal field - static const String l = 'L'; - - /// internal field - static const String it = 'IT'; - - /// internal field - static const String cap = 'Cap'; - - /// internal field - static const String lle = 'LLE'; - - /// internal field - static const String le = 'LE'; - - /// internal field - static const String cp = 'CP'; - - /// internal field - static const String vertices = 'Vertices'; - - /// internal field - static const String firstChar = 'FirstChar'; - - /// internal field - static const String lastChar = 'LastChar'; - - /// internal field - static const String widths = 'Widths'; - - /// internal field - static const String be = 'BE'; - - /// internal field - static const String rd = 'RD'; - - /// internal field - static const String measure = 'Measure'; - - /// internal field - static const String llo = 'LLO'; - - /// internal field - static const String ft = 'FT'; - - /// internal field - static const String v = 'V'; - - /// internal field - static const String creationDate = 'CreationDate'; - - /// internal field - static const String keywords = 'Keywords'; - - /// internal field - static const String creator = 'Creator'; - - /// internal field - static const String producer = 'Producer'; - - /// internal field - static const String info = 'Info'; - - /// internal field - static const String r = 'R'; - - /// internal field - static const String standard = 'Standard'; - - /// internal field - static const String id = 'ID'; - - /// internal field - static const String visible = 'Visible'; - - /// internal field - static const String ocProperties = 'OCProperties'; - - /// internal field - static const String layerID = 'LayerID'; - - /// internal field - static const String properties = 'Properties'; - - /// internal field - static const String ocgOrder = 'Order'; - - /// internal field - static const String ocgOn = 'On'; - - /// internal field - static const String ocgOff = 'OFF'; - - /// internal field - static const String usageApplication = 'AS'; - - /// internal field - static const String category = 'Category'; - - /// internal field - static const String event = 'Event'; - - /// internal field - static const String ocg = 'OCGs'; - - /// internal field - static const String usage = 'Usage'; - - /// internal field - static const String print = 'Print'; - - /// internal field - static const String defaultView = 'D'; - - /// internal field - static const String cf = 'CF'; - - /// internal field - static const String cfm = 'CFM'; - - /// internal field - static const String stmF = 'StmF'; - - /// internal field - static const String strF = 'StrF'; - - /// internal field - static const String stdCF = 'StdCF'; - - /// internal field - static const String ue = 'UE'; - - /// internal field - static const String oe = 'OE'; - - /// internal field - static const String perms = 'Perms'; - - /// internal field - static const String aesv2 = 'AESV2'; - - /// internal field - static const String aesv3 = 'AESV3'; - - /// internal field - static const String authEvent = 'AuthEvent'; - - /// internal field - static const String docOpen = 'DocOpen'; - - /// internal field - static const String metadata = 'Metadata'; - - /// internal field - static const String xml = 'XML'; - - /// internal field - static const String encryptMetadata = 'EncryptMetadata'; - - /// internal field - static const String cidSet = 'CIDSet'; - - /// internal field - static const String embeddedFile = 'EmbeddedFile'; - - /// internal field - static const String params = 'Params'; - - /// internal field - static const String filespec = 'Filespec'; - - /// internal field - static const String description = 'Desc'; - - /// internal field - static const String uf = 'UF'; - - /// internal field - static const String ef = 'EF'; - - /// internal field - static const String embeddedFiles = 'EmbeddedFiles'; - - /// internal field - /// internal field - static const String afRelationship = 'AFRelationship'; - - /// internal field - static const String limits = 'Limits'; - - /// internal field - static const String ocgLock = 'Locked'; - - /// internal field - static const String af = 'AF'; - - /// internal field - static const String fs = 'FS'; - - /// internal field - static const String eff = 'EFF'; - - /// internal field - static const String cryptFilter = 'CryptFilter'; - - /// internal field - static const String efOpen = 'EFOpen'; - - /// internal field - static const String dl = 'DL'; - - /// internal field - static const String needAppearances = 'NeedAppearances'; - - /// internal field - static const String dr = 'DR'; - - /// internal field - static const String q = 'Q'; - - /// internal field - static const String bc = 'BC'; - - /// internal field - static const String bg = 'BG'; - - /// internal field - static const String acroForm = 'AcroForm'; - - /// internal field - static const String sig = 'Sig'; - - /// internal field - static const String mk = 'MK'; - - /// internal field - static const String da = 'DA'; - - /// internal field - static const String maxLen = 'MaxLen'; - - /// internal field - static const String tx = 'Tx'; - - /// internal field - static const String widget = 'Widget'; - - /// internal field - static const String fieldFlags = 'Ff'; - - /// internal field - static const String tabs = 'Tabs'; - - /// internal field - static const String tm = 'TM'; - - /// internal field - static const String tu = 'TU'; - - /// internal field - static const String dv = 'DV'; - - /// internal field - static const String btn = 'Btn'; - - /// internal field - static const String yes = 'Yes'; - - /// internal field - static const String off = 'Off'; - - /// internal field - static const String opt = 'Opt'; - - /// internal field - static const String ch = 'Ch'; - - /// internal field - static const String e = 'E'; - - /// internal field - static const String x = 'X'; - - /// internal field - static const String fo = 'Fo'; - - /// internal field - static const String bl = 'Bl'; - - /// internal field - static const String js = 'JS'; - - /// internal field - static const String javaScript = 'JavaScript'; - - /// internal field - static const String aa = 'AA'; - - /// internal field - static const String submitForm = 'SubmitForm'; - - /// internal field - static const String resetForm = 'ResetForm'; - - /// internal field - static const String sigFlags = 'SigFlags'; - - /// internal field - static const String docMDP = 'DocMDP'; - - /// internal field - static const String transformMethod = 'TransformMethod'; - - /// internal field - static const String subFilter = 'SubFilter'; - - /// internal field - static const String reason = 'Reason'; - - /// internal field - static const String location = 'Location'; - - /// internal field - static const String contactInfo = 'ContactInfo'; - - /// internal field - static const String byteRange = 'ByteRange'; - - /// internal field - static const String reference = 'Reference'; - - /// internal field - static const String sigRef = 'SigRef'; - - /// internal field - static const String data = 'Data'; - - /// internal field - static const String xfdf = 'xfdf'; - - /// internal field - static const String field = 'field'; - - /// internal field - static const String value = 'value'; - - /// internal field - static const String quadPoints = 'QuadPoints'; - - /// internal field - static const String highlight = 'Highlight'; - - /// internal field - static const String underline = 'Underline'; - - /// internal field - static const String strikeOut = 'StrikeOut'; - - /// internal field - static const String squiggly = 'Squiggly'; - - /// internal field - static const String open = 'Open'; - - /// internal field - static const String irt = 'IRT'; - - /// internal field - static const String b = 'B'; - - /// internal field - static const String nm = 'NM'; - - /// internal field - static const String cl = 'CL'; - - /// internal field - static const String ds = 'DS'; - - /// internal field - static const String rc = 'RC'; - - /// internal field - static const String repeat = 'Repeat'; - - /// internal field - static const String overlayText = 'OverlayText'; - - /// internal field - static const String inkList = 'InkList'; - - /// internal field - static const String customData = 'CustomData'; - - /// internal field - static const String sound = 'Sound'; - - /// internal field - static const String rt = 'RT'; - - /// internal field - static const String ss = 'SS'; - - /// internal field - static const String fd = 'FD'; - - /// internal field - static const String targetUnitConversion = 'TargetUnitConversion'; - - /// internal field - static const String dss = 'DSS'; - - /// internal field - static const String ocsps = 'OCSPs'; - - /// internal field - static const String crls = 'CRLs'; - - /// internal field - static const String vri = 'VRI'; - - /// internal field - static const String ocsp = 'OCSP'; - - /// internal field - static const String crl = 'CRL'; - - /// internal field - static const String certs = 'Certs'; -} - -/// Class of string PDF common operators. -class PdfOperators { - //Constants - /// internal field - static const String obj = 'obj'; - - /// internal field - static const String endobj = 'endobj'; - - /// internal field - static const String newLine = '\r\n'; - - /// internal field - static const String whiteSpace = ' '; - - /// internal field - static const String crossReference = 'xref'; - - /// internal field - static const String f = 'f'; - - /// internal field - static const String n = 'n'; - - /// internal field - static const String trailer = 'trailer'; - - /// internal field - static const String startCrossReference = 'startxref'; - - /// internal field - static const String endOfFileMarker = '%%EOF'; - - /// internal field - static const String saveState = 'q'; - - /// internal field - static const String restoreState = 'Q'; - - /// internal field - static const String currentMatrix = 'cm'; - - /// internal field - static const String transformationMatrix = 'Tm'; - - /// internal field - static const String appendRectangle = 're'; - - /// internal field - static const String closePath = 'h'; - - /// internal field - static const String clipPath = 'W'; - - /// internal field - static const String evenOdd = '*'; - - /// internal field - static const String endPath = 'n'; - - /// internal field - static const String setLineWidth = 'w'; - - /// internal field - static const String setLineCapStyle = 'J'; - - /// internal field - static const String setLineJoinStyle = 'j'; - - /// internal field - static const String setMiterLimit = 'M'; - - /// internal field - static const String setDashPattern = 'd'; - - /// internal field - static const String setRenderingMode = 'Tr'; - - /// internal field - static const String setCharacterSpace = 'Tc'; - - /// internal field - static const String setWordSpace = 'Tw'; - - /// internal field - static const String beginText = 'BT'; - - /// internal field - static const String selectColorSpaceForStroking = 'CS'; - - /// internal field - static const String selectColorSpaceForNonStroking = 'cs'; - - /// internal field - static const String setFont = 'Tf'; - - /// internal field - static const String setCoords = 'Td'; - - /// internal field - static const String setTextOnNewLine = "'"; - - /// internal field - static const String endText = 'ET'; - - /// internal field - static const String setTextScaling = 'Tz'; - - /// internal field - static const String setTextLeading = 'TL'; - - /// internal field - static const String beginPath = 'm'; - - /// internal field - static const String appendLineSegment = 'l'; - - /// internal field - static const String fill = 'f'; - - /// internal field - static const String stroke = 'S'; - - /// internal field - static const String closeStrokePath = 's'; - - /// internal field - static const String fillStroke = 'B'; - - /// internal field - static const String closeFillStrokePath = 'b'; - - /// internal field - static const String paintXObject = 'Do'; - - /// internal field - static const String goToNextLine = 'T*'; - - /// internal field - static const String setText = 'Tj'; - - /// internal field - static const String setGraphicsState = 'gs'; - - /// internal field - static const String appendBezierCurve = 'c'; - - /// internal field - static const String slash = '/'; -} +/// PDF dictionary properties. +class PdfDictionaryProperties { + //Constants + /// internal field + static const String length = 'Length'; + + /// internal field + static const String type = 'Type'; + + /// internal field + static const String kids = 'Kids'; + + /// internal field + static const String count = 'Count'; + + /// internal field + static const String resources = 'Resources'; + + /// internal field + static const String rotate = 'Rotate'; + + /// internal field + static const String mediaBox = 'MediaBox'; + + /// internal field + static const String pages = 'Pages'; + + /// internal field + static const String parent = 'Parent'; + + /// internal field + static const String root = 'Root'; + + /// internal field + static const String flateDecode = 'FlateDecode'; + + /// internal field + static const String filter = 'Filter'; + + /// internal field + static const String size = 'Size'; + + /// internal field + static const String contents = 'Contents'; + + /// internal field + static const String procSet = 'ProcSet'; + + /// internal field + static const String k = 'K'; + + /// internal field + static const String s = 'S'; + + /// internal field + static const String i = 'I'; + + /// internal field + static const String group = 'Group'; + + /// internal field + static const String bBox = 'BBox'; + + /// internal field + static const String xObject = 'XObject'; + + /// internal field + static const String subtype = 'Subtype'; + + /// internal field + static const String form = 'Form'; + + /// internal field + static const String font = 'Font'; + + /// internal field + static const String type1 = 'Type1'; + + /// internal field + static const String baseFont = 'BaseFont'; + + /// internal field + static const String encoding = 'Encoding'; + + /// internal field + static const String pdf = 'PDF'; + + /// internal field + static const String text = 'Text'; + + /// internal field + static const String grayScaleImage = 'ImageB'; + + /// internal field + static const String colorImage = 'ImageC'; + + /// internal field + static const String indexedImage = 'ImageI'; + + /// internal field + static const String type0 = 'Type0'; + + /// internal field + static const String descendantFonts = 'DescendantFonts'; + + /// internal field + static const String dw = 'DW'; + + /// internal field + static const String cidFontType2 = 'CIDFontType2'; + + /// internal field + static const String w = 'W'; + + /// internal field + static const String cidSystemInfo = 'CIDSystemInfo'; + + /// internal field + static const String registry = 'Registry'; + + /// internal field + static const String ordering = 'Ordering'; + + /// internal field + static const String supplement = 'Supplement'; + + /// internal field + static const String fontBBox = 'FontBBox'; + + /// internal field + static const String fontName = 'FontName'; + + /// internal field + static const String italicAngle = 'ItalicAngle'; + + /// internal field + static const String missingWidth = 'MissingWidth'; + + /// internal field + static const String fontDescriptor = 'FontDescriptor'; + + /// internal field + static const String ascent = 'Ascent'; + + /// internal field + static const String descent = 'Descent'; + + /// internal field + static const String flags = 'Flags'; + + /// internal field + static const String stemV = 'StemV'; + + /// internal field + static const String stemH = 'StemH'; + + /// internal field + static const String maxWidth = 'MaxWidth'; + + /// internal field + static const String avgWidth = 'AvgWidth'; + + /// internal field + static const String capHeight = 'CapHeight'; + + /// internal field + static const String xHeight = 'XHeight'; + + /// internal field + static const String leading = 'Leading'; + + /// internal field + static const String cidToGIDMap = 'CIDToGIDMap'; + + /// internal field + static const String identity = 'Identity'; + + /// internal field + static const String fontFile2 = 'FontFile2'; + + /// internal field + static const String identityH = 'Identity-H'; + + /// internal field + static const String toUnicode = 'ToUnicode'; + + /// internal field + static const String image = 'Image'; + + /// internal field + static const String width = 'Width'; + + /// internal field + static const String height = 'Height'; + + /// internal field + static const String bitsPerComponent = 'BitsPerComponent'; + + /// internal field + static const String dctDecode = 'DCTDecode'; + + /// internal field + static const String decodeParms = 'DecodeParms'; + + /// internal field + static const String deviceRGB = 'DeviceRGB'; + + /// internal field + static const String deviceGray = 'DeviceGray'; + + /// internal field + static const String deviceCMYK = 'DeviceCMYK'; + + /// internal field + static const String columns = 'Columns'; + + /// internal field + static const String blackIs1 = 'BlackIs1'; + + /// internal field + static const String predictor = 'Predictor'; + + /// internal field + static const String colorSpace = 'ColorSpace'; + + /// internal field + static const String decode = 'Decode'; + + /// internal field + static const String indexed = 'Indexed'; + + /// internal field + static const String gamma = 'Gamma'; + + /// internal field + static const String matrix = 'Matrix'; + + /// internal field + static const String whitePoint = 'WhitePoint'; + + /// internal field + static const String calRGB = 'CalRGB'; + + /// internal field + static const String sMask = 'SMask'; + + /// internal field + static const String colors = 'Colors'; + + /// internal field + static const String stroke = 'CA'; + + /// internal field + static const String fill = 'ca'; + + /// internal field + static const String bm = 'BM'; + + /// internal field + static const String extGState = 'ExtGState'; + + /// internal field + static const String rect = 'Rect'; + + /// internal field + static const String annots = 'Annots'; + + /// internal field + static const String annot = 'Annot'; + + /// internal field + static const String border = 'Border'; + + /// internal field + static const String ic = 'IC'; + + /// internal field + static const String link = 'Link'; + + /// internal field + static const String h = 'H'; + + /// internal field + static const String next = 'Next'; + + /// internal field + static const String action = 'Action'; + + /// internal field + static const String uri = 'URI'; + + /// internal field + static const String a = 'A'; + + /// internal field + static const String p = 'P'; + + /// internal field + static const String xyz = 'XYZ'; + + /// internal field + static const String fit = 'Fit'; + + /// internal field + static const String fitR = 'FitR'; + + /// internal field + static const String fitH = 'FitH'; + + /// internal field + static const String dest = 'Dest'; + + /// internal field + static const String f = 'F'; + + /// internal field + static const String title = 'Title'; + + /// internal field + static const String prev = 'Prev'; + + /// internal field + static const String d = 'D'; + + /// internal field + static const String goTo = 'GoTo'; + + /// internal field + static const String first = 'First'; + + /// internal field + static const String last = 'Last'; + + /// internal field + static const String outlines = 'Outlines'; + + /// internal field + static const String c = 'C'; + + /// internal field + static const String names = 'Names'; + + /// internal field + static const String dests = 'Dests'; + + /// internal field + static const String cropBox = 'CropBox'; + + /// internal field + static const String crossReference = 'xref'; + + /// internal field + static const String obj = 'obj'; + + /// internal field + static const String u = 'U'; + + /// internal field + static const String o = 'O'; + + /// internal field + static const String catalog = 'Catalog'; + + /// internal field + static const String version = 'Version'; + + /// internal field + static const String index = 'Index'; + + /// internal field + static const String crypt = 'Crypt'; + + /// internal field + static const String runLengthDecode = 'RunLengthDecode'; + + /// internal field + static const String flateDecodeShort = 'Fl'; + + /// internal field + static const String ascii85Decode = 'ASCII85Decode'; + + /// internal field + static const String ascii85DecodeShort = 'A85'; + + /// internal field + static const String n = 'N'; + + /// internal field + static const String name = 'Name'; + + /// internal field + static const String encrypt = 'Encrypt'; + + /// internal field + static const String differences = 'Differences'; + + /// internal field + static const String fields = 'Fields'; + + /// internal field + static const String fitBH = 'FitBH'; + + /// internal field + static const String circle = 'Circle'; + + /// internal field + static const String square = 'Square'; + + /// internal field + static const String line = 'Line'; + + /// internal field + static const String polygon = 'Polygon'; + + /// internal field + static const String iC = 'IC'; + + /// internal field + static const String author = 'Author'; + + /// internal field + static const String subj = 'Subj'; + + /// internal field + static const String subject = 'Subject'; + + /// internal field + static const String bs = 'BS'; + + /// internal field + static const String ap = 'AP'; + + /// internal field + static const String t = 'T'; + + /// internal field + static const String ca = 'CA'; + + /// internal field + static const String modificationDate = 'ModDate'; + + /// internal field + static const String m = 'M'; + + /// internal field + static const String popup = 'Popup'; + + /// internal field + static const String ll = 'LL'; + + /// internal field + static const String l = 'L'; + + /// internal field + static const String it = 'IT'; + + /// internal field + static const String cap = 'Cap'; + + /// internal field + static const String lle = 'LLE'; + + /// internal field + static const String le = 'LE'; + + /// internal field + static const String cp = 'CP'; + + /// internal field + static const String vertices = 'Vertices'; + + /// internal field + static const String firstChar = 'FirstChar'; + + /// internal field + static const String lastChar = 'LastChar'; + + /// internal field + static const String widths = 'Widths'; + + /// internal field + static const String be = 'BE'; + + /// internal field + static const String rd = 'RD'; + + /// internal field + static const String measure = 'Measure'; + + /// internal field + static const String llo = 'LLO'; + + /// internal field + static const String ft = 'FT'; + + /// internal field + static const String v = 'V'; + + /// internal field + static const String creationDate = 'CreationDate'; + + /// internal field + static const String keywords = 'Keywords'; + + /// internal field + static const String creator = 'Creator'; + + /// internal field + static const String producer = 'Producer'; + + /// internal field + static const String info = 'Info'; + + /// internal field + static const String r = 'R'; + + /// internal field + static const String standard = 'Standard'; + + /// internal field + static const String id = 'ID'; + + /// internal field + static const String visible = 'Visible'; + + /// internal field + static const String ocProperties = 'OCProperties'; + + /// internal field + static const String layerID = 'LayerID'; + + /// internal field + static const String properties = 'Properties'; + + /// internal field + static const String ocgOrder = 'Order'; + + /// internal field + static const String ocgOn = 'On'; + + /// internal field + static const String ocgOff = 'OFF'; + + /// internal field + static const String usageApplication = 'AS'; + + /// internal field + static const String category = 'Category'; + + /// internal field + static const String event = 'Event'; + + /// internal field + static const String ocg = 'OCGs'; + + /// internal field + static const String usage = 'Usage'; + + /// internal field + static const String print = 'Print'; + + /// internal field + static const String defaultView = 'D'; + + /// internal field + static const String cf = 'CF'; + + /// internal field + static const String cfm = 'CFM'; + + /// internal field + static const String stmF = 'StmF'; + + /// internal field + static const String strF = 'StrF'; + + /// internal field + static const String stdCF = 'StdCF'; + + /// internal field + static const String ue = 'UE'; + + /// internal field + static const String oe = 'OE'; + + /// internal field + static const String perms = 'Perms'; + + /// internal field + static const String aesv2 = 'AESV2'; + + /// internal field + static const String aesv3 = 'AESV3'; + + /// internal field + static const String authEvent = 'AuthEvent'; + + /// internal field + static const String docOpen = 'DocOpen'; + + /// internal field + static const String metadata = 'Metadata'; + + /// internal field + static const String xml = 'XML'; + + /// internal field + static const String encryptMetadata = 'EncryptMetadata'; + + /// internal field + static const String cidSet = 'CIDSet'; + + /// internal field + static const String embeddedFile = 'EmbeddedFile'; + + /// internal field + static const String params = 'Params'; + + /// internal field + static const String filespec = 'Filespec'; + + /// internal field + static const String description = 'Desc'; + + /// internal field + static const String uf = 'UF'; + + /// internal field + static const String ef = 'EF'; + + /// internal field + static const String embeddedFiles = 'EmbeddedFiles'; + + /// internal field + /// internal field + static const String afRelationship = 'AFRelationship'; + + /// internal field + static const String limits = 'Limits'; + + /// internal field + static const String ocgLock = 'Locked'; + + /// internal field + static const String af = 'AF'; + + /// internal field + static const String fs = 'FS'; + + /// internal field + static const String eff = 'EFF'; + + /// internal field + static const String cryptFilter = 'CryptFilter'; + + /// internal field + static const String efOpen = 'EFOpen'; + + /// internal field + static const String dl = 'DL'; + + /// internal field + static const String needAppearances = 'NeedAppearances'; + + /// internal field + static const String dr = 'DR'; + + /// internal field + static const String q = 'Q'; + + /// internal field + static const String bc = 'BC'; + + /// internal field + static const String bg = 'BG'; + + /// internal field + static const String acroForm = 'AcroForm'; + + /// internal field + static const String sig = 'Sig'; + + /// internal field + static const String mk = 'MK'; + + /// internal field + static const String da = 'DA'; + + /// internal field + static const String maxLen = 'MaxLen'; + + /// internal field + static const String tx = 'Tx'; + + /// internal field + static const String widget = 'Widget'; + + /// internal field + static const String fieldFlags = 'Ff'; + + /// internal field + static const String tabs = 'Tabs'; + + /// internal field + static const String tm = 'TM'; + + /// internal field + static const String tu = 'TU'; + + /// internal field + static const String dv = 'DV'; + + /// internal field + static const String btn = 'Btn'; + + /// internal field + static const String yes = 'Yes'; + + /// internal field + static const String off = 'Off'; + + /// internal field + static const String opt = 'Opt'; + + /// internal field + static const String ch = 'Ch'; + + /// internal field + static const String e = 'E'; + + /// internal field + static const String x = 'X'; + + /// internal field + static const String fo = 'Fo'; + + /// internal field + static const String bl = 'Bl'; + + /// internal field + static const String js = 'JS'; + + /// internal field + static const String javaScript = 'JavaScript'; + + /// internal field + static const String aa = 'AA'; + + /// internal field + static const String submitForm = 'SubmitForm'; + + /// internal field + static const String resetForm = 'ResetForm'; + + /// internal field + static const String sigFlags = 'SigFlags'; + + /// internal field + static const String docMDP = 'DocMDP'; + + /// internal field + static const String transformMethod = 'TransformMethod'; + + /// internal field + static const String subFilter = 'SubFilter'; + + /// internal field + static const String reason = 'Reason'; + + /// internal field + static const String location = 'Location'; + + /// internal field + static const String contactInfo = 'ContactInfo'; + + /// internal field + static const String byteRange = 'ByteRange'; + + /// internal field + static const String reference = 'Reference'; + + /// internal field + static const String sigRef = 'SigRef'; + + /// internal field + static const String data = 'Data'; + + /// internal field + static const String xfdf = 'xfdf'; + + /// internal field + static const String field = 'field'; + + /// internal field + static const String value = 'value'; + + /// internal field + static const String quadPoints = 'QuadPoints'; + + /// internal field + static const String highlight = 'Highlight'; + + /// internal field + static const String underline = 'Underline'; + + /// internal field + static const String strikeOut = 'StrikeOut'; + + /// internal field + static const String squiggly = 'Squiggly'; + + /// internal field + static const String open = 'Open'; + + /// internal field + static const String irt = 'IRT'; + + /// internal field + static const String b = 'B'; + + /// internal field + static const String nm = 'NM'; + + /// internal field + static const String cl = 'CL'; + + /// internal field + static const String ds = 'DS'; + + /// internal field + static const String rc = 'RC'; + + /// internal field + static const String repeat = 'Repeat'; + + /// internal field + static const String overlayText = 'OverlayText'; + + /// internal field + static const String inkList = 'InkList'; + + /// internal field + static const String customData = 'CustomData'; + + /// internal field + static const String sound = 'Sound'; + + /// internal field + static const String rt = 'RT'; + + /// internal field + static const String ss = 'SS'; + + /// internal field + static const String fd = 'FD'; + + /// internal field + static const String targetUnitConversion = 'TargetUnitConversion'; + + /// internal field + static const String dss = 'DSS'; + + /// internal field + static const String ocsps = 'OCSPs'; + + /// internal field + static const String crls = 'CRLs'; + + /// internal field + static const String vri = 'VRI'; + + /// internal field + static const String ocsp = 'OCSP'; + + /// internal field + static const String crl = 'CRL'; + + /// internal field + static const String certs = 'Certs'; +} + +/// Class of string PDF common operators. +class PdfOperators { + //Constants + /// internal field + static const String obj = 'obj'; + + /// internal field + static const String endobj = 'endobj'; + + /// internal field + static const String newLine = '\r\n'; + + /// internal field + static const String whiteSpace = ' '; + + /// internal field + static const String crossReference = 'xref'; + + /// internal field + static const String f = 'f'; + + /// internal field + static const String n = 'n'; + + /// internal field + static const String trailer = 'trailer'; + + /// internal field + static const String startCrossReference = 'startxref'; + + /// internal field + static const String endOfFileMarker = '%%EOF'; + + /// internal field + static const String saveState = 'q'; + + /// internal field + static const String restoreState = 'Q'; + + /// internal field + static const String currentMatrix = 'cm'; + + /// internal field + static const String transformationMatrix = 'Tm'; + + /// internal field + static const String appendRectangle = 're'; + + /// internal field + static const String closePath = 'h'; + + /// internal field + static const String clipPath = 'W'; + + /// internal field + static const String evenOdd = '*'; + + /// internal field + static const String endPath = 'n'; + + /// internal field + static const String setLineWidth = 'w'; + + /// internal field + static const String setLineCapStyle = 'J'; + + /// internal field + static const String setLineJoinStyle = 'j'; + + /// internal field + static const String setMiterLimit = 'M'; + + /// internal field + static const String setDashPattern = 'd'; + + /// internal field + static const String setRenderingMode = 'Tr'; + + /// internal field + static const String setCharacterSpace = 'Tc'; + + /// internal field + static const String setWordSpace = 'Tw'; + + /// internal field + static const String beginText = 'BT'; + + /// internal field + static const String selectColorSpaceForStroking = 'CS'; + + /// internal field + static const String selectColorSpaceForNonStroking = 'cs'; + + /// internal field + static const String setFont = 'Tf'; + + /// internal field + static const String setCoords = 'Td'; + + /// internal field + static const String setTextOnNewLine = "'"; + + /// internal field + static const String endText = 'ET'; + + /// internal field + static const String setTextScaling = 'Tz'; + + /// internal field + static const String setTextLeading = 'TL'; + + /// internal field + static const String beginPath = 'm'; + + /// internal field + static const String appendLineSegment = 'l'; + + /// internal field + static const String fill = 'f'; + + /// internal field + static const String stroke = 'S'; + + /// internal field + static const String closeStrokePath = 's'; + + /// internal field + static const String fillStroke = 'B'; + + /// internal field + static const String closeFillStrokePath = 'b'; + + /// internal field + static const String paintXObject = 'Do'; + + /// internal field + static const String goToNextLine = 'T*'; + + /// internal field + static const String setText = 'Tj'; + + /// internal field + static const String setGraphicsState = 'gs'; + + /// internal field + static const String appendBezierCurve = 'c'; + + /// internal field + static const String slash = '/'; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_cross_table.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_cross_table.dart index 444bc483c..63f4b7f9f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_cross_table.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_cross_table.dart @@ -1,1875 +1,1875 @@ -import 'dart:collection'; -import 'dart:math'; - -import '../../interfaces/pdf_interface.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_collection.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_catalog.dart'; -import '../pdf_document/pdf_document.dart'; -import '../pdf_document/pdf_file_structure.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import '../security/pdf_encryptor.dart'; -import '../security/pdf_security.dart'; -import 'cross_table.dart'; -import 'enums.dart'; -import 'object_info.dart'; -import 'pdf_archive_stream.dart'; -import 'pdf_constants.dart'; -import 'pdf_main_object_collection.dart'; -import 'pdf_writer.dart'; - -/// PDFCrossTable is responsible for intermediate level parsing and -/// savingof a PDF document. -class PdfCrossTable { - //Constructor - /// internal constructor - PdfCrossTable([PdfDocument? document, List? data]) { - if (document != null) { - this.document = document; - objNumbers = Queue(); - if (data != null) { - _data = data; - _initializeCrossTable(); - this.document = document; - } - } - _isColorSpace = false; - } - - /// internal constructor - PdfCrossTable.fromCatalog( - int tableCount, - PdfDictionary? encryptionDictionary, - this.pdfDocumentCatalog, - ) { - _storedCount = tableCount; - _encryptorDictionary = encryptionDictionary; - _bForceNew = true; - _isColorSpace = false; - } - - /// internal constructor - PdfCrossTable.fromFdf(List docStream) { - _data = docStream; - crossTable = CrossTable.fromFdf(docStream, this); - } - - //Fields - PdfDocument? _pdfDocument; - int _count = 0; - - /// internal field - PdfMainObjectCollection? items; - PdfDictionary? _trailer; - Map? _objects = {}; - List? _data; - - /// internal field - CrossTable? crossTable; - - /// internal field - late Queue objNumbers; - - /// internal field - PdfDictionary? pdfDocumentCatalog; - bool _isIndexOutOfRange = false; - PdfDictionary? _encryptorDictionary; - List<_ArchiveInfo>? _archives; - PdfArchiveStream? _archive; - double _maxGenNumIndex = 0; - late int _storedCount; - bool _bForceNew = false; - Map? _mappedReferences; - List? _prevRef; - late bool _isColorSpace; - bool _isOutlineOrDestination = false; - - //Properties - /// internal property - int get nextObjectNumber { - if (count == 0) { - count++; - } - return count++; - } - - /// internal property - PdfEncryptor? get encryptor { - return crossTable?.encryptor; - } - - set encryptor(PdfEncryptor? value) { - if (value != null) { - crossTable!.encryptor = value.clone(); - } - } - - /// internal property - PdfDictionary? get documentCatalog { - if (pdfDocumentCatalog == null && crossTable != null) { - pdfDocumentCatalog = - dereference(crossTable!.documentCatalog) as PdfDictionary?; - } - return pdfDocumentCatalog; - } - - /// internal property - PdfDictionary? get trailer { - _trailer ??= crossTable == null ? PdfStream() : crossTable!.trailer; - if (_trailer!.containsKey('XRefStm')) { - _trailer!.remove('XRefStm'); - } - return _trailer; - } - - /// internal property - PdfDictionary? get encryptorDictionary { - if (_encryptorDictionary == null && - trailer!.containsKey(PdfDictionaryProperties.encrypt)) { - final IPdfPrimitive? primitive = dereference( - trailer![PdfDictionaryProperties.encrypt], - ); - if (primitive is PdfDictionary) { - _encryptorDictionary = primitive; - } - } - return _encryptorDictionary; - } - - /// internal property - int get count { - if (_count == 0) { - IPdfPrimitive? obj; - PdfNumber? tempCount; - if (crossTable != null) { - obj = crossTable!.trailer![PdfDictionaryProperties.size]; - } - if (obj != null) { - tempCount = dereference(obj) as PdfNumber?; - } else { - tempCount = PdfNumber(0); - } - _count = tempCount!.value!.toInt(); - } - return _count; - } - - set count(int value) { - _count = value; - } - - /// internal property - PdfMainObjectCollection? get objectCollection => - PdfDocumentHelper.getHelper(_pdfDocument!).objects; - - /// internal property - PdfDocument? get document => _pdfDocument; - set document(PdfDocument? document) { - if (document == null) { - throw ArgumentError('Document'); - } - _pdfDocument = document; - items = PdfDocumentHelper.getHelper(_pdfDocument!).objects; - } - - /// internal property - List? get prevReference => - (_prevRef != null) ? _prevRef : _prevRef = []; - - set prevReference(List? value) { - if (value != null) { - _prevRef = value; - } - } - - //Implementation - void _initializeCrossTable() { - crossTable = CrossTable(_data, this); - } - - void _markTrailerReferences() { - trailer!.items!.forEach((PdfName? name, IPdfPrimitive? element) { - if (element is PdfReferenceHolder) { - final PdfReferenceHolder rh = element; - if (!PdfDocumentHelper.getHelper( - document!, - ).objects.contains(rh.object!)) { - PdfDocumentHelper.getHelper(document!).objects.add(rh.object); - } - } - }); - } - - Future _markTrailerReferencesAsync() async { - trailer!.items!.forEach((PdfName? name, IPdfPrimitive? element) { - if (element is PdfReferenceHolder) { - final PdfReferenceHolder rh = element; - if (!PdfDocumentHelper.getHelper( - document!, - ).objects.contains(rh.object!)) { - PdfDocumentHelper.getHelper(document!).objects.add(rh.object); - } - } - }); - } - - /// internal method - void save(PdfWriter writer) { - _saveHead(writer); - _objects!.clear(); - if (_archives != null) { - _archives!.clear(); - } - _archive = null; - _markTrailerReferences(); - _saveObjects(writer); - final int saveCount = count; - if (PdfDocumentHelper.getHelper(document!).isLoadedDocument) { - writer.position = writer.length; - } - if (_isCrossReferenceStream(writer.document)) { - _saveArchives(writer); - } - _registerObject(PdfReference(0, -1), position: 0, isFreeType: true); - final int? referencePosition = writer.position; - final int prevXRef = - crossTable == null ? 0 : crossTable!.startCrossReference; - if (_isCrossReferenceStream(writer.document)) { - PdfReference? xRefReference; - final Map returnedValue = _prepareXRefStream( - prevXRef.toDouble(), - referencePosition!.toDouble(), - xRefReference, - ); - final PdfStream xRefStream = returnedValue['xRefStream']! as PdfStream; - xRefReference = returnedValue['reference'] as PdfReference?; - xRefStream.blockEncryption = true; - _doSaveObject(xRefStream, xRefReference!, writer); - } else { - writer.write(PdfOperators.crossReference); - writer.write(PdfOperators.newLine); - _saveSections(writer); - _saveTrailer(writer, count, prevXRef); - } - _saveEnd(writer, referencePosition); - count = saveCount; - for (int i = 0; i < objectCollection!.count; i++) { - final PdfObjectInfo objectInfo = objectCollection![i]; - objectInfo.object!.isSaving = false; - } - } - - /// internal method - Future saveAsync(PdfWriter writer) async { - await _saveHeadAsync(writer); - _objects!.clear(); - if (_archives != null) { - _archives!.clear(); - } - _archive = null; - await _markTrailerReferencesAsync(); - await _saveObjectsAsync(writer); - final int saveCount = count; - if (PdfDocumentHelper.getHelper(document!).isLoadedDocument) { - writer.position = writer.length; - } - if (await _isCrossReferenceStreamAsync(writer.document)) { - await _saveArchivesAsync(writer); - } - await _registerObjectAsync( - PdfReference(0, -1), - position: 0, - isFreeType: true, - ); - final int? referencePosition = writer.position; - final int prevXRef = - crossTable == null ? 0 : crossTable!.startCrossReference; - if (await _isCrossReferenceStreamAsync(writer.document)) { - PdfReference? xRefReference; - PdfStream? xRefStream; - await _prepareXRefStreamAsync( - prevXRef.toDouble(), - referencePosition!.toDouble(), - xRefReference, - ).then((Map returnedValue) { - xRefStream = returnedValue['xRefStream']! as PdfStream; - xRefReference = returnedValue['reference'] as PdfReference?; - }); - xRefStream!.blockEncryption = true; - await _doSaveObjectAsync(xRefStream!, xRefReference!, writer); - } else { - await writer.writeAsync(PdfOperators.crossReference).then((_) async { - await writer.writeAsync(PdfOperators.newLine).then((_) async { - await _saveSectionsAsync(writer).then((_) async { - await _saveTrailerAsync(writer, count, prevXRef); - }); - }); - }); - } - await _saveEndAsync(writer, referencePosition); - count = saveCount; - for (int i = 0; i < objectCollection!.count; i++) { - final PdfObjectInfo objectInfo = objectCollection![i]; - objectInfo.object!.isSaving = false; - } - } - - void _saveHead(PdfWriter writer) { - writer.write('%PDF-'); - final String version = _generateFileVersion(writer.document!); - writer.write(version); - writer.write(PdfOperators.newLine); - writer.write([0x25, 0x83, 0x92, 0xfa, 0xfe]); - writer.write(PdfOperators.newLine); - } - - Future _saveHeadAsync(PdfWriter writer) async { - await writer.writeAsync('%PDF-').then((_) async { - final String version = await _generateFileVersionAsync(writer.document!); - await writer.writeAsync(version).then((_) async { - await writer.writeAsync(PdfOperators.newLine).then((_) async { - await writer.writeAsync([0x25, 0x83, 0x92, 0xfa, 0xfe]).then(( - _, - ) async { - await writer.writeAsync(PdfOperators.newLine); - }); - }); - }); - }); - } - - String _generateFileVersion(PdfDocument document) { - if (document.fileStructure.version == PdfVersion.version2_0) { - const String version = '2.0'; - return version; - } else { - return '1.${document.fileStructure.version.index}'; - } - } - - Future _generateFileVersionAsync(PdfDocument document) async { - if (document.fileStructure.version == PdfVersion.version2_0) { - const String version = '2.0'; - return version; - } else { - return '1.${document.fileStructure.version.index}'; - } - } - - void _saveObjects(PdfWriter writer) { - final PdfMainObjectCollection objects = objectCollection!; - if (_bForceNew) { - count = 1; - _mappedReferences = null; - } - _setSecurity(); - for (int i = 0; i < objects.count; i++) { - final PdfObjectInfo objInfo = objects[i]; - if (objInfo.modified! || _bForceNew) { - final IPdfPrimitive obj = objInfo.object!; - final IPdfPrimitive? reference = objInfo.reference; - if (reference == null) { - final PdfReference ref = getReference(obj); - objInfo.reference = ref; - } - bool skip = false; - if (obj is PdfDictionary && obj.isSkip) { - skip = true; - } - if (!skip) { - _saveIndirectObject(obj, writer); - } - } - } - } - - Future _saveObjectsAsync(PdfWriter writer) async { - final PdfMainObjectCollection objects = objectCollection!; - if (_bForceNew) { - count = 1; - _mappedReferences = null; - } - await _setSecurityAsync(); - for (int i = 0; i < objects.count; i++) { - final PdfObjectInfo objInfo = objects[i]; - if (objInfo.modified! || _bForceNew) { - final IPdfPrimitive obj = objInfo.object!; - final IPdfPrimitive? reference = objInfo.reference; - if (reference == null) { - final PdfReference ref = await getReferenceAsync(obj); - objInfo.reference = ref; - } - bool skip = false; - if (obj is PdfDictionary && obj.isSkip) { - skip = true; - } - if (!skip) { - await _saveIndirectObjectAsync(obj, writer); - } - } - } - } - - void _setSecurity() { - final PdfSecurity security = document!.security; - trailer!.encrypt = false; - if (PdfSecurityHelper.getHelper(security).encryptor.encrypt) { - PdfDictionary? securityDictionary = encryptorDictionary; - if (securityDictionary == null) { - securityDictionary = PdfDictionary(); - securityDictionary.encrypt = false; - PdfDocumentHelper.getHelper(document!).objects.add(securityDictionary); - securityDictionary.position = -1; - } - securityDictionary = PdfSecurityHelper.getHelper( - security, - ).encryptor.saveToDictionary(securityDictionary); - trailer![PdfDictionaryProperties.id] = - PdfSecurityHelper.getHelper(security).encryptor.fileID; - trailer![PdfDictionaryProperties.encrypt] = PdfReferenceHolder( - securityDictionary, - ); - } else if (!PdfSecurityHelper.getHelper( - security, - ).encryptor.encryptOnlyAttachment) { - if (trailer!.containsKey(PdfDictionaryProperties.encrypt)) { - trailer!.remove(PdfDictionaryProperties.encrypt); - } - if (trailer!.containsKey(PdfDictionaryProperties.id) && - !PdfFileStructureHelper.fileID(document!.fileStructure)) { - trailer!.remove(PdfDictionaryProperties.id); - } - } - } - - Future _setSecurityAsync() async { - final PdfSecurity security = document!.security; - trailer!.encrypt = false; - if (PdfSecurityHelper.getHelper(security).encryptor.encrypt) { - PdfDictionary? securityDictionary = encryptorDictionary; - if (securityDictionary == null) { - securityDictionary = PdfDictionary(); - securityDictionary.encrypt = false; - PdfDocumentHelper.getHelper(document!).objects.add(securityDictionary); - securityDictionary.position = -1; - } - securityDictionary = await PdfSecurityHelper.getHelper( - security, - ).encryptor.saveToDictionaryAsync(securityDictionary); - trailer![PdfDictionaryProperties.id] = - PdfSecurityHelper.getHelper(security).encryptor.fileID; - trailer![PdfDictionaryProperties.encrypt] = PdfReferenceHolder( - securityDictionary, - ); - } else if (!PdfSecurityHelper.getHelper( - security, - ).encryptor.encryptOnlyAttachment) { - if (trailer!.containsKey(PdfDictionaryProperties.encrypt)) { - trailer!.remove(PdfDictionaryProperties.encrypt); - } - if (trailer!.containsKey(PdfDictionaryProperties.id) && - !PdfFileStructureHelper.fileID(document!.fileStructure)) { - trailer!.remove(PdfDictionaryProperties.id); - } - } - } - - void _saveIndirectObject(IPdfPrimitive object, PdfWriter writer) { - final PdfReference reference = getReference(object); - if (object is PdfCatalog) { - trailer![PdfDictionaryProperties.root] = reference; - //NOTE: This is needed to get PDF/A Conformance. - if (document != null && - PdfDocumentHelper.getHelper(document!).conformanceLevel != - PdfConformanceLevel.none) { - trailer![PdfDictionaryProperties.id] = - PdfSecurityHelper.getHelper(document!.security).encryptor.fileID; - } - } - PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; - bool archive = false; - archive = object is! PdfDictionary || object.archive; - final bool allowedType = - !((object is PdfStream) || !archive || (object is PdfCatalog)); - bool sigFlag = false; - if (object is PdfDictionary && - document!.fileStructure.crossReferenceType == - PdfCrossReferenceType.crossReferenceStream) { - final PdfDictionary dictionary = object; - if (dictionary.containsKey(PdfDictionaryProperties.type)) { - final PdfName? name = - dictionary[PdfDictionaryProperties.type] as PdfName?; - if (name != null && name.name! == 'Sig') { - sigFlag = true; - } - } - } - if (allowedType && - _isCrossReferenceStream(writer.document) && - reference.genNum == 0 && - !sigFlag) { - _doArchiveObject(object, reference, writer); - } else { - _registerObject(reference, position: writer.position); - _doSaveObject(object, reference, writer); - if (object == _archive) { - _archive = null; - } - } - } - - Future _saveIndirectObjectAsync( - IPdfPrimitive object, - PdfWriter writer, - ) async { - await getReferenceAsync(object).then((PdfReference reference) async { - if (object is PdfCatalog) { - trailer![PdfDictionaryProperties.root] = reference; - //NOTE: This is needed to get PDF/A Conformance. - if (document != null && - PdfDocumentHelper.getHelper(document!).conformanceLevel != - PdfConformanceLevel.none) { - trailer![PdfDictionaryProperties.id] = - PdfSecurityHelper.getHelper(document!.security).encryptor.fileID; - } - } - PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; - bool archive = false; - archive = object is! PdfDictionary || object.archive; - final bool allowedType = - !((object is PdfStream) || !archive || (object is PdfCatalog)); - bool sigFlag = false; - if (object is PdfDictionary && - document!.fileStructure.crossReferenceType == - PdfCrossReferenceType.crossReferenceStream) { - final PdfDictionary dictionary = object; - if (dictionary.containsKey(PdfDictionaryProperties.type)) { - final PdfName? name = - dictionary[PdfDictionaryProperties.type] as PdfName?; - if (name != null && name.name! == 'Sig') { - sigFlag = true; - } - } - } - if (allowedType && - await _isCrossReferenceStreamAsync(writer.document) && - reference.genNum == 0 && - !sigFlag) { - await _doArchiveObjectAsync(object, reference, writer); - } else { - await _registerObjectAsync(reference, position: writer.position).then(( - _, - ) async { - await _doSaveObjectAsync(object, reference, writer).then((_) { - if (object == _archive) { - _archive = null; - } - }); - }); - } - }); - } - - /// internal method - PdfReference getReference(IPdfPrimitive? object) { - if (object is PdfArchiveStream) { - final PdfReference r = _findArchiveReference(object); - return r; - } - if (object is PdfReferenceHolder) { - object = object.object; - if (document != null && - !PdfDocumentHelper.getHelper(document!).isLoadedDocument) { - object!.isSaving = true; - } - } - if (object is IPdfWrapper) { - object = IPdfWrapper.getElement(object! as IPdfWrapper); - } - dynamic reference; - bool? wasNew = false; - if (object!.isSaving!) { - if (items!.count > 0 && - object.objectCollectionIndex! > 0 && - items!.count > object.objectCollectionIndex! - 1) { - final Map result = PdfDocumentHelper.getHelper( - document!, - ).objects.getReference(object, wasNew); - wasNew = result['isNew'] as bool?; - reference = result['reference']; - } - } else { - final Map result = PdfDocumentHelper.getHelper( - document!, - ).objects.getReference(object, wasNew); - wasNew = result['isNew'] as bool?; - reference = result['reference']; - } - if (reference == null) { - if (object.status == PdfObjectStatus.registered) { - wasNew = false; - } else { - wasNew = true; - } - } else { - wasNew = false; - } - if (_bForceNew) { - if (reference == null) { - int maxObj = - (_storedCount > 0) - ? _storedCount++ - : PdfDocumentHelper.getHelper(document!).objects.count; - if (maxObj <= 0) { - maxObj = -1; - _storedCount = 2; - } - while (PdfDocumentHelper.getHelper( - document!, - ).objects.mainObjectCollection!.containsKey(maxObj)) { - maxObj++; - } - reference = PdfReference(maxObj, 0); - if (wasNew) { - PdfDocumentHelper.getHelper(document!).objects.add(object, reference); - } - } - reference = getMappedReference(reference); - } - if (reference == null) { - int objectNumber = nextObjectNumber; - if (crossTable != null) { - while (crossTable!.objects.containsKey(objectNumber)) { - objectNumber = nextObjectNumber; - } - } - if (PdfDocumentHelper.getHelper( - document!, - ).objects.mainObjectCollection!.containsKey(objectNumber)) { - reference = PdfReference(nextObjectNumber, 0); - } else { - PdfNumber? trailerCount; - if (crossTable != null) { - trailerCount = - crossTable!.trailer![PdfDictionaryProperties.size] as PdfNumber?; - } - if (trailerCount != null && objectNumber == trailerCount.value) { - reference = PdfReference(nextObjectNumber, 0); - } else { - reference = PdfReference(objectNumber, 0); - } - } - if (wasNew) { - if (object is IPdfChangable) { - (object as IPdfChangable).changed = true; - } - PdfDocumentHelper.getHelper(document!).objects.add(object); - PdfDocumentHelper.getHelper( - document!, - ).objects.trySetReference(object, reference); - final int tempIndex = - PdfDocumentHelper.getHelper(document!).objects.count - 1; - final int? tempkey = - PdfDocumentHelper.getHelper( - document!, - ).objects.objectCollection![tempIndex].reference!.objNum; - final PdfObjectInfo tempvalue = - PdfDocumentHelper.getHelper( - document!, - ).objects.objectCollection![PdfDocumentHelper.getHelper( - document!, - ).objects.count - - 1]; - PdfDocumentHelper.getHelper( - document!, - ).objects.mainObjectCollection![tempkey] = - tempvalue; - object.position = -1; - } else { - PdfDocumentHelper.getHelper( - document!, - ).objects.trySetReference(object, reference); - } - object.objectCollectionIndex = reference.objNum as int?; - object.status = PdfObjectStatus.none; - } - return reference as PdfReference; - } - - /// internal method - Future getReferenceAsync(IPdfPrimitive? object) async { - if (object is PdfArchiveStream) { - await _findArchiveReferenceAsync(object).then((PdfReference r) { - return r; - }); - } - if (object is PdfReferenceHolder) { - object = object.object; - if (document != null && - !PdfDocumentHelper.getHelper(document!).isLoadedDocument) { - object!.isSaving = true; - } - } - if (object is IPdfWrapper) { - object = IPdfWrapper.getElement(object! as IPdfWrapper); - } - dynamic reference; - bool? wasNew = false; - if (object!.isSaving!) { - if (items!.count > 0 && - object.objectCollectionIndex! > 0 && - items!.count > object.objectCollectionIndex! - 1) { - await PdfDocumentHelper.getHelper(document!).objects - .getReferenceAsync(object, wasNew) - .then((Map result) { - wasNew = result['isNew'] as bool?; - reference = result['reference']; - }); - } - } else { - await PdfDocumentHelper.getHelper(document!).objects - .getReferenceAsync(object, wasNew) - .then((Map result) { - wasNew = result['isNew'] as bool?; - reference = result['reference']; - }); - } - if (reference == null) { - if (object.status == PdfObjectStatus.registered) { - wasNew = false; - } else { - wasNew = true; - } - } else { - wasNew = false; - } - if (_bForceNew) { - if (reference == null) { - int maxObj = - (_storedCount > 0) - ? _storedCount++ - : PdfDocumentHelper.getHelper(document!).objects.count; - if (maxObj <= 0) { - maxObj = -1; - _storedCount = 2; - } - while (PdfDocumentHelper.getHelper( - document!, - ).objects.mainObjectCollection!.containsKey(maxObj)) { - maxObj++; - } - reference = PdfReference(maxObj, 0); - if (wasNew!) { - PdfDocumentHelper.getHelper(document!).objects.add(object, reference); - } - } - reference = await getMappedReferenceAsync(reference); - } - if (reference == null) { - int objectNumber = nextObjectNumber; - if (crossTable != null) { - while (crossTable!.objects.containsKey(objectNumber)) { - objectNumber = nextObjectNumber; - } - } - if (PdfDocumentHelper.getHelper( - document!, - ).objects.mainObjectCollection!.containsKey(objectNumber)) { - reference = PdfReference(nextObjectNumber, 0); - } else { - PdfNumber? trailerCount; - if (crossTable != null) { - trailerCount = - crossTable!.trailer![PdfDictionaryProperties.size] as PdfNumber?; - } - if (trailerCount != null && objectNumber == trailerCount.value) { - reference = PdfReference(nextObjectNumber, 0); - } else { - reference = PdfReference(objectNumber, 0); - } - } - if (wasNew!) { - if (object is IPdfChangable) { - (object as IPdfChangable).changed = true; - } - await PdfDocumentHelper.getHelper(document!).objects.addAsync(object); - await PdfDocumentHelper.getHelper( - document!, - ).objects.trySetReferenceAsync(object, reference); - final int tempIndex = - PdfDocumentHelper.getHelper(document!).objects.count - 1; - final int? tempkey = - PdfDocumentHelper.getHelper( - document!, - ).objects.objectCollection![tempIndex].reference!.objNum; - final PdfObjectInfo tempvalue = - PdfDocumentHelper.getHelper( - document!, - ).objects.objectCollection![PdfDocumentHelper.getHelper( - document!, - ).objects.count - - 1]; - PdfDocumentHelper.getHelper( - document!, - ).objects.mainObjectCollection![tempkey] = - tempvalue; - object.position = -1; - } else { - await PdfDocumentHelper.getHelper( - document!, - ).objects.trySetReferenceAsync(object, reference); - } - object.objectCollectionIndex = reference.objNum as int?; - object.status = PdfObjectStatus.none; - } - return reference as PdfReference; - } - - /// internal method - PdfReference getMappedReference(PdfReference reference) { - _mappedReferences ??= {}; - PdfReference? mref = - _mappedReferences!.containsKey(reference) - ? _mappedReferences![reference] - : null; - if (mref == null) { - mref = PdfReference(nextObjectNumber, 0); - _mappedReferences![reference] = mref; - } - return mref; - } - - /// internal method - Future getMappedReferenceAsync(PdfReference reference) async { - _mappedReferences ??= {}; - PdfReference? mref = - _mappedReferences!.containsKey(reference) - ? _mappedReferences![reference] - : null; - if (mref == null) { - mref = PdfReference(nextObjectNumber, 0); - _mappedReferences![reference] = mref; - } - return mref; - } - - void _registerObject( - PdfReference reference, { - int? position, - PdfArchiveStream? archive, - bool? isFreeType, - }) { - if (isFreeType == null) { - if (position != null) { - _objects![reference.objNum] = _RegisteredObject(position, reference); - _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); - } else { - _objects![reference.objNum] = _RegisteredObject.fromArchive( - this, - archive, - reference, - ); - _maxGenNumIndex = max(_maxGenNumIndex, archive!.count.toDouble()); - } - } else { - _objects![reference.objNum] = _RegisteredObject( - position, - reference, - isFreeType, - ); - _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); - } - } - - Future _registerObjectAsync( - PdfReference reference, { - int? position, - PdfArchiveStream? archive, - bool? isFreeType, - }) async { - if (isFreeType == null) { - if (position != null) { - _objects![reference.objNum] = _RegisteredObject(position, reference); - _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); - } else { - _objects![reference.objNum] = _RegisteredObject.fromArchive( - this, - archive, - reference, - ); - _maxGenNumIndex = max(_maxGenNumIndex, archive!.count.toDouble()); - } - } else { - _objects![reference.objNum] = _RegisteredObject( - position, - reference, - isFreeType, - ); - _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); - } - } - - void _doSaveObject( - IPdfPrimitive object, - PdfReference reference, - PdfWriter writer, - ) { - writer.write(reference.objNum); - writer.write(PdfOperators.whiteSpace); - writer.write(reference.genNum); - writer.write(PdfOperators.whiteSpace); - writer.write(PdfOperators.obj); - writer.write(PdfOperators.newLine); - object.save(writer); - if (object is PdfName || object is PdfNumber || object is PdfNull) { - writer.write(PdfOperators.newLine); - } - writer.write(PdfOperators.endobj); - writer.write(PdfOperators.newLine); - } - - Future _doSaveObjectAsync( - IPdfPrimitive object, - PdfReference reference, - PdfWriter writer, - ) async { - await writer.writeAsync(reference.objNum).then((_) async { - await writer.writeAsync(PdfOperators.whiteSpace).then((_) async { - await writer.writeAsync(reference.genNum).then((_) async { - await writer.writeAsync(PdfOperators.whiteSpace).then((_) async { - await writer.writeAsync(PdfOperators.obj).then((_) async { - await writer.writeAsync(PdfOperators.newLine).then((_) async { - object.save(writer); - if (object is PdfName || - object is PdfNumber || - object is PdfNull) { - await writer.writeAsync(PdfOperators.newLine); - } - await writer.writeAsync(PdfOperators.endobj).then((_) async { - await writer.writeAsync(PdfOperators.newLine); - }); - }); - }); - }); - }); - }); - }); - } - - void _saveSections(IPdfWriter writer) { - int objectNumber = 0; - int? count = 0; - do { - final Map result = _prepareSubsection(objectNumber); - count = result['count']; - objectNumber = result['objectNumber']!; - _saveSubsection(writer, objectNumber, count!); - objectNumber += count; - } while (count != 0); - } - - Future _saveSectionsAsync(IPdfWriter writer) async { - int objectNumber = 0; - int? count = 0; - do { - await _prepareSubsectionAsync(objectNumber).then(( - Map result, - ) { - count = result['count']; - objectNumber = result['objectNumber']!; - }); - await _saveSubsectionAsync(writer, objectNumber, count!).then((_) { - objectNumber += count!; - }); - } while (count != 0); - } - - Map _prepareSubsection(int objectNumber) { - int tempCount = 0; - int i; - int total = count; - if (total <= 0) { - total = PdfDocumentHelper.getHelper(document!).objects.count + 1; - } - if (total < - PdfDocumentHelper.getHelper( - document!, - ).objects.maximumReferenceObjectNumber!) { - total = - PdfDocumentHelper.getHelper( - document!, - ).objects.maximumReferenceObjectNumber!; - _isIndexOutOfRange = true; - } - if (objectNumber >= total) { - return {'count': tempCount, 'objectNumber': objectNumber}; - } - for (i = objectNumber; i < total; ++i) { - if (_objects!.containsKey(i)) { - break; - } - } - objectNumber = i; - for (; i < total; ++i) { - if (!_objects!.containsKey(i)) { - break; - } - ++tempCount; - } - return {'count': tempCount, 'objectNumber': objectNumber}; - } - - Future> _prepareSubsectionAsync(int objectNumber) async { - int tempCount = 0; - int i; - int total = count; - if (total <= 0) { - total = PdfDocumentHelper.getHelper(document!).objects.count + 1; - } - if (total < - PdfDocumentHelper.getHelper( - document!, - ).objects.maximumReferenceObjectNumber!) { - total = - PdfDocumentHelper.getHelper( - document!, - ).objects.maximumReferenceObjectNumber!; - _isIndexOutOfRange = true; - } - if (objectNumber >= total) { - return {'count': tempCount, 'objectNumber': objectNumber}; - } - for (i = objectNumber; i < total; ++i) { - if (_objects!.containsKey(i)) { - break; - } - } - objectNumber = i; - for (; i < total; ++i) { - if (!_objects!.containsKey(i)) { - break; - } - ++tempCount; - } - return {'count': tempCount, 'objectNumber': objectNumber}; - } - - void _saveSubsection(IPdfWriter writer, int? objectNumber, int tempCount) { - if (tempCount <= 0 || objectNumber! >= count && !_isIndexOutOfRange) { - return; - } - - writer.write('$objectNumber $tempCount${PdfOperators.newLine}'); - for (int i = objectNumber; i < objectNumber + tempCount; ++i) { - final _RegisteredObject obj = _objects![i]!; - String value = ''; - if (obj._type == PdfObjectType.free) { - value = _getItem(obj._offset, 65535, true); - } else { - value = _getItem(obj._offset, obj._generationNumber!, false); - } - writer.write(value); - } - } - - Future _saveSubsectionAsync( - IPdfWriter writer, - int? objectNumber, - int tempCount, - ) async { - if (tempCount <= 0 || objectNumber! >= count && !_isIndexOutOfRange) { - return; - } - - writer.write('$objectNumber $tempCount${PdfOperators.newLine}'); - for (int i = objectNumber; i < objectNumber + tempCount; ++i) { - final _RegisteredObject obj = _objects![i]!; - String value = ''; - if (obj._type == PdfObjectType.free) { - value = await _getItemAsync(obj._offset, 65535, true); - } else { - value = await _getItemAsync(obj._offset, obj._generationNumber!, false); - } - writer.write(value); - } - } - - String _getItem(int? offset, int generationNumber, bool isFreeType) { - String result = ''; - final int offsetLength = 10 - offset.toString().length; - if (generationNumber <= 0) { - generationNumber = 0; - } - final int generationNumberLength = - (5 - generationNumber.toString().length) <= 0 - ? 0 - : (5 - generationNumber.toString().length); - for (int index = 0; index < offsetLength; index++) { - result = '${result}0'; - } - result = '$result$offset '; - for (int index = 0; index < generationNumberLength; index++) { - result = '${result}0'; - } - result = '$result$generationNumber '; - result = - result + - (isFreeType ? PdfOperators.f : PdfOperators.n) + - PdfOperators.newLine; - return result; - } - - Future _getItemAsync( - int? offset, - int generationNumber, - bool isFreeType, - ) async { - String result = ''; - final int offsetLength = 10 - offset.toString().length; - if (generationNumber <= 0) { - generationNumber = 0; - } - final int generationNumberLength = - (5 - generationNumber.toString().length) <= 0 - ? 0 - : (5 - generationNumber.toString().length); - for (int index = 0; index < offsetLength; index++) { - result = '${result}0'; - } - result = '$result$offset '; - for (int index = 0; index < generationNumberLength; index++) { - result = '${result}0'; - } - result = '$result$generationNumber '; - result = - result + - (isFreeType ? PdfOperators.f : PdfOperators.n) + - PdfOperators.newLine; - return result; - } - - void _saveTrailer(IPdfWriter writer, int count, int prevCrossReference) { - writer.write(PdfOperators.trailer); - writer.write(PdfOperators.newLine); - PdfDictionary trailerDictionary = trailer!; - if (prevCrossReference != 0) { - trailer![PdfDictionaryProperties.prev] = PdfNumber(prevCrossReference); - } - trailerDictionary[PdfDictionaryProperties.size] = PdfNumber(_count); - trailerDictionary = PdfDictionary(trailerDictionary); - trailerDictionary.encrypt = false; - trailerDictionary.save(writer); - } - - Future _saveTrailerAsync( - IPdfWriter writer, - int count, - int prevCrossReference, - ) async { - writer.write(PdfOperators.trailer); - writer.write(PdfOperators.newLine); - PdfDictionary trailerDictionary = trailer!; - if (prevCrossReference != 0) { - trailer![PdfDictionaryProperties.prev] = PdfNumber(prevCrossReference); - } - trailerDictionary[PdfDictionaryProperties.size] = PdfNumber(_count); - trailerDictionary = PdfDictionary(trailerDictionary); - trailerDictionary.encrypt = false; - trailerDictionary.save(writer); - } - - void _saveEnd(IPdfWriter writer, int? position) { - writer.write( - PdfOperators.newLine + - PdfOperators.startCrossReference + - PdfOperators.newLine, - ); - writer.write(position.toString() + PdfOperators.newLine); - writer.write(PdfOperators.endOfFileMarker); - writer.write(PdfOperators.newLine); - } - - Future _saveEndAsync(IPdfWriter writer, int? position) async { - writer.write( - PdfOperators.newLine + - PdfOperators.startCrossReference + - PdfOperators.newLine, - ); - writer.write(position.toString() + PdfOperators.newLine); - writer.write(PdfOperators.endOfFileMarker); - writer.write(PdfOperators.newLine); - } - - /// internal method - static IPdfPrimitive? dereference(IPdfPrimitive? element) { - if (element != null && element is PdfReferenceHolder) { - final PdfReferenceHolder holder = element; - return holder.object; - } - return element; - } - - /// internal method - void dispose() { - if (items != null) { - items!.dispose(); - items = null; - } - if (_objects != null && _objects!.isNotEmpty) { - _objects!.clear(); - _objects = null; - } - } - - /// internal method - IPdfPrimitive? getObject(IPdfPrimitive? pointer) { - bool isEncryptedMetadata = true; - IPdfPrimitive? result = pointer; - if (pointer is PdfReferenceHolder) { - result = pointer.object; - } else if (pointer is PdfReference) { - final PdfReference reference = pointer; - objNumbers.addLast(pointer); - IPdfPrimitive? obj; - if (crossTable != null) { - obj = crossTable!.getObject(pointer); - } else { - final int? index = items!.getObjectIndex(reference); - if (index == 0) { - obj = items!.getObjectFromReference(reference); - } - } - obj = _pageProceed(obj); - final PdfMainObjectCollection? goc = items; - if (obj != null) { - if (goc!.containsReference(reference)) { - goc.getObjectIndex(reference); - obj = goc.getObjectFromReference(reference); - } else { - goc.add(obj, reference); - obj.position = -1; - reference.position = -1; - } - } - result = obj; - if (obj != null && obj is PdfDictionary) { - final PdfDictionary dictionary = obj; - if (dictionary.containsKey(PdfDictionaryProperties.type)) { - final IPdfPrimitive? primitive = - dictionary[PdfDictionaryProperties.type]; - if (primitive != null && - primitive is PdfName && - primitive.name == PdfDictionaryProperties.metadata) { - if (encryptor != null) { - isEncryptedMetadata = encryptor!.encryptMetadata; - } - } - } - } - if (PdfDocumentHelper.getHelper(document!).isEncrypted && - isEncryptedMetadata) { - _decrypt(result); - } - } - if (pointer is PdfReference) { - objNumbers.removeLast(); - } - return result; - } - - IPdfPrimitive? _pageProceed(IPdfPrimitive? obj) { - if (obj is PdfPage) { - return obj; - } - if (obj is PdfDictionary) { - final PdfDictionary dic = obj; - if (obj is! PdfPage) { - if (dic.containsKey(PdfDictionaryProperties.type)) { - final IPdfPrimitive? objType = dic[PdfDictionaryProperties.type]; - if (objType is PdfName) { - final PdfName type = getObject(objType)! as PdfName; - if (type.name == 'Page') { - if (!dic.containsKey(PdfDictionaryProperties.kids)) { - if (PdfDocumentHelper.getHelper( - _pdfDocument!, - ).isLoadedDocument) { - final PdfPage lPage = PdfPageCollectionHelper.getHelper( - _pdfDocument!.pages, - ).getPage(dic); - obj = IPdfWrapper.getElement(lPage); - final PdfMainObjectCollection items = - PdfDocumentHelper.getHelper(_pdfDocument!).objects; - final int index = items.lookFor(dic)!; - if (index >= 0) { - items.reregisterReference(index, obj!); - obj.position = -1; - } - } - } - } - } - } - } - } - return obj; - } - - bool _isCrossReferenceStream(PdfDocument? document) { - ArgumentError.notNull('document'); - bool result = false; - if (crossTable != null) { - if (crossTable!.trailer is PdfStream) { - result = true; - } - } else { - result = - document!.fileStructure.crossReferenceType == - PdfCrossReferenceType.crossReferenceStream; - } - return result; - } - - Future _isCrossReferenceStreamAsync(PdfDocument? document) async { - ArgumentError.notNull('document'); - bool result = false; - if (crossTable != null) { - if (crossTable!.trailer is PdfStream) { - result = true; - } - } else { - result = - document!.fileStructure.crossReferenceType == - PdfCrossReferenceType.crossReferenceStream; - } - return result; - } - - void _saveArchives(PdfWriter writer) { - if (_archives != null) { - for (final _ArchiveInfo ai in _archives!) { - PdfReference? reference = ai._reference; - if (reference == null) { - reference = PdfReference(nextObjectNumber, 0); - ai._reference = reference; - } - PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; - _registerObject(reference, position: writer.position); - _doSaveObject(ai._archive!, reference, writer); - } - } - } - - Future _saveArchivesAsync(PdfWriter writer) async { - if (_archives != null) { - for (final _ArchiveInfo ai in _archives!) { - PdfReference? reference = ai._reference; - if (reference == null) { - reference = PdfReference(nextObjectNumber, 0); - ai._reference = reference; - } - PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; - await _registerObjectAsync(reference, position: writer.position).then(( - _, - ) async { - await _doSaveObjectAsync(ai._archive!, reference!, writer); - }); - } - } - } - - void _doArchiveObject( - IPdfPrimitive obj, - PdfReference reference, - PdfWriter writer, - ) { - if (_archive == null) { - _archive = PdfArchiveStream(document); - _saveArchive(writer); - } - _registerObject(reference, archive: _archive); - _archive!.saveObject(obj, reference); - if (_archive!.objCount >= 100) { - _archive = null; - } - } - - Future _doArchiveObjectAsync( - IPdfPrimitive obj, - PdfReference reference, - PdfWriter writer, - ) async { - if (_archive == null) { - _archive = PdfArchiveStream(document); - await _saveArchiveAsync(writer); - } - await _registerObjectAsync(reference, archive: _archive); - await _archive!.saveObjectAsync(obj, reference).then((_) { - if (_archive!.objCount >= 100) { - _archive = null; - } - }); - } - - void _saveArchive(PdfWriter writer) { - final _ArchiveInfo ai = _ArchiveInfo(null, _archive); - _archives ??= <_ArchiveInfo>[]; - _archives!.add(ai); - } - - Future _saveArchiveAsync(PdfWriter writer) async { - final _ArchiveInfo ai = _ArchiveInfo(null, _archive); - _archives ??= <_ArchiveInfo>[]; - _archives!.add(ai); - } - - Map _prepareXRefStream( - double prevXRef, - double position, - PdfReference? reference, - ) { - PdfStream? xRefStream; - xRefStream = _trailer as PdfStream?; - if (xRefStream == null) { - xRefStream = PdfStream(); - } else { - xRefStream.remove(PdfDictionaryProperties.filter); - xRefStream.remove(PdfDictionaryProperties.decodeParms); - } - final PdfArray sectionIndeces = PdfArray(); - reference = PdfReference(nextObjectNumber, 0); - _registerObject(reference, position: position.toInt()); - - double objectNum = 0; - double count = 0; - final List paramsFormat = [1, 8, 1]; - paramsFormat[1] = max(_getSize(position), _getSize(this.count.toDouble())); - paramsFormat[2] = _getSize(_maxGenNumIndex); - final List ms = []; - while (true) { - final Map result = _prepareSubsection(objectNum.toInt()); - count = result['count']!.toDouble(); - objectNum = result['objectNumber']!.toDouble(); - if (count <= 0) { - break; - } else { - sectionIndeces.add(PdfNumber(objectNum)); - sectionIndeces.add(PdfNumber(count)); - _saveSubSection(ms, objectNum, count, paramsFormat); - objectNum += count; - } - } - //iw.Flush(); - xRefStream.data = ms; - xRefStream[PdfDictionaryProperties.index] = sectionIndeces; - xRefStream[PdfDictionaryProperties.size] = PdfNumber(this.count); - xRefStream[PdfDictionaryProperties.prev] = PdfNumber(prevXRef); - xRefStream[PdfDictionaryProperties.type] = PdfName('XRef'); - xRefStream[PdfDictionaryProperties.w] = PdfArray(paramsFormat); - if (crossTable != null) { - final PdfDictionary trailer = crossTable!.trailer!; - for (final PdfName? key in trailer.items!.keys) { - final bool contains = xRefStream.containsKey(key); - if (!contains && - key!.name != PdfDictionaryProperties.decodeParms && - key.name != PdfDictionaryProperties.filter) { - xRefStream[key] = trailer[key]; - } - } - } - if (prevXRef == 0 && xRefStream.containsKey(PdfDictionaryProperties.prev)) { - xRefStream.remove(PdfDictionaryProperties.prev); - } - xRefStream.encrypt = false; - return { - 'xRefStream': xRefStream, - 'reference': reference, - }; - } - - Future> _prepareXRefStreamAsync( - double prevXRef, - double position, - PdfReference? reference, - ) async { - PdfStream? xRefStream; - xRefStream = _trailer as PdfStream?; - if (xRefStream == null) { - xRefStream = PdfStream(); - } else { - xRefStream.remove(PdfDictionaryProperties.filter); - xRefStream.remove(PdfDictionaryProperties.decodeParms); - } - final PdfArray sectionIndeces = PdfArray(); - reference = PdfReference(nextObjectNumber, 0); - await _registerObjectAsync(reference, position: position.toInt()); - - double objectNum = 0; - double count = 0; - final List paramsFormat = [1, 8, 1]; - paramsFormat[1] = max( - await _getSizeAsync(position), - await _getSizeAsync(this.count.toDouble()), - ); - paramsFormat[2] = await _getSizeAsync(_maxGenNumIndex); - final List ms = []; - while (true) { - await _prepareSubsectionAsync(objectNum.toInt()).then(( - Map result, - ) { - count = result['count']!.toDouble(); - objectNum = result['objectNumber']!.toDouble(); - }); - if (count <= 0) { - break; - } else { - sectionIndeces.add(PdfNumber(objectNum)); - sectionIndeces.add(PdfNumber(count)); - await _saveSubSectionAsync(ms, objectNum, count, paramsFormat).then(( - _, - ) { - objectNum += count; - }); - } - } - //iw.Flush(); - xRefStream.data = ms; - xRefStream[PdfDictionaryProperties.index] = sectionIndeces; - xRefStream[PdfDictionaryProperties.size] = PdfNumber(this.count); - xRefStream[PdfDictionaryProperties.prev] = PdfNumber(prevXRef); - xRefStream[PdfDictionaryProperties.type] = PdfName('XRef'); - xRefStream[PdfDictionaryProperties.w] = PdfArray(paramsFormat); - if (crossTable != null) { - final PdfDictionary trailer = crossTable!.trailer!; - for (final PdfName? key in trailer.items!.keys) { - final bool contains = xRefStream.containsKey(key); - if (!contains && - key!.name != PdfDictionaryProperties.decodeParms && - key.name != PdfDictionaryProperties.filter) { - xRefStream[key] = trailer[key]; - } - } - } - if (prevXRef == 0 && xRefStream.containsKey(PdfDictionaryProperties.prev)) { - xRefStream.remove(PdfDictionaryProperties.prev); - } - xRefStream.encrypt = false; - return { - 'xRefStream': xRefStream, - 'reference': reference, - }; - } - - int _getSize(double number) { - int size = 0; - - if (number < 4294967295) { - if (number < 65535) { - if (number < 255) { - size = 1; - } else { - size = 2; - } - } else { - if (number < (65535 | 65535 << 8)) { - size = 3; - } else { - size = 4; - } - } - } else { - size = 8; - } - return size; - } - - Future _getSizeAsync(double number) async { - int size = 0; - - if (number < 4294967295) { - if (number < 65535) { - if (number < 255) { - size = 1; - } else { - size = 2; - } - } else { - if (number < (65535 | 65535 << 8)) { - size = 3; - } else { - size = 4; - } - } - } else { - size = 8; - } - return size; - } - - void _saveSubSection( - List xRefStream, - double objectNum, - double count, - List format, - ) { - for (int i = objectNum.toInt(); i < objectNum + count; ++i) { - final _RegisteredObject obj = _objects![i]!; - xRefStream.add(obj._type!.index.toUnsigned(8)); - switch (obj._type) { - case PdfObjectType.free: - _saveLong(xRefStream, obj._objectNumber!.toInt(), format[1]); - _saveLong(xRefStream, obj._generationNumber, format[2]); - break; - - case PdfObjectType.normal: - _saveLong(xRefStream, obj.offset, format[1]); - _saveLong(xRefStream, obj._generationNumber, format[2]); - break; - - case PdfObjectType.packed: - _saveLong(xRefStream, obj._objectNumber!.toInt(), format[1]); - _saveLong(xRefStream, obj.offset, format[2]); - break; - - // ignore: no_default_cases - default: - throw ArgumentError('Internal error: Undefined object type.'); - } - } - } - - Future _saveSubSectionAsync( - List xRefStream, - double objectNum, - double count, - List format, - ) async { - for (int i = objectNum.toInt(); i < objectNum + count; ++i) { - final _RegisteredObject obj = _objects![i]!; - xRefStream.add(obj._type!.index.toUnsigned(8)); - switch (obj._type) { - case PdfObjectType.free: - await _saveLongAsync( - xRefStream, - obj._objectNumber!.toInt(), - format[1], - ); - await _saveLongAsync(xRefStream, obj._generationNumber, format[2]); - break; - - case PdfObjectType.normal: - await _saveLongAsync(xRefStream, obj.offset, format[1]); - await _saveLongAsync(xRefStream, obj._generationNumber, format[2]); - break; - - case PdfObjectType.packed: - await _saveLongAsync( - xRefStream, - obj._objectNumber!.toInt(), - format[1], - ); - await _saveLongAsync(xRefStream, obj.offset, format[2]); - break; - - // ignore: no_default_cases - default: - throw ArgumentError('Internal error: Undefined object type.'); - } - } - } - - void _saveLong(List xRefStream, int? number, int count) { - for (int i = count - 1; i >= 0; --i) { - final int b = (number! >> (i << 3) & 255).toUnsigned(8); - xRefStream.add(b); - } - } - - Future _saveLongAsync( - List xRefStream, - int? number, - int count, - ) async { - for (int i = count - 1; i >= 0; --i) { - final int b = (number! >> (i << 3) & 255).toUnsigned(8); - xRefStream.add(b); - } - } - - PdfReference _findArchiveReference(PdfArchiveStream archive) { - int i = 0; - late _ArchiveInfo ai; - for (final int count = _archives!.length; i < count; ++i) { - ai = _archives![i]; - if (ai._archive == archive) { - break; - } - } - PdfReference? reference = ai._reference; - reference ??= PdfReference(nextObjectNumber, 0); - ai._reference = reference; - return reference; - } - - Future _findArchiveReferenceAsync( - PdfArchiveStream archive, - ) async { - int i = 0; - late _ArchiveInfo ai; - for (final int count = _archives!.length; i < count; ++i) { - ai = _archives![i]; - if (ai._archive == archive) { - break; - } - } - PdfReference? reference = ai._reference; - reference ??= PdfReference(nextObjectNumber, 0); - ai._reference = reference; - return reference; - } - - void _decrypt(IPdfPrimitive? obj) { - if (obj != null) { - if (obj is PdfDictionary || obj is PdfStream) { - final PdfDictionary dic = obj as PdfDictionary; - _isOutlineOrDestination = _checkForOutlinesAndDestination(dic); - if (!dic.decrypted!) { - dic.items!.forEach((PdfName? key, IPdfPrimitive? element) { - _decrypt(element); - }); - if (obj is PdfStream) { - final PdfStream stream = obj; - if (objNumbers.isNotEmpty) { - stream.crossTable = this; - stream.objNumber = objNumbers.last.objNum; - } else if (PdfDocumentHelper.getHelper(document!).isEncrypted && - !stream.decrypted! && - objNumbers.isNotEmpty && - encryptor != null && - !encryptor!.encryptAttachmentOnly!) { - stream.decrypt(encryptor!, objNumbers.last.objNum); - } - } - } - _isOutlineOrDestination = false; - } else if (obj is PdfArray) { - final PdfArray array = obj; - for (final IPdfPrimitive? element in array.elements) { - if (element != null && element is PdfName) { - final PdfName name = element; - if (name.name == 'Indexed') { - _isColorSpace = true; - } - } - _decrypt(element); - } - _isColorSpace = false; - } else if (obj is PdfString) { - final PdfString str = obj; - if (!str.decrypted && - (!str.isHex! || _isColorSpace || _isOutlineOrDestination)) { - if (PdfDocumentHelper.getHelper(document!).isEncrypted && - objNumbers.isNotEmpty) { - obj.decrypt(encryptor!, objNumbers.last.objNum); - } - } - } - } - } - - /// Checks the dictionary if it is an outline type. - bool _checkForOutlinesAndDestination(PdfDictionary dictionary) { - if (dictionary.containsKey(PdfDictionaryProperties.parent)) { - final IPdfPrimitive? outline = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.parent], - ); - if (outline != null && outline is PdfDictionary) { - if (documentCatalog != null && - documentCatalog!.containsKey(PdfDictionaryProperties.outlines)) { - final IPdfPrimitive? dict = PdfCrossTable.dereference( - documentCatalog![PdfDictionaryProperties.outlines], - ); - if (dict != null && dict is PdfDictionary && dict == outline) { - return true; - } else { - return _checkForOutlinesAndDestination(outline); - } - } - } - } else if (dictionary.containsKey(PdfDictionaryProperties.limits)) { - return true; - } - return false; - } -} - -/// Represents a registered object. -class _RegisteredObject { - _RegisteredObject(int? offset, PdfReference reference, [bool? isFreeType]) { - _offset = offset; - _generationNumber = reference.genNum; - _objNumber = reference.objNum!.toDouble(); - if (isFreeType != null) { - _type = isFreeType ? PdfObjectType.free : PdfObjectType.normal; - } else { - _type = PdfObjectType.normal; - _objNumber = reference.objNum!.toDouble(); - } - } - - _RegisteredObject.fromArchive( - PdfCrossTable xrefTable, - PdfArchiveStream? archive, - PdfReference reference, - ) { - _xrefTable = xrefTable; - _archive = archive; - _offset = reference.objNum; - _type = PdfObjectType.packed; - } - int? _offset; - int? _generationNumber; - PdfObjectType? _type; - double? _objNumber; - late PdfCrossTable _xrefTable; - PdfArchiveStream? _archive; - - int? get offset { - int? result; - if (_archive != null) { - result = _archive!.getIndex(_offset); - } else { - result = _offset; - } - return result; - } - - double? get _objectNumber { - _objNumber ??= 0; - if (_objNumber == 0) { - if (_archive != null) { - _objNumber = _xrefTable.getReference(_archive).objNum!.toDouble(); - } - } - return _objNumber; - } -} - -class _ArchiveInfo { - // Constructor - _ArchiveInfo(PdfReference? reference, PdfArchiveStream? archive) { - _reference = reference; - _archive = archive; - } - // Fields - PdfReference? _reference; - PdfArchiveStream? _archive; -} +import 'dart:collection'; +import 'dart:math'; + +import '../../interfaces/pdf_interface.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_collection.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_catalog.dart'; +import '../pdf_document/pdf_document.dart'; +import '../pdf_document/pdf_file_structure.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import '../security/pdf_encryptor.dart'; +import '../security/pdf_security.dart'; +import 'cross_table.dart'; +import 'enums.dart'; +import 'object_info.dart'; +import 'pdf_archive_stream.dart'; +import 'pdf_constants.dart'; +import 'pdf_main_object_collection.dart'; +import 'pdf_writer.dart'; + +/// PDFCrossTable is responsible for intermediate level parsing and +/// savingof a PDF document. +class PdfCrossTable { + //Constructor + /// internal constructor + PdfCrossTable([PdfDocument? document, List? data]) { + if (document != null) { + this.document = document; + objNumbers = Queue(); + if (data != null) { + _data = data; + _initializeCrossTable(); + this.document = document; + } + } + _isColorSpace = false; + } + + /// internal constructor + PdfCrossTable.fromCatalog( + int tableCount, + PdfDictionary? encryptionDictionary, + this.pdfDocumentCatalog, + ) { + _storedCount = tableCount; + _encryptorDictionary = encryptionDictionary; + _bForceNew = true; + _isColorSpace = false; + } + + /// internal constructor + PdfCrossTable.fromFdf(List docStream) { + _data = docStream; + crossTable = CrossTable.fromFdf(docStream, this); + } + + //Fields + PdfDocument? _pdfDocument; + int _count = 0; + + /// internal field + PdfMainObjectCollection? items; + PdfDictionary? _trailer; + Map? _objects = {}; + List? _data; + + /// internal field + CrossTable? crossTable; + + /// internal field + late Queue objNumbers; + + /// internal field + PdfDictionary? pdfDocumentCatalog; + bool _isIndexOutOfRange = false; + PdfDictionary? _encryptorDictionary; + List<_ArchiveInfo>? _archives; + PdfArchiveStream? _archive; + double _maxGenNumIndex = 0; + late int _storedCount; + bool _bForceNew = false; + Map? _mappedReferences; + List? _prevRef; + late bool _isColorSpace; + bool _isOutlineOrDestination = false; + + //Properties + /// internal property + int get nextObjectNumber { + if (count == 0) { + count++; + } + return count++; + } + + /// internal property + PdfEncryptor? get encryptor { + return crossTable?.encryptor; + } + + set encryptor(PdfEncryptor? value) { + if (value != null) { + crossTable!.encryptor = value.clone(); + } + } + + /// internal property + PdfDictionary? get documentCatalog { + if (pdfDocumentCatalog == null && crossTable != null) { + pdfDocumentCatalog = + dereference(crossTable!.documentCatalog) as PdfDictionary?; + } + return pdfDocumentCatalog; + } + + /// internal property + PdfDictionary? get trailer { + _trailer ??= crossTable == null ? PdfStream() : crossTable!.trailer; + if (_trailer!.containsKey('XRefStm')) { + _trailer!.remove('XRefStm'); + } + return _trailer; + } + + /// internal property + PdfDictionary? get encryptorDictionary { + if (_encryptorDictionary == null && + trailer!.containsKey(PdfDictionaryProperties.encrypt)) { + final IPdfPrimitive? primitive = dereference( + trailer![PdfDictionaryProperties.encrypt], + ); + if (primitive is PdfDictionary) { + _encryptorDictionary = primitive; + } + } + return _encryptorDictionary; + } + + /// internal property + int get count { + if (_count == 0) { + IPdfPrimitive? obj; + PdfNumber? tempCount; + if (crossTable != null) { + obj = crossTable!.trailer![PdfDictionaryProperties.size]; + } + if (obj != null) { + tempCount = dereference(obj) as PdfNumber?; + } else { + tempCount = PdfNumber(0); + } + _count = tempCount!.value!.toInt(); + } + return _count; + } + + set count(int value) { + _count = value; + } + + /// internal property + PdfMainObjectCollection? get objectCollection => + PdfDocumentHelper.getHelper(_pdfDocument!).objects; + + /// internal property + PdfDocument? get document => _pdfDocument; + set document(PdfDocument? document) { + if (document == null) { + throw ArgumentError('Document'); + } + _pdfDocument = document; + items = PdfDocumentHelper.getHelper(_pdfDocument!).objects; + } + + /// internal property + List? get prevReference => + (_prevRef != null) ? _prevRef : _prevRef = []; + + set prevReference(List? value) { + if (value != null) { + _prevRef = value; + } + } + + //Implementation + void _initializeCrossTable() { + crossTable = CrossTable(_data, this); + } + + void _markTrailerReferences() { + trailer!.items!.forEach((PdfName? name, IPdfPrimitive? element) { + if (element is PdfReferenceHolder) { + final PdfReferenceHolder rh = element; + if (!PdfDocumentHelper.getHelper( + document!, + ).objects.contains(rh.object!)) { + PdfDocumentHelper.getHelper(document!).objects.add(rh.object); + } + } + }); + } + + Future _markTrailerReferencesAsync() async { + trailer!.items!.forEach((PdfName? name, IPdfPrimitive? element) { + if (element is PdfReferenceHolder) { + final PdfReferenceHolder rh = element; + if (!PdfDocumentHelper.getHelper( + document!, + ).objects.contains(rh.object!)) { + PdfDocumentHelper.getHelper(document!).objects.add(rh.object); + } + } + }); + } + + /// internal method + void save(PdfWriter writer) { + _saveHead(writer); + _objects!.clear(); + if (_archives != null) { + _archives!.clear(); + } + _archive = null; + _markTrailerReferences(); + _saveObjects(writer); + final int saveCount = count; + if (PdfDocumentHelper.getHelper(document!).isLoadedDocument) { + writer.position = writer.length; + } + if (_isCrossReferenceStream(writer.document)) { + _saveArchives(writer); + } + _registerObject(PdfReference(0, -1), position: 0, isFreeType: true); + final int? referencePosition = writer.position; + final int prevXRef = + crossTable == null ? 0 : crossTable!.startCrossReference; + if (_isCrossReferenceStream(writer.document)) { + PdfReference? xRefReference; + final Map returnedValue = _prepareXRefStream( + prevXRef.toDouble(), + referencePosition!.toDouble(), + xRefReference, + ); + final PdfStream xRefStream = returnedValue['xRefStream']! as PdfStream; + xRefReference = returnedValue['reference'] as PdfReference?; + xRefStream.blockEncryption = true; + _doSaveObject(xRefStream, xRefReference!, writer); + } else { + writer.write(PdfOperators.crossReference); + writer.write(PdfOperators.newLine); + _saveSections(writer); + _saveTrailer(writer, count, prevXRef); + } + _saveEnd(writer, referencePosition); + count = saveCount; + for (int i = 0; i < objectCollection!.count; i++) { + final PdfObjectInfo objectInfo = objectCollection![i]; + objectInfo.object!.isSaving = false; + } + } + + /// internal method + Future saveAsync(PdfWriter writer) async { + await _saveHeadAsync(writer); + _objects!.clear(); + if (_archives != null) { + _archives!.clear(); + } + _archive = null; + await _markTrailerReferencesAsync(); + await _saveObjectsAsync(writer); + final int saveCount = count; + if (PdfDocumentHelper.getHelper(document!).isLoadedDocument) { + writer.position = writer.length; + } + if (await _isCrossReferenceStreamAsync(writer.document)) { + await _saveArchivesAsync(writer); + } + await _registerObjectAsync( + PdfReference(0, -1), + position: 0, + isFreeType: true, + ); + final int? referencePosition = writer.position; + final int prevXRef = + crossTable == null ? 0 : crossTable!.startCrossReference; + if (await _isCrossReferenceStreamAsync(writer.document)) { + PdfReference? xRefReference; + PdfStream? xRefStream; + await _prepareXRefStreamAsync( + prevXRef.toDouble(), + referencePosition!.toDouble(), + xRefReference, + ).then((Map returnedValue) { + xRefStream = returnedValue['xRefStream']! as PdfStream; + xRefReference = returnedValue['reference'] as PdfReference?; + }); + xRefStream!.blockEncryption = true; + await _doSaveObjectAsync(xRefStream!, xRefReference!, writer); + } else { + await writer.writeAsync(PdfOperators.crossReference).then((_) async { + await writer.writeAsync(PdfOperators.newLine).then((_) async { + await _saveSectionsAsync(writer).then((_) async { + await _saveTrailerAsync(writer, count, prevXRef); + }); + }); + }); + } + await _saveEndAsync(writer, referencePosition); + count = saveCount; + for (int i = 0; i < objectCollection!.count; i++) { + final PdfObjectInfo objectInfo = objectCollection![i]; + objectInfo.object!.isSaving = false; + } + } + + void _saveHead(PdfWriter writer) { + writer.write('%PDF-'); + final String version = _generateFileVersion(writer.document!); + writer.write(version); + writer.write(PdfOperators.newLine); + writer.write([0x25, 0x83, 0x92, 0xfa, 0xfe]); + writer.write(PdfOperators.newLine); + } + + Future _saveHeadAsync(PdfWriter writer) async { + await writer.writeAsync('%PDF-').then((_) async { + final String version = await _generateFileVersionAsync(writer.document!); + await writer.writeAsync(version).then((_) async { + await writer.writeAsync(PdfOperators.newLine).then((_) async { + await writer.writeAsync([0x25, 0x83, 0x92, 0xfa, 0xfe]).then(( + _, + ) async { + await writer.writeAsync(PdfOperators.newLine); + }); + }); + }); + }); + } + + String _generateFileVersion(PdfDocument document) { + if (document.fileStructure.version == PdfVersion.version2_0) { + const String version = '2.0'; + return version; + } else { + return '1.${document.fileStructure.version.index}'; + } + } + + Future _generateFileVersionAsync(PdfDocument document) async { + if (document.fileStructure.version == PdfVersion.version2_0) { + const String version = '2.0'; + return version; + } else { + return '1.${document.fileStructure.version.index}'; + } + } + + void _saveObjects(PdfWriter writer) { + final PdfMainObjectCollection objects = objectCollection!; + if (_bForceNew) { + count = 1; + _mappedReferences = null; + } + _setSecurity(); + for (int i = 0; i < objects.count; i++) { + final PdfObjectInfo objInfo = objects[i]; + if (objInfo.modified! || _bForceNew) { + final IPdfPrimitive obj = objInfo.object!; + final IPdfPrimitive? reference = objInfo.reference; + if (reference == null) { + final PdfReference ref = getReference(obj); + objInfo.reference = ref; + } + bool skip = false; + if (obj is PdfDictionary && obj.isSkip) { + skip = true; + } + if (!skip) { + _saveIndirectObject(obj, writer); + } + } + } + } + + Future _saveObjectsAsync(PdfWriter writer) async { + final PdfMainObjectCollection objects = objectCollection!; + if (_bForceNew) { + count = 1; + _mappedReferences = null; + } + await _setSecurityAsync(); + for (int i = 0; i < objects.count; i++) { + final PdfObjectInfo objInfo = objects[i]; + if (objInfo.modified! || _bForceNew) { + final IPdfPrimitive obj = objInfo.object!; + final IPdfPrimitive? reference = objInfo.reference; + if (reference == null) { + final PdfReference ref = await getReferenceAsync(obj); + objInfo.reference = ref; + } + bool skip = false; + if (obj is PdfDictionary && obj.isSkip) { + skip = true; + } + if (!skip) { + await _saveIndirectObjectAsync(obj, writer); + } + } + } + } + + void _setSecurity() { + final PdfSecurity security = document!.security; + trailer!.encrypt = false; + if (PdfSecurityHelper.getHelper(security).encryptor.encrypt) { + PdfDictionary? securityDictionary = encryptorDictionary; + if (securityDictionary == null) { + securityDictionary = PdfDictionary(); + securityDictionary.encrypt = false; + PdfDocumentHelper.getHelper(document!).objects.add(securityDictionary); + securityDictionary.position = -1; + } + securityDictionary = PdfSecurityHelper.getHelper( + security, + ).encryptor.saveToDictionary(securityDictionary); + trailer![PdfDictionaryProperties.id] = + PdfSecurityHelper.getHelper(security).encryptor.fileID; + trailer![PdfDictionaryProperties.encrypt] = PdfReferenceHolder( + securityDictionary, + ); + } else if (!PdfSecurityHelper.getHelper( + security, + ).encryptor.encryptOnlyAttachment) { + if (trailer!.containsKey(PdfDictionaryProperties.encrypt)) { + trailer!.remove(PdfDictionaryProperties.encrypt); + } + if (trailer!.containsKey(PdfDictionaryProperties.id) && + !PdfFileStructureHelper.fileID(document!.fileStructure)) { + trailer!.remove(PdfDictionaryProperties.id); + } + } + } + + Future _setSecurityAsync() async { + final PdfSecurity security = document!.security; + trailer!.encrypt = false; + if (PdfSecurityHelper.getHelper(security).encryptor.encrypt) { + PdfDictionary? securityDictionary = encryptorDictionary; + if (securityDictionary == null) { + securityDictionary = PdfDictionary(); + securityDictionary.encrypt = false; + PdfDocumentHelper.getHelper(document!).objects.add(securityDictionary); + securityDictionary.position = -1; + } + securityDictionary = await PdfSecurityHelper.getHelper( + security, + ).encryptor.saveToDictionaryAsync(securityDictionary); + trailer![PdfDictionaryProperties.id] = + PdfSecurityHelper.getHelper(security).encryptor.fileID; + trailer![PdfDictionaryProperties.encrypt] = PdfReferenceHolder( + securityDictionary, + ); + } else if (!PdfSecurityHelper.getHelper( + security, + ).encryptor.encryptOnlyAttachment) { + if (trailer!.containsKey(PdfDictionaryProperties.encrypt)) { + trailer!.remove(PdfDictionaryProperties.encrypt); + } + if (trailer!.containsKey(PdfDictionaryProperties.id) && + !PdfFileStructureHelper.fileID(document!.fileStructure)) { + trailer!.remove(PdfDictionaryProperties.id); + } + } + } + + void _saveIndirectObject(IPdfPrimitive object, PdfWriter writer) { + final PdfReference reference = getReference(object); + if (object is PdfCatalog) { + trailer![PdfDictionaryProperties.root] = reference; + //NOTE: This is needed to get PDF/A Conformance. + if (document != null && + PdfDocumentHelper.getHelper(document!).conformanceLevel != + PdfConformanceLevel.none) { + trailer![PdfDictionaryProperties.id] = + PdfSecurityHelper.getHelper(document!.security).encryptor.fileID; + } + } + PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; + bool archive = false; + archive = object is! PdfDictionary || object.archive; + final bool allowedType = + !((object is PdfStream) || !archive || (object is PdfCatalog)); + bool sigFlag = false; + if (object is PdfDictionary && + document!.fileStructure.crossReferenceType == + PdfCrossReferenceType.crossReferenceStream) { + final PdfDictionary dictionary = object; + if (dictionary.containsKey(PdfDictionaryProperties.type)) { + final PdfName? name = + dictionary[PdfDictionaryProperties.type] as PdfName?; + if (name != null && name.name! == 'Sig') { + sigFlag = true; + } + } + } + if (allowedType && + _isCrossReferenceStream(writer.document) && + reference.genNum == 0 && + !sigFlag) { + _doArchiveObject(object, reference, writer); + } else { + _registerObject(reference, position: writer.position); + _doSaveObject(object, reference, writer); + if (object == _archive) { + _archive = null; + } + } + } + + Future _saveIndirectObjectAsync( + IPdfPrimitive object, + PdfWriter writer, + ) async { + await getReferenceAsync(object).then((PdfReference reference) async { + if (object is PdfCatalog) { + trailer![PdfDictionaryProperties.root] = reference; + //NOTE: This is needed to get PDF/A Conformance. + if (document != null && + PdfDocumentHelper.getHelper(document!).conformanceLevel != + PdfConformanceLevel.none) { + trailer![PdfDictionaryProperties.id] = + PdfSecurityHelper.getHelper(document!.security).encryptor.fileID; + } + } + PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; + bool archive = false; + archive = object is! PdfDictionary || object.archive; + final bool allowedType = + !((object is PdfStream) || !archive || (object is PdfCatalog)); + bool sigFlag = false; + if (object is PdfDictionary && + document!.fileStructure.crossReferenceType == + PdfCrossReferenceType.crossReferenceStream) { + final PdfDictionary dictionary = object; + if (dictionary.containsKey(PdfDictionaryProperties.type)) { + final PdfName? name = + dictionary[PdfDictionaryProperties.type] as PdfName?; + if (name != null && name.name! == 'Sig') { + sigFlag = true; + } + } + } + if (allowedType && + await _isCrossReferenceStreamAsync(writer.document) && + reference.genNum == 0 && + !sigFlag) { + await _doArchiveObjectAsync(object, reference, writer); + } else { + await _registerObjectAsync(reference, position: writer.position).then(( + _, + ) async { + await _doSaveObjectAsync(object, reference, writer).then((_) { + if (object == _archive) { + _archive = null; + } + }); + }); + } + }); + } + + /// internal method + PdfReference getReference(IPdfPrimitive? object) { + if (object is PdfArchiveStream) { + final PdfReference r = _findArchiveReference(object); + return r; + } + if (object is PdfReferenceHolder) { + object = object.object; + if (document != null && + !PdfDocumentHelper.getHelper(document!).isLoadedDocument) { + object!.isSaving = true; + } + } + if (object is IPdfWrapper) { + object = IPdfWrapper.getElement(object! as IPdfWrapper); + } + dynamic reference; + bool? wasNew = false; + if (object!.isSaving!) { + if (items!.count > 0 && + object.objectCollectionIndex! > 0 && + items!.count > object.objectCollectionIndex! - 1) { + final Map result = PdfDocumentHelper.getHelper( + document!, + ).objects.getReference(object, wasNew); + wasNew = result['isNew'] as bool?; + reference = result['reference']; + } + } else { + final Map result = PdfDocumentHelper.getHelper( + document!, + ).objects.getReference(object, wasNew); + wasNew = result['isNew'] as bool?; + reference = result['reference']; + } + if (reference == null) { + if (object.status == PdfObjectStatus.registered) { + wasNew = false; + } else { + wasNew = true; + } + } else { + wasNew = false; + } + if (_bForceNew) { + if (reference == null) { + int maxObj = + (_storedCount > 0) + ? _storedCount++ + : PdfDocumentHelper.getHelper(document!).objects.count; + if (maxObj <= 0) { + maxObj = -1; + _storedCount = 2; + } + while (PdfDocumentHelper.getHelper( + document!, + ).objects.mainObjectCollection!.containsKey(maxObj)) { + maxObj++; + } + reference = PdfReference(maxObj, 0); + if (wasNew) { + PdfDocumentHelper.getHelper(document!).objects.add(object, reference); + } + } + reference = getMappedReference(reference); + } + if (reference == null) { + int objectNumber = nextObjectNumber; + if (crossTable != null) { + while (crossTable!.objects.containsKey(objectNumber)) { + objectNumber = nextObjectNumber; + } + } + if (PdfDocumentHelper.getHelper( + document!, + ).objects.mainObjectCollection!.containsKey(objectNumber)) { + reference = PdfReference(nextObjectNumber, 0); + } else { + PdfNumber? trailerCount; + if (crossTable != null) { + trailerCount = + crossTable!.trailer![PdfDictionaryProperties.size] as PdfNumber?; + } + if (trailerCount != null && objectNumber == trailerCount.value) { + reference = PdfReference(nextObjectNumber, 0); + } else { + reference = PdfReference(objectNumber, 0); + } + } + if (wasNew) { + if (object is IPdfChangable) { + (object as IPdfChangable).changed = true; + } + PdfDocumentHelper.getHelper(document!).objects.add(object); + PdfDocumentHelper.getHelper( + document!, + ).objects.trySetReference(object, reference); + final int tempIndex = + PdfDocumentHelper.getHelper(document!).objects.count - 1; + final int? tempkey = + PdfDocumentHelper.getHelper( + document!, + ).objects.objectCollection![tempIndex].reference!.objNum; + final PdfObjectInfo tempvalue = + PdfDocumentHelper.getHelper( + document!, + ).objects.objectCollection![PdfDocumentHelper.getHelper( + document!, + ).objects.count - + 1]; + PdfDocumentHelper.getHelper( + document!, + ).objects.mainObjectCollection![tempkey] = + tempvalue; + object.position = -1; + } else { + PdfDocumentHelper.getHelper( + document!, + ).objects.trySetReference(object, reference); + } + object.objectCollectionIndex = reference.objNum as int?; + object.status = PdfObjectStatus.none; + } + return reference as PdfReference; + } + + /// internal method + Future getReferenceAsync(IPdfPrimitive? object) async { + if (object is PdfArchiveStream) { + await _findArchiveReferenceAsync(object).then((PdfReference r) { + return r; + }); + } + if (object is PdfReferenceHolder) { + object = object.object; + if (document != null && + !PdfDocumentHelper.getHelper(document!).isLoadedDocument) { + object!.isSaving = true; + } + } + if (object is IPdfWrapper) { + object = IPdfWrapper.getElement(object! as IPdfWrapper); + } + dynamic reference; + bool? wasNew = false; + if (object!.isSaving!) { + if (items!.count > 0 && + object.objectCollectionIndex! > 0 && + items!.count > object.objectCollectionIndex! - 1) { + await PdfDocumentHelper.getHelper(document!).objects + .getReferenceAsync(object, wasNew) + .then((Map result) { + wasNew = result['isNew'] as bool?; + reference = result['reference']; + }); + } + } else { + await PdfDocumentHelper.getHelper(document!).objects + .getReferenceAsync(object, wasNew) + .then((Map result) { + wasNew = result['isNew'] as bool?; + reference = result['reference']; + }); + } + if (reference == null) { + if (object.status == PdfObjectStatus.registered) { + wasNew = false; + } else { + wasNew = true; + } + } else { + wasNew = false; + } + if (_bForceNew) { + if (reference == null) { + int maxObj = + (_storedCount > 0) + ? _storedCount++ + : PdfDocumentHelper.getHelper(document!).objects.count; + if (maxObj <= 0) { + maxObj = -1; + _storedCount = 2; + } + while (PdfDocumentHelper.getHelper( + document!, + ).objects.mainObjectCollection!.containsKey(maxObj)) { + maxObj++; + } + reference = PdfReference(maxObj, 0); + if (wasNew!) { + PdfDocumentHelper.getHelper(document!).objects.add(object, reference); + } + } + reference = await getMappedReferenceAsync(reference); + } + if (reference == null) { + int objectNumber = nextObjectNumber; + if (crossTable != null) { + while (crossTable!.objects.containsKey(objectNumber)) { + objectNumber = nextObjectNumber; + } + } + if (PdfDocumentHelper.getHelper( + document!, + ).objects.mainObjectCollection!.containsKey(objectNumber)) { + reference = PdfReference(nextObjectNumber, 0); + } else { + PdfNumber? trailerCount; + if (crossTable != null) { + trailerCount = + crossTable!.trailer![PdfDictionaryProperties.size] as PdfNumber?; + } + if (trailerCount != null && objectNumber == trailerCount.value) { + reference = PdfReference(nextObjectNumber, 0); + } else { + reference = PdfReference(objectNumber, 0); + } + } + if (wasNew!) { + if (object is IPdfChangable) { + (object as IPdfChangable).changed = true; + } + await PdfDocumentHelper.getHelper(document!).objects.addAsync(object); + await PdfDocumentHelper.getHelper( + document!, + ).objects.trySetReferenceAsync(object, reference); + final int tempIndex = + PdfDocumentHelper.getHelper(document!).objects.count - 1; + final int? tempkey = + PdfDocumentHelper.getHelper( + document!, + ).objects.objectCollection![tempIndex].reference!.objNum; + final PdfObjectInfo tempvalue = + PdfDocumentHelper.getHelper( + document!, + ).objects.objectCollection![PdfDocumentHelper.getHelper( + document!, + ).objects.count - + 1]; + PdfDocumentHelper.getHelper( + document!, + ).objects.mainObjectCollection![tempkey] = + tempvalue; + object.position = -1; + } else { + await PdfDocumentHelper.getHelper( + document!, + ).objects.trySetReferenceAsync(object, reference); + } + object.objectCollectionIndex = reference.objNum as int?; + object.status = PdfObjectStatus.none; + } + return reference as PdfReference; + } + + /// internal method + PdfReference getMappedReference(PdfReference reference) { + _mappedReferences ??= {}; + PdfReference? mref = + _mappedReferences!.containsKey(reference) + ? _mappedReferences![reference] + : null; + if (mref == null) { + mref = PdfReference(nextObjectNumber, 0); + _mappedReferences![reference] = mref; + } + return mref; + } + + /// internal method + Future getMappedReferenceAsync(PdfReference reference) async { + _mappedReferences ??= {}; + PdfReference? mref = + _mappedReferences!.containsKey(reference) + ? _mappedReferences![reference] + : null; + if (mref == null) { + mref = PdfReference(nextObjectNumber, 0); + _mappedReferences![reference] = mref; + } + return mref; + } + + void _registerObject( + PdfReference reference, { + int? position, + PdfArchiveStream? archive, + bool? isFreeType, + }) { + if (isFreeType == null) { + if (position != null) { + _objects![reference.objNum] = _RegisteredObject(position, reference); + _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); + } else { + _objects![reference.objNum] = _RegisteredObject.fromArchive( + this, + archive, + reference, + ); + _maxGenNumIndex = max(_maxGenNumIndex, archive!.count.toDouble()); + } + } else { + _objects![reference.objNum] = _RegisteredObject( + position, + reference, + isFreeType, + ); + _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); + } + } + + Future _registerObjectAsync( + PdfReference reference, { + int? position, + PdfArchiveStream? archive, + bool? isFreeType, + }) async { + if (isFreeType == null) { + if (position != null) { + _objects![reference.objNum] = _RegisteredObject(position, reference); + _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); + } else { + _objects![reference.objNum] = _RegisteredObject.fromArchive( + this, + archive, + reference, + ); + _maxGenNumIndex = max(_maxGenNumIndex, archive!.count.toDouble()); + } + } else { + _objects![reference.objNum] = _RegisteredObject( + position, + reference, + isFreeType, + ); + _maxGenNumIndex = max(_maxGenNumIndex, reference.genNum!.toDouble()); + } + } + + void _doSaveObject( + IPdfPrimitive object, + PdfReference reference, + PdfWriter writer, + ) { + writer.write(reference.objNum); + writer.write(PdfOperators.whiteSpace); + writer.write(reference.genNum); + writer.write(PdfOperators.whiteSpace); + writer.write(PdfOperators.obj); + writer.write(PdfOperators.newLine); + object.save(writer); + if (object is PdfName || object is PdfNumber || object is PdfNull) { + writer.write(PdfOperators.newLine); + } + writer.write(PdfOperators.endobj); + writer.write(PdfOperators.newLine); + } + + Future _doSaveObjectAsync( + IPdfPrimitive object, + PdfReference reference, + PdfWriter writer, + ) async { + await writer.writeAsync(reference.objNum).then((_) async { + await writer.writeAsync(PdfOperators.whiteSpace).then((_) async { + await writer.writeAsync(reference.genNum).then((_) async { + await writer.writeAsync(PdfOperators.whiteSpace).then((_) async { + await writer.writeAsync(PdfOperators.obj).then((_) async { + await writer.writeAsync(PdfOperators.newLine).then((_) async { + object.save(writer); + if (object is PdfName || + object is PdfNumber || + object is PdfNull) { + await writer.writeAsync(PdfOperators.newLine); + } + await writer.writeAsync(PdfOperators.endobj).then((_) async { + await writer.writeAsync(PdfOperators.newLine); + }); + }); + }); + }); + }); + }); + }); + } + + void _saveSections(IPdfWriter writer) { + int objectNumber = 0; + int? count = 0; + do { + final Map result = _prepareSubsection(objectNumber); + count = result['count']; + objectNumber = result['objectNumber']!; + _saveSubsection(writer, objectNumber, count!); + objectNumber += count; + } while (count != 0); + } + + Future _saveSectionsAsync(IPdfWriter writer) async { + int objectNumber = 0; + int? count = 0; + do { + await _prepareSubsectionAsync(objectNumber).then(( + Map result, + ) { + count = result['count']; + objectNumber = result['objectNumber']!; + }); + await _saveSubsectionAsync(writer, objectNumber, count!).then((_) { + objectNumber += count!; + }); + } while (count != 0); + } + + Map _prepareSubsection(int objectNumber) { + int tempCount = 0; + int i; + int total = count; + if (total <= 0) { + total = PdfDocumentHelper.getHelper(document!).objects.count + 1; + } + if (total < + PdfDocumentHelper.getHelper( + document!, + ).objects.maximumReferenceObjectNumber!) { + total = + PdfDocumentHelper.getHelper( + document!, + ).objects.maximumReferenceObjectNumber!; + _isIndexOutOfRange = true; + } + if (objectNumber >= total) { + return {'count': tempCount, 'objectNumber': objectNumber}; + } + for (i = objectNumber; i < total; ++i) { + if (_objects!.containsKey(i)) { + break; + } + } + objectNumber = i; + for (; i < total; ++i) { + if (!_objects!.containsKey(i)) { + break; + } + ++tempCount; + } + return {'count': tempCount, 'objectNumber': objectNumber}; + } + + Future> _prepareSubsectionAsync(int objectNumber) async { + int tempCount = 0; + int i; + int total = count; + if (total <= 0) { + total = PdfDocumentHelper.getHelper(document!).objects.count + 1; + } + if (total < + PdfDocumentHelper.getHelper( + document!, + ).objects.maximumReferenceObjectNumber!) { + total = + PdfDocumentHelper.getHelper( + document!, + ).objects.maximumReferenceObjectNumber!; + _isIndexOutOfRange = true; + } + if (objectNumber >= total) { + return {'count': tempCount, 'objectNumber': objectNumber}; + } + for (i = objectNumber; i < total; ++i) { + if (_objects!.containsKey(i)) { + break; + } + } + objectNumber = i; + for (; i < total; ++i) { + if (!_objects!.containsKey(i)) { + break; + } + ++tempCount; + } + return {'count': tempCount, 'objectNumber': objectNumber}; + } + + void _saveSubsection(IPdfWriter writer, int? objectNumber, int tempCount) { + if (tempCount <= 0 || objectNumber! >= count && !_isIndexOutOfRange) { + return; + } + + writer.write('$objectNumber $tempCount${PdfOperators.newLine}'); + for (int i = objectNumber; i < objectNumber + tempCount; ++i) { + final _RegisteredObject obj = _objects![i]!; + String value = ''; + if (obj._type == PdfObjectType.free) { + value = _getItem(obj._offset, 65535, true); + } else { + value = _getItem(obj._offset, obj._generationNumber!, false); + } + writer.write(value); + } + } + + Future _saveSubsectionAsync( + IPdfWriter writer, + int? objectNumber, + int tempCount, + ) async { + if (tempCount <= 0 || objectNumber! >= count && !_isIndexOutOfRange) { + return; + } + + writer.write('$objectNumber $tempCount${PdfOperators.newLine}'); + for (int i = objectNumber; i < objectNumber + tempCount; ++i) { + final _RegisteredObject obj = _objects![i]!; + String value = ''; + if (obj._type == PdfObjectType.free) { + value = await _getItemAsync(obj._offset, 65535, true); + } else { + value = await _getItemAsync(obj._offset, obj._generationNumber!, false); + } + writer.write(value); + } + } + + String _getItem(int? offset, int generationNumber, bool isFreeType) { + String result = ''; + final int offsetLength = 10 - offset.toString().length; + if (generationNumber <= 0) { + generationNumber = 0; + } + final int generationNumberLength = + (5 - generationNumber.toString().length) <= 0 + ? 0 + : (5 - generationNumber.toString().length); + for (int index = 0; index < offsetLength; index++) { + result = '${result}0'; + } + result = '$result$offset '; + for (int index = 0; index < generationNumberLength; index++) { + result = '${result}0'; + } + result = '$result$generationNumber '; + result = + result + + (isFreeType ? PdfOperators.f : PdfOperators.n) + + PdfOperators.newLine; + return result; + } + + Future _getItemAsync( + int? offset, + int generationNumber, + bool isFreeType, + ) async { + String result = ''; + final int offsetLength = 10 - offset.toString().length; + if (generationNumber <= 0) { + generationNumber = 0; + } + final int generationNumberLength = + (5 - generationNumber.toString().length) <= 0 + ? 0 + : (5 - generationNumber.toString().length); + for (int index = 0; index < offsetLength; index++) { + result = '${result}0'; + } + result = '$result$offset '; + for (int index = 0; index < generationNumberLength; index++) { + result = '${result}0'; + } + result = '$result$generationNumber '; + result = + result + + (isFreeType ? PdfOperators.f : PdfOperators.n) + + PdfOperators.newLine; + return result; + } + + void _saveTrailer(IPdfWriter writer, int count, int prevCrossReference) { + writer.write(PdfOperators.trailer); + writer.write(PdfOperators.newLine); + PdfDictionary trailerDictionary = trailer!; + if (prevCrossReference != 0) { + trailer![PdfDictionaryProperties.prev] = PdfNumber(prevCrossReference); + } + trailerDictionary[PdfDictionaryProperties.size] = PdfNumber(_count); + trailerDictionary = PdfDictionary(trailerDictionary); + trailerDictionary.encrypt = false; + trailerDictionary.save(writer); + } + + Future _saveTrailerAsync( + IPdfWriter writer, + int count, + int prevCrossReference, + ) async { + writer.write(PdfOperators.trailer); + writer.write(PdfOperators.newLine); + PdfDictionary trailerDictionary = trailer!; + if (prevCrossReference != 0) { + trailer![PdfDictionaryProperties.prev] = PdfNumber(prevCrossReference); + } + trailerDictionary[PdfDictionaryProperties.size] = PdfNumber(_count); + trailerDictionary = PdfDictionary(trailerDictionary); + trailerDictionary.encrypt = false; + trailerDictionary.save(writer); + } + + void _saveEnd(IPdfWriter writer, int? position) { + writer.write( + PdfOperators.newLine + + PdfOperators.startCrossReference + + PdfOperators.newLine, + ); + writer.write(position.toString() + PdfOperators.newLine); + writer.write(PdfOperators.endOfFileMarker); + writer.write(PdfOperators.newLine); + } + + Future _saveEndAsync(IPdfWriter writer, int? position) async { + writer.write( + PdfOperators.newLine + + PdfOperators.startCrossReference + + PdfOperators.newLine, + ); + writer.write(position.toString() + PdfOperators.newLine); + writer.write(PdfOperators.endOfFileMarker); + writer.write(PdfOperators.newLine); + } + + /// internal method + static IPdfPrimitive? dereference(IPdfPrimitive? element) { + if (element != null && element is PdfReferenceHolder) { + final PdfReferenceHolder holder = element; + return holder.object; + } + return element; + } + + /// internal method + void dispose() { + if (items != null) { + items!.dispose(); + items = null; + } + if (_objects != null && _objects!.isNotEmpty) { + _objects!.clear(); + _objects = null; + } + } + + /// internal method + IPdfPrimitive? getObject(IPdfPrimitive? pointer) { + bool isEncryptedMetadata = true; + IPdfPrimitive? result = pointer; + if (pointer is PdfReferenceHolder) { + result = pointer.object; + } else if (pointer is PdfReference) { + final PdfReference reference = pointer; + objNumbers.addLast(pointer); + IPdfPrimitive? obj; + if (crossTable != null) { + obj = crossTable!.getObject(pointer); + } else { + final int? index = items!.getObjectIndex(reference); + if (index == 0) { + obj = items!.getObjectFromReference(reference); + } + } + obj = _pageProceed(obj); + final PdfMainObjectCollection? goc = items; + if (obj != null) { + if (goc!.containsReference(reference)) { + goc.getObjectIndex(reference); + obj = goc.getObjectFromReference(reference); + } else { + goc.add(obj, reference); + obj.position = -1; + reference.position = -1; + } + } + result = obj; + if (obj != null && obj is PdfDictionary) { + final PdfDictionary dictionary = obj; + if (dictionary.containsKey(PdfDictionaryProperties.type)) { + final IPdfPrimitive? primitive = + dictionary[PdfDictionaryProperties.type]; + if (primitive != null && + primitive is PdfName && + primitive.name == PdfDictionaryProperties.metadata) { + if (encryptor != null) { + isEncryptedMetadata = encryptor!.encryptMetadata; + } + } + } + } + if (PdfDocumentHelper.getHelper(document!).isEncrypted && + isEncryptedMetadata) { + _decrypt(result); + } + } + if (pointer is PdfReference) { + objNumbers.removeLast(); + } + return result; + } + + IPdfPrimitive? _pageProceed(IPdfPrimitive? obj) { + if (obj is PdfPage) { + return obj; + } + if (obj is PdfDictionary) { + final PdfDictionary dic = obj; + if (obj is! PdfPage) { + if (dic.containsKey(PdfDictionaryProperties.type)) { + final IPdfPrimitive? objType = dic[PdfDictionaryProperties.type]; + if (objType is PdfName) { + final PdfName type = getObject(objType)! as PdfName; + if (type.name == 'Page') { + if (!dic.containsKey(PdfDictionaryProperties.kids)) { + if (PdfDocumentHelper.getHelper( + _pdfDocument!, + ).isLoadedDocument) { + final PdfPage lPage = PdfPageCollectionHelper.getHelper( + _pdfDocument!.pages, + ).getPage(dic); + obj = IPdfWrapper.getElement(lPage); + final PdfMainObjectCollection items = + PdfDocumentHelper.getHelper(_pdfDocument!).objects; + final int index = items.lookFor(dic)!; + if (index >= 0) { + items.reregisterReference(index, obj!); + obj.position = -1; + } + } + } + } + } + } + } + } + return obj; + } + + bool _isCrossReferenceStream(PdfDocument? document) { + ArgumentError.notNull('document'); + bool result = false; + if (crossTable != null) { + if (crossTable!.trailer is PdfStream) { + result = true; + } + } else { + result = + document!.fileStructure.crossReferenceType == + PdfCrossReferenceType.crossReferenceStream; + } + return result; + } + + Future _isCrossReferenceStreamAsync(PdfDocument? document) async { + ArgumentError.notNull('document'); + bool result = false; + if (crossTable != null) { + if (crossTable!.trailer is PdfStream) { + result = true; + } + } else { + result = + document!.fileStructure.crossReferenceType == + PdfCrossReferenceType.crossReferenceStream; + } + return result; + } + + void _saveArchives(PdfWriter writer) { + if (_archives != null) { + for (final _ArchiveInfo ai in _archives!) { + PdfReference? reference = ai._reference; + if (reference == null) { + reference = PdfReference(nextObjectNumber, 0); + ai._reference = reference; + } + PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; + _registerObject(reference, position: writer.position); + _doSaveObject(ai._archive!, reference, writer); + } + } + } + + Future _saveArchivesAsync(PdfWriter writer) async { + if (_archives != null) { + for (final _ArchiveInfo ai in _archives!) { + PdfReference? reference = ai._reference; + if (reference == null) { + reference = PdfReference(nextObjectNumber, 0); + ai._reference = reference; + } + PdfDocumentHelper.getHelper(document!).currentSavingObject = reference; + await _registerObjectAsync(reference, position: writer.position).then(( + _, + ) async { + await _doSaveObjectAsync(ai._archive!, reference!, writer); + }); + } + } + } + + void _doArchiveObject( + IPdfPrimitive obj, + PdfReference reference, + PdfWriter writer, + ) { + if (_archive == null) { + _archive = PdfArchiveStream(document); + _saveArchive(writer); + } + _registerObject(reference, archive: _archive); + _archive!.saveObject(obj, reference); + if (_archive!.objCount >= 100) { + _archive = null; + } + } + + Future _doArchiveObjectAsync( + IPdfPrimitive obj, + PdfReference reference, + PdfWriter writer, + ) async { + if (_archive == null) { + _archive = PdfArchiveStream(document); + await _saveArchiveAsync(writer); + } + await _registerObjectAsync(reference, archive: _archive); + await _archive!.saveObjectAsync(obj, reference).then((_) { + if (_archive!.objCount >= 100) { + _archive = null; + } + }); + } + + void _saveArchive(PdfWriter writer) { + final _ArchiveInfo ai = _ArchiveInfo(null, _archive); + _archives ??= <_ArchiveInfo>[]; + _archives!.add(ai); + } + + Future _saveArchiveAsync(PdfWriter writer) async { + final _ArchiveInfo ai = _ArchiveInfo(null, _archive); + _archives ??= <_ArchiveInfo>[]; + _archives!.add(ai); + } + + Map _prepareXRefStream( + double prevXRef, + double position, + PdfReference? reference, + ) { + PdfStream? xRefStream; + xRefStream = _trailer as PdfStream?; + if (xRefStream == null) { + xRefStream = PdfStream(); + } else { + xRefStream.remove(PdfDictionaryProperties.filter); + xRefStream.remove(PdfDictionaryProperties.decodeParms); + } + final PdfArray sectionIndeces = PdfArray(); + reference = PdfReference(nextObjectNumber, 0); + _registerObject(reference, position: position.toInt()); + + double objectNum = 0; + double count = 0; + final List paramsFormat = [1, 8, 1]; + paramsFormat[1] = max(_getSize(position), _getSize(this.count.toDouble())); + paramsFormat[2] = _getSize(_maxGenNumIndex); + final List ms = []; + while (true) { + final Map result = _prepareSubsection(objectNum.toInt()); + count = result['count']!.toDouble(); + objectNum = result['objectNumber']!.toDouble(); + if (count <= 0) { + break; + } else { + sectionIndeces.add(PdfNumber(objectNum)); + sectionIndeces.add(PdfNumber(count)); + _saveSubSection(ms, objectNum, count, paramsFormat); + objectNum += count; + } + } + //iw.Flush(); + xRefStream.data = ms; + xRefStream[PdfDictionaryProperties.index] = sectionIndeces; + xRefStream[PdfDictionaryProperties.size] = PdfNumber(this.count); + xRefStream[PdfDictionaryProperties.prev] = PdfNumber(prevXRef); + xRefStream[PdfDictionaryProperties.type] = PdfName('XRef'); + xRefStream[PdfDictionaryProperties.w] = PdfArray(paramsFormat); + if (crossTable != null) { + final PdfDictionary trailer = crossTable!.trailer!; + for (final PdfName? key in trailer.items!.keys) { + final bool contains = xRefStream.containsKey(key); + if (!contains && + key!.name != PdfDictionaryProperties.decodeParms && + key.name != PdfDictionaryProperties.filter) { + xRefStream[key] = trailer[key]; + } + } + } + if (prevXRef == 0 && xRefStream.containsKey(PdfDictionaryProperties.prev)) { + xRefStream.remove(PdfDictionaryProperties.prev); + } + xRefStream.encrypt = false; + return { + 'xRefStream': xRefStream, + 'reference': reference, + }; + } + + Future> _prepareXRefStreamAsync( + double prevXRef, + double position, + PdfReference? reference, + ) async { + PdfStream? xRefStream; + xRefStream = _trailer as PdfStream?; + if (xRefStream == null) { + xRefStream = PdfStream(); + } else { + xRefStream.remove(PdfDictionaryProperties.filter); + xRefStream.remove(PdfDictionaryProperties.decodeParms); + } + final PdfArray sectionIndeces = PdfArray(); + reference = PdfReference(nextObjectNumber, 0); + await _registerObjectAsync(reference, position: position.toInt()); + + double objectNum = 0; + double count = 0; + final List paramsFormat = [1, 8, 1]; + paramsFormat[1] = max( + await _getSizeAsync(position), + await _getSizeAsync(this.count.toDouble()), + ); + paramsFormat[2] = await _getSizeAsync(_maxGenNumIndex); + final List ms = []; + while (true) { + await _prepareSubsectionAsync(objectNum.toInt()).then(( + Map result, + ) { + count = result['count']!.toDouble(); + objectNum = result['objectNumber']!.toDouble(); + }); + if (count <= 0) { + break; + } else { + sectionIndeces.add(PdfNumber(objectNum)); + sectionIndeces.add(PdfNumber(count)); + await _saveSubSectionAsync(ms, objectNum, count, paramsFormat).then(( + _, + ) { + objectNum += count; + }); + } + } + //iw.Flush(); + xRefStream.data = ms; + xRefStream[PdfDictionaryProperties.index] = sectionIndeces; + xRefStream[PdfDictionaryProperties.size] = PdfNumber(this.count); + xRefStream[PdfDictionaryProperties.prev] = PdfNumber(prevXRef); + xRefStream[PdfDictionaryProperties.type] = PdfName('XRef'); + xRefStream[PdfDictionaryProperties.w] = PdfArray(paramsFormat); + if (crossTable != null) { + final PdfDictionary trailer = crossTable!.trailer!; + for (final PdfName? key in trailer.items!.keys) { + final bool contains = xRefStream.containsKey(key); + if (!contains && + key!.name != PdfDictionaryProperties.decodeParms && + key.name != PdfDictionaryProperties.filter) { + xRefStream[key] = trailer[key]; + } + } + } + if (prevXRef == 0 && xRefStream.containsKey(PdfDictionaryProperties.prev)) { + xRefStream.remove(PdfDictionaryProperties.prev); + } + xRefStream.encrypt = false; + return { + 'xRefStream': xRefStream, + 'reference': reference, + }; + } + + int _getSize(double number) { + int size = 0; + + if (number < 4294967295) { + if (number < 65535) { + if (number < 255) { + size = 1; + } else { + size = 2; + } + } else { + if (number < (65535 | 65535 << 8)) { + size = 3; + } else { + size = 4; + } + } + } else { + size = 8; + } + return size; + } + + Future _getSizeAsync(double number) async { + int size = 0; + + if (number < 4294967295) { + if (number < 65535) { + if (number < 255) { + size = 1; + } else { + size = 2; + } + } else { + if (number < (65535 | 65535 << 8)) { + size = 3; + } else { + size = 4; + } + } + } else { + size = 8; + } + return size; + } + + void _saveSubSection( + List xRefStream, + double objectNum, + double count, + List format, + ) { + for (int i = objectNum.toInt(); i < objectNum + count; ++i) { + final _RegisteredObject obj = _objects![i]!; + xRefStream.add(obj._type!.index.toUnsigned(8)); + switch (obj._type) { + case PdfObjectType.free: + _saveLong(xRefStream, obj._objectNumber!.toInt(), format[1]); + _saveLong(xRefStream, obj._generationNumber, format[2]); + break; + + case PdfObjectType.normal: + _saveLong(xRefStream, obj.offset, format[1]); + _saveLong(xRefStream, obj._generationNumber, format[2]); + break; + + case PdfObjectType.packed: + _saveLong(xRefStream, obj._objectNumber!.toInt(), format[1]); + _saveLong(xRefStream, obj.offset, format[2]); + break; + + // ignore: no_default_cases + default: + throw ArgumentError('Internal error: Undefined object type.'); + } + } + } + + Future _saveSubSectionAsync( + List xRefStream, + double objectNum, + double count, + List format, + ) async { + for (int i = objectNum.toInt(); i < objectNum + count; ++i) { + final _RegisteredObject obj = _objects![i]!; + xRefStream.add(obj._type!.index.toUnsigned(8)); + switch (obj._type) { + case PdfObjectType.free: + await _saveLongAsync( + xRefStream, + obj._objectNumber!.toInt(), + format[1], + ); + await _saveLongAsync(xRefStream, obj._generationNumber, format[2]); + break; + + case PdfObjectType.normal: + await _saveLongAsync(xRefStream, obj.offset, format[1]); + await _saveLongAsync(xRefStream, obj._generationNumber, format[2]); + break; + + case PdfObjectType.packed: + await _saveLongAsync( + xRefStream, + obj._objectNumber!.toInt(), + format[1], + ); + await _saveLongAsync(xRefStream, obj.offset, format[2]); + break; + + // ignore: no_default_cases + default: + throw ArgumentError('Internal error: Undefined object type.'); + } + } + } + + void _saveLong(List xRefStream, int? number, int count) { + for (int i = count - 1; i >= 0; --i) { + final int b = (number! >> (i << 3) & 255).toUnsigned(8); + xRefStream.add(b); + } + } + + Future _saveLongAsync( + List xRefStream, + int? number, + int count, + ) async { + for (int i = count - 1; i >= 0; --i) { + final int b = (number! >> (i << 3) & 255).toUnsigned(8); + xRefStream.add(b); + } + } + + PdfReference _findArchiveReference(PdfArchiveStream archive) { + int i = 0; + late _ArchiveInfo ai; + for (final int count = _archives!.length; i < count; ++i) { + ai = _archives![i]; + if (ai._archive == archive) { + break; + } + } + PdfReference? reference = ai._reference; + reference ??= PdfReference(nextObjectNumber, 0); + ai._reference = reference; + return reference; + } + + Future _findArchiveReferenceAsync( + PdfArchiveStream archive, + ) async { + int i = 0; + late _ArchiveInfo ai; + for (final int count = _archives!.length; i < count; ++i) { + ai = _archives![i]; + if (ai._archive == archive) { + break; + } + } + PdfReference? reference = ai._reference; + reference ??= PdfReference(nextObjectNumber, 0); + ai._reference = reference; + return reference; + } + + void _decrypt(IPdfPrimitive? obj) { + if (obj != null) { + if (obj is PdfDictionary || obj is PdfStream) { + final PdfDictionary dic = obj as PdfDictionary; + _isOutlineOrDestination = _checkForOutlinesAndDestination(dic); + if (!dic.decrypted!) { + dic.items!.forEach((PdfName? key, IPdfPrimitive? element) { + _decrypt(element); + }); + if (obj is PdfStream) { + final PdfStream stream = obj; + if (objNumbers.isNotEmpty) { + stream.crossTable = this; + stream.objNumber = objNumbers.last.objNum; + } else if (PdfDocumentHelper.getHelper(document!).isEncrypted && + !stream.decrypted! && + objNumbers.isNotEmpty && + encryptor != null && + !encryptor!.encryptAttachmentOnly!) { + stream.decrypt(encryptor!, objNumbers.last.objNum); + } + } + } + _isOutlineOrDestination = false; + } else if (obj is PdfArray) { + final PdfArray array = obj; + for (final IPdfPrimitive? element in array.elements) { + if (element != null && element is PdfName) { + final PdfName name = element; + if (name.name == 'Indexed') { + _isColorSpace = true; + } + } + _decrypt(element); + } + _isColorSpace = false; + } else if (obj is PdfString) { + final PdfString str = obj; + if (!str.decrypted && + (!str.isHex! || _isColorSpace || _isOutlineOrDestination)) { + if (PdfDocumentHelper.getHelper(document!).isEncrypted && + objNumbers.isNotEmpty) { + obj.decrypt(encryptor!, objNumbers.last.objNum); + } + } + } + } + } + + /// Checks the dictionary if it is an outline type. + bool _checkForOutlinesAndDestination(PdfDictionary dictionary) { + if (dictionary.containsKey(PdfDictionaryProperties.parent)) { + final IPdfPrimitive? outline = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.parent], + ); + if (outline != null && outline is PdfDictionary) { + if (documentCatalog != null && + documentCatalog!.containsKey(PdfDictionaryProperties.outlines)) { + final IPdfPrimitive? dict = PdfCrossTable.dereference( + documentCatalog![PdfDictionaryProperties.outlines], + ); + if (dict != null && dict is PdfDictionary && dict == outline) { + return true; + } else { + return _checkForOutlinesAndDestination(outline); + } + } + } + } else if (dictionary.containsKey(PdfDictionaryProperties.limits)) { + return true; + } + return false; + } +} + +/// Represents a registered object. +class _RegisteredObject { + _RegisteredObject(int? offset, PdfReference reference, [bool? isFreeType]) { + _offset = offset; + _generationNumber = reference.genNum; + _objNumber = reference.objNum!.toDouble(); + if (isFreeType != null) { + _type = isFreeType ? PdfObjectType.free : PdfObjectType.normal; + } else { + _type = PdfObjectType.normal; + _objNumber = reference.objNum!.toDouble(); + } + } + + _RegisteredObject.fromArchive( + PdfCrossTable xrefTable, + PdfArchiveStream? archive, + PdfReference reference, + ) { + _xrefTable = xrefTable; + _archive = archive; + _offset = reference.objNum; + _type = PdfObjectType.packed; + } + int? _offset; + int? _generationNumber; + PdfObjectType? _type; + double? _objNumber; + late PdfCrossTable _xrefTable; + PdfArchiveStream? _archive; + + int? get offset { + int? result; + if (_archive != null) { + result = _archive!.getIndex(_offset); + } else { + result = _offset; + } + return result; + } + + double? get _objectNumber { + _objNumber ??= 0; + if (_objNumber == 0) { + if (_archive != null) { + _objNumber = _xrefTable.getReference(_archive).objNum!.toDouble(); + } + } + return _objNumber; + } +} + +class _ArchiveInfo { + // Constructor + _ArchiveInfo(PdfReference? reference, PdfArchiveStream? archive) { + _reference = reference; + _archive = archive; + } + // Fields + PdfReference? _reference; + PdfArchiveStream? _archive; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_lexer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_lexer.dart index 967f7e0f5..5d4573dfb 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_lexer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_lexer.dart @@ -1,906 +1,906 @@ -import 'enums.dart'; -import 'pdf_reader.dart'; - -/// internal class -class PdfLexer { - //Constructor - /// internal constructor - PdfLexer(PdfReader reader) { - _initialize(reader); - } - - //Constants - /// internal field - final int bufferSize = 8192; - - /// internal field - final int f = -1; - - /// internal field - final int noState = -1; - - /// internal field - final int notAccept = 0; - - /// internal field - final int start = 1; - - /// internal field - final int end = 2; - - /// internal field - final int noAnchor = 4; - - /// internal field - final int bol = 256; - - /// internal field - final int eof = 257; - - /// internal field - final String prefix = '<<'; - - //Fields - late PdfReader _reader; - - /// internal field - late int bufferIndex; - - /// internal field - late int bufferRead; - - /// internal field - late int bufferStart; - - /// internal field - late int bufferEnd; - - /// internal field - late List buffer; - - /// internal field - bool _lastWasCr = false; - - /// internal field - late int line; - - /// internal field - late bool atBool; - - /// internal field - late State lexicalState; - - /// internal field - List stateTrans = [0, 81, 83]; - - /// internal field - late List accept; - - /// internal field - String? objectName; - - /// internal field - bool isArray = false; - - /// internal field - int paren = 0; - - /// internal field - String stringText = ''; - - /// internal field - bool skip = false; - - //Properties - /// internal property - int get position { - return _reader.position - bufferRead + bufferIndex; - } - - /// internal property - String get text => _text(); - - /// internal property - late List cMap; - - /// internal property - late List rMap; - - /// internal property - late List> next; - - //Implementation - void _initialize(PdfReader reader) { - _reader = reader; - buffer = List.filled(bufferSize, 0); - bufferRead = 0; - bufferIndex = 0; - bufferStart = 0; - bufferEnd = 0; - line = 0; - atBool = true; - lexicalState = State.initial; - accept = [ - notAccept, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - notAccept, - noAnchor, - noAnchor, - noAnchor, - noAnchor, - notAccept, - noAnchor, - notAccept, - noAnchor, - notAccept, - noAnchor, - notAccept, - noAnchor, - notAccept, - noAnchor, - notAccept, - noAnchor, - notAccept, - noAnchor, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - notAccept, - ]; - cMap = - _unpackFromString( - 1, - 258, - '3,17:8,3,11,17,3,4,17:18,3,17:4,1,17:2,7,2,17,26,17,26,28,16,27:10,17:2,5,17,6,17:2,13:6,17:11,35,17:8,14,12,15,17:3,23,30,13,33,21,22,17:2,36,31,17,24,34,32,29,17:2,19,25,18,20,17:2,37,17:2,10,17,10,17:128,8,9,0:2', - )[0]; - rMap = - _unpackFromString( - 1, - 88, - '0,1,2,1:2,3,4,1:2,5,6,7,1:3,8,1:18,9,1,10,11,12,13,14,15,16,17,18,19,20,21,7,8:2,22,23,24,25,13,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57', - )[0]; - next = _unpackFromString( - 58, - 38, - '1,2,3,4:2,5,37,6,3:3,4,3:2,7,8,9,3,42,3:2,44,10,3:2,46,48,11,50,52,3:2,38,3:2,12,3,54,-1:39,2:3,-1,2:6,-1,2:26,-1:5,13,-1:40,36,-1:37,9:2,-1:2,9:2,-1:3,9:21,-1:23,45,-1:41,11,49,-1:36,15,-1:11,35:3,84,35:33,-1:9,55,-1:34,14,-1:51,85,-1:18,63,17,63:8,64,63:26,-1,30:3,82,30:33,-1:20,56,-1:2,57,-1:33,41,-1:51,58,-1:36,43,-1:29,59,-1:31,47,-1:38,86,-1:3,60,-1:45,16,-1:36,51,-1:28,62,-1:35,53,-1:39,18,-1:52,65,-1:26,66,-1:3,67,-1:33,56,-1:31,87,-1:42,19,-1:35,20,-1:16,55:3,-1,55:6,-1,-1:26,-1,64,39,64,63,64:33,-1:24,69,-1:31,70,-1:49,71,-1:30,72,-1:35,74,-1:35,75,-1:49,21,-1:40,22,-1:40,76,-1:19,23,-1:39,77,-1:35,78,-1:41,79,-1:35,80,-1:50,24,-1:25,25,-1:15,1,26:2,27:2,26,28,26:4,27,40,29,26:7,29:3,26:3,29,26:2,29,26:2,29,26:4,-1:11,30,-1:26,1,31,32,31:4,33,31:4,34,31:25,-1:11,35,-1:50,61,-1:34,68,-1:34,73,-1:19', - ); - } - - List> _unpackFromString(int size1, int size2, String text) { - int colonIndex = -1; - String lengthString; - int sequenceLength = 0; - int sequenceInteger = 0; - int commaIndex; - String workString; - final List> res = List>.generate( - size1, - (int i) => List.generate(size2, (int j) => 0), - ); - for (int i = 0; i < size1; ++i) { - for (int j = 0; j < size2; ++j) { - if (sequenceLength != 0) { - res[i][j] = sequenceInteger; - --sequenceLength; - continue; - } - commaIndex = text.indexOf(','); - workString = (commaIndex == -1) ? text : text.substring(0, commaIndex); - text = text.substring(commaIndex + 1); - colonIndex = workString.indexOf(':'); - - if (colonIndex == -1) { - res[i][j] = int.tryParse(workString)!; - continue; - } - lengthString = workString.substring(colonIndex + 1); - final int? sl = int.tryParse(lengthString); - if (sl != null) { - sequenceLength = sl; - } - workString = workString.substring(0, colonIndex); - final int? si = int.tryParse(workString); - if (si != null) { - sequenceInteger = si; - } - res[i][j] = sequenceInteger; - --sequenceLength; - } - } - return res; - } - - /// internal method - void reset() { - buffer = List.filled(bufferSize, 0); - bufferRead = 0; - bufferIndex = 0; - bufferStart = 0; - bufferEnd = 0; - line = 0; - atBool = true; - lexicalState = State.initial; - } - - void _markStart() { - for (int i = bufferStart; i < bufferIndex; ++i) { - if (10 == buffer[i] && !_lastWasCr) { - ++line; - } - if (13 == buffer[i]) { - ++line; - _lastWasCr = true; - } else { - _lastWasCr = false; - } - } - bufferStart = bufferIndex; - } - - void _markEnd() { - bufferEnd = bufferIndex; - } - - int? _advance() { - if (bufferIndex < bufferRead) { - return buffer[bufferIndex++]; - } - - int nextRead; - - if (0 != bufferStart) { - int i = bufferStart; - int j = 0; - - while (i < bufferRead) { - buffer[j] = buffer[i]; - ++i; - ++j; - } - - bufferEnd -= bufferStart; - bufferStart = 0; - bufferRead = j; - bufferIndex = j; - - nextRead = _read(); - - if (nextRead <= 0) { - return eof; - } - } - - while (bufferIndex >= bufferRead) { - if (bufferIndex >= buffer.length) { - buffer = _double(buffer); - } - - nextRead = _read(); - - if (nextRead <= 0) { - return eof; - } - } - return buffer[bufferIndex++]; - } - - /// internal method - void skipNewLine() { - bufferIndex = bufferStart + 1; - - if (buffer[bufferIndex] == 13) { - if (buffer[bufferIndex + 1] == 10) { - bufferIndex += 2; - } - } else if (buffer[bufferIndex] == 10) { - if (buffer[bufferIndex - 1] != 10) { - bufferIndex += 1; - } - } - _markStart(); - } - - /// internal method - void skipToken() { - bufferStart = bufferEnd; - } - - List _double(List buffer) { - final int length = buffer.length; - final List newBuffer = List.filled(2 * length, 0, growable: true); - List.copyRange(newBuffer, 0, buffer, 0, length); - return newBuffer; - } - - int _read() { - final int nextRead = _reader.readData( - buffer, - bufferRead, - buffer.length - bufferRead, - ); - if (nextRead > 0) { - bufferRead += nextRead; - } - return nextRead; - } - - /// internal method - List readBytes(int count) { - final List list = List.filled(count, 0); - _markStart(); - if (bufferRead - bufferStart < count) { - while (buffer.length - bufferStart < count) { - buffer = _double(buffer); - } - } - final int readCount = _read(); - if (bufferRead - bufferStart < readCount) { - if (readCount > count) { - count = readCount; - } - } - int j = 0; - for (int i = bufferStart; i < bufferStart + count; ++i, bufferIndex = i) { - list[j++] = buffer[i]; - } - _markStart(); - _markEnd(); - return list; - } - - void _moveEnd() { - if (bufferEnd > bufferStart && 10 == buffer[bufferEnd - 1]) { - bufferEnd--; - } - if (bufferEnd > bufferStart && 13 == buffer[bufferEnd - 1]) { - bufferEnd--; - } - } - - void _toMark() { - bufferIndex = bufferEnd; - atBool = - (bufferEnd > bufferStart) && - (13 == buffer[bufferEnd - 1] || - 10 == buffer[bufferEnd - 1] || - 2028 == buffer[bufferEnd - 1] || - 2029 == buffer[bufferEnd - 1]); - } - - /// internal method - PdfTokenType getNextToken() { - int? lookAhead; - int anchor = noAnchor; - int state = stateTrans[lexicalState.index]; - int? nextState = noState; - int? lastAcceptState = noState; - bool initial = true; - int thisAccept; - - _markStart(); - thisAccept = accept[state]; - - if (notAccept != thisAccept) { - lastAcceptState = state; - _markEnd(); - } - - while (true) { - if (initial && atBool) { - lookAhead = bol; - } else { - lookAhead = _advance(); - } - - nextState = f; - nextState = next[rMap[state]][cMap[lookAhead!]]; - if (eof == lookAhead && initial) { - return PdfTokenType.eof; - } - if (f != nextState) { - state = nextState; - initial = false; - thisAccept = accept[state]; - if (notAccept != thisAccept) { - lastAcceptState = state; - _markEnd(); - } - } else { - if (noState == lastAcceptState) { - throw ArgumentError.value(noState, 'Lexical Error: Unmatched Input.'); - } else { - anchor = accept[lastAcceptState!]; - if (0 != (end & anchor)) { - _moveEnd(); - } - _toMark(); - switch (lastAcceptState) { - case 1: - break; - case -2: - break; - case 2: - { - break; - } - case -3: - break; - case 3: - { - break; - } - case -4: - break; - case 4: - { - break; - } - case -5: - break; - case 5: - { - _begin(State.hexString); - return PdfTokenType.hexStringStart; - } - case -6: - break; - case 6: - { - _begin(State.string); - stringText = ''; - break; - } - case -7: - break; - case 7: - { - return PdfTokenType.arrayStart; - } - case -8: - break; - case 8: - { - return PdfTokenType.arrayEnd; - } - case -9: - break; - case 9: - { - return PdfTokenType.name; - } - case -10: - break; - case 10: - { - return PdfTokenType.objectType; - } - case -11: - break; - case 11: - { - return PdfTokenType.number; - } - case -12: - break; - case 12: - { - return PdfTokenType.reference; - } - case -13: - break; - case 13: - { - return PdfTokenType.dictionaryStart; - } - case -14: - break; - case 14: - { - return PdfTokenType.dictionaryEnd; - } - case -15: - break; - case 15: - { - return PdfTokenType.real; - } - case -16: - break; - case 16: - { - return PdfTokenType.objectStart; - } - case -17: - break; - case 17: - { - return PdfTokenType.unicodeString; - } - case -18: - break; - case 18: - { - return PdfTokenType.boolean; - } - case -19: - break; - case 19: - { - return PdfTokenType.nullType; - } - case -20: - break; - case 20: - { - return PdfTokenType.xRef; - } - case -21: - break; - case 21: - { - return PdfTokenType.objectEnd; - } - case -22: - break; - case 22: - { - return PdfTokenType.streamStart; - } - case -23: - break; - case 23: - { - return PdfTokenType.trailer; - } - case -24: - break; - case 24: - { - return PdfTokenType.streamEnd; - } - case -25: - break; - case 25: - { - return PdfTokenType.startXRef; - } - case -26: - break; - case 26: - { - return PdfTokenType.hexStringWeird; - } - case -27: - break; - case 27: - { - return PdfTokenType.whiteSpace; - } - case -28: - break; - case 28: - { - _begin(State.initial); - return PdfTokenType.hexStringEnd; - } - case -29: - break; - case 29: - { - return PdfTokenType.hexDigit; - } - case -30: - break; - case 30: - { - return PdfTokenType.hexStringWeirdEscape; - } - case -31: - break; - case 31: - { - stringText += _text(); - break; - } - case -32: - break; - case 32: - { - if (paren > 0) { - stringText += _text(); - --paren; - } else { - _begin(State.initial); - return PdfTokenType.string; - } - break; - } - case -33: - break; - case 33: - { - stringText += _text(); - ++paren; - break; - } - case -34: - break; - case 34: - { - break; - } - case -35: - break; - case 35: - { - stringText += _text(); - break; - } - case -36: - break; - case 37: - { - _error(_Error.match, true); - break; - } - case -37: - break; - case 38: - { - return PdfTokenType.objectType; - } - case -38: - break; - case 39: - { - return PdfTokenType.unicodeString; - } - case -39: - break; - case 40: - { - return PdfTokenType.hexStringWeird; - } - case -40: - break; - case 42: - { - return PdfTokenType.unknown; - } - case -41: - break; - case 44: - return PdfTokenType.unknown; - case -42: - break; - case 46: - { - if (buffer[bufferIndex - 1] == 115 && - (buffer[bufferIndex] == 116 || buffer[bufferIndex] == 37)) { - break; - } else { - _error(_Error.match, true); - break; - } - } - case -43: - break; - case 48: - { - _error(_Error.match, true); - break; - } - case -44: - break; - case 50: - { - if (isArray) { - int index = bufferIndex - 2; - String text = ''; - for (int i = 0; i < 2; i++) { - text += String.fromCharCode(buffer[index]); - index++; - } - final double? value = double.tryParse(text); - if (value != null && - buffer[bufferIndex - 1] == '.'.codeUnitAt(0) && - (buffer[bufferIndex] == ' '.codeUnitAt(0) || - buffer[bufferIndex] == ']'.codeUnitAt(0))) { - break; - } - } else { - if (buffer[bufferIndex - 1] == '.'.codeUnitAt(0) && - buffer[bufferIndex] == '-'.codeUnitAt(0)) { - return PdfTokenType.unknown; - } - } - _error(_Error.match, true); - break; - } - case -45: - break; - case 52: - { - break; - } - case -46: - break; - case 54: - { - _error(_Error.match, true); - break; - } - case -47: - break; - default: - _error(_Error.internal, false); - break; - } - initial = true; - state = stateTrans[lexicalState.index]; - nextState = noState; - lastAcceptState = noState; - _markStart(); - thisAccept = accept[state]; - if (notAccept != thisAccept) { - lastAcceptState = state; - _markEnd(); - } - } - } - } - } - - String _text() { - if (buffer.length > 2 && bufferEnd > 2) { - final String end = String.fromCharCode(buffer[bufferEnd - 1]); - final String start = String.fromCharCode(buffer[bufferEnd - 2]); - final int value = bufferEnd - bufferStart; - if (end == ')' && (start == r'\' || start == '\u0000') && value > 3) { - int? index = bufferEnd; - final String text = String.fromCharCodes(buffer); - index = text.indexOf(end, bufferStart) + 1; - int prvIndex = 0; - while (text[index! - 2] == r'\') { - index = text.indexOf(end, index) + 1; - if (index > 0) { - prvIndex = index; - } else { - index = prvIndex; - break; - } - } - if (text[index] == '>' && text[index + 1] == '>') { - bufferIndex = index; - skip = false; - } else if (text.length > index + 2) { - if (text[index + 2] == '/') { - bufferIndex = index; - skip = false; - } else if (text[index + 1] == '/') { - bufferIndex = index; - skip = false; - } else if (text[index] == '/') { - bufferIndex = index; - skip = false; - } else if (text[index - 1] == ')') { - bufferIndex = index; - skip = false; - } else { - skip = true; - } - } else { - skip = true; - } - final int tempIndex = text.indexOf(')', bufferEnd + 1); - if (tempIndex >= 0 && text[index - 1] == ')' && bufferEnd < index + 1) { - bufferEnd = bufferIndex; - } else { - bufferEnd = index; - } - } else if (end == ')' && value > 3) { - int? index = bufferEnd; - final String text = String.fromCharCodes(buffer); - index = text.indexOf(end, bufferStart) + 1; - while (text[index! - 2] == r'\') { - index = text.indexOf(end, index) + 1; - } - if (bufferEnd > index + 1) { - bufferEnd = index; - } - if (text[index - 1] == ')') { - bufferIndex = index - 1; - skip = false; - } else { - skip = true; - } - } - } - return String.fromCharCodes(buffer.sublist(bufferStart, bufferEnd)); - } - - // ignore: use_setters_to_change_properties - void _begin(State state) { - lexicalState = state; - } - - void _error(_Error code, bool fatal) { - if (fatal) { - if (objectName != null) { - throw ArgumentError.value( - code, - 'Fatal Error occurred at $position.\n When reading object type of ${objectName!}', - ); - } else { - throw ArgumentError.value(code, 'Fatal Error occurred at $position'); - } - } - } -} - -enum State { initial, hexString, string } - -enum _Error { internal, match } +import 'enums.dart'; +import 'pdf_reader.dart'; + +/// internal class +class PdfLexer { + //Constructor + /// internal constructor + PdfLexer(PdfReader reader) { + _initialize(reader); + } + + //Constants + /// internal field + final int bufferSize = 8192; + + /// internal field + final int f = -1; + + /// internal field + final int noState = -1; + + /// internal field + final int notAccept = 0; + + /// internal field + final int start = 1; + + /// internal field + final int end = 2; + + /// internal field + final int noAnchor = 4; + + /// internal field + final int bol = 256; + + /// internal field + final int eof = 257; + + /// internal field + final String prefix = '<<'; + + //Fields + late PdfReader _reader; + + /// internal field + late int bufferIndex; + + /// internal field + late int bufferRead; + + /// internal field + late int bufferStart; + + /// internal field + late int bufferEnd; + + /// internal field + late List buffer; + + /// internal field + bool _lastWasCr = false; + + /// internal field + late int line; + + /// internal field + late bool atBool; + + /// internal field + late State lexicalState; + + /// internal field + List stateTrans = [0, 81, 83]; + + /// internal field + late List accept; + + /// internal field + String? objectName; + + /// internal field + bool isArray = false; + + /// internal field + int paren = 0; + + /// internal field + String stringText = ''; + + /// internal field + bool skip = false; + + //Properties + /// internal property + int get position { + return _reader.position - bufferRead + bufferIndex; + } + + /// internal property + String get text => _text(); + + /// internal property + late List cMap; + + /// internal property + late List rMap; + + /// internal property + late List> next; + + //Implementation + void _initialize(PdfReader reader) { + _reader = reader; + buffer = List.filled(bufferSize, 0); + bufferRead = 0; + bufferIndex = 0; + bufferStart = 0; + bufferEnd = 0; + line = 0; + atBool = true; + lexicalState = State.initial; + accept = [ + notAccept, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + notAccept, + noAnchor, + noAnchor, + noAnchor, + noAnchor, + notAccept, + noAnchor, + notAccept, + noAnchor, + notAccept, + noAnchor, + notAccept, + noAnchor, + notAccept, + noAnchor, + notAccept, + noAnchor, + notAccept, + noAnchor, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + notAccept, + ]; + cMap = + _unpackFromString( + 1, + 258, + '3,17:8,3,11,17,3,4,17:18,3,17:4,1,17:2,7,2,17,26,17,26,28,16,27:10,17:2,5,17,6,17:2,13:6,17:11,35,17:8,14,12,15,17:3,23,30,13,33,21,22,17:2,36,31,17,24,34,32,29,17:2,19,25,18,20,17:2,37,17:2,10,17,10,17:128,8,9,0:2', + )[0]; + rMap = + _unpackFromString( + 1, + 88, + '0,1,2,1:2,3,4,1:2,5,6,7,1:3,8,1:18,9,1,10,11,12,13,14,15,16,17,18,19,20,21,7,8:2,22,23,24,25,13,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57', + )[0]; + next = _unpackFromString( + 58, + 38, + '1,2,3,4:2,5,37,6,3:3,4,3:2,7,8,9,3,42,3:2,44,10,3:2,46,48,11,50,52,3:2,38,3:2,12,3,54,-1:39,2:3,-1,2:6,-1,2:26,-1:5,13,-1:40,36,-1:37,9:2,-1:2,9:2,-1:3,9:21,-1:23,45,-1:41,11,49,-1:36,15,-1:11,35:3,84,35:33,-1:9,55,-1:34,14,-1:51,85,-1:18,63,17,63:8,64,63:26,-1,30:3,82,30:33,-1:20,56,-1:2,57,-1:33,41,-1:51,58,-1:36,43,-1:29,59,-1:31,47,-1:38,86,-1:3,60,-1:45,16,-1:36,51,-1:28,62,-1:35,53,-1:39,18,-1:52,65,-1:26,66,-1:3,67,-1:33,56,-1:31,87,-1:42,19,-1:35,20,-1:16,55:3,-1,55:6,-1,-1:26,-1,64,39,64,63,64:33,-1:24,69,-1:31,70,-1:49,71,-1:30,72,-1:35,74,-1:35,75,-1:49,21,-1:40,22,-1:40,76,-1:19,23,-1:39,77,-1:35,78,-1:41,79,-1:35,80,-1:50,24,-1:25,25,-1:15,1,26:2,27:2,26,28,26:4,27,40,29,26:7,29:3,26:3,29,26:2,29,26:2,29,26:4,-1:11,30,-1:26,1,31,32,31:4,33,31:4,34,31:25,-1:11,35,-1:50,61,-1:34,68,-1:34,73,-1:19', + ); + } + + List> _unpackFromString(int size1, int size2, String text) { + int colonIndex = -1; + String lengthString; + int sequenceLength = 0; + int sequenceInteger = 0; + int commaIndex; + String workString; + final List> res = List>.generate( + size1, + (int i) => List.generate(size2, (int j) => 0), + ); + for (int i = 0; i < size1; ++i) { + for (int j = 0; j < size2; ++j) { + if (sequenceLength != 0) { + res[i][j] = sequenceInteger; + --sequenceLength; + continue; + } + commaIndex = text.indexOf(','); + workString = (commaIndex == -1) ? text : text.substring(0, commaIndex); + text = text.substring(commaIndex + 1); + colonIndex = workString.indexOf(':'); + + if (colonIndex == -1) { + res[i][j] = int.tryParse(workString)!; + continue; + } + lengthString = workString.substring(colonIndex + 1); + final int? sl = int.tryParse(lengthString); + if (sl != null) { + sequenceLength = sl; + } + workString = workString.substring(0, colonIndex); + final int? si = int.tryParse(workString); + if (si != null) { + sequenceInteger = si; + } + res[i][j] = sequenceInteger; + --sequenceLength; + } + } + return res; + } + + /// internal method + void reset() { + buffer = List.filled(bufferSize, 0); + bufferRead = 0; + bufferIndex = 0; + bufferStart = 0; + bufferEnd = 0; + line = 0; + atBool = true; + lexicalState = State.initial; + } + + void _markStart() { + for (int i = bufferStart; i < bufferIndex; ++i) { + if (10 == buffer[i] && !_lastWasCr) { + ++line; + } + if (13 == buffer[i]) { + ++line; + _lastWasCr = true; + } else { + _lastWasCr = false; + } + } + bufferStart = bufferIndex; + } + + void _markEnd() { + bufferEnd = bufferIndex; + } + + int? _advance() { + if (bufferIndex < bufferRead) { + return buffer[bufferIndex++]; + } + + int nextRead; + + if (0 != bufferStart) { + int i = bufferStart; + int j = 0; + + while (i < bufferRead) { + buffer[j] = buffer[i]; + ++i; + ++j; + } + + bufferEnd -= bufferStart; + bufferStart = 0; + bufferRead = j; + bufferIndex = j; + + nextRead = _read(); + + if (nextRead <= 0) { + return eof; + } + } + + while (bufferIndex >= bufferRead) { + if (bufferIndex >= buffer.length) { + buffer = _double(buffer); + } + + nextRead = _read(); + + if (nextRead <= 0) { + return eof; + } + } + return buffer[bufferIndex++]; + } + + /// internal method + void skipNewLine() { + bufferIndex = bufferStart + 1; + + if (buffer[bufferIndex] == 13) { + if (buffer[bufferIndex + 1] == 10) { + bufferIndex += 2; + } + } else if (buffer[bufferIndex] == 10) { + if (buffer[bufferIndex - 1] != 10) { + bufferIndex += 1; + } + } + _markStart(); + } + + /// internal method + void skipToken() { + bufferStart = bufferEnd; + } + + List _double(List buffer) { + final int length = buffer.length; + final List newBuffer = List.filled(2 * length, 0, growable: true); + List.copyRange(newBuffer, 0, buffer, 0, length); + return newBuffer; + } + + int _read() { + final int nextRead = _reader.readData( + buffer, + bufferRead, + buffer.length - bufferRead, + ); + if (nextRead > 0) { + bufferRead += nextRead; + } + return nextRead; + } + + /// internal method + List readBytes(int count) { + final List list = List.filled(count, 0); + _markStart(); + if (bufferRead - bufferStart < count) { + while (buffer.length - bufferStart < count) { + buffer = _double(buffer); + } + } + final int readCount = _read(); + if (bufferRead - bufferStart < readCount) { + if (readCount > count) { + count = readCount; + } + } + int j = 0; + for (int i = bufferStart; i < bufferStart + count; ++i, bufferIndex = i) { + list[j++] = buffer[i]; + } + _markStart(); + _markEnd(); + return list; + } + + void _moveEnd() { + if (bufferEnd > bufferStart && 10 == buffer[bufferEnd - 1]) { + bufferEnd--; + } + if (bufferEnd > bufferStart && 13 == buffer[bufferEnd - 1]) { + bufferEnd--; + } + } + + void _toMark() { + bufferIndex = bufferEnd; + atBool = + (bufferEnd > bufferStart) && + (13 == buffer[bufferEnd - 1] || + 10 == buffer[bufferEnd - 1] || + 2028 == buffer[bufferEnd - 1] || + 2029 == buffer[bufferEnd - 1]); + } + + /// internal method + PdfTokenType getNextToken() { + int? lookAhead; + int anchor = noAnchor; + int state = stateTrans[lexicalState.index]; + int? nextState = noState; + int? lastAcceptState = noState; + bool initial = true; + int thisAccept; + + _markStart(); + thisAccept = accept[state]; + + if (notAccept != thisAccept) { + lastAcceptState = state; + _markEnd(); + } + + while (true) { + if (initial && atBool) { + lookAhead = bol; + } else { + lookAhead = _advance(); + } + + nextState = f; + nextState = next[rMap[state]][cMap[lookAhead!]]; + if (eof == lookAhead && initial) { + return PdfTokenType.eof; + } + if (f != nextState) { + state = nextState; + initial = false; + thisAccept = accept[state]; + if (notAccept != thisAccept) { + lastAcceptState = state; + _markEnd(); + } + } else { + if (noState == lastAcceptState) { + throw ArgumentError.value(noState, 'Lexical Error: Unmatched Input.'); + } else { + anchor = accept[lastAcceptState!]; + if (0 != (end & anchor)) { + _moveEnd(); + } + _toMark(); + switch (lastAcceptState) { + case 1: + break; + case -2: + break; + case 2: + { + break; + } + case -3: + break; + case 3: + { + break; + } + case -4: + break; + case 4: + { + break; + } + case -5: + break; + case 5: + { + _begin(State.hexString); + return PdfTokenType.hexStringStart; + } + case -6: + break; + case 6: + { + _begin(State.string); + stringText = ''; + break; + } + case -7: + break; + case 7: + { + return PdfTokenType.arrayStart; + } + case -8: + break; + case 8: + { + return PdfTokenType.arrayEnd; + } + case -9: + break; + case 9: + { + return PdfTokenType.name; + } + case -10: + break; + case 10: + { + return PdfTokenType.objectType; + } + case -11: + break; + case 11: + { + return PdfTokenType.number; + } + case -12: + break; + case 12: + { + return PdfTokenType.reference; + } + case -13: + break; + case 13: + { + return PdfTokenType.dictionaryStart; + } + case -14: + break; + case 14: + { + return PdfTokenType.dictionaryEnd; + } + case -15: + break; + case 15: + { + return PdfTokenType.real; + } + case -16: + break; + case 16: + { + return PdfTokenType.objectStart; + } + case -17: + break; + case 17: + { + return PdfTokenType.unicodeString; + } + case -18: + break; + case 18: + { + return PdfTokenType.boolean; + } + case -19: + break; + case 19: + { + return PdfTokenType.nullType; + } + case -20: + break; + case 20: + { + return PdfTokenType.xRef; + } + case -21: + break; + case 21: + { + return PdfTokenType.objectEnd; + } + case -22: + break; + case 22: + { + return PdfTokenType.streamStart; + } + case -23: + break; + case 23: + { + return PdfTokenType.trailer; + } + case -24: + break; + case 24: + { + return PdfTokenType.streamEnd; + } + case -25: + break; + case 25: + { + return PdfTokenType.startXRef; + } + case -26: + break; + case 26: + { + return PdfTokenType.hexStringWeird; + } + case -27: + break; + case 27: + { + return PdfTokenType.whiteSpace; + } + case -28: + break; + case 28: + { + _begin(State.initial); + return PdfTokenType.hexStringEnd; + } + case -29: + break; + case 29: + { + return PdfTokenType.hexDigit; + } + case -30: + break; + case 30: + { + return PdfTokenType.hexStringWeirdEscape; + } + case -31: + break; + case 31: + { + stringText += _text(); + break; + } + case -32: + break; + case 32: + { + if (paren > 0) { + stringText += _text(); + --paren; + } else { + _begin(State.initial); + return PdfTokenType.string; + } + break; + } + case -33: + break; + case 33: + { + stringText += _text(); + ++paren; + break; + } + case -34: + break; + case 34: + { + break; + } + case -35: + break; + case 35: + { + stringText += _text(); + break; + } + case -36: + break; + case 37: + { + _error(_Error.match, true); + break; + } + case -37: + break; + case 38: + { + return PdfTokenType.objectType; + } + case -38: + break; + case 39: + { + return PdfTokenType.unicodeString; + } + case -39: + break; + case 40: + { + return PdfTokenType.hexStringWeird; + } + case -40: + break; + case 42: + { + return PdfTokenType.unknown; + } + case -41: + break; + case 44: + return PdfTokenType.unknown; + case -42: + break; + case 46: + { + if (buffer[bufferIndex - 1] == 115 && + (buffer[bufferIndex] == 116 || buffer[bufferIndex] == 37)) { + break; + } else { + _error(_Error.match, true); + break; + } + } + case -43: + break; + case 48: + { + _error(_Error.match, true); + break; + } + case -44: + break; + case 50: + { + if (isArray) { + int index = bufferIndex - 2; + String text = ''; + for (int i = 0; i < 2; i++) { + text += String.fromCharCode(buffer[index]); + index++; + } + final double? value = double.tryParse(text); + if (value != null && + buffer[bufferIndex - 1] == '.'.codeUnitAt(0) && + (buffer[bufferIndex] == ' '.codeUnitAt(0) || + buffer[bufferIndex] == ']'.codeUnitAt(0))) { + break; + } + } else { + if (buffer[bufferIndex - 1] == '.'.codeUnitAt(0) && + buffer[bufferIndex] == '-'.codeUnitAt(0)) { + return PdfTokenType.unknown; + } + } + _error(_Error.match, true); + break; + } + case -45: + break; + case 52: + { + break; + } + case -46: + break; + case 54: + { + _error(_Error.match, true); + break; + } + case -47: + break; + default: + _error(_Error.internal, false); + break; + } + initial = true; + state = stateTrans[lexicalState.index]; + nextState = noState; + lastAcceptState = noState; + _markStart(); + thisAccept = accept[state]; + if (notAccept != thisAccept) { + lastAcceptState = state; + _markEnd(); + } + } + } + } + } + + String _text() { + if (buffer.length > 2 && bufferEnd > 2) { + final String end = String.fromCharCode(buffer[bufferEnd - 1]); + final String start = String.fromCharCode(buffer[bufferEnd - 2]); + final int value = bufferEnd - bufferStart; + if (end == ')' && (start == r'\' || start == '\u0000') && value > 3) { + int? index = bufferEnd; + final String text = String.fromCharCodes(buffer); + index = text.indexOf(end, bufferStart) + 1; + int prvIndex = 0; + while (text[index! - 2] == r'\') { + index = text.indexOf(end, index) + 1; + if (index > 0) { + prvIndex = index; + } else { + index = prvIndex; + break; + } + } + if (text[index] == '>' && text[index + 1] == '>') { + bufferIndex = index; + skip = false; + } else if (text.length > index + 2) { + if (text[index + 2] == '/') { + bufferIndex = index; + skip = false; + } else if (text[index + 1] == '/') { + bufferIndex = index; + skip = false; + } else if (text[index] == '/') { + bufferIndex = index; + skip = false; + } else if (text[index - 1] == ')') { + bufferIndex = index; + skip = false; + } else { + skip = true; + } + } else { + skip = true; + } + final int tempIndex = text.indexOf(')', bufferEnd + 1); + if (tempIndex >= 0 && text[index - 1] == ')' && bufferEnd < index + 1) { + bufferEnd = bufferIndex; + } else { + bufferEnd = index; + } + } else if (end == ')' && value > 3) { + int? index = bufferEnd; + final String text = String.fromCharCodes(buffer); + index = text.indexOf(end, bufferStart) + 1; + while (text[index! - 2] == r'\') { + index = text.indexOf(end, index) + 1; + } + if (bufferEnd > index + 1) { + bufferEnd = index; + } + if (text[index - 1] == ')') { + bufferIndex = index - 1; + skip = false; + } else { + skip = true; + } + } + } + return String.fromCharCodes(buffer.sublist(bufferStart, bufferEnd)); + } + + // ignore: use_setters_to_change_properties + void _begin(State state) { + lexicalState = state; + } + + void _error(_Error code, bool fatal) { + if (fatal) { + if (objectName != null) { + throw ArgumentError.value( + code, + 'Fatal Error occurred at $position.\n When reading object type of ${objectName!}', + ); + } else { + throw ArgumentError.value(code, 'Fatal Error occurred at $position'); + } + } + } +} + +enum State { initial, hexString, string } + +enum _Error { internal, match } diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_main_object_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_main_object_collection.dart index 8ac908d88..4d7571e68 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_main_object_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_main_object_collection.dart @@ -1,363 +1,363 @@ -import '../../interfaces/pdf_interface.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference.dart'; -import 'enums.dart'; -import 'object_info.dart'; - -/// internal class -class PdfMainObjectCollection { - //Constructor - /// internal constructor - PdfMainObjectCollection() { - _initialize(); - } - - //Fields - int? _index; - - /// internal field - Map? mainObjectCollection; - - /// internal field - List? objectCollection; - Map? _primitiveObjectCollection; - - /// internal field - int? maximumReferenceObjectNumber = 0; - - //Properties - /// internal property - int get count { - return objectCollection!.length; - } - - /// Get the PdfMainObjectCollection items. - PdfObjectInfo operator [](int key) => _returnValue(key); - - //Implementation - void _initialize() { - _index = 0; - mainObjectCollection = {}; - objectCollection = []; - _primitiveObjectCollection = {}; - } - - /// Check key and return the value. - PdfObjectInfo _returnValue(int index) { - if (index < 0 || index > objectCollection!.length) { - throw ArgumentError.value(index, 'index', 'index out of range'); - } - return objectCollection![index]; - } - - /// internal property - bool containsReference(PdfReference reference) { - return mainObjectCollection!.containsKey(reference.objNum); - } - - /// Adds the specified element. - void add(dynamic element, [PdfReference? reference]) { - if (element == null) { - throw ArgumentError.value(element, 'element', 'value cannot be null'); - } - if (element is IPdfWrapper) { - element = IPdfWrapper.getElement(element); - } - if (reference == null) { - final PdfObjectInfo info = PdfObjectInfo(element); - objectCollection!.add(info); - if (!_primitiveObjectCollection!.containsKey(element)) { - _primitiveObjectCollection![element] = objectCollection!.length - 1; - } - element.position = objectCollection!.length - 1; - _index = objectCollection!.length - 1; - element.status = PdfObjectStatus.registered; - } else { - final PdfObjectInfo info = PdfObjectInfo(element, reference); - if (maximumReferenceObjectNumber! < reference.objNum!) { - maximumReferenceObjectNumber = reference.objNum; - } - objectCollection!.add(info); - if (!_primitiveObjectCollection!.containsKey(element)) { - _primitiveObjectCollection![element] = objectCollection!.length - 1; - } - mainObjectCollection![reference.objNum] = info; - element.position = objectCollection!.length - 1; - reference.position = objectCollection!.length - 1; - } - } - - /// Adds the specified element. - Future addAsync(dynamic element, [PdfReference? reference]) async { - if (element == null) { - throw ArgumentError.value(element, 'element', 'value cannot be null'); - } - if (element is IPdfWrapper) { - element = IPdfWrapper.getElement(element); - } - if (reference == null) { - final PdfObjectInfo info = PdfObjectInfo(element); - objectCollection!.add(info); - if (!_primitiveObjectCollection!.containsKey(element)) { - _primitiveObjectCollection![element] = objectCollection!.length - 1; - } - element.position = objectCollection!.length - 1; - _index = objectCollection!.length - 1; - element.status = PdfObjectStatus.registered; - } else { - final PdfObjectInfo info = PdfObjectInfo(element, reference); - if (maximumReferenceObjectNumber! < reference.objNum!) { - maximumReferenceObjectNumber = reference.objNum; - } - objectCollection!.add(info); - if (!_primitiveObjectCollection!.containsKey(element)) { - _primitiveObjectCollection![element] = objectCollection!.length - 1; - } - mainObjectCollection![reference.objNum] = info; - element.position = objectCollection!.length - 1; - reference.position = objectCollection!.length - 1; - } - } - - /// internal property - Map getReference(IPdfPrimitive object, bool? isNew) { - _index = lookFor(object); - PdfReference? reference; - if (_index! < 0 || _index! > count) { - isNew = true; - } else { - isNew = false; - final PdfObjectInfo objectInfo = objectCollection![_index!]; - reference = objectInfo.reference; - } - return {'isNew': isNew, 'reference': reference}; - } - - /// internal method - Future> getReferenceAsync( - IPdfPrimitive object, - bool? isNew, - ) async { - _index = await lookForAsync(object); - PdfReference? reference; - if (_index! < 0 || _index! > count) { - isNew = true; - } else { - isNew = false; - final PdfObjectInfo objectInfo = objectCollection![_index!]; - reference = objectInfo.reference; - } - return {'isNew': isNew, 'reference': reference}; - } - - /// internal property - bool contains(IPdfPrimitive element) { - return lookFor(element)! >= 0; - } - - /// internal property - int? lookFor(IPdfPrimitive obj) { - int? index = -1; - if (obj.position != -1) { - return obj.position; - } - if (_primitiveObjectCollection!.containsKey(obj) && - count == _primitiveObjectCollection!.length) { - index = _primitiveObjectCollection![obj]; - } else { - for (int i = count - 1; i >= 0; i--) { - final PdfObjectInfo objectInfo = objectCollection![i]; - final IPdfPrimitive? primitive = objectInfo.object; - final bool isValidType = - !((primitive is PdfName && obj is! PdfName) || - (primitive is! PdfName && obj is PdfName)); - if (isValidType && primitive == obj) { - index = i; - break; - } - } - } - return index; - } - - /// internal method - Future lookForAsync(IPdfPrimitive obj) async { - int? index = -1; - if (obj.position != -1) { - return obj.position; - } - if (_primitiveObjectCollection!.containsKey(obj) && - count == _primitiveObjectCollection!.length) { - index = _primitiveObjectCollection![obj]; - } else { - for (int i = count - 1; i >= 0; i--) { - final PdfObjectInfo objectInfo = objectCollection![i]; - final IPdfPrimitive? primitive = objectInfo.object; - final bool isValidType = - !((primitive is PdfName && obj is! PdfName) || - (primitive is! PdfName && obj is PdfName)); - if (isValidType && primitive == obj) { - index = i; - break; - } - } - } - return index; - } - - /// internal property - IPdfPrimitive? getObject(PdfReference reference) { - try { - return mainObjectCollection![reference.objNum]!.object; - } catch (e) { - return null; - } - } - - /// internal property - int? getObjectIndex(PdfReference reference) { - if (reference.position != -1) { - return reference.position; - } - if (mainObjectCollection!.isEmpty) { - if (objectCollection!.isEmpty) { - return -1; - } else { - for (int i = 0; i < objectCollection!.length - 1; i++) { - mainObjectCollection![objectCollection![i].reference!.objNum] = - objectCollection![i]; - } - if (!mainObjectCollection!.containsKey(reference.objNum)) { - return -1; - } else { - return 0; - } - } - } else { - if (!mainObjectCollection!.containsKey(reference.objNum)) { - return -1; - } else { - return 0; - } - } - } - - /// internal property - bool trySetReference(IPdfPrimitive object, PdfReference reference) { - bool result = true; - _index = lookFor(object); - if (_index! < 0 || _index! >= objectCollection!.length) { - result = false; - } else { - final PdfObjectInfo objectInfo = objectCollection![_index!]; - if (objectInfo.reference != null) { - result = false; - } else { - objectInfo.setReference(reference); - } - } - return result; - } - - /// internal method - Future trySetReferenceAsync( - IPdfPrimitive object, - PdfReference reference, - ) async { - bool result = true; - _index = await lookForAsync(object); - if (_index! < 0 || _index! >= objectCollection!.length) { - result = false; - } else { - final PdfObjectInfo objectInfo = objectCollection![_index!]; - if (objectInfo.reference != null) { - result = false; - } else { - await objectInfo.setReferenceAsync(reference); - } - } - return result; - } - - /// internal property - IPdfPrimitive? getObjectFromReference(PdfReference reference) { - try { - return mainObjectCollection![reference.objNum]!.object; - } catch (e) { - return null; - } - } - - /// internal property - void reregisterReference(int oldObjIndex, IPdfPrimitive newObj) { - if (oldObjIndex < 0 || oldObjIndex > count) { - throw ArgumentError.value( - oldObjIndex, - 'oldObjIndex', - 'index out of range', - ); - } - final PdfObjectInfo oi = objectCollection![oldObjIndex]; - if (oi.object != newObj) { - _primitiveObjectCollection!.remove(oi.object); - _primitiveObjectCollection![newObj] = oldObjIndex; - } - oi.object = newObj; - newObj.position = oldObjIndex; - } - - /// internal method - Future reregisterReferenceAsync( - int oldObjIndex, - IPdfPrimitive newObj, - ) async { - if (oldObjIndex < 0 || oldObjIndex > count) { - throw ArgumentError.value( - oldObjIndex, - 'oldObjIndex', - 'index out of range', - ); - } - final PdfObjectInfo oi = objectCollection![oldObjIndex]; - if (oi.object != newObj) { - _primitiveObjectCollection!.remove(oi.object); - _primitiveObjectCollection![newObj] = oldObjIndex; - } - oi.object = newObj; - newObj.position = oldObjIndex; - } - - /// internal method - void remove(int index) { - if (mainObjectCollection != null && - mainObjectCollection!.containsKey(index)) { - if (objectCollection != null && - objectCollection!.contains(mainObjectCollection![index])) { - objectCollection!.remove(mainObjectCollection![index]); - } - mainObjectCollection!.remove(index); - } - } - - /// internal property - void dispose() { - if (mainObjectCollection != null) { - mainObjectCollection!.clear(); - mainObjectCollection = null; - } - if (objectCollection != null) { - objectCollection!.clear(); - objectCollection = null; - } - if (_primitiveObjectCollection != null && - _primitiveObjectCollection!.isNotEmpty) { - final List primitives = - _primitiveObjectCollection!.keys.toList(); - for (int i = 0; i < primitives.length; i++) { - primitives[i]!.dispose(); - } - _primitiveObjectCollection!.clear(); - _primitiveObjectCollection = null; - } - } -} +import '../../interfaces/pdf_interface.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference.dart'; +import 'enums.dart'; +import 'object_info.dart'; + +/// internal class +class PdfMainObjectCollection { + //Constructor + /// internal constructor + PdfMainObjectCollection() { + _initialize(); + } + + //Fields + int? _index; + + /// internal field + Map? mainObjectCollection; + + /// internal field + List? objectCollection; + Map? _primitiveObjectCollection; + + /// internal field + int? maximumReferenceObjectNumber = 0; + + //Properties + /// internal property + int get count { + return objectCollection!.length; + } + + /// Get the PdfMainObjectCollection items. + PdfObjectInfo operator [](int key) => _returnValue(key); + + //Implementation + void _initialize() { + _index = 0; + mainObjectCollection = {}; + objectCollection = []; + _primitiveObjectCollection = {}; + } + + /// Check key and return the value. + PdfObjectInfo _returnValue(int index) { + if (index < 0 || index > objectCollection!.length) { + throw ArgumentError.value(index, 'index', 'index out of range'); + } + return objectCollection![index]; + } + + /// internal property + bool containsReference(PdfReference reference) { + return mainObjectCollection!.containsKey(reference.objNum); + } + + /// Adds the specified element. + void add(dynamic element, [PdfReference? reference]) { + if (element == null) { + throw ArgumentError.value(element, 'element', 'value cannot be null'); + } + if (element is IPdfWrapper) { + element = IPdfWrapper.getElement(element); + } + if (reference == null) { + final PdfObjectInfo info = PdfObjectInfo(element); + objectCollection!.add(info); + if (!_primitiveObjectCollection!.containsKey(element)) { + _primitiveObjectCollection![element] = objectCollection!.length - 1; + } + element.position = objectCollection!.length - 1; + _index = objectCollection!.length - 1; + element.status = PdfObjectStatus.registered; + } else { + final PdfObjectInfo info = PdfObjectInfo(element, reference); + if (maximumReferenceObjectNumber! < reference.objNum!) { + maximumReferenceObjectNumber = reference.objNum; + } + objectCollection!.add(info); + if (!_primitiveObjectCollection!.containsKey(element)) { + _primitiveObjectCollection![element] = objectCollection!.length - 1; + } + mainObjectCollection![reference.objNum] = info; + element.position = objectCollection!.length - 1; + reference.position = objectCollection!.length - 1; + } + } + + /// Adds the specified element. + Future addAsync(dynamic element, [PdfReference? reference]) async { + if (element == null) { + throw ArgumentError.value(element, 'element', 'value cannot be null'); + } + if (element is IPdfWrapper) { + element = IPdfWrapper.getElement(element); + } + if (reference == null) { + final PdfObjectInfo info = PdfObjectInfo(element); + objectCollection!.add(info); + if (!_primitiveObjectCollection!.containsKey(element)) { + _primitiveObjectCollection![element] = objectCollection!.length - 1; + } + element.position = objectCollection!.length - 1; + _index = objectCollection!.length - 1; + element.status = PdfObjectStatus.registered; + } else { + final PdfObjectInfo info = PdfObjectInfo(element, reference); + if (maximumReferenceObjectNumber! < reference.objNum!) { + maximumReferenceObjectNumber = reference.objNum; + } + objectCollection!.add(info); + if (!_primitiveObjectCollection!.containsKey(element)) { + _primitiveObjectCollection![element] = objectCollection!.length - 1; + } + mainObjectCollection![reference.objNum] = info; + element.position = objectCollection!.length - 1; + reference.position = objectCollection!.length - 1; + } + } + + /// internal property + Map getReference(IPdfPrimitive object, bool? isNew) { + _index = lookFor(object); + PdfReference? reference; + if (_index! < 0 || _index! > count) { + isNew = true; + } else { + isNew = false; + final PdfObjectInfo objectInfo = objectCollection![_index!]; + reference = objectInfo.reference; + } + return {'isNew': isNew, 'reference': reference}; + } + + /// internal method + Future> getReferenceAsync( + IPdfPrimitive object, + bool? isNew, + ) async { + _index = await lookForAsync(object); + PdfReference? reference; + if (_index! < 0 || _index! > count) { + isNew = true; + } else { + isNew = false; + final PdfObjectInfo objectInfo = objectCollection![_index!]; + reference = objectInfo.reference; + } + return {'isNew': isNew, 'reference': reference}; + } + + /// internal property + bool contains(IPdfPrimitive element) { + return lookFor(element)! >= 0; + } + + /// internal property + int? lookFor(IPdfPrimitive obj) { + int? index = -1; + if (obj.position != -1) { + return obj.position; + } + if (_primitiveObjectCollection!.containsKey(obj) && + count == _primitiveObjectCollection!.length) { + index = _primitiveObjectCollection![obj]; + } else { + for (int i = count - 1; i >= 0; i--) { + final PdfObjectInfo objectInfo = objectCollection![i]; + final IPdfPrimitive? primitive = objectInfo.object; + final bool isValidType = + !((primitive is PdfName && obj is! PdfName) || + (primitive is! PdfName && obj is PdfName)); + if (isValidType && primitive == obj) { + index = i; + break; + } + } + } + return index; + } + + /// internal method + Future lookForAsync(IPdfPrimitive obj) async { + int? index = -1; + if (obj.position != -1) { + return obj.position; + } + if (_primitiveObjectCollection!.containsKey(obj) && + count == _primitiveObjectCollection!.length) { + index = _primitiveObjectCollection![obj]; + } else { + for (int i = count - 1; i >= 0; i--) { + final PdfObjectInfo objectInfo = objectCollection![i]; + final IPdfPrimitive? primitive = objectInfo.object; + final bool isValidType = + !((primitive is PdfName && obj is! PdfName) || + (primitive is! PdfName && obj is PdfName)); + if (isValidType && primitive == obj) { + index = i; + break; + } + } + } + return index; + } + + /// internal property + IPdfPrimitive? getObject(PdfReference reference) { + try { + return mainObjectCollection![reference.objNum]!.object; + } catch (e) { + return null; + } + } + + /// internal property + int? getObjectIndex(PdfReference reference) { + if (reference.position != -1) { + return reference.position; + } + if (mainObjectCollection!.isEmpty) { + if (objectCollection!.isEmpty) { + return -1; + } else { + for (int i = 0; i < objectCollection!.length - 1; i++) { + mainObjectCollection![objectCollection![i].reference!.objNum] = + objectCollection![i]; + } + if (!mainObjectCollection!.containsKey(reference.objNum)) { + return -1; + } else { + return 0; + } + } + } else { + if (!mainObjectCollection!.containsKey(reference.objNum)) { + return -1; + } else { + return 0; + } + } + } + + /// internal property + bool trySetReference(IPdfPrimitive object, PdfReference reference) { + bool result = true; + _index = lookFor(object); + if (_index! < 0 || _index! >= objectCollection!.length) { + result = false; + } else { + final PdfObjectInfo objectInfo = objectCollection![_index!]; + if (objectInfo.reference != null) { + result = false; + } else { + objectInfo.setReference(reference); + } + } + return result; + } + + /// internal method + Future trySetReferenceAsync( + IPdfPrimitive object, + PdfReference reference, + ) async { + bool result = true; + _index = await lookForAsync(object); + if (_index! < 0 || _index! >= objectCollection!.length) { + result = false; + } else { + final PdfObjectInfo objectInfo = objectCollection![_index!]; + if (objectInfo.reference != null) { + result = false; + } else { + await objectInfo.setReferenceAsync(reference); + } + } + return result; + } + + /// internal property + IPdfPrimitive? getObjectFromReference(PdfReference reference) { + try { + return mainObjectCollection![reference.objNum]!.object; + } catch (e) { + return null; + } + } + + /// internal property + void reregisterReference(int oldObjIndex, IPdfPrimitive newObj) { + if (oldObjIndex < 0 || oldObjIndex > count) { + throw ArgumentError.value( + oldObjIndex, + 'oldObjIndex', + 'index out of range', + ); + } + final PdfObjectInfo oi = objectCollection![oldObjIndex]; + if (oi.object != newObj) { + _primitiveObjectCollection!.remove(oi.object); + _primitiveObjectCollection![newObj] = oldObjIndex; + } + oi.object = newObj; + newObj.position = oldObjIndex; + } + + /// internal method + Future reregisterReferenceAsync( + int oldObjIndex, + IPdfPrimitive newObj, + ) async { + if (oldObjIndex < 0 || oldObjIndex > count) { + throw ArgumentError.value( + oldObjIndex, + 'oldObjIndex', + 'index out of range', + ); + } + final PdfObjectInfo oi = objectCollection![oldObjIndex]; + if (oi.object != newObj) { + _primitiveObjectCollection!.remove(oi.object); + _primitiveObjectCollection![newObj] = oldObjIndex; + } + oi.object = newObj; + newObj.position = oldObjIndex; + } + + /// internal method + void remove(int index) { + if (mainObjectCollection != null && + mainObjectCollection!.containsKey(index)) { + if (objectCollection != null && + objectCollection!.contains(mainObjectCollection![index])) { + objectCollection!.remove(mainObjectCollection![index]); + } + mainObjectCollection!.remove(index); + } + } + + /// internal property + void dispose() { + if (mainObjectCollection != null) { + mainObjectCollection!.clear(); + mainObjectCollection = null; + } + if (objectCollection != null) { + objectCollection!.clear(); + objectCollection = null; + } + if (_primitiveObjectCollection != null && + _primitiveObjectCollection!.isNotEmpty) { + final List primitives = + _primitiveObjectCollection!.keys.toList(); + for (int i = 0; i < primitives.length; i++) { + primitives[i]!.dispose(); + } + _primitiveObjectCollection!.clear(); + _primitiveObjectCollection = null; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_parser.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_parser.dart index b62208810..2eae78ef7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_parser.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_parser.dart @@ -1,891 +1,891 @@ -import 'dart:collection'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/fdf_parser.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'cross_table.dart'; -import 'decode_big_endian.dart'; -import 'enums.dart'; -import 'pdf_constants.dart'; -import 'pdf_cross_table.dart'; -import 'pdf_lexer.dart'; -import 'pdf_reader.dart'; - -/// internal class -class PdfParser { - //Constructor - /// internal constructor - PdfParser(CrossTable cTable, PdfReader reader, PdfCrossTable crossTable) { - _isColorSpace = false; - _isPassword = false; - _reader = reader; - _cTable = cTable; - _crossTable = crossTable; - _lexer = PdfLexer(reader); - } - - //Fields - CrossTable? _cTable; - late PdfReader _reader; - PdfLexer? _lexer; - PdfTokenType? _next; - PdfCrossTable? _crossTable; - - /// internal field - Queue integerQueue = Queue(); - late bool _isPassword; - late bool _isColorSpace; - List? _windows1252MapTable; - - //Properties - /// internal property - List? get windows1252MapTable { - _windows1252MapTable ??= [ - '\u007f', - '€', - '\u0081', - '‚', - 'ƒ', - '„', - '…', - '†', - '‡', - 'ˆ', - '‰', - 'Š', - '‹', - 'Œ', - '\u008d', - 'Ž', - '\u008f', - '\u0090', - '‘', - '’', - '“', - '”', - '•', - '–', - '—', - '˜', - '™', - 'š', - '›', - 'œ', - '\u009d', - 'ž', - 'Ÿ', - ' ', - '¡', - '¢', - '£', - ]; - return _windows1252MapTable; - } - - /// internal property - PdfTokenType? get next => _next; - - /// internal property - PdfLexer? get lexer => _lexer; - - //Implementation - /// internal method - void setOffset(int offset) { - _reader.position = offset; - if (integerQueue.isNotEmpty) { - integerQueue = Queue(); - } - _lexer!.reset(); - } - - /// internal method - void advance() { - if (_cTable != null && _cTable!.validateSyntax) { - _lexer!.getNextToken(); - } - _next = _lexer!.getNextToken(); - } - - /// Read fdf object - FdfObject? parseObject() { - final IPdfPrimitive? num1 = simple(); - final IPdfPrimitive? num2 = simple(); - _match(_next, PdfTokenType.objectStart); - advance(); - final IPdfPrimitive? obj = simple(); - if (_next != PdfTokenType.objectEnd) { - _next = PdfTokenType.objectEnd; - } - _match(_next, PdfTokenType.objectEnd); - return num1 != null && - num2 != null && - obj != null && - num1 is PdfNumber && - num2 is PdfNumber - ? FdfObject(num1, num2, obj) - : null; - } - - /// internal method - IPdfPrimitive trailer() { - _match(_next, PdfTokenType.trailer); - advance(); - return _dictionary(); - } - - PdfNumber? _parseInteger() { - final double? value = double.tryParse(_lexer!.text); - PdfNumber? integer; - if (value != null) { - integer = PdfNumber(value); - } else { - _error(_ErrorType.badlyFormedInteger, _lexer!.text); - } - advance(); - return integer; - } - - IPdfPrimitive? _number() { - IPdfPrimitive? obj; - PdfNumber? integer; - if (integerQueue.isNotEmpty) { - integer = PdfNumber(integerQueue.removeFirst()); - } else { - _match(_next, PdfTokenType.number); - integer = _parseInteger(); - } - obj = integer; - if (_next == PdfTokenType.number) { - final PdfNumber? integer2 = _parseInteger(); - if (_next == PdfTokenType.reference) { - final PdfReference reference = PdfReference( - integer!.value!.toInt(), - integer2!.value!.toInt(), - ); - obj = PdfReferenceHolder.fromReference(reference, _crossTable); - advance(); - } else { - integerQueue.addLast(integer2!.value!.toInt()); - } - } - return obj; - } - - void _parseOldXRef(CrossTable cTable, Map? objects) { - advance(); - while (_isSubsection()) { - cTable.parseSubsection(this, objects); - } - } - - bool _isSubsection() { - bool result = false; - if (_next == PdfTokenType.trailer) { - result = false; - } else if (_next == PdfTokenType.number) { - result = true; - } else { - throw ArgumentError.value(result, 'Invalid format'); - } - return result; - } - - /// internal method - Map parseCrossReferenceTable( - Map? objects, - CrossTable cTable, - ) { - IPdfPrimitive? obj; - advance(); - if (_next == PdfTokenType.xRef) { - _parseOldXRef(cTable, objects); - obj = trailer(); - final PdfDictionary trailerDic = obj as PdfDictionary; - if (trailerDic.containsKey('Size')) { - final int size = (trailerDic['Size']! as PdfNumber).value!.toInt(); - int initialNumber = 0; - if (cTable.initialSubsectionCount == cTable.initialNumberOfSubsection) { - initialNumber = cTable.initialNumberOfSubsection; - } else { - initialNumber = cTable.initialSubsectionCount; - } - int total = 0; - total = cTable.totalNumberOfSubsection; - if (size < initialNumber + total && - initialNumber > 0 && - size == total) { - final int difference = initialNumber + total - size; - final Map newObjects = - {}; - final List keys = objects!.keys.toList(); - for (int i = 0; i < keys.length; i++) { - newObjects[keys[i] - difference] = objects[keys[i]]!; - } - objects = newObjects; - cTable.objects = newObjects; - } - } - } else { - obj = _parse(); - objects = cTable.parseNewTable(obj as PdfStream?, objects); - } - if (obj is PdfDictionary && - _crossTable != null && - obj.containsKey('XRefStm')) { - try { - int xrefStreamPosition = 0; - final PdfDictionary trailerDictionary = obj; - final IPdfPrimitive? pdfNumber = PdfCrossTable.dereference( - trailerDictionary['XRefStm'], - ); - if (pdfNumber != null && pdfNumber is PdfNumber) { - xrefStreamPosition = pdfNumber.value!.toInt(); - } - cTable.parser.setOffset(xrefStreamPosition); - final IPdfPrimitive? xrefStream = cTable.parser.parseOffset( - xrefStreamPosition, - ); - if (xrefStream != null && xrefStream is PdfStream) { - objects = cTable.parseNewTable(xrefStream, objects); - } - } catch (e) { - //exception may occurs if offest is not correct/crosstable is corrupted. - } - } - return {'object': obj, 'objects': objects}; - } - - /// internal method - IPdfPrimitive? parseOffset(int offset) { - setOffset(offset); - advance(); - return _parse(); - } - - IPdfPrimitive? _parse() { - _match(_next, PdfTokenType.number); - simple(); - simple(); - _match(_next, PdfTokenType.objectStart); - advance(); - final IPdfPrimitive? obj = simple(); - if (_next != PdfTokenType.objectEnd) { - _next = PdfTokenType.objectEnd; - } - _match(_next, PdfTokenType.objectEnd); - if (!_lexer!.skip) { - advance(); - } else { - _lexer!.skip = false; - } - return obj; - } - - /// internal method - IPdfPrimitive? simple() { - IPdfPrimitive? obj; - if (integerQueue.isNotEmpty) { - obj = _number(); - } else { - switch (_next) { - case PdfTokenType.dictionaryStart: - obj = _dictionary(); - break; - case PdfTokenType.arrayStart: - obj = _array(); - break; - case PdfTokenType.hexStringStart: - obj = _hexString(); - break; - case PdfTokenType.string: - obj = _readString(); - break; - case PdfTokenType.unicodeString: - obj = _readUnicodeString(); - break; - case PdfTokenType.name: - obj = _readName(); - break; - case PdfTokenType.boolean: - obj = _readBoolean(); - break; - case PdfTokenType.real: - obj = _real(); - break; - case PdfTokenType.number: - obj = _number(); - break; - case PdfTokenType.nullType: - obj = PdfNull(); - advance(); - break; - // ignore: no_default_cases - default: - obj = null; - break; - } - } - return obj; - } - - IPdfPrimitive? _real() { - _match(_next, PdfTokenType.real); - final double? value = double.tryParse(_lexer!.text); - PdfNumber? real; - if (value != null) { - real = PdfNumber(value); - } else { - _error(_ErrorType.badlyFormedReal, _lexer!.text); - } - advance(); - return real; - } - - IPdfPrimitive _readBoolean() { - _match(_next, PdfTokenType.boolean); - final bool value = _lexer!.text == 'true'; - final PdfBoolean result = PdfBoolean(value); - advance(); - return result; - } - - IPdfPrimitive _readName() { - _match(_next, PdfTokenType.name); - final String name = _lexer!.text.substring(1); - final PdfName result = PdfName(name); - advance(); - return result; - } - - /// internal method - void startFrom(int offset) { - setOffset(offset); - advance(); - } - - /// internal method - void rebuildXrefTable( - Map newObjects, - CrossTable? crosstable, - ) { - final PdfReader reader = PdfReader(_reader.streamReader.data); - reader.position = 0; - newObjects.clear(); - int? objNumber = 0; - int? marker = 0; - List previoursToken = ['\u0000']; - while (true) { - if (reader.position >= reader.length! - 1) { - break; - } - final int previousPosition = reader.position; - String str = ''; - str = reader.readLine(); - if (str == '') { - continue; - } - final List tokens = str.split(''); - final bool previousObject = - previoursToken[0].codeUnitAt(0) >= '0'.codeUnitAt(0) && - previoursToken[0].codeUnitAt(0) <= '9'.codeUnitAt(0) && - tokens.length > 1 && - tokens[1].codeUnitAt(0) >= '0'.codeUnitAt(0) && - tokens[1].codeUnitAt(0) <= '9'.codeUnitAt(0); - if (tokens[0].codeUnitAt(0) >= '0'.codeUnitAt(0) && - tokens[0].codeUnitAt(0) <= '9'.codeUnitAt(0) || - previousObject) { - if (!previousObject) { - previoursToken = tokens; - } - final List words = str.split(' '); - if (previousObject && words[0] == '') { - words[0] = previoursToken[0]; - } - if (words.length > 2) { - objNumber = int.tryParse(words[0]); - if (objNumber != null) { - marker = int.tryParse(words[1]); - if (marker != null) { - if (marker == 0 && words[2] == PdfDictionaryProperties.obj) { - final ObjectInformation objectInfo = ObjectInformation( - previousPosition, - null, - crosstable, - ); - if (!newObjects.containsKey(objNumber)) { - newObjects[objNumber] = objectInfo; - } - } - } - } - } - } - } - } - - IPdfPrimitive _readString() { - _match(_next, PdfTokenType.string); - String text = _lexer!.stringText; - bool unicode = false; - if (_isPassword) { - text = String.fromCharCodes(_processEscapes(text)); - } else if (!_isColorSpace) { - if (_checkForPreamble(text)) { - text = _processUnicodeWithPreamble(text); - unicode = true; - } else { - if (!_checkUnicodePreamble(text)) { - text = String.fromCharCodes(_processEscapes(text)); - } - if (_checkForPreamble(text)) { - text = _processUnicodeWithPreamble(text); - unicode = true; - } - if (_checkUnicodePreamble(text)) { - text = text.substring(2); - text = String.fromCharCodes(_processEscapes(text)); - } - } - } else if ((_crossTable != null && - _crossTable!.document != null && - PdfDocumentHelper.getHelper(_crossTable!.document!).isEncrypted) || - _isColorSpace) { - text = String.fromCharCodes(_processEscapes(text)); - } - final PdfString str = PdfString(text); - if (_isColorSpace) { - str.isColorSpace = true; - } - if (!unicode) { - str.encode = ForceEncoding.ascii; - } else { - str.encode = ForceEncoding.unicode; - } - advance(); - return str; - } - - String _processUnicodeWithPreamble(String text) { - final List data = _processEscapes(text); - return decodeBigEndian(data, 2, data.length - 2); - } - - IPdfPrimitive _readUnicodeString([String? validateText]) { - final String text = validateText ?? _lexer!.text; - String value = text.substring(0); - bool unicode = false; - if (value.length > 2) { - value = value.substring(1, value.length - 1); - } - if (_checkForPreamble(value)) { - value = _processUnicodeWithPreamble(value); - unicode = true; - } else { - value = String.fromCharCodes(_processEscapes(value)); - } - final PdfString str = PdfString(value); - if (!unicode) { - str.encode = ForceEncoding.ascii; - } else { - str.encode = ForceEncoding.unicode; - } - if (!_lexer!.skip) { - advance(); - } else { - _next = PdfTokenType.dictionaryEnd; - } - return str; - } - - bool _checkForPreamble(String text) { - return text.length > 1 && - text.codeUnitAt(0) == 254 && - text.codeUnitAt(1) == 255; - } - - bool _checkUnicodePreamble(String text) { - return text.length > 1 && - text.codeUnitAt(0) == 255 && - text.codeUnitAt(1) == 254; - } - - List _processEscapes(String text) { - final List data = text.codeUnits; - final List result = []; - for (int i = 0; i < data.length; i++) { - if (data[i] == 92) { - int next = data[++i]; - switch (next) { - case 110: - result.add(10); - break; - case 114: - result.add(13); - break; - case 116: - result.add(9); - break; - case 98: - result.add(8); - break; - case 102: - result.add(12); - break; - case 13: - next = data[++i]; - if (next != 10) { - --i; - } - break; - case 10: - break; - case 40: - case 41: - case 92: - result.add(next); - break; - default: - if (next >= 48 && next <= 55) { - int octal = next - 48; - for (int j = 0; j < 2 && i + 1 < data.length; j++) { - next = data[i + 1]; - if (next < 48 || next > 55) { - break; - } - i++; - octal = (octal << 3) + (next - 48); - } - result.add(octal & 0xFF); - } else { - result.add(next); - } - break; - } - } else { - result.add(data[i]); - } - } - return result; - } - - // ignore: unused_element - Map _processOctal(String text, int i) { - final int length = text.length; - int count = 0; - int value = 0; - String octalText = ''; - - while (i < length && count < 3) { - if (text.codeUnitAt(i) <= '7'.codeUnitAt(0) && - text.codeUnitAt(i) >= '0'.codeUnitAt(0)) { - octalText += text[i]; - } - ++i; - ++count; - } - value = double.tryParse(octalText)!.toInt(); - return {'value': String.fromCharCode(value), 'index': i}; - } - - IPdfPrimitive _hexString() { - _match(_next, PdfTokenType.hexStringStart); - advance(); - final StringBuffer sb = StringBuffer(); - bool isHex = true; - while (_next != PdfTokenType.hexStringEnd) { - String text = _lexer!.text; - if (_next == PdfTokenType.hexStringWeird) { - isHex = false; - } else if (_next == PdfTokenType.hexStringWeirdEscape) { - isHex = false; - text = text.substring(1); - } - sb.write(text); - advance(); - } - _match(_next, PdfTokenType.hexStringEnd); - advance(); - final PdfString result = PdfString(sb.toString(), !isHex); - if (_isColorSpace) { - result.isColorSpace = true; - } - return result; - } - - IPdfPrimitive _array() { - _match(_next, PdfTokenType.arrayStart); - advance(); - IPdfPrimitive? obj; - final PdfArray array = PdfArray(); - _lexer!.isArray = true; - while ((obj = simple()) != null) { - array.add(obj!); - if (array[0] is PdfName && (array[0]! as PdfName).name == 'Indexed') { - _isColorSpace = true; - } else { - _isColorSpace = false; - } - if (_next == PdfTokenType.unknown) { - advance(); - } - } - _match(_next, PdfTokenType.arrayEnd); - advance(); - _lexer!.isArray = false; - array.freezeChanges(this); - return array; - } - - IPdfPrimitive _dictionary() { - _match(_next, PdfTokenType.dictionaryStart); - advance(); - final PdfDictionary dic = PdfDictionary(); - _Pair pair = _readPair(); - while (pair.name != null && pair._value != null) { - if (pair._value != null) { - dic[pair.name] = pair._value; - } - pair = _readPair(); - } - if (_next != PdfTokenType.dictionaryEnd) { - _next = PdfTokenType.dictionaryEnd; - } - _match(_next, PdfTokenType.dictionaryEnd); - if (!_lexer!.skip) { - advance(); - } else { - _next = PdfTokenType.objectEnd; - _lexer!.skip = false; - } - IPdfPrimitive result; - if (_next == PdfTokenType.streamStart) { - result = _readStream(dic); - } else { - result = dic; - } - (result as IPdfChangable).freezeChanges(this); - return result; - } - - IPdfPrimitive _readStream(PdfDictionary dic) { - _match(_next, PdfTokenType.streamStart); - _lexer!.skipToken(); - _lexer!.skipNewLine(); - - IPdfPrimitive? obj = dic[PdfDictionaryProperties.length]; - PdfNumber? length; - PdfReferenceHolder? reference; - if (obj is PdfNumber) { - length = obj; - } - if (obj is PdfReferenceHolder) { - reference = obj; - } - if (length == null && reference == null) { - final int lexerPosition = _lexer!.position; - final int position = _reader.position; - _reader.position = lexerPosition; - final int end = _reader.searchForward('endstream'); - int streamLength; - if (end > lexerPosition) { - streamLength = end - lexerPosition; - } else { - streamLength = lexerPosition - end; - } - _reader.position = position; - final List buffer = _lexer!.readBytes(streamLength); - final PdfStream innerStream = PdfStream(dic, buffer); - advance(); - if (_next != PdfTokenType.streamEnd) { - _next = PdfTokenType.streamEnd; - } - _match(_next, PdfTokenType.streamEnd); - advance(); - if (_next != PdfTokenType.objectEnd) {} - return innerStream; - } else if (reference != null) { - final PdfReferenceHolder reference = obj! as PdfReferenceHolder; - final PdfLexer? lex = _lexer; - final int position = _reader.position; - _lexer = PdfLexer(_reader); - obj = _cTable!.getObject(reference.reference); - length = obj as PdfNumber?; - _reader.position = position; - _lexer = lex; - } - final int intLength = length!.value!.toInt(); - final bool check = _checkStreamLength(_lexer!.position, intLength); - PdfStream stream; - if (check) { - final List buf = _lexer!.readBytes(intLength); - stream = PdfStream(dic, buf); - } else { - final int lexerPosition = _lexer!.position; - final int position = _reader.position; - _reader.position = lexerPosition; - final int end = _reader.searchForward('endstream'); - int streamLength; - if (end > lexerPosition) { - streamLength = end - lexerPosition; - } else { - streamLength = lexerPosition - end; - } - _reader.position = position; - final List buf = _lexer!.readBytes(streamLength); - stream = PdfStream(dic, buf); - } - advance(); - if (_next != PdfTokenType.streamEnd) { - _next = PdfTokenType.streamEnd; - } - _match(_next, PdfTokenType.streamEnd); - advance(); - if (_next != PdfTokenType.objectEnd) { - _next = PdfTokenType.objectEnd; - } - return stream; - } - - /// internal method - String getObjectFlag() { - _match(_next, PdfTokenType.objectType); - final String type = _lexer!.text[0]; - advance(); - return type; - } - - bool _checkStreamLength(int lexPosition, int value) { - String line = ''; - bool check = true; - final int position = _reader.position; - _reader.position = lexPosition + value; - final List buff = List.filled(20, ''); - _reader.readBlock(buff, 0, 20); - for (int i = 0; i < buff.length; i++) { - line += buff[i]; - } - if (!line.startsWith('\nendstream') && - !line.startsWith('\r\nendstream') && - !line.startsWith('\rendstream') && - !line.startsWith('endstream')) { - check = false; - } - _reader.position = position; - return check; - } - - _Pair _readPair() { - IPdfPrimitive? obj; - try { - obj = simple(); - } catch (e) { - obj = null; - } - if (obj == null) { - return _Pair.empty; - } - PdfName? name; - if (obj is PdfName) { - name = obj; - } else { - _error(_ErrorType.badlyFormedDictionary, 'next should be a name.'); - } - if (name!.name == PdfDictionaryProperties.u || - name.name == PdfDictionaryProperties.o || - name.name == PdfDictionaryProperties.id) { - _isPassword = true; - } - obj = simple(); - _isPassword = false; - return _Pair(name, obj); - } - - /// internal method - int startCrossReference() { - advance(); - _match(_next, PdfTokenType.startXRef); - advance(); - final PdfNumber? number = _number() as PdfNumber?; - if (number != null) { - return number.value!.toInt(); - } else { - return 0; - } - } - - void _match(PdfTokenType? token, PdfTokenType match) { - if (token != match) { - _error(_ErrorType.unexpected, token.toString()); - } - } - - void _error(_ErrorType error, String? additional) { - String message; - - switch (error) { - case _ErrorType.unexpected: - message = 'Unexpected token '; - break; - - case _ErrorType.badlyFormedReal: - message = 'Badly formed real number '; - break; - - case _ErrorType.badlyFormedInteger: - message = 'Badly formed integer number '; - break; - - case _ErrorType.unknownStreamLength: - message = 'Unknown stream length'; - break; - - case _ErrorType.badlyFormedDictionary: - message = 'Badly formed dictionary '; - break; - - case _ErrorType.none: - case _ErrorType.badlyFormedHexString: - message = 'Internal error.'; - break; - } - - if (additional != null) { - message = '$message$additional before ${_lexer!.position}'; - } - - throw ArgumentError.value(error, message); - } -} - -enum _ErrorType { - none, - unexpected, - badlyFormedReal, - badlyFormedInteger, - badlyFormedHexString, - badlyFormedDictionary, - unknownStreamLength, -} - -class _Pair { - //constructor - _Pair(this.name, IPdfPrimitive? value) { - _value = value; - } - - static _Pair get empty => _Pair(null, null); - - //Fields - PdfName? name; - IPdfPrimitive? _value; -} +import 'dart:collection'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/fdf_parser.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'cross_table.dart'; +import 'decode_big_endian.dart'; +import 'enums.dart'; +import 'pdf_constants.dart'; +import 'pdf_cross_table.dart'; +import 'pdf_lexer.dart'; +import 'pdf_reader.dart'; + +/// internal class +class PdfParser { + //Constructor + /// internal constructor + PdfParser(CrossTable cTable, PdfReader reader, PdfCrossTable crossTable) { + _isColorSpace = false; + _isPassword = false; + _reader = reader; + _cTable = cTable; + _crossTable = crossTable; + _lexer = PdfLexer(reader); + } + + //Fields + CrossTable? _cTable; + late PdfReader _reader; + PdfLexer? _lexer; + PdfTokenType? _next; + PdfCrossTable? _crossTable; + + /// internal field + Queue integerQueue = Queue(); + late bool _isPassword; + late bool _isColorSpace; + List? _windows1252MapTable; + + //Properties + /// internal property + List? get windows1252MapTable { + _windows1252MapTable ??= [ + '\u007f', + '€', + '\u0081', + '‚', + 'ƒ', + '„', + '…', + '†', + '‡', + 'ˆ', + '‰', + 'Š', + '‹', + 'Œ', + '\u008d', + 'Ž', + '\u008f', + '\u0090', + '‘', + '’', + '“', + '”', + '•', + '–', + '—', + '˜', + '™', + 'š', + '›', + 'œ', + '\u009d', + 'ž', + 'Ÿ', + ' ', + '¡', + '¢', + '£', + ]; + return _windows1252MapTable; + } + + /// internal property + PdfTokenType? get next => _next; + + /// internal property + PdfLexer? get lexer => _lexer; + + //Implementation + /// internal method + void setOffset(int offset) { + _reader.position = offset; + if (integerQueue.isNotEmpty) { + integerQueue = Queue(); + } + _lexer!.reset(); + } + + /// internal method + void advance() { + if (_cTable != null && _cTable!.validateSyntax) { + _lexer!.getNextToken(); + } + _next = _lexer!.getNextToken(); + } + + /// Read fdf object + FdfObject? parseObject() { + final IPdfPrimitive? num1 = simple(); + final IPdfPrimitive? num2 = simple(); + _match(_next, PdfTokenType.objectStart); + advance(); + final IPdfPrimitive? obj = simple(); + if (_next != PdfTokenType.objectEnd) { + _next = PdfTokenType.objectEnd; + } + _match(_next, PdfTokenType.objectEnd); + return num1 != null && + num2 != null && + obj != null && + num1 is PdfNumber && + num2 is PdfNumber + ? FdfObject(num1, num2, obj) + : null; + } + + /// internal method + IPdfPrimitive trailer() { + _match(_next, PdfTokenType.trailer); + advance(); + return _dictionary(); + } + + PdfNumber? _parseInteger() { + final double? value = double.tryParse(_lexer!.text); + PdfNumber? integer; + if (value != null) { + integer = PdfNumber(value); + } else { + _error(_ErrorType.badlyFormedInteger, _lexer!.text); + } + advance(); + return integer; + } + + IPdfPrimitive? _number() { + IPdfPrimitive? obj; + PdfNumber? integer; + if (integerQueue.isNotEmpty) { + integer = PdfNumber(integerQueue.removeFirst()); + } else { + _match(_next, PdfTokenType.number); + integer = _parseInteger(); + } + obj = integer; + if (_next == PdfTokenType.number) { + final PdfNumber? integer2 = _parseInteger(); + if (_next == PdfTokenType.reference) { + final PdfReference reference = PdfReference( + integer!.value!.toInt(), + integer2!.value!.toInt(), + ); + obj = PdfReferenceHolder.fromReference(reference, _crossTable); + advance(); + } else { + integerQueue.addLast(integer2!.value!.toInt()); + } + } + return obj; + } + + void _parseOldXRef(CrossTable cTable, Map? objects) { + advance(); + while (_isSubsection()) { + cTable.parseSubsection(this, objects); + } + } + + bool _isSubsection() { + bool result = false; + if (_next == PdfTokenType.trailer) { + result = false; + } else if (_next == PdfTokenType.number) { + result = true; + } else { + throw ArgumentError.value(result, 'Invalid format'); + } + return result; + } + + /// internal method + Map parseCrossReferenceTable( + Map? objects, + CrossTable cTable, + ) { + IPdfPrimitive? obj; + advance(); + if (_next == PdfTokenType.xRef) { + _parseOldXRef(cTable, objects); + obj = trailer(); + final PdfDictionary trailerDic = obj as PdfDictionary; + if (trailerDic.containsKey('Size')) { + final int size = (trailerDic['Size']! as PdfNumber).value!.toInt(); + int initialNumber = 0; + if (cTable.initialSubsectionCount == cTable.initialNumberOfSubsection) { + initialNumber = cTable.initialNumberOfSubsection; + } else { + initialNumber = cTable.initialSubsectionCount; + } + int total = 0; + total = cTable.totalNumberOfSubsection; + if (size < initialNumber + total && + initialNumber > 0 && + size == total) { + final int difference = initialNumber + total - size; + final Map newObjects = + {}; + final List keys = objects!.keys.toList(); + for (int i = 0; i < keys.length; i++) { + newObjects[keys[i] - difference] = objects[keys[i]]!; + } + objects = newObjects; + cTable.objects = newObjects; + } + } + } else { + obj = _parse(); + objects = cTable.parseNewTable(obj as PdfStream?, objects); + } + if (obj is PdfDictionary && + _crossTable != null && + obj.containsKey('XRefStm')) { + try { + int xrefStreamPosition = 0; + final PdfDictionary trailerDictionary = obj; + final IPdfPrimitive? pdfNumber = PdfCrossTable.dereference( + trailerDictionary['XRefStm'], + ); + if (pdfNumber != null && pdfNumber is PdfNumber) { + xrefStreamPosition = pdfNumber.value!.toInt(); + } + cTable.parser.setOffset(xrefStreamPosition); + final IPdfPrimitive? xrefStream = cTable.parser.parseOffset( + xrefStreamPosition, + ); + if (xrefStream != null && xrefStream is PdfStream) { + objects = cTable.parseNewTable(xrefStream, objects); + } + } catch (e) { + //exception may occurs if offest is not correct/crosstable is corrupted. + } + } + return {'object': obj, 'objects': objects}; + } + + /// internal method + IPdfPrimitive? parseOffset(int offset) { + setOffset(offset); + advance(); + return _parse(); + } + + IPdfPrimitive? _parse() { + _match(_next, PdfTokenType.number); + simple(); + simple(); + _match(_next, PdfTokenType.objectStart); + advance(); + final IPdfPrimitive? obj = simple(); + if (_next != PdfTokenType.objectEnd) { + _next = PdfTokenType.objectEnd; + } + _match(_next, PdfTokenType.objectEnd); + if (!_lexer!.skip) { + advance(); + } else { + _lexer!.skip = false; + } + return obj; + } + + /// internal method + IPdfPrimitive? simple() { + IPdfPrimitive? obj; + if (integerQueue.isNotEmpty) { + obj = _number(); + } else { + switch (_next) { + case PdfTokenType.dictionaryStart: + obj = _dictionary(); + break; + case PdfTokenType.arrayStart: + obj = _array(); + break; + case PdfTokenType.hexStringStart: + obj = _hexString(); + break; + case PdfTokenType.string: + obj = _readString(); + break; + case PdfTokenType.unicodeString: + obj = _readUnicodeString(); + break; + case PdfTokenType.name: + obj = _readName(); + break; + case PdfTokenType.boolean: + obj = _readBoolean(); + break; + case PdfTokenType.real: + obj = _real(); + break; + case PdfTokenType.number: + obj = _number(); + break; + case PdfTokenType.nullType: + obj = PdfNull(); + advance(); + break; + // ignore: no_default_cases + default: + obj = null; + break; + } + } + return obj; + } + + IPdfPrimitive? _real() { + _match(_next, PdfTokenType.real); + final double? value = double.tryParse(_lexer!.text); + PdfNumber? real; + if (value != null) { + real = PdfNumber(value); + } else { + _error(_ErrorType.badlyFormedReal, _lexer!.text); + } + advance(); + return real; + } + + IPdfPrimitive _readBoolean() { + _match(_next, PdfTokenType.boolean); + final bool value = _lexer!.text == 'true'; + final PdfBoolean result = PdfBoolean(value); + advance(); + return result; + } + + IPdfPrimitive _readName() { + _match(_next, PdfTokenType.name); + final String name = _lexer!.text.substring(1); + final PdfName result = PdfName(name); + advance(); + return result; + } + + /// internal method + void startFrom(int offset) { + setOffset(offset); + advance(); + } + + /// internal method + void rebuildXrefTable( + Map newObjects, + CrossTable? crosstable, + ) { + final PdfReader reader = PdfReader(_reader.streamReader.data); + reader.position = 0; + newObjects.clear(); + int? objNumber = 0; + int? marker = 0; + List previoursToken = ['\u0000']; + while (true) { + if (reader.position >= reader.length! - 1) { + break; + } + final int previousPosition = reader.position; + String str = ''; + str = reader.readLine(); + if (str == '') { + continue; + } + final List tokens = str.split(''); + final bool previousObject = + previoursToken[0].codeUnitAt(0) >= '0'.codeUnitAt(0) && + previoursToken[0].codeUnitAt(0) <= '9'.codeUnitAt(0) && + tokens.length > 1 && + tokens[1].codeUnitAt(0) >= '0'.codeUnitAt(0) && + tokens[1].codeUnitAt(0) <= '9'.codeUnitAt(0); + if (tokens[0].codeUnitAt(0) >= '0'.codeUnitAt(0) && + tokens[0].codeUnitAt(0) <= '9'.codeUnitAt(0) || + previousObject) { + if (!previousObject) { + previoursToken = tokens; + } + final List words = str.split(' '); + if (previousObject && words[0] == '') { + words[0] = previoursToken[0]; + } + if (words.length > 2) { + objNumber = int.tryParse(words[0]); + if (objNumber != null) { + marker = int.tryParse(words[1]); + if (marker != null) { + if (marker == 0 && words[2] == PdfDictionaryProperties.obj) { + final ObjectInformation objectInfo = ObjectInformation( + previousPosition, + null, + crosstable, + ); + if (!newObjects.containsKey(objNumber)) { + newObjects[objNumber] = objectInfo; + } + } + } + } + } + } + } + } + + IPdfPrimitive _readString() { + _match(_next, PdfTokenType.string); + String text = _lexer!.stringText; + bool unicode = false; + if (_isPassword) { + text = String.fromCharCodes(_processEscapes(text)); + } else if (!_isColorSpace) { + if (_checkForPreamble(text)) { + text = _processUnicodeWithPreamble(text); + unicode = true; + } else { + if (!_checkUnicodePreamble(text)) { + text = String.fromCharCodes(_processEscapes(text)); + } + if (_checkForPreamble(text)) { + text = _processUnicodeWithPreamble(text); + unicode = true; + } + if (_checkUnicodePreamble(text)) { + text = text.substring(2); + text = String.fromCharCodes(_processEscapes(text)); + } + } + } else if ((_crossTable != null && + _crossTable!.document != null && + PdfDocumentHelper.getHelper(_crossTable!.document!).isEncrypted) || + _isColorSpace) { + text = String.fromCharCodes(_processEscapes(text)); + } + final PdfString str = PdfString(text); + if (_isColorSpace) { + str.isColorSpace = true; + } + if (!unicode) { + str.encode = ForceEncoding.ascii; + } else { + str.encode = ForceEncoding.unicode; + } + advance(); + return str; + } + + String _processUnicodeWithPreamble(String text) { + final List data = _processEscapes(text); + return decodeBigEndian(data, 2, data.length - 2); + } + + IPdfPrimitive _readUnicodeString([String? validateText]) { + final String text = validateText ?? _lexer!.text; + String value = text.substring(0); + bool unicode = false; + if (value.length > 2) { + value = value.substring(1, value.length - 1); + } + if (_checkForPreamble(value)) { + value = _processUnicodeWithPreamble(value); + unicode = true; + } else { + value = String.fromCharCodes(_processEscapes(value)); + } + final PdfString str = PdfString(value); + if (!unicode) { + str.encode = ForceEncoding.ascii; + } else { + str.encode = ForceEncoding.unicode; + } + if (!_lexer!.skip) { + advance(); + } else { + _next = PdfTokenType.dictionaryEnd; + } + return str; + } + + bool _checkForPreamble(String text) { + return text.length > 1 && + text.codeUnitAt(0) == 254 && + text.codeUnitAt(1) == 255; + } + + bool _checkUnicodePreamble(String text) { + return text.length > 1 && + text.codeUnitAt(0) == 255 && + text.codeUnitAt(1) == 254; + } + + List _processEscapes(String text) { + final List data = text.codeUnits; + final List result = []; + for (int i = 0; i < data.length; i++) { + if (data[i] == 92) { + int next = data[++i]; + switch (next) { + case 110: + result.add(10); + break; + case 114: + result.add(13); + break; + case 116: + result.add(9); + break; + case 98: + result.add(8); + break; + case 102: + result.add(12); + break; + case 13: + next = data[++i]; + if (next != 10) { + --i; + } + break; + case 10: + break; + case 40: + case 41: + case 92: + result.add(next); + break; + default: + if (next >= 48 && next <= 55) { + int octal = next - 48; + for (int j = 0; j < 2 && i + 1 < data.length; j++) { + next = data[i + 1]; + if (next < 48 || next > 55) { + break; + } + i++; + octal = (octal << 3) + (next - 48); + } + result.add(octal & 0xFF); + } else { + result.add(next); + } + break; + } + } else { + result.add(data[i]); + } + } + return result; + } + + // ignore: unused_element + Map _processOctal(String text, int i) { + final int length = text.length; + int count = 0; + int value = 0; + String octalText = ''; + + while (i < length && count < 3) { + if (text.codeUnitAt(i) <= '7'.codeUnitAt(0) && + text.codeUnitAt(i) >= '0'.codeUnitAt(0)) { + octalText += text[i]; + } + ++i; + ++count; + } + value = double.tryParse(octalText)!.toInt(); + return {'value': String.fromCharCode(value), 'index': i}; + } + + IPdfPrimitive _hexString() { + _match(_next, PdfTokenType.hexStringStart); + advance(); + final StringBuffer sb = StringBuffer(); + bool isHex = true; + while (_next != PdfTokenType.hexStringEnd) { + String text = _lexer!.text; + if (_next == PdfTokenType.hexStringWeird) { + isHex = false; + } else if (_next == PdfTokenType.hexStringWeirdEscape) { + isHex = false; + text = text.substring(1); + } + sb.write(text); + advance(); + } + _match(_next, PdfTokenType.hexStringEnd); + advance(); + final PdfString result = PdfString(sb.toString(), !isHex); + if (_isColorSpace) { + result.isColorSpace = true; + } + return result; + } + + IPdfPrimitive _array() { + _match(_next, PdfTokenType.arrayStart); + advance(); + IPdfPrimitive? obj; + final PdfArray array = PdfArray(); + _lexer!.isArray = true; + while ((obj = simple()) != null) { + array.add(obj!); + if (array[0] is PdfName && (array[0]! as PdfName).name == 'Indexed') { + _isColorSpace = true; + } else { + _isColorSpace = false; + } + if (_next == PdfTokenType.unknown) { + advance(); + } + } + _match(_next, PdfTokenType.arrayEnd); + advance(); + _lexer!.isArray = false; + array.freezeChanges(this); + return array; + } + + IPdfPrimitive _dictionary() { + _match(_next, PdfTokenType.dictionaryStart); + advance(); + final PdfDictionary dic = PdfDictionary(); + _Pair pair = _readPair(); + while (pair.name != null && pair._value != null) { + if (pair._value != null) { + dic[pair.name] = pair._value; + } + pair = _readPair(); + } + if (_next != PdfTokenType.dictionaryEnd) { + _next = PdfTokenType.dictionaryEnd; + } + _match(_next, PdfTokenType.dictionaryEnd); + if (!_lexer!.skip) { + advance(); + } else { + _next = PdfTokenType.objectEnd; + _lexer!.skip = false; + } + IPdfPrimitive result; + if (_next == PdfTokenType.streamStart) { + result = _readStream(dic); + } else { + result = dic; + } + (result as IPdfChangable).freezeChanges(this); + return result; + } + + IPdfPrimitive _readStream(PdfDictionary dic) { + _match(_next, PdfTokenType.streamStart); + _lexer!.skipToken(); + _lexer!.skipNewLine(); + + IPdfPrimitive? obj = dic[PdfDictionaryProperties.length]; + PdfNumber? length; + PdfReferenceHolder? reference; + if (obj is PdfNumber) { + length = obj; + } + if (obj is PdfReferenceHolder) { + reference = obj; + } + if (length == null && reference == null) { + final int lexerPosition = _lexer!.position; + final int position = _reader.position; + _reader.position = lexerPosition; + final int end = _reader.searchForward('endstream'); + int streamLength; + if (end > lexerPosition) { + streamLength = end - lexerPosition; + } else { + streamLength = lexerPosition - end; + } + _reader.position = position; + final List buffer = _lexer!.readBytes(streamLength); + final PdfStream innerStream = PdfStream(dic, buffer); + advance(); + if (_next != PdfTokenType.streamEnd) { + _next = PdfTokenType.streamEnd; + } + _match(_next, PdfTokenType.streamEnd); + advance(); + if (_next != PdfTokenType.objectEnd) {} + return innerStream; + } else if (reference != null) { + final PdfReferenceHolder reference = obj! as PdfReferenceHolder; + final PdfLexer? lex = _lexer; + final int position = _reader.position; + _lexer = PdfLexer(_reader); + obj = _cTable!.getObject(reference.reference); + length = obj as PdfNumber?; + _reader.position = position; + _lexer = lex; + } + final int intLength = length!.value!.toInt(); + final bool check = _checkStreamLength(_lexer!.position, intLength); + PdfStream stream; + if (check) { + final List buf = _lexer!.readBytes(intLength); + stream = PdfStream(dic, buf); + } else { + final int lexerPosition = _lexer!.position; + final int position = _reader.position; + _reader.position = lexerPosition; + final int end = _reader.searchForward('endstream'); + int streamLength; + if (end > lexerPosition) { + streamLength = end - lexerPosition; + } else { + streamLength = lexerPosition - end; + } + _reader.position = position; + final List buf = _lexer!.readBytes(streamLength); + stream = PdfStream(dic, buf); + } + advance(); + if (_next != PdfTokenType.streamEnd) { + _next = PdfTokenType.streamEnd; + } + _match(_next, PdfTokenType.streamEnd); + advance(); + if (_next != PdfTokenType.objectEnd) { + _next = PdfTokenType.objectEnd; + } + return stream; + } + + /// internal method + String getObjectFlag() { + _match(_next, PdfTokenType.objectType); + final String type = _lexer!.text[0]; + advance(); + return type; + } + + bool _checkStreamLength(int lexPosition, int value) { + String line = ''; + bool check = true; + final int position = _reader.position; + _reader.position = lexPosition + value; + final List buff = List.filled(20, ''); + _reader.readBlock(buff, 0, 20); + for (int i = 0; i < buff.length; i++) { + line += buff[i]; + } + if (!line.startsWith('\nendstream') && + !line.startsWith('\r\nendstream') && + !line.startsWith('\rendstream') && + !line.startsWith('endstream')) { + check = false; + } + _reader.position = position; + return check; + } + + _Pair _readPair() { + IPdfPrimitive? obj; + try { + obj = simple(); + } catch (e) { + obj = null; + } + if (obj == null) { + return _Pair.empty; + } + PdfName? name; + if (obj is PdfName) { + name = obj; + } else { + _error(_ErrorType.badlyFormedDictionary, 'next should be a name.'); + } + if (name!.name == PdfDictionaryProperties.u || + name.name == PdfDictionaryProperties.o || + name.name == PdfDictionaryProperties.id) { + _isPassword = true; + } + obj = simple(); + _isPassword = false; + return _Pair(name, obj); + } + + /// internal method + int startCrossReference() { + advance(); + _match(_next, PdfTokenType.startXRef); + advance(); + final PdfNumber? number = _number() as PdfNumber?; + if (number != null) { + return number.value!.toInt(); + } else { + return 0; + } + } + + void _match(PdfTokenType? token, PdfTokenType match) { + if (token != match) { + _error(_ErrorType.unexpected, token.toString()); + } + } + + void _error(_ErrorType error, String? additional) { + String message; + + switch (error) { + case _ErrorType.unexpected: + message = 'Unexpected token '; + break; + + case _ErrorType.badlyFormedReal: + message = 'Badly formed real number '; + break; + + case _ErrorType.badlyFormedInteger: + message = 'Badly formed integer number '; + break; + + case _ErrorType.unknownStreamLength: + message = 'Unknown stream length'; + break; + + case _ErrorType.badlyFormedDictionary: + message = 'Badly formed dictionary '; + break; + + case _ErrorType.none: + case _ErrorType.badlyFormedHexString: + message = 'Internal error.'; + break; + } + + if (additional != null) { + message = '$message$additional before ${_lexer!.position}'; + } + + throw ArgumentError.value(error, message); + } +} + +enum _ErrorType { + none, + unexpected, + badlyFormedReal, + badlyFormedInteger, + badlyFormedHexString, + badlyFormedDictionary, + unknownStreamLength, +} + +class _Pair { + //constructor + _Pair(this.name, IPdfPrimitive? value) { + _value = value; + } + + static _Pair get empty => _Pair(null, null); + + //Fields + PdfName? name; + IPdfPrimitive? _value; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_reader.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_reader.dart index 091cced9e..2bce06e7b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_reader.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_reader.dart @@ -1,417 +1,417 @@ -import 'dart:convert'; - -import 'pdf_constants.dart'; -import 'stream_reader.dart'; - -/// internal class -class PdfReader { - //Constructor - /// internal constructor - PdfReader(List? data) { - streamReader = PdfStreamReader(data); - _peekedByte = 0; - _bytePeeked = false; - _delimiters = '()<>[]{}/%'; - } - - //Fields - /// internal field - late PdfStreamReader streamReader; - late String _delimiters; - final List _spaceCharacters = [ - '\u0020', - '\u00a0', - '\u1680', - '\u2000', - '\u2001', - '\u2002', - '\u2003', - '\u2004', - '\u2005', - '\u2006', - '\u2007', - '\u2008', - '\u2009', - '\u200a', - '\u202f', - '\u205f', - '\u3000', - '\u2028', - '\u2029', - '\u0009', - '\u000a', - '\u000b', - '\u000c', - '\u000d', - '\u0085', - ]; - late int _peekedByte; - late bool _bytePeeked; - - //Properties - /// internal property - int get position => streamReader.position; - set position(int value) { - streamReader.position = value; - } - - /// internal property - int? get length => streamReader.length; - - //Implementation - /// internal method - void skipWhiteSpace() { - if (position != streamReader.length) { - int value; - do { - value = _read(); - } while (value != -1 && - _spaceCharacters.contains(String.fromCharCode(value))); - position = value == -1 ? streamReader.length! : (position - 1); - } - } - - int _skipWhiteSpaceBack() { - if (position == 0) { - throw ArgumentError.value(position, 'Invalid PDF Document Format'); - } - position -= 1; - while (_spaceCharacters.contains(String.fromCharCode(_read()))) { - position -= 2; - } - return position; - } - - int _read() { - int? value = 0; - if (_bytePeeked) { - value = _getPeeked(value); - } else { - value = streamReader.readByte(); - } - return value!; - } - - /// internal method - List readBytes(int length) { - final List bytes = List.filled(length, 0, growable: true); - for (int i = 0; i < length; i++) { - bytes[i] = _read(); - } - return bytes; - } - - /// internal method - int readBlock(List buffer, int index, int count) { - if (count < 0) { - throw ArgumentError.value(count, 'The value cannot be less then zero'); - } - int i = index; - if (_bytePeeked && count > 0) { - buffer[i] = String.fromCharCode(_peekedByte); - _bytePeeked = false; - --count; - ++i; - } - if (count > 0) { - final List buf = List.filled(count, 0); - int tempCount = 0; - for (int j = 0; j < count && position < length!; j++) { - buf[j] = _read(); - tempCount++; - } - count = tempCount; - for (int k = 0; k < count; ++k) { - final String ch = String.fromCharCode(buf[k]); - buffer[i + k] = ch; - } - i += count; - } - return i - index; - } - - /// internal method - String readLine() { - String line = ''; - int character; - character = _read(); - while (character != -1 && !_isEol(String.fromCharCode(character))) { - line += String.fromCharCode(character); - character = _read(); - } - if (character == 13) { - if (String.fromCharCode(_read()) != '\n') { - position -= 1; - } - } - return line; - } - - bool _isEol(String character) { - return character == '\n' || character == '\r'; - } - - /// internal method - int readData(List? buffer, int index, int count) { - if (count < 0) { - throw ArgumentError.value(count, "The value can't be less then zero"); - } - int i = index; - if (_bytePeeked && count > 0) { - buffer![i] = _peekedByte; - _bytePeeked = false; - --count; - ++i; - } - if (count > 0) { - if (position == length) { - count = 0; - } else { - final int lp = length! - position; - count = count > lp ? lp : count; - final List bytes = readBytes(count); - for (int j = 0; j < count; j++) { - buffer![i + j] = bytes[j]; - } - } - i += count; - } - return i - index; - } - - /// internal method - Map copyBytes(List? buffer, int index, int count) { - if (index < 0 || index > buffer!.length) { - throw ArgumentError.value(index, 'Invalid index to read'); - } - final int pos = position; - for ( - int i = pos; - i < length! && i < (pos + count) && index < buffer.length; - i++ - ) { - buffer[index] = _read(); - index++; - } - return {'next': index, 'buffer': buffer}; - } - - String _readBack(int length) { - if (position < length) { - throw ArgumentError.value(position, 'Invalid PDF Document Format'); - } - position -= length; - return String.fromCharCodes(readBytes(length)); - } - - /// internal method - int? seekEnd() { - return streamReader.length; - } - - /// internal method - int searchBack(String token) { - int pos = position; - position = _skipWhiteSpaceBack(); - if (position < token.length) { - return -1; - } - String str = _readBack(token.length); - pos = position - token.length; - while (str != token) { - if (pos < 0) { - throw ArgumentError.value(pos, 'Invalid PDF Document Format'); - } - position -= 1; - if (position < token.length) { - return -1; - } - str = _readBack(token.length); - pos = position - token.length; - } - while (token == PdfOperators.crossReference) { - final int xrefPos = pos; - final int startPos = searchBack(PdfOperators.startCrossReference); - if (startPos == xrefPos - 5) { - str = PdfOperators.startCrossReference; - while (str != token) { - if (pos < 0) { - throw ArgumentError.value(pos, 'Invalid PDF Document Format'); - } - position -= 1; - if (position < token.length) { - return -1; - } - str = _readBack(token.length); - pos = position - token.length; - } - } else { - pos = xrefPos; - break; - } - } - position = pos; - return pos; - } - - /// internal method - int searchForward(String token) { - List? buf = List.filled(token.length, 0); - bool isStartXref = false; - while (true) { - int pos = position; - final int character = _read(); - buf![0] = character.toUnsigned(8); - if (buf[0] == token.codeUnitAt(0)) { - if (!isStartXref) { - pos = position - 1; - final Map result = copyBytes( - buf, - 1, - token.length - 1, - ); - final int length = result['next'] as int; - buf = result['buffer'] as List?; - position = pos; - if (length < token.length - 1) { - return -1; - } else if (token == String.fromCharCodes(buf!)) { - return pos; - } else { - position += 1; - } - } - } else if (buf[0] == PdfOperators.startCrossReference.codeUnitAt(0)) { - isStartXref = false; - pos = position - 1; - position = pos; - int newPosition = pos; - List? buff = List.filled( - PdfOperators.startCrossReference.length, - 0, - ); - final Map result = copyBytes( - buff, - 1, - PdfOperators.startCrossReference.length, - ); - buff = result['buffer'] as List?; - if (PdfOperators.startCrossReference == String.fromCharCodes(buff!)) { - isStartXref = true; - position = ++newPosition; - } - } else if (character == -1) { - return -1; - } - } - } - - int _getPeeked(int? byteValue) { - if (_bytePeeked) { - _bytePeeked = false; - byteValue = _peekedByte; - } else { - byteValue = 0; - } - return byteValue; - } - - String _getEqualChar(int? charCode) { - return charCode == -1 ? '\uffff' : String.fromCharCode(charCode!); - } - - /// internal method - String? getNextToken() { - String? token = ''; - int? character = 0; - skipWhiteSpace(); - character = _peek(); - if (_isDelimiter(_getEqualChar(character))) { - final Map result = _appendCharacter(token); - character = result['character'] as int?; - token = result['token'] as String?; - return token; - } - while (character != -1 && - !_isSeparator(_getEqualChar(character)) && - token != '\u0000') { - final Map result = _appendCharacter(token); - character = result['character'] as int?; - token = result['token'] as String?; - character = _peek(); - } - return token; - } - - Map _appendCharacter(String? token) { - final int character = _read(); - if (character != -1) { - token = token! + String.fromCharCode(character); - } - final Map result = {}; - result['token'] = token; - result['character'] = character; - return result; - } - - int _peek() { - int? value = 0; - if (_bytePeeked) { - value = _getPeeked(value); - } else { - _peekedByte = _read(); - value = _peekedByte; - } - if (_peekedByte != -1) { - _bytePeeked = true; - } - return value; - } - - bool _isDelimiter(String character) { - for (int index = 0; index < _delimiters.length; index++) { - if (_delimiters[index] == character) { - return true; - } - } - return false; - } - - bool _isSeparator(String character) { - return _spaceCharacters.contains(character) || _isDelimiter(character); - } - - bool _isJsonDelimiter(String character) { - // ignore: unnecessary_string_escapes - return character.contains(RegExp('[":,{}]|[\[]|]')); - } - - /// internal method - String getNextJsonToken() { - String token = ''; - int character; - final List word = []; - skipWhiteSpace(); - character = _peek(); - //Return the character if it is a delimiter character. - if (_isJsonDelimiter(_getEqualChar(character))) { - final Map result = _appendCharacter(token); - character = result['character'] as int; - return token = result['token'] as String; - } - //Read all character sequentially until separator read. - while (character != -1 && - !_isJsonDelimiter(String.fromCharCode(character)) && - token != '\u0000') { - word.add(character.toUnsigned(8)); - _read(); - character = _peek(); - } - token = ''; - if (word.isNotEmpty) { - token = utf8.decode(word); - } - word.clear(); - return token; - } -} +import 'dart:convert'; + +import 'pdf_constants.dart'; +import 'stream_reader.dart'; + +/// internal class +class PdfReader { + //Constructor + /// internal constructor + PdfReader(List? data) { + streamReader = PdfStreamReader(data); + _peekedByte = 0; + _bytePeeked = false; + _delimiters = '()<>[]{}/%'; + } + + //Fields + /// internal field + late PdfStreamReader streamReader; + late String _delimiters; + final List _spaceCharacters = [ + '\u0020', + '\u00a0', + '\u1680', + '\u2000', + '\u2001', + '\u2002', + '\u2003', + '\u2004', + '\u2005', + '\u2006', + '\u2007', + '\u2008', + '\u2009', + '\u200a', + '\u202f', + '\u205f', + '\u3000', + '\u2028', + '\u2029', + '\u0009', + '\u000a', + '\u000b', + '\u000c', + '\u000d', + '\u0085', + ]; + late int _peekedByte; + late bool _bytePeeked; + + //Properties + /// internal property + int get position => streamReader.position; + set position(int value) { + streamReader.position = value; + } + + /// internal property + int? get length => streamReader.length; + + //Implementation + /// internal method + void skipWhiteSpace() { + if (position != streamReader.length) { + int value; + do { + value = _read(); + } while (value != -1 && + _spaceCharacters.contains(String.fromCharCode(value))); + position = value == -1 ? streamReader.length! : (position - 1); + } + } + + int _skipWhiteSpaceBack() { + if (position == 0) { + throw ArgumentError.value(position, 'Invalid PDF Document Format'); + } + position -= 1; + while (_spaceCharacters.contains(String.fromCharCode(_read()))) { + position -= 2; + } + return position; + } + + int _read() { + int? value = 0; + if (_bytePeeked) { + value = _getPeeked(value); + } else { + value = streamReader.readByte(); + } + return value!; + } + + /// internal method + List readBytes(int length) { + final List bytes = List.filled(length, 0, growable: true); + for (int i = 0; i < length; i++) { + bytes[i] = _read(); + } + return bytes; + } + + /// internal method + int readBlock(List buffer, int index, int count) { + if (count < 0) { + throw ArgumentError.value(count, 'The value cannot be less then zero'); + } + int i = index; + if (_bytePeeked && count > 0) { + buffer[i] = String.fromCharCode(_peekedByte); + _bytePeeked = false; + --count; + ++i; + } + if (count > 0) { + final List buf = List.filled(count, 0); + int tempCount = 0; + for (int j = 0; j < count && position < length!; j++) { + buf[j] = _read(); + tempCount++; + } + count = tempCount; + for (int k = 0; k < count; ++k) { + final String ch = String.fromCharCode(buf[k]); + buffer[i + k] = ch; + } + i += count; + } + return i - index; + } + + /// internal method + String readLine() { + String line = ''; + int character; + character = _read(); + while (character != -1 && !_isEol(String.fromCharCode(character))) { + line += String.fromCharCode(character); + character = _read(); + } + if (character == 13) { + if (String.fromCharCode(_read()) != '\n') { + position -= 1; + } + } + return line; + } + + bool _isEol(String character) { + return character == '\n' || character == '\r'; + } + + /// internal method + int readData(List? buffer, int index, int count) { + if (count < 0) { + throw ArgumentError.value(count, "The value can't be less then zero"); + } + int i = index; + if (_bytePeeked && count > 0) { + buffer![i] = _peekedByte; + _bytePeeked = false; + --count; + ++i; + } + if (count > 0) { + if (position == length) { + count = 0; + } else { + final int lp = length! - position; + count = count > lp ? lp : count; + final List bytes = readBytes(count); + for (int j = 0; j < count; j++) { + buffer![i + j] = bytes[j]; + } + } + i += count; + } + return i - index; + } + + /// internal method + Map copyBytes(List? buffer, int index, int count) { + if (index < 0 || index > buffer!.length) { + throw ArgumentError.value(index, 'Invalid index to read'); + } + final int pos = position; + for ( + int i = pos; + i < length! && i < (pos + count) && index < buffer.length; + i++ + ) { + buffer[index] = _read(); + index++; + } + return {'next': index, 'buffer': buffer}; + } + + String _readBack(int length) { + if (position < length) { + throw ArgumentError.value(position, 'Invalid PDF Document Format'); + } + position -= length; + return String.fromCharCodes(readBytes(length)); + } + + /// internal method + int? seekEnd() { + return streamReader.length; + } + + /// internal method + int searchBack(String token) { + int pos = position; + position = _skipWhiteSpaceBack(); + if (position < token.length) { + return -1; + } + String str = _readBack(token.length); + pos = position - token.length; + while (str != token) { + if (pos < 0) { + throw ArgumentError.value(pos, 'Invalid PDF Document Format'); + } + position -= 1; + if (position < token.length) { + return -1; + } + str = _readBack(token.length); + pos = position - token.length; + } + while (token == PdfOperators.crossReference) { + final int xrefPos = pos; + final int startPos = searchBack(PdfOperators.startCrossReference); + if (startPos == xrefPos - 5) { + str = PdfOperators.startCrossReference; + while (str != token) { + if (pos < 0) { + throw ArgumentError.value(pos, 'Invalid PDF Document Format'); + } + position -= 1; + if (position < token.length) { + return -1; + } + str = _readBack(token.length); + pos = position - token.length; + } + } else { + pos = xrefPos; + break; + } + } + position = pos; + return pos; + } + + /// internal method + int searchForward(String token) { + List? buf = List.filled(token.length, 0); + bool isStartXref = false; + while (true) { + int pos = position; + final int character = _read(); + buf![0] = character.toUnsigned(8); + if (buf[0] == token.codeUnitAt(0)) { + if (!isStartXref) { + pos = position - 1; + final Map result = copyBytes( + buf, + 1, + token.length - 1, + ); + final int length = result['next'] as int; + buf = result['buffer'] as List?; + position = pos; + if (length < token.length - 1) { + return -1; + } else if (token == String.fromCharCodes(buf!)) { + return pos; + } else { + position += 1; + } + } + } else if (buf[0] == PdfOperators.startCrossReference.codeUnitAt(0)) { + isStartXref = false; + pos = position - 1; + position = pos; + int newPosition = pos; + List? buff = List.filled( + PdfOperators.startCrossReference.length, + 0, + ); + final Map result = copyBytes( + buff, + 1, + PdfOperators.startCrossReference.length, + ); + buff = result['buffer'] as List?; + if (PdfOperators.startCrossReference == String.fromCharCodes(buff!)) { + isStartXref = true; + position = ++newPosition; + } + } else if (character == -1) { + return -1; + } + } + } + + int _getPeeked(int? byteValue) { + if (_bytePeeked) { + _bytePeeked = false; + byteValue = _peekedByte; + } else { + byteValue = 0; + } + return byteValue; + } + + String _getEqualChar(int? charCode) { + return charCode == -1 ? '\uffff' : String.fromCharCode(charCode!); + } + + /// internal method + String? getNextToken() { + String? token = ''; + int? character = 0; + skipWhiteSpace(); + character = _peek(); + if (_isDelimiter(_getEqualChar(character))) { + final Map result = _appendCharacter(token); + character = result['character'] as int?; + token = result['token'] as String?; + return token; + } + while (character != -1 && + !_isSeparator(_getEqualChar(character)) && + token != '\u0000') { + final Map result = _appendCharacter(token); + character = result['character'] as int?; + token = result['token'] as String?; + character = _peek(); + } + return token; + } + + Map _appendCharacter(String? token) { + final int character = _read(); + if (character != -1) { + token = token! + String.fromCharCode(character); + } + final Map result = {}; + result['token'] = token; + result['character'] = character; + return result; + } + + int _peek() { + int? value = 0; + if (_bytePeeked) { + value = _getPeeked(value); + } else { + _peekedByte = _read(); + value = _peekedByte; + } + if (_peekedByte != -1) { + _bytePeeked = true; + } + return value; + } + + bool _isDelimiter(String character) { + for (int index = 0; index < _delimiters.length; index++) { + if (_delimiters[index] == character) { + return true; + } + } + return false; + } + + bool _isSeparator(String character) { + return _spaceCharacters.contains(character) || _isDelimiter(character); + } + + bool _isJsonDelimiter(String character) { + // ignore: unnecessary_string_escapes + return character.contains(RegExp('[":,{}]|[\[]|]')); + } + + /// internal method + String getNextJsonToken() { + String token = ''; + int character; + final List word = []; + skipWhiteSpace(); + character = _peek(); + //Return the character if it is a delimiter character. + if (_isJsonDelimiter(_getEqualChar(character))) { + final Map result = _appendCharacter(token); + character = result['character'] as int; + return token = result['token'] as String; + } + //Read all character sequentially until separator read. + while (character != -1 && + !_isJsonDelimiter(String.fromCharCode(character)) && + token != '\u0000') { + word.add(character.toUnsigned(8)); + _read(); + character = _peek(); + } + token = ''; + if (word.isNotEmpty) { + token = utf8.decode(word); + } + word.clear(); + return token; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_stream_writer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_stream_writer.dart index 678093434..c8be34e6a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_stream_writer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_stream_writer.dart @@ -1,400 +1,400 @@ -import '../../interfaces/pdf_interface.dart'; -import '../graphics/enums.dart'; -import '../graphics/fonts/pdf_font.dart'; -import '../graphics/pdf_color.dart'; -import '../graphics/pdf_transformation_matrix.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_constants.dart'; - -/// Helper class to write PDF graphic streams easily. -class PdfStreamWriter implements IPdfWriter { - //Constructor - /// internal constructor - PdfStreamWriter(this.stream); - - //Fields - /// internal field - PdfStream? stream; - - //Implementation - /// internal method - void saveGraphicsState() { - writeOperator(PdfOperators.saveState); - } - - /// internal method - void restoreGraphicsState() { - writeOperator(PdfOperators.restoreState); - } - - /// internal method - void writeOperator(String opcode) { - stream!.write(opcode); - stream!.write(PdfOperators.newLine); - } - - /// internal method - void writeComment(String comment) { - writeOperator('% $comment'); - } - - /// internal method - void writePoint(double? x, double y) { - write(x); - stream!.write(PdfOperators.whiteSpace); - write(-y); - stream!.write(PdfOperators.whiteSpace); - } - - /// internal method - void closePath() { - writeOperator(PdfOperators.closePath); - } - - /// internal method - void clipPath(bool useEvenOddRule) { - stream!.write(PdfOperators.clipPath); - if (useEvenOddRule) { - stream!.write(PdfOperators.evenOdd); - } - stream!.write(PdfOperators.whiteSpace); - stream!.write(PdfOperators.endPath); - stream!.write(PdfOperators.newLine); - } - - /// internal method - void appendRectangle(double? x, double y, double? width, double height) { - writePoint(x, y); - writePoint(width, height); - writeOperator(PdfOperators.appendRectangle); - } - - /// internal method - void modifyCurrentMatrix(PdfTransformationMatrix matrix) { - stream!.write(matrix.getString()); - writeOperator(PdfOperators.currentMatrix); - } - - /// internal method - void modifyTransformationMatrix(PdfTransformationMatrix matrix) { - stream!.write(matrix.getString()); - writeOperator(PdfOperators.transformationMatrix); - } - - /// internal method - void setLineWidth(double width) { - write(width); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setLineWidth); - } - - /// internal method - void setLineCap(PdfLineCap lineCapStyle) { - write(lineCapStyle.index); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setLineCapStyle); - } - - /// internal method - void setLineJoin(PdfLineJoin lineJoinStyle) { - write(lineJoinStyle.index); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setLineJoinStyle); - } - - /// internal method - void setMiterLimit(double? miterLimit) { - write(miterLimit); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setMiterLimit); - } - - /// internal method - void setLineDashPattern(List? pattern, double patternOffset) { - final PdfArray patternArray = PdfArray(pattern); - patternArray.save(this); - stream!.write(PdfOperators.whiteSpace); - write(patternOffset); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setDashPattern); - } - - /// internal method - void setColorAndSpace( - PdfColor color, - PdfColorSpace? colorSpace, - bool forStroking, - ) { - if (!color.isEmpty) { - stream!.write( - PdfColorHelper.getHelper(color).getString(colorSpace, forStroking), - ); - stream!.write(PdfOperators.newLine); - } - } - - /// internal method - void setColorSpace(PdfName name, bool forStroking) { - stream!.write(name.toString()); - stream!.write(PdfOperators.whiteSpace); - stream!.write( - forStroking - ? PdfOperators.selectColorSpaceForStroking - : PdfOperators.selectColorSpaceForNonStroking, - ); - stream!.write(PdfOperators.newLine); - } - - /// internal method - void setFont(PdfFont font, PdfName name, double size) { - stream!.write(name.toString()); - stream!.write(PdfOperators.whiteSpace); - stream!.write(size.toStringAsFixed(2)); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setFont); - } - - /// internal method - void setTextRenderingMode(int renderingMode) { - write(renderingMode); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setRenderingMode); - } - - /// internal method - void setTextScaling(double? textScaling) { - write(textScaling); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setTextScaling); - } - - /// internal method - void setCharacterSpacing(double? charSpacing) { - write(charSpacing); - stream!.write(PdfOperators.whiteSpace); - stream!.write(PdfOperators.setCharacterSpace); - stream!.write(PdfOperators.newLine); - } - - /// internal method - void setWordSpacing(double? wordSpacing) { - write(wordSpacing); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setWordSpace); - } - - /// internal method - void showNextLineText(dynamic value) { - if (value == null) { - throw ArgumentError.value(value, 'value', 'value cannot be null'); - } - _writeText(value); - writeOperator(PdfOperators.setTextOnNewLine); - } - - /// internal method - void startNextLine([double? x, double? y]) { - if (x == null && y == null) { - writeOperator(PdfOperators.goToNextLine); - } else { - writePoint(x, y!); - writeOperator(PdfOperators.setCoords); - } - } - - /// internal method - void showText(PdfString pdfString) { - _writeText(pdfString); - writeOperator(PdfOperators.setText); - } - - /// internal method - void endText() { - writeOperator(PdfOperators.endText); - } - - void _writeText(dynamic value) { - if (value is PdfString) { - stream!.write(value.pdfEncode(null)); - } else if (value is List) { - stream!.write(PdfString.stringMark[0]); - stream!.write(value); - stream!.write(PdfString.stringMark[1]); - } - } - - /// internal method - void setGraphicsState(PdfName name) { - if (name.name!.isEmpty) { - throw ArgumentError.value( - name, - 'name', - 'dictionary name cannot be empty', - ); - } - stream!.write(name.toString()); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.setGraphicsState); - } - - /// internal method - void beginPath(double x, double y) { - writePoint(x, y); - writeOperator(PdfOperators.beginPath); - } - - /// internal method - void appendLineSegment(double x, double y) { - writePoint(x, y); - writeOperator(PdfOperators.appendLineSegment); - } - - /// internal method - void strokePath() { - writeOperator(PdfOperators.stroke); - } - - /// internal method - void closeFillStrokePath(bool useEvenOddRule) { - stream!.write(PdfOperators.closeFillStrokePath); - if (useEvenOddRule) { - stream!.write(PdfOperators.evenOdd); - } - stream!.write(PdfOperators.newLine); - } - - /// internal method - void fillStrokePath(bool useEvenOddRule) { - stream!.write(PdfOperators.fillStroke); - if (useEvenOddRule) { - stream!.write(PdfOperators.evenOdd); - } - stream!.write(PdfOperators.newLine); - } - - /// internal method - void fillPath(bool useEvenOddRule) { - stream!.write(PdfOperators.fill); - if (useEvenOddRule) { - stream!.write(PdfOperators.evenOdd); - } - stream!.write(PdfOperators.newLine); - } - - /// internal method - void closeFillPath(bool useEvenOddRule) { - writeOperator(PdfOperators.closePath); - stream!.write(PdfOperators.fill); - if (useEvenOddRule) { - stream!.write(PdfOperators.evenOdd); - } - stream!.write(PdfOperators.newLine); - } - - /// internal method - void closeStrokePath() { - writeOperator(PdfOperators.closeStrokePath); - } - - /// internal method - void endPath() { - writeOperator(PdfOperators.n); - } - - /// internal method - void executeObject(PdfName pdfName) { - stream!.write(pdfName.toString()); - stream!.write(PdfOperators.whiteSpace); - writeOperator(PdfOperators.paintXObject); - } - - /// internal method - void appendBezierSegment( - double x1, - double y1, - double x2, - double y2, - double x3, - double y3, - ) { - writePoint(x1, y1); - writePoint(x2, y2); - writePoint(x3, y3); - writeOperator(PdfOperators.appendBezierCurve); - } - - /// internal method - void clear() { - stream!.clearStream(); - } - - //IPdfWriter members - @override - PdfDocument? get document => null; - - @override - //ignore:unused_element - set document(PdfDocument? value) { - throw ArgumentError.value( - value, - 'The method or operation is not implemented', - ); - } - - @override - //ignore:unused_element - int get length => stream!.dataStream!.length; - - @override - //ignore:unused_element - set length(int? value) { - throw ArgumentError.value( - value, - 'The method or operation is not implemented', - ); - } - - @override - //ignore:unused_element - int? get position => stream!.position; - @override - //ignore:unused_element - set position(int? value) { - throw ArgumentError.value( - value, - 'The method or operation is not implemented', - ); - } - - @override - void write(dynamic pdfObject) { - if (pdfObject is IPdfPrimitive) { - pdfObject.save(this); - } else if (pdfObject is int) { - stream!.write(pdfObject.toString()); - } else if (pdfObject is double) { - pdfObject = pdfObject.toStringAsFixed(2); - if ((pdfObject as String).endsWith('.00')) { - if (pdfObject.length == 3) { - pdfObject = '0'; - } else { - pdfObject = pdfObject.substring(0, pdfObject.length - 3); - } - } - stream!.write(pdfObject); - } else if (pdfObject is String) { - stream!.write(pdfObject); - } else if (pdfObject is List) { - stream!.write(pdfObject); - } else { - throw ArgumentError.value( - pdfObject, - 'The method or operation is not implemented', - ); - } - } -} +import '../../interfaces/pdf_interface.dart'; +import '../graphics/enums.dart'; +import '../graphics/fonts/pdf_font.dart'; +import '../graphics/pdf_color.dart'; +import '../graphics/pdf_transformation_matrix.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_constants.dart'; + +/// Helper class to write PDF graphic streams easily. +class PdfStreamWriter implements IPdfWriter { + //Constructor + /// internal constructor + PdfStreamWriter(this.stream); + + //Fields + /// internal field + PdfStream? stream; + + //Implementation + /// internal method + void saveGraphicsState() { + writeOperator(PdfOperators.saveState); + } + + /// internal method + void restoreGraphicsState() { + writeOperator(PdfOperators.restoreState); + } + + /// internal method + void writeOperator(String opcode) { + stream!.write(opcode); + stream!.write(PdfOperators.newLine); + } + + /// internal method + void writeComment(String comment) { + writeOperator('% $comment'); + } + + /// internal method + void writePoint(double? x, double y) { + write(x); + stream!.write(PdfOperators.whiteSpace); + write(-y); + stream!.write(PdfOperators.whiteSpace); + } + + /// internal method + void closePath() { + writeOperator(PdfOperators.closePath); + } + + /// internal method + void clipPath(bool useEvenOddRule) { + stream!.write(PdfOperators.clipPath); + if (useEvenOddRule) { + stream!.write(PdfOperators.evenOdd); + } + stream!.write(PdfOperators.whiteSpace); + stream!.write(PdfOperators.endPath); + stream!.write(PdfOperators.newLine); + } + + /// internal method + void appendRectangle(double? x, double y, double? width, double height) { + writePoint(x, y); + writePoint(width, height); + writeOperator(PdfOperators.appendRectangle); + } + + /// internal method + void modifyCurrentMatrix(PdfTransformationMatrix matrix) { + stream!.write(matrix.getString()); + writeOperator(PdfOperators.currentMatrix); + } + + /// internal method + void modifyTransformationMatrix(PdfTransformationMatrix matrix) { + stream!.write(matrix.getString()); + writeOperator(PdfOperators.transformationMatrix); + } + + /// internal method + void setLineWidth(double width) { + write(width); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setLineWidth); + } + + /// internal method + void setLineCap(PdfLineCap lineCapStyle) { + write(lineCapStyle.index); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setLineCapStyle); + } + + /// internal method + void setLineJoin(PdfLineJoin lineJoinStyle) { + write(lineJoinStyle.index); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setLineJoinStyle); + } + + /// internal method + void setMiterLimit(double? miterLimit) { + write(miterLimit); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setMiterLimit); + } + + /// internal method + void setLineDashPattern(List? pattern, double patternOffset) { + final PdfArray patternArray = PdfArray(pattern); + patternArray.save(this); + stream!.write(PdfOperators.whiteSpace); + write(patternOffset); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setDashPattern); + } + + /// internal method + void setColorAndSpace( + PdfColor color, + PdfColorSpace? colorSpace, + bool forStroking, + ) { + if (!color.isEmpty) { + stream!.write( + PdfColorHelper.getHelper(color).getString(colorSpace, forStroking), + ); + stream!.write(PdfOperators.newLine); + } + } + + /// internal method + void setColorSpace(PdfName name, bool forStroking) { + stream!.write(name.toString()); + stream!.write(PdfOperators.whiteSpace); + stream!.write( + forStroking + ? PdfOperators.selectColorSpaceForStroking + : PdfOperators.selectColorSpaceForNonStroking, + ); + stream!.write(PdfOperators.newLine); + } + + /// internal method + void setFont(PdfFont font, PdfName name, double size) { + stream!.write(name.toString()); + stream!.write(PdfOperators.whiteSpace); + stream!.write(size.toStringAsFixed(2)); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setFont); + } + + /// internal method + void setTextRenderingMode(int renderingMode) { + write(renderingMode); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setRenderingMode); + } + + /// internal method + void setTextScaling(double? textScaling) { + write(textScaling); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setTextScaling); + } + + /// internal method + void setCharacterSpacing(double? charSpacing) { + write(charSpacing); + stream!.write(PdfOperators.whiteSpace); + stream!.write(PdfOperators.setCharacterSpace); + stream!.write(PdfOperators.newLine); + } + + /// internal method + void setWordSpacing(double? wordSpacing) { + write(wordSpacing); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setWordSpace); + } + + /// internal method + void showNextLineText(dynamic value) { + if (value == null) { + throw ArgumentError.value(value, 'value', 'value cannot be null'); + } + _writeText(value); + writeOperator(PdfOperators.setTextOnNewLine); + } + + /// internal method + void startNextLine([double? x, double? y]) { + if (x == null && y == null) { + writeOperator(PdfOperators.goToNextLine); + } else { + writePoint(x, y!); + writeOperator(PdfOperators.setCoords); + } + } + + /// internal method + void showText(PdfString pdfString) { + _writeText(pdfString); + writeOperator(PdfOperators.setText); + } + + /// internal method + void endText() { + writeOperator(PdfOperators.endText); + } + + void _writeText(dynamic value) { + if (value is PdfString) { + stream!.write(value.pdfEncode(null)); + } else if (value is List) { + stream!.write(PdfString.stringMark[0]); + stream!.write(value); + stream!.write(PdfString.stringMark[1]); + } + } + + /// internal method + void setGraphicsState(PdfName name) { + if (name.name!.isEmpty) { + throw ArgumentError.value( + name, + 'name', + 'dictionary name cannot be empty', + ); + } + stream!.write(name.toString()); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.setGraphicsState); + } + + /// internal method + void beginPath(double x, double y) { + writePoint(x, y); + writeOperator(PdfOperators.beginPath); + } + + /// internal method + void appendLineSegment(double x, double y) { + writePoint(x, y); + writeOperator(PdfOperators.appendLineSegment); + } + + /// internal method + void strokePath() { + writeOperator(PdfOperators.stroke); + } + + /// internal method + void closeFillStrokePath(bool useEvenOddRule) { + stream!.write(PdfOperators.closeFillStrokePath); + if (useEvenOddRule) { + stream!.write(PdfOperators.evenOdd); + } + stream!.write(PdfOperators.newLine); + } + + /// internal method + void fillStrokePath(bool useEvenOddRule) { + stream!.write(PdfOperators.fillStroke); + if (useEvenOddRule) { + stream!.write(PdfOperators.evenOdd); + } + stream!.write(PdfOperators.newLine); + } + + /// internal method + void fillPath(bool useEvenOddRule) { + stream!.write(PdfOperators.fill); + if (useEvenOddRule) { + stream!.write(PdfOperators.evenOdd); + } + stream!.write(PdfOperators.newLine); + } + + /// internal method + void closeFillPath(bool useEvenOddRule) { + writeOperator(PdfOperators.closePath); + stream!.write(PdfOperators.fill); + if (useEvenOddRule) { + stream!.write(PdfOperators.evenOdd); + } + stream!.write(PdfOperators.newLine); + } + + /// internal method + void closeStrokePath() { + writeOperator(PdfOperators.closeStrokePath); + } + + /// internal method + void endPath() { + writeOperator(PdfOperators.n); + } + + /// internal method + void executeObject(PdfName pdfName) { + stream!.write(pdfName.toString()); + stream!.write(PdfOperators.whiteSpace); + writeOperator(PdfOperators.paintXObject); + } + + /// internal method + void appendBezierSegment( + double x1, + double y1, + double x2, + double y2, + double x3, + double y3, + ) { + writePoint(x1, y1); + writePoint(x2, y2); + writePoint(x3, y3); + writeOperator(PdfOperators.appendBezierCurve); + } + + /// internal method + void clear() { + stream!.clearStream(); + } + + //IPdfWriter members + @override + PdfDocument? get document => null; + + @override + //ignore:unused_element + set document(PdfDocument? value) { + throw ArgumentError.value( + value, + 'The method or operation is not implemented', + ); + } + + @override + //ignore:unused_element + int get length => stream!.dataStream!.length; + + @override + //ignore:unused_element + set length(int? value) { + throw ArgumentError.value( + value, + 'The method or operation is not implemented', + ); + } + + @override + //ignore:unused_element + int? get position => stream!.position; + @override + //ignore:unused_element + set position(int? value) { + throw ArgumentError.value( + value, + 'The method or operation is not implemented', + ); + } + + @override + void write(dynamic pdfObject) { + if (pdfObject is IPdfPrimitive) { + pdfObject.save(this); + } else if (pdfObject is int) { + stream!.write(pdfObject.toString()); + } else if (pdfObject is double) { + pdfObject = pdfObject.toStringAsFixed(2); + if ((pdfObject as String).endsWith('.00')) { + if (pdfObject.length == 3) { + pdfObject = '0'; + } else { + pdfObject = pdfObject.substring(0, pdfObject.length - 3); + } + } + stream!.write(pdfObject); + } else if (pdfObject is String) { + stream!.write(pdfObject); + } else if (pdfObject is List) { + stream!.write(pdfObject); + } else { + throw ArgumentError.value( + pdfObject, + 'The method or operation is not implemented', + ); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_writer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_writer.dart index f185a55a0..da8990964 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_writer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/pdf_writer.dart @@ -1,177 +1,177 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import '../../interfaces/pdf_interface.dart'; -import '../pdf_document/pdf_document.dart'; - -/// Helper class to write PDF primitive elements easily. -class PdfWriter implements IPdfWriter { - //Constructor - /// internal constructor - PdfWriter(this.buffer, [PdfBytesBuilder? bytesBuilder]) { - if (bytesBuilder != null) { - this.bytesBuilder = bytesBuilder; - length = this.bytesBuilder!.length; - position = this.bytesBuilder!.length; - isBytesBuilder = true; - } else { - length = buffer!.length; - position = buffer!.length; - } - } - - //Fields - /// internal field - List? buffer; - PdfBytesBuilder? bytesBuilder; - bool isBytesBuilder = false; - //IPdfWriter members - @override - PdfDocument? document; - @override - //ignore:unused_field - int? length; - @override - int? position; - @override - void write(dynamic data, [int? end]) { - if (data == null) { - throw ArgumentError.value(data, 'data', 'value cannot be null'); - } - if (data is int) { - write(data.toString()); - } else if (data is double) { - String value = data.toStringAsFixed(2); - if (value.endsWith('.00')) { - if (value.length == 3) { - value = '0'; - } else { - value = value.substring(0, value.length - 3); - } - } - write(value); - } else if (data is String) { - write(utf8.encode(data)); - } else if (data is IPdfPrimitive) { - data.save(this); - } else if (data is List) { - int tempLength; - if (end == null) { - tempLength = data.length; - } else { - tempLength = end; - } - length = length! + tempLength; - position = position! + tempLength; - if (end == null) { - if (isBytesBuilder) { - bytesBuilder!.add(data); - } else { - _addDataInChunks(data); - //buffer!.addAll(data); - } - } else { - if (isBytesBuilder) { - bytesBuilder!.add(data.take(end).toList()); - } else { - _addDataInChunks(data.take(end).toList()); - //buffer!.addAll(data.take(end)); - } - } - } - } - - void _addDataInChunks(List data) { - const int chunkSize = 8190; - for (int i = 0; i < data.length; i += chunkSize) { - final int end = - (i + chunkSize < data.length) ? i + chunkSize : data.length; - buffer!.addAll(data.sublist(i, end)); - } - } - - /// Internal method - Future writeAsync(dynamic data, [int? end]) async { - if (data == null) { - throw ArgumentError.value(data, 'data', 'value cannot be null'); - } - if (data is int) { - writeAsync(data.toString()); - } else if (data is double) { - String value = data.toStringAsFixed(2); - if (value.endsWith('.00')) { - if (value.length == 3) { - value = '0'; - } else { - value = value.substring(0, value.length - 3); - } - } - writeAsync(value); - } else if (data is String) { - writeAsync(utf8.encode(data)); - } else if (data is IPdfPrimitive) { - data.save(this); - } else if (data is List) { - int tempLength; - if (end == null) { - tempLength = data.length; - } else { - tempLength = end; - } - length = length! + tempLength; - position = position! + tempLength; - if (end == null) { - if (isBytesBuilder) { - bytesBuilder!.add(data); - } else { - _addDataInChunks(data); - //buffer!.addAll(data); - } - } else { - if (isBytesBuilder) { - bytesBuilder!.add(data.take(end).toList()); - } else { - _addDataInChunks(data.take(end).toList()); - //buffer!.addAll(data.take(end)); - } - } - } - } -} - -///Helper class to write the PDF document data. -class PdfBytesBuilder { - /// internal fields - final List _chunks = []; - int _length = 0; - - /// get the length of the data - int get length => _length; - - /// add the data - void add(List data) { - if (data.isEmpty) { - return; - } - final Uint8List chunk = Uint8List.fromList(data); - _chunks.add(chunk); - _length += chunk.length; - } - - /// get the bytes - Uint8List takeBytes() { - final Uint8List result = Uint8List(_length); - int offset = 0; - for (final Uint8List chunk in _chunks) { - result.setRange(offset, offset + chunk.length, chunk); - offset += chunk.length; - } - return result; - } - - /// clear the data - void clear() { - _chunks.clear(); - _length = 0; - } -} +import 'dart:convert'; +import 'dart:typed_data'; + +import '../../interfaces/pdf_interface.dart'; +import '../pdf_document/pdf_document.dart'; + +/// Helper class to write PDF primitive elements easily. +class PdfWriter implements IPdfWriter { + //Constructor + /// internal constructor + PdfWriter(this.buffer, [PdfBytesBuilder? bytesBuilder]) { + if (bytesBuilder != null) { + this.bytesBuilder = bytesBuilder; + length = this.bytesBuilder!.length; + position = this.bytesBuilder!.length; + isBytesBuilder = true; + } else { + length = buffer!.length; + position = buffer!.length; + } + } + + //Fields + /// internal field + List? buffer; + PdfBytesBuilder? bytesBuilder; + bool isBytesBuilder = false; + //IPdfWriter members + @override + PdfDocument? document; + @override + //ignore:unused_field + int? length; + @override + int? position; + @override + void write(dynamic data, [int? end]) { + if (data == null) { + throw ArgumentError.value(data, 'data', 'value cannot be null'); + } + if (data is int) { + write(data.toString()); + } else if (data is double) { + String value = data.toStringAsFixed(2); + if (value.endsWith('.00')) { + if (value.length == 3) { + value = '0'; + } else { + value = value.substring(0, value.length - 3); + } + } + write(value); + } else if (data is String) { + write(utf8.encode(data)); + } else if (data is IPdfPrimitive) { + data.save(this); + } else if (data is List) { + int tempLength; + if (end == null) { + tempLength = data.length; + } else { + tempLength = end; + } + length = length! + tempLength; + position = position! + tempLength; + if (end == null) { + if (isBytesBuilder) { + bytesBuilder!.add(data); + } else { + _addDataInChunks(data); + //buffer!.addAll(data); + } + } else { + if (isBytesBuilder) { + bytesBuilder!.add(data.take(end).toList()); + } else { + _addDataInChunks(data.take(end).toList()); + //buffer!.addAll(data.take(end)); + } + } + } + } + + void _addDataInChunks(List data) { + const int chunkSize = 8190; + for (int i = 0; i < data.length; i += chunkSize) { + final int end = + (i + chunkSize < data.length) ? i + chunkSize : data.length; + buffer!.addAll(data.sublist(i, end)); + } + } + + /// Internal method + Future writeAsync(dynamic data, [int? end]) async { + if (data == null) { + throw ArgumentError.value(data, 'data', 'value cannot be null'); + } + if (data is int) { + writeAsync(data.toString()); + } else if (data is double) { + String value = data.toStringAsFixed(2); + if (value.endsWith('.00')) { + if (value.length == 3) { + value = '0'; + } else { + value = value.substring(0, value.length - 3); + } + } + writeAsync(value); + } else if (data is String) { + writeAsync(utf8.encode(data)); + } else if (data is IPdfPrimitive) { + data.save(this); + } else if (data is List) { + int tempLength; + if (end == null) { + tempLength = data.length; + } else { + tempLength = end; + } + length = length! + tempLength; + position = position! + tempLength; + if (end == null) { + if (isBytesBuilder) { + bytesBuilder!.add(data); + } else { + _addDataInChunks(data); + //buffer!.addAll(data); + } + } else { + if (isBytesBuilder) { + bytesBuilder!.add(data.take(end).toList()); + } else { + _addDataInChunks(data.take(end).toList()); + //buffer!.addAll(data.take(end)); + } + } + } + } +} + +///Helper class to write the PDF document data. +class PdfBytesBuilder { + /// internal fields + final List _chunks = []; + int _length = 0; + + /// get the length of the data + int get length => _length; + + /// add the data + void add(List data) { + if (data.isEmpty) { + return; + } + final Uint8List chunk = Uint8List.fromList(data); + _chunks.add(chunk); + _length += chunk.length; + } + + /// get the bytes + Uint8List takeBytes() { + final Uint8List result = Uint8List(_length); + int offset = 0; + for (final Uint8List chunk in _chunks) { + result.setRange(offset, offset + chunk.length, chunk); + offset += chunk.length; + } + return result; + } + + /// clear the data + void clear() { + _chunks.clear(); + _length = 0; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/stream_reader.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/stream_reader.dart index a1f60077d..16f70b78a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/stream_reader.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/io/stream_reader.dart @@ -1,53 +1,53 @@ -/// internal class -class PdfStreamReader { - //Constructor - /// internal constructor - PdfStreamReader([this.data]) { - _position = 0; - } - - //Fields - /// internal field - List? data; - int? _position; - - //Properties - /// internal property - int? get length => data!.length; - - /// internal property - int get position => _position!; - set position(int value) { - if (value < 0) { - throw ArgumentError.value(value, 'position', 'Invalid position'); - } - _position = value; - } - - //Implementation - /// internal method - int? readByte() { - if (_position != length) { - final int result = data![position]; - _position = _position! + 1; - return result; - } else { - return -1; - } - } - - /// internal method - int? read(List buffer, int offset, int length) { - _position = offset; - int pos = offset; - final int end = _position! + length; - while (_position! < end) { - final int byte = readByte()!; - if (byte == -1) { - break; - } - buffer[pos++] = byte; - } - return pos - offset; - } -} +/// internal class +class PdfStreamReader { + //Constructor + /// internal constructor + PdfStreamReader([this.data]) { + _position = 0; + } + + //Fields + /// internal field + List? data; + int? _position; + + //Properties + /// internal property + int? get length => data!.length; + + /// internal property + int get position => _position!; + set position(int value) { + if (value < 0) { + throw ArgumentError.value(value, 'position', 'Invalid position'); + } + _position = value; + } + + //Implementation + /// internal method + int? readByte() { + if (_position != length) { + final int result = data![position]; + _position = _position! + 1; + return result; + } else { + return -1; + } + } + + /// internal method + int? read(List buffer, int offset, int length) { + _position = offset; + int pos = offset; + final int end = _position! + length; + while (_position! < end) { + final int byte = readByte()!; + if (byte == -1) { + break; + } + buffer[pos++] = byte; + } + return pos - offset; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/enum.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/enum.dart index 4e96f022a..50b4fca0a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/enum.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/enum.dart @@ -1,135 +1,135 @@ -/// Enumerator that represents the PDF page orientations. -enum PdfPageOrientation { - /// Portrait orientation. - portrait, - - /// Landscape orientation. - landscape, -} - -/// The number of degrees by which the page should be rotated clockwise -/// when displayed or printed. -enum PdfPageRotateAngle { - /// The page is rotated as 0 angle. - rotateAngle0, - - /// The page is rotated as 90 angle. - rotateAngle90, - - /// The page is rotated as 180 angle. - rotateAngle180, - - /// The page is rotated as 270 angle. - rotateAngle270, -} - -/// Specifies the docking style of the page template. -enum PdfDockStyle { - /// The page template is not docked. - none, - - /// The page template edge is docked to the bottom page's side. - bottom, - - /// The page template edge is docked to the top page's side. - top, - - /// The page template edge is docked to the left page's side. - left, - - /// The page template edge is docked to the right page's side. - right, - - /// The page template stretch on full page. - fill, -} - -/// Specifies how the page template is aligned relative to the template area. -enum PdfAlignmentStyle { - /// Specifies no alignment. - none, - - /// The template is top left aligned. - topLeft, - - /// The template is top center aligned. - topCenter, - - /// The template is top right aligned. - topRight, - - /// The template is middle left aligned. - middleLeft, - - /// The template is middle center aligned. - middleCenter, - - /// The template is middle right aligned. - middleRight, - - /// The template is bottom left aligned. - bottomLeft, - - /// The template is bottom center aligned. - bottomCenter, - - /// The template is bottom right aligned. - bottomRight, -} - -/// Specifies numbering style of page labels. -enum PdfNumberStyle { - /// No numbering at all. - none, - - /// Decimal arabic numerals. - numeric, - - /// Lowercase letters a-z. - lowerLatin, - - /// Lowercase roman numerals. - lowerRoman, - - /// Uppercase letters A-Z. - upperLatin, - - /// Uppercase roman numerals. - upperRoman, -} - -/// Specifies tab order types for form fields -enum PdfFormFieldsTabOrder { - /// Form fields are visited default order - none, - - /// Form fields are visited rows running horizontally across the page - row, - - /// Form fields are visited column running vertically up and down the page - column, - - /// Form fields are visited based on the structure tree - structure, - - /// Form fields are visited manual order - manual, -} - -/// TemplateArea can be header/footer on of the following types. -enum TemplateType { - /// Page template is not used as header. - none, - - /// Page template is used as Top. - top, - - /// Page template is used as Bottom. - bottom, - - /// Page template is used as Left. - left, - - /// Page template is used as Right. - right, -} +/// Enumerator that represents the PDF page orientations. +enum PdfPageOrientation { + /// Portrait orientation. + portrait, + + /// Landscape orientation. + landscape, +} + +/// The number of degrees by which the page should be rotated clockwise +/// when displayed or printed. +enum PdfPageRotateAngle { + /// The page is rotated as 0 angle. + rotateAngle0, + + /// The page is rotated as 90 angle. + rotateAngle90, + + /// The page is rotated as 180 angle. + rotateAngle180, + + /// The page is rotated as 270 angle. + rotateAngle270, +} + +/// Specifies the docking style of the page template. +enum PdfDockStyle { + /// The page template is not docked. + none, + + /// The page template edge is docked to the bottom page's side. + bottom, + + /// The page template edge is docked to the top page's side. + top, + + /// The page template edge is docked to the left page's side. + left, + + /// The page template edge is docked to the right page's side. + right, + + /// The page template stretch on full page. + fill, +} + +/// Specifies how the page template is aligned relative to the template area. +enum PdfAlignmentStyle { + /// Specifies no alignment. + none, + + /// The template is top left aligned. + topLeft, + + /// The template is top center aligned. + topCenter, + + /// The template is top right aligned. + topRight, + + /// The template is middle left aligned. + middleLeft, + + /// The template is middle center aligned. + middleCenter, + + /// The template is middle right aligned. + middleRight, + + /// The template is bottom left aligned. + bottomLeft, + + /// The template is bottom center aligned. + bottomCenter, + + /// The template is bottom right aligned. + bottomRight, +} + +/// Specifies numbering style of page labels. +enum PdfNumberStyle { + /// No numbering at all. + none, + + /// Decimal arabic numerals. + numeric, + + /// Lowercase letters a-z. + lowerLatin, + + /// Lowercase roman numerals. + lowerRoman, + + /// Uppercase letters A-Z. + upperLatin, + + /// Uppercase roman numerals. + upperRoman, +} + +/// Specifies tab order types for form fields +enum PdfFormFieldsTabOrder { + /// Form fields are visited default order + none, + + /// Form fields are visited rows running horizontally across the page + row, + + /// Form fields are visited column running vertically up and down the page + column, + + /// Form fields are visited based on the structure tree + structure, + + /// Form fields are visited manual order + manual, +} + +/// TemplateArea can be header/footer on of the following types. +enum TemplateType { + /// Page template is not used as header. + none, + + /// Page template is used as Top. + top, + + /// Page template is used as Bottom. + bottom, + + /// Page template is used as Left. + left, + + /// Page template is used as Right. + right, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart index 620cb5fc6..18b40b538 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer.dart @@ -1,732 +1,729 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_margins.dart'; -import '../graphics/pdf_resources.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_layer_collection.dart'; -import 'pdf_section.dart'; -import 'pdf_section_collection.dart'; - -/// The [PdfLayer] used to create layers in PDF document. -class PdfLayer implements IPdfWrapper { - // Constructor - PdfLayer._() { - _helper = PdfLayerHelper(this); - _clipPageTemplates = true; - _helper._content = PdfStream(); - _helper.dictionary = PdfDictionary(); - } - - // Fields - late PdfLayerHelper _helper; - bool _clipPageTemplates = true; - PdfGraphics? _graphics; - final Map _graphicsMap = - {}; - final Map _pageGraphics = {}; - bool _isEmptyLayer = false; - String? _name; - bool _visible = true; - PdfLayerCollection? _layerCollection; - bool? _isPresent; - - // Properties - /// Gets the name of the layer - String? get name => _name; - - /// Sets the name of the layer - set name(String? value) { - _name = value; - if (_helper.dictionary != null && _name != null && _name != '') { - _helper.dictionary!.setProperty( - PdfDictionaryProperties.name, - PdfString(_name!), - ); - } - } - - /// Gets the visibility of the page layer. - bool get visible { - if (_helper.dictionary != null && - _helper.dictionary!.containsKey(PdfDictionaryProperties.visible)) { - _visible = - (_helper.dictionary![PdfDictionaryProperties.visible]! as PdfBoolean) - .value!; - } - return _visible; - } - - /// Sets the visibility of the page layer. - set visible(bool value) { - _visible = value; - if (_helper.dictionary != null) { - _helper.dictionary![PdfDictionaryProperties.visible] = PdfBoolean(value); - } - _helper._setVisibility(_visible); - } - - /// Gets the collection of child [PdfLayer] - PdfLayerCollection get layers { - _layerCollection ??= PdfLayerCollectionHelper.withLayer( - _helper.document, - _helper.layer, - ); - return _layerCollection!; - } - - // Implementation - /// Initializes Graphics context of the layer. - PdfGraphics createGraphics(PdfPage page) { - _helper.page = page; - if (_graphics == null) { - PdfPageHelper.getHelper( - page, - ).contents.add(PdfReferenceHolder(_helper.layer)); - } - final PdfResources? resource = PdfPageHelper.getHelper(page).getResources(); - if (PdfLayerHelper.getHelper(_helper.layer!).layerId == null || - PdfLayerHelper.getHelper(_helper.layer!).layerId!.isEmpty) { - PdfLayerHelper.getHelper(_helper.layer!).layerId = - 'OCG_${PdfResources.globallyUniqueIdentifier}'; - } - if (resource != null && - resource.containsKey(PdfDictionaryProperties.properties)) { - final PdfDictionary? propertie = - resource[PdfDictionaryProperties.properties] as PdfDictionary?; - if (propertie != null) { - if (PdfLayerHelper.getHelper(_helper.layer!).layerId![0] == '/') { - PdfLayerHelper.getHelper(_helper.layer!).layerId = - PdfLayerHelper.getHelper(_helper.layer!).layerId!.substring(1); - } - propertie[PdfLayerHelper.getHelper(_helper.layer!).layerId] = - PdfLayerHelper.getHelper(_helper.layer!).referenceHolder; - } else { - resource.properties[PdfLayerHelper.getHelper(_helper.layer!).layerId] = - PdfLayerHelper.getHelper(_helper.layer!).referenceHolder; - resource[PdfDictionaryProperties.properties] = resource.properties; - } - } else { - resource!.properties[PdfLayerHelper.getHelper(_helper.layer!).layerId] = - PdfLayerHelper.getHelper(_helper.layer!).referenceHolder; - resource[PdfDictionaryProperties.properties] = resource.properties; - } - - if (_graphics == null) { - final Function resources = PdfPageHelper.getHelper(page).getResources; - bool isPageHasMediaBox = false; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfName(PdfDictionaryProperties.mediaBox))) { - isPageHasMediaBox = true; - } - double llx = 0; - double lly = 0; - double urx = 0; - double ury = 0; - final PdfArray? mediaBox = - PdfPageHelper.getHelper(page).dictionary!.getValue( - PdfDictionaryProperties.mediaBox, - PdfDictionaryProperties.parent, - ) - as PdfArray?; - if (mediaBox != null) { - // Lower Left X co-ordinate Value. - llx = (mediaBox[0]! as PdfNumber).value!.toDouble(); - // Lower Left Y co-ordinate value. - lly = (mediaBox[1]! as PdfNumber).value!.toDouble(); - // Upper right X co-ordinate value. - urx = (mediaBox[2]! as PdfNumber).value!.toDouble(); - // Upper right Y co-ordinate value. - ury = (mediaBox[3]! as PdfNumber).value!.toDouble(); - } - PdfArray? cropBox; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { - cropBox = - PdfPageHelper.getHelper(page).dictionary!.getValue( - PdfDictionaryProperties.cropBox, - PdfDictionaryProperties.parent, - ) - as PdfArray?; - final double cropX = (cropBox![0]! as PdfNumber).value!.toDouble(); - final double cropY = (cropBox[1]! as PdfNumber).value!.toDouble(); - final double cropRX = (cropBox[2]! as PdfNumber).value!.toDouble(); - final double cropRY = (cropBox[3]! as PdfNumber).value!.toDouble(); - if ((cropX < 0 || cropY < 0 || cropRX < 0 || cropRY < 0) && - (cropY.abs().floor() == page.size.height.abs().floor()) && - (cropX.abs().floor()) == page.size.width.abs().floor()) { - final Size pageSize = Size( - [cropX, cropRX].reduce(max), - [cropY, cropRY].reduce(max), - ); - _graphics = PdfGraphicsHelper.load( - pageSize, - resources, - _helper._content!, - ); - } else { - _graphics = PdfGraphicsHelper.load( - page.size, - resources, - _helper._content!, - ); - PdfGraphicsHelper.getHelper(_graphics!).cropBox = cropBox; - } - } else if ((llx < 0 || lly < 0 || urx < 0 || ury < 0) && - (lly.abs().floor() == page.size.height.abs().floor()) && - (urx.abs().floor() == page.size.width.abs().floor())) { - final Size pageSize = Size( - [llx, urx].reduce(max), - [lly, ury].reduce(max), - ); - if (pageSize.width <= 0 || pageSize.height <= 0) { - _graphics = PdfGraphicsHelper.load( - pageSize, - resources, - _helper._content!, - ); - } - } else { - _graphics = PdfGraphicsHelper.load( - page.size, - resources, - _helper._content!, - ); - } - if (isPageHasMediaBox) { - PdfGraphicsHelper.getHelper(_graphics!).mediaBoxUpperRightBound = ury; - } - if (!PdfPageHelper.getHelper(page).isLoadedPage) { - final PdfSectionCollection? sectionCollection = - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page).section!, - ).parent; - if (sectionCollection != null) { - _graphics!.colorSpace = - PdfSectionCollectionHelper.getHelper( - sectionCollection, - ).document!.colorSpace; - } - } - if (!_graphicsMap.containsKey(_graphics)) { - _graphicsMap[_graphics!] = _graphics!; - } - if (!_pageGraphics.containsKey(page)) { - _pageGraphics[page] = _graphics!; - } - _helper._content!.beginSave = _beginSaveContent; - } else { - if (!_helper.pages.contains(page)) { - _graphicsContent(page); - } else if (_pageGraphics.containsKey(page)) { - _graphics = _pageGraphics[page]; - return _graphics!; - } - } - PdfGraphicsHelper.getHelper( - _graphics!, - ).streamWriter!.write(PdfOperators.newLine); - _graphics!.save(); - PdfGraphicsHelper.getHelper(_graphics!).initializeCoordinates(); - if (PdfGraphicsHelper.getHelper(_graphics!).hasTransparencyBrush) { - PdfGraphicsHelper.getHelper(_graphics!).setTransparencyGroup(page); - } - if (PdfPageHelper.getHelper(page).isLoadedPage && - (page.rotation != PdfPageRotateAngle.rotateAngle0 || - PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.rotate))) { - PdfArray? cropBox; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { - cropBox = - PdfPageHelper.getHelper(page).dictionary!.getValue( - PdfDictionaryProperties.cropBox, - PdfDictionaryProperties.parent, - ) - as PdfArray?; - } - _updatePageRotation(page, _graphics, cropBox); - } - if (!PdfPageHelper.getHelper(page).isLoadedPage) { - final PdfRectangle clipRect = PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page).section!, - ).getActualBounds(page, true); - if (_clipPageTemplates) { - if (PdfPageHelper.getHelper(page).origin.dx >= 0 && - PdfPageHelper.getHelper(page).origin.dy >= 0) { - PdfGraphicsHelper.getHelper( - _graphics!, - ).clipTranslateMarginsWithBounds(clipRect); - } - } else { - final PdfMargins margins = - PdfPageHelper.getHelper(page).section!.pageSettings.margins; - PdfGraphicsHelper.getHelper(_graphics!).clipTranslateMargins( - clipRect.x, - clipRect.y, - margins.left, - margins.top, - margins.right, - margins.bottom, - ); - } - } - if (!_helper.pages.contains(page)) { - _helper.pages.add(page); - } - PdfGraphicsHelper.getHelper(_graphics!).setLayer(null, this); - return _graphics!; - } - - void _updatePageRotation( - PdfPage page, - PdfGraphics? graphics, - PdfArray? cropBox, - ) { - PdfNumber? rotation; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.rotate)) { - rotation = - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .rotate] - as PdfNumber?; - rotation ??= - rotation = - PdfCrossTable.dereference( - PdfPageHelper.getHelper( - page, - ).dictionary![PdfDictionaryProperties.rotate], - ) - as PdfNumber?; - } else if (page.rotation != PdfPageRotateAngle.rotateAngle0) { - if (page.rotation == PdfPageRotateAngle.rotateAngle90) { - rotation = PdfNumber(90); - } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { - rotation = PdfNumber(180); - } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { - rotation = PdfNumber(270); - } - } - if (rotation!.value == 90) { - graphics!.translateTransform(0, page.size.height); - graphics.rotateTransform(-90); - if (cropBox != null) { - final double height = (cropBox[3]! as PdfNumber).value!.toDouble(); - final Size cropBoxSize = Size( - (cropBox[2]! as PdfNumber).value!.toDouble(), - height != 0 ? height : (cropBox[1]! as PdfNumber).value!.toDouble(), - ); - final Offset cropBoxOffset = Offset( - (cropBox[0]! as PdfNumber).value!.toDouble(), - (cropBox[1]! as PdfNumber).value!.toDouble(), - ); - if (page.size.height < cropBoxSize.height) { - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - page.size.height - cropBoxOffset.dy, - cropBoxSize.width - cropBoxOffset.dx, - ); - } else { - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - cropBoxSize.height - cropBoxOffset.dy, - cropBoxSize.width - cropBoxOffset.dx, - ); - } - } else { - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - page.size.height, - page.size.width, - ); - } - } else if (rotation.value == 180) { - graphics!.translateTransform(page.size.width, page.size.height); - graphics.rotateTransform(-180); - } else if (rotation.value == 270) { - graphics!.translateTransform(page.size.width, 0); - graphics.rotateTransform(-270); - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - page.size.height, - page.size.width, - ); - } - } - - void _graphicsContent(PdfPage page) { - final PdfStream stream = PdfStream(); - _graphics = PdfGraphicsHelper.load( - page.size, - PdfPageHelper.getHelper(page).getResources, - stream, - ); - PdfPageHelper.getHelper(page).contents.add(PdfReferenceHolder(stream)); - stream.beginSave = _beginSaveContent; - if (!_graphicsMap.containsKey(_graphics)) { - _graphicsMap[_graphics!] = _graphics!; - } - if (!_pageGraphics.containsKey(page)) { - _pageGraphics[page] = _graphics!; - } - } - - void _beginSaveContent(Object sender, SavePdfPrimitiveArgs? e) { - bool flag = false; - PdfGraphics? keyValue; - _graphicsMap.forEach((PdfGraphics? key, PdfGraphics? values) { - if (!flag) { - _graphics = key; - if (!_isEmptyLayer) { - _helper.beginLayer(_graphics); - PdfGraphicsHelper.getHelper(_graphics!).endMarkContent(); - } - PdfGraphicsHelper.getHelper( - _graphics!, - ).streamWriter!.write(PdfOperators.restoreState + PdfOperators.newLine); - keyValue = key; - flag = true; - } - }); - if (keyValue != null) { - _graphicsMap.remove(keyValue); - } - } -} - -/// [PdfLayer] helper -class PdfLayerHelper { - /// internal constructor - PdfLayerHelper(this.base); - - /// internal field - late PdfLayer base; - PdfStream? _content; - - /// internal method - static PdfLayerHelper getHelper(PdfLayer base) { - return base._helper; - } - - /// internal method - static PdfLayer internal() { - return PdfLayer._(); - } - - /// internal field - PdfLayer? layer; - - /// internal field - String? layerId; - - /// internal field - PdfReferenceHolder? referenceHolder; - - /// internal field - final List parentLayer = []; - - /// internal field - PdfDictionary? dictionary; - - /// internal field - bool isEndState = false; - - /// internal method - final List pages = []; - - /// internal method - PdfPage? page; - - /// internal method - PdfDocument? document; - - /// internal method - PdfDictionary? printOption; - - /// internal method - PdfDictionary? usage; - - /// internal method - PdfLayer? parent; - - /// internal method - final List child = []; - - /// internal method - final PdfArray sublayer = PdfArray(); - - /// internal method - final List xobject = []; - - /// internal method - bool pageParsed = false; - - /// internal method - void beginLayer(PdfGraphics? currentGraphics) { - if (base._graphicsMap.containsKey(currentGraphics)) { - base._graphics = base._graphicsMap[currentGraphics]; - } else { - base._graphics = currentGraphics; - } - if (base._graphics != null) { - if (base._name != null && base._name != '') { - base._isEmptyLayer = true; - if (parentLayer.isNotEmpty) { - for (int i = 0; i < parentLayer.length; i++) { - PdfGraphicsHelper.getHelper(base._graphics!).streamWriter!.write( - '/OC /${PdfLayerHelper.getHelper(parentLayer[i]).layerId!} BDC\n', - ); - } - } - if (base.name != null && base.name != '') { - PdfGraphicsHelper.getHelper( - base._graphics!, - ).streamWriter!.write('/OC /${layerId!} BDC\n'); - isEndState = true; - } else { - _content!.write('/OC /${layerId!} BDC\n'); - } - } - } - } - - /// internal method - void parsingLayerPage() { - if (document != null && - PdfDocumentHelper.getHelper(document!).isLoadedDocument) { - for (int i = 0; i < document!.pages.count; i++) { - final PdfDictionary pageDictionary = - PdfPageHelper.getHelper(document!.pages[i]).dictionary!; - final PdfPage page = document!.pages[i]; - if (pageDictionary.containsKey(PdfDictionaryProperties.resources)) { - final PdfDictionary? resources = - PdfCrossTable.dereference( - pageDictionary[PdfDictionaryProperties.resources], - ) - as PdfDictionary?; - if (resources != null && - (resources.containsKey(PdfDictionaryProperties.properties)) || - (resources!.containsKey(PdfDictionaryProperties.xObject))) { - final PdfDictionary? properties = - PdfCrossTable.dereference( - resources[PdfDictionaryProperties.properties], - ) - as PdfDictionary?; - final PdfDictionary? xObject = - PdfCrossTable.dereference( - resources[PdfDictionaryProperties.xObject], - ) - as PdfDictionary?; - if (properties != null) { - properties.items!.forEach((PdfName? key, IPdfPrimitive? value) { - if (value is PdfReferenceHolder) { - final PdfDictionary? dictionary = - value.object as PdfDictionary?; - _parsingDictionary(dictionary, value, page, key); - } - }); - if (properties.items!.isEmpty) { - pageParsed = true; - } - } - if (xObject != null) { - xObject.items!.forEach((PdfName? key, IPdfPrimitive? value) { - PdfReferenceHolder reference = value! as PdfReferenceHolder; - PdfDictionary dictionary = reference.object! as PdfDictionary; - if (dictionary.containsKey('OC')) { - final PdfName? layerID = key; - reference = dictionary['OC']! as PdfReferenceHolder; - dictionary = - PdfCrossTable.dereference(dictionary['OC'])! - as PdfDictionary; - final bool isPresent = - _parsingDictionary(dictionary, reference, page, layerID)!; - if (isPresent) { - PdfLayerHelper.getHelper( - layer!, - ).xobject.add(layerID!.name!); - } - } - }); - if (xObject.items!.isEmpty) { - pageParsed = true; - } - } - } - } - } - } - } - - bool? _parsingDictionary( - PdfDictionary? dictionary, - PdfReferenceHolder? reference, - PdfPage? page, - PdfName? layerID, - ) { - if (base._isPresent == null || !base._isPresent!) { - base._isPresent = false; - if (!dictionary!.containsKey(PdfDictionaryProperties.name) && - dictionary.containsKey(PdfDictionaryProperties.ocg)) { - if (dictionary.containsKey(PdfDictionaryProperties.ocg)) { - final PdfArray? pdfArray = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ocg]) - as PdfArray?; - if (pdfArray == null) { - reference = - dictionary[PdfDictionaryProperties.ocg] as PdfReferenceHolder?; - dictionary = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.ocg], - ) - as PdfDictionary?; - if (dictionary != null && - dictionary.containsKey(PdfDictionaryProperties.name)) { - base._isPresent = _setLayerPage(reference, page, layerID); - } - } else { - for (int a = 0; a < pdfArray.count; a++) { - if (pdfArray[a] is PdfReferenceHolder) { - reference = pdfArray[a]! as PdfReferenceHolder; - dictionary = reference.object as PdfDictionary?; - base._isPresent = _setLayerPage(reference, page, layerID); - } - } - } - } - } else if (dictionary.containsKey(PdfDictionaryProperties.name)) { - base._isPresent = _setLayerPage(reference, page, layerID); - } - return base._isPresent; - } else { - return false; - } - } - - bool _setLayerPage( - PdfReferenceHolder? reference, - PdfPage? page, - PdfName? layerID, - ) { - bool isPresent = false; - if (PdfLayerHelper.getHelper(layer!).referenceHolder != null) { - if (identical( - PdfLayerHelper.getHelper(layer!).referenceHolder, - reference, - ) || - identical( - PdfLayerHelper.getHelper(layer!).referenceHolder!.object, - reference!.object, - ) || - PdfLayerHelper.getHelper(layer!).referenceHolder?.reference?.objNum == - reference.reference?.objNum) { - PdfLayerHelper.getHelper(layer!).pageParsed = true; - isPresent = true; - PdfLayerHelper.getHelper(layer!).layerId = layerID!.name; - PdfLayerHelper.getHelper(layer!).page = page; - if (!PdfLayerHelper.getHelper(layer!).pages.contains(page)) { - PdfLayerHelper.getHelper(layer!).pages.add(page!); - } - } - } - return isPresent; - } - - void _setVisibility(bool? value) { - PdfDictionary? oCProperties; - if (PdfDocumentHelper.getHelper( - document!, - ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { - oCProperties = - PdfCrossTable.dereference( - PdfDocumentHelper.getHelper( - document!, - ).catalog[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - } - if (oCProperties != null) { - PdfDictionary? defaultView; - if (oCProperties.containsKey(PdfDictionaryProperties.defaultView)) { - final value = oCProperties[PdfDictionaryProperties.defaultView]; - if (value is PdfReferenceHolder) { - defaultView = PdfCrossTable.dereference(value) as PdfDictionary?; - } else if (value is PdfDictionary) { - defaultView = value; - } - } - if (defaultView != null) { - PdfArray? ocgON = - defaultView[PdfDictionaryProperties.ocgOn] as PdfArray?; - PdfArray? ocgOFF = - defaultView[PdfDictionaryProperties.ocgOff] as PdfArray?; - if (referenceHolder != null) { - if (value == false) { - if (ocgON != null) { - _removeContent(ocgON, referenceHolder); - } - if (ocgOFF == null) { - ocgOFF = PdfArray(); - defaultView.items![PdfName(PdfDictionaryProperties.ocgOff)] = - ocgOFF; - } - ocgOFF.insert(ocgOFF.count, referenceHolder!); - } else if (value ?? true) { - if (ocgOFF != null) { - _removeContent(ocgOFF, referenceHolder); - } - if (ocgON == null) { - ocgON = PdfArray(); - defaultView.items![PdfName(PdfDictionaryProperties.ocgOn)] = - ocgON; - } - ocgON.insert(ocgON.count, referenceHolder!); - } - } - } - } - } - - void _removeContent(PdfArray content, PdfReferenceHolder? referenceHolder) { - bool flag = false; - for (int i = 0; i < content.count; i++) { - final IPdfPrimitive? primitive = content.elements[i]; - if (primitive != null && primitive is PdfReferenceHolder) { - final PdfReferenceHolder holder = primitive; - if (holder.reference != null && referenceHolder!.reference != null) { - if (holder.reference!.objNum == referenceHolder.reference!.objNum) { - content.elements.removeAt(i); - flag = true; - i--; - } - } - } - } - if (flag) { - content.changed = true; - } - } - - /// internal property - IPdfPrimitive? get element => _content; - //ignore: unused_element - set element(IPdfPrimitive? value) { - _content = value as PdfStream?; - } -} +import 'dart:math'; +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_margins.dart'; +import '../graphics/pdf_resources.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_layer_collection.dart'; +import 'pdf_section.dart'; +import 'pdf_section_collection.dart'; + +/// The [PdfLayer] used to create layers in PDF document. +class PdfLayer implements IPdfWrapper { + // Constructor + PdfLayer._() { + _helper = PdfLayerHelper(this); + _clipPageTemplates = true; + _helper._content = PdfStream(); + _helper.dictionary = PdfDictionary(); + } + + // Fields + late PdfLayerHelper _helper; + bool _clipPageTemplates = true; + PdfGraphics? _graphics; + final Map _graphicsMap = + {}; + final Map _pageGraphics = {}; + bool _isEmptyLayer = false; + String? _name; + bool _visible = true; + PdfLayerCollection? _layerCollection; + bool? _isPresent; + + // Properties + /// Gets the name of the layer + String? get name => _name; + + /// Sets the name of the layer + set name(String? value) { + _name = value; + if (_helper.dictionary != null && _name != null && _name != '') { + _helper.dictionary!.setProperty( + PdfDictionaryProperties.name, + PdfString(_name!), + ); + } + } + + /// Gets the visibility of the page layer. + bool get visible { + if (_helper.dictionary != null && + _helper.dictionary!.containsKey(PdfDictionaryProperties.visible)) { + _visible = + (_helper.dictionary![PdfDictionaryProperties.visible]! as PdfBoolean) + .value!; + } + return _visible; + } + + /// Sets the visibility of the page layer. + set visible(bool value) { + _visible = value; + if (_helper.dictionary != null) { + _helper.dictionary![PdfDictionaryProperties.visible] = PdfBoolean(value); + } + _helper._setVisibility(_visible); + } + + /// Gets the collection of child [PdfLayer] + PdfLayerCollection get layers { + _layerCollection ??= PdfLayerCollectionHelper.withLayer( + _helper.document, + _helper.layer, + ); + return _layerCollection!; + } + + // Implementation + /// Initializes Graphics context of the layer. + PdfGraphics createGraphics(PdfPage page) { + _helper.page = page; + if (_graphics == null) { + PdfPageHelper.getHelper( + page, + ).contents.add(PdfReferenceHolder(_helper.layer)); + } + final PdfResources? resource = PdfPageHelper.getHelper(page).getResources(); + if (PdfLayerHelper.getHelper(_helper.layer!).layerId == null || + PdfLayerHelper.getHelper(_helper.layer!).layerId!.isEmpty) { + PdfLayerHelper.getHelper(_helper.layer!).layerId = + 'OCG_${PdfResources.globallyUniqueIdentifier}'; + } + if (resource != null && + resource.containsKey(PdfDictionaryProperties.properties)) { + final PdfDictionary? propertie = + resource[PdfDictionaryProperties.properties] as PdfDictionary?; + if (propertie != null) { + if (PdfLayerHelper.getHelper(_helper.layer!).layerId![0] == '/') { + PdfLayerHelper.getHelper(_helper.layer!).layerId = + PdfLayerHelper.getHelper(_helper.layer!).layerId!.substring(1); + } + propertie[PdfLayerHelper.getHelper(_helper.layer!).layerId] = + PdfLayerHelper.getHelper(_helper.layer!).referenceHolder; + } else { + resource.properties[PdfLayerHelper.getHelper(_helper.layer!).layerId] = + PdfLayerHelper.getHelper(_helper.layer!).referenceHolder; + resource[PdfDictionaryProperties.properties] = resource.properties; + } + } else { + resource!.properties[PdfLayerHelper.getHelper(_helper.layer!).layerId] = + PdfLayerHelper.getHelper(_helper.layer!).referenceHolder; + resource[PdfDictionaryProperties.properties] = resource.properties; + } + + if (_graphics == null) { + final Function resources = PdfPageHelper.getHelper(page).getResources; + bool isPageHasMediaBox = false; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfName(PdfDictionaryProperties.mediaBox))) { + isPageHasMediaBox = true; + } + double llx = 0; + double lly = 0; + double urx = 0; + double ury = 0; + final PdfArray? mediaBox = + PdfPageHelper.getHelper(page).dictionary!.getValue( + PdfDictionaryProperties.mediaBox, + PdfDictionaryProperties.parent, + ) + as PdfArray?; + if (mediaBox != null) { + // Lower Left X co-ordinate Value. + llx = (mediaBox[0]! as PdfNumber).value!.toDouble(); + // Lower Left Y co-ordinate value. + lly = (mediaBox[1]! as PdfNumber).value!.toDouble(); + // Upper right X co-ordinate value. + urx = (mediaBox[2]! as PdfNumber).value!.toDouble(); + // Upper right Y co-ordinate value. + ury = (mediaBox[3]! as PdfNumber).value!.toDouble(); + } + PdfArray? cropBox; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { + cropBox = + PdfPageHelper.getHelper(page).dictionary!.getValue( + PdfDictionaryProperties.cropBox, + PdfDictionaryProperties.parent, + ) + as PdfArray?; + final double cropX = (cropBox![0]! as PdfNumber).value!.toDouble(); + final double cropY = (cropBox[1]! as PdfNumber).value!.toDouble(); + final double cropRX = (cropBox[2]! as PdfNumber).value!.toDouble(); + final double cropRY = (cropBox[3]! as PdfNumber).value!.toDouble(); + if ((cropX < 0 || cropY < 0 || cropRX < 0 || cropRY < 0) && + (cropY.abs().floor() == page.size.height.abs().floor()) && + (cropX.abs().floor()) == page.size.width.abs().floor()) { + final Size pageSize = Size( + [cropX, cropRX].reduce(max), + [cropY, cropRY].reduce(max), + ); + _graphics = PdfGraphicsHelper.load( + pageSize, + resources, + _helper._content!, + ); + } else { + _graphics = PdfGraphicsHelper.load( + page.size, + resources, + _helper._content!, + ); + PdfGraphicsHelper.getHelper(_graphics!).cropBox = cropBox; + } + } else if ((llx < 0 || lly < 0 || urx < 0 || ury < 0) && + (lly.abs().floor() == page.size.height.abs().floor()) && + (urx.abs().floor() == page.size.width.abs().floor())) { + final Size pageSize = Size( + [llx, urx].reduce(max), + [lly, ury].reduce(max), + ); + if (pageSize.width <= 0 || pageSize.height <= 0) { + _graphics = PdfGraphicsHelper.load( + pageSize, + resources, + _helper._content!, + ); + } + } else { + _graphics = PdfGraphicsHelper.load( + page.size, + resources, + _helper._content!, + ); + } + if (isPageHasMediaBox) { + PdfGraphicsHelper.getHelper(_graphics!).mediaBoxUpperRightBound = ury; + } + if (!PdfPageHelper.getHelper(page).isLoadedPage) { + final PdfSectionCollection? sectionCollection = + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page).section!, + ).parent; + if (sectionCollection != null) { + _graphics!.colorSpace = + PdfSectionCollectionHelper.getHelper( + sectionCollection, + ).document!.colorSpace; + } + } + if (!_graphicsMap.containsKey(_graphics)) { + _graphicsMap[_graphics!] = _graphics!; + } + if (!_pageGraphics.containsKey(page)) { + _pageGraphics[page] = _graphics!; + } + _helper._content!.beginSave = _beginSaveContent; + } else { + if (!_helper.pages.contains(page)) { + _graphicsContent(page); + } else if (_pageGraphics.containsKey(page)) { + _graphics = _pageGraphics[page]; + return _graphics!; + } + } + PdfGraphicsHelper.getHelper( + _graphics!, + ).streamWriter!.write(PdfOperators.newLine); + _graphics!.save(); + PdfGraphicsHelper.getHelper(_graphics!).initializeCoordinates(); + if (PdfGraphicsHelper.getHelper(_graphics!).hasTransparencyBrush) { + PdfGraphicsHelper.getHelper(_graphics!).setTransparencyGroup(page); + } + if (PdfPageHelper.getHelper(page).isLoadedPage && + (page.rotation != PdfPageRotateAngle.rotateAngle0 || + PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.rotate))) { + PdfArray? cropBox; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { + cropBox = + PdfPageHelper.getHelper(page).dictionary!.getValue( + PdfDictionaryProperties.cropBox, + PdfDictionaryProperties.parent, + ) + as PdfArray?; + } + _updatePageRotation(page, _graphics, cropBox); + } + if (!PdfPageHelper.getHelper(page).isLoadedPage) { + final PdfRectangle clipRect = PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page).section!, + ).getActualBounds(page, true); + if (_clipPageTemplates) { + if (PdfPageHelper.getHelper(page).origin.dx >= 0 && + PdfPageHelper.getHelper(page).origin.dy >= 0) { + PdfGraphicsHelper.getHelper( + _graphics!, + ).clipTranslateMarginsWithBounds(clipRect); + } + } else { + final PdfMargins margins = + PdfPageHelper.getHelper(page).section!.pageSettings.margins; + PdfGraphicsHelper.getHelper(_graphics!).clipTranslateMargins( + clipRect.x, + clipRect.y, + margins.left, + margins.top, + margins.right, + margins.bottom, + ); + } + } + if (!_helper.pages.contains(page)) { + _helper.pages.add(page); + } + PdfGraphicsHelper.getHelper(_graphics!).setLayer(null, this); + return _graphics!; + } + + void _updatePageRotation( + PdfPage page, + PdfGraphics? graphics, + PdfArray? cropBox, + ) { + PdfNumber? rotation; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.rotate)) { + rotation = + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .rotate] + as PdfNumber?; + rotation ??= + rotation = + PdfCrossTable.dereference( + PdfPageHelper.getHelper( + page, + ).dictionary![PdfDictionaryProperties.rotate], + ) + as PdfNumber?; + } else if (page.rotation != PdfPageRotateAngle.rotateAngle0) { + if (page.rotation == PdfPageRotateAngle.rotateAngle90) { + rotation = PdfNumber(90); + } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { + rotation = PdfNumber(180); + } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { + rotation = PdfNumber(270); + } + } + if (rotation!.value == 90) { + graphics!.translateTransform(0, page.size.height); + graphics.rotateTransform(-90); + if (cropBox != null) { + final double height = (cropBox[3]! as PdfNumber).value!.toDouble(); + final Size cropBoxSize = Size( + (cropBox[2]! as PdfNumber).value!.toDouble(), + height != 0 ? height : (cropBox[1]! as PdfNumber).value!.toDouble(), + ); + final Offset cropBoxOffset = Offset( + (cropBox[0]! as PdfNumber).value!.toDouble(), + (cropBox[1]! as PdfNumber).value!.toDouble(), + ); + if (page.size.height < cropBoxSize.height) { + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + page.size.height - cropBoxOffset.dy, + cropBoxSize.width - cropBoxOffset.dx, + ); + } else { + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + cropBoxSize.height - cropBoxOffset.dy, + cropBoxSize.width - cropBoxOffset.dx, + ); + } + } else { + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + page.size.height, + page.size.width, + ); + } + } else if (rotation.value == 180) { + graphics!.translateTransform(page.size.width, page.size.height); + graphics.rotateTransform(-180); + } else if (rotation.value == 270) { + graphics!.translateTransform(page.size.width, 0); + graphics.rotateTransform(-270); + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + page.size.height, + page.size.width, + ); + } + } + + void _graphicsContent(PdfPage page) { + final PdfStream stream = PdfStream(); + _graphics = PdfGraphicsHelper.load( + page.size, + PdfPageHelper.getHelper(page).getResources, + stream, + ); + PdfPageHelper.getHelper(page).contents.add(PdfReferenceHolder(stream)); + stream.beginSave = _beginSaveContent; + if (!_graphicsMap.containsKey(_graphics)) { + _graphicsMap[_graphics!] = _graphics!; + } + if (!_pageGraphics.containsKey(page)) { + _pageGraphics[page] = _graphics!; + } + } + + void _beginSaveContent(Object sender, SavePdfPrimitiveArgs? e) { + bool flag = false; + PdfGraphics? keyValue; + _graphicsMap.forEach((PdfGraphics? key, PdfGraphics? values) { + if (!flag) { + _graphics = key; + if (!_isEmptyLayer) { + _helper.beginLayer(_graphics); + PdfGraphicsHelper.getHelper(_graphics!).endMarkContent(); + } + PdfGraphicsHelper.getHelper( + _graphics!, + ).streamWriter!.write(PdfOperators.restoreState + PdfOperators.newLine); + keyValue = key; + flag = true; + } + }); + if (keyValue != null) { + _graphicsMap.remove(keyValue); + } + } +} + +/// [PdfLayer] helper +class PdfLayerHelper { + /// internal constructor + PdfLayerHelper(this.base); + + /// internal field + late PdfLayer base; + PdfStream? _content; + + /// internal method + static PdfLayerHelper getHelper(PdfLayer base) { + return base._helper; + } + + /// internal method + static PdfLayer internal() { + return PdfLayer._(); + } + + /// internal field + PdfLayer? layer; + + /// internal field + String? layerId; + + /// internal field + PdfReferenceHolder? referenceHolder; + + /// internal field + final List parentLayer = []; + + /// internal field + PdfDictionary? dictionary; + + /// internal field + bool isEndState = false; + + /// internal method + final List pages = []; + + /// internal method + PdfPage? page; + + /// internal method + PdfDocument? document; + + /// internal method + PdfDictionary? printOption; + + /// internal method + PdfDictionary? usage; + + /// internal method + PdfLayer? parent; + + /// internal method + final List child = []; + + /// internal method + final PdfArray sublayer = PdfArray(); + + /// internal method + final List xobject = []; + + /// internal method + bool pageParsed = false; + + /// internal method + void beginLayer(PdfGraphics? currentGraphics) { + if (base._graphicsMap.containsKey(currentGraphics)) { + base._graphics = base._graphicsMap[currentGraphics]; + } else { + base._graphics = currentGraphics; + } + if (base._graphics != null) { + if (base._name != null && base._name != '') { + base._isEmptyLayer = true; + if (parentLayer.isNotEmpty) { + for (int i = 0; i < parentLayer.length; i++) { + PdfGraphicsHelper.getHelper(base._graphics!).streamWriter!.write( + '/OC /${PdfLayerHelper.getHelper(parentLayer[i]).layerId!} BDC\n', + ); + } + } + if (base.name != null && base.name != '') { + PdfGraphicsHelper.getHelper( + base._graphics!, + ).streamWriter!.write('/OC /${layerId!} BDC\n'); + isEndState = true; + } else { + _content!.write('/OC /${layerId!} BDC\n'); + } + } + } + } + + /// internal method + void parsingLayerPage() { + if (document != null && + PdfDocumentHelper.getHelper(document!).isLoadedDocument) { + for (int i = 0; i < document!.pages.count; i++) { + final PdfDictionary pageDictionary = + PdfPageHelper.getHelper(document!.pages[i]).dictionary!; + final PdfPage page = document!.pages[i]; + if (pageDictionary.containsKey(PdfDictionaryProperties.resources)) { + final PdfDictionary? resources = + PdfCrossTable.dereference( + pageDictionary[PdfDictionaryProperties.resources], + ) + as PdfDictionary?; + if (resources != null && + (resources.containsKey(PdfDictionaryProperties.properties)) || + (resources!.containsKey(PdfDictionaryProperties.xObject))) { + final PdfDictionary? properties = + PdfCrossTable.dereference( + resources[PdfDictionaryProperties.properties], + ) + as PdfDictionary?; + final PdfDictionary? xObject = + PdfCrossTable.dereference( + resources[PdfDictionaryProperties.xObject], + ) + as PdfDictionary?; + if (properties != null) { + properties.items!.forEach((PdfName? key, IPdfPrimitive? value) { + if (value is PdfReferenceHolder) { + final PdfDictionary? dictionary = + value.object as PdfDictionary?; + if (base._isPresent != null && base._isPresent!) { + return; + } + _parsingDictionary(dictionary, value, page, key); + } + }); + if (properties.items!.isEmpty) { + pageParsed = true; + } + } + if (xObject != null) { + xObject.items!.forEach((PdfName? key, IPdfPrimitive? value) { + PdfReferenceHolder reference = value! as PdfReferenceHolder; + PdfDictionary dictionary = reference.object! as PdfDictionary; + if (dictionary.containsKey('OC')) { + final PdfName? layerID = key; + reference = dictionary['OC']! as PdfReferenceHolder; + dictionary = + PdfCrossTable.dereference(dictionary['OC'])! + as PdfDictionary; + final bool isPresent = + _parsingDictionary(dictionary, reference, page, layerID)!; + if (isPresent) { + PdfLayerHelper.getHelper( + layer!, + ).xobject.add(layerID!.name!); + } + } + }); + if (xObject.items!.isEmpty) { + pageParsed = true; + } + } + } + } + } + } + } + + bool? _parsingDictionary( + PdfDictionary? dictionary, + PdfReferenceHolder? reference, + PdfPage? page, + PdfName? layerID, + ) { + base._isPresent = false; + if (!dictionary!.containsKey(PdfDictionaryProperties.name) && + dictionary.containsKey(PdfDictionaryProperties.ocg)) { + if (dictionary.containsKey(PdfDictionaryProperties.ocg)) { + final PdfArray? pdfArray = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ocg]) + as PdfArray?; + if (pdfArray == null) { + reference = + dictionary[PdfDictionaryProperties.ocg] as PdfReferenceHolder?; + dictionary = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.ocg]) + as PdfDictionary?; + if (dictionary != null && + dictionary.containsKey(PdfDictionaryProperties.name)) { + base._isPresent = _setLayerPage(reference, page, layerID); + } + } else { + for (int a = 0; a < pdfArray.count; a++) { + if (pdfArray[a] is PdfReferenceHolder) { + reference = pdfArray[a]! as PdfReferenceHolder; + dictionary = reference.object as PdfDictionary?; + base._isPresent = _setLayerPage(reference, page, layerID); + } + } + } + } + } else if (dictionary.containsKey(PdfDictionaryProperties.name)) { + base._isPresent = _setLayerPage(reference, page, layerID); + } + return base._isPresent; + } + + bool _setLayerPage( + PdfReferenceHolder? reference, + PdfPage? page, + PdfName? layerID, + ) { + bool isPresent = false; + if (PdfLayerHelper.getHelper(layer!).referenceHolder != null) { + if (identical( + PdfLayerHelper.getHelper(layer!).referenceHolder, + reference, + ) || + identical( + PdfLayerHelper.getHelper(layer!).referenceHolder!.object, + reference!.object, + ) || + PdfLayerHelper.getHelper(layer!).referenceHolder?.reference?.objNum == + reference.reference?.objNum) { + PdfLayerHelper.getHelper(layer!).pageParsed = true; + isPresent = true; + PdfLayerHelper.getHelper(layer!).layerId = layerID!.name; + PdfLayerHelper.getHelper(layer!).page = page; + if (!PdfLayerHelper.getHelper(layer!).pages.contains(page)) { + PdfLayerHelper.getHelper(layer!).pages.add(page!); + } + } + } + return isPresent; + } + + void _setVisibility(bool? value) { + PdfDictionary? oCProperties; + if (PdfDocumentHelper.getHelper( + document!, + ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { + oCProperties = + PdfCrossTable.dereference( + PdfDocumentHelper.getHelper( + document!, + ).catalog[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + } + if (oCProperties != null) { + PdfDictionary? defaultView; + if (oCProperties.containsKey(PdfDictionaryProperties.defaultView)) { + final value = oCProperties[PdfDictionaryProperties.defaultView]; + if (value is PdfReferenceHolder) { + defaultView = PdfCrossTable.dereference(value) as PdfDictionary?; + } else if (value is PdfDictionary) { + defaultView = value; + } + } + if (defaultView != null) { + PdfArray? ocgON = + defaultView[PdfDictionaryProperties.ocgOn] as PdfArray?; + PdfArray? ocgOFF = + defaultView[PdfDictionaryProperties.ocgOff] as PdfArray?; + if (referenceHolder != null) { + if (value == false) { + if (ocgON != null) { + _removeContent(ocgON, referenceHolder); + } + if (ocgOFF == null) { + ocgOFF = PdfArray(); + defaultView.items![PdfName(PdfDictionaryProperties.ocgOff)] = + ocgOFF; + } + ocgOFF.insert(ocgOFF.count, referenceHolder!); + } else if (value ?? true) { + if (ocgOFF != null) { + _removeContent(ocgOFF, referenceHolder); + } + if (ocgON == null) { + ocgON = PdfArray(); + defaultView.items![PdfName(PdfDictionaryProperties.ocgOn)] = + ocgON; + } + ocgON.insert(ocgON.count, referenceHolder!); + } + } + } + } + } + + void _removeContent(PdfArray content, PdfReferenceHolder? referenceHolder) { + bool flag = false; + for (int i = 0; i < content.count; i++) { + final IPdfPrimitive? primitive = content.elements[i]; + if (primitive != null && primitive is PdfReferenceHolder) { + final PdfReferenceHolder holder = primitive; + if (holder.reference != null && referenceHolder!.reference != null) { + if (holder.reference!.objNum == referenceHolder.reference!.objNum) { + content.elements.removeAt(i); + flag = true; + i--; + } + } + } + } + if (flag) { + content.changed = true; + } + } + + /// internal property + IPdfPrimitive? get element => _content; + //ignore: unused_element + set element(IPdfPrimitive? value) { + _content = value as PdfStream?; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart index 50d1a3e11..0c9e0a44c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_layer_collection.dart @@ -1,1050 +1,1057 @@ -import '../../interfaces/pdf_interface.dart'; -import '../exporting/pdf_text_extractor/parser/content_parser.dart'; -import '../general/pdf_collection.dart'; -import '../graphics/pdf_resources.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_layer.dart'; -import 'pdf_page.dart'; - -/// The class provides methods and properties to handle the collections of [PdfLayer] -class PdfLayerCollection extends PdfObjectCollection { - // Contructor - PdfLayerCollection._(PdfDocument document) { - _helper = PdfLayerCollectionHelper(this, document); - } - - PdfLayerCollection._withLayer(PdfDocument? document, PdfLayer? layer) { - _helper = PdfLayerCollectionHelper._(this, document, layer); - } - - // Fields - late PdfLayerCollectionHelper _helper; - - //Properties - /// Gets [PdfLayer] by its index from [PdfLayerCollection]. - PdfLayer operator [](int index) { - if (index < 0 || index >= count) { - throw RangeError('index'); - } - return _helper.list[index] as PdfLayer; - } - - // Implementation - /// Creates a new [PdfLayer] with name and adds it to the end of the collection. - PdfLayer add({String? name, bool? visible}) { - return _helper.add(name, visible); - } - - /// Removes layer from the collection by using layer or layer name and may also remove graphical content, if isRemoveGraphicalContent is true. - void remove({ - PdfLayer? layer, - String? name, - bool isRemoveGraphicalContent = false, - }) { - _helper.remove(layer, name, isRemoveGraphicalContent); - } - - /// Removes layer by its index from collections and may also remove graphical content if isRemoveGraphicalContent is true. - void removeAt(int index, [bool isRemoveGraphicalContent = false]) { - _helper.removeAt(index, isRemoveGraphicalContent); - } - - /// Clears layers from the [PdfLayerCollection]. - void clear() { - _helper.clear(); - } -} - -/// [PdfLayerCollection] helper -class PdfLayerCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfLayerCollectionHelper(this.layerCollection, PdfDocument document) - : super(layerCollection) { - _document = document; - _sublayer = false; - if (PdfDocumentHelper.getHelper(document).isLoadedDocument) { - _getDocumentLayer(document); - } - } - - /// internal constructor - PdfLayerCollectionHelper._( - this.layerCollection, - PdfDocument? document, - PdfLayer? layer, - ) : super(layerCollection) { - _document = document; - _parent = layer; - _sublayer = true; - } - - /// internal field - late PdfLayerCollection layerCollection; - - PdfDocument? _document; - bool? _sublayer; - PdfLayer? _parent; - final PdfDictionary _optionalContent = PdfDictionary(); - final Map _layerDictionary = - {}; - int _bdcCount = 0; - - /// internal method - static PdfLayerCollection load(PdfDocument document) { - return PdfLayerCollection._(document); - } - - /// internal method - static PdfLayerCollection withLayer(PdfDocument? document, PdfLayer? layer) { - return PdfLayerCollection._withLayer(document, layer); - } - - /// Creates a new [PdfLayer] with name and adds it to the end of the collection. - PdfLayer add(String? name, bool? visible) { - final PdfLayer layer = PdfLayerHelper.internal(); - if (name != null) { - layer.name = name; - } - PdfLayerHelper.getHelper(layer).document = _document; - if (visible != null) { - layer.visible = visible; - } - PdfLayerHelper.getHelper(layer).layerId = - 'OCG_${PdfResources.globallyUniqueIdentifier}'; - PdfLayerHelper.getHelper(layer).layer = layer; - _add(layer); - return layer; - } - - /// Removes layer from the collection by using layer or layer name and may also remove graphical content, if isRemoveGraphicalContent is true. - void remove(PdfLayer? layer, String? name, bool isRemoveGraphicalContent) { - if (layer != null) { - _removeLayer(layer, isRemoveGraphicalContent); - list.remove(layer); - } else if (name != null) { - bool isFind = false; - for (int i = 0; i < list.length; i++) { - final PdfLayer layer = list[i] as PdfLayer; - if (layer.name == name) { - isFind = true; - _removeLayer(layer, isRemoveGraphicalContent); - list.remove(layer); - i = i - 1; - } - } - if (!isFind) { - ArgumentError.value('Given layerName is not found'); - } - } else { - ArgumentError.value('layer or layerName must be required'); - } - } - - /// Removes layer by its index from collections and may also remove graphical content if isRemoveGraphicalContent is true. - void removeAt(int index, bool isRemoveGraphicalContent) { - if (index < 0 || index > list.length - 1) { - ArgumentError.value( - '$index Value can not be less 0 and greater List.Count - 1', - ); - } - final PdfLayer layer = layerCollection[index]; - list.removeAt(index); - _removeLayer(layer, isRemoveGraphicalContent); - } - - /// Clears layers from the [PdfLayerCollection]. - void clear() { - for (int i = 0; i < list.length; i++) { - final PdfLayer layer = layerCollection[i]; - _removeLayer(layer, true); - } - list.clear(); - } - - int _add(PdfLayer layer) { - list.add(layer); - final int index = layerCollection.count - 1; - if (_document is PdfDocument) { - _createLayer(layer); - } - PdfLayerHelper.getHelper(layer).layer = layer; - return index; - } - - void _createLayer(PdfLayer layer) { - final PdfDictionary ocProperties = PdfDictionary(); - ocProperties[PdfDictionaryProperties - .ocg] = _createOptionalContentDictionary(layer); - ocProperties[PdfDictionaryProperties - .defaultView] = _createOptionalContentViews(layer); - PdfDocumentHelper.getHelper(_document!).catalog[PdfDictionaryProperties - .ocProperties] = - ocProperties; - PdfDocumentHelper.getHelper( - _document!, - ).catalog.setProperty(PdfDictionaryProperties.ocProperties, ocProperties); - } - - IPdfPrimitive? _createOptionalContentDictionary(PdfLayer layer) { - final PdfDictionary dictionary = PdfDictionary(); - dictionary[PdfDictionaryProperties.name] = PdfString(layer.name!); - dictionary[PdfDictionaryProperties.type] = PdfName('OCG'); - dictionary[PdfDictionaryProperties.layerID] = PdfName( - PdfLayerHelper.getHelper(layer).layerId, - ); - dictionary[PdfDictionaryProperties.visible] = PdfBoolean(layer.visible); - - PdfLayerHelper.getHelper(layer).usage = _setPrintOption(layer); - dictionary[PdfDictionaryProperties.usage] = PdfReferenceHolder( - PdfLayerHelper.getHelper(layer).usage, - ); - PdfDocumentHelper.getHelper( - _document!, - ).printLayer!.add(PdfReferenceHolder(dictionary)); - - final PdfReferenceHolder reference = PdfReferenceHolder(dictionary); - PdfDocumentHelper.getHelper(_document!).pdfPrimitive!.add(reference); - PdfLayerHelper.getHelper(layer).referenceHolder = reference; - PdfLayerHelper.getHelper(layer).dictionary = dictionary; - - // Order of the layers - final PdfDictionary? ocProperties = - PdfCrossTable.dereference( - PdfDocumentHelper.getHelper( - _document!, - ).catalog[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - _createSublayer(ocProperties, reference, layer); - if (layer.visible) { - PdfDocumentHelper.getHelper(_document!).on!.add(reference); - } else { - PdfDocumentHelper.getHelper(_document!).off!.add(reference); - } - return PdfDocumentHelper.getHelper(_document!).pdfPrimitive; - } - - PdfDictionary _setPrintOption(PdfLayer layer) { - final PdfDictionary usage = PdfDictionary(); - PdfLayerHelper.getHelper(layer).printOption = PdfDictionary(); - PdfLayerHelper.getHelper(layer).printOption![PdfDictionaryProperties - .subtype] = PdfName('Print'); - usage[PdfDictionaryProperties.print] = PdfReferenceHolder( - PdfLayerHelper.getHelper(layer).printOption, - ); - return usage; - } - - void _createSublayer( - PdfDictionary? ocProperties, - PdfReferenceHolder reference, - PdfLayer layer, - ) { - if (_sublayer == false) { - if (ocProperties != null) { - PdfArray? order; - final PdfDictionary? defaultview = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultview != null) { - order = - PdfCrossTable.dereference( - defaultview[PdfDictionaryProperties.ocgOrder], - ) - as PdfArray?; - } - if (PdfDocumentHelper.getHelper(_document!).order != null && - order != null) { - PdfDocumentHelper.getHelper(_document!).order = order; - } - PdfDocumentHelper.getHelper(_document!).order!.add(reference); - } else { - PdfDocumentHelper.getHelper(_document!).order!.add(reference); - } - } else { - PdfLayerHelper.getHelper(layer).parent = _parent; - if (ocProperties != null) { - PdfArray? order; - final PdfDictionary? defaultview = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultview != null) { - order = - PdfCrossTable.dereference( - defaultview[PdfDictionaryProperties.ocgOrder], - ) - as PdfArray?; - } - if (PdfDocumentHelper.getHelper(_document!).order != null && - order != null) { - PdfDocumentHelper.getHelper(_document!).order = order; - } - } - if (PdfLayerHelper.getHelper(_parent!).child.isEmpty) { - PdfLayerHelper.getHelper(_parent!).sublayer.add(reference); - } else if (PdfDocumentHelper.getHelper( - _document!, - ).order!.contains(PdfLayerHelper.getHelper(_parent!).referenceHolder!)) { - final int position = PdfDocumentHelper.getHelper( - _document!, - ).order!.indexOf(PdfLayerHelper.getHelper(_parent!).referenceHolder!); - PdfDocumentHelper.getHelper(_document!).order!.removeAt(position + 1); - PdfLayerHelper.getHelper(_parent!).sublayer.add(reference); - } else { - PdfLayerHelper.getHelper(_parent!).sublayer.add(reference); - } - if (PdfDocumentHelper.getHelper( - _document!, - ).order!.contains(PdfLayerHelper.getHelper(_parent!).referenceHolder!)) { - final int position = PdfDocumentHelper.getHelper( - _document!, - ).order!.indexOf(PdfLayerHelper.getHelper(_parent!).referenceHolder!); - PdfDocumentHelper.getHelper(_document!).order!.insert( - position + 1, - PdfLayerHelper.getHelper(_parent!).sublayer, - ); - } else { - if (PdfLayerHelper.getHelper(_parent!).parent != null) { - if (PdfLayerHelper.getHelper( - PdfLayerHelper.getHelper(_parent!).parent!, - ).sublayer.contains( - PdfLayerHelper.getHelper(_parent!).referenceHolder!, - )) { - int position = PdfLayerHelper.getHelper( - PdfLayerHelper.getHelper(_parent!).parent!, - ).sublayer.indexOf( - PdfLayerHelper.getHelper(_parent!).referenceHolder!, - ); - if (PdfLayerHelper.getHelper(_parent!).sublayer.count == 1) { - PdfLayerHelper.getHelper( - PdfLayerHelper.getHelper(_parent!).parent!, - ).sublayer.insert( - position + 1, - PdfLayerHelper.getHelper(_parent!).sublayer, - ); - } - if (PdfDocumentHelper.getHelper(_document!).order!.contains( - PdfLayerHelper.getHelper( - PdfLayerHelper.getHelper(_parent!).parent!, - ).referenceHolder!, - )) { - position = PdfDocumentHelper.getHelper(_document!).order!.indexOf( - PdfLayerHelper.getHelper( - PdfLayerHelper.getHelper(_parent!).parent!, - ).referenceHolder!, - ); - PdfDocumentHelper.getHelper( - _document!, - ).order!.removeAt(position + 1); - PdfDocumentHelper.getHelper(_document!).order!.insert( - position + 1, - PdfLayerHelper.getHelper( - PdfLayerHelper.getHelper(_parent!).parent!, - ).sublayer, - ); - } - } - } - } - - PdfLayerHelper.getHelper(_parent!).child.add(layer); - - if (PdfLayerHelper.getHelper(_parent!).parentLayer.isEmpty) { - PdfLayerHelper.getHelper(layer).parentLayer.add(_parent!); - } else { - for ( - int i = 0; - i < PdfLayerHelper.getHelper(_parent!).parentLayer.length; - i++ - ) { - if (!PdfLayerHelper.getHelper(layer).parentLayer.contains( - PdfLayerHelper.getHelper(_parent!).parentLayer[i], - )) { - PdfLayerHelper.getHelper(layer).parentLayer.add( - PdfLayerHelper.getHelper(_parent!).parentLayer[i], - ); - } - } - PdfLayerHelper.getHelper(layer).parentLayer.add(_parent!); - } - } - } - - IPdfPrimitive _createOptionalContentViews(PdfLayer layer) { - final PdfArray usageApplication = PdfArray(); - _optionalContent[PdfDictionaryProperties.name] = PdfString('Layers'); - _optionalContent[PdfDictionaryProperties.ocgOrder] = - PdfDocumentHelper.getHelper(_document!).order; - _optionalContent[PdfDictionaryProperties.ocgOn] = - PdfDocumentHelper.getHelper(_document!).on; - _optionalContent[PdfDictionaryProperties.ocgOff] = - PdfDocumentHelper.getHelper(_document!).off; - final PdfArray category = PdfArray(); - category.add(PdfName('Print')); - final PdfDictionary applicationDictionary = PdfDictionary(); - applicationDictionary[PdfDictionaryProperties.category] = category; - applicationDictionary[PdfDictionaryProperties.ocg] = - PdfDocumentHelper.getHelper(_document!).printLayer; - applicationDictionary[PdfDictionaryProperties.event] = PdfName('Print'); - usageApplication.add(PdfReferenceHolder(applicationDictionary)); - _optionalContent[PdfDictionaryProperties.usageApplication] = - usageApplication; - return _optionalContent; - } - - void _getDocumentLayer(PdfDocument document) { - PdfDictionary? layerDictionary; - PdfReferenceHolder layerReference; - if (PdfDocumentHelper.getHelper( - _document!, - ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { - final PdfDictionary? ocProperties = - PdfCrossTable.dereference( - PdfDocumentHelper.getHelper( - _document!, - ).catalog[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - if (ocProperties != null) { - if (ocProperties.containsKey(PdfDictionaryProperties.ocg)) { - final PdfArray ocGroup = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.ocg], - )! - as PdfArray; - for (int i = 0; i < ocGroup.count; i++) { - if (ocGroup[i] is PdfReferenceHolder) { - layerReference = ocGroup[i]! as PdfReferenceHolder; - layerDictionary = layerReference.object as PdfDictionary?; - final PdfLayer layer = PdfLayerHelper.internal(); - if (layerDictionary != null && - layerDictionary.containsKey(PdfDictionaryProperties.name)) { - final PdfString layerName = - PdfCrossTable.dereference( - layerDictionary[PdfDictionaryProperties.name], - )! - as PdfString; - layer.name = layerName.value; - PdfLayerHelper.getHelper(layer).dictionary = layerDictionary; - PdfLayerHelper.getHelper(layer).referenceHolder = - layerReference; - final IPdfPrimitive? layerId = PdfCrossTable.dereference( - layerDictionary[PdfDictionaryProperties.layerID], - ); - if (layerId != null) { - PdfLayerHelper.getHelper(layer).layerId = layerId.toString(); - } - final PdfDictionary? usage = - PdfCrossTable.dereference( - layerDictionary[PdfDictionaryProperties.usage], - ) - as PdfDictionary?; - - if (usage != null) { - final PdfDictionary? printOption = - PdfCrossTable.dereference( - usage[PdfDictionaryProperties.print], - ) - as PdfDictionary?; - - if (printOption != null) { - PdfLayerHelper.getHelper(layer).printOption = printOption; - } - } - } - PdfLayerHelper.getHelper(layer).document = document; - PdfLayerHelper.getHelper(layer).layer = layer; - // layer.parsingLayerPage(); - _layerDictionary[layerReference] = layer; - list.add(layer); - } - } - } - _checkLayerLock(ocProperties); - _checkLayerVisible(ocProperties); - _checkParentLayer(ocProperties); - _createLayerHierarchical(ocProperties); - } - } - } - - void _checkLayerVisible(PdfDictionary ocProperties) { - PdfArray? visible; - if (PdfDocumentHelper.getHelper( - _document!, - ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { - final PdfDictionary? defaultView = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - - if (defaultView != null && - defaultView.containsKey(PdfDictionaryProperties.ocgOff)) { - visible = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOff], - ) - as PdfArray?; - } - if (visible != null) { - for (int i = 0; i < visible.count; i++) { - final PdfLayer? pdfLayer = - _layerDictionary[visible[i]! as PdfReferenceHolder]; - if (pdfLayer != null) { - pdfLayer.visible = false; - if (PdfLayerHelper.getHelper(pdfLayer).dictionary != null && - PdfLayerHelper.getHelper( - pdfLayer, - ).dictionary!.containsKey(PdfDictionaryProperties.visible)) { - PdfLayerHelper.getHelper(pdfLayer).dictionary!.setProperty( - PdfDictionaryProperties.visible, - PdfBoolean(false), - ); - } - } - } - } - } - } - - void _checkParentLayer(PdfDictionary ocProperties) { - final PdfDictionary? defaultView = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultView != null) { - final PdfArray? array = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOrder], - ) - as PdfArray?; - if (array != null) { - _parsingLayerOrder(array, _layerDictionary); - } - } - } - - void _checkLayerLock(PdfDictionary ocProperties) { - PdfArray? locked; - final PdfDictionary? defaultView = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultView != null && - defaultView.containsKey(PdfDictionaryProperties.ocgLock)) { - locked = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgLock], - ) - as PdfArray?; - } - if (locked != null) { - for (int i = 0; i < locked.count; i++) { - final PdfLayer? pdfLayer = - _layerDictionary[locked[i]! as PdfReferenceHolder]; - if (pdfLayer != null) { - continue; - } - } - } - } - - void _createLayerHierarchical(PdfDictionary ocProperties) { - final PdfDictionary? defaultView = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultView != null && - defaultView.containsKey(PdfDictionaryProperties.ocgOrder)) { - if (_layerDictionary.isNotEmpty) { - list.clear(); - _layerDictionary.forEach((PdfReferenceHolder key, PdfLayer value) { - final PdfLayer pdfLayer = value; - if (PdfLayerHelper.getHelper(pdfLayer).parent == null && - !list.contains(pdfLayer)) { - list.add(pdfLayer); - } else if (PdfLayerHelper.getHelper(pdfLayer).child.isNotEmpty) { - _addChildlayer(PdfLayerHelper.getHelper(pdfLayer).parent!); - } else if (PdfLayerHelper.getHelper(pdfLayer).parent != null && - PdfLayerHelper.getHelper(pdfLayer).child.isEmpty && - !PdfLayerHelper.getHelper( - pdfLayer, - ).parent!.layers._helper.list.contains(pdfLayer)) { - PdfLayerHelper.getHelper( - pdfLayer, - ).parent!.layers._helper._addNestedLayer(pdfLayer); - } - }); - } - } - } - - void _addChildlayer(PdfLayer pdfLayer) { - for (int i = 0; i < PdfLayerHelper.getHelper(pdfLayer).child.length; i++) { - final PdfLayer child = PdfLayerHelper.getHelper(pdfLayer).child[i]; - if (!pdfLayer.layers._helper.list.contains(child)) { - pdfLayer.layers._helper._addNestedLayer(child); - } - } - } - - int _addNestedLayer(PdfLayer layer) { - list.add(layer); - PdfLayerHelper.getHelper(layer).layer = layer; - return list.length - 1; - } - - void _parsingLayerOrder( - PdfArray array, - Map layerDictionary, [ - PdfLayer? parent, - ]) { - PdfReferenceHolder reference; - PdfLayer? layer; - for (int i = 0; i < array.count; i++) { - if (array[i] is PdfReferenceHolder) { - reference = array[i]! as PdfReferenceHolder; - layerDictionary.forEach((PdfReferenceHolder key, PdfLayer value) { - if (identical(key.object, reference.object) || - identical(key.reference, reference.reference)) { - layer = value; - } - }); - if (layer != null) { - if (parent != null) { - PdfLayerHelper.getHelper(parent).child.add(layer!); - if (PdfLayerHelper.getHelper(parent).parentLayer.isEmpty) { - PdfLayerHelper.getHelper(parent).parentLayer.add(parent); - PdfLayerHelper.getHelper(layer!).parent = parent; - } else { - for ( - int j = 0; - j < PdfLayerHelper.getHelper(parent).parentLayer.length; - j++ - ) { - if (!PdfLayerHelper.getHelper(layer!).parentLayer.contains( - PdfLayerHelper.getHelper(parent).parentLayer[j], - )) { - PdfLayerHelper.getHelper(layer!).parentLayer.add( - PdfLayerHelper.getHelper(parent).parentLayer[j], - ); - } - } - PdfLayerHelper.getHelper(layer!).parentLayer.add(parent); - PdfLayerHelper.getHelper(layer!).parent = parent; - } - } - if (array.count > i + 1 && - PdfCrossTable.dereference(array[i + 1]) is PdfArray) { - i++; - final PdfArray pdfArray = - PdfCrossTable.dereference(array[i])! as PdfArray; - PdfLayerHelper.getHelper(layer!).sublayer.add(pdfArray); - _parsingLayerOrder(pdfArray, layerDictionary, layer); - } - } - } else if (PdfCrossTable.dereference(array[i]) is PdfArray) { - final PdfArray? subarray = - PdfCrossTable.dereference(array[i]) as PdfArray?; - if (subarray == null) { - return; - } - if (subarray[0] is PdfString) { - parent = null; - _parsingLayerOrder(subarray, layerDictionary, parent); - } else { - parent = null; - _parsingLayerOrder( - PdfCrossTable.dereference(array[i])! as PdfArray, - layerDictionary, - parent, - ); - } - } - } - } - - void _removeLayer(PdfLayer layer, bool isRemoveContent) { - PdfDictionary? dictionary; - if (_document != null) { - dictionary = PdfDocumentHelper.getHelper(_document!).catalog; - if (dictionary.containsKey(PdfDictionaryProperties.ocProperties)) { - final PdfDictionary? ocPropertie = - PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - if (ocPropertie != null) { - final PdfArray? ocGroup = - PdfCrossTable.dereference( - ocPropertie[PdfDictionaryProperties.ocg], - ) - as PdfArray?; - if (ocGroup != null) { - _removeOCProperties( - ocGroup, - PdfLayerHelper.getHelper(layer).referenceHolder, - ); - } - if (ocPropertie.containsKey(PdfDictionaryProperties.defaultView)) { - final PdfDictionary? defaultView = - PdfCrossTable.dereference( - ocPropertie[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultView != null) { - PdfArray? on, off; - if (defaultView.containsKey(PdfDictionaryProperties.ocgOrder)) { - final PdfArray? order = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOrder], - ) - as PdfArray?; - if (order != null) { - _removeOrder(layer, order, []); - // _removeOCProperties(order, layer.referenceHolder); - } - } - if (defaultView.containsKey(PdfDictionaryProperties.ocgLock)) { - final PdfArray? locked = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgLock], - ) - as PdfArray?; - if (locked != null) { - _removeOCProperties( - locked, - PdfLayerHelper.getHelper(layer).referenceHolder, - ); - } - } - if (defaultView.containsKey(PdfDictionaryProperties.ocgOff)) { - off = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOff], - ) - as PdfArray?; - } - if (defaultView.containsKey(PdfDictionaryProperties.ocgOn)) { - on = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOn], - ) - as PdfArray?; - } else if (defaultView.containsKey('ON')) { - on = PdfCrossTable.dereference(defaultView['ON']) as PdfArray?; - } - if (defaultView.containsKey( - PdfDictionaryProperties.usageApplication, - )) { - final PdfArray? usage = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.usageApplication], - ) - as PdfArray?; - if (usage != null) { - _removeOCProperties( - usage, - PdfLayerHelper.getHelper(layer).referenceHolder, - ); - } - } - _removeVisible(layer, on, off); - } - } - } - } - if (isRemoveContent) { - _removeLayerContent(layer); - } - } - } - - void _removeVisible(PdfLayer layer, PdfArray? on, PdfArray? off) { - if (layer.visible) { - if (on != null) { - _removeOCProperties( - on, - PdfLayerHelper.getHelper(layer).referenceHolder, - ); - } - } else { - if (off != null) { - _removeOCProperties( - off, - PdfLayerHelper.getHelper(layer).referenceHolder, - ); - } - } - } - - void _removeOrder(PdfLayer layer, PdfArray order, List arrayList) { - bool isRemoveOrder = false; - for (int i = 0; i < order.count; i++) { - if (order[i] is PdfReferenceHolder) { - final PdfReferenceHolder holder = order[i]! as PdfReferenceHolder; - if (identical( - holder.object, - PdfLayerHelper.getHelper(layer).referenceHolder!.object, - ) || - identical( - holder.reference, - PdfLayerHelper.getHelper(layer).referenceHolder!.reference, - )) { - if (i != order.count - 1) { - if (order[i + 1] is PdfArray) { - order.removeAt(i); - order.removeAt(i); - isRemoveOrder = true; - break; - } else { - order.removeAt(i); - isRemoveOrder = true; - break; - } - } else { - order.removeAt(i); - isRemoveOrder = true; - break; - } - } - } else if (order[i] is PdfArray) { - arrayList.add(order[i]! as PdfArray); - } - } - if (!isRemoveOrder) { - for (int i = 0; i < arrayList.length; i++) { - order = arrayList[i]; - arrayList.removeAt(i); - i = i - 1; - _removeOrder(layer, order, arrayList); - } - } - } - - void _removeOCProperties( - PdfArray content, - PdfReferenceHolder? referenceHolder, - ) { - bool isChange = false; - for (int i = 0; i < content.count; i++) { - final IPdfPrimitive? primitive = content.elements[i]; - if (primitive != null && primitive is PdfReferenceHolder) { - final PdfReferenceHolder holder = primitive; - if (holder.reference != null && referenceHolder!.reference != null) { - if (holder.reference!.objNum == referenceHolder.reference!.objNum) { - content.elements.removeAt(i); - isChange = true; - i--; - } - } else if (identical(holder, referenceHolder)) { - content.elements.removeAt(i); - isChange = true; - i--; - } else if (identical(holder.object, referenceHolder!.object)) { - content.elements.removeAt(i); - isChange = true; - i--; - } - } else if (primitive != null && primitive is PdfArray) { - _removeOCProperties(primitive, referenceHolder); - } - } - if (isChange) { - content.changed = true; - } - } - - void _removeLayerContent(PdfLayer layer) { - PdfDictionary? properties; - bool isSkip = false; - PdfDictionary? xObject; - if (!PdfLayerHelper.getHelper(layer).pageParsed) { - PdfLayerHelper.getHelper(layer).parsingLayerPage(); - _removeLayerContent(layer); - return; - } - if (PdfLayerHelper.getHelper(layer).pages.isNotEmpty) { - for (int i = 0; i < PdfLayerHelper.getHelper(layer).pages.length; i++) { - final PdfDictionary? resource = - PdfCrossTable.dereference( - PdfPageHelper.getHelper( - PdfLayerHelper.getHelper(layer).pages[i], - ).dictionary![PdfDictionaryProperties.resources], - ) - as PdfDictionary?; - if (resource != null) { - properties = - PdfCrossTable.dereference( - resource[PdfDictionaryProperties.properties], - ) - as PdfDictionary?; - xObject = - PdfCrossTable.dereference( - resource[PdfDictionaryProperties.xObject], - ) - as PdfDictionary?; - if (properties != null) { - if (properties.containsKey( - PdfLayerHelper.getHelper(layer).layerId, - )) { - properties.remove(PdfLayerHelper.getHelper(layer).layerId); - } - } - if (xObject != null && - PdfLayerHelper.getHelper(layer).xobject.isNotEmpty) { - for (final PdfName? key in xObject.items!.keys) { - if (PdfLayerHelper.getHelper(layer).xobject.contains(key!.name)) { - xObject.remove(key); - } - if (xObject.items!.isEmpty) { - break; - } - } - } - final PdfArray content = - PdfPageHelper.getHelper( - PdfLayerHelper.getHelper(layer).pages[i], - ).contents; - for (int m = 0; m < content.count; m++) { - List? stream = []; - final PdfStream data = PdfStream(); - final PdfStream pageContent = - PdfCrossTable.dereference(content[m])! as PdfStream; - if (PdfPageHelper.getHelper( - PdfLayerHelper.getHelper(layer).pages[i], - ).isLoadedPage) { - pageContent.decompress(); - } - stream = pageContent.dataStream; - final ContentParser parser = ContentParser(stream); - final PdfRecordCollection recordCollection = parser.readContent()!; - for (int j = 0; j < recordCollection.recordCollection.length; j++) { - final String? mOperator = - recordCollection.recordCollection[j].operatorName; - if (mOperator == 'BMC' || - mOperator == 'EMC' || - mOperator == 'BDC') { - _processBeginMarkContent( - layer, - mOperator, - recordCollection.recordCollection[j].operands, - data, - ); - isSkip = true; - } - if (mOperator == PdfOperators.paintXObject) { - if (PdfLayerHelper.getHelper(layer).xobject.contains( - recordCollection.recordCollection[j].operands![0], - )) { - isSkip = true; - } - } - if (mOperator == 'RG' || - mOperator == PdfOperators.saveState || - mOperator == PdfOperators.restoreState || - mOperator == PdfOperators.setLineWidth || - mOperator == PdfOperators.setLineCapStyle || - mOperator == PdfOperators.setLineJoinStyle || - mOperator == PdfOperators.setMiterLimit || - mOperator == PdfOperators.setDashPattern || - mOperator == PdfOperators.setGraphicsState || - mOperator == PdfOperators.currentMatrix || - mOperator == PdfOperators.selectColorSpaceForNonStroking || - mOperator == PdfOperators.selectColorSpaceForStroking) { - if (!isSkip) { - _streamWrite( - recordCollection.recordCollection[j].operands, - mOperator, - false, - data, - ); - } - } else if (!isSkip) { - _streamWrite( - recordCollection.recordCollection[j].operands, - mOperator, - true, - data, - ); - } - isSkip = false; - } - if (data.dataStream!.isNotEmpty) { - pageContent.clear(); - pageContent.dataStream!.clear(); - pageContent.write(data.dataStream); - } else { - pageContent.clear(); - } - } - } - } - } - } - - void _processBeginMarkContent( - PdfLayer parser, - String? mOperator, - List? operands, - PdfStream data, - ) { - if ('BDC' == mOperator) { - String? operand; - if (operands!.length > 1 && ((operands[0]) == '/OC')) { - operand = operands[1].substring(1); - } - if (_bdcCount > 0) { - _bdcCount++; - return; - } - if (operand != null && - (operand == PdfLayerHelper.getHelper(parser).layerId)) { - _bdcCount++; - } - } - _streamWrite(operands, mOperator, true, data); - if (('EMC' == mOperator) && _bdcCount > 0) { - _bdcCount--; - } - } - - void _streamWrite( - List? operands, - String? mOperator, - bool skip, - PdfStream data, - ) { - PdfString pdfString; - if (skip && _bdcCount > 0) { - return; - } - if (operands != null) { - for (final String operand in operands) { - pdfString = PdfString(operand); - data.write(pdfString.data); - data.write(PdfOperators.whiteSpace); - } - } - pdfString = PdfString(mOperator!); - data.write(pdfString.data); - data.write(PdfOperators.newLine); - } -} +import '../../interfaces/pdf_interface.dart'; +import '../exporting/pdf_text_extractor/parser/content_parser.dart'; +import '../general/pdf_collection.dart'; +import '../graphics/pdf_resources.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_layer.dart'; +import 'pdf_page.dart'; + +/// The class provides methods and properties to handle the collections of [PdfLayer] +class PdfLayerCollection extends PdfObjectCollection { + // Contructor + PdfLayerCollection._(PdfDocument document) { + _helper = PdfLayerCollectionHelper(this, document); + } + + PdfLayerCollection._withLayer(PdfDocument? document, PdfLayer? layer) { + _helper = PdfLayerCollectionHelper._(this, document, layer); + } + + // Fields + late PdfLayerCollectionHelper _helper; + + //Properties + /// Gets [PdfLayer] by its index from [PdfLayerCollection]. + PdfLayer operator [](int index) { + if (index < 0 || index >= count) { + throw RangeError('index'); + } + return _helper.list[index] as PdfLayer; + } + + // Implementation + /// Creates a new [PdfLayer] with name and adds it to the end of the collection. + PdfLayer add({String? name, bool? visible}) { + return _helper.add(name, visible); + } + + /// Removes layer from the collection by using layer or layer name and may also remove graphical content, if isRemoveGraphicalContent is true. + void remove({ + PdfLayer? layer, + String? name, + bool isRemoveGraphicalContent = false, + }) { + _helper.remove(layer, name, isRemoveGraphicalContent); + } + + /// Removes layer by its index from collections and may also remove graphical content if isRemoveGraphicalContent is true. + void removeAt(int index, [bool isRemoveGraphicalContent = false]) { + _helper.removeAt(index, isRemoveGraphicalContent); + } + + /// Clears layers from the [PdfLayerCollection]. + void clear() { + _helper.clear(); + } +} + +/// [PdfLayerCollection] helper +class PdfLayerCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfLayerCollectionHelper(this.layerCollection, PdfDocument document) + : super(layerCollection) { + _document = document; + _sublayer = false; + if (PdfDocumentHelper.getHelper(document).isLoadedDocument) { + _getDocumentLayer(document); + } + } + + /// internal constructor + PdfLayerCollectionHelper._( + this.layerCollection, + PdfDocument? document, + PdfLayer? layer, + ) : super(layerCollection) { + _document = document; + _parent = layer; + _sublayer = true; + } + + /// internal field + late PdfLayerCollection layerCollection; + + PdfDocument? _document; + bool? _sublayer; + PdfLayer? _parent; + final PdfDictionary _optionalContent = PdfDictionary(); + final Map _layerDictionary = + {}; + int _bdcCount = 0; + + /// internal method + static PdfLayerCollection load(PdfDocument document) { + return PdfLayerCollection._(document); + } + + /// internal method + static PdfLayerCollection withLayer(PdfDocument? document, PdfLayer? layer) { + return PdfLayerCollection._withLayer(document, layer); + } + + /// Creates a new [PdfLayer] with name and adds it to the end of the collection. + PdfLayer add(String? name, bool? visible) { + final PdfLayer layer = PdfLayerHelper.internal(); + if (name != null) { + layer.name = name; + } + PdfLayerHelper.getHelper(layer).document = _document; + if (visible != null) { + layer.visible = visible; + } + PdfLayerHelper.getHelper(layer).layerId = + 'OCG_${PdfResources.globallyUniqueIdentifier}'; + PdfLayerHelper.getHelper(layer).layer = layer; + _add(layer); + return layer; + } + + /// Removes layer from the collection by using layer or layer name and may also remove graphical content, if isRemoveGraphicalContent is true. + void remove(PdfLayer? layer, String? name, bool isRemoveGraphicalContent) { + if (layer != null) { + _removeLayer(layer, isRemoveGraphicalContent); + list.remove(layer); + } else if (name != null) { + bool isFind = false; + for (int i = 0; i < list.length; i++) { + final PdfLayer layer = list[i] as PdfLayer; + if (layer.name == name) { + isFind = true; + _removeLayer(layer, isRemoveGraphicalContent); + list.remove(layer); + i = i - 1; + } + } + if (!isFind) { + ArgumentError.value('Given layerName is not found'); + } + } else { + ArgumentError.value('layer or layerName must be required'); + } + } + + /// Removes layer by its index from collections and may also remove graphical content if isRemoveGraphicalContent is true. + void removeAt(int index, bool isRemoveGraphicalContent) { + if (index < 0 || index > list.length - 1) { + ArgumentError.value( + '$index Value can not be less 0 and greater List.Count - 1', + ); + } + final PdfLayer layer = layerCollection[index]; + list.removeAt(index); + _removeLayer(layer, isRemoveGraphicalContent); + } + + /// Clears layers from the [PdfLayerCollection]. + void clear() { + for (int i = 0; i < list.length; i++) { + final PdfLayer layer = layerCollection[i]; + _removeLayer(layer, true); + } + list.clear(); + } + + int _add(PdfLayer layer) { + list.add(layer); + final int index = layerCollection.count - 1; + if (_document is PdfDocument) { + _createLayer(layer); + } + PdfLayerHelper.getHelper(layer).layer = layer; + return index; + } + + void _createLayer(PdfLayer layer) { + final PdfDictionary ocProperties = PdfDictionary(); + ocProperties[PdfDictionaryProperties + .ocg] = _createOptionalContentDictionary(layer); + ocProperties[PdfDictionaryProperties + .defaultView] = _createOptionalContentViews(layer); + PdfDocumentHelper.getHelper(_document!).catalog[PdfDictionaryProperties + .ocProperties] = + ocProperties; + PdfDocumentHelper.getHelper( + _document!, + ).catalog.setProperty(PdfDictionaryProperties.ocProperties, ocProperties); + } + + IPdfPrimitive? _createOptionalContentDictionary(PdfLayer layer) { + final PdfDictionary dictionary = PdfDictionary(); + dictionary[PdfDictionaryProperties.name] = PdfString(layer.name!); + dictionary[PdfDictionaryProperties.type] = PdfName('OCG'); + dictionary[PdfDictionaryProperties.layerID] = PdfName( + PdfLayerHelper.getHelper(layer).layerId, + ); + dictionary[PdfDictionaryProperties.visible] = PdfBoolean(layer.visible); + + PdfLayerHelper.getHelper(layer).usage = _setPrintOption(layer); + dictionary[PdfDictionaryProperties.usage] = PdfReferenceHolder( + PdfLayerHelper.getHelper(layer).usage, + ); + PdfDocumentHelper.getHelper( + _document!, + ).printLayer!.add(PdfReferenceHolder(dictionary)); + + final PdfReferenceHolder reference = PdfReferenceHolder(dictionary); + PdfDocumentHelper.getHelper(_document!).pdfPrimitive!.add(reference); + PdfLayerHelper.getHelper(layer).referenceHolder = reference; + PdfLayerHelper.getHelper(layer).dictionary = dictionary; + + // Order of the layers + final PdfDictionary? ocProperties = + PdfCrossTable.dereference( + PdfDocumentHelper.getHelper( + _document!, + ).catalog[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + _createSublayer(ocProperties, reference, layer); + if (layer.visible) { + PdfDocumentHelper.getHelper(_document!).on!.add(reference); + } else { + PdfDocumentHelper.getHelper(_document!).off!.add(reference); + } + return PdfDocumentHelper.getHelper(_document!).pdfPrimitive; + } + + PdfDictionary _setPrintOption(PdfLayer layer) { + final PdfDictionary usage = PdfDictionary(); + PdfLayerHelper.getHelper(layer).printOption = PdfDictionary(); + PdfLayerHelper.getHelper(layer).printOption![PdfDictionaryProperties + .subtype] = PdfName('Print'); + usage[PdfDictionaryProperties.print] = PdfReferenceHolder( + PdfLayerHelper.getHelper(layer).printOption, + ); + return usage; + } + + void _createSublayer( + PdfDictionary? ocProperties, + PdfReferenceHolder reference, + PdfLayer layer, + ) { + if (_sublayer == false) { + if (ocProperties != null) { + PdfArray? order; + final PdfDictionary? defaultview = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultview != null) { + order = + PdfCrossTable.dereference( + defaultview[PdfDictionaryProperties.ocgOrder], + ) + as PdfArray?; + } + if (PdfDocumentHelper.getHelper(_document!).order != null && + order != null) { + PdfDocumentHelper.getHelper(_document!).order = order; + } + PdfDocumentHelper.getHelper(_document!).order!.add(reference); + } else { + PdfDocumentHelper.getHelper(_document!).order!.add(reference); + } + } else { + PdfLayerHelper.getHelper(layer).parent = _parent; + if (ocProperties != null) { + PdfArray? order; + final PdfDictionary? defaultview = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultview != null) { + order = + PdfCrossTable.dereference( + defaultview[PdfDictionaryProperties.ocgOrder], + ) + as PdfArray?; + } + if (PdfDocumentHelper.getHelper(_document!).order != null && + order != null) { + PdfDocumentHelper.getHelper(_document!).order = order; + } + } + if (PdfLayerHelper.getHelper(_parent!).child.isEmpty) { + PdfLayerHelper.getHelper(_parent!).sublayer.add(reference); + } else if (PdfDocumentHelper.getHelper( + _document!, + ).order!.contains(PdfLayerHelper.getHelper(_parent!).referenceHolder!)) { + final int position = PdfDocumentHelper.getHelper( + _document!, + ).order!.indexOf(PdfLayerHelper.getHelper(_parent!).referenceHolder!); + PdfDocumentHelper.getHelper(_document!).order!.removeAt(position + 1); + PdfLayerHelper.getHelper(_parent!).sublayer.add(reference); + } else { + PdfLayerHelper.getHelper(_parent!).sublayer.add(reference); + } + if (PdfDocumentHelper.getHelper( + _document!, + ).order!.contains(PdfLayerHelper.getHelper(_parent!).referenceHolder!)) { + final int position = PdfDocumentHelper.getHelper( + _document!, + ).order!.indexOf(PdfLayerHelper.getHelper(_parent!).referenceHolder!); + PdfDocumentHelper.getHelper(_document!).order!.insert( + position + 1, + PdfLayerHelper.getHelper(_parent!).sublayer, + ); + } else { + if (PdfLayerHelper.getHelper(_parent!).parent != null) { + if (PdfLayerHelper.getHelper( + PdfLayerHelper.getHelper(_parent!).parent!, + ).sublayer.contains( + PdfLayerHelper.getHelper(_parent!).referenceHolder!, + )) { + int position = PdfLayerHelper.getHelper( + PdfLayerHelper.getHelper(_parent!).parent!, + ).sublayer.indexOf( + PdfLayerHelper.getHelper(_parent!).referenceHolder!, + ); + if (PdfLayerHelper.getHelper(_parent!).sublayer.count == 1) { + PdfLayerHelper.getHelper( + PdfLayerHelper.getHelper(_parent!).parent!, + ).sublayer.insert( + position + 1, + PdfLayerHelper.getHelper(_parent!).sublayer, + ); + } + if (PdfDocumentHelper.getHelper(_document!).order!.contains( + PdfLayerHelper.getHelper( + PdfLayerHelper.getHelper(_parent!).parent!, + ).referenceHolder!, + )) { + position = PdfDocumentHelper.getHelper(_document!).order!.indexOf( + PdfLayerHelper.getHelper( + PdfLayerHelper.getHelper(_parent!).parent!, + ).referenceHolder!, + ); + PdfDocumentHelper.getHelper( + _document!, + ).order!.removeAt(position + 1); + PdfDocumentHelper.getHelper(_document!).order!.insert( + position + 1, + PdfLayerHelper.getHelper( + PdfLayerHelper.getHelper(_parent!).parent!, + ).sublayer, + ); + } + } + } + } + + PdfLayerHelper.getHelper(_parent!).child.add(layer); + + if (PdfLayerHelper.getHelper(_parent!).parentLayer.isEmpty) { + PdfLayerHelper.getHelper(layer).parentLayer.add(_parent!); + } else { + for ( + int i = 0; + i < PdfLayerHelper.getHelper(_parent!).parentLayer.length; + i++ + ) { + if (!PdfLayerHelper.getHelper(layer).parentLayer.contains( + PdfLayerHelper.getHelper(_parent!).parentLayer[i], + )) { + PdfLayerHelper.getHelper(layer).parentLayer.add( + PdfLayerHelper.getHelper(_parent!).parentLayer[i], + ); + } + } + PdfLayerHelper.getHelper(layer).parentLayer.add(_parent!); + } + } + } + + IPdfPrimitive _createOptionalContentViews(PdfLayer layer) { + final PdfArray usageApplication = PdfArray(); + _optionalContent[PdfDictionaryProperties.name] = PdfString('Layers'); + _optionalContent[PdfDictionaryProperties.ocgOrder] = + PdfDocumentHelper.getHelper(_document!).order; + _optionalContent[PdfDictionaryProperties.ocgOn] = + PdfDocumentHelper.getHelper(_document!).on; + _optionalContent[PdfDictionaryProperties.ocgOff] = + PdfDocumentHelper.getHelper(_document!).off; + final PdfArray category = PdfArray(); + category.add(PdfName('Print')); + final PdfDictionary applicationDictionary = PdfDictionary(); + applicationDictionary[PdfDictionaryProperties.category] = category; + applicationDictionary[PdfDictionaryProperties.ocg] = + PdfDocumentHelper.getHelper(_document!).printLayer; + applicationDictionary[PdfDictionaryProperties.event] = PdfName('Print'); + usageApplication.add(PdfReferenceHolder(applicationDictionary)); + _optionalContent[PdfDictionaryProperties.usageApplication] = + usageApplication; + return _optionalContent; + } + + void _getDocumentLayer(PdfDocument document) { + PdfDictionary? layerDictionary; + PdfReferenceHolder layerReference; + if (PdfDocumentHelper.getHelper( + _document!, + ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { + final PdfDictionary? ocProperties = + PdfCrossTable.dereference( + PdfDocumentHelper.getHelper( + _document!, + ).catalog[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + if (ocProperties != null) { + if (ocProperties.containsKey(PdfDictionaryProperties.ocg)) { + final PdfArray ocGroup = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.ocg], + )! + as PdfArray; + for (int i = 0; i < ocGroup.count; i++) { + if (ocGroup[i] is PdfReferenceHolder) { + layerReference = ocGroup[i]! as PdfReferenceHolder; + layerDictionary = layerReference.object as PdfDictionary?; + final PdfLayer layer = PdfLayerHelper.internal(); + if (layerDictionary != null && + layerDictionary.containsKey(PdfDictionaryProperties.name)) { + final PdfString layerName = + PdfCrossTable.dereference( + layerDictionary[PdfDictionaryProperties.name], + )! + as PdfString; + layer.name = layerName.value; + PdfLayerHelper.getHelper(layer).dictionary = layerDictionary; + PdfLayerHelper.getHelper(layer).referenceHolder = + layerReference; + final IPdfPrimitive? layerId = PdfCrossTable.dereference( + layerDictionary[PdfDictionaryProperties.layerID], + ); + if (layerId != null) { + PdfLayerHelper.getHelper(layer).layerId = layerId.toString(); + } + final PdfDictionary? usage = + PdfCrossTable.dereference( + layerDictionary[PdfDictionaryProperties.usage], + ) + as PdfDictionary?; + + if (usage != null) { + final PdfDictionary? printOption = + PdfCrossTable.dereference( + usage[PdfDictionaryProperties.print], + ) + as PdfDictionary?; + + if (printOption != null) { + PdfLayerHelper.getHelper(layer).printOption = printOption; + } + } + } + PdfLayerHelper.getHelper(layer).document = document; + PdfLayerHelper.getHelper(layer).layer = layer; + // layer.parsingLayerPage(); + _layerDictionary[layerReference] = layer; + list.add(layer); + } + } + } + _checkLayerLock(ocProperties); + _checkLayerVisible(ocProperties); + _checkParentLayer(ocProperties); + _createLayerHierarchical(ocProperties); + } + } + } + + void _checkLayerVisible(PdfDictionary ocProperties) { + PdfArray? visible; + if (PdfDocumentHelper.getHelper( + _document!, + ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { + final PdfDictionary? defaultView = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + + if (defaultView != null && + defaultView.containsKey(PdfDictionaryProperties.ocgOff)) { + visible = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOff], + ) + as PdfArray?; + } + if (visible != null) { + for (int i = 0; i < visible.count; i++) { + final PdfLayer? pdfLayer = + _layerDictionary[visible[i]! as PdfReferenceHolder]; + if (pdfLayer != null) { + pdfLayer.visible = false; + if (PdfLayerHelper.getHelper(pdfLayer).dictionary != null && + PdfLayerHelper.getHelper( + pdfLayer, + ).dictionary!.containsKey(PdfDictionaryProperties.visible)) { + PdfLayerHelper.getHelper(pdfLayer).dictionary!.setProperty( + PdfDictionaryProperties.visible, + PdfBoolean(false), + ); + } + } + } + } + } + } + + void _checkParentLayer(PdfDictionary ocProperties) { + final PdfDictionary? defaultView = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultView != null) { + final PdfArray? array = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOrder], + ) + as PdfArray?; + if (array != null) { + _parsingLayerOrder(array, _layerDictionary); + } + } + } + + void _checkLayerLock(PdfDictionary ocProperties) { + PdfArray? locked; + final PdfDictionary? defaultView = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultView != null && + defaultView.containsKey(PdfDictionaryProperties.ocgLock)) { + locked = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgLock], + ) + as PdfArray?; + } + if (locked != null) { + for (int i = 0; i < locked.count; i++) { + final PdfLayer? pdfLayer = + _layerDictionary[locked[i]! as PdfReferenceHolder]; + if (pdfLayer != null) { + continue; + } + } + } + } + + void _createLayerHierarchical(PdfDictionary ocProperties) { + final PdfDictionary? defaultView = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultView != null && + defaultView.containsKey(PdfDictionaryProperties.ocgOrder)) { + if (_layerDictionary.isNotEmpty) { + list.clear(); + _layerDictionary.forEach((PdfReferenceHolder key, PdfLayer value) { + final PdfLayer pdfLayer = value; + if (PdfLayerHelper.getHelper(pdfLayer).parent == null && + !list.contains(pdfLayer)) { + list.add(pdfLayer); + } else if (PdfLayerHelper.getHelper(pdfLayer).child.isNotEmpty) { + _addChildlayer(PdfLayerHelper.getHelper(pdfLayer).parent!); + } else if (PdfLayerHelper.getHelper(pdfLayer).parent != null && + PdfLayerHelper.getHelper(pdfLayer).child.isEmpty && + !PdfLayerHelper.getHelper( + pdfLayer, + ).parent!.layers._helper.list.contains(pdfLayer)) { + PdfLayerHelper.getHelper( + pdfLayer, + ).parent!.layers._helper._addNestedLayer(pdfLayer); + } + }); + } + } + } + + void _addChildlayer(PdfLayer pdfLayer) { + for (int i = 0; i < PdfLayerHelper.getHelper(pdfLayer).child.length; i++) { + final PdfLayer child = PdfLayerHelper.getHelper(pdfLayer).child[i]; + if (!pdfLayer.layers._helper.list.contains(child)) { + pdfLayer.layers._helper._addNestedLayer(child); + } + } + } + + int _addNestedLayer(PdfLayer layer) { + list.add(layer); + PdfLayerHelper.getHelper(layer).layer = layer; + return list.length - 1; + } + + void _parsingLayerOrder( + PdfArray array, + Map layerDictionary, [ + PdfLayer? parent, + ]) { + PdfReferenceHolder reference; + PdfLayer? layer; + for (int i = 0; i < array.count; i++) { + if (array[i] is PdfReferenceHolder) { + reference = array[i]! as PdfReferenceHolder; + layerDictionary.forEach((PdfReferenceHolder key, PdfLayer value) { + if (identical(key.object, reference.object) || + identical(key.reference, reference.reference)) { + layer = value; + } + }); + if (layer != null) { + if (parent != null) { + PdfLayerHelper.getHelper(parent).child.add(layer!); + if (PdfLayerHelper.getHelper(parent).parentLayer.isEmpty) { + PdfLayerHelper.getHelper(parent).parentLayer.add(parent); + PdfLayerHelper.getHelper(layer!).parent = parent; + } else { + for ( + int j = 0; + j < PdfLayerHelper.getHelper(parent).parentLayer.length; + j++ + ) { + if (!PdfLayerHelper.getHelper(layer!).parentLayer.contains( + PdfLayerHelper.getHelper(parent).parentLayer[j], + )) { + PdfLayerHelper.getHelper(layer!).parentLayer.add( + PdfLayerHelper.getHelper(parent).parentLayer[j], + ); + } + } + PdfLayerHelper.getHelper(layer!).parentLayer.add(parent); + PdfLayerHelper.getHelper(layer!).parent = parent; + } + } + if (array.count > i + 1 && + PdfCrossTable.dereference(array[i + 1]) is PdfArray) { + i++; + final PdfArray pdfArray = + PdfCrossTable.dereference(array[i])! as PdfArray; + PdfLayerHelper.getHelper(layer!).sublayer.add(pdfArray); + _parsingLayerOrder(pdfArray, layerDictionary, layer); + } + } + } else if (PdfCrossTable.dereference(array[i]) is PdfArray) { + final PdfArray? subarray = + PdfCrossTable.dereference(array[i]) as PdfArray?; + if (subarray == null) { + return; + } + if (subarray[0] is PdfString) { + parent = null; + _parsingLayerOrder(subarray, layerDictionary, parent); + } else { + parent = null; + _parsingLayerOrder( + PdfCrossTable.dereference(array[i])! as PdfArray, + layerDictionary, + parent, + ); + } + } + } + } + + void _removeLayer(PdfLayer layer, bool isRemoveContent) { + PdfDictionary? dictionary; + if (_document != null) { + dictionary = PdfDocumentHelper.getHelper(_document!).catalog; + if (dictionary.containsKey(PdfDictionaryProperties.ocProperties)) { + final PdfDictionary? ocPropertie = + PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + if (ocPropertie != null) { + final PdfArray? ocGroup = + PdfCrossTable.dereference( + ocPropertie[PdfDictionaryProperties.ocg], + ) + as PdfArray?; + if (ocGroup != null) { + _removeOCProperties( + ocGroup, + PdfLayerHelper.getHelper(layer).referenceHolder, + ); + } + if (ocPropertie.containsKey(PdfDictionaryProperties.defaultView)) { + final PdfDictionary? defaultView = + PdfCrossTable.dereference( + ocPropertie[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultView != null) { + PdfArray? on, off; + if (defaultView.containsKey(PdfDictionaryProperties.ocgOrder)) { + final PdfArray? order = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOrder], + ) + as PdfArray?; + if (order != null) { + _removeOrder(layer, order, []); + // _removeOCProperties(order, layer.referenceHolder); + } + } + if (defaultView.containsKey(PdfDictionaryProperties.ocgLock)) { + final PdfArray? locked = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgLock], + ) + as PdfArray?; + if (locked != null) { + _removeOCProperties( + locked, + PdfLayerHelper.getHelper(layer).referenceHolder, + ); + } + } + if (defaultView.containsKey(PdfDictionaryProperties.ocgOff)) { + off = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOff], + ) + as PdfArray?; + } + if (defaultView.containsKey(PdfDictionaryProperties.ocgOn)) { + on = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOn], + ) + as PdfArray?; + } else if (defaultView.containsKey('ON')) { + on = PdfCrossTable.dereference(defaultView['ON']) as PdfArray?; + } + if (defaultView.containsKey( + PdfDictionaryProperties.usageApplication, + )) { + final PdfArray? usage = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.usageApplication], + ) + as PdfArray?; + if (usage != null) { + _removeOCProperties( + usage, + PdfLayerHelper.getHelper(layer).referenceHolder, + ); + } + } + _removeVisible(layer, on, off); + } + } + } + } + if (isRemoveContent) { + _removeLayerContent(layer); + } + } + } + + void _removeVisible(PdfLayer layer, PdfArray? on, PdfArray? off) { + if (layer.visible) { + if (on != null) { + _removeOCProperties( + on, + PdfLayerHelper.getHelper(layer).referenceHolder, + ); + } + } else { + if (off != null) { + _removeOCProperties( + off, + PdfLayerHelper.getHelper(layer).referenceHolder, + ); + } + } + } + + void _removeOrder(PdfLayer layer, PdfArray order, List arrayList) { + bool isRemoveOrder = false; + for (int i = 0; i < order.count; i++) { + if (order[i] is PdfReferenceHolder) { + final PdfReferenceHolder holder = order[i]! as PdfReferenceHolder; + if (identical( + holder.object, + PdfLayerHelper.getHelper(layer).referenceHolder!.object, + ) || + identical( + holder.reference, + PdfLayerHelper.getHelper(layer).referenceHolder!.reference, + )) { + if (i != order.count - 1) { + if (order[i + 1] is PdfArray) { + order.removeAt(i); + order.removeAt(i); + isRemoveOrder = true; + break; + } else { + order.removeAt(i); + isRemoveOrder = true; + break; + } + } else { + order.removeAt(i); + isRemoveOrder = true; + break; + } + } + } else if (order[i] is PdfArray) { + arrayList.add(order[i]! as PdfArray); + } + } + if (!isRemoveOrder) { + for (int i = 0; i < arrayList.length; i++) { + order = arrayList[i]; + arrayList.removeAt(i); + i = i - 1; + _removeOrder(layer, order, arrayList); + } + } + } + + void _removeOCProperties( + PdfArray content, + PdfReferenceHolder? referenceHolder, + ) { + bool isChange = false; + for (int i = 0; i < content.count; i++) { + final IPdfPrimitive? primitive = content.elements[i]; + if (primitive != null && primitive is PdfReferenceHolder) { + final PdfReferenceHolder holder = primitive; + if (holder.reference != null && referenceHolder!.reference != null) { + if (holder.reference!.objNum == referenceHolder.reference!.objNum) { + content.elements.removeAt(i); + isChange = true; + i--; + } + } else if (identical(holder, referenceHolder)) { + content.elements.removeAt(i); + isChange = true; + i--; + } else if (identical(holder.object, referenceHolder!.object)) { + content.elements.removeAt(i); + isChange = true; + i--; + } + } else if (primitive != null && primitive is PdfArray) { + _removeOCProperties(primitive, referenceHolder); + } + } + if (isChange) { + content.changed = true; + } + } + + void _removeLayerContent(PdfLayer layer) { + PdfDictionary? properties; + bool isSkip = false; + PdfDictionary? xObject; + if (!PdfLayerHelper.getHelper(layer).pageParsed) { + PdfLayerHelper.getHelper(layer).parsingLayerPage(); + _removeLayerContent(layer); + return; + } + if (PdfLayerHelper.getHelper(layer).pages.isNotEmpty) { + for (int i = 0; i < PdfLayerHelper.getHelper(layer).pages.length; i++) { + final PdfDictionary? resource = + PdfCrossTable.dereference( + PdfPageHelper.getHelper( + PdfLayerHelper.getHelper(layer).pages[i], + ).dictionary![PdfDictionaryProperties.resources], + ) + as PdfDictionary?; + if (resource != null) { + properties = + PdfCrossTable.dereference( + resource[PdfDictionaryProperties.properties], + ) + as PdfDictionary?; + xObject = + PdfCrossTable.dereference( + resource[PdfDictionaryProperties.xObject], + ) + as PdfDictionary?; + if (properties != null) { + if (properties.containsKey( + PdfLayerHelper.getHelper(layer).layerId, + )) { + properties.remove(PdfLayerHelper.getHelper(layer).layerId); + } + } + if (xObject != null && + PdfLayerHelper.getHelper(layer).xobject.isNotEmpty) { + final keysToRemove = []; + for (final PdfName? key in xObject.items!.keys) { + if (PdfLayerHelper.getHelper(layer).xobject.contains(key!.name)) { + keysToRemove.add(key); + } + if (xObject.items!.isEmpty) { + break; + } + } + // ignore: prefer_foreach + for (final PdfName key in keysToRemove) { + xObject.remove(key); + } + } + final PdfArray content = + PdfPageHelper.getHelper( + PdfLayerHelper.getHelper(layer).pages[i], + ).contents; + for (int m = 0; m < content.count; m++) { + List? stream = []; + final PdfStream data = PdfStream(); + final PdfStream pageContent = + PdfCrossTable.dereference(content[m])! as PdfStream; + if (PdfPageHelper.getHelper( + PdfLayerHelper.getHelper(layer).pages[i], + ).isLoadedPage) { + pageContent.decompress(); + } + stream = pageContent.dataStream; + final ContentParser parser = ContentParser(stream); + final PdfRecordCollection recordCollection = parser.readContent()!; + for (int j = 0; j < recordCollection.recordCollection.length; j++) { + final String? mOperator = + recordCollection.recordCollection[j].operatorName; + if (mOperator == 'BMC' || + mOperator == 'EMC' || + mOperator == 'BDC') { + _processBeginMarkContent( + layer, + mOperator, + recordCollection.recordCollection[j].operands, + data, + ); + isSkip = true; + } + if (mOperator == PdfOperators.paintXObject) { + if (PdfLayerHelper.getHelper(layer).xobject.contains( + recordCollection.recordCollection[j].operands![0] + .trim() + .replaceFirst('/', ''), + )) { + isSkip = true; + } + } + if (mOperator == 'RG' || + mOperator == PdfOperators.saveState || + mOperator == PdfOperators.restoreState || + mOperator == PdfOperators.setLineWidth || + mOperator == PdfOperators.setLineCapStyle || + mOperator == PdfOperators.setLineJoinStyle || + mOperator == PdfOperators.setMiterLimit || + mOperator == PdfOperators.setDashPattern || + mOperator == PdfOperators.setGraphicsState || + mOperator == PdfOperators.currentMatrix || + mOperator == PdfOperators.selectColorSpaceForNonStroking || + mOperator == PdfOperators.selectColorSpaceForStroking) { + if (!isSkip) { + _streamWrite( + recordCollection.recordCollection[j].operands, + mOperator, + false, + data, + ); + } + } else if (!isSkip) { + _streamWrite( + recordCollection.recordCollection[j].operands, + mOperator, + true, + data, + ); + } + isSkip = false; + } + if (data.dataStream!.isNotEmpty) { + pageContent.clear(); + pageContent.dataStream!.clear(); + pageContent.write(data.dataStream); + } else { + pageContent.clear(); + } + } + } + } + } + } + + void _processBeginMarkContent( + PdfLayer parser, + String? mOperator, + List? operands, + PdfStream data, + ) { + if ('BDC' == mOperator) { + String? operand; + if (operands!.length > 1 && ((operands[0]) == '/OC')) { + operand = operands[1].substring(1); + } + if (_bdcCount > 0) { + _bdcCount++; + return; + } + if (operand != null && + (operand == PdfLayerHelper.getHelper(parser).layerId)) { + _bdcCount++; + } + } + _streamWrite(operands, mOperator, true, data); + if (('EMC' == mOperator) && _bdcCount > 0) { + _bdcCount--; + } + } + + void _streamWrite( + List? operands, + String? mOperator, + bool skip, + PdfStream data, + ) { + PdfString pdfString; + if (skip && _bdcCount > 0) { + return; + } + if (operands != null) { + for (final String operand in operands) { + pdfString = PdfString(operand); + data.write(pdfString.data); + data.write(PdfOperators.whiteSpace); + } + } + pdfString = PdfString(mOperator!); + data.write(pdfString.data); + data.write(PdfOperators.newLine); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page.dart index 5f48e3f82..a4b37d36f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page.dart @@ -1,1105 +1,1105 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/pdf_annotation_collection.dart'; -import '../forms/pdf_field.dart'; -import '../forms/pdf_form.dart'; -import '../forms/pdf_form_field_collection.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_resources.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'enum.dart'; -import 'pdf_page_layer.dart'; -import 'pdf_page_layer_collection.dart'; -import 'pdf_page_settings.dart'; -import 'pdf_section.dart'; -import 'pdf_section_collection.dart'; - -/// Provides methods and properties to create PDF pages -/// and its elements, [PdfPage]. -/// ```dart -/// //Create a new PDF documentation -/// PdfDocument document = PdfDocument(); -/// //Create a new PDF page and draw the text -/// document.pages.add().graphics.drawString( -/// 'Hello World!!!', -/// PdfStandardFont(PdfFontFamily.helvetica, 27), -/// brush: PdfBrushes.darkBlue, -/// bounds: const Rect.fromLTWH(170, 100, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfPage implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfPage] class. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF page - /// PdfPage page = document.pages.add(); - /// //Draw the text to the page - /// page.graphics.drawString( - /// 'Hello World!!!', - /// PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, - /// bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPage() { - _helper = PdfPageHelper(this); - _initialize(); - } - - PdfPage._fromDictionary( - PdfDocument document, - PdfCrossTable crossTable, - PdfDictionary dictionary, - ) { - _helper = PdfPageHelper(this); - _helper._pdfDocument = document; - _helper.dictionary = dictionary; - _helper.crossTable = crossTable; - _helper.isLoadedPage = true; - _size = Size.zero; - _helper.isTextExtraction = false; - _graphicStateUpdated = false; - } - - //Fields - late PdfPageHelper _helper; - PdfPageLayerCollection? _layers; - int _defaultLayerIndex = -1; - Size? _size; - late bool _graphicStateUpdated; - PdfFormFieldsTabOrder _formFieldsTabOrder = PdfFormFieldsTabOrder.none; - PdfPageRotateAngle? _rotation; - - //Properties - /// Gets size of the PDF page- Read only - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF page and Gets the size of its page - /// Size size = document.pages.add().size; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Size get size { - if (_helper.isLoadedPage) { - if (_size == null || (_size!.width == 0 && _size!.height == 0)) { - double width = 0; - double height = 0; - final IPdfPrimitive? mBox = _helper.dictionary!.getValue( - PdfDictionaryProperties.mediaBox, - PdfDictionaryProperties.parent, - ); - final IPdfPrimitive? cBox = _helper.dictionary!.getValue( - PdfDictionaryProperties.cropBox, - PdfDictionaryProperties.parent, - ); - if (cBox != null && cBox is PdfArray) { - final num c0 = (cBox[0]! as PdfNumber).value!; - final num? c1 = (cBox[1]! as PdfNumber).value; - final num c2 = (cBox[2]! as PdfNumber).value!; - final num? c3 = (cBox[3]! as PdfNumber).value; - width = (c2 - c0).toDouble(); - height = c3 != 0 ? (c3! - c1!).toDouble() : c1!.toDouble(); - } else if (mBox != null && mBox is PdfArray) { - final num m0 = (mBox[0]! as PdfNumber).value!; - final num? m1 = (mBox[1]! as PdfNumber).value; - final num m2 = (mBox[2]! as PdfNumber).value!; - final num? m3 = (mBox[3]! as PdfNumber).value; - width = (m2 - m0).toDouble(); - height = m3 != 0 ? (m3! - m1!).toDouble() : m1!.toDouble(); - } - _size = Size(width, height); - } - return _size!; - } else { - return _helper.section!.pageSettings.size; - } - } - - /// Gets a collection of the annotations of the page- Read only. - /// ```dart - /// //Creates a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Creates a rectangle annotation - /// PdfRectangleAnnotation rectangleAnnotation = PdfRectangleAnnotation( - /// Rect.fromLTWH(0, 30, 80, 80), 'Rectangle Annotation', - /// author: 'Syncfusion', - /// color: PdfColor(255, 0, 0), - /// modifiedDate: DateTime.now()); - /// //Create a new PDF page and Adds the annotation to the PDF page - /// document.pages.add().annotations.add(rectangleAnnotation); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfAnnotationCollection get annotations { - if (!_helper.isLoadedPage) { - if (_helper._annotations == null) { - _helper._annotations = PdfAnnotationCollection(this); - if (!_helper.dictionary!.containsKey(PdfDictionaryProperties.annots)) { - _helper.dictionary![PdfDictionaryProperties.annots] = - PdfAnnotationCollectionHelper.getHelper( - _helper._annotations!, - ).internalAnnotations; - } - PdfAnnotationCollectionHelper.getHelper( - _helper._annotations!, - ).internalAnnotations = - _helper.dictionary![PdfDictionaryProperties.annots] as PdfArray?; - } - } else { - if (_helper._annotations == null || _helper.importAnnotation) { - // Create the annotations. - _helper.createAnnotations(_helper.getWidgetReferences()); - } - if (_helper._annotations == null || - (PdfAnnotationCollectionHelper.getHelper( - _helper._annotations!, - ).internalAnnotations.count == - 0 && - _helper._annotations!.count != 0)) { - _helper._annotations = PdfAnnotationCollectionHelper.load(this); - } - } - return _helper._annotations!; - } - - /// Gets the graphics of the `defaultLayer`. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF page and draw the text - /// document.pages.add().graphics.drawString( - /// 'Hello World!!!', - /// PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, - /// bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGraphics get graphics { - _helper.isDefaultGraphics = true; - return defaultLayer.graphics; - } - - /// Gets the collection of the page's layers (Read only). - /// ```dart - /// //Creates a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Creates a new page - /// PdfPage page = document.pages.add(); - /// //Gets the layers from the page and Add the new layer. - /// PdfPageLayer layer = page.layers.add(name: 'Layer1'); - /// //Get the layer graphics. - /// PdfGraphics graphics = layer.graphics; - /// graphics.translateTransform(100, 60); - /// //Draw an Arc. - /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, - /// pen: PdfPen(PdfColor(250, 0, 0), width: 50)); - /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, - /// pen: PdfPen(PdfColor(0, 0, 250), width: 30)); - /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, - /// pen: PdfPen(PdfColor(250, 250, 0), width: 20)); - /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, - /// pen: PdfPen(PdfColor(0, 250, 0), width: 10)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageLayerCollection get layers { - if (!_helper.isTextExtraction && !_graphicStateUpdated) { - _layers = PdfPageLayerCollection(this); - _graphicStateUpdated = true; - } else { - _layers ??= PdfPageLayerCollection(this); - } - return _layers!; - } - - /// Gets the default layer of the page (Read only). - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF page and gets the default layer - /// PdfPageLayer defaultLayer = document.pages.add().defaultLayer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageLayer get defaultLayer => layers[defaultLayerIndex]; - - /// Gets or sets index of the default layer (Read only). - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF page and gets the default layer index - /// int layerIndex = document.pages.add().defaultLayerIndex; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get defaultLayerIndex { - if (layers.count == 0 || _defaultLayerIndex == -1) { - final PdfPageLayer layer = layers.add(); - _defaultLayerIndex = layers.indexOf(layer); - } - return _defaultLayerIndex; - } - - /// Gets or sets the tab order type for form fields - PdfFormFieldsTabOrder get formFieldsTabOrder => _formFieldsTabOrder; - set formFieldsTabOrder(PdfFormFieldsTabOrder value) { - _formFieldsTabOrder = value; - if (_formFieldsTabOrder != PdfFormFieldsTabOrder.none) { - String tabs = ' '; - if (_formFieldsTabOrder == PdfFormFieldsTabOrder.row) { - tabs = PdfDictionaryProperties.r; - } - if (_formFieldsTabOrder == PdfFormFieldsTabOrder.column) { - tabs = PdfDictionaryProperties.c; - } - if (_formFieldsTabOrder == PdfFormFieldsTabOrder.structure) { - tabs = PdfDictionaryProperties.s; - } - _helper.dictionary![PdfDictionaryProperties.tabs] = PdfName(tabs); - } - } - - /// Gets or sets the rotation of PDF page - /// - /// This property only works on existing PDF document pages - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(inputBytes: data); - /// //Rotation of the PDF page - /// PdfPageRotateAngle rotation = document.pages[0].rotation; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageRotateAngle get rotation { - _rotation ??= _obtainRotation(); - return _rotation!; - } - - set rotation(PdfPageRotateAngle angle) { - if (_helper.isLoadedPage && rotation != angle) { - _rotation = angle; - _helper.dictionary![PdfDictionaryProperties.rotate] = PdfNumber( - PdfSectionCollectionHelper.rotateFactor * angle.index, - ); - } - } - - //Public methods - /// Get the PDF page size reduced by page margins and - /// page template dimensions. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF page - /// PdfPage page = document.pages.add(); - /// //Gets the page client size - /// Size clientSize = page.getClientSize(); - /// //Draw the text to the page - /// page.graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, - /// bounds: Rect.fromLTWH(400, 600, clientSize.width, clientSize.height)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Size getClientSize() { - return _helper.isLoadedPage - ? size - : PdfSectionHelper.getHelper( - _helper.section!, - ).getActualBounds(this, true).size.size; - } - - /// Creates a template from the page content. - /// ```dart - /// //Loads an existing PDF document and create the template - /// PdfTemplate template = - /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) - /// .pages[0] - /// .createTemplate(); - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Sets the page settings margin - /// document.pageSettings.setMargins(2); - /// //Create a new PDF page - /// PdfPage page = document.pages.add(); - /// //Draw the Pdf template by using created template - /// page.graphics.drawPdfTemplate( - /// template, Offset(20, 0), Size(page.size.width / 2, page.size.height)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfTemplate createTemplate() { - return _helper._getContent(); - } - - //Implementation - - void _initialize() { - _helper.dictionary = PdfDictionary(); - _helper.dictionary![PdfDictionaryProperties.type] = PdfName('Page'); - _helper.dictionary!.beginSave = _pageBeginSave; - _size = Size.zero; - _helper.isTextExtraction = false; - _graphicStateUpdated = false; - } - - void _drawPageTemplates(PdfDocument doc) { - // Draw Background templates. - final bool hasBackTemplates = PdfSectionHelper.getHelper( - _helper.section!, - ).containsTemplates(doc, this, false); - if (hasBackTemplates) { - final PdfPageLayer backLayer = PdfPageLayerHelper.fromClipPageTemplate( - this, - false, - ); - final PdfPageLayerCollection layer = PdfPageLayerCollection(this); - _layers = layer; - _layers!.addLayer(backLayer); - PdfSectionHelper.getHelper( - _helper.section!, - ).drawTemplates(this, backLayer, doc, false); - } - - // Draw Foreground templates. - final bool hasFrontTemplates = PdfSectionHelper.getHelper( - _helper.section!, - ).containsTemplates(doc, this, true); - - if (hasFrontTemplates) { - final PdfPageLayer frontLayer = PdfPageLayerHelper.fromClipPageTemplate( - this, - false, - ); - final PdfPageLayerCollection layer = PdfPageLayerCollection(this); - _layers = layer; - _layers!.addLayer(frontLayer); - PdfSectionHelper.getHelper( - _helper.section!, - ).drawTemplates(this, frontLayer, doc, true); - } - } - - PdfPageRotateAngle _obtainRotation() { - PdfDictionary? parent = _helper.dictionary; - PdfNumber? angle; - while (parent != null && angle == null) { - if (parent.containsKey(PdfDictionaryProperties.rotate)) { - if (parent[PdfDictionaryProperties.rotate] is PdfReferenceHolder) { - angle = - (parent[PdfDictionaryProperties.rotate]! as PdfReferenceHolder) - .object - as PdfNumber?; - } else { - angle = parent[PdfDictionaryProperties.rotate] as PdfNumber?; - } - } - if (parent.containsKey(PdfDictionaryProperties.parent)) { - IPdfPrimitive? parentPrimitive = parent[PdfDictionaryProperties.parent]; - if (parentPrimitive != null) { - parentPrimitive = PdfCrossTable.dereference(parentPrimitive); - parent = - parentPrimitive != null && parentPrimitive is PdfDictionary - ? parentPrimitive - : null; - } else { - parent = null; - } - } else { - parent = null; - } - } - angle ??= PdfNumber(0); - if (angle.value!.toInt() < 0) { - angle.value = 360 + angle.value!.toInt(); - } - final PdfPageRotateAngle rotateAngle = _getRotationFromAngle( - angle.value! ~/ 90, - ); - return rotateAngle; - } - - PdfPageRotateAngle _getRotationFromAngle(int angle) { - if (angle == 1) { - return PdfPageRotateAngle.rotateAngle90; - } else if (angle == 2) { - return PdfPageRotateAngle.rotateAngle180; - } else if (angle == 3) { - return PdfPageRotateAngle.rotateAngle270; - } else { - return PdfPageRotateAngle.rotateAngle0; - } - } - - void _pageBeginSave(Object sender, SavePdfPrimitiveArgs? args) { - final PdfDocument? doc = args!.writer!.document; - if (doc != null && _helper.document != null) { - _drawPageTemplates(doc); - } - if (_helper.beginSave != null) { - _helper.beginSave!(); - } - } -} - -/// [PdfPage] helper -class PdfPageHelper { - /// internal constructor - PdfPageHelper(this.base); - - /// internal field - late PdfPage base; - - /// internal field - bool importAnnotation = false; - - /// internal method - static PdfPageHelper getHelper(PdfPage base) { - return base._helper; - } - - /// internal method - static PdfPage fromDictionary( - PdfDocument document, - PdfCrossTable crossTable, - PdfDictionary dictionary, - ) { - return PdfPage._fromDictionary(document, crossTable, dictionary); - } - - /// internal method - IPdfPrimitive? get element => dictionary; - - // ignore: unused_element - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - dictionary = value; - } - } - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal field - bool? isNewPage; - - /// internal method - PdfSection? section; - - /// internal method - bool isLoadedPage = false; - - /// internal method - PdfCrossTable? crossTable; - - /// internal method - final List terminalAnnotation = []; - - /// internal method - final PdfArray annotsReference = PdfArray(); - - /// internal method - late bool isTextExtraction; - - /// internal method - bool isDefaultGraphics = false; - - /// Raises before the page saves. - Function? beginSave; - PdfDocument? _pdfDocument; - PdfResources? _resources; - Rect _cBox = Rect.zero; - Rect _mBox = Rect.zero; - bool _checkResources = false; - PdfAnnotationCollection? _annotations; - - /// internal method - Offset get origin { - if (section != null) { - return PdfPageSettingsHelper.getHelper( - section!.pageSettings, - ).origin.offset; - } else { - return Offset.zero; - } - } - - /// internal property - PdfDocument? get document { - if (isLoadedPage || _pdfDocument != null) { - return _pdfDocument; - } else { - if (section != null) { - if (PdfSectionHelper.getHelper(section!).parent != null) { - return PdfSectionCollectionHelper.getHelper( - PdfSectionHelper.getHelper(section!).parent!, - ).document; - } else if (PdfSectionHelper.getHelper(section!).document != null) { - return PdfSectionHelper.getHelper(section!).document; - } else { - return null; - } - } else { - return null; - } - } - } - - set document(PdfDocument? value) { - _pdfDocument = value; - } - - /// Gets the crop box. - Rect get cropBox { - if (_cBox.isEmpty) { - final IPdfPrimitive? cBox = dictionary!.getValue( - PdfDictionaryProperties.cropBox, - PdfDictionaryProperties.parent, - ); - if (cBox != null && cBox is PdfArray) { - final double width = (cBox[2]! as PdfNumber).value!.toDouble(); - final double height = - (cBox[3]! as PdfNumber).value != 0 - ? (cBox[3]! as PdfNumber).value!.toDouble() - : (cBox[1]! as PdfNumber).value!.toDouble(); - final double x = (cBox[0]! as PdfNumber).value!.toDouble(); - final double y = (cBox[1]! as PdfNumber).value!.toDouble(); - _cBox = _calculateBounds(x, y, width, height); - } - } - return _cBox; - } - - /// Gets the media box. - Rect get mediaBox { - if (_mBox.isEmpty) { - final IPdfPrimitive? mBox = dictionary!.getValue( - PdfDictionaryProperties.mediaBox, - PdfDictionaryProperties.parent, - ); - if (mBox != null && mBox is PdfArray) { - final double width = (mBox[2]! as PdfNumber).value!.toDouble(); - final double height = - (mBox[3]! as PdfNumber).value != 0 - ? (mBox[3]! as PdfNumber).value!.toDouble() - : (mBox[1]! as PdfNumber).value!.toDouble(); - final double x = (mBox[0]! as PdfNumber).value!.toDouble(); - final double y = (mBox[1]! as PdfNumber).value!.toDouble(); - _mBox = _calculateBounds(x, y, width, height); - } - } - return _mBox; - } - - /// Gets array of page's content. - PdfArray get contents { - final IPdfPrimitive? contentArray = - dictionary![PdfDictionaryProperties.contents]; - PdfArray? elements; - if (contentArray is PdfReferenceHolder) { - final PdfReferenceHolder holder = contentArray; - final IPdfPrimitive? primitive = holder.object; - if (primitive is PdfArray) { - elements = primitive; - } else if (primitive is PdfStream) { - elements = PdfArray(); - elements.add(PdfReferenceHolder(primitive)); - if (!isTextExtraction) { - dictionary![PdfDictionaryProperties.contents] = elements; - } - } - } else if (contentArray is PdfArray) { - elements = contentArray; - } - if (elements == null) { - elements = PdfArray(); - if (!isTextExtraction) { - dictionary![PdfDictionaryProperties.contents] = elements; - } - } - return elements; - } - - /// internal property - PdfPageOrientation get orientation => _obtainOrientation(); - - PdfPageOrientation _obtainOrientation() { - return (base.size.width > base.size.height) - ? PdfPageOrientation.landscape - : PdfPageOrientation.portrait; - } - - Rect _calculateBounds(double x, double y, double width, double height) { - width = width - x; - if (height != y) { - height = height - y; - } - return Rect.fromLTWH(x, y, width, height); - } - - /// internal method - void assignSection(PdfSection section) { - this.section = section; - dictionary![PdfDictionaryProperties.parent] = PdfReferenceHolder(section); - } - - /// internal method - PdfResources? getResources() { - if (_resources == null) { - if (!isLoadedPage) { - _resources = PdfResources(); - dictionary![PdfDictionaryProperties.resources] = _resources; - } else { - if (!dictionary!.containsKey(PdfDictionaryProperties.resources) || - _checkResources) { - _resources = PdfResources(); - dictionary![PdfDictionaryProperties.resources] = _resources; - // Check for the resources in the corresponding page section. - if (_resources!.getNames()!.isEmpty || _resources!.items!.isEmpty) { - if (dictionary!.containsKey(PdfDictionaryProperties.parent)) { - IPdfPrimitive? obj = dictionary![PdfDictionaryProperties.parent]; - PdfDictionary? parentDic; - if (obj is PdfReferenceHolder) { - parentDic = obj.object as PdfDictionary?; - } else { - parentDic = obj as PdfDictionary?; - } - if (parentDic!.containsKey(PdfDictionaryProperties.resources)) { - obj = parentDic[PdfDictionaryProperties.resources]; - if (obj is PdfDictionary && obj.items!.isNotEmpty) { - dictionary![PdfDictionaryProperties.resources] = obj; - _resources = PdfResources(obj); - final PdfDictionary xobjects = PdfDictionary(); - if (_resources!.containsKey( - PdfDictionaryProperties.xObject, - )) { - final PdfDictionary? xObject = - _resources![PdfDictionaryProperties.xObject] - as PdfDictionary?; - - if (xObject != null) { - final IPdfPrimitive? content = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.contents], - ); - if (content != null) { - if (content is PdfArray) { - for (int i = 0; i < content.count; i++) { - final PdfStream pageContent = - PdfCrossTable.dereference(content[i])! - as PdfStream; - pageContent.decompress(); - } - } else if (content is PdfStream) { - content.decompress(); - } - } - _resources!.setProperty( - PdfDictionaryProperties.xObject, - xobjects, - ); - setResources(_resources); - } - } - } else if (obj is PdfReferenceHolder) { - bool isValueEqual = false; - final PdfDictionary pageSourceDictionary = - obj.object! as PdfDictionary; - if (pageSourceDictionary.items!.length == - _resources!.items!.length || - _resources!.items!.isEmpty) { - for (final PdfName? key in _resources!.items!.keys) { - if (pageSourceDictionary.items!.containsKey(key)) { - if (pageSourceDictionary.items!.containsValue( - _resources![key], - )) { - isValueEqual = true; - } - } else { - isValueEqual = false; - break; - } - } - if (isValueEqual || _resources!.items!.isEmpty) { - dictionary![PdfDictionaryProperties.resources] = obj; - _resources = PdfResources(obj.object as PdfDictionary?); - } - setResources(_resources); - } - } - } - } - } - } else { - final IPdfPrimitive? dicObj = - dictionary![PdfDictionaryProperties.resources]; - final PdfDictionary? dic = - crossTable!.getObject(dicObj) as PdfDictionary?; - _resources = PdfResources(dic); - dictionary![PdfDictionaryProperties.resources] = _resources; - if (dictionary!.containsKey(PdfDictionaryProperties.parent)) { - final PdfDictionary? parentDic = - PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.parent], - ) - as PdfDictionary?; - if (parentDic != null && - parentDic.containsKey(PdfDictionaryProperties.resources)) { - final IPdfPrimitive? resource = - parentDic[PdfDictionaryProperties.resources]; - if (dicObj is PdfReferenceHolder && - resource is PdfReferenceHolder && - resource.reference == dicObj.reference) { - final PdfDictionary? resourceDict = - PdfCrossTable.dereference(dicObj) as PdfDictionary?; - if (resourceDict != null) { - _resources = PdfResources(resourceDict); - } - } - } - } - setResources(_resources); - } - _checkResources = true; - } - } - return _resources; - } - - /// internal method - void setResources(PdfResources? resources) { - _resources = resources; - dictionary![PdfDictionaryProperties.resources] = _resources; - } - - /// internal method - void createAnnotations(List widgetReferences) { - IPdfPrimitive? annots; - if (dictionary!.containsKey(PdfDictionaryProperties.annots)) { - annots = crossTable!.getObject( - dictionary![PdfDictionaryProperties.annots], - ); - if (annots != null && annots is PdfArray) { - for (int count = 0; count < annots.count; ++count) { - PdfDictionary? annotDictionary; - if (crossTable!.getObject(annots[count]) is PdfDictionary) { - annotDictionary = - crossTable!.getObject(annots[count]) as PdfDictionary?; - } - PdfReferenceHolder? annotReference; - if (crossTable!.getObject(annots[count]) is PdfReferenceHolder) { - annotReference = - crossTable!.getObject(annots[count]) as PdfReferenceHolder?; - } - if (document != null && - PdfDocumentHelper.getHelper(document!).crossTable.encryptor != - null && - PdfDocumentHelper.getHelper( - document!, - ).crossTable.encryptor!.encryptAttachmentOnly!) { - if (annotDictionary != null && - annotDictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? primitive = - annotDictionary.items![PdfName( - PdfDictionaryProperties.subtype, - )]; - if (primitive is PdfName && - primitive.name == 'FileAttachment' && - annotDictionary.containsKey(PdfDictionaryProperties.fs)) { - final IPdfPrimitive? file = - annotDictionary[PdfDictionaryProperties.fs]; - if (file != null && file is PdfReferenceHolder) { - final IPdfPrimitive? streamDictionary = file.object; - if (streamDictionary != null && - streamDictionary is PdfDictionary && - streamDictionary.containsKey( - PdfDictionaryProperties.ef, - )) { - PdfDictionary? attachmentStream; - IPdfPrimitive? holder = - streamDictionary[PdfDictionaryProperties.ef]; - if (holder is PdfReferenceHolder) { - holder = holder.object; - if (holder != null && holder is PdfDictionary) { - attachmentStream = holder; - } - } else if (holder is PdfDictionary) { - attachmentStream = holder; - } - if (attachmentStream != null && - attachmentStream.containsKey( - PdfDictionaryProperties.f, - )) { - holder = attachmentStream[PdfDictionaryProperties.f]; - if (holder != null && holder is PdfReferenceHolder) { - final PdfReference? reference = holder.reference; - holder = holder.object; - if (holder != null && holder is PdfStream) { - final PdfStream encryptedObj = holder; - if (PdfDocumentHelper.getHelper( - document!, - ).isLoadedDocument) { - if (document!.onPdfPassword != null && - PdfDocumentHelper.getHelper( - document!, - ).password == - '') { - final PdfPasswordArgs args = - PdfPasswordArgsHelper.load(); - PdfDocumentHelper.getHelper( - document!, - ).setUserPassword(args); - PdfDocumentHelper.getHelper(document!).password = - args.attachmentOpenPassword; - } - PdfDocumentHelper.getHelper( - document!, - ).checkEncryption( - PdfDocumentHelper.getHelper( - document!, - ).crossTable.encryptor!.encryptAttachmentOnly, - ); - encryptedObj.decrypt( - PdfDocumentHelper.getHelper( - document!, - ).crossTable.encryptor!, - reference!.objNum, - ); - } - } - } - } - } - } - } - } - } - if (annotDictionary != null && - annotDictionary.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName? name = - annotDictionary.items![PdfName(PdfDictionaryProperties.subtype)] - as PdfName?; - if (name != null && name.name.toString() != 'Widget') { - if (!terminalAnnotation.contains(annotDictionary)) { - terminalAnnotation.add(annotDictionary); - } - } else if (name != null && name.name.toString() == 'Widget') { - if (annotDictionary.containsKey(PdfDictionaryProperties.parent)) { - final PdfDictionary? annotParentDictionary = - (annotDictionary.items![PdfName( - PdfDictionaryProperties.parent, - )]! - as PdfReferenceHolder) - .object - as PdfDictionary?; - if (annotParentDictionary != null) { - if (!annotParentDictionary.containsKey( - PdfDictionaryProperties.fields, - )) { - if (annotReference != null && - annotReference.reference != null && - !widgetReferences.contains( - annotReference.reference!.objNum, - )) { - if (!PdfFormHelper.getHelper( - document!.form, - ).terminalFields.contains(annotParentDictionary)) { - PdfFormHelper.getHelper( - document!.form, - ).terminalFields.add(annotParentDictionary); - } - } else if (annotParentDictionary.containsKey( - PdfDictionaryProperties.kids, - ) && - annotParentDictionary.count == 1) { - annotDictionary.remove(PdfDictionaryProperties.parent); - } - } else if (!annotParentDictionary.containsKey( - PdfDictionaryProperties.kids, - )) { - annotDictionary.remove(PdfDictionaryProperties.parent); - } - } - } else if (!PdfFormHelper.getHelper( - document!.form, - ).terminalFields.contains(annotDictionary)) { - Map>? widgetDictionary = - PdfFormHelper.getHelper(document!.form).widgetDictionary; - if (widgetDictionary == null) { - PdfFormHelper.getHelper(document!.form).widgetDictionary = - >{}; - widgetDictionary = - PdfFormHelper.getHelper(document!.form).widgetDictionary; - } - if (annotDictionary.containsKey(PdfDictionaryProperties.t)) { - final String? fieldName = - (annotDictionary.items![PdfName( - PdfDictionaryProperties.t, - )]! - as PdfString) - .value; - if (widgetDictionary!.containsKey(fieldName)) { - final List dict = - widgetDictionary[fieldName]!; - dict.add(annotDictionary); - } else { - if (!PdfFormFieldCollectionHelper.getHelper( - document!.form.fields, - ).addedFieldNames.contains(fieldName)) { - widgetDictionary[fieldName] = [ - annotDictionary, - ]; - } - } - } - } - } - } - if (annotReference != null && annotReference.reference != null) { - if (!annotsReference.contains(annotReference.reference!)) { - annotsReference.add(annotReference.reference!); - } - bool skip = false; - if (document != null && - widgetReferences.contains(annotReference.reference!.objNum)) { - final PdfFormFieldCollection collection = document!.form.fields; - for (int i = 0; i < collection.count; i++) { - final PdfField field = collection[i]; - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if (helper.isLoadedField) { - final IPdfPrimitive widget = helper.getWidgetAnnotation( - helper.dictionary!, - helper.crossTable, - ); - final PdfReference widgetReference = crossTable!.getReference( - widget, - ); - if (annotReference.reference!.objNum == - widgetReference.objNum && - annotReference.reference!.genNum == - widgetReference.genNum) { - skip = true; - } - } - } - } - if (annotDictionary != null && annotReference.reference != null) { - if (!widgetReferences.contains( - annotReference.reference!.objNum, - ) && - !skip) { - if (!terminalAnnotation.contains(annotDictionary)) { - terminalAnnotation.add(annotDictionary); - } - } - } - } - } - } - } - if (importAnnotation) { - importAnnotation = false; - } - _annotations = PdfAnnotationCollectionHelper.load(base); - } - - PdfTemplate _getContent() { - final List combinedData = - PdfPageLayerCollectionHelper.getHelper( - base.layers, - ).combineContent(false)!; - final PdfDictionary? resources = - PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.resources], - ) - as PdfDictionary?; - final PdfTemplate template = PdfTemplateHelper.internal( - origin, - base.size, - combinedData, - resources!, - isLoadedPage, - this, - ); - return template; - } - - /// internal method - List getWidgetReferences() { - final List widgetReferences = []; - final PdfFormFieldCollection collection = document!.form.fields; - for (int i = 0; i < collection.count; i++) { - final PdfField field = collection[i]; - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); - if (helper.isLoadedField) { - final IPdfPrimitive widget = helper.getWidgetAnnotation( - helper.dictionary!, - helper.crossTable, - ); - final Map widgetReference = - PdfDocumentHelper.getHelper( - document!, - ).objects.getReference(widget, false); - widgetReferences.add( - ((widgetReference['isNew'] as bool) - ? crossTable!.getReference(widget).objNum - : (widgetReference['reference'] as PdfReference).objNum)! - .toSigned(64), - ); - widgetReference.clear(); - } - } - return widgetReferences; - } - - /// internal method - PdfArray? obtainAnnotations() { - final IPdfPrimitive? obj = dictionary!.getValue( - PdfDictionaryProperties.annots, - PdfDictionaryProperties.parent, - ); - return (obj != null && obj is PdfReferenceHolder ? obj.object : obj) - as PdfArray?; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/pdf_annotation_collection.dart'; +import '../forms/pdf_field.dart'; +import '../forms/pdf_form.dart'; +import '../forms/pdf_form_field_collection.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_resources.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'enum.dart'; +import 'pdf_page_layer.dart'; +import 'pdf_page_layer_collection.dart'; +import 'pdf_page_settings.dart'; +import 'pdf_section.dart'; +import 'pdf_section_collection.dart'; + +/// Provides methods and properties to create PDF pages +/// and its elements, [PdfPage]. +/// ```dart +/// //Create a new PDF documentation +/// PdfDocument document = PdfDocument(); +/// //Create a new PDF page and draw the text +/// document.pages.add().graphics.drawString( +/// 'Hello World!!!', +/// PdfStandardFont(PdfFontFamily.helvetica, 27), +/// brush: PdfBrushes.darkBlue, +/// bounds: const Rect.fromLTWH(170, 100, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfPage implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfPage] class. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF page + /// PdfPage page = document.pages.add(); + /// //Draw the text to the page + /// page.graphics.drawString( + /// 'Hello World!!!', + /// PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, + /// bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPage() { + _helper = PdfPageHelper(this); + _initialize(); + } + + PdfPage._fromDictionary( + PdfDocument document, + PdfCrossTable crossTable, + PdfDictionary dictionary, + ) { + _helper = PdfPageHelper(this); + _helper._pdfDocument = document; + _helper.dictionary = dictionary; + _helper.crossTable = crossTable; + _helper.isLoadedPage = true; + _size = Size.zero; + _helper.isTextExtraction = false; + _graphicStateUpdated = false; + } + + //Fields + late PdfPageHelper _helper; + PdfPageLayerCollection? _layers; + int _defaultLayerIndex = -1; + Size? _size; + late bool _graphicStateUpdated; + PdfFormFieldsTabOrder _formFieldsTabOrder = PdfFormFieldsTabOrder.none; + PdfPageRotateAngle? _rotation; + + //Properties + /// Gets size of the PDF page- Read only + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF page and Gets the size of its page + /// Size size = document.pages.add().size; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Size get size { + if (_helper.isLoadedPage) { + if (_size == null || (_size!.width == 0 && _size!.height == 0)) { + double width = 0; + double height = 0; + final IPdfPrimitive? mBox = _helper.dictionary!.getValue( + PdfDictionaryProperties.mediaBox, + PdfDictionaryProperties.parent, + ); + final IPdfPrimitive? cBox = _helper.dictionary!.getValue( + PdfDictionaryProperties.cropBox, + PdfDictionaryProperties.parent, + ); + if (cBox != null && cBox is PdfArray) { + final num c0 = (cBox[0]! as PdfNumber).value!; + final num? c1 = (cBox[1]! as PdfNumber).value; + final num c2 = (cBox[2]! as PdfNumber).value!; + final num? c3 = (cBox[3]! as PdfNumber).value; + width = (c2 - c0).toDouble(); + height = c3 != 0 ? (c3! - c1!).toDouble() : c1!.toDouble(); + } else if (mBox != null && mBox is PdfArray) { + final num m0 = (mBox[0]! as PdfNumber).value!; + final num? m1 = (mBox[1]! as PdfNumber).value; + final num m2 = (mBox[2]! as PdfNumber).value!; + final num? m3 = (mBox[3]! as PdfNumber).value; + width = (m2 - m0).toDouble(); + height = m3 != 0 ? (m3! - m1!).toDouble() : m1!.toDouble(); + } + _size = Size(width, height); + } + return _size!; + } else { + return _helper.section!.pageSettings.size; + } + } + + /// Gets a collection of the annotations of the page- Read only. + /// ```dart + /// //Creates a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Creates a rectangle annotation + /// PdfRectangleAnnotation rectangleAnnotation = PdfRectangleAnnotation( + /// Rect.fromLTWH(0, 30, 80, 80), 'Rectangle Annotation', + /// author: 'Syncfusion', + /// color: PdfColor(255, 0, 0), + /// modifiedDate: DateTime.now()); + /// //Create a new PDF page and Adds the annotation to the PDF page + /// document.pages.add().annotations.add(rectangleAnnotation); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfAnnotationCollection get annotations { + if (!_helper.isLoadedPage) { + if (_helper._annotations == null) { + _helper._annotations = PdfAnnotationCollection(this); + if (!_helper.dictionary!.containsKey(PdfDictionaryProperties.annots)) { + _helper.dictionary![PdfDictionaryProperties.annots] = + PdfAnnotationCollectionHelper.getHelper( + _helper._annotations!, + ).internalAnnotations; + } + PdfAnnotationCollectionHelper.getHelper( + _helper._annotations!, + ).internalAnnotations = + _helper.dictionary![PdfDictionaryProperties.annots] as PdfArray?; + } + } else { + if (_helper._annotations == null || _helper.importAnnotation) { + // Create the annotations. + _helper.createAnnotations(_helper.getWidgetReferences()); + } + if (_helper._annotations == null || + (PdfAnnotationCollectionHelper.getHelper( + _helper._annotations!, + ).internalAnnotations.count == + 0 && + _helper._annotations!.count != 0)) { + _helper._annotations = PdfAnnotationCollectionHelper.load(this); + } + } + return _helper._annotations!; + } + + /// Gets the graphics of the `defaultLayer`. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF page and draw the text + /// document.pages.add().graphics.drawString( + /// 'Hello World!!!', + /// PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, + /// bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGraphics get graphics { + _helper.isDefaultGraphics = true; + return defaultLayer.graphics; + } + + /// Gets the collection of the page's layers (Read only). + /// ```dart + /// //Creates a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Creates a new page + /// PdfPage page = document.pages.add(); + /// //Gets the layers from the page and Add the new layer. + /// PdfPageLayer layer = page.layers.add(name: 'Layer1'); + /// //Get the layer graphics. + /// PdfGraphics graphics = layer.graphics; + /// graphics.translateTransform(100, 60); + /// //Draw an Arc. + /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, + /// pen: PdfPen(PdfColor(250, 0, 0), width: 50)); + /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, + /// pen: PdfPen(PdfColor(0, 0, 250), width: 30)); + /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, + /// pen: PdfPen(PdfColor(250, 250, 0), width: 20)); + /// graphics.drawArc(Rect.fromLTWH(0, 0, 50, 50), 360, 360, + /// pen: PdfPen(PdfColor(0, 250, 0), width: 10)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageLayerCollection get layers { + if (!_helper.isTextExtraction && !_graphicStateUpdated) { + _layers = PdfPageLayerCollection(this); + _graphicStateUpdated = true; + } else { + _layers ??= PdfPageLayerCollection(this); + } + return _layers!; + } + + /// Gets the default layer of the page (Read only). + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF page and gets the default layer + /// PdfPageLayer defaultLayer = document.pages.add().defaultLayer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageLayer get defaultLayer => layers[defaultLayerIndex]; + + /// Gets or sets index of the default layer (Read only). + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF page and gets the default layer index + /// int layerIndex = document.pages.add().defaultLayerIndex; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get defaultLayerIndex { + if (layers.count == 0 || _defaultLayerIndex == -1) { + final PdfPageLayer layer = layers.add(); + _defaultLayerIndex = layers.indexOf(layer); + } + return _defaultLayerIndex; + } + + /// Gets or sets the tab order type for form fields + PdfFormFieldsTabOrder get formFieldsTabOrder => _formFieldsTabOrder; + set formFieldsTabOrder(PdfFormFieldsTabOrder value) { + _formFieldsTabOrder = value; + if (_formFieldsTabOrder != PdfFormFieldsTabOrder.none) { + String tabs = ' '; + if (_formFieldsTabOrder == PdfFormFieldsTabOrder.row) { + tabs = PdfDictionaryProperties.r; + } + if (_formFieldsTabOrder == PdfFormFieldsTabOrder.column) { + tabs = PdfDictionaryProperties.c; + } + if (_formFieldsTabOrder == PdfFormFieldsTabOrder.structure) { + tabs = PdfDictionaryProperties.s; + } + _helper.dictionary![PdfDictionaryProperties.tabs] = PdfName(tabs); + } + } + + /// Gets or sets the rotation of PDF page + /// + /// This property only works on existing PDF document pages + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(inputBytes: data); + /// //Rotation of the PDF page + /// PdfPageRotateAngle rotation = document.pages[0].rotation; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageRotateAngle get rotation { + _rotation ??= _obtainRotation(); + return _rotation!; + } + + set rotation(PdfPageRotateAngle angle) { + if (_helper.isLoadedPage && rotation != angle) { + _rotation = angle; + _helper.dictionary![PdfDictionaryProperties.rotate] = PdfNumber( + PdfSectionCollectionHelper.rotateFactor * angle.index, + ); + } + } + + //Public methods + /// Get the PDF page size reduced by page margins and + /// page template dimensions. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF page + /// PdfPage page = document.pages.add(); + /// //Gets the page client size + /// Size clientSize = page.getClientSize(); + /// //Draw the text to the page + /// page.graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, + /// bounds: Rect.fromLTWH(400, 600, clientSize.width, clientSize.height)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Size getClientSize() { + return _helper.isLoadedPage + ? size + : PdfSectionHelper.getHelper( + _helper.section!, + ).getActualBounds(this, true).size.size; + } + + /// Creates a template from the page content. + /// ```dart + /// //Loads an existing PDF document and create the template + /// PdfTemplate template = + /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) + /// .pages[0] + /// .createTemplate(); + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Sets the page settings margin + /// document.pageSettings.setMargins(2); + /// //Create a new PDF page + /// PdfPage page = document.pages.add(); + /// //Draw the Pdf template by using created template + /// page.graphics.drawPdfTemplate( + /// template, Offset(20, 0), Size(page.size.width / 2, page.size.height)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfTemplate createTemplate() { + return _helper._getContent(); + } + + //Implementation + + void _initialize() { + _helper.dictionary = PdfDictionary(); + _helper.dictionary![PdfDictionaryProperties.type] = PdfName('Page'); + _helper.dictionary!.beginSave = _pageBeginSave; + _size = Size.zero; + _helper.isTextExtraction = false; + _graphicStateUpdated = false; + } + + void _drawPageTemplates(PdfDocument doc) { + // Draw Background templates. + final bool hasBackTemplates = PdfSectionHelper.getHelper( + _helper.section!, + ).containsTemplates(doc, this, false); + if (hasBackTemplates) { + final PdfPageLayer backLayer = PdfPageLayerHelper.fromClipPageTemplate( + this, + false, + ); + final PdfPageLayerCollection layer = PdfPageLayerCollection(this); + _layers = layer; + _layers!.addLayer(backLayer); + PdfSectionHelper.getHelper( + _helper.section!, + ).drawTemplates(this, backLayer, doc, false); + } + + // Draw Foreground templates. + final bool hasFrontTemplates = PdfSectionHelper.getHelper( + _helper.section!, + ).containsTemplates(doc, this, true); + + if (hasFrontTemplates) { + final PdfPageLayer frontLayer = PdfPageLayerHelper.fromClipPageTemplate( + this, + false, + ); + final PdfPageLayerCollection layer = PdfPageLayerCollection(this); + _layers = layer; + _layers!.addLayer(frontLayer); + PdfSectionHelper.getHelper( + _helper.section!, + ).drawTemplates(this, frontLayer, doc, true); + } + } + + PdfPageRotateAngle _obtainRotation() { + PdfDictionary? parent = _helper.dictionary; + PdfNumber? angle; + while (parent != null && angle == null) { + if (parent.containsKey(PdfDictionaryProperties.rotate)) { + if (parent[PdfDictionaryProperties.rotate] is PdfReferenceHolder) { + angle = + (parent[PdfDictionaryProperties.rotate]! as PdfReferenceHolder) + .object + as PdfNumber?; + } else { + angle = parent[PdfDictionaryProperties.rotate] as PdfNumber?; + } + } + if (parent.containsKey(PdfDictionaryProperties.parent)) { + IPdfPrimitive? parentPrimitive = parent[PdfDictionaryProperties.parent]; + if (parentPrimitive != null) { + parentPrimitive = PdfCrossTable.dereference(parentPrimitive); + parent = + parentPrimitive != null && parentPrimitive is PdfDictionary + ? parentPrimitive + : null; + } else { + parent = null; + } + } else { + parent = null; + } + } + angle ??= PdfNumber(0); + if (angle.value!.toInt() < 0) { + angle.value = 360 + angle.value!.toInt(); + } + final PdfPageRotateAngle rotateAngle = _getRotationFromAngle( + angle.value! ~/ 90, + ); + return rotateAngle; + } + + PdfPageRotateAngle _getRotationFromAngle(int angle) { + if (angle == 1) { + return PdfPageRotateAngle.rotateAngle90; + } else if (angle == 2) { + return PdfPageRotateAngle.rotateAngle180; + } else if (angle == 3) { + return PdfPageRotateAngle.rotateAngle270; + } else { + return PdfPageRotateAngle.rotateAngle0; + } + } + + void _pageBeginSave(Object sender, SavePdfPrimitiveArgs? args) { + final PdfDocument? doc = args!.writer!.document; + if (doc != null && _helper.document != null) { + _drawPageTemplates(doc); + } + if (_helper.beginSave != null) { + _helper.beginSave!(); + } + } +} + +/// [PdfPage] helper +class PdfPageHelper { + /// internal constructor + PdfPageHelper(this.base); + + /// internal field + late PdfPage base; + + /// internal field + bool importAnnotation = false; + + /// internal method + static PdfPageHelper getHelper(PdfPage base) { + return base._helper; + } + + /// internal method + static PdfPage fromDictionary( + PdfDocument document, + PdfCrossTable crossTable, + PdfDictionary dictionary, + ) { + return PdfPage._fromDictionary(document, crossTable, dictionary); + } + + /// internal method + IPdfPrimitive? get element => dictionary; + + // ignore: unused_element + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + dictionary = value; + } + } + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal field + bool? isNewPage; + + /// internal method + PdfSection? section; + + /// internal method + bool isLoadedPage = false; + + /// internal method + PdfCrossTable? crossTable; + + /// internal method + final List terminalAnnotation = []; + + /// internal method + final PdfArray annotsReference = PdfArray(); + + /// internal method + late bool isTextExtraction; + + /// internal method + bool isDefaultGraphics = false; + + /// Raises before the page saves. + Function? beginSave; + PdfDocument? _pdfDocument; + PdfResources? _resources; + Rect _cBox = Rect.zero; + Rect _mBox = Rect.zero; + bool _checkResources = false; + PdfAnnotationCollection? _annotations; + + /// internal method + Offset get origin { + if (section != null) { + return PdfPageSettingsHelper.getHelper( + section!.pageSettings, + ).origin.offset; + } else { + return Offset.zero; + } + } + + /// internal property + PdfDocument? get document { + if (isLoadedPage || _pdfDocument != null) { + return _pdfDocument; + } else { + if (section != null) { + if (PdfSectionHelper.getHelper(section!).parent != null) { + return PdfSectionCollectionHelper.getHelper( + PdfSectionHelper.getHelper(section!).parent!, + ).document; + } else if (PdfSectionHelper.getHelper(section!).document != null) { + return PdfSectionHelper.getHelper(section!).document; + } else { + return null; + } + } else { + return null; + } + } + } + + set document(PdfDocument? value) { + _pdfDocument = value; + } + + /// Gets the crop box. + Rect get cropBox { + if (_cBox.isEmpty) { + final IPdfPrimitive? cBox = dictionary!.getValue( + PdfDictionaryProperties.cropBox, + PdfDictionaryProperties.parent, + ); + if (cBox != null && cBox is PdfArray) { + final double width = (cBox[2]! as PdfNumber).value!.toDouble(); + final double height = + (cBox[3]! as PdfNumber).value != 0 + ? (cBox[3]! as PdfNumber).value!.toDouble() + : (cBox[1]! as PdfNumber).value!.toDouble(); + final double x = (cBox[0]! as PdfNumber).value!.toDouble(); + final double y = (cBox[1]! as PdfNumber).value!.toDouble(); + _cBox = _calculateBounds(x, y, width, height); + } + } + return _cBox; + } + + /// Gets the media box. + Rect get mediaBox { + if (_mBox.isEmpty) { + final IPdfPrimitive? mBox = dictionary!.getValue( + PdfDictionaryProperties.mediaBox, + PdfDictionaryProperties.parent, + ); + if (mBox != null && mBox is PdfArray) { + final double width = (mBox[2]! as PdfNumber).value!.toDouble(); + final double height = + (mBox[3]! as PdfNumber).value != 0 + ? (mBox[3]! as PdfNumber).value!.toDouble() + : (mBox[1]! as PdfNumber).value!.toDouble(); + final double x = (mBox[0]! as PdfNumber).value!.toDouble(); + final double y = (mBox[1]! as PdfNumber).value!.toDouble(); + _mBox = _calculateBounds(x, y, width, height); + } + } + return _mBox; + } + + /// Gets array of page's content. + PdfArray get contents { + final IPdfPrimitive? contentArray = + dictionary![PdfDictionaryProperties.contents]; + PdfArray? elements; + if (contentArray is PdfReferenceHolder) { + final PdfReferenceHolder holder = contentArray; + final IPdfPrimitive? primitive = holder.object; + if (primitive is PdfArray) { + elements = primitive; + } else if (primitive is PdfStream) { + elements = PdfArray(); + elements.add(PdfReferenceHolder(primitive)); + if (!isTextExtraction) { + dictionary![PdfDictionaryProperties.contents] = elements; + } + } + } else if (contentArray is PdfArray) { + elements = contentArray; + } + if (elements == null) { + elements = PdfArray(); + if (!isTextExtraction) { + dictionary![PdfDictionaryProperties.contents] = elements; + } + } + return elements; + } + + /// internal property + PdfPageOrientation get orientation => _obtainOrientation(); + + PdfPageOrientation _obtainOrientation() { + return (base.size.width > base.size.height) + ? PdfPageOrientation.landscape + : PdfPageOrientation.portrait; + } + + Rect _calculateBounds(double x, double y, double width, double height) { + width = width - x; + if (height != y) { + height = height - y; + } + return Rect.fromLTWH(x, y, width, height); + } + + /// internal method + void assignSection(PdfSection section) { + this.section = section; + dictionary![PdfDictionaryProperties.parent] = PdfReferenceHolder(section); + } + + /// internal method + PdfResources? getResources() { + if (_resources == null) { + if (!isLoadedPage) { + _resources = PdfResources(); + dictionary![PdfDictionaryProperties.resources] = _resources; + } else { + if (!dictionary!.containsKey(PdfDictionaryProperties.resources) || + _checkResources) { + _resources = PdfResources(); + dictionary![PdfDictionaryProperties.resources] = _resources; + // Check for the resources in the corresponding page section. + if (_resources!.getNames()!.isEmpty || _resources!.items!.isEmpty) { + if (dictionary!.containsKey(PdfDictionaryProperties.parent)) { + IPdfPrimitive? obj = dictionary![PdfDictionaryProperties.parent]; + PdfDictionary? parentDic; + if (obj is PdfReferenceHolder) { + parentDic = obj.object as PdfDictionary?; + } else { + parentDic = obj as PdfDictionary?; + } + if (parentDic!.containsKey(PdfDictionaryProperties.resources)) { + obj = parentDic[PdfDictionaryProperties.resources]; + if (obj is PdfDictionary && obj.items!.isNotEmpty) { + dictionary![PdfDictionaryProperties.resources] = obj; + _resources = PdfResources(obj); + final PdfDictionary xobjects = PdfDictionary(); + if (_resources!.containsKey( + PdfDictionaryProperties.xObject, + )) { + final PdfDictionary? xObject = + _resources![PdfDictionaryProperties.xObject] + as PdfDictionary?; + + if (xObject != null) { + final IPdfPrimitive? content = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.contents], + ); + if (content != null) { + if (content is PdfArray) { + for (int i = 0; i < content.count; i++) { + final PdfStream pageContent = + PdfCrossTable.dereference(content[i])! + as PdfStream; + pageContent.decompress(); + } + } else if (content is PdfStream) { + content.decompress(); + } + } + _resources!.setProperty( + PdfDictionaryProperties.xObject, + xobjects, + ); + setResources(_resources); + } + } + } else if (obj is PdfReferenceHolder) { + bool isValueEqual = false; + final PdfDictionary pageSourceDictionary = + obj.object! as PdfDictionary; + if (pageSourceDictionary.items!.length == + _resources!.items!.length || + _resources!.items!.isEmpty) { + for (final PdfName? key in _resources!.items!.keys) { + if (pageSourceDictionary.items!.containsKey(key)) { + if (pageSourceDictionary.items!.containsValue( + _resources![key], + )) { + isValueEqual = true; + } + } else { + isValueEqual = false; + break; + } + } + if (isValueEqual || _resources!.items!.isEmpty) { + dictionary![PdfDictionaryProperties.resources] = obj; + _resources = PdfResources(obj.object as PdfDictionary?); + } + setResources(_resources); + } + } + } + } + } + } else { + final IPdfPrimitive? dicObj = + dictionary![PdfDictionaryProperties.resources]; + final PdfDictionary? dic = + crossTable!.getObject(dicObj) as PdfDictionary?; + _resources = PdfResources(dic); + dictionary![PdfDictionaryProperties.resources] = _resources; + if (dictionary!.containsKey(PdfDictionaryProperties.parent)) { + final PdfDictionary? parentDic = + PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.parent], + ) + as PdfDictionary?; + if (parentDic != null && + parentDic.containsKey(PdfDictionaryProperties.resources)) { + final IPdfPrimitive? resource = + parentDic[PdfDictionaryProperties.resources]; + if (dicObj is PdfReferenceHolder && + resource is PdfReferenceHolder && + resource.reference == dicObj.reference) { + final PdfDictionary? resourceDict = + PdfCrossTable.dereference(dicObj) as PdfDictionary?; + if (resourceDict != null) { + _resources = PdfResources(resourceDict); + } + } + } + } + setResources(_resources); + } + _checkResources = true; + } + } + return _resources; + } + + /// internal method + void setResources(PdfResources? resources) { + _resources = resources; + dictionary![PdfDictionaryProperties.resources] = _resources; + } + + /// internal method + void createAnnotations(List widgetReferences) { + IPdfPrimitive? annots; + if (dictionary!.containsKey(PdfDictionaryProperties.annots)) { + annots = crossTable!.getObject( + dictionary![PdfDictionaryProperties.annots], + ); + if (annots != null && annots is PdfArray) { + for (int count = 0; count < annots.count; ++count) { + PdfDictionary? annotDictionary; + if (crossTable!.getObject(annots[count]) is PdfDictionary) { + annotDictionary = + crossTable!.getObject(annots[count]) as PdfDictionary?; + } + PdfReferenceHolder? annotReference; + if (crossTable!.getObject(annots[count]) is PdfReferenceHolder) { + annotReference = + crossTable!.getObject(annots[count]) as PdfReferenceHolder?; + } + if (document != null && + PdfDocumentHelper.getHelper(document!).crossTable.encryptor != + null && + PdfDocumentHelper.getHelper( + document!, + ).crossTable.encryptor!.encryptAttachmentOnly!) { + if (annotDictionary != null && + annotDictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? primitive = + annotDictionary.items![PdfName( + PdfDictionaryProperties.subtype, + )]; + if (primitive is PdfName && + primitive.name == 'FileAttachment' && + annotDictionary.containsKey(PdfDictionaryProperties.fs)) { + final IPdfPrimitive? file = + annotDictionary[PdfDictionaryProperties.fs]; + if (file != null && file is PdfReferenceHolder) { + final IPdfPrimitive? streamDictionary = file.object; + if (streamDictionary != null && + streamDictionary is PdfDictionary && + streamDictionary.containsKey( + PdfDictionaryProperties.ef, + )) { + PdfDictionary? attachmentStream; + IPdfPrimitive? holder = + streamDictionary[PdfDictionaryProperties.ef]; + if (holder is PdfReferenceHolder) { + holder = holder.object; + if (holder != null && holder is PdfDictionary) { + attachmentStream = holder; + } + } else if (holder is PdfDictionary) { + attachmentStream = holder; + } + if (attachmentStream != null && + attachmentStream.containsKey( + PdfDictionaryProperties.f, + )) { + holder = attachmentStream[PdfDictionaryProperties.f]; + if (holder != null && holder is PdfReferenceHolder) { + final PdfReference? reference = holder.reference; + holder = holder.object; + if (holder != null && holder is PdfStream) { + final PdfStream encryptedObj = holder; + if (PdfDocumentHelper.getHelper( + document!, + ).isLoadedDocument) { + if (document!.onPdfPassword != null && + PdfDocumentHelper.getHelper( + document!, + ).password == + '') { + final PdfPasswordArgs args = + PdfPasswordArgsHelper.load(); + PdfDocumentHelper.getHelper( + document!, + ).setUserPassword(args); + PdfDocumentHelper.getHelper(document!).password = + args.attachmentOpenPassword; + } + PdfDocumentHelper.getHelper( + document!, + ).checkEncryption( + PdfDocumentHelper.getHelper( + document!, + ).crossTable.encryptor!.encryptAttachmentOnly, + ); + encryptedObj.decrypt( + PdfDocumentHelper.getHelper( + document!, + ).crossTable.encryptor!, + reference!.objNum, + ); + } + } + } + } + } + } + } + } + } + if (annotDictionary != null && + annotDictionary.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName? name = + annotDictionary.items![PdfName(PdfDictionaryProperties.subtype)] + as PdfName?; + if (name != null && name.name.toString() != 'Widget') { + if (!terminalAnnotation.contains(annotDictionary)) { + terminalAnnotation.add(annotDictionary); + } + } else if (name != null && name.name.toString() == 'Widget') { + if (annotDictionary.containsKey(PdfDictionaryProperties.parent)) { + final PdfDictionary? annotParentDictionary = + (annotDictionary.items![PdfName( + PdfDictionaryProperties.parent, + )]! + as PdfReferenceHolder) + .object + as PdfDictionary?; + if (annotParentDictionary != null) { + if (!annotParentDictionary.containsKey( + PdfDictionaryProperties.fields, + )) { + if (annotReference != null && + annotReference.reference != null && + !widgetReferences.contains( + annotReference.reference!.objNum, + )) { + if (!PdfFormHelper.getHelper( + document!.form, + ).terminalFields.contains(annotParentDictionary)) { + PdfFormHelper.getHelper( + document!.form, + ).terminalFields.add(annotParentDictionary); + } + } else if (annotParentDictionary.containsKey( + PdfDictionaryProperties.kids, + ) && + annotParentDictionary.count == 1) { + annotDictionary.remove(PdfDictionaryProperties.parent); + } + } else if (!annotParentDictionary.containsKey( + PdfDictionaryProperties.kids, + )) { + annotDictionary.remove(PdfDictionaryProperties.parent); + } + } + } else if (!PdfFormHelper.getHelper( + document!.form, + ).terminalFields.contains(annotDictionary)) { + Map>? widgetDictionary = + PdfFormHelper.getHelper(document!.form).widgetDictionary; + if (widgetDictionary == null) { + PdfFormHelper.getHelper(document!.form).widgetDictionary = + >{}; + widgetDictionary = + PdfFormHelper.getHelper(document!.form).widgetDictionary; + } + if (annotDictionary.containsKey(PdfDictionaryProperties.t)) { + final String? fieldName = + (annotDictionary.items![PdfName( + PdfDictionaryProperties.t, + )]! + as PdfString) + .value; + if (widgetDictionary!.containsKey(fieldName)) { + final List dict = + widgetDictionary[fieldName]!; + dict.add(annotDictionary); + } else { + if (!PdfFormFieldCollectionHelper.getHelper( + document!.form.fields, + ).addedFieldNames.contains(fieldName)) { + widgetDictionary[fieldName] = [ + annotDictionary, + ]; + } + } + } + } + } + } + if (annotReference != null && annotReference.reference != null) { + if (!annotsReference.contains(annotReference.reference!)) { + annotsReference.add(annotReference.reference!); + } + bool skip = false; + if (document != null && + widgetReferences.contains(annotReference.reference!.objNum)) { + final PdfFormFieldCollection collection = document!.form.fields; + for (int i = 0; i < collection.count; i++) { + final PdfField field = collection[i]; + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if (helper.isLoadedField) { + final IPdfPrimitive widget = helper.getWidgetAnnotation( + helper.dictionary!, + helper.crossTable, + ); + final PdfReference widgetReference = crossTable!.getReference( + widget, + ); + if (annotReference.reference!.objNum == + widgetReference.objNum && + annotReference.reference!.genNum == + widgetReference.genNum) { + skip = true; + } + } + } + } + if (annotDictionary != null && annotReference.reference != null) { + if (!widgetReferences.contains( + annotReference.reference!.objNum, + ) && + !skip) { + if (!terminalAnnotation.contains(annotDictionary)) { + terminalAnnotation.add(annotDictionary); + } + } + } + } + } + } + } + if (importAnnotation) { + importAnnotation = false; + } + _annotations = PdfAnnotationCollectionHelper.load(base); + } + + PdfTemplate _getContent() { + final List combinedData = + PdfPageLayerCollectionHelper.getHelper( + base.layers, + ).combineContent(false)!; + final PdfDictionary? resources = + PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.resources], + ) + as PdfDictionary?; + final PdfTemplate template = PdfTemplateHelper.internal( + origin, + base.size, + combinedData, + resources!, + isLoadedPage, + this, + ); + return template; + } + + /// internal method + List getWidgetReferences() { + final List widgetReferences = []; + final PdfFormFieldCollection collection = document!.form.fields; + for (int i = 0; i < collection.count; i++) { + final PdfField field = collection[i]; + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field); + if (helper.isLoadedField) { + final IPdfPrimitive widget = helper.getWidgetAnnotation( + helper.dictionary!, + helper.crossTable, + ); + final Map widgetReference = + PdfDocumentHelper.getHelper( + document!, + ).objects.getReference(widget, false); + widgetReferences.add( + ((widgetReference['isNew'] as bool) + ? crossTable!.getReference(widget).objNum + : (widgetReference['reference'] as PdfReference).objNum)! + .toSigned(64), + ); + widgetReference.clear(); + } + } + return widgetReferences; + } + + /// internal method + PdfArray? obtainAnnotations() { + final IPdfPrimitive? obj = dictionary!.getValue( + PdfDictionaryProperties.annots, + PdfDictionaryProperties.parent, + ); + return (obj != null && obj is PdfReferenceHolder ? obj.object : obj) + as PdfArray?; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_collection.dart index 88023c38f..49c2b5e7a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_collection.dart @@ -1,902 +1,902 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../forms/pdf_form_field_collection.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_margins.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/outlines/pdf_outline.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'enum.dart'; -import 'pdf_page_layer.dart'; -import 'pdf_page_settings.dart'; -import 'pdf_section.dart'; -import 'pdf_section_collection.dart'; - -/// Represents the collection of pages in a [PdfDocument] . -class PdfPageCollection { - //Constructor - /// Initializes a new instance of the [PdfPageCollection] class. - PdfPageCollection._(PdfDocument? document, [PdfSection? section]) { - if (document == null) { - throw ArgumentError.notNull('document'); - } - _helper = PdfPageCollectionHelper(this); - _helper.document = document; - if (section != null) { - _helper._section = section; - } - _helper._pageCache ??= {}; - } - - PdfPageCollection._fromCrossTable( - PdfDocument document, - PdfCrossTable crossTable, - ) { - _helper = PdfPageCollectionHelper(this); - _helper.document = document; - _helper._crossTable = crossTable; - _helper._pageCache ??= {}; - } - - //Fields - /// Represents the method that executes on a PdfDocument - /// when a new page is created. - PageAddedCallback? pageAdded; - IPdfPrimitive? _pageCatalog; - PdfDictionary? _nodeDictionary; - int _nodeCount = 0; - PdfCrossTable? _lastCrossTable; - PdfArray? _nodeKids; - int _lastPageIndex = 0; - int _lastKidIndex = 0; - late PdfPageCollectionHelper _helper; - - //Properties - /// Gets the page by index - PdfPage operator [](int index) => _returnValue(index)!; - - /// Gets the total number of the pages. - int get count { - if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { - int tempCount = 0; - final IPdfPrimitive? obj = - PdfDocumentHelper.getHelper( - _helper.document!, - ).catalog[PdfDictionaryProperties.pages]; - final PdfDictionary? node = - PdfCrossTable.dereference(obj) as PdfDictionary?; - if (node != null) { - tempCount = _getNodeCount(node); - } - return tempCount; - } else { - if (_helper._section == null) { - return _countPages(); - } else { - return PdfSectionHelper.getHelper(_helper._section!).count; - } - } - } - - //Public methods - /// Adds a new page. - PdfPage add() { - PdfPage page; - if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { - page = insert(count); - PdfPageHelper.getHelper(page).document = _helper.document; - } else { - page = PdfPage(); - PdfPageHelper.getHelper(page).isNewPage = true; - _helper.addPage(page); - PdfPageHelper.getHelper(page).isNewPage = false; - } - return page; - } - - /// Gets the index of the page. - int indexOf(PdfPage page) { - if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { - int index = -1; - final int count = this.count; - for (int i = 0; i < count; i++) { - final PdfPage? p = _returnValue(i); - if (p == page) { - index = i; - break; - } - } - return index; - } else if (_helper._section != null) { - return PdfSectionHelper.getHelper(_helper._section!).indexOf(page); - } else { - int index = -1; - int numPages = 0; - for (int i = 0; i < _helper.document!.sections!.count; i++) { - final PdfSection section = _helper.document!.sections![i]; - index = PdfSectionHelper.getHelper(section).indexOf(page); - if (index >= 0) { - index += numPages; - break; - } - numPages += PdfSectionHelper.getHelper(section).count; - } - return index; - } - } - - /// Inserts a page at the specified index to the last section in the - /// document. - /// - /// [index] - The index of the page in the section. - /// [size] - The page size. - /// [margins] - The page margin. - /// [rotation] - The PDF page rotation angle. - /// [orientation] - The PDF page orientation. - PdfPage insert( - int index, [ - Size? size, - PdfMargins? margins, - PdfPageRotateAngle? rotation, - PdfPageOrientation? orientation, - ]) { - if (size == null || size.isEmpty) { - size = PdfPageSize.a4; - } - rotation ??= PdfPageRotateAngle.rotateAngle0; - orientation ??= - (size.width > size.height) - ? PdfPageOrientation.landscape - : PdfPageOrientation.portrait; - final PdfPage page = PdfPage(); - final PdfPageSettings settings = PdfPageSettings(size, orientation); - if (margins == null) { - margins = PdfMargins(); - margins.all = PdfDocumentHelper.defaultMargin; - } - settings.margins = margins; - settings.rotate = rotation; - final PdfSection sec = PdfSectionHelper.load(_helper.document, settings); - PdfSectionHelper.getHelper(sec).dropCropBox(); - PdfSectionHelper.getHelper(sec).add(page); - PdfDictionary dic = IPdfWrapper.getElement(sec)! as PdfDictionary; - int? localIndex = 0; - final Map result = _getValidParent( - index, - localIndex, - false, - ); - final PdfDictionary parent = result['node'] as PdfDictionary; - localIndex = result['index'] as int?; - if (parent.containsKey(PdfDictionaryProperties.rotate)) { - final int rotationValue = page.rotation.index * 90; - final PdfNumber parentRotation = - parent[PdfDictionaryProperties.rotate]! as PdfNumber; - if (parentRotation.value!.toInt() != rotationValue && - (!dic.containsKey(PdfDictionaryProperties.rotate))) { - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .rotate] = PdfNumber(rotationValue); - } - } - dic[PdfDictionaryProperties.parent] = PdfReferenceHolder(parent); - final PdfArray kids = _getNodeKids(parent)!; - kids.insert(localIndex!, PdfReferenceHolder(dic)); - _updateCount(parent); - dic = IPdfWrapper.getElement(page)! as PdfDictionary; - _helper._pageCache![dic] = page; - page.graphics.colorSpace = _helper.document!.colorSpace; - PdfPageLayerHelper.getHelper( - PdfGraphicsHelper.getHelper(page.graphics).layer!, - ).colorSpace = - _helper.document!.colorSpace; - return page; - } - - /// Removes the specified page. - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData); - /// //Get the first page. - /// PdfPage page = document.pages[0]; - /// //Remove the first page. - /// document.pages.remove(page); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - void remove(PdfPage page) { - _removePage(page, indexOf(page)); - } - - /// Removes the page at the given specified index. - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData); - /// //Remove the page at index 0. - /// document.pages.removeAt(0); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - void removeAt(int index) { - if (index > -1 && index < count) { - final PdfPage? page = _returnValue(index); - _removePage(page, index); - } - } - - //Implementation - int _getNodeCount(PdfDictionary node) { - final PdfNumber? number = - _helper._crossTable!.getObject(node[PdfDictionaryProperties.count]) - as PdfNumber?; - return (number == null) ? 0 : number.value!.toInt(); - } - - PdfPage? _returnValue(int index) { - if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { - int localIndex = 0; - final Map result = _getParent(index, localIndex); - PdfDictionary node = result['node'] as PdfDictionary; - localIndex = result['index'] as int; - final PdfArray? kids = _getNodeKids(node); - int i = localIndex; - int j = 0; - while (true) { - node = - _helper._crossTable!.getObject(kids![localIndex])! as PdfDictionary; - if ((node[PdfDictionaryProperties.type]! as PdfName).name == 'Pages') { - i++; - node = _helper._crossTable!.getObject(kids[i])! as PdfDictionary; - final PdfArray? innerKids = _getNodeKids(node); - if (innerKids == null) { - break; - } - if (innerKids.count > 0) { - node = - _helper._crossTable!.getObject(innerKids[j])! as PdfDictionary; - j++; - break; - } - } else { - break; - } - } - return _helper.getPage(node); - } else { - if (_helper._section != null) { - return PdfSectionHelper.getHelper( - _helper._section!, - ).getPageByIndex(index); - } else { - if (index < 0 || index >= count) { - throw ArgumentError.value('index', 'out of range'); - } - PdfPage? page; - int sectionStartIndex = 0; - int sectionCount = 0; - int pageIndex = 0; - for (int i = 0; i < _helper.document!.sections!.count; i++) { - final PdfSection section = _helper.document!.sections![i]; - sectionCount = PdfSectionHelper.getHelper(section).count; - pageIndex = index - sectionStartIndex; - if (index >= sectionStartIndex && pageIndex < sectionCount) { - page = PdfSectionHelper.getHelper( - section, - ).getPageByIndex(pageIndex); - break; - } - sectionStartIndex += sectionCount; - } - return page; - } - } - } - - void _updateCount(PdfDictionary? parent) { - while (parent != null) { - final int count = _getNodeCount(parent) + 1; - parent[PdfDictionaryProperties.count] = PdfNumber(count); - parent = - PdfCrossTable.dereference(parent[PdfDictionaryProperties.parent]) - as PdfDictionary?; - } - } - - Map _getValidParent( - int index, - int? localIndex, - bool zeroValid, - ) { - if (index < 0 && index > count) { - throw ArgumentError.value(index, 'page index is not within range'); - } - final IPdfPrimitive? obj = - PdfDocumentHelper.getHelper( - _helper.document!, - ).catalog[PdfDictionaryProperties.pages]; - PdfDictionary node = _helper._crossTable!.getObject(obj)! as PdfDictionary; - int lowIndex = 0; - localIndex = _getNodeCount(node); - if (index == 0 && !zeroValid) { - localIndex = 0; - } else if (index < count) { - PdfArray kids = _getNodeKids(node)!; - for (int i = 0; i < kids.count; i++) { - final IPdfPrimitive? primitive = kids.elements[i]; - if (primitive != null && primitive is PdfReferenceHolder) { - final PdfReferenceHolder pageReferenceHolder = primitive; - final PdfDictionary kidsCollection = - pageReferenceHolder.object! as PdfDictionary; - final List keys = kidsCollection.items!.keys.toList(); - for (int keyIndex = 0; keyIndex < keys.length; keyIndex++) { - final PdfName key = keys[keyIndex]!; - final IPdfPrimitive? value = kidsCollection[key]; - if (key.name == 'Kids') { - PdfArray? kidValue; - if (value is PdfReferenceHolder) { - kidValue = value.object as PdfArray?; - } else { - kidValue = value as PdfArray?; - } - if (kidValue != null && kidValue.count == 0) { - kids.removeAt(i); - } - } - } - } - } - for (int i = 0, count = kids.count; i < count; ++i) { - final PdfDictionary subNode = - _helper._crossTable!.getObject(kids[i])! as PdfDictionary; - String? pageValue = - (subNode[PdfDictionaryProperties.type]! as PdfName).name; - if (_isNodeLeaf(subNode) && - !(pageValue == PdfDictionaryProperties.pages)) { - if ((lowIndex + i) == index) { - localIndex = i; - break; - } - } else { - final int nodeCount = _getNodeCount(subNode); - if (index < lowIndex + nodeCount + i) { - lowIndex += i; - node = subNode; - kids = _getNodeKids(node)!; - i = -1; - count = kids.count; - if (nodeCount == count) { - final PdfDictionary kidsSubNode = - _helper._crossTable!.getObject(kids[0])! as PdfDictionary; - pageValue = - (kidsSubNode[PdfDictionaryProperties.type]! as PdfName).name; - if (pageValue == PdfDictionaryProperties.pages) { - continue; - } else { - localIndex = index - lowIndex; - break; - } - } - continue; - } else { - lowIndex += nodeCount - 1; - } - } - } - } else { - localIndex = _getNodeKids(node)!.count; - } - return {'node': node, 'index': localIndex}; - } - - Map _getParent(int index, int? localIndex) { - if (index < 0 && index > count) { - throw ArgumentError.value(index, 'page index is not within range'); - } - _pageCatalog ??= - PdfDocumentHelper.getHelper( - _helper.document!, - ).catalog[PdfDictionaryProperties.pages]; - bool isNodeChanged = false; - PdfDictionary? node; - if (_nodeDictionary == null) { - _nodeDictionary = - _helper._crossTable!.getObject(_pageCatalog) as PdfDictionary?; - node = _nodeDictionary; - _nodeCount = _getNodeCount(node!); - _lastCrossTable = _helper._crossTable; - isNodeChanged = true; - } else if (_helper._crossTable == _lastCrossTable) { - node = _nodeDictionary; - } else { - _nodeDictionary = - _helper._crossTable!.getObject(_pageCatalog) as PdfDictionary?; - node = _nodeDictionary; - _nodeCount = _getNodeCount(node!); - _lastCrossTable = _helper._crossTable; - isNodeChanged = true; - } - localIndex = _nodeCount > 0 ? _nodeCount : _getNodeCount(node!); - if (index < count) { - PdfArray? kids; - if (_nodeKids == null || isNodeChanged) { - _nodeKids = _getNodeKids(node!); - kids = _nodeKids; - for (int i = 0; i < kids!.count; i++) { - final IPdfPrimitive? primitive = kids.elements[i]; - if (primitive != null && primitive is PdfReferenceHolder) { - final PdfReferenceHolder pageReferenceHolder = primitive; - final PdfDictionary kidsCollection = - pageReferenceHolder.object! as PdfDictionary; - final List keys = kidsCollection.items!.keys.toList(); - for (int keyIndex = 0; keyIndex < keys.length; keyIndex++) { - final PdfName key = keys[keyIndex]!; - final IPdfPrimitive? value = kidsCollection[key]; - if (key.name == 'Kids') { - PdfArray? kidValue; - if (value is PdfReferenceHolder) { - kidValue = value.object as PdfArray?; - } else { - kidValue = value as PdfArray?; - } - if (kidValue != null && kidValue.count == 0) { - kids.removeAt(i); - } - } - } - } - } - } else { - kids = _nodeKids; - } - int kidStartIndex = 0; - if ((_lastPageIndex == index - 1 || _lastPageIndex < index) && - _lastKidIndex < kids!.count) { - kidStartIndex = _lastKidIndex; - } - bool? isParentNodeFetched = false; - PdfDictionary? tempNode; - int? tempLocalIndex = 0; - - if (kids!.count == count) { - Map returnValue = _getParentNode( - kidStartIndex, - kids, - 0, - index, - tempNode, - tempLocalIndex, - isParentNodeFetched, - ); - tempNode = returnValue['tempNode'] as PdfDictionary?; - tempLocalIndex = returnValue['tempLocalIndex'] as int?; - isParentNodeFetched = returnValue['isParentNodeFetched'] as bool?; - if (!isParentNodeFetched!) { - returnValue = _getParentNode( - 0, - kids, - 0, - index, - tempNode, - tempLocalIndex, - isParentNodeFetched, - ); - tempNode = returnValue['tempNode'] as PdfDictionary?; - tempLocalIndex = returnValue['tempLocalIndex'] as int?; - isParentNodeFetched = returnValue['isParentNodeFetched'] as bool?; - } - } else { - final Map returnValue = _getParentNode( - 0, - kids, - 0, - index, - tempNode, - tempLocalIndex, - isParentNodeFetched, - ); - tempNode = returnValue['tempNode'] as PdfDictionary?; - tempLocalIndex = returnValue['tempLocalIndex'] as int?; - isParentNodeFetched = returnValue['isParentNodeFetched'] as bool?; - } - - if (tempNode != null) { - node = tempNode; - } - if (tempLocalIndex != -1) { - localIndex = tempLocalIndex; - } - } else { - localIndex = _getNodeKids(node!)!.count; - } - _lastPageIndex = index; - return {'node': node, 'index': localIndex}; - } - - PdfArray? _getNodeKids(PdfDictionary node) { - final IPdfPrimitive? obj = node[PdfDictionaryProperties.kids]; - final PdfArray? kids = _helper._crossTable!.getObject(obj) as PdfArray?; - return kids; - } - - Map _getParentNode( - int kidStartIndex, - PdfArray kids, - int lowIndex, - int pageIndex, - PdfDictionary? node, - int? localIndex, - bool? isParentFetched, - ) { - isParentFetched = false; - node = null; - localIndex = -1; - bool isNonLeafNode = false; - int tempCount = kids.count; - for (int i = kidStartIndex; i < tempCount; ++i) { - final IPdfPrimitive? primitive = _helper._crossTable!.getObject(kids[i]); - if (primitive != null && primitive is PdfDictionary) { - final PdfDictionary subNode = primitive; - final String? pageValue = - (subNode[PdfDictionaryProperties.type]! as PdfName).name; - if (_isNodeLeaf(subNode) && - !(pageValue == PdfDictionaryProperties.pages)) { - if ((lowIndex + i) == pageIndex) { - localIndex = i; - isParentFetched = true; - if (!isNonLeafNode) { - _lastKidIndex = i; - } - break; - } - } else { - final int nodeCount = _getNodeCount(subNode); - if (pageIndex < lowIndex + nodeCount + i) { - isNonLeafNode = true; - _lastKidIndex = i; - lowIndex += i; - node = subNode; - kids = _getNodeKids(node)!; - i = -1; - tempCount = kids.count; - continue; - } else { - lowIndex += nodeCount - 1; - } - } - } - } - return { - 'tempNode': node, - 'tempLocalIndex': localIndex, - 'isParentNodeFetched': isParentFetched, - }; - } - - bool _isNodeLeaf(PdfDictionary node) { - return _getNodeCount(node) == 0; - } - - int _countPages() { - final PdfSectionCollection sectionCollection = _helper.document!.sections!; - int count = 0; - for ( - int i = 0; - i < - PdfSectionCollectionHelper.getHelper( - sectionCollection, - ).sections.length; - i++ - ) { - final PdfSection section = sectionCollection[i]; - count += PdfSectionHelper.getHelper(section).count; - } - return count; - } - - void _removePage(PdfPage? page, int index) { - if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument && - index > -1) { - final Map? pageToBookmarkDic = - PdfDocumentHelper.getHelper( - _helper.document!, - ).createBookmarkDestinationDictionary(); - if (pageToBookmarkDic != null) { - List? bookmarks; - if (pageToBookmarkDic.containsKey(page)) { - bookmarks = pageToBookmarkDic[page!] as List?; - } - if (bookmarks != null) { - for (int i = 0; i < bookmarks.length; i++) { - if (bookmarks[i] is PdfBookmarkBase) { - final PdfBookmarkBase current = bookmarks[i] as PdfBookmarkBase; - if (PdfBookmarkBaseHelper.getHelper( - current, - ).dictionary!.containsKey(PdfDictionaryProperties.a)) { - PdfBookmarkBaseHelper.getHelper( - current, - ).dictionary!.remove(PdfDictionaryProperties.a); - } - if (PdfBookmarkBaseHelper.getHelper( - current, - ).dictionary!.containsKey(PdfDictionaryProperties.dest)) { - PdfBookmarkBaseHelper.getHelper( - current, - ).dictionary!.remove(PdfDictionaryProperties.dest); - } - } - } - } - } - final PdfDictionary dic = IPdfWrapper.getElement(page!)! as PdfDictionary; - int? localIndex = 0; - final Map result = _getParent(index, localIndex); - final PdfDictionary parent = result['node'] as PdfDictionary; - localIndex = result['index'] as int?; - dic[PdfDictionaryProperties.parent] = PdfReferenceHolder(parent); - PdfArray? kids = _getNodeKids(parent); - if (index == 0) { - final PdfCrossTable table = - PdfDocumentHelper.getHelper(_helper.document!).crossTable; - if (table.documentCatalog != null) { - final IPdfPrimitive? primitive = table.documentCatalog!['OpenAction']; - PdfArray? documentCatalog; - if (primitive != null) { - if (primitive is PdfArray) { - documentCatalog = primitive; - } - } - if (documentCatalog != null) { - documentCatalog.remove(PdfReferenceHolder(dic)); - } else if (primitive is PdfReferenceHolder) { - final IPdfPrimitive? documentDic = primitive.object; - if (documentDic != null && documentDic is PdfDictionary) { - if (documentDic.containsKey('D')) { - final IPdfPrimitive? documentObject = documentDic['D']; - if (documentObject != null && documentObject is PdfArray) { - for (int i = 0; i < documentObject.count; i++) { - final IPdfPrimitive? entry = documentObject[i]; - if (entry != null && entry is PdfReferenceHolder) { - final IPdfPrimitive? referenceDictionary = entry.object; - if (referenceDictionary != null && - referenceDictionary == dic) { - documentObject.remove(entry); - } - } - } - } - } - } - } - } - } - PdfReferenceHolder? remove; - for (int i = 0; i < kids!.count; i++) { - final IPdfPrimitive? holder = kids[i]; - if (holder != null && - holder is PdfReferenceHolder && - holder.object == dic) { - remove = holder; - break; - } - } - if (remove != null) { - _removeFormFields(remove); - kids.remove(remove); - if (kids.count == 0 && - parent.containsKey(PdfDictionaryProperties.parent)) { - PdfDictionary? parentDic; - IPdfPrimitive? holder = parent[PdfDictionaryProperties.parent]; - if (holder is PdfReferenceHolder) { - holder = holder.object; - if (holder != null && holder is PdfDictionary) { - parentDic = holder; - } - } else if (holder is PdfDictionary) { - parentDic = holder; - } - if (parentDic != null) { - IPdfPrimitive? kidsPrimitive = - parentDic[PdfDictionaryProperties.kids]; - if (kidsPrimitive is PdfReferenceHolder) { - kidsPrimitive = kidsPrimitive.object; - if (kidsPrimitive != null && kidsPrimitive is PdfArray) { - kids = kidsPrimitive; - } - } else if (kidsPrimitive is PdfArray) { - kids = kidsPrimitive; - } - PdfReferenceHolder? remove; - for (int i = 0; i < kids.count; i++) { - final IPdfPrimitive? holder = kids[i]; - if (holder != null && - holder is PdfReferenceHolder && - holder.object == parent) { - remove = holder; - break; - } - } - if (remove != null) { - kids.remove(remove); - } - } - } - } - _updateCountDecrement(parent); - dic.isSkip = true; - } - } - - void _removeFormFields(PdfReferenceHolder pageHolder) { - if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { - PdfFormFieldCollectionHelper.getHelper( - PdfPageCollectionHelper.getHelper(this).document!.form.fields, - ).removeContainingField(pageHolder); - } - } - - void _updateCountDecrement(PdfDictionary? parent) { - while (parent != null) { - int count = _getNodeCount(parent) - 1; - if (count == 0) { - final PdfDictionary node = parent; - final IPdfPrimitive? result = PdfCrossTable.dereference( - parent[PdfDictionaryProperties.parent], - ); - if (result != null && result is PdfDictionary) { - final IPdfPrimitive? kids = result[PdfDictionaryProperties.kids]; - if (kids != null && kids is PdfArray) { - kids.remove(PdfReferenceHolder(node)); - } - } - } - count = _getNodeCount(parent) - 1; - parent[PdfDictionaryProperties.count] = PdfNumber(count); - final IPdfPrimitive? primitive = PdfCrossTable.dereference( - parent[PdfDictionaryProperties.parent], - ); - parent = - (primitive != null && primitive is PdfDictionary) ? primitive : null; - } - } -} - -/// [PdfPageCollection] helper -class PdfPageCollectionHelper { - /// internal constructor - PdfPageCollectionHelper(this.base); - - /// internal field - late PdfPageCollection base; - - /// internal method - static PdfPageCollectionHelper getHelper(PdfPageCollection base) { - return base._helper; - } - - /// internal method - static PdfPageCollection load(PdfDocument? document, [PdfSection? section]) { - return PdfPageCollection._(document, section); - } - - /// internal method - static PdfPageCollection fromCrossTable( - PdfDocument document, - PdfCrossTable crossTable, - ) { - return PdfPageCollection._fromCrossTable(document, crossTable); - } - - /// internal field - PdfDocument? document; - - /// internal field - final Map pageCollectionIndex = {}; - int _count = 0; - PdfSection? _section; - Map? _pageCache; - PdfCrossTable? _crossTable; - - /// internal method - void addPage(PdfPage page) { - PdfSection section = _section ?? _getLastSection(); - if (_section == null) { - if (!_checkPageSettings(PdfSectionHelper.getHelper(section).settings)) { - section = document!.sections!.add(); - section.pageSettings = - PdfPageSettingsHelper.getHelper(document!.pageSettings).clone(); - } - if (!pageCollectionIndex.containsKey(page)) { - pageCollectionIndex[page] = _count++; - } - } - PdfSectionHelper.getHelper(section).add(page); - } - - PdfSection _getLastSection() { - final PdfSectionCollection sectionCollection = document!.sections!; - if (PdfSectionCollectionHelper.getHelper( - sectionCollection, - ).sections.isEmpty) { - sectionCollection.add(); - } - return sectionCollection[PdfSectionCollectionHelper.getHelper( - sectionCollection, - ).sections.length - - 1]; - } - - bool _checkPageSettings(PdfPageSettings sectionSettings) { - final PdfPageSettings docSettings = document!.pageSettings; - return sectionSettings.size == docSettings.size && - sectionSettings.orientation == docSettings.orientation && - (sectionSettings.margins.left == docSettings.margins.left && - sectionSettings.margins.top == docSettings.margins.top && - sectionSettings.margins.right == docSettings.margins.right && - sectionSettings.margins.bottom == docSettings.margins.bottom); - } - - /// internal method - bool contains(PdfPage page) { - if (_section != null) { - return PdfSectionHelper.getHelper(_section!).indexOf(page) != -1; - } else { - bool value = false; - for (int i = 0; i < document!.sections!.count; i++) { - value |= PdfPageCollectionHelper.getHelper( - document!.sections![i].pages, - ).contains(page); - } - return value; - } - } - - /// internal method - void onPageAdded(PageAddedArgs args) { - if (base.pageAdded != null) { - base.pageAdded!(base, args); - } - } - - /// internal method - void remove(PdfPage page) { - if (_section != null) { - PdfSectionHelper.getHelper(_section!).remove(page); - } else { - for (int i = 0; i < document!.sections!.count; i++) { - if (PdfPageCollectionHelper.getHelper( - document!.sections![i].pages, - ).contains(page)) { - PdfPageCollectionHelper.getHelper( - document!.sections![i].pages, - ).remove(page); - break; - } - } - } - } - - /// internal method - PdfPage getPage(PdfDictionary? dic) { - final Map pageCahce = _pageCache!; - PdfPage? page; - if (pageCahce.containsKey(dic)) { - page = pageCahce[dic]; - } - if (page == null) { - page = PdfPageHelper.fromDictionary(document!, _crossTable!, dic!); - pageCahce[dic] = page; - } - return page; - } -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../forms/pdf_form_field_collection.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_margins.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/outlines/pdf_outline.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'enum.dart'; +import 'pdf_page_layer.dart'; +import 'pdf_page_settings.dart'; +import 'pdf_section.dart'; +import 'pdf_section_collection.dart'; + +/// Represents the collection of pages in a [PdfDocument] . +class PdfPageCollection { + //Constructor + /// Initializes a new instance of the [PdfPageCollection] class. + PdfPageCollection._(PdfDocument? document, [PdfSection? section]) { + if (document == null) { + throw ArgumentError.notNull('document'); + } + _helper = PdfPageCollectionHelper(this); + _helper.document = document; + if (section != null) { + _helper._section = section; + } + _helper._pageCache ??= {}; + } + + PdfPageCollection._fromCrossTable( + PdfDocument document, + PdfCrossTable crossTable, + ) { + _helper = PdfPageCollectionHelper(this); + _helper.document = document; + _helper._crossTable = crossTable; + _helper._pageCache ??= {}; + } + + //Fields + /// Represents the method that executes on a PdfDocument + /// when a new page is created. + PageAddedCallback? pageAdded; + IPdfPrimitive? _pageCatalog; + PdfDictionary? _nodeDictionary; + int _nodeCount = 0; + PdfCrossTable? _lastCrossTable; + PdfArray? _nodeKids; + int _lastPageIndex = 0; + int _lastKidIndex = 0; + late PdfPageCollectionHelper _helper; + + //Properties + /// Gets the page by index + PdfPage operator [](int index) => _returnValue(index)!; + + /// Gets the total number of the pages. + int get count { + if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { + int tempCount = 0; + final IPdfPrimitive? obj = + PdfDocumentHelper.getHelper( + _helper.document!, + ).catalog[PdfDictionaryProperties.pages]; + final PdfDictionary? node = + PdfCrossTable.dereference(obj) as PdfDictionary?; + if (node != null) { + tempCount = _getNodeCount(node); + } + return tempCount; + } else { + if (_helper._section == null) { + return _countPages(); + } else { + return PdfSectionHelper.getHelper(_helper._section!).count; + } + } + } + + //Public methods + /// Adds a new page. + PdfPage add() { + PdfPage page; + if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { + page = insert(count); + PdfPageHelper.getHelper(page).document = _helper.document; + } else { + page = PdfPage(); + PdfPageHelper.getHelper(page).isNewPage = true; + _helper.addPage(page); + PdfPageHelper.getHelper(page).isNewPage = false; + } + return page; + } + + /// Gets the index of the page. + int indexOf(PdfPage page) { + if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { + int index = -1; + final int count = this.count; + for (int i = 0; i < count; i++) { + final PdfPage? p = _returnValue(i); + if (p == page) { + index = i; + break; + } + } + return index; + } else if (_helper._section != null) { + return PdfSectionHelper.getHelper(_helper._section!).indexOf(page); + } else { + int index = -1; + int numPages = 0; + for (int i = 0; i < _helper.document!.sections!.count; i++) { + final PdfSection section = _helper.document!.sections![i]; + index = PdfSectionHelper.getHelper(section).indexOf(page); + if (index >= 0) { + index += numPages; + break; + } + numPages += PdfSectionHelper.getHelper(section).count; + } + return index; + } + } + + /// Inserts a page at the specified index to the last section in the + /// document. + /// + /// [index] - The index of the page in the section. + /// [size] - The page size. + /// [margins] - The page margin. + /// [rotation] - The PDF page rotation angle. + /// [orientation] - The PDF page orientation. + PdfPage insert( + int index, [ + Size? size, + PdfMargins? margins, + PdfPageRotateAngle? rotation, + PdfPageOrientation? orientation, + ]) { + if (size == null || size.isEmpty) { + size = PdfPageSize.a4; + } + rotation ??= PdfPageRotateAngle.rotateAngle0; + orientation ??= + (size.width > size.height) + ? PdfPageOrientation.landscape + : PdfPageOrientation.portrait; + final PdfPage page = PdfPage(); + final PdfPageSettings settings = PdfPageSettings(size, orientation); + if (margins == null) { + margins = PdfMargins(); + margins.all = PdfDocumentHelper.defaultMargin; + } + settings.margins = margins; + settings.rotate = rotation; + final PdfSection sec = PdfSectionHelper.load(_helper.document, settings); + PdfSectionHelper.getHelper(sec).dropCropBox(); + PdfSectionHelper.getHelper(sec).add(page); + PdfDictionary dic = IPdfWrapper.getElement(sec)! as PdfDictionary; + int? localIndex = 0; + final Map result = _getValidParent( + index, + localIndex, + false, + ); + final PdfDictionary parent = result['node'] as PdfDictionary; + localIndex = result['index'] as int?; + if (parent.containsKey(PdfDictionaryProperties.rotate)) { + final int rotationValue = page.rotation.index * 90; + final PdfNumber parentRotation = + parent[PdfDictionaryProperties.rotate]! as PdfNumber; + if (parentRotation.value!.toInt() != rotationValue && + (!dic.containsKey(PdfDictionaryProperties.rotate))) { + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .rotate] = PdfNumber(rotationValue); + } + } + dic[PdfDictionaryProperties.parent] = PdfReferenceHolder(parent); + final PdfArray kids = _getNodeKids(parent)!; + kids.insert(localIndex!, PdfReferenceHolder(dic)); + _updateCount(parent); + dic = IPdfWrapper.getElement(page)! as PdfDictionary; + _helper._pageCache![dic] = page; + page.graphics.colorSpace = _helper.document!.colorSpace; + PdfPageLayerHelper.getHelper( + PdfGraphicsHelper.getHelper(page.graphics).layer!, + ).colorSpace = + _helper.document!.colorSpace; + return page; + } + + /// Removes the specified page. + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData); + /// //Get the first page. + /// PdfPage page = document.pages[0]; + /// //Remove the first page. + /// document.pages.remove(page); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + void remove(PdfPage page) { + _removePage(page, indexOf(page)); + } + + /// Removes the page at the given specified index. + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData); + /// //Remove the page at index 0. + /// document.pages.removeAt(0); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + void removeAt(int index) { + if (index > -1 && index < count) { + final PdfPage? page = _returnValue(index); + _removePage(page, index); + } + } + + //Implementation + int _getNodeCount(PdfDictionary node) { + final PdfNumber? number = + _helper._crossTable!.getObject(node[PdfDictionaryProperties.count]) + as PdfNumber?; + return (number == null) ? 0 : number.value!.toInt(); + } + + PdfPage? _returnValue(int index) { + if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { + int localIndex = 0; + final Map result = _getParent(index, localIndex); + PdfDictionary node = result['node'] as PdfDictionary; + localIndex = result['index'] as int; + final PdfArray? kids = _getNodeKids(node); + int i = localIndex; + int j = 0; + while (true) { + node = + _helper._crossTable!.getObject(kids![localIndex])! as PdfDictionary; + if ((node[PdfDictionaryProperties.type]! as PdfName).name == 'Pages') { + i++; + node = _helper._crossTable!.getObject(kids[i])! as PdfDictionary; + final PdfArray? innerKids = _getNodeKids(node); + if (innerKids == null) { + break; + } + if (innerKids.count > 0) { + node = + _helper._crossTable!.getObject(innerKids[j])! as PdfDictionary; + j++; + break; + } + } else { + break; + } + } + return _helper.getPage(node); + } else { + if (_helper._section != null) { + return PdfSectionHelper.getHelper( + _helper._section!, + ).getPageByIndex(index); + } else { + if (index < 0 || index >= count) { + throw ArgumentError.value('index', 'out of range'); + } + PdfPage? page; + int sectionStartIndex = 0; + int sectionCount = 0; + int pageIndex = 0; + for (int i = 0; i < _helper.document!.sections!.count; i++) { + final PdfSection section = _helper.document!.sections![i]; + sectionCount = PdfSectionHelper.getHelper(section).count; + pageIndex = index - sectionStartIndex; + if (index >= sectionStartIndex && pageIndex < sectionCount) { + page = PdfSectionHelper.getHelper( + section, + ).getPageByIndex(pageIndex); + break; + } + sectionStartIndex += sectionCount; + } + return page; + } + } + } + + void _updateCount(PdfDictionary? parent) { + while (parent != null) { + final int count = _getNodeCount(parent) + 1; + parent[PdfDictionaryProperties.count] = PdfNumber(count); + parent = + PdfCrossTable.dereference(parent[PdfDictionaryProperties.parent]) + as PdfDictionary?; + } + } + + Map _getValidParent( + int index, + int? localIndex, + bool zeroValid, + ) { + if (index < 0 && index > count) { + throw ArgumentError.value(index, 'page index is not within range'); + } + final IPdfPrimitive? obj = + PdfDocumentHelper.getHelper( + _helper.document!, + ).catalog[PdfDictionaryProperties.pages]; + PdfDictionary node = _helper._crossTable!.getObject(obj)! as PdfDictionary; + int lowIndex = 0; + localIndex = _getNodeCount(node); + if (index == 0 && !zeroValid) { + localIndex = 0; + } else if (index < count) { + PdfArray kids = _getNodeKids(node)!; + for (int i = 0; i < kids.count; i++) { + final IPdfPrimitive? primitive = kids.elements[i]; + if (primitive != null && primitive is PdfReferenceHolder) { + final PdfReferenceHolder pageReferenceHolder = primitive; + final PdfDictionary kidsCollection = + pageReferenceHolder.object! as PdfDictionary; + final List keys = kidsCollection.items!.keys.toList(); + for (int keyIndex = 0; keyIndex < keys.length; keyIndex++) { + final PdfName key = keys[keyIndex]!; + final IPdfPrimitive? value = kidsCollection[key]; + if (key.name == 'Kids') { + PdfArray? kidValue; + if (value is PdfReferenceHolder) { + kidValue = value.object as PdfArray?; + } else { + kidValue = value as PdfArray?; + } + if (kidValue != null && kidValue.count == 0) { + kids.removeAt(i); + } + } + } + } + } + for (int i = 0, count = kids.count; i < count; ++i) { + final PdfDictionary subNode = + _helper._crossTable!.getObject(kids[i])! as PdfDictionary; + String? pageValue = + (subNode[PdfDictionaryProperties.type]! as PdfName).name; + if (_isNodeLeaf(subNode) && + !(pageValue == PdfDictionaryProperties.pages)) { + if ((lowIndex + i) == index) { + localIndex = i; + break; + } + } else { + final int nodeCount = _getNodeCount(subNode); + if (index < lowIndex + nodeCount + i) { + lowIndex += i; + node = subNode; + kids = _getNodeKids(node)!; + i = -1; + count = kids.count; + if (nodeCount == count) { + final PdfDictionary kidsSubNode = + _helper._crossTable!.getObject(kids[0])! as PdfDictionary; + pageValue = + (kidsSubNode[PdfDictionaryProperties.type]! as PdfName).name; + if (pageValue == PdfDictionaryProperties.pages) { + continue; + } else { + localIndex = index - lowIndex; + break; + } + } + continue; + } else { + lowIndex += nodeCount - 1; + } + } + } + } else { + localIndex = _getNodeKids(node)!.count; + } + return {'node': node, 'index': localIndex}; + } + + Map _getParent(int index, int? localIndex) { + if (index < 0 && index > count) { + throw ArgumentError.value(index, 'page index is not within range'); + } + _pageCatalog ??= + PdfDocumentHelper.getHelper( + _helper.document!, + ).catalog[PdfDictionaryProperties.pages]; + bool isNodeChanged = false; + PdfDictionary? node; + if (_nodeDictionary == null) { + _nodeDictionary = + _helper._crossTable!.getObject(_pageCatalog) as PdfDictionary?; + node = _nodeDictionary; + _nodeCount = _getNodeCount(node!); + _lastCrossTable = _helper._crossTable; + isNodeChanged = true; + } else if (_helper._crossTable == _lastCrossTable) { + node = _nodeDictionary; + } else { + _nodeDictionary = + _helper._crossTable!.getObject(_pageCatalog) as PdfDictionary?; + node = _nodeDictionary; + _nodeCount = _getNodeCount(node!); + _lastCrossTable = _helper._crossTable; + isNodeChanged = true; + } + localIndex = _nodeCount > 0 ? _nodeCount : _getNodeCount(node!); + if (index < count) { + PdfArray? kids; + if (_nodeKids == null || isNodeChanged) { + _nodeKids = _getNodeKids(node!); + kids = _nodeKids; + for (int i = 0; i < kids!.count; i++) { + final IPdfPrimitive? primitive = kids.elements[i]; + if (primitive != null && primitive is PdfReferenceHolder) { + final PdfReferenceHolder pageReferenceHolder = primitive; + final PdfDictionary kidsCollection = + pageReferenceHolder.object! as PdfDictionary; + final List keys = kidsCollection.items!.keys.toList(); + for (int keyIndex = 0; keyIndex < keys.length; keyIndex++) { + final PdfName key = keys[keyIndex]!; + final IPdfPrimitive? value = kidsCollection[key]; + if (key.name == 'Kids') { + PdfArray? kidValue; + if (value is PdfReferenceHolder) { + kidValue = value.object as PdfArray?; + } else { + kidValue = value as PdfArray?; + } + if (kidValue != null && kidValue.count == 0) { + kids.removeAt(i); + } + } + } + } + } + } else { + kids = _nodeKids; + } + int kidStartIndex = 0; + if ((_lastPageIndex == index - 1 || _lastPageIndex < index) && + _lastKidIndex < kids!.count) { + kidStartIndex = _lastKidIndex; + } + bool? isParentNodeFetched = false; + PdfDictionary? tempNode; + int? tempLocalIndex = 0; + + if (kids!.count == count) { + Map returnValue = _getParentNode( + kidStartIndex, + kids, + 0, + index, + tempNode, + tempLocalIndex, + isParentNodeFetched, + ); + tempNode = returnValue['tempNode'] as PdfDictionary?; + tempLocalIndex = returnValue['tempLocalIndex'] as int?; + isParentNodeFetched = returnValue['isParentNodeFetched'] as bool?; + if (!isParentNodeFetched!) { + returnValue = _getParentNode( + 0, + kids, + 0, + index, + tempNode, + tempLocalIndex, + isParentNodeFetched, + ); + tempNode = returnValue['tempNode'] as PdfDictionary?; + tempLocalIndex = returnValue['tempLocalIndex'] as int?; + isParentNodeFetched = returnValue['isParentNodeFetched'] as bool?; + } + } else { + final Map returnValue = _getParentNode( + 0, + kids, + 0, + index, + tempNode, + tempLocalIndex, + isParentNodeFetched, + ); + tempNode = returnValue['tempNode'] as PdfDictionary?; + tempLocalIndex = returnValue['tempLocalIndex'] as int?; + isParentNodeFetched = returnValue['isParentNodeFetched'] as bool?; + } + + if (tempNode != null) { + node = tempNode; + } + if (tempLocalIndex != -1) { + localIndex = tempLocalIndex; + } + } else { + localIndex = _getNodeKids(node!)!.count; + } + _lastPageIndex = index; + return {'node': node, 'index': localIndex}; + } + + PdfArray? _getNodeKids(PdfDictionary node) { + final IPdfPrimitive? obj = node[PdfDictionaryProperties.kids]; + final PdfArray? kids = _helper._crossTable!.getObject(obj) as PdfArray?; + return kids; + } + + Map _getParentNode( + int kidStartIndex, + PdfArray kids, + int lowIndex, + int pageIndex, + PdfDictionary? node, + int? localIndex, + bool? isParentFetched, + ) { + isParentFetched = false; + node = null; + localIndex = -1; + bool isNonLeafNode = false; + int tempCount = kids.count; + for (int i = kidStartIndex; i < tempCount; ++i) { + final IPdfPrimitive? primitive = _helper._crossTable!.getObject(kids[i]); + if (primitive != null && primitive is PdfDictionary) { + final PdfDictionary subNode = primitive; + final String? pageValue = + (subNode[PdfDictionaryProperties.type]! as PdfName).name; + if (_isNodeLeaf(subNode) && + !(pageValue == PdfDictionaryProperties.pages)) { + if ((lowIndex + i) == pageIndex) { + localIndex = i; + isParentFetched = true; + if (!isNonLeafNode) { + _lastKidIndex = i; + } + break; + } + } else { + final int nodeCount = _getNodeCount(subNode); + if (pageIndex < lowIndex + nodeCount + i) { + isNonLeafNode = true; + _lastKidIndex = i; + lowIndex += i; + node = subNode; + kids = _getNodeKids(node)!; + i = -1; + tempCount = kids.count; + continue; + } else { + lowIndex += nodeCount - 1; + } + } + } + } + return { + 'tempNode': node, + 'tempLocalIndex': localIndex, + 'isParentNodeFetched': isParentFetched, + }; + } + + bool _isNodeLeaf(PdfDictionary node) { + return _getNodeCount(node) == 0; + } + + int _countPages() { + final PdfSectionCollection sectionCollection = _helper.document!.sections!; + int count = 0; + for ( + int i = 0; + i < + PdfSectionCollectionHelper.getHelper( + sectionCollection, + ).sections.length; + i++ + ) { + final PdfSection section = sectionCollection[i]; + count += PdfSectionHelper.getHelper(section).count; + } + return count; + } + + void _removePage(PdfPage? page, int index) { + if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument && + index > -1) { + final Map? pageToBookmarkDic = + PdfDocumentHelper.getHelper( + _helper.document!, + ).createBookmarkDestinationDictionary(); + if (pageToBookmarkDic != null) { + List? bookmarks; + if (pageToBookmarkDic.containsKey(page)) { + bookmarks = pageToBookmarkDic[page!] as List?; + } + if (bookmarks != null) { + for (int i = 0; i < bookmarks.length; i++) { + if (bookmarks[i] is PdfBookmarkBase) { + final PdfBookmarkBase current = bookmarks[i] as PdfBookmarkBase; + if (PdfBookmarkBaseHelper.getHelper( + current, + ).dictionary!.containsKey(PdfDictionaryProperties.a)) { + PdfBookmarkBaseHelper.getHelper( + current, + ).dictionary!.remove(PdfDictionaryProperties.a); + } + if (PdfBookmarkBaseHelper.getHelper( + current, + ).dictionary!.containsKey(PdfDictionaryProperties.dest)) { + PdfBookmarkBaseHelper.getHelper( + current, + ).dictionary!.remove(PdfDictionaryProperties.dest); + } + } + } + } + } + final PdfDictionary dic = IPdfWrapper.getElement(page!)! as PdfDictionary; + int? localIndex = 0; + final Map result = _getParent(index, localIndex); + final PdfDictionary parent = result['node'] as PdfDictionary; + localIndex = result['index'] as int?; + dic[PdfDictionaryProperties.parent] = PdfReferenceHolder(parent); + PdfArray? kids = _getNodeKids(parent); + if (index == 0) { + final PdfCrossTable table = + PdfDocumentHelper.getHelper(_helper.document!).crossTable; + if (table.documentCatalog != null) { + final IPdfPrimitive? primitive = table.documentCatalog!['OpenAction']; + PdfArray? documentCatalog; + if (primitive != null) { + if (primitive is PdfArray) { + documentCatalog = primitive; + } + } + if (documentCatalog != null) { + documentCatalog.remove(PdfReferenceHolder(dic)); + } else if (primitive is PdfReferenceHolder) { + final IPdfPrimitive? documentDic = primitive.object; + if (documentDic != null && documentDic is PdfDictionary) { + if (documentDic.containsKey('D')) { + final IPdfPrimitive? documentObject = documentDic['D']; + if (documentObject != null && documentObject is PdfArray) { + for (int i = 0; i < documentObject.count; i++) { + final IPdfPrimitive? entry = documentObject[i]; + if (entry != null && entry is PdfReferenceHolder) { + final IPdfPrimitive? referenceDictionary = entry.object; + if (referenceDictionary != null && + referenceDictionary == dic) { + documentObject.remove(entry); + } + } + } + } + } + } + } + } + } + PdfReferenceHolder? remove; + for (int i = 0; i < kids!.count; i++) { + final IPdfPrimitive? holder = kids[i]; + if (holder != null && + holder is PdfReferenceHolder && + holder.object == dic) { + remove = holder; + break; + } + } + if (remove != null) { + _removeFormFields(remove); + kids.remove(remove); + if (kids.count == 0 && + parent.containsKey(PdfDictionaryProperties.parent)) { + PdfDictionary? parentDic; + IPdfPrimitive? holder = parent[PdfDictionaryProperties.parent]; + if (holder is PdfReferenceHolder) { + holder = holder.object; + if (holder != null && holder is PdfDictionary) { + parentDic = holder; + } + } else if (holder is PdfDictionary) { + parentDic = holder; + } + if (parentDic != null) { + IPdfPrimitive? kidsPrimitive = + parentDic[PdfDictionaryProperties.kids]; + if (kidsPrimitive is PdfReferenceHolder) { + kidsPrimitive = kidsPrimitive.object; + if (kidsPrimitive != null && kidsPrimitive is PdfArray) { + kids = kidsPrimitive; + } + } else if (kidsPrimitive is PdfArray) { + kids = kidsPrimitive; + } + PdfReferenceHolder? remove; + for (int i = 0; i < kids.count; i++) { + final IPdfPrimitive? holder = kids[i]; + if (holder != null && + holder is PdfReferenceHolder && + holder.object == parent) { + remove = holder; + break; + } + } + if (remove != null) { + kids.remove(remove); + } + } + } + } + _updateCountDecrement(parent); + dic.isSkip = true; + } + } + + void _removeFormFields(PdfReferenceHolder pageHolder) { + if (PdfDocumentHelper.getHelper(_helper.document!).isLoadedDocument) { + PdfFormFieldCollectionHelper.getHelper( + PdfPageCollectionHelper.getHelper(this).document!.form.fields, + ).removeContainingField(pageHolder); + } + } + + void _updateCountDecrement(PdfDictionary? parent) { + while (parent != null) { + int count = _getNodeCount(parent) - 1; + if (count == 0) { + final PdfDictionary node = parent; + final IPdfPrimitive? result = PdfCrossTable.dereference( + parent[PdfDictionaryProperties.parent], + ); + if (result != null && result is PdfDictionary) { + final IPdfPrimitive? kids = result[PdfDictionaryProperties.kids]; + if (kids != null && kids is PdfArray) { + kids.remove(PdfReferenceHolder(node)); + } + } + } + count = _getNodeCount(parent) - 1; + parent[PdfDictionaryProperties.count] = PdfNumber(count); + final IPdfPrimitive? primitive = PdfCrossTable.dereference( + parent[PdfDictionaryProperties.parent], + ); + parent = + (primitive != null && primitive is PdfDictionary) ? primitive : null; + } + } +} + +/// [PdfPageCollection] helper +class PdfPageCollectionHelper { + /// internal constructor + PdfPageCollectionHelper(this.base); + + /// internal field + late PdfPageCollection base; + + /// internal method + static PdfPageCollectionHelper getHelper(PdfPageCollection base) { + return base._helper; + } + + /// internal method + static PdfPageCollection load(PdfDocument? document, [PdfSection? section]) { + return PdfPageCollection._(document, section); + } + + /// internal method + static PdfPageCollection fromCrossTable( + PdfDocument document, + PdfCrossTable crossTable, + ) { + return PdfPageCollection._fromCrossTable(document, crossTable); + } + + /// internal field + PdfDocument? document; + + /// internal field + final Map pageCollectionIndex = {}; + int _count = 0; + PdfSection? _section; + Map? _pageCache; + PdfCrossTable? _crossTable; + + /// internal method + void addPage(PdfPage page) { + PdfSection section = _section ?? _getLastSection(); + if (_section == null) { + if (!_checkPageSettings(PdfSectionHelper.getHelper(section).settings)) { + section = document!.sections!.add(); + section.pageSettings = + PdfPageSettingsHelper.getHelper(document!.pageSettings).clone(); + } + if (!pageCollectionIndex.containsKey(page)) { + pageCollectionIndex[page] = _count++; + } + } + PdfSectionHelper.getHelper(section).add(page); + } + + PdfSection _getLastSection() { + final PdfSectionCollection sectionCollection = document!.sections!; + if (PdfSectionCollectionHelper.getHelper( + sectionCollection, + ).sections.isEmpty) { + sectionCollection.add(); + } + return sectionCollection[PdfSectionCollectionHelper.getHelper( + sectionCollection, + ).sections.length - + 1]; + } + + bool _checkPageSettings(PdfPageSettings sectionSettings) { + final PdfPageSettings docSettings = document!.pageSettings; + return sectionSettings.size == docSettings.size && + sectionSettings.orientation == docSettings.orientation && + (sectionSettings.margins.left == docSettings.margins.left && + sectionSettings.margins.top == docSettings.margins.top && + sectionSettings.margins.right == docSettings.margins.right && + sectionSettings.margins.bottom == docSettings.margins.bottom); + } + + /// internal method + bool contains(PdfPage page) { + if (_section != null) { + return PdfSectionHelper.getHelper(_section!).indexOf(page) != -1; + } else { + bool value = false; + for (int i = 0; i < document!.sections!.count; i++) { + value |= PdfPageCollectionHelper.getHelper( + document!.sections![i].pages, + ).contains(page); + } + return value; + } + } + + /// internal method + void onPageAdded(PageAddedArgs args) { + if (base.pageAdded != null) { + base.pageAdded!(base, args); + } + } + + /// internal method + void remove(PdfPage page) { + if (_section != null) { + PdfSectionHelper.getHelper(_section!).remove(page); + } else { + for (int i = 0; i < document!.sections!.count; i++) { + if (PdfPageCollectionHelper.getHelper( + document!.sections![i].pages, + ).contains(page)) { + PdfPageCollectionHelper.getHelper( + document!.sections![i].pages, + ).remove(page); + break; + } + } + } + } + + /// internal method + PdfPage getPage(PdfDictionary? dic) { + final Map pageCahce = _pageCache!; + PdfPage? page; + if (pageCahce.containsKey(dic)) { + page = pageCahce[dic]; + } + if (page == null) { + page = PdfPageHelper.fromDictionary(document!, _crossTable!, dic!); + pageCahce[dic] = page; + } + return page; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer.dart index 6595a777a..ff7328b7e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer.dart @@ -1,565 +1,565 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../graphics/enums.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_margins.dart'; -import '../graphics/pdf_resources.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import 'enum.dart'; -import 'pdf_section.dart'; -import 'pdf_section_collection.dart'; - -/// The [PdfPageLayer] used to create layers in PDF document. -/// Layers refers to sections of content in a PDF document that can be -/// selectively viewed or hidden by document authors or consumers. -class PdfPageLayer implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfPageLayer] class - /// with specified PDF page. - PdfPageLayer(PdfPage pdfPage) { - _helper = PdfPageLayerHelper(this); - _initialize(pdfPage, true); - } - - PdfPageLayer._fromClipPageTemplate( - PdfPage pdfPage, [ - bool? clipPageTemplates, - ]) { - _helper = PdfPageLayerHelper(this); - _initialize(pdfPage, clipPageTemplates); - } - - //Fields - late PdfPageLayerHelper _helper; - late PdfPage _page; - bool? _clipPageTemplates; - String? _name; - PdfGraphicsState? _graphicsState; - bool _isEndState = false; - bool _isSaved = false; - bool _visible = true; - - //Properties - /// Gets parent page of the layer. - PdfPage get page => _page; - - /// Gets Graphics context of the layer, used to draw various graphical - /// content on layer. - PdfGraphics get graphics { - if (_helper.graphics == null || _isSaved) { - _initializeGraphics(page); - } - return _helper.graphics!; - } - - /// Gets the name of the layer - String? get name { - return _name; - } - - /// Sets the name of the layer - set name(String? value) { - if (value != null) { - _name = value; - _helper.layerID ??= 'OCG_${PdfResources.globallyUniqueIdentifier}'; - } - } - - /// Gets the visibility of the page layer. - bool get visible { - if (_helper.dictionary != null && - _helper.dictionary!.containsKey(PdfDictionaryProperties.visible)) { - _visible = - (_helper.dictionary![PdfDictionaryProperties.visible]! as PdfBoolean) - .value!; - } - return _visible; - } - - /// Sets the visibility of the page layer. - set visible(bool value) { - _visible = value; - if (_helper.dictionary != null) { - _helper.dictionary![PdfDictionaryProperties.visible] = PdfBoolean(value); - } - _setVisibility(_visible); - } - - //Implementation - void _initialize(PdfPage? pdfPage, bool? clipPageTemplates) { - if (pdfPage != null) { - _page = pdfPage; - } else { - throw ArgumentError.value(pdfPage, 'page'); - } - _clipPageTemplates = clipPageTemplates; - _helper._content = PdfStream(); - _helper.dictionary = PdfDictionary(); - } - - void _initializeGraphics(PdfPage? page) { - if (_helper.graphics == null) { - final Function resources = PdfPageHelper.getHelper(page!).getResources; - bool isPageHasMediaBox = false; - bool isInvalidSize = false; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfName(PdfDictionaryProperties.mediaBox))) { - isPageHasMediaBox = true; - } - double llx = 0; - double lly = 0; - double urx = 0; - double ury = 0; - final PdfArray? mediaBox = - PdfPageHelper.getHelper(page).dictionary!.getValue( - PdfDictionaryProperties.mediaBox, - PdfDictionaryProperties.parent, - ) - as PdfArray?; - final PdfReferenceHolder referenceHolder = PdfReferenceHolder(this); - if (mediaBox != null) { - // Lower Left X co-ordinate Value. - llx = (mediaBox[0]! as PdfNumber).value!.toDouble(); - // Lower Left Y co-ordinate value. - lly = (mediaBox[1]! as PdfNumber).value!.toDouble(); - // Upper right X co-ordinate value. - urx = (mediaBox[2]! as PdfNumber).value!.toDouble(); - // Upper right Y co-ordinate value. - ury = (mediaBox[3]! as PdfNumber).value!.toDouble(); - } - PdfArray? cropBox; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { - cropBox = - PdfPageHelper.getHelper(page).dictionary!.getValue( - PdfDictionaryProperties.cropBox, - PdfDictionaryProperties.parent, - ) - as PdfArray?; - final double cropX = (cropBox![0]! as PdfNumber).value!.toDouble(); - final double cropY = (cropBox[1]! as PdfNumber).value!.toDouble(); - final double cropRX = (cropBox[2]! as PdfNumber).value!.toDouble(); - final double cropRY = (cropBox[3]! as PdfNumber).value!.toDouble(); - if ((cropX < 0 || cropY < 0 || cropRX < 0 || cropRY < 0) && - (cropY.abs().floor() == page.size.height.abs().floor()) && - (cropX.abs().floor()) == page.size.width.abs().floor()) { - final Size pageSize = Size( - [cropX, cropRX].reduce(max), - [cropY, cropRY].reduce(max), - ); - _helper.graphics = PdfGraphicsHelper.load( - pageSize, - resources, - _helper._content!, - ); - if (!PdfPageHelper.getHelper( - page, - ).contents.contains(referenceHolder) && - !PdfPageHelper.getHelper(page).isDefaultGraphics && - !_isContainsPageContent( - PdfPageHelper.getHelper(page).contents, - referenceHolder, - )) { - PdfPageHelper.getHelper(page).contents.add(referenceHolder); - } - } else { - _helper.graphics = PdfGraphicsHelper.load( - page.size, - resources, - _helper._content!, - ); - PdfGraphicsHelper.getHelper(_helper.graphics!).cropBox = cropBox; - if (!PdfPageHelper.getHelper( - page, - ).contents.contains(referenceHolder) && - !PdfPageHelper.getHelper(page).isDefaultGraphics && - !_isContainsPageContent( - PdfPageHelper.getHelper(page).contents, - referenceHolder, - )) { - PdfPageHelper.getHelper(page).contents.add(referenceHolder); - } - } - } else if ((llx < 0 || lly < 0 || urx < 0 || ury < 0) && - (lly.abs().floor() == page.size.height.abs().floor()) && - (urx.abs().floor() == page.size.width.abs().floor())) { - Size pageSize = Size( - [llx, urx].reduce(max), - [lly, ury].reduce(max), - ); - if (pageSize.width <= 0 || pageSize.height <= 0) { - isInvalidSize = true; - if (llx < 0) { - llx = -llx; - } else if (urx < 0) { - urx = -urx; - } - if (lly < 0) { - lly = -lly; - } else if (ury < 0) { - ury = -ury; - } - pageSize = Size( - [llx, urx].reduce(max), - [lly, ury].reduce(max), - ); - _helper.graphics = PdfGraphicsHelper.load( - pageSize, - resources, - _helper._content!, - ); - if (!PdfPageHelper.getHelper( - page, - ).contents.contains(referenceHolder) && - !PdfPageHelper.getHelper(page).isDefaultGraphics && - !_isContainsPageContent( - PdfPageHelper.getHelper(page).contents, - referenceHolder, - )) { - PdfPageHelper.getHelper(page).contents.add(referenceHolder); - } - } - } else { - _helper.graphics = PdfGraphicsHelper.load( - page.size, - resources, - _helper._content!, - ); - if (!PdfPageHelper.getHelper(page).contents.contains(referenceHolder) && - !PdfPageHelper.getHelper(page).isDefaultGraphics && - !_isContainsPageContent( - PdfPageHelper.getHelper(page).contents, - referenceHolder, - )) { - PdfPageHelper.getHelper(page).contents.add(referenceHolder); - } - } - - if (isPageHasMediaBox) { - PdfGraphicsHelper.getHelper(_helper.graphics!).mediaBoxUpperRightBound = - isInvalidSize ? -lly : ury; - } - if (!PdfPageHelper.getHelper(page).isLoadedPage) { - final PdfSectionCollection? sectionCollection = - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page).section!, - ).parent; - if (sectionCollection != null) { - _helper.graphics!.colorSpace = - PdfSectionCollectionHelper.getHelper( - sectionCollection, - ).document!.colorSpace; - _helper.colorSpace = - PdfSectionCollectionHelper.getHelper( - sectionCollection, - ).document!.colorSpace; - } - } - _helper._content!.beginSave = _beginSaveContent; - } - _graphicsState = _helper.graphics!.save(); - if (name != null && name!.isNotEmpty) { - PdfGraphicsHelper.getHelper( - _helper.graphics!, - ).streamWriter!.write('/OC /${_helper.layerID!} BDC\n'); - _isEndState = true; - } - PdfGraphicsHelper.getHelper(_helper.graphics!).initializeCoordinates(); - if (PdfGraphicsHelper.getHelper(_helper.graphics!).hasTransparencyBrush) { - PdfGraphicsHelper.getHelper( - _helper.graphics!, - ).setTransparencyGroup(page!); - } - if (page != null && - (!PdfPageHelper.getHelper(page).isLoadedPage) && - (page.rotation != PdfPageRotateAngle.rotateAngle0 || - PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.rotate))) { - PdfArray? cropBox; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { - cropBox = - PdfPageHelper.getHelper(page).dictionary!.getValue( - PdfDictionaryProperties.cropBox, - PdfDictionaryProperties.parent, - ) - as PdfArray?; - } - _updatePageRotation(page, _helper.graphics, cropBox); - } - if (page != null && !PdfPageHelper.getHelper(page).isLoadedPage) { - final PdfRectangle clipRect = PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page).section!, - ).getActualBounds(page, true); - if (_clipPageTemplates!) { - if (PdfPageHelper.getHelper(page).origin.dx >= 0 && - PdfPageHelper.getHelper(page).origin.dy >= 0) { - PdfGraphicsHelper.getHelper( - _helper.graphics!, - ).clipTranslateMarginsWithBounds(clipRect); - } - } else { - final PdfMargins margins = - PdfPageHelper.getHelper(page).section!.pageSettings.margins; - PdfGraphicsHelper.getHelper(_helper.graphics!).clipTranslateMargins( - clipRect.x, - clipRect.y, - margins.left, - margins.top, - margins.right, - margins.bottom, - ); - } - } - PdfGraphicsHelper.getHelper(_helper.graphics!).setLayer(this); - _isSaved = false; - } - - void _updatePageRotation( - PdfPage page, - PdfGraphics? graphics, - PdfArray? cropBox, - ) { - PdfNumber? rotation; - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.rotate)) { - rotation = - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .rotate] - as PdfNumber?; - rotation ??= - rotation = - PdfCrossTable.dereference( - PdfPageHelper.getHelper( - page, - ).dictionary![PdfDictionaryProperties.rotate], - ) - as PdfNumber?; - } else if (page.rotation != PdfPageRotateAngle.rotateAngle0) { - if (page.rotation == PdfPageRotateAngle.rotateAngle90) { - rotation = PdfNumber(90); - } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { - rotation = PdfNumber(180); - } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { - rotation = PdfNumber(270); - } - } - if (rotation!.value == 90) { - graphics!.translateTransform(0, page.size.height); - graphics.rotateTransform(-90); - if (cropBox != null) { - final double height = (cropBox[3]! as PdfNumber).value!.toDouble(); - final Size cropBoxSize = Size( - (cropBox[2]! as PdfNumber).value!.toDouble(), - height != 0 ? height : (cropBox[1]! as PdfNumber).value!.toDouble(), - ); - final Offset cropBoxOffset = Offset( - (cropBox[0]! as PdfNumber).value!.toDouble(), - (cropBox[1]! as PdfNumber).value!.toDouble(), - ); - if (page.size.height < cropBoxSize.height) { - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - page.size.height - cropBoxOffset.dy, - cropBoxSize.width - cropBoxOffset.dx, - ); - } else { - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - cropBoxSize.height - cropBoxOffset.dy, - cropBoxSize.width - cropBoxOffset.dx, - ); - } - } else { - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - page.size.height, - page.size.width, - ); - } - } else if (rotation.value == 180) { - graphics!.translateTransform(page.size.width, page.size.height); - graphics.rotateTransform(-180); - } else if (rotation.value == 270) { - graphics!.translateTransform(page.size.width, 0); - graphics.rotateTransform(-270); - PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( - page.size.height, - page.size.width, - ); - } - } - - void _beginSaveContent(Object sender, SavePdfPrimitiveArgs? args) { - if (_graphicsState != null) { - if (_isEndState) { - PdfGraphicsHelper.getHelper( - _helper.graphics!, - ).streamWriter!.write('EMC\n'); - _isEndState = false; - } - graphics.restore(_graphicsState); - _graphicsState = null; - } - _isSaved = true; - } - - void _setVisibility(bool? value) { - PdfDictionary? oCProperties; - if (PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_page).document!, - ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { - oCProperties = - PdfCrossTable.dereference( - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_page).document!, - ).catalog[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - } - if (oCProperties != null) { - final PdfDictionary? defaultView = - oCProperties[PdfDictionaryProperties.defaultView] as PdfDictionary?; - if (defaultView != null) { - PdfArray? ocgON = - defaultView[PdfDictionaryProperties.ocgOn] as PdfArray?; - PdfArray? ocgOFF = - defaultView[PdfDictionaryProperties.ocgOff] as PdfArray?; - if (_helper.referenceHolder != null) { - if (value == false) { - if (ocgON != null) { - _removeContent(ocgON, _helper.referenceHolder); - } - if (ocgOFF == null) { - ocgOFF = PdfArray(); - defaultView.items![PdfName(PdfDictionaryProperties.ocgOff)] = - ocgOFF; - } - ocgOFF.insert(ocgOFF.count, _helper.referenceHolder!); - } else if (value ?? true) { - if (ocgOFF != null) { - _removeContent(ocgOFF, _helper.referenceHolder); - } - if (ocgON == null) { - ocgON = PdfArray(); - defaultView.items![PdfName(PdfDictionaryProperties.ocgOn)] = - ocgON; - } - ocgON.insert(ocgON.count, _helper.referenceHolder!); - } - } - } - } - } - - bool _isContainsPageContent( - PdfArray content, - PdfReferenceHolder referenceHolder, - ) { - for (int i = 0; i < content.count; i++) { - final IPdfPrimitive? primitive = content.elements[i]; - if (primitive != null && primitive is PdfReferenceHolder) { - final PdfReferenceHolder holder = primitive; - if (holder.reference != null && referenceHolder.reference != null) { - if (holder.reference!.objNum == referenceHolder.reference!.objNum) { - return true; - } - } else { - if (identical(holder, referenceHolder)) { - return true; - } else if (identical(holder.object, referenceHolder.object)) { - return true; - } - } - } - } - return false; - } - - void _removeContent(PdfArray content, PdfReferenceHolder? referenceHolder) { - bool flag = false; - for (int i = 0; i < content.count; i++) { - final IPdfPrimitive? primitive = content.elements[i]; - if (primitive != null && primitive is PdfReferenceHolder) { - final PdfReferenceHolder holder = primitive; - if (holder.reference != null && referenceHolder!.reference != null) { - if (holder.reference!.objNum == referenceHolder.reference!.objNum) { - content.elements.removeAt(i); - flag = true; - i--; - } - } - } - } - if (flag) { - content.changed = true; - } - } -} - -/// [PdfPageLayer] helper -class PdfPageLayerHelper { - /// internal constructor - PdfPageLayerHelper(this.base); - - /// internal field - late PdfPageLayer base; - PdfStream? _content; - - /// internal method - static PdfPageLayerHelper getHelper(PdfPageLayer base) { - return base._helper; - } - - /// internal method - static PdfPageLayer fromClipPageTemplate( - PdfPage pdfPage, [ - bool? clipPageTemplates, - ]) { - return PdfPageLayer._fromClipPageTemplate(pdfPage, clipPageTemplates); - } - - /// internal property - IPdfPrimitive? get element => _content; - //ignore: unused_element - set element(IPdfPrimitive? value) { - _content = value as PdfStream?; - } - - /// internal field - //ignore:unused_field - PdfColorSpace? colorSpace; - - /// internal field - PdfDictionary? dictionary; - - /// internal field - String? layerID; - - /// internal field - PdfDictionary? printOption; - - /// internal field - PdfDictionary? usage; - - /// internal field - PdfReferenceHolder? referenceHolder; - - /// internal field - PdfGraphics? graphics; -} +import 'dart:math'; +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../graphics/enums.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_margins.dart'; +import '../graphics/pdf_resources.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import 'enum.dart'; +import 'pdf_section.dart'; +import 'pdf_section_collection.dart'; + +/// The [PdfPageLayer] used to create layers in PDF document. +/// Layers refers to sections of content in a PDF document that can be +/// selectively viewed or hidden by document authors or consumers. +class PdfPageLayer implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfPageLayer] class + /// with specified PDF page. + PdfPageLayer(PdfPage pdfPage) { + _helper = PdfPageLayerHelper(this); + _initialize(pdfPage, true); + } + + PdfPageLayer._fromClipPageTemplate( + PdfPage pdfPage, [ + bool? clipPageTemplates, + ]) { + _helper = PdfPageLayerHelper(this); + _initialize(pdfPage, clipPageTemplates); + } + + //Fields + late PdfPageLayerHelper _helper; + late PdfPage _page; + bool? _clipPageTemplates; + String? _name; + PdfGraphicsState? _graphicsState; + bool _isEndState = false; + bool _isSaved = false; + bool _visible = true; + + //Properties + /// Gets parent page of the layer. + PdfPage get page => _page; + + /// Gets Graphics context of the layer, used to draw various graphical + /// content on layer. + PdfGraphics get graphics { + if (_helper.graphics == null || _isSaved) { + _initializeGraphics(page); + } + return _helper.graphics!; + } + + /// Gets the name of the layer + String? get name { + return _name; + } + + /// Sets the name of the layer + set name(String? value) { + if (value != null) { + _name = value; + _helper.layerID ??= 'OCG_${PdfResources.globallyUniqueIdentifier}'; + } + } + + /// Gets the visibility of the page layer. + bool get visible { + if (_helper.dictionary != null && + _helper.dictionary!.containsKey(PdfDictionaryProperties.visible)) { + _visible = + (_helper.dictionary![PdfDictionaryProperties.visible]! as PdfBoolean) + .value!; + } + return _visible; + } + + /// Sets the visibility of the page layer. + set visible(bool value) { + _visible = value; + if (_helper.dictionary != null) { + _helper.dictionary![PdfDictionaryProperties.visible] = PdfBoolean(value); + } + _setVisibility(_visible); + } + + //Implementation + void _initialize(PdfPage? pdfPage, bool? clipPageTemplates) { + if (pdfPage != null) { + _page = pdfPage; + } else { + throw ArgumentError.value(pdfPage, 'page'); + } + _clipPageTemplates = clipPageTemplates; + _helper._content = PdfStream(); + _helper.dictionary = PdfDictionary(); + } + + void _initializeGraphics(PdfPage? page) { + if (_helper.graphics == null) { + final Function resources = PdfPageHelper.getHelper(page!).getResources; + bool isPageHasMediaBox = false; + bool isInvalidSize = false; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfName(PdfDictionaryProperties.mediaBox))) { + isPageHasMediaBox = true; + } + double llx = 0; + double lly = 0; + double urx = 0; + double ury = 0; + final PdfArray? mediaBox = + PdfPageHelper.getHelper(page).dictionary!.getValue( + PdfDictionaryProperties.mediaBox, + PdfDictionaryProperties.parent, + ) + as PdfArray?; + final PdfReferenceHolder referenceHolder = PdfReferenceHolder(this); + if (mediaBox != null) { + // Lower Left X co-ordinate Value. + llx = (mediaBox[0]! as PdfNumber).value!.toDouble(); + // Lower Left Y co-ordinate value. + lly = (mediaBox[1]! as PdfNumber).value!.toDouble(); + // Upper right X co-ordinate value. + urx = (mediaBox[2]! as PdfNumber).value!.toDouble(); + // Upper right Y co-ordinate value. + ury = (mediaBox[3]! as PdfNumber).value!.toDouble(); + } + PdfArray? cropBox; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { + cropBox = + PdfPageHelper.getHelper(page).dictionary!.getValue( + PdfDictionaryProperties.cropBox, + PdfDictionaryProperties.parent, + ) + as PdfArray?; + final double cropX = (cropBox![0]! as PdfNumber).value!.toDouble(); + final double cropY = (cropBox[1]! as PdfNumber).value!.toDouble(); + final double cropRX = (cropBox[2]! as PdfNumber).value!.toDouble(); + final double cropRY = (cropBox[3]! as PdfNumber).value!.toDouble(); + if ((cropX < 0 || cropY < 0 || cropRX < 0 || cropRY < 0) && + (cropY.abs().floor() == page.size.height.abs().floor()) && + (cropX.abs().floor()) == page.size.width.abs().floor()) { + final Size pageSize = Size( + [cropX, cropRX].reduce(max), + [cropY, cropRY].reduce(max), + ); + _helper.graphics = PdfGraphicsHelper.load( + pageSize, + resources, + _helper._content!, + ); + if (!PdfPageHelper.getHelper( + page, + ).contents.contains(referenceHolder) && + !PdfPageHelper.getHelper(page).isDefaultGraphics && + !_isContainsPageContent( + PdfPageHelper.getHelper(page).contents, + referenceHolder, + )) { + PdfPageHelper.getHelper(page).contents.add(referenceHolder); + } + } else { + _helper.graphics = PdfGraphicsHelper.load( + page.size, + resources, + _helper._content!, + ); + PdfGraphicsHelper.getHelper(_helper.graphics!).cropBox = cropBox; + if (!PdfPageHelper.getHelper( + page, + ).contents.contains(referenceHolder) && + !PdfPageHelper.getHelper(page).isDefaultGraphics && + !_isContainsPageContent( + PdfPageHelper.getHelper(page).contents, + referenceHolder, + )) { + PdfPageHelper.getHelper(page).contents.add(referenceHolder); + } + } + } else if ((llx < 0 || lly < 0 || urx < 0 || ury < 0) && + (lly.abs().floor() == page.size.height.abs().floor()) && + (urx.abs().floor() == page.size.width.abs().floor())) { + Size pageSize = Size( + [llx, urx].reduce(max), + [lly, ury].reduce(max), + ); + if (pageSize.width <= 0 || pageSize.height <= 0) { + isInvalidSize = true; + if (llx < 0) { + llx = -llx; + } else if (urx < 0) { + urx = -urx; + } + if (lly < 0) { + lly = -lly; + } else if (ury < 0) { + ury = -ury; + } + pageSize = Size( + [llx, urx].reduce(max), + [lly, ury].reduce(max), + ); + _helper.graphics = PdfGraphicsHelper.load( + pageSize, + resources, + _helper._content!, + ); + if (!PdfPageHelper.getHelper( + page, + ).contents.contains(referenceHolder) && + !PdfPageHelper.getHelper(page).isDefaultGraphics && + !_isContainsPageContent( + PdfPageHelper.getHelper(page).contents, + referenceHolder, + )) { + PdfPageHelper.getHelper(page).contents.add(referenceHolder); + } + } + } else { + _helper.graphics = PdfGraphicsHelper.load( + page.size, + resources, + _helper._content!, + ); + if (!PdfPageHelper.getHelper(page).contents.contains(referenceHolder) && + !PdfPageHelper.getHelper(page).isDefaultGraphics && + !_isContainsPageContent( + PdfPageHelper.getHelper(page).contents, + referenceHolder, + )) { + PdfPageHelper.getHelper(page).contents.add(referenceHolder); + } + } + + if (isPageHasMediaBox) { + PdfGraphicsHelper.getHelper(_helper.graphics!).mediaBoxUpperRightBound = + isInvalidSize ? -lly : ury; + } + if (!PdfPageHelper.getHelper(page).isLoadedPage) { + final PdfSectionCollection? sectionCollection = + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page).section!, + ).parent; + if (sectionCollection != null) { + _helper.graphics!.colorSpace = + PdfSectionCollectionHelper.getHelper( + sectionCollection, + ).document!.colorSpace; + _helper.colorSpace = + PdfSectionCollectionHelper.getHelper( + sectionCollection, + ).document!.colorSpace; + } + } + _helper._content!.beginSave = _beginSaveContent; + } + _graphicsState = _helper.graphics!.save(); + if (name != null && name!.isNotEmpty) { + PdfGraphicsHelper.getHelper( + _helper.graphics!, + ).streamWriter!.write('/OC /${_helper.layerID!} BDC\n'); + _isEndState = true; + } + PdfGraphicsHelper.getHelper(_helper.graphics!).initializeCoordinates(); + if (PdfGraphicsHelper.getHelper(_helper.graphics!).hasTransparencyBrush) { + PdfGraphicsHelper.getHelper( + _helper.graphics!, + ).setTransparencyGroup(page!); + } + if (page != null && + (!PdfPageHelper.getHelper(page).isLoadedPage) && + (page.rotation != PdfPageRotateAngle.rotateAngle0 || + PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.rotate))) { + PdfArray? cropBox; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.cropBox)) { + cropBox = + PdfPageHelper.getHelper(page).dictionary!.getValue( + PdfDictionaryProperties.cropBox, + PdfDictionaryProperties.parent, + ) + as PdfArray?; + } + _updatePageRotation(page, _helper.graphics, cropBox); + } + if (page != null && !PdfPageHelper.getHelper(page).isLoadedPage) { + final PdfRectangle clipRect = PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page).section!, + ).getActualBounds(page, true); + if (_clipPageTemplates!) { + if (PdfPageHelper.getHelper(page).origin.dx >= 0 && + PdfPageHelper.getHelper(page).origin.dy >= 0) { + PdfGraphicsHelper.getHelper( + _helper.graphics!, + ).clipTranslateMarginsWithBounds(clipRect); + } + } else { + final PdfMargins margins = + PdfPageHelper.getHelper(page).section!.pageSettings.margins; + PdfGraphicsHelper.getHelper(_helper.graphics!).clipTranslateMargins( + clipRect.x, + clipRect.y, + margins.left, + margins.top, + margins.right, + margins.bottom, + ); + } + } + PdfGraphicsHelper.getHelper(_helper.graphics!).setLayer(this); + _isSaved = false; + } + + void _updatePageRotation( + PdfPage page, + PdfGraphics? graphics, + PdfArray? cropBox, + ) { + PdfNumber? rotation; + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.rotate)) { + rotation = + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .rotate] + as PdfNumber?; + rotation ??= + rotation = + PdfCrossTable.dereference( + PdfPageHelper.getHelper( + page, + ).dictionary![PdfDictionaryProperties.rotate], + ) + as PdfNumber?; + } else if (page.rotation != PdfPageRotateAngle.rotateAngle0) { + if (page.rotation == PdfPageRotateAngle.rotateAngle90) { + rotation = PdfNumber(90); + } else if (page.rotation == PdfPageRotateAngle.rotateAngle180) { + rotation = PdfNumber(180); + } else if (page.rotation == PdfPageRotateAngle.rotateAngle270) { + rotation = PdfNumber(270); + } + } + if (rotation!.value == 90) { + graphics!.translateTransform(0, page.size.height); + graphics.rotateTransform(-90); + if (cropBox != null) { + final double height = (cropBox[3]! as PdfNumber).value!.toDouble(); + final Size cropBoxSize = Size( + (cropBox[2]! as PdfNumber).value!.toDouble(), + height != 0 ? height : (cropBox[1]! as PdfNumber).value!.toDouble(), + ); + final Offset cropBoxOffset = Offset( + (cropBox[0]! as PdfNumber).value!.toDouble(), + (cropBox[1]! as PdfNumber).value!.toDouble(), + ); + if (page.size.height < cropBoxSize.height) { + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + page.size.height - cropBoxOffset.dy, + cropBoxSize.width - cropBoxOffset.dx, + ); + } else { + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + cropBoxSize.height - cropBoxOffset.dy, + cropBoxSize.width - cropBoxOffset.dx, + ); + } + } else { + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + page.size.height, + page.size.width, + ); + } + } else if (rotation.value == 180) { + graphics!.translateTransform(page.size.width, page.size.height); + graphics.rotateTransform(-180); + } else if (rotation.value == 270) { + graphics!.translateTransform(page.size.width, 0); + graphics.rotateTransform(-270); + PdfGraphicsHelper.getHelper(graphics).clipBounds.size = PdfSize( + page.size.height, + page.size.width, + ); + } + } + + void _beginSaveContent(Object sender, SavePdfPrimitiveArgs? args) { + if (_graphicsState != null) { + if (_isEndState) { + PdfGraphicsHelper.getHelper( + _helper.graphics!, + ).streamWriter!.write('EMC\n'); + _isEndState = false; + } + graphics.restore(_graphicsState); + _graphicsState = null; + } + _isSaved = true; + } + + void _setVisibility(bool? value) { + PdfDictionary? oCProperties; + if (PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_page).document!, + ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { + oCProperties = + PdfCrossTable.dereference( + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_page).document!, + ).catalog[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + } + if (oCProperties != null) { + final PdfDictionary? defaultView = + oCProperties[PdfDictionaryProperties.defaultView] as PdfDictionary?; + if (defaultView != null) { + PdfArray? ocgON = + defaultView[PdfDictionaryProperties.ocgOn] as PdfArray?; + PdfArray? ocgOFF = + defaultView[PdfDictionaryProperties.ocgOff] as PdfArray?; + if (_helper.referenceHolder != null) { + if (value == false) { + if (ocgON != null) { + _removeContent(ocgON, _helper.referenceHolder); + } + if (ocgOFF == null) { + ocgOFF = PdfArray(); + defaultView.items![PdfName(PdfDictionaryProperties.ocgOff)] = + ocgOFF; + } + ocgOFF.insert(ocgOFF.count, _helper.referenceHolder!); + } else if (value ?? true) { + if (ocgOFF != null) { + _removeContent(ocgOFF, _helper.referenceHolder); + } + if (ocgON == null) { + ocgON = PdfArray(); + defaultView.items![PdfName(PdfDictionaryProperties.ocgOn)] = + ocgON; + } + ocgON.insert(ocgON.count, _helper.referenceHolder!); + } + } + } + } + } + + bool _isContainsPageContent( + PdfArray content, + PdfReferenceHolder referenceHolder, + ) { + for (int i = 0; i < content.count; i++) { + final IPdfPrimitive? primitive = content.elements[i]; + if (primitive != null && primitive is PdfReferenceHolder) { + final PdfReferenceHolder holder = primitive; + if (holder.reference != null && referenceHolder.reference != null) { + if (holder.reference!.objNum == referenceHolder.reference!.objNum) { + return true; + } + } else { + if (identical(holder, referenceHolder)) { + return true; + } else if (identical(holder.object, referenceHolder.object)) { + return true; + } + } + } + } + return false; + } + + void _removeContent(PdfArray content, PdfReferenceHolder? referenceHolder) { + bool flag = false; + for (int i = 0; i < content.count; i++) { + final IPdfPrimitive? primitive = content.elements[i]; + if (primitive != null && primitive is PdfReferenceHolder) { + final PdfReferenceHolder holder = primitive; + if (holder.reference != null && referenceHolder!.reference != null) { + if (holder.reference!.objNum == referenceHolder.reference!.objNum) { + content.elements.removeAt(i); + flag = true; + i--; + } + } + } + } + if (flag) { + content.changed = true; + } + } +} + +/// [PdfPageLayer] helper +class PdfPageLayerHelper { + /// internal constructor + PdfPageLayerHelper(this.base); + + /// internal field + late PdfPageLayer base; + PdfStream? _content; + + /// internal method + static PdfPageLayerHelper getHelper(PdfPageLayer base) { + return base._helper; + } + + /// internal method + static PdfPageLayer fromClipPageTemplate( + PdfPage pdfPage, [ + bool? clipPageTemplates, + ]) { + return PdfPageLayer._fromClipPageTemplate(pdfPage, clipPageTemplates); + } + + /// internal property + IPdfPrimitive? get element => _content; + //ignore: unused_element + set element(IPdfPrimitive? value) { + _content = value as PdfStream?; + } + + /// internal field + //ignore:unused_field + PdfColorSpace? colorSpace; + + /// internal field + PdfDictionary? dictionary; + + /// internal field + String? layerID; + + /// internal field + PdfDictionary? printOption; + + /// internal field + PdfDictionary? usage; + + /// internal field + PdfReferenceHolder? referenceHolder; + + /// internal field + PdfGraphics? graphics; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer_collection.dart index 382d1ecec..5f202d531 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_layer_collection.dart @@ -1,897 +1,897 @@ -import '../../interfaces/pdf_interface.dart'; -import '../exporting/pdf_text_extractor/parser/content_parser.dart'; -import '../general/pdf_collection.dart'; -import '../graphics/pdf_graphics.dart'; -import '../graphics/pdf_resources.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_page.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import 'pdf_page_layer.dart'; - -/// The class provides methods and properties -/// to handle the collections of [PdfPageLayer]. -class PdfPageLayerCollection extends PdfObjectCollection { - //Constructor - /// Initializes a new instance of the - /// [PdfPageLayerCollection] class with PDF page. - PdfPageLayerCollection(PdfPage page) : super() { - _helper = PdfPageLayerCollectionHelper(this, page); - } - - //Fields - late PdfPageLayerCollectionHelper _helper; - - //Properties - /// Gets [PdfPageLayer] by its index from [PdfPageLayerCollection]. - PdfPageLayer operator [](int index) => _helper._returnValue(index); - - //Public methods - /// Creates a new [PdfPageLayer] and adds it to the end of the collection. - PdfPageLayer add({String? name, bool? visible}) { - return _helper.add(name, visible); - } - - /// Adds [PdfPageLayer] to the collection. - int addLayer(PdfPageLayer layer) { - return _helper.addLayer(layer); - } - - /// Returns index of the [PdfPageLayer] in the collection if exists, - /// -1 otherwise. - int indexOf(PdfPageLayer layer) { - return _helper.indexOf(layer); - } - - //Implementation - - /// Removes layer from the collection. - void remove({PdfPageLayer? layer, String? name}) { - _helper.remove(layer, name); - } - - /// Removes layer by its index from collections - void removeAt(int index) { - _helper.removeAt(index); - } - - /// Clears layers from the [PdfPageLayerCollection]. - void clear() { - _helper.clear(); - } -} - -/// [PdfPageLayerCollection] helper -class PdfPageLayerCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfPageLayerCollectionHelper(this.pageLayerCollection, PdfPage page) - : super(pageLayerCollection) { - _optionalContent = PdfDictionary(); - _subLayer = false; - _page = page; - _parseLayers(page); - } - - /// internal field - PdfPageLayerCollection pageLayerCollection; - - //Fields - late PdfPage _page; - late bool _subLayer; - PdfDictionary? _optionalContent; - int _bdcCount = 0; - - PdfPageLayer _returnValue(int index) { - return list[index] as PdfPageLayer; - } - - /// internal method - static PdfPageLayerCollectionHelper getHelper( - PdfPageLayerCollection pageLayerCollection, - ) { - return pageLayerCollection._helper; - } - - /// internal method - List? combineContent(bool skipSave) { - return _combineContent(skipSave); - } - - void _parseLayers(PdfPage page) { - if (!PdfPageHelper.getHelper(page).isTextExtraction) { - final PdfArray contents = PdfPageHelper.getHelper(page).contents; - final PdfDictionary? resource = - PdfPageHelper.getHelper(page).getResources(); - PdfDictionary? ocProperties; - PdfDictionary? propertie; - PdfPage? pdfLoaded; - final Map pageLayerCollection = - {}; - if (PdfPageHelper.getHelper(page).isLoadedPage) { - pdfLoaded = page; - } - if (pdfLoaded != null) { - propertie = - PdfCrossTable.dereference( - resource![PdfDictionaryProperties.properties], - ) - as PdfDictionary?; - if (PdfPageHelper.getHelper(pdfLoaded).document != null) { - ocProperties = - PdfCrossTable.dereference( - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(pdfLoaded).document!, - ).catalog[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - } - } - - if (ocProperties != null && (propertie != null)) { - propertie.items!.forEach((PdfName? key, IPdfPrimitive? value) { - final PdfReferenceHolder? layerReferenceHolder = - value as PdfReferenceHolder?; - final PdfDictionary? layerDictionary = - PdfCrossTable.dereference(value) as PdfDictionary?; - if ((layerDictionary != null && layerReferenceHolder != null) || - layerDictionary!.containsKey(PdfDictionaryProperties.ocg)) { - _addLayer( - page, - layerDictionary, - layerReferenceHolder, - key!.name, - pageLayerCollection, - false, - ); - } - }); - } - if (ocProperties != null && pageLayerCollection.isNotEmpty) { - _checkVisible(ocProperties, pageLayerCollection); - } - - final PdfStream saveStream = PdfStream(); - final PdfStream restoreStream = PdfStream(); - const int saveState = 113; - const int restoreState = 81; - saveStream.data = [saveState]; - if (contents.count > 0) { - contents.insert(0, PdfReferenceHolder(saveStream)); - } else { - contents.add(PdfReferenceHolder(saveStream)); - } - restoreStream.data = [restoreState]; - contents.add(PdfReferenceHolder(restoreStream)); - } - } - - List? _combineContent(bool skipSave) { - final bool decompress = PdfPageHelper.getHelper(_page).isLoadedPage; - List? combinedData; - final List end = [13, 10]; - if (PdfPageHelper.getHelper(_page).isLoadedPage) { - combinedData = _combineProcess(_page, decompress, end, skipSave); - } - return combinedData; - } - - List _combineProcess( - PdfPage page, - bool decompress, - List end, - bool isTextExtraction, - ) { - final List data = []; - for (int i = 0; i < PdfPageHelper.getHelper(page).contents.count; i++) { - PdfStream? layerStream; - final IPdfPrimitive? contentPrimitive = - PdfPageHelper.getHelper(page).contents[i]; - if (contentPrimitive != null && contentPrimitive is PdfReferenceHolder) { - final IPdfPrimitive? primitive = contentPrimitive.object; - if (primitive != null && primitive is PdfStream) { - layerStream = primitive; - } - } else if (contentPrimitive != null && contentPrimitive is PdfStream) { - layerStream = contentPrimitive; - } - if (layerStream != null) { - if (decompress) { - data.addAll(layerStream.getDecompressedData(false)!); - } else { - data.addAll(layerStream.dataStream!); - } - data.addAll(end); - } - } - return data; - } - - void _createLayerLoadedPage(PdfPageLayer layer) { - final PdfDictionary ocProperties = PdfDictionary(); - final IPdfPrimitive? ocgroups = _createOptionContentDictionary(layer); - bool isPresent = false; - if (PdfPageHelper.getHelper(_page).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_page).document!, - ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { - final PdfDictionary? ocDictionary = - PdfCrossTable.dereference( - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_page).document!, - ).catalog[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - if (ocDictionary != null && - ocDictionary.containsKey(PdfDictionaryProperties.ocg)) { - final PdfArray? ocgsList = - PdfCrossTable.dereference(ocDictionary[PdfDictionaryProperties.ocg]) - as PdfArray?; - if (ocgsList != null) { - isPresent = true; - if (!ocgsList.contains( - PdfPageLayerHelper.getHelper(layer).referenceHolder!, - )) { - ocgsList.insert( - ocgsList.count, - PdfPageLayerHelper.getHelper(layer).referenceHolder!, - ); - } - } - if (ocDictionary.containsKey(PdfDictionaryProperties.defaultView)) { - final PdfDictionary? defaultView = - ocDictionary[PdfDictionaryProperties.defaultView] - as PdfDictionary?; - if (defaultView != null) { - PdfArray? on = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOn], - ) - as PdfArray?; - final PdfArray? order = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOrder], - ) - as PdfArray?; - PdfArray? off = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOff], - ) - as PdfArray?; - final PdfArray? usage = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.usageApplication], - ) - as PdfArray?; - - if (on == null) { - on = PdfArray(); - defaultView[PdfDictionaryProperties.ocgOn] = on; - } - - if (!layer.visible && off == null) { - off = PdfArray(); - defaultView[PdfDictionaryProperties.ocgOff] = off; - } - - final PdfReferenceHolder referenceHolder = - PdfPageLayerHelper.getHelper(layer).referenceHolder!; - if (order != null && !order.contains(referenceHolder)) { - order.insert(order.count, referenceHolder); - } - - if (layer.visible && !on.contains(referenceHolder)) { - on.insert(on.count, referenceHolder); - } - if (!layer.visible && - off != null && - !off.contains(referenceHolder)) { - off.insert(off.count, referenceHolder); - } - - if (usage != null && usage.count > 0) { - final PdfDictionary? asDictionary = - PdfCrossTable.dereference(usage[0]) as PdfDictionary?; - if (asDictionary != null && - asDictionary.containsKey(PdfDictionaryProperties.ocg)) { - final PdfArray? usageOcGroup = - PdfCrossTable.dereference( - asDictionary[PdfDictionaryProperties.ocg], - ) - as PdfArray?; - if (usageOcGroup != null && - !usageOcGroup.contains(referenceHolder)) { - usageOcGroup.insert(usageOcGroup.count, referenceHolder); - } - } - } - } - } - } - } - if (!isPresent && PdfPageHelper.getHelper(_page).document != null) { - ocProperties[PdfDictionaryProperties.ocg] = ocgroups; - ocProperties[PdfDictionaryProperties - .defaultView] = _createOptionalContentViews(layer); - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_page).document!, - ).catalog.setProperty(PdfDictionaryProperties.ocProperties, ocProperties); - } - } - - IPdfPrimitive? _createOptionContentDictionary(PdfPageLayer layer) { - final PdfDictionary optionalContent = PdfDictionary(); - optionalContent[PdfDictionaryProperties.name] = PdfString(layer.name!); - optionalContent[PdfDictionaryProperties.type] = PdfName('OCG'); - optionalContent[PdfDictionaryProperties.layerID] = PdfName( - PdfPageLayerHelper.getHelper(layer).layerID, - ); - optionalContent[PdfDictionaryProperties.visible] = PdfBoolean( - layer.visible, - ); - PdfPageLayerHelper.getHelper(layer).usage = _setPrintOption(layer); - optionalContent[PdfDictionaryProperties.usage] = PdfReferenceHolder( - PdfPageLayerHelper.getHelper(layer).usage, - ); - final PdfDocument document = PdfPageHelper.getHelper(_page).document!; - PdfDocumentHelper.getHelper( - document, - ).printLayer!.add(PdfReferenceHolder(optionalContent)); - final PdfReferenceHolder reference = PdfReferenceHolder(optionalContent); - PdfDocumentHelper.getHelper(document).pdfPrimitive!.add(reference); - PdfPageLayerHelper.getHelper(layer).dictionary = optionalContent; - PdfPageLayerHelper.getHelper(layer).referenceHolder = reference; - if (!_subLayer) { - PdfDocumentHelper.getHelper(document).order!.add(reference); - PdfDocumentHelper.getHelper(document).orderPosition = - PdfDocumentHelper.getHelper(document).orderPosition! + 1; - } - if (layer.visible) { - PdfDocumentHelper.getHelper(document).on!.add(reference); - PdfDocumentHelper.getHelper(document).onPosition = - PdfDocumentHelper.getHelper(document).onPosition! + 1; - } else { - PdfDocumentHelper.getHelper(document).off!.add(reference); - PdfDocumentHelper.getHelper(document).offPosition = - PdfDocumentHelper.getHelper(document).offPosition! + 1; - } - PdfDocumentHelper.getHelper(document).position = - PdfDocumentHelper.getHelper(document).position! + 1; - final PdfResources? resource = - PdfPageHelper.getHelper(_page).getResources(); - if (resource != null && - resource.containsKey(PdfDictionaryProperties.properties) && - PdfPageHelper.getHelper(_page).isLoadedPage) { - final PdfDictionary? dic = - resource[PdfDictionaryProperties.properties] as PdfDictionary?; - if (dic != null) { - dic[PdfPageLayerHelper.getHelper(layer).layerID] = reference; - } else { - resource.properties[PdfPageLayerHelper.getHelper(layer).layerID] = - reference; - resource[PdfDictionaryProperties.properties] = resource.properties; - } - } else { - resource!.properties[PdfPageLayerHelper.getHelper(layer).layerID] = - reference; - resource[PdfDictionaryProperties.properties] = resource.properties; - } - return PdfDocumentHelper.getHelper(document).pdfPrimitive; - } - - PdfDictionary _setPrintOption(PdfPageLayer layer) { - final PdfDictionary usage = PdfDictionary(); - PdfPageLayerHelper.getHelper(layer).printOption = PdfDictionary(); - PdfPageLayerHelper.getHelper(layer).printOption![PdfDictionaryProperties - .subtype] = PdfName('Print'); - usage[PdfDictionaryProperties.print] = PdfReferenceHolder( - PdfPageLayerHelper.getHelper(layer).printOption, - ); - return usage; - } - - IPdfPrimitive? _createOptionalContentViews(PdfPageLayer layer) { - final PdfDocument document = PdfPageHelper.getHelper(_page).document!; - final PdfArray usageApplication = PdfArray(); - _optionalContent![PdfDictionaryProperties.name] = PdfString('Layers'); - _optionalContent![PdfDictionaryProperties.ocgOrder] = - PdfDocumentHelper.getHelper(document).order; - _optionalContent![PdfDictionaryProperties.ocgOn] = - PdfDocumentHelper.getHelper(document).on; - _optionalContent![PdfDictionaryProperties.ocgOff] = - PdfDocumentHelper.getHelper(document).off; - final PdfArray category = PdfArray(); - category.add(PdfName('Print')); - final PdfDictionary applicationDictionary = PdfDictionary(); - applicationDictionary[PdfDictionaryProperties.category] = category; - applicationDictionary[PdfDictionaryProperties.ocg] = - PdfDocumentHelper.getHelper(document).printLayer; - applicationDictionary[PdfDictionaryProperties.event] = PdfName('Print'); - usageApplication.add(PdfReferenceHolder(applicationDictionary)); - if (PdfDocumentHelper.getHelper(document).conformanceLevel != - PdfConformanceLevel.a2b && - PdfDocumentHelper.getHelper(document).conformanceLevel != - PdfConformanceLevel.a3b) { - _optionalContent![PdfDictionaryProperties.usageApplication] = - usageApplication; - } - return _optionalContent; - } - - void _addLayer( - PdfPage page, - PdfDictionary dictionary, - PdfReferenceHolder? reference, - String? key, - Map pageLayerCollection, - bool isResourceLayer, - ) { - final PdfPageLayer layer = PdfPageLayer(page); - list.add(layer); - if (!pageLayerCollection.containsKey(reference)) { - pageLayerCollection[reference] = layer; - } - final PdfPageLayerHelper layerHelper = PdfPageLayerHelper.getHelper(layer); - layerHelper.dictionary = dictionary; - layerHelper.referenceHolder = reference; - layerHelper.layerID = key; - if (dictionary.containsKey(PdfDictionaryProperties.name)) { - final PdfString? layerName = - PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.name]) - as PdfString?; - if (layerName != null) { - layer.name = layerName.value; - } - } - } - - void _checkVisible( - PdfDictionary ocproperties, - Map layerDictionary, - ) { - final PdfDictionary? defaultView = - PdfCrossTable.dereference( - ocproperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultView != null) { - final PdfArray? visible = - PdfCrossTable.dereference(defaultView[PdfDictionaryProperties.ocgOff]) - as PdfArray?; - if (visible != null && layerDictionary.isNotEmpty) { - for (int i = 0; i < visible.count; i++) { - if (layerDictionary.containsKey(visible[i]! as PdfReferenceHolder)) { - final PdfPageLayer? pdfLayer = - layerDictionary[visible[i]! as PdfReferenceHolder]; - if (pdfLayer != null) { - pdfLayer.visible = false; - if (PdfPageLayerHelper.getHelper(pdfLayer).dictionary != null && - PdfPageLayerHelper.getHelper( - pdfLayer, - ).dictionary!.containsKey(PdfDictionaryProperties.visible)) { - PdfPageLayerHelper.getHelper(pdfLayer).dictionary!.setProperty( - PdfDictionaryProperties.visible, - PdfBoolean(false), - ); - } - } - } - } - } - } - } - - void _removeLayer(PdfPageLayer layer) { - PdfDictionary? ocProperties; - _removeLayerContent(layer); - final PdfDictionary? resource = - PdfCrossTable.dereference( - PdfPageHelper.getHelper(_page).dictionary![PdfDictionaryProperties - .resources], - ) - as PdfDictionary?; - if (resource != null) { - final PdfDictionary? properties = - PdfCrossTable.dereference( - resource[PdfDictionaryProperties.properties], - ) - as PdfDictionary?; - if (properties != null && - PdfPageLayerHelper.getHelper(layer).layerID != null && - properties.containsKey(PdfPageLayerHelper.getHelper(layer).layerID)) { - properties.remove(PdfPageLayerHelper.getHelper(layer).layerID); - } - } - final PdfPage page = _page; - if (PdfPageHelper.getHelper(page).document != null && - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(page).document!, - ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { - ocProperties = - PdfCrossTable.dereference( - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(page).document!, - ).catalog[PdfDictionaryProperties.ocProperties], - ) - as PdfDictionary?; - } - if (ocProperties != null) { - final PdfArray? ocGroup = - PdfCrossTable.dereference(ocProperties[PdfDictionaryProperties.ocg]) - as PdfArray?; - if (ocGroup != null) { - _removeContent( - ocGroup, - PdfPageLayerHelper.getHelper(layer).referenceHolder, - ); - } - final PdfDictionary? defaultView = - PdfCrossTable.dereference( - ocProperties[PdfDictionaryProperties.defaultView], - ) - as PdfDictionary?; - if (defaultView != null) { - final PdfArray? on = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOn], - ) - as PdfArray?; - final PdfArray? order = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOrder], - ) - as PdfArray?; - final PdfArray? off = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.ocgOff], - ) - as PdfArray?; - final PdfArray? usage = - PdfCrossTable.dereference( - defaultView[PdfDictionaryProperties.usageApplication], - ) - as PdfArray?; - - if (usage != null && usage.count > 0) { - for (int i = 0; i < usage.count; i++) { - final PdfDictionary? usageDictionary = - PdfCrossTable.dereference(usage[i]) as PdfDictionary?; - if (usageDictionary != null && - usageDictionary.containsKey(PdfDictionaryProperties.ocg)) { - final PdfArray? usageOcGroup = - usageDictionary[PdfDictionaryProperties.ocg] as PdfArray?; - if (usageOcGroup != null) { - _removeContent( - usageOcGroup, - PdfPageLayerHelper.getHelper(layer).referenceHolder, - ); - } - } - } - } - if (order != null) { - _removeContent( - order, - PdfPageLayerHelper.getHelper(layer).referenceHolder, - ); - } - if (layer.visible && on != null) { - _removeContent( - on, - PdfPageLayerHelper.getHelper(layer).referenceHolder, - ); - } else if (off != null) { - _removeContent( - off, - PdfPageLayerHelper.getHelper(layer).referenceHolder, - ); - } - } - } - } - - void _removeContent(PdfArray content, PdfReferenceHolder? referenceHolder) { - bool flag = false; - for (int i = 0; i < content.count; i++) { - final IPdfPrimitive? primitive = content.elements[i]; - if (primitive != null && primitive is PdfReferenceHolder) { - final PdfReferenceHolder reference = primitive; - if (reference.reference != null && referenceHolder!.reference != null) { - if (reference.reference!.objNum == - referenceHolder.reference!.objNum) { - content.elements.removeAt(i); - flag = true; - i--; - } - } else if (identical(content.elements[i], referenceHolder)) { - content.elements.removeAt(i); - flag = true; - i--; - } else if (identical( - (content.elements[i]! as PdfReferenceHolder).object, - referenceHolder!.object, - )) { - content.elements.removeAt(i); - flag = true; - i--; - } - } else if (content.elements[i]! is PdfArray) { - _removeContent(content.elements[i]! as PdfArray, referenceHolder); - } - } - if (flag) { - content.changed = true; - } - } - - void _removeLayerContent(PdfPageLayer layer) { - bool isSkip = false; - for (int m = 0; m < PdfPageHelper.getHelper(_page).contents.count; m++) { - bool isNewContentStream = false; - bool? removePageContent = false; - List? stream = []; - final IPdfPrimitive? primitive = - PdfPageHelper.getHelper(_page).contents[m]; - if (primitive! is PdfReferenceHolder) { - final PdfReferenceHolder pdfReference = primitive as PdfReferenceHolder; - if (pdfReference.reference == null) { - isNewContentStream = true; - } - } - final PdfStream pageContent = - PdfCrossTable.dereference(PdfPageHelper.getHelper(_page).contents[m])! - as PdfStream; - final PdfStream data = PdfStream(); - if (PdfPageHelper.getHelper(_page).isLoadedPage) { - pageContent.decompress(); - } - stream = pageContent.dataStream; - final ContentParser parser = ContentParser(stream); - final PdfRecordCollection recordCollection = parser.readContent()!; - for (int j = 0; j < recordCollection.recordCollection.length; j++) { - final String? mOperator = - recordCollection.recordCollection[j].operatorName; - if (mOperator == 'BMC' || mOperator == 'EMC' || mOperator == 'BDC') { - final Map returnedValue = _processBeginMarkContent( - layer, - mOperator, - recordCollection.recordCollection[j].operands, - data, - isNewContentStream, - removePageContent, - ); - removePageContent = returnedValue['removePageContent']; - isSkip = true; - if (removePageContent!) { - break; - } - } - String? id; - if (recordCollection.recordCollection[j].operands!.isNotEmpty && - recordCollection.recordCollection[j].operands![0].startsWith('/')) { - id = recordCollection.recordCollection[j].operands![0].substring(1); - } - if (mOperator == PdfOperators.paintXObject && - (id == PdfPageLayerHelper.getHelper(layer).layerID)) { - isSkip = true; - } - if (mOperator == 'RG' || - mOperator == PdfOperators.saveState || - mOperator == PdfOperators.restoreState || - mOperator == PdfOperators.setLineWidth || - mOperator == PdfOperators.setLineCapStyle || - mOperator == PdfOperators.setLineJoinStyle || - mOperator == PdfOperators.setMiterLimit || - mOperator == PdfOperators.setDashPattern || - mOperator == PdfOperators.setGraphicsState || - mOperator == PdfOperators.currentMatrix || - mOperator == PdfOperators.selectColorSpaceForNonStroking || - mOperator == PdfOperators.selectColorSpaceForStroking) { - if (!isSkip) { - _streamWrite( - recordCollection.recordCollection[j].operands, - mOperator, - false, - data, - ); - } - } else if (!isSkip) { - _streamWrite( - recordCollection.recordCollection[j].operands, - mOperator, - true, - data, - ); - } - isSkip = false; - } - if (data.dataStream!.isNotEmpty && !removePageContent!) { - pageContent.clear(); - pageContent.dataStream!.clear(); - pageContent.write(data.dataStream); - } else { - pageContent.clear(); - } - if (removePageContent!) { - _removeContent( - PdfPageHelper.getHelper(_page).contents, - PdfPageLayerHelper.getHelper(layer).referenceHolder, - ); - if (PdfPageLayerHelper.getHelper(layer).graphics != null && - PdfGraphicsHelper.getHelper( - PdfPageLayerHelper.getHelper(layer).graphics!, - ).streamWriter != - null) { - final PdfStream? lcontent = - PdfGraphicsHelper.getHelper( - PdfPageLayerHelper.getHelper(layer).graphics!, - ).streamWriter!.stream; - if (lcontent != null) { - _removeContent( - PdfPageHelper.getHelper(_page).contents, - PdfReferenceHolder(lcontent), - ); - } - } - } - } - } - - Map _processBeginMarkContent( - PdfPageLayer parser, - String? mOperator, - List? operands, - PdfStream data, - bool isNewContentStream, - bool? removePageContent, - ) { - removePageContent = false; - if ('BDC' == mOperator) { - String? operand; - if (operands!.length > 1 && ((operands[0]) == '/OC')) { - operand = operands[1].substring(1); - } - if (_bdcCount > 0) { - _bdcCount++; - return {'removePageContent': removePageContent}; - } - if (operand != null && - (operand == PdfPageLayerHelper.getHelper(parser).layerID) && - !isNewContentStream) { - _bdcCount++; - } else if (operand != null && - (operand == PdfPageLayerHelper.getHelper(parser).layerID) && - isNewContentStream) { - removePageContent = true; - } - } - _streamWrite(operands, mOperator, true, data); - - if (('EMC' == mOperator) && _bdcCount > 0) { - _bdcCount--; - } - return {'removePageContent': removePageContent}; - } - - void _streamWrite( - List? operands, - String? mOperator, - bool skip, - PdfStream data, - ) { - PdfString pdfString; - if (skip && _bdcCount > 0) { - return; - } - if (operands != null) { - for (final String operand in operands) { - pdfString = PdfString(operand); - data.write(pdfString.data); - data.write(PdfOperators.whiteSpace); - } - } - pdfString = PdfString(mOperator!); - data.write(pdfString.data); - data.write(PdfOperators.newLine); - } - - /// Creates a new [PdfPageLayer] and adds it to the end of the collection. - PdfPageLayer add(String? name, bool? visible) { - final PdfPageLayer layer = PdfPageLayer(_page); - if (name != null) { - layer.name = name; - final String? layerID = PdfPageLayerHelper.getHelper(layer).layerID; - if (layerID == null) { - PdfPageLayerHelper.getHelper(layer).layerID = - 'OCG_${PdfResources.globallyUniqueIdentifier}'; - } - } - if (visible != null) { - layer.visible = visible; - } - addLayer(layer); - return layer; - } - - /// Adds [PdfPageLayer] to the collection. - int addLayer(PdfPageLayer layer) { - if (layer.page != _page) { - ArgumentError.value(layer, 'The layer belongs to another page'); - } - list.add(layer); - final int listIndex = pageLayerCollection.count - 1; - PdfPageHelper.getHelper(_page).contents.add(PdfReferenceHolder(layer)); - if (PdfPageLayerHelper.getHelper(layer).layerID != null) { - if (PdfPageHelper.getHelper(_page).isLoadedPage) { - _createLayerLoadedPage(layer); - } else { - final PdfDictionary ocProperties = PdfDictionary(); - ocProperties[PdfDictionaryProperties - .ocg] = _createOptionContentDictionary(layer); - ocProperties[PdfDictionaryProperties - .defaultView] = _createOptionalContentViews(layer); - PdfDocumentHelper.getHelper( - PdfPageHelper.getHelper(_page).document!, - ).catalog[PdfDictionaryProperties.ocProperties] = - ocProperties; - } - } - return listIndex; - } - - /// Returns index of the [PdfPageLayer] in the collection if exists, - /// -1 otherwise. - int indexOf(PdfPageLayer layer) { - return list.indexOf(layer); - } - - //Implementation - - /// Removes layer from the collection. - void remove(PdfPageLayer? layer, String? name) { - if (layer == null && name == null) { - ArgumentError.value('layer or layerName required'); - } - if (layer != null) { - _removeLayer(layer); - list.remove(layer); - } else { - for (int i = 0; i < list.length; i++) { - final PdfPageLayer layer = list[i] as PdfPageLayer; - if (layer.name == name) { - _removeLayer(layer); - list.remove(layer); - break; - } - } - } - } - - /// Removes layer by its index from collections - void removeAt(int index) { - if (index < 0 || index > list.length - 1) { - ArgumentError.value( - '$index Value can not be less 0 and greater List.Count - 1', - ); - } - final PdfPageLayer layer = pageLayerCollection[index]; - _removeLayer(layer); - list.removeAt(index); - } - - /// Clears layers from the [PdfPageLayerCollection]. - void clear() { - for (int i = 0; i < _page.layers._helper.list.length; i++) { - final PdfPageLayer layer = _page.layers._helper.list[i] as PdfPageLayer; - _removeLayer(layer); - } - _page.layers._helper.list.clear(); - } -} +import '../../interfaces/pdf_interface.dart'; +import '../exporting/pdf_text_extractor/parser/content_parser.dart'; +import '../general/pdf_collection.dart'; +import '../graphics/pdf_graphics.dart'; +import '../graphics/pdf_resources.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_page.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import 'pdf_page_layer.dart'; + +/// The class provides methods and properties +/// to handle the collections of [PdfPageLayer]. +class PdfPageLayerCollection extends PdfObjectCollection { + //Constructor + /// Initializes a new instance of the + /// [PdfPageLayerCollection] class with PDF page. + PdfPageLayerCollection(PdfPage page) : super() { + _helper = PdfPageLayerCollectionHelper(this, page); + } + + //Fields + late PdfPageLayerCollectionHelper _helper; + + //Properties + /// Gets [PdfPageLayer] by its index from [PdfPageLayerCollection]. + PdfPageLayer operator [](int index) => _helper._returnValue(index); + + //Public methods + /// Creates a new [PdfPageLayer] and adds it to the end of the collection. + PdfPageLayer add({String? name, bool? visible}) { + return _helper.add(name, visible); + } + + /// Adds [PdfPageLayer] to the collection. + int addLayer(PdfPageLayer layer) { + return _helper.addLayer(layer); + } + + /// Returns index of the [PdfPageLayer] in the collection if exists, + /// -1 otherwise. + int indexOf(PdfPageLayer layer) { + return _helper.indexOf(layer); + } + + //Implementation + + /// Removes layer from the collection. + void remove({PdfPageLayer? layer, String? name}) { + _helper.remove(layer, name); + } + + /// Removes layer by its index from collections + void removeAt(int index) { + _helper.removeAt(index); + } + + /// Clears layers from the [PdfPageLayerCollection]. + void clear() { + _helper.clear(); + } +} + +/// [PdfPageLayerCollection] helper +class PdfPageLayerCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfPageLayerCollectionHelper(this.pageLayerCollection, PdfPage page) + : super(pageLayerCollection) { + _optionalContent = PdfDictionary(); + _subLayer = false; + _page = page; + _parseLayers(page); + } + + /// internal field + PdfPageLayerCollection pageLayerCollection; + + //Fields + late PdfPage _page; + late bool _subLayer; + PdfDictionary? _optionalContent; + int _bdcCount = 0; + + PdfPageLayer _returnValue(int index) { + return list[index] as PdfPageLayer; + } + + /// internal method + static PdfPageLayerCollectionHelper getHelper( + PdfPageLayerCollection pageLayerCollection, + ) { + return pageLayerCollection._helper; + } + + /// internal method + List? combineContent(bool skipSave) { + return _combineContent(skipSave); + } + + void _parseLayers(PdfPage page) { + if (!PdfPageHelper.getHelper(page).isTextExtraction) { + final PdfArray contents = PdfPageHelper.getHelper(page).contents; + final PdfDictionary? resource = + PdfPageHelper.getHelper(page).getResources(); + PdfDictionary? ocProperties; + PdfDictionary? propertie; + PdfPage? pdfLoaded; + final Map pageLayerCollection = + {}; + if (PdfPageHelper.getHelper(page).isLoadedPage) { + pdfLoaded = page; + } + if (pdfLoaded != null) { + propertie = + PdfCrossTable.dereference( + resource![PdfDictionaryProperties.properties], + ) + as PdfDictionary?; + if (PdfPageHelper.getHelper(pdfLoaded).document != null) { + ocProperties = + PdfCrossTable.dereference( + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(pdfLoaded).document!, + ).catalog[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + } + } + + if (ocProperties != null && (propertie != null)) { + propertie.items!.forEach((PdfName? key, IPdfPrimitive? value) { + final PdfReferenceHolder? layerReferenceHolder = + value as PdfReferenceHolder?; + final PdfDictionary? layerDictionary = + PdfCrossTable.dereference(value) as PdfDictionary?; + if ((layerDictionary != null && layerReferenceHolder != null) || + layerDictionary!.containsKey(PdfDictionaryProperties.ocg)) { + _addLayer( + page, + layerDictionary, + layerReferenceHolder, + key!.name, + pageLayerCollection, + false, + ); + } + }); + } + if (ocProperties != null && pageLayerCollection.isNotEmpty) { + _checkVisible(ocProperties, pageLayerCollection); + } + + final PdfStream saveStream = PdfStream(); + final PdfStream restoreStream = PdfStream(); + const int saveState = 113; + const int restoreState = 81; + saveStream.data = [saveState]; + if (contents.count > 0) { + contents.insert(0, PdfReferenceHolder(saveStream)); + } else { + contents.add(PdfReferenceHolder(saveStream)); + } + restoreStream.data = [restoreState]; + contents.add(PdfReferenceHolder(restoreStream)); + } + } + + List? _combineContent(bool skipSave) { + final bool decompress = PdfPageHelper.getHelper(_page).isLoadedPage; + List? combinedData; + final List end = [13, 10]; + if (PdfPageHelper.getHelper(_page).isLoadedPage) { + combinedData = _combineProcess(_page, decompress, end, skipSave); + } + return combinedData; + } + + List _combineProcess( + PdfPage page, + bool decompress, + List end, + bool isTextExtraction, + ) { + final List data = []; + for (int i = 0; i < PdfPageHelper.getHelper(page).contents.count; i++) { + PdfStream? layerStream; + final IPdfPrimitive? contentPrimitive = + PdfPageHelper.getHelper(page).contents[i]; + if (contentPrimitive != null && contentPrimitive is PdfReferenceHolder) { + final IPdfPrimitive? primitive = contentPrimitive.object; + if (primitive != null && primitive is PdfStream) { + layerStream = primitive; + } + } else if (contentPrimitive != null && contentPrimitive is PdfStream) { + layerStream = contentPrimitive; + } + if (layerStream != null) { + if (decompress) { + data.addAll(layerStream.getDecompressedData(false)!); + } else { + data.addAll(layerStream.dataStream!); + } + data.addAll(end); + } + } + return data; + } + + void _createLayerLoadedPage(PdfPageLayer layer) { + final PdfDictionary ocProperties = PdfDictionary(); + final IPdfPrimitive? ocgroups = _createOptionContentDictionary(layer); + bool isPresent = false; + if (PdfPageHelper.getHelper(_page).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_page).document!, + ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { + final PdfDictionary? ocDictionary = + PdfCrossTable.dereference( + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_page).document!, + ).catalog[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + if (ocDictionary != null && + ocDictionary.containsKey(PdfDictionaryProperties.ocg)) { + final PdfArray? ocgsList = + PdfCrossTable.dereference(ocDictionary[PdfDictionaryProperties.ocg]) + as PdfArray?; + if (ocgsList != null) { + isPresent = true; + if (!ocgsList.contains( + PdfPageLayerHelper.getHelper(layer).referenceHolder!, + )) { + ocgsList.insert( + ocgsList.count, + PdfPageLayerHelper.getHelper(layer).referenceHolder!, + ); + } + } + if (ocDictionary.containsKey(PdfDictionaryProperties.defaultView)) { + final PdfDictionary? defaultView = + ocDictionary[PdfDictionaryProperties.defaultView] + as PdfDictionary?; + if (defaultView != null) { + PdfArray? on = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOn], + ) + as PdfArray?; + final PdfArray? order = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOrder], + ) + as PdfArray?; + PdfArray? off = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOff], + ) + as PdfArray?; + final PdfArray? usage = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.usageApplication], + ) + as PdfArray?; + + if (on == null) { + on = PdfArray(); + defaultView[PdfDictionaryProperties.ocgOn] = on; + } + + if (!layer.visible && off == null) { + off = PdfArray(); + defaultView[PdfDictionaryProperties.ocgOff] = off; + } + + final PdfReferenceHolder referenceHolder = + PdfPageLayerHelper.getHelper(layer).referenceHolder!; + if (order != null && !order.contains(referenceHolder)) { + order.insert(order.count, referenceHolder); + } + + if (layer.visible && !on.contains(referenceHolder)) { + on.insert(on.count, referenceHolder); + } + if (!layer.visible && + off != null && + !off.contains(referenceHolder)) { + off.insert(off.count, referenceHolder); + } + + if (usage != null && usage.count > 0) { + final PdfDictionary? asDictionary = + PdfCrossTable.dereference(usage[0]) as PdfDictionary?; + if (asDictionary != null && + asDictionary.containsKey(PdfDictionaryProperties.ocg)) { + final PdfArray? usageOcGroup = + PdfCrossTable.dereference( + asDictionary[PdfDictionaryProperties.ocg], + ) + as PdfArray?; + if (usageOcGroup != null && + !usageOcGroup.contains(referenceHolder)) { + usageOcGroup.insert(usageOcGroup.count, referenceHolder); + } + } + } + } + } + } + } + if (!isPresent && PdfPageHelper.getHelper(_page).document != null) { + ocProperties[PdfDictionaryProperties.ocg] = ocgroups; + ocProperties[PdfDictionaryProperties + .defaultView] = _createOptionalContentViews(layer); + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_page).document!, + ).catalog.setProperty(PdfDictionaryProperties.ocProperties, ocProperties); + } + } + + IPdfPrimitive? _createOptionContentDictionary(PdfPageLayer layer) { + final PdfDictionary optionalContent = PdfDictionary(); + optionalContent[PdfDictionaryProperties.name] = PdfString(layer.name!); + optionalContent[PdfDictionaryProperties.type] = PdfName('OCG'); + optionalContent[PdfDictionaryProperties.layerID] = PdfName( + PdfPageLayerHelper.getHelper(layer).layerID, + ); + optionalContent[PdfDictionaryProperties.visible] = PdfBoolean( + layer.visible, + ); + PdfPageLayerHelper.getHelper(layer).usage = _setPrintOption(layer); + optionalContent[PdfDictionaryProperties.usage] = PdfReferenceHolder( + PdfPageLayerHelper.getHelper(layer).usage, + ); + final PdfDocument document = PdfPageHelper.getHelper(_page).document!; + PdfDocumentHelper.getHelper( + document, + ).printLayer!.add(PdfReferenceHolder(optionalContent)); + final PdfReferenceHolder reference = PdfReferenceHolder(optionalContent); + PdfDocumentHelper.getHelper(document).pdfPrimitive!.add(reference); + PdfPageLayerHelper.getHelper(layer).dictionary = optionalContent; + PdfPageLayerHelper.getHelper(layer).referenceHolder = reference; + if (!_subLayer) { + PdfDocumentHelper.getHelper(document).order!.add(reference); + PdfDocumentHelper.getHelper(document).orderPosition = + PdfDocumentHelper.getHelper(document).orderPosition! + 1; + } + if (layer.visible) { + PdfDocumentHelper.getHelper(document).on!.add(reference); + PdfDocumentHelper.getHelper(document).onPosition = + PdfDocumentHelper.getHelper(document).onPosition! + 1; + } else { + PdfDocumentHelper.getHelper(document).off!.add(reference); + PdfDocumentHelper.getHelper(document).offPosition = + PdfDocumentHelper.getHelper(document).offPosition! + 1; + } + PdfDocumentHelper.getHelper(document).position = + PdfDocumentHelper.getHelper(document).position! + 1; + final PdfResources? resource = + PdfPageHelper.getHelper(_page).getResources(); + if (resource != null && + resource.containsKey(PdfDictionaryProperties.properties) && + PdfPageHelper.getHelper(_page).isLoadedPage) { + final PdfDictionary? dic = + resource[PdfDictionaryProperties.properties] as PdfDictionary?; + if (dic != null) { + dic[PdfPageLayerHelper.getHelper(layer).layerID] = reference; + } else { + resource.properties[PdfPageLayerHelper.getHelper(layer).layerID] = + reference; + resource[PdfDictionaryProperties.properties] = resource.properties; + } + } else { + resource!.properties[PdfPageLayerHelper.getHelper(layer).layerID] = + reference; + resource[PdfDictionaryProperties.properties] = resource.properties; + } + return PdfDocumentHelper.getHelper(document).pdfPrimitive; + } + + PdfDictionary _setPrintOption(PdfPageLayer layer) { + final PdfDictionary usage = PdfDictionary(); + PdfPageLayerHelper.getHelper(layer).printOption = PdfDictionary(); + PdfPageLayerHelper.getHelper(layer).printOption![PdfDictionaryProperties + .subtype] = PdfName('Print'); + usage[PdfDictionaryProperties.print] = PdfReferenceHolder( + PdfPageLayerHelper.getHelper(layer).printOption, + ); + return usage; + } + + IPdfPrimitive? _createOptionalContentViews(PdfPageLayer layer) { + final PdfDocument document = PdfPageHelper.getHelper(_page).document!; + final PdfArray usageApplication = PdfArray(); + _optionalContent![PdfDictionaryProperties.name] = PdfString('Layers'); + _optionalContent![PdfDictionaryProperties.ocgOrder] = + PdfDocumentHelper.getHelper(document).order; + _optionalContent![PdfDictionaryProperties.ocgOn] = + PdfDocumentHelper.getHelper(document).on; + _optionalContent![PdfDictionaryProperties.ocgOff] = + PdfDocumentHelper.getHelper(document).off; + final PdfArray category = PdfArray(); + category.add(PdfName('Print')); + final PdfDictionary applicationDictionary = PdfDictionary(); + applicationDictionary[PdfDictionaryProperties.category] = category; + applicationDictionary[PdfDictionaryProperties.ocg] = + PdfDocumentHelper.getHelper(document).printLayer; + applicationDictionary[PdfDictionaryProperties.event] = PdfName('Print'); + usageApplication.add(PdfReferenceHolder(applicationDictionary)); + if (PdfDocumentHelper.getHelper(document).conformanceLevel != + PdfConformanceLevel.a2b && + PdfDocumentHelper.getHelper(document).conformanceLevel != + PdfConformanceLevel.a3b) { + _optionalContent![PdfDictionaryProperties.usageApplication] = + usageApplication; + } + return _optionalContent; + } + + void _addLayer( + PdfPage page, + PdfDictionary dictionary, + PdfReferenceHolder? reference, + String? key, + Map pageLayerCollection, + bool isResourceLayer, + ) { + final PdfPageLayer layer = PdfPageLayer(page); + list.add(layer); + if (!pageLayerCollection.containsKey(reference)) { + pageLayerCollection[reference] = layer; + } + final PdfPageLayerHelper layerHelper = PdfPageLayerHelper.getHelper(layer); + layerHelper.dictionary = dictionary; + layerHelper.referenceHolder = reference; + layerHelper.layerID = key; + if (dictionary.containsKey(PdfDictionaryProperties.name)) { + final PdfString? layerName = + PdfCrossTable.dereference(dictionary[PdfDictionaryProperties.name]) + as PdfString?; + if (layerName != null) { + layer.name = layerName.value; + } + } + } + + void _checkVisible( + PdfDictionary ocproperties, + Map layerDictionary, + ) { + final PdfDictionary? defaultView = + PdfCrossTable.dereference( + ocproperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultView != null) { + final PdfArray? visible = + PdfCrossTable.dereference(defaultView[PdfDictionaryProperties.ocgOff]) + as PdfArray?; + if (visible != null && layerDictionary.isNotEmpty) { + for (int i = 0; i < visible.count; i++) { + if (layerDictionary.containsKey(visible[i]! as PdfReferenceHolder)) { + final PdfPageLayer? pdfLayer = + layerDictionary[visible[i]! as PdfReferenceHolder]; + if (pdfLayer != null) { + pdfLayer.visible = false; + if (PdfPageLayerHelper.getHelper(pdfLayer).dictionary != null && + PdfPageLayerHelper.getHelper( + pdfLayer, + ).dictionary!.containsKey(PdfDictionaryProperties.visible)) { + PdfPageLayerHelper.getHelper(pdfLayer).dictionary!.setProperty( + PdfDictionaryProperties.visible, + PdfBoolean(false), + ); + } + } + } + } + } + } + } + + void _removeLayer(PdfPageLayer layer) { + PdfDictionary? ocProperties; + _removeLayerContent(layer); + final PdfDictionary? resource = + PdfCrossTable.dereference( + PdfPageHelper.getHelper(_page).dictionary![PdfDictionaryProperties + .resources], + ) + as PdfDictionary?; + if (resource != null) { + final PdfDictionary? properties = + PdfCrossTable.dereference( + resource[PdfDictionaryProperties.properties], + ) + as PdfDictionary?; + if (properties != null && + PdfPageLayerHelper.getHelper(layer).layerID != null && + properties.containsKey(PdfPageLayerHelper.getHelper(layer).layerID)) { + properties.remove(PdfPageLayerHelper.getHelper(layer).layerID); + } + } + final PdfPage page = _page; + if (PdfPageHelper.getHelper(page).document != null && + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(page).document!, + ).catalog.containsKey(PdfDictionaryProperties.ocProperties)) { + ocProperties = + PdfCrossTable.dereference( + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(page).document!, + ).catalog[PdfDictionaryProperties.ocProperties], + ) + as PdfDictionary?; + } + if (ocProperties != null) { + final PdfArray? ocGroup = + PdfCrossTable.dereference(ocProperties[PdfDictionaryProperties.ocg]) + as PdfArray?; + if (ocGroup != null) { + _removeContent( + ocGroup, + PdfPageLayerHelper.getHelper(layer).referenceHolder, + ); + } + final PdfDictionary? defaultView = + PdfCrossTable.dereference( + ocProperties[PdfDictionaryProperties.defaultView], + ) + as PdfDictionary?; + if (defaultView != null) { + final PdfArray? on = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOn], + ) + as PdfArray?; + final PdfArray? order = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOrder], + ) + as PdfArray?; + final PdfArray? off = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.ocgOff], + ) + as PdfArray?; + final PdfArray? usage = + PdfCrossTable.dereference( + defaultView[PdfDictionaryProperties.usageApplication], + ) + as PdfArray?; + + if (usage != null && usage.count > 0) { + for (int i = 0; i < usage.count; i++) { + final PdfDictionary? usageDictionary = + PdfCrossTable.dereference(usage[i]) as PdfDictionary?; + if (usageDictionary != null && + usageDictionary.containsKey(PdfDictionaryProperties.ocg)) { + final PdfArray? usageOcGroup = + usageDictionary[PdfDictionaryProperties.ocg] as PdfArray?; + if (usageOcGroup != null) { + _removeContent( + usageOcGroup, + PdfPageLayerHelper.getHelper(layer).referenceHolder, + ); + } + } + } + } + if (order != null) { + _removeContent( + order, + PdfPageLayerHelper.getHelper(layer).referenceHolder, + ); + } + if (layer.visible && on != null) { + _removeContent( + on, + PdfPageLayerHelper.getHelper(layer).referenceHolder, + ); + } else if (off != null) { + _removeContent( + off, + PdfPageLayerHelper.getHelper(layer).referenceHolder, + ); + } + } + } + } + + void _removeContent(PdfArray content, PdfReferenceHolder? referenceHolder) { + bool flag = false; + for (int i = 0; i < content.count; i++) { + final IPdfPrimitive? primitive = content.elements[i]; + if (primitive != null && primitive is PdfReferenceHolder) { + final PdfReferenceHolder reference = primitive; + if (reference.reference != null && referenceHolder!.reference != null) { + if (reference.reference!.objNum == + referenceHolder.reference!.objNum) { + content.elements.removeAt(i); + flag = true; + i--; + } + } else if (identical(content.elements[i], referenceHolder)) { + content.elements.removeAt(i); + flag = true; + i--; + } else if (identical( + (content.elements[i]! as PdfReferenceHolder).object, + referenceHolder!.object, + )) { + content.elements.removeAt(i); + flag = true; + i--; + } + } else if (content.elements[i]! is PdfArray) { + _removeContent(content.elements[i]! as PdfArray, referenceHolder); + } + } + if (flag) { + content.changed = true; + } + } + + void _removeLayerContent(PdfPageLayer layer) { + bool isSkip = false; + for (int m = 0; m < PdfPageHelper.getHelper(_page).contents.count; m++) { + bool isNewContentStream = false; + bool? removePageContent = false; + List? stream = []; + final IPdfPrimitive? primitive = + PdfPageHelper.getHelper(_page).contents[m]; + if (primitive! is PdfReferenceHolder) { + final PdfReferenceHolder pdfReference = primitive as PdfReferenceHolder; + if (pdfReference.reference == null) { + isNewContentStream = true; + } + } + final PdfStream pageContent = + PdfCrossTable.dereference(PdfPageHelper.getHelper(_page).contents[m])! + as PdfStream; + final PdfStream data = PdfStream(); + if (PdfPageHelper.getHelper(_page).isLoadedPage) { + pageContent.decompress(); + } + stream = pageContent.dataStream; + final ContentParser parser = ContentParser(stream); + final PdfRecordCollection recordCollection = parser.readContent()!; + for (int j = 0; j < recordCollection.recordCollection.length; j++) { + final String? mOperator = + recordCollection.recordCollection[j].operatorName; + if (mOperator == 'BMC' || mOperator == 'EMC' || mOperator == 'BDC') { + final Map returnedValue = _processBeginMarkContent( + layer, + mOperator, + recordCollection.recordCollection[j].operands, + data, + isNewContentStream, + removePageContent, + ); + removePageContent = returnedValue['removePageContent']; + isSkip = true; + if (removePageContent!) { + break; + } + } + String? id; + if (recordCollection.recordCollection[j].operands!.isNotEmpty && + recordCollection.recordCollection[j].operands![0].startsWith('/')) { + id = recordCollection.recordCollection[j].operands![0].substring(1); + } + if (mOperator == PdfOperators.paintXObject && + (id == PdfPageLayerHelper.getHelper(layer).layerID)) { + isSkip = true; + } + if (mOperator == 'RG' || + mOperator == PdfOperators.saveState || + mOperator == PdfOperators.restoreState || + mOperator == PdfOperators.setLineWidth || + mOperator == PdfOperators.setLineCapStyle || + mOperator == PdfOperators.setLineJoinStyle || + mOperator == PdfOperators.setMiterLimit || + mOperator == PdfOperators.setDashPattern || + mOperator == PdfOperators.setGraphicsState || + mOperator == PdfOperators.currentMatrix || + mOperator == PdfOperators.selectColorSpaceForNonStroking || + mOperator == PdfOperators.selectColorSpaceForStroking) { + if (!isSkip) { + _streamWrite( + recordCollection.recordCollection[j].operands, + mOperator, + false, + data, + ); + } + } else if (!isSkip) { + _streamWrite( + recordCollection.recordCollection[j].operands, + mOperator, + true, + data, + ); + } + isSkip = false; + } + if (data.dataStream!.isNotEmpty && !removePageContent!) { + pageContent.clear(); + pageContent.dataStream!.clear(); + pageContent.write(data.dataStream); + } else { + pageContent.clear(); + } + if (removePageContent!) { + _removeContent( + PdfPageHelper.getHelper(_page).contents, + PdfPageLayerHelper.getHelper(layer).referenceHolder, + ); + if (PdfPageLayerHelper.getHelper(layer).graphics != null && + PdfGraphicsHelper.getHelper( + PdfPageLayerHelper.getHelper(layer).graphics!, + ).streamWriter != + null) { + final PdfStream? lcontent = + PdfGraphicsHelper.getHelper( + PdfPageLayerHelper.getHelper(layer).graphics!, + ).streamWriter!.stream; + if (lcontent != null) { + _removeContent( + PdfPageHelper.getHelper(_page).contents, + PdfReferenceHolder(lcontent), + ); + } + } + } + } + } + + Map _processBeginMarkContent( + PdfPageLayer parser, + String? mOperator, + List? operands, + PdfStream data, + bool isNewContentStream, + bool? removePageContent, + ) { + removePageContent = false; + if ('BDC' == mOperator) { + String? operand; + if (operands!.length > 1 && ((operands[0]) == '/OC')) { + operand = operands[1].substring(1); + } + if (_bdcCount > 0) { + _bdcCount++; + return {'removePageContent': removePageContent}; + } + if (operand != null && + (operand == PdfPageLayerHelper.getHelper(parser).layerID) && + !isNewContentStream) { + _bdcCount++; + } else if (operand != null && + (operand == PdfPageLayerHelper.getHelper(parser).layerID) && + isNewContentStream) { + removePageContent = true; + } + } + _streamWrite(operands, mOperator, true, data); + + if (('EMC' == mOperator) && _bdcCount > 0) { + _bdcCount--; + } + return {'removePageContent': removePageContent}; + } + + void _streamWrite( + List? operands, + String? mOperator, + bool skip, + PdfStream data, + ) { + PdfString pdfString; + if (skip && _bdcCount > 0) { + return; + } + if (operands != null) { + for (final String operand in operands) { + pdfString = PdfString(operand); + data.write(pdfString.data); + data.write(PdfOperators.whiteSpace); + } + } + pdfString = PdfString(mOperator!); + data.write(pdfString.data); + data.write(PdfOperators.newLine); + } + + /// Creates a new [PdfPageLayer] and adds it to the end of the collection. + PdfPageLayer add(String? name, bool? visible) { + final PdfPageLayer layer = PdfPageLayer(_page); + if (name != null) { + layer.name = name; + final String? layerID = PdfPageLayerHelper.getHelper(layer).layerID; + if (layerID == null) { + PdfPageLayerHelper.getHelper(layer).layerID = + 'OCG_${PdfResources.globallyUniqueIdentifier}'; + } + } + if (visible != null) { + layer.visible = visible; + } + addLayer(layer); + return layer; + } + + /// Adds [PdfPageLayer] to the collection. + int addLayer(PdfPageLayer layer) { + if (layer.page != _page) { + ArgumentError.value(layer, 'The layer belongs to another page'); + } + list.add(layer); + final int listIndex = pageLayerCollection.count - 1; + PdfPageHelper.getHelper(_page).contents.add(PdfReferenceHolder(layer)); + if (PdfPageLayerHelper.getHelper(layer).layerID != null) { + if (PdfPageHelper.getHelper(_page).isLoadedPage) { + _createLayerLoadedPage(layer); + } else { + final PdfDictionary ocProperties = PdfDictionary(); + ocProperties[PdfDictionaryProperties + .ocg] = _createOptionContentDictionary(layer); + ocProperties[PdfDictionaryProperties + .defaultView] = _createOptionalContentViews(layer); + PdfDocumentHelper.getHelper( + PdfPageHelper.getHelper(_page).document!, + ).catalog[PdfDictionaryProperties.ocProperties] = + ocProperties; + } + } + return listIndex; + } + + /// Returns index of the [PdfPageLayer] in the collection if exists, + /// -1 otherwise. + int indexOf(PdfPageLayer layer) { + return list.indexOf(layer); + } + + //Implementation + + /// Removes layer from the collection. + void remove(PdfPageLayer? layer, String? name) { + if (layer == null && name == null) { + ArgumentError.value('layer or layerName required'); + } + if (layer != null) { + _removeLayer(layer); + list.remove(layer); + } else { + for (int i = 0; i < list.length; i++) { + final PdfPageLayer layer = list[i] as PdfPageLayer; + if (layer.name == name) { + _removeLayer(layer); + list.remove(layer); + break; + } + } + } + } + + /// Removes layer by its index from collections + void removeAt(int index) { + if (index < 0 || index > list.length - 1) { + ArgumentError.value( + '$index Value can not be less 0 and greater List.Count - 1', + ); + } + final PdfPageLayer layer = pageLayerCollection[index]; + _removeLayer(layer); + list.removeAt(index); + } + + /// Clears layers from the [PdfPageLayerCollection]. + void clear() { + for (int i = 0; i < _page.layers._helper.list.length; i++) { + final PdfPageLayer layer = _page.layers._helper.list[i] as PdfPageLayer; + _removeLayer(layer); + } + _page.layers._helper.list.clear(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_settings.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_settings.dart index 11bf127dd..37ff9136c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_settings.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_settings.dart @@ -1,436 +1,436 @@ -import 'dart:ui'; - -import '../drawing/drawing.dart'; -import '../graphics/pdf_margins.dart'; -import 'enum.dart'; - -/// The class provides various setting related with PDF pages. -class PdfPageSettings { - //Constructor - /// Initalizes the [PdfPageSettings] class. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a PDF page settings. - /// document.pageSettings = - /// PdfPageSettings(PdfPageSize.a4, PdfPageOrientation.portrait); - /// //Set margins. - /// document.pageSettings.margins.all = 50; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfPageSettings([Size? size, PdfPageOrientation? orientation]) { - _helper = PdfPageSettingsHelper(this); - if (size != null) { - _size = PdfSize.fromSize(size); - } - if (orientation != null) { - _orientation = orientation; - _updateSize(orientation); - } - _helper.origin = PdfPoint(0, 0); - _margins = PdfMargins(); - } - - //Fields - late PdfPageSettingsHelper _helper; - late PdfMargins _margins; - PdfPageOrientation _orientation = PdfPageOrientation.portrait; - PdfSize _size = PdfSize.fromSize(PdfPageSize.a4); - PdfPageRotateAngle _rotateAngle = PdfPageRotateAngle.rotateAngle0; - - //Properties - /// Gets or sets the margins of the PDF page. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.margins.all = 50; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfMargins get margins => _margins; - set margins(PdfMargins value) { - if (!PdfMarginsHelper.getHelper(_margins).equals(value) && - !_helper.isPageAdded) { - _margins = value; - } - } - - /// Gets the width of the page. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Get page width. - /// double width = document.pageSettings.width; - /// //Get page height. - /// double height = document.pageSettings.height; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, width, height)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - double get width => _size.width; - - /// Gets the height of the page. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Get page width. - /// double width = document.pageSettings.width; - /// //Get page height. - /// double height = document.pageSettings.height; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, width, height)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - double get height => _size.height; - - /// Gets the page orientation. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Get the page orientation. - /// PdfPageOrientation orientation = document.pageSettings.orientation; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH.(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfPageOrientation get orientation => _orientation; - - /// Sets the page orientation. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Set the page orientation. - /// document.pageSettings.orientation = PdfPageOrientation.landscape; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - set orientation(PdfPageOrientation value) { - if (value != _orientation && !_helper.isPageAdded) { - _orientation = value; - _updateSize(_orientation); - } - } - - /// Gets the size fo the page. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Get the page size. - /// Size pageSize = document.pageSettings.size; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - Size get size => _size.size; - - /// Sets the page size. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Set the page size. - /// document.pageSettings.size = Size(595, 842); - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - set size(Size value) { - if (!_helper.isPageAdded) { - _updateSize(_orientation, value); - } - } - - /// Gets the number of degrees by which the page should be rotated clockwise - /// when displayed or printed. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Get the rotate angle. - /// PdfPageRotateAngle angle = document.pageSettings.rotate; - /// //Set the rotation angle. - /// document.pageSettings.rotate = PdfPageRotateAngle.rotateAngle90; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfPageRotateAngle get rotate => _rotateAngle; - - /// Sets the number of degrees by which the page should be rotated clockwise - /// when displayed or printed. - /// - ///```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Get the rotate angle. - /// PdfPageRotateAngle angle = document.pageSettings.rotate; - /// //Set the rotation angle. - /// document.pageSettings.rotate = PdfPageRotateAngle.rotateAngle90; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - set rotate(PdfPageRotateAngle value) { - if (!_helper.isPageAdded) { - _rotateAngle = value; - _helper.isRotation = true; - } - } - - //Public methods - /// Sets the margins. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(50); - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - void setMargins(double all, [double? top, double? right, double? bottom]) { - if (!_helper.isPageAdded) { - if (top != null && right != null && bottom != null) { - PdfMarginsHelper.getHelper( - margins, - ).setMarginsAll(all, top, right, bottom); - } else if (top != null && right == null) { - PdfMarginsHelper.getHelper(margins).setMarginsLT(all, top); - } else if (top == null && bottom != null) { - PdfMarginsHelper.getHelper(margins).setMarginsLT(all, bottom); - } else { - PdfMarginsHelper.getHelper(margins).setMargins(all); - } - } - } - - //Implementation - void _updateSize(PdfPageOrientation orientation, [Size? size]) { - double min; - double max; - if (size != null) { - min = size.width < size.height ? size.width : size.height; - max = size.width > size.height ? size.width : size.height; - } else { - min = width < height ? width : height; - max = width > height ? width : height; - } - switch (orientation) { - case PdfPageOrientation.portrait: - _size = PdfSize(min, max); - break; - - case PdfPageOrientation.landscape: - _size = PdfSize(max, min); - break; - } - } -} - -/// [PdfPageSettings] helper -class PdfPageSettingsHelper { - /// internal constructor - PdfPageSettingsHelper(this.base); - - /// internal field - late PdfPageSettings base; - - /// internal method - static PdfPageSettingsHelper getHelper(PdfPageSettings base) { - return base._helper; - } - - /// internal field - late PdfPoint origin; - - /// internal method - bool isRotation = false; - - /// internal method - // ignore: prefer_final_fields - bool isPageAdded = false; - - /// internal method - Size getActualSize() { - return Size( - base.width - (base.margins.left + base.margins.right), - base.height - (base.margins.top + base.margins.bottom), - ); - } - - /// internal method - PdfPageSettings clone() { - final PdfPageSettings result = PdfPageSettings(); - result.size = Size(base.size.width, base.size.height); - switch (base.rotate) { - case PdfPageRotateAngle.rotateAngle90: - result.rotate = PdfPageRotateAngle.rotateAngle90; - break; - case PdfPageRotateAngle.rotateAngle180: - result.rotate = PdfPageRotateAngle.rotateAngle180; - break; - case PdfPageRotateAngle.rotateAngle270: - result.rotate = PdfPageRotateAngle.rotateAngle270; - break; - case PdfPageRotateAngle.rotateAngle0: - result.rotate = PdfPageRotateAngle.rotateAngle0; - break; - } - if (base.orientation == PdfPageOrientation.landscape) { - result.orientation = PdfPageOrientation.landscape; - } else { - result.orientation = PdfPageOrientation.portrait; - } - result.margins = PdfMarginsHelper.getHelper(base.margins).clone(); - return result; - } -} - -/// Represents information about various predefined page sizes. -class PdfPageSize { - PdfPageSize._(); - - /// Letter format. - static const Size letter = Size(612, 792); - - /// Note format. - static const Size note = Size(540, 720); - - /// Legal format. - static const Size legal = Size(612, 1008); - - /// A0 format. - static const Size a0 = Size(2380, 3368); - - /// A1 format. - static const Size a1 = Size(1684, 2380); - - /// A2 format. - static const Size a2 = Size(1190, 1684); - - /// A3 format. - static const Size a3 = Size(842, 1190); - - /// A4 format. - static const Size a4 = Size(595, 842); - - /// A5 format. - static const Size a5 = Size(421, 595); - - /// A6 format. - static const Size a6 = Size(297, 421); - - /// A7 format. - static const Size a7 = Size(210, 297); - - /// A8 format. - static const Size a8 = Size(148, 210); - - /// A9 format. - static const Size a9 = Size(105, 148); - - /// A10 format. - static const Size a10 = Size(74, 105); - - /// B0 format. - static const Size b0 = Size(2836, 4008); - - /// B1 format. - static const Size b1 = Size(2004, 2836); - - /// B2 format. - static const Size b2 = Size(1418, 2004); - - /// B3 format. - static const Size b3 = Size(1002, 1418); - - /// B4 format. - static const Size b4 = Size(709, 1002); - - /// B5 format. - static const Size b5 = Size(501, 709); - - /// ArchE format. - static const Size archE = Size(2592, 3456); - - /// ArchD format. - static const Size archD = Size(1728, 2592); - - /// ArchC format. - static const Size archC = Size(1296, 1728); - - /// ArchB format. - static const Size archB = Size(864, 1296); - - /// ArchA format. - static const Size archA = Size(648, 864); - - /// The American Foolscap format. - static const Size flsa = Size(612, 936); - - /// HalfLetter format. - static const Size halfLetter = Size(396, 612); - - /// 11x17 format. - static const Size letter11x17 = Size(792, 1224); - - /// Ledger format. - static const Size ledger = Size(1224, 792); -} +import 'dart:ui'; + +import '../drawing/drawing.dart'; +import '../graphics/pdf_margins.dart'; +import 'enum.dart'; + +/// The class provides various setting related with PDF pages. +class PdfPageSettings { + //Constructor + /// Initalizes the [PdfPageSettings] class. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a PDF page settings. + /// document.pageSettings = + /// PdfPageSettings(PdfPageSize.a4, PdfPageOrientation.portrait); + /// //Set margins. + /// document.pageSettings.margins.all = 50; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfPageSettings([Size? size, PdfPageOrientation? orientation]) { + _helper = PdfPageSettingsHelper(this); + if (size != null) { + _size = PdfSize.fromSize(size); + } + if (orientation != null) { + _orientation = orientation; + _updateSize(orientation); + } + _helper.origin = PdfPoint(0, 0); + _margins = PdfMargins(); + } + + //Fields + late PdfPageSettingsHelper _helper; + late PdfMargins _margins; + PdfPageOrientation _orientation = PdfPageOrientation.portrait; + PdfSize _size = PdfSize.fromSize(PdfPageSize.a4); + PdfPageRotateAngle _rotateAngle = PdfPageRotateAngle.rotateAngle0; + + //Properties + /// Gets or sets the margins of the PDF page. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.margins.all = 50; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfMargins get margins => _margins; + set margins(PdfMargins value) { + if (!PdfMarginsHelper.getHelper(_margins).equals(value) && + !_helper.isPageAdded) { + _margins = value; + } + } + + /// Gets the width of the page. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Get page width. + /// double width = document.pageSettings.width; + /// //Get page height. + /// double height = document.pageSettings.height; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, width, height)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + double get width => _size.width; + + /// Gets the height of the page. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Get page width. + /// double width = document.pageSettings.width; + /// //Get page height. + /// double height = document.pageSettings.height; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, width, height)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + double get height => _size.height; + + /// Gets the page orientation. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Get the page orientation. + /// PdfPageOrientation orientation = document.pageSettings.orientation; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH.(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfPageOrientation get orientation => _orientation; + + /// Sets the page orientation. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Set the page orientation. + /// document.pageSettings.orientation = PdfPageOrientation.landscape; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + set orientation(PdfPageOrientation value) { + if (value != _orientation && !_helper.isPageAdded) { + _orientation = value; + _updateSize(_orientation); + } + } + + /// Gets the size fo the page. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Get the page size. + /// Size pageSize = document.pageSettings.size; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + Size get size => _size.size; + + /// Sets the page size. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Set the page size. + /// document.pageSettings.size = Size(595, 842); + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + set size(Size value) { + if (!_helper.isPageAdded) { + _updateSize(_orientation, value); + } + } + + /// Gets the number of degrees by which the page should be rotated clockwise + /// when displayed or printed. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Get the rotate angle. + /// PdfPageRotateAngle angle = document.pageSettings.rotate; + /// //Set the rotation angle. + /// document.pageSettings.rotate = PdfPageRotateAngle.rotateAngle90; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfPageRotateAngle get rotate => _rotateAngle; + + /// Sets the number of degrees by which the page should be rotated clockwise + /// when displayed or printed. + /// + ///```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Get the rotate angle. + /// PdfPageRotateAngle angle = document.pageSettings.rotate; + /// //Set the rotation angle. + /// document.pageSettings.rotate = PdfPageRotateAngle.rotateAngle90; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + set rotate(PdfPageRotateAngle value) { + if (!_helper.isPageAdded) { + _rotateAngle = value; + _helper.isRotation = true; + } + } + + //Public methods + /// Sets the margins. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(50); + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + void setMargins(double all, [double? top, double? right, double? bottom]) { + if (!_helper.isPageAdded) { + if (top != null && right != null && bottom != null) { + PdfMarginsHelper.getHelper( + margins, + ).setMarginsAll(all, top, right, bottom); + } else if (top != null && right == null) { + PdfMarginsHelper.getHelper(margins).setMarginsLT(all, top); + } else if (top == null && bottom != null) { + PdfMarginsHelper.getHelper(margins).setMarginsLT(all, bottom); + } else { + PdfMarginsHelper.getHelper(margins).setMargins(all); + } + } + } + + //Implementation + void _updateSize(PdfPageOrientation orientation, [Size? size]) { + double min; + double max; + if (size != null) { + min = size.width < size.height ? size.width : size.height; + max = size.width > size.height ? size.width : size.height; + } else { + min = width < height ? width : height; + max = width > height ? width : height; + } + switch (orientation) { + case PdfPageOrientation.portrait: + _size = PdfSize(min, max); + break; + + case PdfPageOrientation.landscape: + _size = PdfSize(max, min); + break; + } + } +} + +/// [PdfPageSettings] helper +class PdfPageSettingsHelper { + /// internal constructor + PdfPageSettingsHelper(this.base); + + /// internal field + late PdfPageSettings base; + + /// internal method + static PdfPageSettingsHelper getHelper(PdfPageSettings base) { + return base._helper; + } + + /// internal field + late PdfPoint origin; + + /// internal method + bool isRotation = false; + + /// internal method + // ignore: prefer_final_fields + bool isPageAdded = false; + + /// internal method + Size getActualSize() { + return Size( + base.width - (base.margins.left + base.margins.right), + base.height - (base.margins.top + base.margins.bottom), + ); + } + + /// internal method + PdfPageSettings clone() { + final PdfPageSettings result = PdfPageSettings(); + result.size = Size(base.size.width, base.size.height); + switch (base.rotate) { + case PdfPageRotateAngle.rotateAngle90: + result.rotate = PdfPageRotateAngle.rotateAngle90; + break; + case PdfPageRotateAngle.rotateAngle180: + result.rotate = PdfPageRotateAngle.rotateAngle180; + break; + case PdfPageRotateAngle.rotateAngle270: + result.rotate = PdfPageRotateAngle.rotateAngle270; + break; + case PdfPageRotateAngle.rotateAngle0: + result.rotate = PdfPageRotateAngle.rotateAngle0; + break; + } + if (base.orientation == PdfPageOrientation.landscape) { + result.orientation = PdfPageOrientation.landscape; + } else { + result.orientation = PdfPageOrientation.portrait; + } + result.margins = PdfMarginsHelper.getHelper(base.margins).clone(); + return result; + } +} + +/// Represents information about various predefined page sizes. +class PdfPageSize { + PdfPageSize._(); + + /// Letter format. + static const Size letter = Size(612, 792); + + /// Note format. + static const Size note = Size(540, 720); + + /// Legal format. + static const Size legal = Size(612, 1008); + + /// A0 format. + static const Size a0 = Size(2380, 3368); + + /// A1 format. + static const Size a1 = Size(1684, 2380); + + /// A2 format. + static const Size a2 = Size(1190, 1684); + + /// A3 format. + static const Size a3 = Size(842, 1190); + + /// A4 format. + static const Size a4 = Size(595, 842); + + /// A5 format. + static const Size a5 = Size(421, 595); + + /// A6 format. + static const Size a6 = Size(297, 421); + + /// A7 format. + static const Size a7 = Size(210, 297); + + /// A8 format. + static const Size a8 = Size(148, 210); + + /// A9 format. + static const Size a9 = Size(105, 148); + + /// A10 format. + static const Size a10 = Size(74, 105); + + /// B0 format. + static const Size b0 = Size(2836, 4008); + + /// B1 format. + static const Size b1 = Size(2004, 2836); + + /// B2 format. + static const Size b2 = Size(1418, 2004); + + /// B3 format. + static const Size b3 = Size(1002, 1418); + + /// B4 format. + static const Size b4 = Size(709, 1002); + + /// B5 format. + static const Size b5 = Size(501, 709); + + /// ArchE format. + static const Size archE = Size(2592, 3456); + + /// ArchD format. + static const Size archD = Size(1728, 2592); + + /// ArchC format. + static const Size archC = Size(1296, 1728); + + /// ArchB format. + static const Size archB = Size(864, 1296); + + /// ArchA format. + static const Size archA = Size(648, 864); + + /// The American Foolscap format. + static const Size flsa = Size(612, 936); + + /// HalfLetter format. + static const Size halfLetter = Size(396, 612); + + /// 11x17 format. + static const Size letter11x17 = Size(792, 1224); + + /// Ledger format. + static const Size ledger = Size(1224, 792); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_template_element.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_template_element.dart index 3b07de8cb..a34478e24 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_template_element.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_page_template_element.dart @@ -1,763 +1,763 @@ -import 'dart:ui'; - -import '../drawing/drawing.dart'; -import '../graphics/figures/pdf_template.dart'; -import '../graphics/pdf_graphics.dart'; -import '../pdf_document/pdf_document.dart'; -import 'enum.dart'; -import 'pdf_page.dart'; -import 'pdf_page_layer.dart'; -import 'pdf_page_settings.dart'; -import 'pdf_section.dart'; - -/// Describes a page template object that can be used as header/footer, watermark or stamp. -/// ```dart -/// //Create a new pdf document -/// PdfDocument document = PdfDocument(); -/// //Create a header and add the top of the document. -/// document.template.top = PdfPageTemplateElement(Rect.fromLTWH(0, 0, 515, 50)) -/// ..graphics.drawString( -/// 'Header', PdfStandardFont(PdfFontFamily.helvetica, 14), -/// brush: PdfBrushes.black); -/// //Create footer and add the bottom of the document. -/// document.template.bottom = -/// PdfPageTemplateElement(Rect.fromLTWH(0, 0, 515, 50)) -/// ..graphics.drawString( -/// 'Footer', PdfStandardFont(PdfFontFamily.helvetica, 11), -/// brush: PdfBrushes.black); -/// //Add the pages to the document -/// for (int i = 1; i <= 5; i++) { -/// document.pages.add().graphics.drawString( -/// 'Page $i', PdfStandardFont(PdfFontFamily.timesRoman, 11), -/// bounds: Rect.fromLTWH(250, 0, 515, 100)); -/// } -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfPageTemplateElement { - //Constructor - /// Initializes a new instance of the [PdfPageTemplateElement] class. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// header.graphics.drawString( - /// 'Header', PdfStandardFont(PdfFontFamily.helvetica, 14), - /// brush: PdfBrushes.black); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); - /// header.graphics.drawString( - /// 'Footer', PdfStandardFont(PdfFontFamily.helvetica, 11), - /// brush: PdfBrushes.black); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageTemplateElement(Rect bounds, [PdfPage? page]) { - _helper = PdfPageTemplateElementHelper(this); - x = bounds.left; - y = bounds.top; - _helper._pdfTemplate = PdfTemplate(bounds.width, bounds.height); - if (page != null) { - graphics.colorSpace = PdfPageHelper.getHelper(page).document!.colorSpace; - } - } - - //Fields - /// Indicates whether the page template is located in front of the - /// page layers or behind of it. If false, the page template will be located - /// behind of page layer. - bool foreground = false; - PdfPoint _currentLocation = PdfPoint.empty; - late PdfPageTemplateElementHelper _helper; - - //Properties - /// Gets or sets the dock style of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets the dock style - /// custom.dock = PdfDockStyle.right; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfDockStyle get dock { - _helper._dockStyle ??= PdfDockStyle.none; - return _helper._dockStyle!; - } - - set dock(PdfDockStyle value) { - _helper._dockStyle = value; - _helper._resetAlignment(); - } - - /// Gets or sets the alignment of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets dock style. - /// custom.dock = PdfDockStyle.right; - /// //Gets or sets alignment style. - /// custom.alignment = PdfAlignmentStyle.middleCenter; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfAlignmentStyle get alignment => _helper._alignmentStyle; - set alignment(PdfAlignmentStyle value) { - if (_helper._alignmentStyle != value) { - _setAlignment(value); - } - } - - /// Indicates whether the page template is located behind of the page layers - /// or in front of it. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// const Offset(5, 5) & const Size(110, 110), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets background. - /// custom.background = true; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool get background => !foreground; - set background(bool value) { - foreground = !value; - } - - /// Gets or sets location of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets location. - /// custom.location = Offset(5, 5); - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Offset get location => _currentLocation.offset; - set location(Offset value) { - if (_helper._templateType == TemplateType.none) { - _currentLocation = PdfPoint.fromOffset(value); - } - } - - /// Gets or sets X co-ordinate of the template element on the page. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets X co-ordinate. - /// custom.x = 10.10; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get x => _currentLocation.x; - set x(double value) { - if (_helper.type == TemplateType.none) { - _currentLocation.x = value; - } - } - - /// Gets or sets Y co-ordinate of the template element on the page. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets Y co-ordinate. - /// custom.y = 10.10; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get y => _currentLocation.y; - set y(double value) { - if (_helper.type == TemplateType.none) { - _currentLocation.y = value; - } - } - - /// Gets or sets the size of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets size. - /// custom.size = Size(110, 110); - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Size get size => _helper._template!.size; - set size(Size value) { - if (_helper.type == TemplateType.none) { - _helper._template!.reset(value.width, value.height); - } - } - - /// Gets or sets width of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets width. - /// custom.width = 110; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get width => _helper._template!.size.width; - set width(double value) { - if (_helper._template!.size.width != value && - _helper.type == TemplateType.none) { - _helper._template!.reset(value, _helper._template!.size.height); - } - } - - /// Gets or sets height of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets height. - /// custom.height = 110; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get height => _helper._template!.size.height; - set height(double value) { - if (_helper._template!.size.height != value && - _helper.type == TemplateType.none) { - _helper._template!.reset(_helper._template!.size.width, value); - } - } - - /// Gets or sets graphics context of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGraphics get graphics => _helper._template!.graphics!; - - /// Gets or sets bounds of the page template element. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Set margins. - /// document.pageSettings.setMargins(25); - /// //Create the page template with specific bounds - /// PdfPageTemplateElement custom = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); - /// document.template.stamps.add(custom); - /// //Gets or sets bounds. - /// Rect bounds = custom.bounds; - /// //Draw template into pdf page. - /// custom.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), - /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), - /// bounds: Rect.fromLTWH(0, 0, 100, 100)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Rect get bounds => Rect.fromLTWH(x, y, width, height); - set bounds(Rect value) { - if (_helper.type == TemplateType.none) { - location = Offset(value.left, value.top); - size = Size(value.width, value.height); - } - } - - //Implementation - void _setAlignment(PdfAlignmentStyle alignment) { - if (dock == PdfDockStyle.none) { - _helper._alignmentStyle = alignment; - } else { - bool canBeSet = false; - switch (dock) { - case PdfDockStyle.left: - canBeSet = - alignment == PdfAlignmentStyle.topLeft || - alignment == PdfAlignmentStyle.middleLeft || - alignment == PdfAlignmentStyle.bottomLeft || - alignment == PdfAlignmentStyle.none; - break; - case PdfDockStyle.top: - canBeSet = - alignment == PdfAlignmentStyle.topLeft || - alignment == PdfAlignmentStyle.topCenter || - alignment == PdfAlignmentStyle.topRight || - alignment == PdfAlignmentStyle.none; - break; - case PdfDockStyle.right: - canBeSet = - alignment == PdfAlignmentStyle.topRight || - alignment == PdfAlignmentStyle.middleRight || - alignment == PdfAlignmentStyle.bottomRight || - alignment == PdfAlignmentStyle.none; - break; - case PdfDockStyle.bottom: - canBeSet = - alignment == PdfAlignmentStyle.bottomLeft || - alignment == PdfAlignmentStyle.bottomCenter || - alignment == PdfAlignmentStyle.bottomRight || - alignment == PdfAlignmentStyle.none; - break; - case PdfDockStyle.fill: - canBeSet = - alignment == PdfAlignmentStyle.middleCenter || - alignment == PdfAlignmentStyle.none; - break; - case PdfDockStyle.none: - break; - } - if (canBeSet) { - _helper._alignmentStyle = alignment; - } - } - } -} - -/// [PdfPageTemplateElement] helper -class PdfPageTemplateElementHelper { - /// internal constructor - PdfPageTemplateElementHelper(this.base); - - /// internal field - late PdfPageTemplateElement base; - - /// internal method - static PdfPageTemplateElementHelper getHelper(PdfPageTemplateElement base) { - return base._helper; - } - - TemplateType _templateType = TemplateType.none; - PdfTemplate? _pdfTemplate; - PdfAlignmentStyle _alignmentStyle = PdfAlignmentStyle.none; - PdfDockStyle? _dockStyle; - - /// Gets type of the usage of this page template. - TemplateType get type => _templateType; - - /// Sets type of the usage of this page template. - set type(TemplateType value) { - _updateDocking(value); - _templateType = value; - } - - void _updateDocking(TemplateType type) { - if (type != TemplateType.none) { - switch (type) { - case TemplateType.top: - base.dock = PdfDockStyle.top; - break; - case TemplateType.bottom: - base.dock = PdfDockStyle.bottom; - break; - case TemplateType.left: - base.dock = PdfDockStyle.left; - break; - case TemplateType.right: - base.dock = PdfDockStyle.right; - break; - case TemplateType.none: - break; - } - _resetAlignment(); - } - } - - void _resetAlignment() { - base.alignment = PdfAlignmentStyle.none; - } - - /// Gets PDF template object. - PdfTemplate? get _template => _pdfTemplate; - - /// internal method - void draw(PdfPageLayer layer, PdfDocument document) { - final PdfPage page = layer.page; - final Rect bounds = _calculateBounds(page, document); - PdfPageHelper.getHelper(layer.page).isDefaultGraphics = true; - layer.graphics.drawPdfTemplate(_template!, bounds.topLeft, bounds.size); - } - - Rect _calculateBounds(PdfPage page, PdfDocument document) { - Rect result = base.bounds; - if (_alignmentStyle != PdfAlignmentStyle.none) { - result = _getAlignmentBounds(page, document); - } else if (_dockStyle != PdfDockStyle.none) { - result = _getDockBounds(page, document); - } - return result; - } - - Rect _getAlignmentBounds(PdfPage page, PdfDocument document) { - Rect result = base.bounds; - if (type == TemplateType.none) { - result = _getSimpleAlignmentBounds(page, document); - } - return result; - } - - Rect _getSimpleAlignmentBounds(PdfPage page, PdfDocument document) { - final Rect result = base.bounds; - final PdfSection section = PdfPageHelper.getHelper(page).section!; - final PdfRectangle actualBounds = PdfSectionHelper.getHelper( - section, - ).getActualBounds(page, false, document); - double x = base.location.dx; - double y = base.location.dy; - - switch (_alignmentStyle) { - case PdfAlignmentStyle.topLeft: - { - x = 0.0; - y = 0.0; - } - break; - - case PdfAlignmentStyle.topCenter: - { - x = (actualBounds.width - base.width) / 2.0; - y = 0.0; - } - break; - - case PdfAlignmentStyle.topRight: - { - x = actualBounds.width - base.width; - y = 0.0; - } - break; - - case PdfAlignmentStyle.middleLeft: - { - x = 0.0; - y = (actualBounds.height - base.height) / 2.0; - } - break; - - case PdfAlignmentStyle.middleCenter: - { - x = (actualBounds.width - base.width) / 2.0; - y = (actualBounds.height - base.height) / 2.0; - } - break; - - case PdfAlignmentStyle.middleRight: - { - x = actualBounds.width - base.width; - y = (actualBounds.height - base.height) / 2.0; - } - break; - - case PdfAlignmentStyle.bottomLeft: - { - x = 0.0; - y = actualBounds.height - base.height; - } - break; - - case PdfAlignmentStyle.bottomCenter: - { - x = (actualBounds.width - base.width) / 2.0; - y = actualBounds.height - base.height; - } - break; - - case PdfAlignmentStyle.bottomRight: - { - x = actualBounds.width - base.width; - y = actualBounds.height - base.height; - } - break; - case PdfAlignmentStyle.none: - break; - } - - return Offset(x, y) & result.size; - } - - Rect _getDockBounds(PdfPage page, PdfDocument document) { - Rect result = base.bounds; - - if (type == TemplateType.none) { - result = _getSimpleDockBounds(page, document); - } else { - result = _getTemplateDockBounds(page, document); - } - return result; - } - - Rect _getSimpleDockBounds(PdfPage page, PdfDocument document) { - Rect result = base.bounds; - final PdfSection section = PdfPageHelper.getHelper(page).section!; - final PdfRectangle actualBounds = PdfSectionHelper.getHelper( - section, - ).getActualBounds(page, false, document); - double x = base.location.dx; - double y = base.location.dy; - double? width = base.width; - double? height = base.height; - - switch (_dockStyle) { - case PdfDockStyle.left: - x = 0.0; - y = 0.0; - width = base.width; - height = actualBounds.height; - break; - - case PdfDockStyle.top: - x = 0.0; - y = 0.0; - width = actualBounds.width; - height = base.height; - break; - - case PdfDockStyle.right: - x = actualBounds.width - base.width; - y = 0.0; - width = base.width; - height = actualBounds.height; - break; - - case PdfDockStyle.bottom: - x = 0.0; - y = actualBounds.height - base.height; - width = actualBounds.width; - height = base.height; - break; - - case PdfDockStyle.fill: - x = 0.0; - x = 0.0; - width = actualBounds.width; - height = actualBounds.height; - break; - case PdfDockStyle.none: - break; - // ignore: no_default_cases - default: - break; - } - - result = Rect.fromLTWH(x, y, width, height); - - return result; - } - - Rect _getTemplateDockBounds(PdfPage page, PdfDocument document) { - final PdfSection section = PdfPageHelper.getHelper(page).section!; - final PdfRectangle actualBounds = PdfSectionHelper.getHelper( - section, - ).getActualBounds(page, false, document); - final PdfSize actualSize = PdfSize.fromSize( - PdfPageSettingsHelper.getHelper(section.pageSettings).getActualSize(), - ); - double x = base.location.dx; - double y = base.location.dy; - double? width = base.width; - double? height = base.height; - - switch (_dockStyle) { - case PdfDockStyle.left: - x = -actualBounds.x; - y = 0.0; - width = base.width; - height = actualBounds.height; - break; - - case PdfDockStyle.top: - x = -actualBounds.x; - y = -actualBounds.y; - width = actualSize.width; - height = base.height; - - if (actualBounds.height < 0) { - y = -actualBounds.y + actualSize.height; - } - break; - - case PdfDockStyle.right: - x = - actualBounds.width + - PdfSectionHelper.getHelper( - section, - ).getRightIndentWidth(document, page, false) - - base.width; - y = 0.0; - width = base.width; - height = actualBounds.height; - break; - - case PdfDockStyle.bottom: - x = -actualBounds.x; - y = - actualBounds.height + - PdfSectionHelper.getHelper( - section, - ).getBottomIndentHeight(document, page, false) - - base.height; - width = actualSize.width; - height = base.height; - if (actualBounds.height < 0) { - y -= actualSize.height; - } - break; - - case PdfDockStyle.fill: - x = 0.0; - x = 0.0; - width = actualBounds.width; - height = actualBounds.height; - break; - case PdfDockStyle.none: - break; - // ignore: no_default_cases - default: - break; - } - return Rect.fromLTWH(x, y, width, height); - } -} +import 'dart:ui'; + +import '../drawing/drawing.dart'; +import '../graphics/figures/pdf_template.dart'; +import '../graphics/pdf_graphics.dart'; +import '../pdf_document/pdf_document.dart'; +import 'enum.dart'; +import 'pdf_page.dart'; +import 'pdf_page_layer.dart'; +import 'pdf_page_settings.dart'; +import 'pdf_section.dart'; + +/// Describes a page template object that can be used as header/footer, watermark or stamp. +/// ```dart +/// //Create a new pdf document +/// PdfDocument document = PdfDocument(); +/// //Create a header and add the top of the document. +/// document.template.top = PdfPageTemplateElement(Rect.fromLTWH(0, 0, 515, 50)) +/// ..graphics.drawString( +/// 'Header', PdfStandardFont(PdfFontFamily.helvetica, 14), +/// brush: PdfBrushes.black); +/// //Create footer and add the bottom of the document. +/// document.template.bottom = +/// PdfPageTemplateElement(Rect.fromLTWH(0, 0, 515, 50)) +/// ..graphics.drawString( +/// 'Footer', PdfStandardFont(PdfFontFamily.helvetica, 11), +/// brush: PdfBrushes.black); +/// //Add the pages to the document +/// for (int i = 1; i <= 5; i++) { +/// document.pages.add().graphics.drawString( +/// 'Page $i', PdfStandardFont(PdfFontFamily.timesRoman, 11), +/// bounds: Rect.fromLTWH(250, 0, 515, 100)); +/// } +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfPageTemplateElement { + //Constructor + /// Initializes a new instance of the [PdfPageTemplateElement] class. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// header.graphics.drawString( + /// 'Header', PdfStandardFont(PdfFontFamily.helvetica, 14), + /// brush: PdfBrushes.black); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); + /// header.graphics.drawString( + /// 'Footer', PdfStandardFont(PdfFontFamily.helvetica, 11), + /// brush: PdfBrushes.black); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageTemplateElement(Rect bounds, [PdfPage? page]) { + _helper = PdfPageTemplateElementHelper(this); + x = bounds.left; + y = bounds.top; + _helper._pdfTemplate = PdfTemplate(bounds.width, bounds.height); + if (page != null) { + graphics.colorSpace = PdfPageHelper.getHelper(page).document!.colorSpace; + } + } + + //Fields + /// Indicates whether the page template is located in front of the + /// page layers or behind of it. If false, the page template will be located + /// behind of page layer. + bool foreground = false; + PdfPoint _currentLocation = PdfPoint.empty; + late PdfPageTemplateElementHelper _helper; + + //Properties + /// Gets or sets the dock style of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets the dock style + /// custom.dock = PdfDockStyle.right; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfDockStyle get dock { + _helper._dockStyle ??= PdfDockStyle.none; + return _helper._dockStyle!; + } + + set dock(PdfDockStyle value) { + _helper._dockStyle = value; + _helper._resetAlignment(); + } + + /// Gets or sets the alignment of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets dock style. + /// custom.dock = PdfDockStyle.right; + /// //Gets or sets alignment style. + /// custom.alignment = PdfAlignmentStyle.middleCenter; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfAlignmentStyle get alignment => _helper._alignmentStyle; + set alignment(PdfAlignmentStyle value) { + if (_helper._alignmentStyle != value) { + _setAlignment(value); + } + } + + /// Indicates whether the page template is located behind of the page layers + /// or in front of it. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// const Offset(5, 5) & const Size(110, 110), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets background. + /// custom.background = true; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool get background => !foreground; + set background(bool value) { + foreground = !value; + } + + /// Gets or sets location of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets location. + /// custom.location = Offset(5, 5); + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Offset get location => _currentLocation.offset; + set location(Offset value) { + if (_helper._templateType == TemplateType.none) { + _currentLocation = PdfPoint.fromOffset(value); + } + } + + /// Gets or sets X co-ordinate of the template element on the page. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets X co-ordinate. + /// custom.x = 10.10; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get x => _currentLocation.x; + set x(double value) { + if (_helper.type == TemplateType.none) { + _currentLocation.x = value; + } + } + + /// Gets or sets Y co-ordinate of the template element on the page. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets Y co-ordinate. + /// custom.y = 10.10; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get y => _currentLocation.y; + set y(double value) { + if (_helper.type == TemplateType.none) { + _currentLocation.y = value; + } + } + + /// Gets or sets the size of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets size. + /// custom.size = Size(110, 110); + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Size get size => _helper._template!.size; + set size(Size value) { + if (_helper.type == TemplateType.none) { + _helper._template!.reset(value.width, value.height); + } + } + + /// Gets or sets width of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets width. + /// custom.width = 110; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get width => _helper._template!.size.width; + set width(double value) { + if (_helper._template!.size.width != value && + _helper.type == TemplateType.none) { + _helper._template!.reset(value, _helper._template!.size.height); + } + } + + /// Gets or sets height of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets height. + /// custom.height = 110; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get height => _helper._template!.size.height; + set height(double value) { + if (_helper._template!.size.height != value && + _helper.type == TemplateType.none) { + _helper._template!.reset(_helper._template!.size.width, value); + } + } + + /// Gets or sets graphics context of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGraphics get graphics => _helper._template!.graphics!; + + /// Gets or sets bounds of the page template element. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Set margins. + /// document.pageSettings.setMargins(25); + /// //Create the page template with specific bounds + /// PdfPageTemplateElement custom = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, 100, 100), document.pages.add()); + /// document.template.stamps.add(custom); + /// //Gets or sets bounds. + /// Rect bounds = custom.bounds; + /// //Draw template into pdf page. + /// custom.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(255, 165, 0), width: 3), + /// brush: PdfSolidBrush(PdfColor(173, 255, 47)), + /// bounds: Rect.fromLTWH(0, 0, 100, 100)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Rect get bounds => Rect.fromLTWH(x, y, width, height); + set bounds(Rect value) { + if (_helper.type == TemplateType.none) { + location = Offset(value.left, value.top); + size = Size(value.width, value.height); + } + } + + //Implementation + void _setAlignment(PdfAlignmentStyle alignment) { + if (dock == PdfDockStyle.none) { + _helper._alignmentStyle = alignment; + } else { + bool canBeSet = false; + switch (dock) { + case PdfDockStyle.left: + canBeSet = + alignment == PdfAlignmentStyle.topLeft || + alignment == PdfAlignmentStyle.middleLeft || + alignment == PdfAlignmentStyle.bottomLeft || + alignment == PdfAlignmentStyle.none; + break; + case PdfDockStyle.top: + canBeSet = + alignment == PdfAlignmentStyle.topLeft || + alignment == PdfAlignmentStyle.topCenter || + alignment == PdfAlignmentStyle.topRight || + alignment == PdfAlignmentStyle.none; + break; + case PdfDockStyle.right: + canBeSet = + alignment == PdfAlignmentStyle.topRight || + alignment == PdfAlignmentStyle.middleRight || + alignment == PdfAlignmentStyle.bottomRight || + alignment == PdfAlignmentStyle.none; + break; + case PdfDockStyle.bottom: + canBeSet = + alignment == PdfAlignmentStyle.bottomLeft || + alignment == PdfAlignmentStyle.bottomCenter || + alignment == PdfAlignmentStyle.bottomRight || + alignment == PdfAlignmentStyle.none; + break; + case PdfDockStyle.fill: + canBeSet = + alignment == PdfAlignmentStyle.middleCenter || + alignment == PdfAlignmentStyle.none; + break; + case PdfDockStyle.none: + break; + } + if (canBeSet) { + _helper._alignmentStyle = alignment; + } + } + } +} + +/// [PdfPageTemplateElement] helper +class PdfPageTemplateElementHelper { + /// internal constructor + PdfPageTemplateElementHelper(this.base); + + /// internal field + late PdfPageTemplateElement base; + + /// internal method + static PdfPageTemplateElementHelper getHelper(PdfPageTemplateElement base) { + return base._helper; + } + + TemplateType _templateType = TemplateType.none; + PdfTemplate? _pdfTemplate; + PdfAlignmentStyle _alignmentStyle = PdfAlignmentStyle.none; + PdfDockStyle? _dockStyle; + + /// Gets type of the usage of this page template. + TemplateType get type => _templateType; + + /// Sets type of the usage of this page template. + set type(TemplateType value) { + _updateDocking(value); + _templateType = value; + } + + void _updateDocking(TemplateType type) { + if (type != TemplateType.none) { + switch (type) { + case TemplateType.top: + base.dock = PdfDockStyle.top; + break; + case TemplateType.bottom: + base.dock = PdfDockStyle.bottom; + break; + case TemplateType.left: + base.dock = PdfDockStyle.left; + break; + case TemplateType.right: + base.dock = PdfDockStyle.right; + break; + case TemplateType.none: + break; + } + _resetAlignment(); + } + } + + void _resetAlignment() { + base.alignment = PdfAlignmentStyle.none; + } + + /// Gets PDF template object. + PdfTemplate? get _template => _pdfTemplate; + + /// internal method + void draw(PdfPageLayer layer, PdfDocument document) { + final PdfPage page = layer.page; + final Rect bounds = _calculateBounds(page, document); + PdfPageHelper.getHelper(layer.page).isDefaultGraphics = true; + layer.graphics.drawPdfTemplate(_template!, bounds.topLeft, bounds.size); + } + + Rect _calculateBounds(PdfPage page, PdfDocument document) { + Rect result = base.bounds; + if (_alignmentStyle != PdfAlignmentStyle.none) { + result = _getAlignmentBounds(page, document); + } else if (_dockStyle != PdfDockStyle.none) { + result = _getDockBounds(page, document); + } + return result; + } + + Rect _getAlignmentBounds(PdfPage page, PdfDocument document) { + Rect result = base.bounds; + if (type == TemplateType.none) { + result = _getSimpleAlignmentBounds(page, document); + } + return result; + } + + Rect _getSimpleAlignmentBounds(PdfPage page, PdfDocument document) { + final Rect result = base.bounds; + final PdfSection section = PdfPageHelper.getHelper(page).section!; + final PdfRectangle actualBounds = PdfSectionHelper.getHelper( + section, + ).getActualBounds(page, false, document); + double x = base.location.dx; + double y = base.location.dy; + + switch (_alignmentStyle) { + case PdfAlignmentStyle.topLeft: + { + x = 0.0; + y = 0.0; + } + break; + + case PdfAlignmentStyle.topCenter: + { + x = (actualBounds.width - base.width) / 2.0; + y = 0.0; + } + break; + + case PdfAlignmentStyle.topRight: + { + x = actualBounds.width - base.width; + y = 0.0; + } + break; + + case PdfAlignmentStyle.middleLeft: + { + x = 0.0; + y = (actualBounds.height - base.height) / 2.0; + } + break; + + case PdfAlignmentStyle.middleCenter: + { + x = (actualBounds.width - base.width) / 2.0; + y = (actualBounds.height - base.height) / 2.0; + } + break; + + case PdfAlignmentStyle.middleRight: + { + x = actualBounds.width - base.width; + y = (actualBounds.height - base.height) / 2.0; + } + break; + + case PdfAlignmentStyle.bottomLeft: + { + x = 0.0; + y = actualBounds.height - base.height; + } + break; + + case PdfAlignmentStyle.bottomCenter: + { + x = (actualBounds.width - base.width) / 2.0; + y = actualBounds.height - base.height; + } + break; + + case PdfAlignmentStyle.bottomRight: + { + x = actualBounds.width - base.width; + y = actualBounds.height - base.height; + } + break; + case PdfAlignmentStyle.none: + break; + } + + return Offset(x, y) & result.size; + } + + Rect _getDockBounds(PdfPage page, PdfDocument document) { + Rect result = base.bounds; + + if (type == TemplateType.none) { + result = _getSimpleDockBounds(page, document); + } else { + result = _getTemplateDockBounds(page, document); + } + return result; + } + + Rect _getSimpleDockBounds(PdfPage page, PdfDocument document) { + Rect result = base.bounds; + final PdfSection section = PdfPageHelper.getHelper(page).section!; + final PdfRectangle actualBounds = PdfSectionHelper.getHelper( + section, + ).getActualBounds(page, false, document); + double x = base.location.dx; + double y = base.location.dy; + double? width = base.width; + double? height = base.height; + + switch (_dockStyle) { + case PdfDockStyle.left: + x = 0.0; + y = 0.0; + width = base.width; + height = actualBounds.height; + break; + + case PdfDockStyle.top: + x = 0.0; + y = 0.0; + width = actualBounds.width; + height = base.height; + break; + + case PdfDockStyle.right: + x = actualBounds.width - base.width; + y = 0.0; + width = base.width; + height = actualBounds.height; + break; + + case PdfDockStyle.bottom: + x = 0.0; + y = actualBounds.height - base.height; + width = actualBounds.width; + height = base.height; + break; + + case PdfDockStyle.fill: + x = 0.0; + x = 0.0; + width = actualBounds.width; + height = actualBounds.height; + break; + case PdfDockStyle.none: + break; + // ignore: no_default_cases + default: + break; + } + + result = Rect.fromLTWH(x, y, width, height); + + return result; + } + + Rect _getTemplateDockBounds(PdfPage page, PdfDocument document) { + final PdfSection section = PdfPageHelper.getHelper(page).section!; + final PdfRectangle actualBounds = PdfSectionHelper.getHelper( + section, + ).getActualBounds(page, false, document); + final PdfSize actualSize = PdfSize.fromSize( + PdfPageSettingsHelper.getHelper(section.pageSettings).getActualSize(), + ); + double x = base.location.dx; + double y = base.location.dy; + double? width = base.width; + double? height = base.height; + + switch (_dockStyle) { + case PdfDockStyle.left: + x = -actualBounds.x; + y = 0.0; + width = base.width; + height = actualBounds.height; + break; + + case PdfDockStyle.top: + x = -actualBounds.x; + y = -actualBounds.y; + width = actualSize.width; + height = base.height; + + if (actualBounds.height < 0) { + y = -actualBounds.y + actualSize.height; + } + break; + + case PdfDockStyle.right: + x = + actualBounds.width + + PdfSectionHelper.getHelper( + section, + ).getRightIndentWidth(document, page, false) - + base.width; + y = 0.0; + width = base.width; + height = actualBounds.height; + break; + + case PdfDockStyle.bottom: + x = -actualBounds.x; + y = + actualBounds.height + + PdfSectionHelper.getHelper( + section, + ).getBottomIndentHeight(document, page, false) - + base.height; + width = actualSize.width; + height = base.height; + if (actualBounds.height < 0) { + y -= actualSize.height; + } + break; + + case PdfDockStyle.fill: + x = 0.0; + x = 0.0; + width = actualBounds.width; + height = actualBounds.height; + break; + case PdfDockStyle.none: + break; + // ignore: no_default_cases + default: + break; + } + return Rect.fromLTWH(x, y, width, height); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section.dart index ac18a2623..d849ddcbd 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section.dart @@ -1,769 +1,769 @@ -import 'dart:ui'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../general/pdf_collection.dart'; -import '../graphics/pdf_margins.dart'; -import '../io/pdf_constants.dart'; -import '../pdf_document/pdf_document.dart'; -import '../pdf_document/pdf_document_template.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'enum.dart'; -import 'pdf_page.dart'; -import 'pdf_page_collection.dart'; -import 'pdf_page_layer.dart'; -import 'pdf_page_settings.dart'; -import 'pdf_page_template_element.dart'; -import 'pdf_section_collection.dart'; -import 'pdf_section_template.dart'; - -/// Represents a section entity. A section is a set of the pages -/// with similar page settings. -/// ```dart -/// //Create a new PDF documentation -/// PdfDocument document = PdfDocument(); -/// //Create a new PDF section -/// PdfSection section = document.sections!.add(); -/// //Create a new PDF page and draw the text -/// section.pages.add().graphics.drawString( -/// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), -/// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfSection implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfSection] class. - PdfSection._(PdfDocument? document, [PdfPageSettings? settings]) { - _helper = PdfSectionHelper(this); - _helper.pageReferences = PdfArray(); - _helper._section = PdfDictionary(); - _helper._section!.beginSave = _helper.beginSave; - _helper._pageCount = PdfNumber(0); - _helper._section![PdfDictionaryProperties.count] = _helper._pageCount; - _helper._section![PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.pages, - ); - _helper._section![PdfDictionaryProperties.kids] = _helper.pageReferences; - _helper.pdfDocument = document; - _helper.settings = - settings != null - ? PdfPageSettingsHelper.getHelper(settings).clone() - : PdfPageSettingsHelper.getHelper(document!.pageSettings).clone(); - } - - /// Event rises when the new page has been added - PageAddedCallback? pageAdded; - PdfSectionTemplate? _template; - PdfPageCollection? _pageCollection; - late PdfSectionHelper _helper; - - //Properties - /// Gets or sets the [PdfSectionTemplate] for the pages in the section. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Sets the page settings of the section - /// section.pageSettings = - /// PdfPageSettings(PdfPageSize.a4, PdfPageOrientation.portrait); - /// //Sets the template for the page in the section - /// section.template = PdfSectionTemplate(); - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfSectionTemplate get template { - _template ??= PdfSectionTemplate(); - return _template!; - } - - set template(PdfSectionTemplate value) { - _template = value; - } - - /// Gets the collection of pages in this section. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageCollection get pages { - _pageCollection ??= PdfPageCollectionHelper.load(_helper.pdfDocument, this); - return _pageCollection!; - } - - /// Gets or sets the [PdfPageSettings] of the section. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Sets the page settings of the section - /// section.pageSettings = - /// PdfPageSettings(PdfPageSize.a4, PdfPageOrientation.portrait); - /// //Sets the template for the page in the section - /// section.template = PdfSectionTemplate(); - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageSettings get pageSettings { - PdfMarginsHelper.getHelper(_helper.settings.margins).isPageAdded = - _helper._pages.isNotEmpty; - PdfPageSettingsHelper.getHelper(_helper.settings).isPageAdded = - _helper._pages.isNotEmpty; - return _helper.settings; - } - - set pageSettings(PdfPageSettings settings) { - if (_helper._pages.isEmpty) { - _helper.settings = settings; - } - } -} - -/// [PdfSection] helper -class PdfSectionHelper { - /// internal constructor - PdfSectionHelper(this.base); - - /// internal field - late PdfSection base; - - /// internal method - static PdfSectionHelper getHelper(PdfSection base) { - return base._helper; - } - - /// internal method - static PdfSection load(PdfDocument? document, [PdfPageSettings? settings]) { - return PdfSection._(document, settings); - } - - /// internal field - PdfDictionary? _section; - PdfSectionCollection? _sectionCollection; - final List _pages = []; - PdfNumber? _pageCount; - - /// internal method - IPdfPrimitive? get element => _section; - //ignore: unused_element - set element(IPdfPrimitive? value) { - _section = value as PdfDictionary?; - } - - /// internal method - PdfArray? pageReferences; - - /// internal method - PdfDocument? pdfDocument; - - /// internal method - late PdfPageSettings settings; - - /// internal method - bool? isNewPageSection = false; - - /// internal method - PdfSectionCollection? get parent => _sectionCollection; - - /// Sets the parent. - set parent(PdfSectionCollection? sections) { - _sectionCollection = sections; - if (sections != null) { - _section![PdfDictionaryProperties.parent] = PdfReferenceHolder(sections); - } else { - _section!.remove(PdfDictionaryProperties.parent); - } - } - - /// internal method - PdfDocument? get document { - if (_sectionCollection != null) { - return PdfSectionCollectionHelper.getHelper(_sectionCollection!).document; - } else { - return null; - } - } - - /// internal method - int get count => pageReferences!.count; - - /// internal method - void add(PdfPage page) { - if (!isNewPageSection!) { - isNewPageSection = PdfPageHelper.getHelper(page).isNewPage; - } - final PdfReferenceHolder holder = PdfReferenceHolder(page); - isNewPageSection = false; - _pages.add(page); - pageReferences!.add(holder); - PdfPageHelper.getHelper(page).assignSection(base); - _pdfPageAdded(page); - } - - void _pdfPageAdded(PdfPage page) { - final PageAddedArgs args = PageAddedArgs(page); - _onPageAdded(args); - final PdfSectionCollection? sectionCollection = parent; - if (sectionCollection != null) { - PdfPageCollectionHelper.getHelper( - PdfSectionCollectionHelper.getHelper(sectionCollection).document!.pages, - ).onPageAdded(args); - } - _pageCount!.value = count; - } - - void _onPageAdded(PageAddedArgs args) { - if (base.pageAdded != null) { - base.pageAdded!(base, args); - } - } - - /// internal method - void remove(PdfPage page) { - for (int i = 0; i < pageReferences!.elements.length; i++) { - final IPdfPrimitive? pageReference = pageReferences!.elements[i]; - if (pageReference != null && - pageReference is PdfReferenceHolder && - pageReference.object == PdfPageHelper.getHelper(page).element) { - pageReferences!.elements.removeAt(i); - _pages.remove(page); - break; - } - } - } - - /// internal method - PdfPage? getPageByIndex(int index) { - if (index < 0 || index >= count) { - throw ArgumentError.value(index, 'our of range'); - } - return _pages[index]; - } - - /// internal method - PdfRectangle getActualBounds( - PdfPage page, - bool includeMargins, [ - PdfDocument? document, - ]) { - if (document == null) { - if (parent != null) { - final PdfDocument? pdfDocument = - PdfSectionCollectionHelper.getHelper(parent!).document; - return getActualBounds(page, includeMargins, pdfDocument); - } else { - final PdfSize size = - includeMargins - ? PdfSize.fromSize( - PdfPageSettingsHelper.getHelper( - base.pageSettings, - ).getActualSize(), - ) - : base.pageSettings.size as PdfSize; - final double left = includeMargins ? base.pageSettings.margins.left : 0; - final double top = includeMargins ? base.pageSettings.margins.top : 0; - return PdfRectangle(left, top, size.width, size.height); - } - } else { - final PdfRectangle bounds = PdfRectangle.empty; - final Size size = - includeMargins - ? base.pageSettings.size - : PdfPageSettingsHelper.getHelper( - base.pageSettings, - ).getActualSize(); - bounds.width = size.width; - bounds.height = size.height; - final double left = getLeftIndentWidth(document, page, includeMargins); - final double top = getTopIndentHeight(document, page, includeMargins); - final double right = getRightIndentWidth(document, page, includeMargins); - final double bottom = getBottomIndentHeight( - document, - page, - includeMargins, - ); - bounds.x += left; - bounds.y += top; - bounds.width -= left + right; - bounds.height -= top + bottom; - return bounds; - } - } - - /// internal method - double getLeftIndentWidth( - PdfDocument document, - PdfPage page, - bool includeMargins, - ) { - double value = includeMargins ? base.pageSettings.margins.left : 0; - final double templateWidth = - PdfDocumentTemplateHelper.getHelper(base.template).getLeft(page) != null - ? PdfDocumentTemplateHelper.getHelper( - base.template, - ).getLeft(page)!.width - : 0; - final double docTemplateWidth = - PdfDocumentTemplateHelper.getHelper(document.template).getLeft(page) != - null - ? PdfDocumentTemplateHelper.getHelper( - document.template, - ).getLeft(page)!.width - : 0; - value += - base.template.leftTemplate - ? (templateWidth >= docTemplateWidth - ? templateWidth - : docTemplateWidth) - : templateWidth; - return value; - } - - /// internal method - double getTopIndentHeight( - PdfDocument document, - PdfPage page, - bool includeMargins, - ) { - double value = includeMargins ? base.pageSettings.margins.top : 0; - final double templateHeight = - PdfDocumentTemplateHelper.getHelper(base.template).getTop(page) != null - ? PdfDocumentTemplateHelper.getHelper( - base.template, - ).getTop(page)!.height - : 0; - final double docTemplateHeight = - PdfDocumentTemplateHelper.getHelper(document.template).getTop(page) != - null - ? PdfDocumentTemplateHelper.getHelper( - document.template, - ).getTop(page)!.height - : 0; - value += - base.template.topTemplate - ? (templateHeight >= docTemplateHeight - ? templateHeight - : docTemplateHeight) - : templateHeight; - return value; - } - - /// internal method - double getRightIndentWidth( - PdfDocument document, - PdfPage page, - bool includeMargins, - ) { - double value = includeMargins ? base.pageSettings.margins.right : 0; - final double templateWidth = - PdfDocumentTemplateHelper.getHelper(base.template).getRight(page) != - null - ? PdfDocumentTemplateHelper.getHelper( - base.template, - ).getRight(page)!.width - : 0; - final double docTemplateWidth = - PdfDocumentTemplateHelper.getHelper(document.template).getRight(page) != - null - ? PdfDocumentTemplateHelper.getHelper( - document.template, - ).getRight(page)!.width - : 0; - value += - base.template.rightTemplate - ? (templateWidth >= docTemplateWidth - ? templateWidth - : docTemplateWidth) - : templateWidth; - return value; - } - - /// internal method - double getBottomIndentHeight( - PdfDocument document, - PdfPage page, - bool includeMargins, - ) { - double value = includeMargins ? base.pageSettings.margins.bottom : 0; - final double templateHeight = - PdfDocumentTemplateHelper.getHelper(base.template).getBottom(page) != - null - ? PdfDocumentTemplateHelper.getHelper( - base.template, - ).getBottom(page)!.height - : 0; - final double docTemplateHeight = - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getBottom(page) != - null - ? PdfDocumentTemplateHelper.getHelper( - document.template, - ).getBottom(page)!.height - : 0; - value += - base.template.bottomTemplate - ? (templateHeight >= docTemplateHeight - ? templateHeight - : docTemplateHeight) - : templateHeight; - return value; - } - - /// internal method - void beginSave(Object sender, SavePdfPrimitiveArgs? args) { - _pageCount!.value = count; - final PdfDocument? document = args!.writer!.document; - if (document == null) { - _setPageSettings(_section!); - } else { - _setPageSettings(_section!, document.pageSettings); - } - } - - void _setPageSettings( - PdfDictionary container, [ - PdfPageSettings? parentSettings, - ]) { - if (parentSettings == null || - base.pageSettings.size != parentSettings.size) { - final PdfRectangle bounds = PdfRectangle( - PdfPageSettingsHelper.getHelper(settings).origin.x, - PdfPageSettingsHelper.getHelper(settings).origin.y, - settings.size.width, - settings.size.height, - ); - container[PdfDictionaryProperties.mediaBox] = PdfArray.fromRectangle( - bounds, - ); - } - if (parentSettings == null || - base.pageSettings.rotate != parentSettings.rotate) { - int rotate = 0; - if (_sectionCollection != null) { - if (PdfPageSettingsHelper.getHelper(base.pageSettings).isRotation && - !PdfPageSettingsHelper.getHelper( - document!.pageSettings, - ).isRotation) { - rotate = - PdfSectionCollectionHelper.rotateFactor * - base.pageSettings.rotate.index; - } else { - if (!PdfPageSettingsHelper.getHelper( - document!.pageSettings, - ).isRotation && - base.pageSettings.rotate != PdfPageRotateAngle.rotateAngle0) { - rotate = - PdfSectionCollectionHelper.rotateFactor * - base.pageSettings.rotate.index; - } else { - if (PdfPageSettingsHelper.getHelper(base.pageSettings).isRotation) { - rotate = - PdfSectionCollectionHelper.rotateFactor * - base.pageSettings.rotate.index; - } else if (parentSettings != null) { - rotate = - PdfSectionCollectionHelper.rotateFactor * - parentSettings.rotate.index; - } - } - } - } else { - rotate = - PdfSectionCollectionHelper.rotateFactor * - base.pageSettings.rotate.index; - } - final PdfNumber angle = PdfNumber(rotate); - if (angle.value != 0) { - container[PdfDictionaryProperties.rotate] = angle; - } - } - } - - /// internal method - int indexOf(PdfPage page) { - if (_pages.contains(page)) { - return _pages.indexOf(page); - } - final PdfReferenceHolder holder = PdfReferenceHolder(page); - return pageReferences!.indexOf(holder); - } - - /// internal method - bool containsTemplates(PdfDocument document, PdfPage page, bool foreground) { - final List documentHeaders = _getDocumentTemplates( - document, - page, - true, - foreground, - ); - final List documentTemplates = - _getDocumentTemplates(document, page, false, foreground); - final List sectionHeaders = _getSectionTemplates( - page, - true, - foreground, - ); - final List sectionTemplates = _getSectionTemplates( - page, - false, - foreground, - ); - final bool contains = - documentHeaders.isNotEmpty || - documentTemplates.isNotEmpty || - sectionHeaders.isNotEmpty || - sectionTemplates.isNotEmpty; - return contains; - } - - List _getDocumentTemplates( - PdfDocument document, - PdfPage page, - bool headers, - bool foreground, - ) { - final List templates = []; - if (headers) { - if (base.template.topTemplate && - PdfDocumentTemplateHelper.getHelper(document.template).getTop(page) != - null && - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getTop(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper(document.template).getTop(page)!, - ); - } - if (base.template.bottomTemplate && - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getBottom(page) != - null && - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getBottom(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getBottom(page)!, - ); - } - if (base.template.leftTemplate && - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getLeft(page) != - null && - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getLeft(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper(document.template).getLeft(page)!, - ); - } - if (base.template.rightTemplate && - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getRight(page) != - null && - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getRight(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper( - document.template, - ).getRight(page)!, - ); - } - } else if (base.template.stamp) { - final List list = - PdfObjectCollectionHelper.getHelper(document.template.stamps).list; - for (int i = 0; i < list.length; i++) { - final PdfPageTemplateElement template = - list[i] as PdfPageTemplateElement; - if (template.foreground == foreground) { - templates.add(template); - } - } - } - return templates; - } - - List _getSectionTemplates( - PdfPage page, - bool headers, - bool foreground, - ) { - final List templates = []; - if (headers) { - if (PdfDocumentTemplateHelper.getHelper(base.template).getTop(page) != - null && - PdfDocumentTemplateHelper.getHelper( - base.template, - ).getTop(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper(base.template).getTop(page)!, - ); - } - if (PdfDocumentTemplateHelper.getHelper(base.template).getBottom(page) != - null && - PdfDocumentTemplateHelper.getHelper( - base.template, - ).getBottom(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper(base.template).getBottom(page)!, - ); - } - if (PdfDocumentTemplateHelper.getHelper(base.template).getLeft(page) != - null && - PdfDocumentTemplateHelper.getHelper( - base.template, - ).getLeft(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper(base.template).getLeft(page)!, - ); - } - if (PdfDocumentTemplateHelper.getHelper(base.template).getRight(page) != - null && - PdfDocumentTemplateHelper.getHelper( - base.template, - ).getRight(page)!.foreground == - foreground) { - templates.add( - PdfDocumentTemplateHelper.getHelper(base.template).getRight(page)!, - ); - } - } else { - final List list = - PdfObjectCollectionHelper.getHelper(base.template.stamps).list; - for (int i = 0; i < list.length; i++) { - final PdfPageTemplateElement temp = list[i] as PdfPageTemplateElement; - if (temp.foreground == foreground) { - templates.add(temp); - } - } - } - return templates; - } - - /// internal method - void drawTemplates( - PdfPage page, - PdfPageLayer layer, - PdfDocument document, - bool foreground, - ) { - final List documentHeaders = _getDocumentTemplates( - document, - page, - true, - foreground, - ); - final List documentTemplates = - _getDocumentTemplates(document, page, false, foreground); - final List sectionHeaders = _getSectionTemplates( - page, - true, - foreground, - ); - final List sectionTemplates = _getSectionTemplates( - page, - false, - foreground, - ); - if (foreground) { - _internaldrawTemplates(layer, document, sectionHeaders); - _internaldrawTemplates(layer, document, sectionTemplates); - _internaldrawTemplates(layer, document, documentHeaders); - _internaldrawTemplates(layer, document, documentTemplates); - } else { - _internaldrawTemplates(layer, document, documentHeaders); - _internaldrawTemplates(layer, document, documentTemplates); - _internaldrawTemplates(layer, document, sectionHeaders); - _internaldrawTemplates(layer, document, sectionTemplates); - } - } - - void _internaldrawTemplates( - PdfPageLayer layer, - PdfDocument document, - List templates, - ) { - if (templates.isNotEmpty) { - for (final PdfPageTemplateElement template in templates) { - PdfPageTemplateElementHelper.getHelper(template).draw(layer, document); - } - } - } - - /// internal method - PdfPoint pointToNativePdf(PdfPage page, PdfPoint point) { - final PdfRectangle bounds = getActualBounds(page, true); - point.x += bounds.left; - point.y = base.pageSettings.height - (bounds.top + point.y); - return point; - } - - /// internal method - void dropCropBox() { - _setPageSettings(_section!); - _section![PdfDictionaryProperties.cropBox] = - _section![PdfDictionaryProperties.mediaBox]; - } -} - -/// Represents the method that executes on a [PdfDocument] -/// when a new page is created. -typedef PageAddedCallback = void Function(Object sender, PageAddedArgs args); - -/// Provides data for [PageAddedCallback] event. -class PageAddedArgs { - /// Initializes a new instance of the [PageAddedArgs] class. - /// - /// [page] - represending the page which is added in the document. - PageAddedArgs([PdfPage? page]) { - if (page != null) { - this.page = page; - } - } - - /// Gets the newly added page. - late PdfPage page; -} +import 'dart:ui'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../general/pdf_collection.dart'; +import '../graphics/pdf_margins.dart'; +import '../io/pdf_constants.dart'; +import '../pdf_document/pdf_document.dart'; +import '../pdf_document/pdf_document_template.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'enum.dart'; +import 'pdf_page.dart'; +import 'pdf_page_collection.dart'; +import 'pdf_page_layer.dart'; +import 'pdf_page_settings.dart'; +import 'pdf_page_template_element.dart'; +import 'pdf_section_collection.dart'; +import 'pdf_section_template.dart'; + +/// Represents a section entity. A section is a set of the pages +/// with similar page settings. +/// ```dart +/// //Create a new PDF documentation +/// PdfDocument document = PdfDocument(); +/// //Create a new PDF section +/// PdfSection section = document.sections!.add(); +/// //Create a new PDF page and draw the text +/// section.pages.add().graphics.drawString( +/// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), +/// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfSection implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfSection] class. + PdfSection._(PdfDocument? document, [PdfPageSettings? settings]) { + _helper = PdfSectionHelper(this); + _helper.pageReferences = PdfArray(); + _helper._section = PdfDictionary(); + _helper._section!.beginSave = _helper.beginSave; + _helper._pageCount = PdfNumber(0); + _helper._section![PdfDictionaryProperties.count] = _helper._pageCount; + _helper._section![PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.pages, + ); + _helper._section![PdfDictionaryProperties.kids] = _helper.pageReferences; + _helper.pdfDocument = document; + _helper.settings = + settings != null + ? PdfPageSettingsHelper.getHelper(settings).clone() + : PdfPageSettingsHelper.getHelper(document!.pageSettings).clone(); + } + + /// Event rises when the new page has been added + PageAddedCallback? pageAdded; + PdfSectionTemplate? _template; + PdfPageCollection? _pageCollection; + late PdfSectionHelper _helper; + + //Properties + /// Gets or sets the [PdfSectionTemplate] for the pages in the section. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Sets the page settings of the section + /// section.pageSettings = + /// PdfPageSettings(PdfPageSize.a4, PdfPageOrientation.portrait); + /// //Sets the template for the page in the section + /// section.template = PdfSectionTemplate(); + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfSectionTemplate get template { + _template ??= PdfSectionTemplate(); + return _template!; + } + + set template(PdfSectionTemplate value) { + _template = value; + } + + /// Gets the collection of pages in this section. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageCollection get pages { + _pageCollection ??= PdfPageCollectionHelper.load(_helper.pdfDocument, this); + return _pageCollection!; + } + + /// Gets or sets the [PdfPageSettings] of the section. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Sets the page settings of the section + /// section.pageSettings = + /// PdfPageSettings(PdfPageSize.a4, PdfPageOrientation.portrait); + /// //Sets the template for the page in the section + /// section.template = PdfSectionTemplate(); + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageSettings get pageSettings { + PdfMarginsHelper.getHelper(_helper.settings.margins).isPageAdded = + _helper._pages.isNotEmpty; + PdfPageSettingsHelper.getHelper(_helper.settings).isPageAdded = + _helper._pages.isNotEmpty; + return _helper.settings; + } + + set pageSettings(PdfPageSettings settings) { + if (_helper._pages.isEmpty) { + _helper.settings = settings; + } + } +} + +/// [PdfSection] helper +class PdfSectionHelper { + /// internal constructor + PdfSectionHelper(this.base); + + /// internal field + late PdfSection base; + + /// internal method + static PdfSectionHelper getHelper(PdfSection base) { + return base._helper; + } + + /// internal method + static PdfSection load(PdfDocument? document, [PdfPageSettings? settings]) { + return PdfSection._(document, settings); + } + + /// internal field + PdfDictionary? _section; + PdfSectionCollection? _sectionCollection; + final List _pages = []; + PdfNumber? _pageCount; + + /// internal method + IPdfPrimitive? get element => _section; + //ignore: unused_element + set element(IPdfPrimitive? value) { + _section = value as PdfDictionary?; + } + + /// internal method + PdfArray? pageReferences; + + /// internal method + PdfDocument? pdfDocument; + + /// internal method + late PdfPageSettings settings; + + /// internal method + bool? isNewPageSection = false; + + /// internal method + PdfSectionCollection? get parent => _sectionCollection; + + /// Sets the parent. + set parent(PdfSectionCollection? sections) { + _sectionCollection = sections; + if (sections != null) { + _section![PdfDictionaryProperties.parent] = PdfReferenceHolder(sections); + } else { + _section!.remove(PdfDictionaryProperties.parent); + } + } + + /// internal method + PdfDocument? get document { + if (_sectionCollection != null) { + return PdfSectionCollectionHelper.getHelper(_sectionCollection!).document; + } else { + return null; + } + } + + /// internal method + int get count => pageReferences!.count; + + /// internal method + void add(PdfPage page) { + if (!isNewPageSection!) { + isNewPageSection = PdfPageHelper.getHelper(page).isNewPage; + } + final PdfReferenceHolder holder = PdfReferenceHolder(page); + isNewPageSection = false; + _pages.add(page); + pageReferences!.add(holder); + PdfPageHelper.getHelper(page).assignSection(base); + _pdfPageAdded(page); + } + + void _pdfPageAdded(PdfPage page) { + final PageAddedArgs args = PageAddedArgs(page); + _onPageAdded(args); + final PdfSectionCollection? sectionCollection = parent; + if (sectionCollection != null) { + PdfPageCollectionHelper.getHelper( + PdfSectionCollectionHelper.getHelper(sectionCollection).document!.pages, + ).onPageAdded(args); + } + _pageCount!.value = count; + } + + void _onPageAdded(PageAddedArgs args) { + if (base.pageAdded != null) { + base.pageAdded!(base, args); + } + } + + /// internal method + void remove(PdfPage page) { + for (int i = 0; i < pageReferences!.elements.length; i++) { + final IPdfPrimitive? pageReference = pageReferences!.elements[i]; + if (pageReference != null && + pageReference is PdfReferenceHolder && + pageReference.object == PdfPageHelper.getHelper(page).element) { + pageReferences!.elements.removeAt(i); + _pages.remove(page); + break; + } + } + } + + /// internal method + PdfPage? getPageByIndex(int index) { + if (index < 0 || index >= count) { + throw ArgumentError.value(index, 'our of range'); + } + return _pages[index]; + } + + /// internal method + PdfRectangle getActualBounds( + PdfPage page, + bool includeMargins, [ + PdfDocument? document, + ]) { + if (document == null) { + if (parent != null) { + final PdfDocument? pdfDocument = + PdfSectionCollectionHelper.getHelper(parent!).document; + return getActualBounds(page, includeMargins, pdfDocument); + } else { + final PdfSize size = + includeMargins + ? PdfSize.fromSize( + PdfPageSettingsHelper.getHelper( + base.pageSettings, + ).getActualSize(), + ) + : base.pageSettings.size as PdfSize; + final double left = includeMargins ? base.pageSettings.margins.left : 0; + final double top = includeMargins ? base.pageSettings.margins.top : 0; + return PdfRectangle(left, top, size.width, size.height); + } + } else { + final PdfRectangle bounds = PdfRectangle.empty; + final Size size = + includeMargins + ? base.pageSettings.size + : PdfPageSettingsHelper.getHelper( + base.pageSettings, + ).getActualSize(); + bounds.width = size.width; + bounds.height = size.height; + final double left = getLeftIndentWidth(document, page, includeMargins); + final double top = getTopIndentHeight(document, page, includeMargins); + final double right = getRightIndentWidth(document, page, includeMargins); + final double bottom = getBottomIndentHeight( + document, + page, + includeMargins, + ); + bounds.x += left; + bounds.y += top; + bounds.width -= left + right; + bounds.height -= top + bottom; + return bounds; + } + } + + /// internal method + double getLeftIndentWidth( + PdfDocument document, + PdfPage page, + bool includeMargins, + ) { + double value = includeMargins ? base.pageSettings.margins.left : 0; + final double templateWidth = + PdfDocumentTemplateHelper.getHelper(base.template).getLeft(page) != null + ? PdfDocumentTemplateHelper.getHelper( + base.template, + ).getLeft(page)!.width + : 0; + final double docTemplateWidth = + PdfDocumentTemplateHelper.getHelper(document.template).getLeft(page) != + null + ? PdfDocumentTemplateHelper.getHelper( + document.template, + ).getLeft(page)!.width + : 0; + value += + base.template.leftTemplate + ? (templateWidth >= docTemplateWidth + ? templateWidth + : docTemplateWidth) + : templateWidth; + return value; + } + + /// internal method + double getTopIndentHeight( + PdfDocument document, + PdfPage page, + bool includeMargins, + ) { + double value = includeMargins ? base.pageSettings.margins.top : 0; + final double templateHeight = + PdfDocumentTemplateHelper.getHelper(base.template).getTop(page) != null + ? PdfDocumentTemplateHelper.getHelper( + base.template, + ).getTop(page)!.height + : 0; + final double docTemplateHeight = + PdfDocumentTemplateHelper.getHelper(document.template).getTop(page) != + null + ? PdfDocumentTemplateHelper.getHelper( + document.template, + ).getTop(page)!.height + : 0; + value += + base.template.topTemplate + ? (templateHeight >= docTemplateHeight + ? templateHeight + : docTemplateHeight) + : templateHeight; + return value; + } + + /// internal method + double getRightIndentWidth( + PdfDocument document, + PdfPage page, + bool includeMargins, + ) { + double value = includeMargins ? base.pageSettings.margins.right : 0; + final double templateWidth = + PdfDocumentTemplateHelper.getHelper(base.template).getRight(page) != + null + ? PdfDocumentTemplateHelper.getHelper( + base.template, + ).getRight(page)!.width + : 0; + final double docTemplateWidth = + PdfDocumentTemplateHelper.getHelper(document.template).getRight(page) != + null + ? PdfDocumentTemplateHelper.getHelper( + document.template, + ).getRight(page)!.width + : 0; + value += + base.template.rightTemplate + ? (templateWidth >= docTemplateWidth + ? templateWidth + : docTemplateWidth) + : templateWidth; + return value; + } + + /// internal method + double getBottomIndentHeight( + PdfDocument document, + PdfPage page, + bool includeMargins, + ) { + double value = includeMargins ? base.pageSettings.margins.bottom : 0; + final double templateHeight = + PdfDocumentTemplateHelper.getHelper(base.template).getBottom(page) != + null + ? PdfDocumentTemplateHelper.getHelper( + base.template, + ).getBottom(page)!.height + : 0; + final double docTemplateHeight = + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getBottom(page) != + null + ? PdfDocumentTemplateHelper.getHelper( + document.template, + ).getBottom(page)!.height + : 0; + value += + base.template.bottomTemplate + ? (templateHeight >= docTemplateHeight + ? templateHeight + : docTemplateHeight) + : templateHeight; + return value; + } + + /// internal method + void beginSave(Object sender, SavePdfPrimitiveArgs? args) { + _pageCount!.value = count; + final PdfDocument? document = args!.writer!.document; + if (document == null) { + _setPageSettings(_section!); + } else { + _setPageSettings(_section!, document.pageSettings); + } + } + + void _setPageSettings( + PdfDictionary container, [ + PdfPageSettings? parentSettings, + ]) { + if (parentSettings == null || + base.pageSettings.size != parentSettings.size) { + final PdfRectangle bounds = PdfRectangle( + PdfPageSettingsHelper.getHelper(settings).origin.x, + PdfPageSettingsHelper.getHelper(settings).origin.y, + settings.size.width, + settings.size.height, + ); + container[PdfDictionaryProperties.mediaBox] = PdfArray.fromRectangle( + bounds, + ); + } + if (parentSettings == null || + base.pageSettings.rotate != parentSettings.rotate) { + int rotate = 0; + if (_sectionCollection != null) { + if (PdfPageSettingsHelper.getHelper(base.pageSettings).isRotation && + !PdfPageSettingsHelper.getHelper( + document!.pageSettings, + ).isRotation) { + rotate = + PdfSectionCollectionHelper.rotateFactor * + base.pageSettings.rotate.index; + } else { + if (!PdfPageSettingsHelper.getHelper( + document!.pageSettings, + ).isRotation && + base.pageSettings.rotate != PdfPageRotateAngle.rotateAngle0) { + rotate = + PdfSectionCollectionHelper.rotateFactor * + base.pageSettings.rotate.index; + } else { + if (PdfPageSettingsHelper.getHelper(base.pageSettings).isRotation) { + rotate = + PdfSectionCollectionHelper.rotateFactor * + base.pageSettings.rotate.index; + } else if (parentSettings != null) { + rotate = + PdfSectionCollectionHelper.rotateFactor * + parentSettings.rotate.index; + } + } + } + } else { + rotate = + PdfSectionCollectionHelper.rotateFactor * + base.pageSettings.rotate.index; + } + final PdfNumber angle = PdfNumber(rotate); + if (angle.value != 0) { + container[PdfDictionaryProperties.rotate] = angle; + } + } + } + + /// internal method + int indexOf(PdfPage page) { + if (_pages.contains(page)) { + return _pages.indexOf(page); + } + final PdfReferenceHolder holder = PdfReferenceHolder(page); + return pageReferences!.indexOf(holder); + } + + /// internal method + bool containsTemplates(PdfDocument document, PdfPage page, bool foreground) { + final List documentHeaders = _getDocumentTemplates( + document, + page, + true, + foreground, + ); + final List documentTemplates = + _getDocumentTemplates(document, page, false, foreground); + final List sectionHeaders = _getSectionTemplates( + page, + true, + foreground, + ); + final List sectionTemplates = _getSectionTemplates( + page, + false, + foreground, + ); + final bool contains = + documentHeaders.isNotEmpty || + documentTemplates.isNotEmpty || + sectionHeaders.isNotEmpty || + sectionTemplates.isNotEmpty; + return contains; + } + + List _getDocumentTemplates( + PdfDocument document, + PdfPage page, + bool headers, + bool foreground, + ) { + final List templates = []; + if (headers) { + if (base.template.topTemplate && + PdfDocumentTemplateHelper.getHelper(document.template).getTop(page) != + null && + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getTop(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper(document.template).getTop(page)!, + ); + } + if (base.template.bottomTemplate && + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getBottom(page) != + null && + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getBottom(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getBottom(page)!, + ); + } + if (base.template.leftTemplate && + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getLeft(page) != + null && + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getLeft(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper(document.template).getLeft(page)!, + ); + } + if (base.template.rightTemplate && + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getRight(page) != + null && + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getRight(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper( + document.template, + ).getRight(page)!, + ); + } + } else if (base.template.stamp) { + final List list = + PdfObjectCollectionHelper.getHelper(document.template.stamps).list; + for (int i = 0; i < list.length; i++) { + final PdfPageTemplateElement template = + list[i] as PdfPageTemplateElement; + if (template.foreground == foreground) { + templates.add(template); + } + } + } + return templates; + } + + List _getSectionTemplates( + PdfPage page, + bool headers, + bool foreground, + ) { + final List templates = []; + if (headers) { + if (PdfDocumentTemplateHelper.getHelper(base.template).getTop(page) != + null && + PdfDocumentTemplateHelper.getHelper( + base.template, + ).getTop(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper(base.template).getTop(page)!, + ); + } + if (PdfDocumentTemplateHelper.getHelper(base.template).getBottom(page) != + null && + PdfDocumentTemplateHelper.getHelper( + base.template, + ).getBottom(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper(base.template).getBottom(page)!, + ); + } + if (PdfDocumentTemplateHelper.getHelper(base.template).getLeft(page) != + null && + PdfDocumentTemplateHelper.getHelper( + base.template, + ).getLeft(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper(base.template).getLeft(page)!, + ); + } + if (PdfDocumentTemplateHelper.getHelper(base.template).getRight(page) != + null && + PdfDocumentTemplateHelper.getHelper( + base.template, + ).getRight(page)!.foreground == + foreground) { + templates.add( + PdfDocumentTemplateHelper.getHelper(base.template).getRight(page)!, + ); + } + } else { + final List list = + PdfObjectCollectionHelper.getHelper(base.template.stamps).list; + for (int i = 0; i < list.length; i++) { + final PdfPageTemplateElement temp = list[i] as PdfPageTemplateElement; + if (temp.foreground == foreground) { + templates.add(temp); + } + } + } + return templates; + } + + /// internal method + void drawTemplates( + PdfPage page, + PdfPageLayer layer, + PdfDocument document, + bool foreground, + ) { + final List documentHeaders = _getDocumentTemplates( + document, + page, + true, + foreground, + ); + final List documentTemplates = + _getDocumentTemplates(document, page, false, foreground); + final List sectionHeaders = _getSectionTemplates( + page, + true, + foreground, + ); + final List sectionTemplates = _getSectionTemplates( + page, + false, + foreground, + ); + if (foreground) { + _internaldrawTemplates(layer, document, sectionHeaders); + _internaldrawTemplates(layer, document, sectionTemplates); + _internaldrawTemplates(layer, document, documentHeaders); + _internaldrawTemplates(layer, document, documentTemplates); + } else { + _internaldrawTemplates(layer, document, documentHeaders); + _internaldrawTemplates(layer, document, documentTemplates); + _internaldrawTemplates(layer, document, sectionHeaders); + _internaldrawTemplates(layer, document, sectionTemplates); + } + } + + void _internaldrawTemplates( + PdfPageLayer layer, + PdfDocument document, + List templates, + ) { + if (templates.isNotEmpty) { + for (final PdfPageTemplateElement template in templates) { + PdfPageTemplateElementHelper.getHelper(template).draw(layer, document); + } + } + } + + /// internal method + PdfPoint pointToNativePdf(PdfPage page, PdfPoint point) { + final PdfRectangle bounds = getActualBounds(page, true); + point.x += bounds.left; + point.y = base.pageSettings.height - (bounds.top + point.y); + return point; + } + + /// internal method + void dropCropBox() { + _setPageSettings(_section!); + _section![PdfDictionaryProperties.cropBox] = + _section![PdfDictionaryProperties.mediaBox]; + } +} + +/// Represents the method that executes on a [PdfDocument] +/// when a new page is created. +typedef PageAddedCallback = void Function(Object sender, PageAddedArgs args); + +/// Provides data for [PageAddedCallback] event. +class PageAddedArgs { + /// Initializes a new instance of the [PageAddedArgs] class. + /// + /// [page] - represending the page which is added in the document. + PageAddedArgs([PdfPage? page]) { + if (page != null) { + this.page = page; + } + } + + /// Gets the newly added page. + late PdfPage page; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_collection.dart index 9e7757142..2786a2ef6 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_collection.dart @@ -1,141 +1,141 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import 'enum.dart'; -import 'pdf_page_settings.dart'; -import 'pdf_section.dart'; - -/// Represents the collection of the [PdfSection]. -class PdfSectionCollection implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfSectionCollection] class. - PdfSectionCollection._(PdfDocument document) { - _helper = PdfSectionCollectionHelper(this); - _helper.document = document; - _initialize(); - } - - //Fields - late PdfSectionCollectionHelper _helper; - PdfArray? _sectionCollection; - - //Properties - /// Gets the [PdfSection] at the specified index (Read only). - PdfSection operator [](int index) => _returnValue(index); - - ///Gets the total number of [PdfSection] in a document. Read only. - int get count => _helper.sections.length; - - //Public methods - /// Creates a new [PdfSection] and adds it to the collection. - PdfSection add() { - final PdfSection section = PdfSectionHelper.load(_helper.document); - _addSection(section); - return section; - } - - //Implementation - /// Adds the specified section. - void _addSection(PdfSection section) { - final PdfReferenceHolder holder = PdfReferenceHolder(section); - _helper.sections.add(section); - PdfSectionHelper.getHelper(section).parent = this; - _sectionCollection!.add(holder); - } - - void _initialize() { - _helper._count = PdfNumber(0); - _sectionCollection = PdfArray(); - _helper._pages = PdfDictionary(); - _helper._pages!.beginSave = _helper.beginSave; - _helper._pages![PdfDictionaryProperties.type] = PdfName('Pages'); - _helper._pages![PdfDictionaryProperties.kids] = _sectionCollection; - _helper._pages![PdfDictionaryProperties.count] = _helper._count; - _helper._pages![PdfDictionaryProperties.resources] = PdfDictionary(); - _helper._setPageSettings(_helper._pages!, _helper.document!.pageSettings); - } - - /// Check key and return the value. - PdfSection _returnValue(int index) { - if (index < 0 || index >= _helper.sections.length) { - throw ArgumentError.value(index, 'index out of range'); - } - return _helper.sections[index]; - } -} - -/// [PdfSectionCollection] helper -class PdfSectionCollectionHelper { - /// internal constructor - PdfSectionCollectionHelper(this.base); - - /// internal field - late PdfSectionCollection base; - PdfDictionary? _pages; - PdfNumber? _count; - - /// internal method - static PdfSectionCollectionHelper getHelper(PdfSectionCollection base) { - return base._helper; - } - - /// internal method - static PdfSectionCollection load(PdfDocument document) { - return PdfSectionCollection._(document); - } - - /// internal property - IPdfPrimitive? get element => _pages; - - //ignore: unused_element - set element(IPdfPrimitive? value) { - _pages = value as PdfDictionary?; - } - - /// internal constant field - static const int rotateFactor = 90; - - /// internal field - PdfDocument? document; - - /// internal field - final List sections = []; - - /// internal method - void beginSave(Object sender, SavePdfPrimitiveArgs? args) { - _count!.value = _countPages(); - _setPageSettings(_pages!, document!.pageSettings); - } - - void _setPageSettings( - PdfDictionary dictionary, - PdfPageSettings pageSettings, - ) { - final List list = [ - 0, - 0, - pageSettings.size.width, - pageSettings.size.height, - ]; - dictionary[PdfDictionaryProperties.mediaBox] = PdfArray(list); - if (pageSettings.rotate != PdfPageRotateAngle.rotateAngle0) { - dictionary[PdfDictionaryProperties.rotate] = PdfNumber( - rotateFactor * pageSettings.rotate.index, - ); - } - } - - int _countPages() { - int count = 0; - for (int i = 0; i < sections.length; i++) { - final PdfSection section = sections[i]; - count += PdfSectionHelper.getHelper(section).count; - } - return count; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import 'enum.dart'; +import 'pdf_page_settings.dart'; +import 'pdf_section.dart'; + +/// Represents the collection of the [PdfSection]. +class PdfSectionCollection implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfSectionCollection] class. + PdfSectionCollection._(PdfDocument document) { + _helper = PdfSectionCollectionHelper(this); + _helper.document = document; + _initialize(); + } + + //Fields + late PdfSectionCollectionHelper _helper; + PdfArray? _sectionCollection; + + //Properties + /// Gets the [PdfSection] at the specified index (Read only). + PdfSection operator [](int index) => _returnValue(index); + + ///Gets the total number of [PdfSection] in a document. Read only. + int get count => _helper.sections.length; + + //Public methods + /// Creates a new [PdfSection] and adds it to the collection. + PdfSection add() { + final PdfSection section = PdfSectionHelper.load(_helper.document); + _addSection(section); + return section; + } + + //Implementation + /// Adds the specified section. + void _addSection(PdfSection section) { + final PdfReferenceHolder holder = PdfReferenceHolder(section); + _helper.sections.add(section); + PdfSectionHelper.getHelper(section).parent = this; + _sectionCollection!.add(holder); + } + + void _initialize() { + _helper._count = PdfNumber(0); + _sectionCollection = PdfArray(); + _helper._pages = PdfDictionary(); + _helper._pages!.beginSave = _helper.beginSave; + _helper._pages![PdfDictionaryProperties.type] = PdfName('Pages'); + _helper._pages![PdfDictionaryProperties.kids] = _sectionCollection; + _helper._pages![PdfDictionaryProperties.count] = _helper._count; + _helper._pages![PdfDictionaryProperties.resources] = PdfDictionary(); + _helper._setPageSettings(_helper._pages!, _helper.document!.pageSettings); + } + + /// Check key and return the value. + PdfSection _returnValue(int index) { + if (index < 0 || index >= _helper.sections.length) { + throw ArgumentError.value(index, 'index out of range'); + } + return _helper.sections[index]; + } +} + +/// [PdfSectionCollection] helper +class PdfSectionCollectionHelper { + /// internal constructor + PdfSectionCollectionHelper(this.base); + + /// internal field + late PdfSectionCollection base; + PdfDictionary? _pages; + PdfNumber? _count; + + /// internal method + static PdfSectionCollectionHelper getHelper(PdfSectionCollection base) { + return base._helper; + } + + /// internal method + static PdfSectionCollection load(PdfDocument document) { + return PdfSectionCollection._(document); + } + + /// internal property + IPdfPrimitive? get element => _pages; + + //ignore: unused_element + set element(IPdfPrimitive? value) { + _pages = value as PdfDictionary?; + } + + /// internal constant field + static const int rotateFactor = 90; + + /// internal field + PdfDocument? document; + + /// internal field + final List sections = []; + + /// internal method + void beginSave(Object sender, SavePdfPrimitiveArgs? args) { + _count!.value = _countPages(); + _setPageSettings(_pages!, document!.pageSettings); + } + + void _setPageSettings( + PdfDictionary dictionary, + PdfPageSettings pageSettings, + ) { + final List list = [ + 0, + 0, + pageSettings.size.width, + pageSettings.size.height, + ]; + dictionary[PdfDictionaryProperties.mediaBox] = PdfArray(list); + if (pageSettings.rotate != PdfPageRotateAngle.rotateAngle0) { + dictionary[PdfDictionaryProperties.rotate] = PdfNumber( + rotateFactor * pageSettings.rotate.index, + ); + } + } + + int _countPages() { + int count = 0; + for (int i = 0; i < sections.length; i++) { + final PdfSection section = sections[i]; + count += PdfSectionHelper.getHelper(section).count; + } + return count; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_template.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_template.dart index eac7f6dd7..63d2f050e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_template.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pages/pdf_section_template.dart @@ -1,155 +1,155 @@ -import '../pdf_document/pdf_document_template.dart'; - -/// Represents a page template for all the pages in the section. -/// ```dart -/// //Create a new PDF documentation -/// PdfDocument document = PdfDocument(); -/// //Create a new PDF section -/// PdfSection section = document.sections!.add(); -/// //Create a section template -/// PdfSectionTemplate template = PdfSectionTemplate(); -/// //Sets the template for the page in the section -/// section.template = template; -/// //Create a new PDF page and draw the text -/// section.pages.add().graphics.drawString( -/// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), -/// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfSectionTemplate extends PdfDocumentTemplate { - /// Initializes a new instance of the [PdfSectionCollection] class. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Create a section template - /// PdfSectionTemplate template = PdfSectionTemplate(); - /// //Sets the template for the page in the section - /// section.template = template; - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfSectionTemplate() : super() { - leftTemplate = topTemplate = rightTemplate = bottomTemplate = stamp = true; - } - - /// Gets or sets value indicating whether parent Left page template - /// should be used or not. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Create a section template - /// PdfSectionTemplate template = PdfSectionTemplate()..leftTemplate = false; - /// //Sets the template for the page in the section - /// section.template = template; - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late bool leftTemplate; - - /// Gets or sets value indicating whether parent top page template - /// should be used or not. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Create a section template - /// PdfSectionTemplate template = PdfSectionTemplate()..topTemplate = false; - /// //Sets the template for the page in the section - /// section.template = template; - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late bool topTemplate; - - /// Gets or sets value indicating whether parent right page template - /// should be used or not. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Create a section template - /// PdfSectionTemplate template = PdfSectionTemplate()..rightTemplate = false; - /// //Sets the template for the page in the section - /// section.template = template; - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late bool rightTemplate; - - /// Gets or sets value indicating whether parent bottom page template - /// should be used or not. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Create a section template - /// PdfSectionTemplate template = PdfSectionTemplate()..bottomTemplate = false; - /// //Sets the template for the page in the section - /// section.template = template; - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late bool bottomTemplate; - - /// Gets or sets value indicating whether the parent stamp elements - /// should be used or not. - /// ```dart - /// //Create a new PDF documentation - /// PdfDocument document = PdfDocument(); - /// //Create a new PDF section - /// PdfSection section = document.sections!.add(); - /// //Create a section template - /// PdfSectionTemplate template = PdfSectionTemplate()..stamp = false; - /// //Sets the template for the page in the section - /// section.template = template; - /// //Create a new PDF page and draw the text - /// section.pages.add().graphics.drawString( - /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), - /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late bool stamp; -} +import '../pdf_document/pdf_document_template.dart'; + +/// Represents a page template for all the pages in the section. +/// ```dart +/// //Create a new PDF documentation +/// PdfDocument document = PdfDocument(); +/// //Create a new PDF section +/// PdfSection section = document.sections!.add(); +/// //Create a section template +/// PdfSectionTemplate template = PdfSectionTemplate(); +/// //Sets the template for the page in the section +/// section.template = template; +/// //Create a new PDF page and draw the text +/// section.pages.add().graphics.drawString( +/// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), +/// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfSectionTemplate extends PdfDocumentTemplate { + /// Initializes a new instance of the [PdfSectionCollection] class. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Create a section template + /// PdfSectionTemplate template = PdfSectionTemplate(); + /// //Sets the template for the page in the section + /// section.template = template; + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfSectionTemplate() : super() { + leftTemplate = topTemplate = rightTemplate = bottomTemplate = stamp = true; + } + + /// Gets or sets value indicating whether parent Left page template + /// should be used or not. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Create a section template + /// PdfSectionTemplate template = PdfSectionTemplate()..leftTemplate = false; + /// //Sets the template for the page in the section + /// section.template = template; + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late bool leftTemplate; + + /// Gets or sets value indicating whether parent top page template + /// should be used or not. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Create a section template + /// PdfSectionTemplate template = PdfSectionTemplate()..topTemplate = false; + /// //Sets the template for the page in the section + /// section.template = template; + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late bool topTemplate; + + /// Gets or sets value indicating whether parent right page template + /// should be used or not. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Create a section template + /// PdfSectionTemplate template = PdfSectionTemplate()..rightTemplate = false; + /// //Sets the template for the page in the section + /// section.template = template; + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late bool rightTemplate; + + /// Gets or sets value indicating whether parent bottom page template + /// should be used or not. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Create a section template + /// PdfSectionTemplate template = PdfSectionTemplate()..bottomTemplate = false; + /// //Sets the template for the page in the section + /// section.template = template; + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late bool bottomTemplate; + + /// Gets or sets value indicating whether the parent stamp elements + /// should be used or not. + /// ```dart + /// //Create a new PDF documentation + /// PdfDocument document = PdfDocument(); + /// //Create a new PDF section + /// PdfSection section = document.sections!.add(); + /// //Create a section template + /// PdfSectionTemplate template = PdfSectionTemplate()..stamp = false; + /// //Sets the template for the page in the section + /// section.template = template; + /// //Create a new PDF page and draw the text + /// section.pages.add().graphics.drawString( + /// 'Hello World!!!', PdfStandardFont(PdfFontFamily.helvetica, 27), + /// brush: PdfBrushes.darkBlue, bounds: const Rect.fromLTWH(170, 100, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late bool stamp; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment.dart index 7a67400ce..4c78a84d1 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment.dart @@ -1,107 +1,107 @@ -import 'dart:convert'; - -import '../../general/embedded_file.dart'; -import '../../general/embedded_file_specification.dart'; -import '../../general/file_specification_base.dart'; -import '../../io/pdf_constants.dart'; -import '../../primitives/pdf_name.dart'; -import '../enums.dart'; - -/// Represents the attachments of the PDF document. -class PdfAttachment extends PdfEmbeddedFileSpecification { - //Constructor. - /// Initializes a new instance of the [PdfAttachment] class with specified - /// file name and byte data to be attached. - PdfAttachment( - super.fileName, - super.data, { - String? description, - String? mimeType, - }) { - _embeddedFile = - PdfEmbeddedFileSpecificationHelper.getHelper(this).embeddedFile; - _updateValues(description, mimeType); - } - - /// Initializes a new instance of the [PdfAttachment] class with specified - /// file name and byte data as base64 String to be attached. - PdfAttachment.fromBase64String( - String fileName, - String base64String, { - String? description, - String? mimeType, - }) : super(fileName, base64.decode(base64String)) { - _embeddedFile = - PdfEmbeddedFileSpecificationHelper.getHelper(this).embeddedFile; - _updateValues(description, mimeType); - } - - //Fields - late EmbeddedFile _embeddedFile; - - //Properties. - /// Gets the description. - String get description => - PdfEmbeddedFileSpecificationHelper.getHelper(this).description; - - /// Sets the description. - set description(String value) => - PdfEmbeddedFileSpecificationHelper.getHelper(this).description = value; - - /// Gets the file name. - String get fileName => _embeddedFile.fileName; - - /// Sets the file name. - set fileName(String value) => _embeddedFile.fileName = value; - - /// Gets the data. - List get data => _embeddedFile.data; - - /// Sets the data. - set data(List value) => _embeddedFile.data = value; - - /// Gets the MIME type of the embedded file. - String get mimeType => _embeddedFile.mimeType; - - /// Sets the MIME type of the embedded file. - set mimeType(String value) => _embeddedFile.mimeType = value; - - /// Gets creation date. - DateTime get creationDate => _embeddedFile.params.creationDate; - - /// Sets creation date. - set creationDate(DateTime value) => _embeddedFile.params.creationDate = value; - - /// Gets modification date. - DateTime get modificationDate => _embeddedFile.params.modificationDate; - - /// Sets modification date. - set modificationDate(DateTime value) => - _embeddedFile.params.modificationDate = value; - - /// Get the file relationship. - PdfAttachmentRelationship get relationship => - PdfEmbeddedFileSpecificationHelper.getHelper(this).relationship; - - /// Set the file relationship. - set relationship(PdfAttachmentRelationship value) { - PdfEmbeddedFileSpecificationHelper.getHelper(this).relationship = value; - PdfFileSpecificationBaseHelper.getHelper(this).dictionary!.setProperty( - PdfDictionaryProperties.afRelationship, - PdfName( - PdfEmbeddedFileSpecificationHelper.getHelper(this).getEnumName( - PdfEmbeddedFileSpecificationHelper.getHelper(this).relationship, - ), - ), - ); - } - - void _updateValues(String? desc, String? mime) { - if (mime != null) { - mimeType = mime; - } - if (desc != null) { - description = desc; - } - } -} +import 'dart:convert'; + +import '../../general/embedded_file.dart'; +import '../../general/embedded_file_specification.dart'; +import '../../general/file_specification_base.dart'; +import '../../io/pdf_constants.dart'; +import '../../primitives/pdf_name.dart'; +import '../enums.dart'; + +/// Represents the attachments of the PDF document. +class PdfAttachment extends PdfEmbeddedFileSpecification { + //Constructor. + /// Initializes a new instance of the [PdfAttachment] class with specified + /// file name and byte data to be attached. + PdfAttachment( + super.fileName, + super.data, { + String? description, + String? mimeType, + }) { + _embeddedFile = + PdfEmbeddedFileSpecificationHelper.getHelper(this).embeddedFile; + _updateValues(description, mimeType); + } + + /// Initializes a new instance of the [PdfAttachment] class with specified + /// file name and byte data as base64 String to be attached. + PdfAttachment.fromBase64String( + String fileName, + String base64String, { + String? description, + String? mimeType, + }) : super(fileName, base64.decode(base64String)) { + _embeddedFile = + PdfEmbeddedFileSpecificationHelper.getHelper(this).embeddedFile; + _updateValues(description, mimeType); + } + + //Fields + late EmbeddedFile _embeddedFile; + + //Properties. + /// Gets the description. + String get description => + PdfEmbeddedFileSpecificationHelper.getHelper(this).description; + + /// Sets the description. + set description(String value) => + PdfEmbeddedFileSpecificationHelper.getHelper(this).description = value; + + /// Gets the file name. + String get fileName => _embeddedFile.fileName; + + /// Sets the file name. + set fileName(String value) => _embeddedFile.fileName = value; + + /// Gets the data. + List get data => _embeddedFile.data; + + /// Sets the data. + set data(List value) => _embeddedFile.data = value; + + /// Gets the MIME type of the embedded file. + String get mimeType => _embeddedFile.mimeType; + + /// Sets the MIME type of the embedded file. + set mimeType(String value) => _embeddedFile.mimeType = value; + + /// Gets creation date. + DateTime get creationDate => _embeddedFile.params.creationDate; + + /// Sets creation date. + set creationDate(DateTime value) => _embeddedFile.params.creationDate = value; + + /// Gets modification date. + DateTime get modificationDate => _embeddedFile.params.modificationDate; + + /// Sets modification date. + set modificationDate(DateTime value) => + _embeddedFile.params.modificationDate = value; + + /// Get the file relationship. + PdfAttachmentRelationship get relationship => + PdfEmbeddedFileSpecificationHelper.getHelper(this).relationship; + + /// Set the file relationship. + set relationship(PdfAttachmentRelationship value) { + PdfEmbeddedFileSpecificationHelper.getHelper(this).relationship = value; + PdfFileSpecificationBaseHelper.getHelper(this).dictionary!.setProperty( + PdfDictionaryProperties.afRelationship, + PdfName( + PdfEmbeddedFileSpecificationHelper.getHelper(this).getEnumName( + PdfEmbeddedFileSpecificationHelper.getHelper(this).relationship, + ), + ), + ); + } + + void _updateValues(String? desc, String? mime) { + if (mime != null) { + mimeType = mime; + } + if (desc != null) { + description = desc; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment_collection.dart index 685254b8b..5ae1be80a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/attachments/pdf_attachment_collection.dart @@ -1,473 +1,473 @@ -import 'dart:convert'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../general/pdf_collection.dart'; -import '../../io/pdf_constants.dart'; -import '../../io/pdf_cross_table.dart'; -import '../../io/pdf_main_object_collection.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_reference.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_stream.dart'; -import '../../primitives/pdf_string.dart'; -import '../enums.dart'; -import '../pdf_document.dart'; -import 'pdf_attachment.dart'; - -/// Represents a collection of the attachment objects. -class PdfAttachmentCollection extends PdfObjectCollection - implements IPdfWrapper { - //Constructors. - /// Initializes a new instance of the [PdfAttachmentCollection] class. - PdfAttachmentCollection() : super() { - _helper = PdfAttachmentCollectionHelper(this); - } - - PdfAttachmentCollection._( - PdfDictionary dictionary, - PdfCrossTable? crossTable, - ) { - _helper = PdfAttachmentCollectionHelper._(this, dictionary, crossTable); - } - - //Fields - late PdfAttachmentCollectionHelper _helper; - - //Properties - /// Gets the attachment by index from the collection. Read-Only. - PdfAttachment operator [](int index) => _helper.getValue(index); - - //Public methods. - /// Add [PdfAttachment] in the specified attachment collection. - /// - /// Returns position of the inserted attachment. - int add(PdfAttachment attachment) { - return _helper.add(attachment); - } - - /// Removes the specified attachment from the collection. - void remove(PdfAttachment attachment) { - _helper._doRemove(attachment: attachment); - } - - /// Removes attachment at the specified index. - void removeAt(int index) { - _helper._doRemove(index: index); - } - - /// Search and find the index of the attachment. - int indexOf(PdfAttachment attachment) { - return _helper.indexOf(attachment); - } - - /// Determines whether the attachment collection contains the specified attachment. - /// - /// Returns true if the attachment is present. - bool contains(PdfAttachment attachment) { - return _helper.contains(attachment); - } - - /// Remove all the attachments from the collection. - void clear() { - _helper._doClear(); - } -} - -/// [PdfAttachmentCollection] helper -class PdfAttachmentCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfAttachmentCollectionHelper(this.base) : super(base) { - dictionary = PdfDictionary(); - dictionary.setProperty(PdfDictionaryProperties.names, _array); - } - PdfAttachmentCollectionHelper._(this.base, this.dictionary, this.crossTable) - : super(base) { - _initializeAttachmentCollection(); - } - - /// internal field - late PdfAttachmentCollection base; - - /// internal field - late PdfDictionary dictionary; - - /// internal field - PdfArray? _array = PdfArray(); - - /// internal field - int _count = 0; - - /// internal field - final Map _dic = {}; - - /// internal field - PdfCrossTable? crossTable; - - /// internal method - static PdfAttachmentCollectionHelper getHelper(PdfAttachmentCollection base) { - return base._helper; - } - - /// internal method - static PdfAttachmentCollection load( - PdfDictionary attachmentDictionary, - PdfCrossTable? crossTable, - ) { - return PdfAttachmentCollection._(attachmentDictionary, crossTable); - } - - /// internal property - IPdfPrimitive get element => dictionary; - // ignore: unused_element - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - // ignore: prefer_final_fields - bool conformance = false; - - /// internal method - PdfAttachment getValue(int index) { - if (index < 0 || index >= base.count) { - throw RangeError('index'); - } - return list[index] as PdfAttachment; - } - - /// Add [PdfAttachment] in the specified attachment collection. - /// - /// Returns position of the inserted attachment. - int add(PdfAttachment attachment) { - if (conformance) { - throw ArgumentError( - 'Attachment is not allowed for this conformance level.', - ); - } - final int position = _doAdd(attachment); - dictionary.modify(); - return position; - } - - /// Search and find the index of the attachment. - int indexOf(PdfAttachment attachment) { - return list.indexOf(attachment); - } - - /// Determines whether the attachment collection contains the specified attachment. - /// - /// Returns true if the attachment is present. - bool contains(PdfAttachment attachment) { - return list.contains(attachment); - } - - void _initializeAttachmentCollection() { - IPdfPrimitive? embedDictionary = - dictionary[PdfDictionaryProperties.embeddedFiles]; - if (embedDictionary is PdfReferenceHolder) { - embedDictionary = embedDictionary.object; - } - if (embedDictionary is PdfDictionary) { - final IPdfPrimitive? obj = embedDictionary[PdfDictionaryProperties.names]; - final IPdfPrimitive? kid = embedDictionary[PdfDictionaryProperties.kids]; - if (obj is! PdfArray && kid != null && kid is PdfArray) { - final PdfArray kids = kid; - if (kids.count != 0) { - for (int l = 0; l < kids.count; l++) { - if (kids[l] is PdfReferenceHolder || kids[l] is PdfDictionary) { - embedDictionary = - kids[l] is PdfDictionary - ? kids[l]! as PdfDictionary - : (kids[l]! as PdfReferenceHolder).object != null && - (kids[l]! as PdfReferenceHolder).object - is PdfDictionary - ? (kids[l]! as PdfReferenceHolder).object - : null; - if (embedDictionary != null && embedDictionary is PdfDictionary) { - _array = - embedDictionary[PdfDictionaryProperties.names] as PdfArray?; - if (_array != null) { - _attachmentInformation(_array!); - } - } - } - } - } - } else if (obj is PdfArray) { - _array = obj; - _attachmentInformation(_array!); - } - } - } - - //Internal method to get attachement information. - void _attachmentInformation(PdfArray array) { - if (array.count != 0) { - int k = 1; - for (int i = 0; i < (array.count ~/ 2); i++) { - if (array[k] is PdfReferenceHolder || array[k] is PdfDictionary) { - IPdfPrimitive? streamDictionary = array[k]; - if (array[k] is PdfReferenceHolder) { - streamDictionary = (array[k]! as PdfReferenceHolder).object; - } - if (streamDictionary is PdfDictionary) { - PdfStream? stream = PdfStream(); - PdfDictionary? attachmentStream; - if (streamDictionary.containsKey(PdfDictionaryProperties.ef)) { - if (streamDictionary[PdfDictionaryProperties.ef] - is PdfDictionary) { - attachmentStream = - streamDictionary[PdfDictionaryProperties.ef] - as PdfDictionary?; - } else if (streamDictionary[PdfDictionaryProperties.ef] - is PdfReferenceHolder) { - final PdfReferenceHolder streamHolder = - streamDictionary[PdfDictionaryProperties.ef]! - as PdfReferenceHolder; - attachmentStream = streamHolder.object as PdfDictionary?; - } - final PdfReferenceHolder? holder1 = - attachmentStream![PdfDictionaryProperties.f] - as PdfReferenceHolder?; - if (holder1 != null) { - final IPdfPrimitive? reference = holder1.reference; - if (holder1.object != null && holder1.object is PdfStream) { - stream = holder1.object as PdfStream?; - if (stream != null && - crossTable!.encryptor != null && - crossTable!.encryptor!.encryptAttachmentOnly! && - reference != null && - reference is PdfReference) { - stream.decrypt(crossTable!.encryptor!, reference.objNum); - } - } - } - } - PdfAttachment attachment; - if (stream != null) { - stream.decompress(); - if (streamDictionary.containsKey('F')) { - attachment = PdfAttachment( - (streamDictionary['F']! as PdfString).value!, - stream.dataStream!, - ); - final IPdfPrimitive fileStream = stream; - if (fileStream is PdfDictionary) { - final IPdfPrimitive? subtype = PdfCrossTable.dereference( - fileStream[PdfDictionaryProperties.subtype], - ); - if (subtype is PdfName) { - attachment.mimeType = subtype.name! - .replaceAll('#23', '#') - .replaceAll('#20', ' ') - .replaceAll('#2F', '/'); - } - } - if (fileStream is PdfDictionary && - fileStream.containsKey(PdfDictionaryProperties.params)) { - final IPdfPrimitive? mParams = - PdfCrossTable.dereference( - fileStream[PdfDictionaryProperties.params], - ) - as PdfDictionary?; - if (mParams is PdfDictionary) { - final IPdfPrimitive? creationDate = - PdfCrossTable.dereference( - mParams[PdfDictionaryProperties.creationDate], - ); - final IPdfPrimitive? modifiedDate = - PdfCrossTable.dereference( - mParams[PdfDictionaryProperties.modificationDate], - ); - if (creationDate is PdfString) { - attachment.creationDate = mParams.getDateTime( - creationDate, - ); - } - if (modifiedDate is PdfString) { - attachment.modificationDate = mParams.getDateTime( - modifiedDate, - ); - } - } - } - if (streamDictionary.containsKey( - PdfDictionaryProperties.afRelationship, - )) { - final IPdfPrimitive? relationShip = PdfCrossTable.dereference( - streamDictionary[PdfDictionaryProperties.afRelationship], - ); - if (relationShip is PdfName) { - attachment.relationship = _obtainRelationShip( - relationShip.name, - ); - } - } - if (streamDictionary.containsKey('Desc')) { - attachment.description = - (streamDictionary['Desc']! as PdfString).value!; - } - } else { - attachment = PdfAttachment( - (streamDictionary['Desc']! as PdfString).value!, - stream.dataStream!, - ); - } - } else { - if (streamDictionary.containsKey('Desc')) { - attachment = PdfAttachment( - (streamDictionary['Desc']! as PdfString).value!, - [], - ); - } else { - attachment = PdfAttachment( - (streamDictionary['F']! as PdfString).value!, - [], - ); - } - } - list.add(attachment); - } - } - k = k + 2; - } - } - } - - //Obtain Attachement relation ship - PdfAttachmentRelationship _obtainRelationShip(String? relation) { - PdfAttachmentRelationship relationShip = - PdfAttachmentRelationship.unspecified; - switch (relation) { - case 'Alternative': - relationShip = PdfAttachmentRelationship.alternative; - break; - case 'Data': - relationShip = PdfAttachmentRelationship.data; - break; - case 'Source': - relationShip = PdfAttachmentRelationship.source; - break; - case 'Supplement': - relationShip = PdfAttachmentRelationship.supplement; - break; - case 'Unspecified': - relationShip = PdfAttachmentRelationship.unspecified; - break; - default: - break; - } - return relationShip; - } - - //Adds the attachment. - int _doAdd(PdfAttachment attachment) { - final String fileName = attachment.fileName; - final String converted = - utf8.encode(fileName).length != fileName.length - ? 'Attachment ${_count++}' - : fileName; - if (_dic.isEmpty && _array!.count > 0) { - for (int i = 0; i < _array!.count; i += 2) { - if (!_dic.containsKey((_array![i]! as PdfString).value)) { - _dic[(_array![i]! as PdfString).value!] = - _array![i + 1]! as PdfReferenceHolder; - } else { - final String value = '${(_array![i]! as PdfString).value!}_copy'; - _dic[value] = _array![i + 1]! as PdfReferenceHolder; - } - } - } - !_dic.containsKey(converted) - ? _dic[converted] = PdfReferenceHolder(attachment) - : _dic['${converted}_copy'] = PdfReferenceHolder(attachment); - final List orderList = _dic.keys.toList(); - orderList.sort(); - _array!.clear(); - for (final String? key in orderList) { - _array!.add(PdfString(key!)); - _array!.add(_dic[key]!); - } - list.add(attachment); - return list.length - 1; - } - - //Removes the attachment. - void _doRemove({PdfAttachment? attachment, int? index}) { - if (attachment != null) { - index = list.indexOf(attachment); - } - _array!.removeAt(2 * index!); - IPdfPrimitive? attachmentDictionay = PdfCrossTable.dereference( - _array![2 * index], - ); - if (attachmentDictionay is PdfDictionary) { - _removeAttachementObjects(attachmentDictionay); - attachmentDictionay = null; - } - _array!.removeAt(2 * index); - list.removeAt(index); - } - - //Removing attachment dictionary and stream from main object collection. - void _removeAttachementObjects(PdfDictionary attachmentDictionary) { - PdfMainObjectCollection? objectCollection; - if (crossTable != null && crossTable!.document != null) { - objectCollection = - PdfDocumentHelper.getHelper(crossTable!.document!).objects; - } - if (objectCollection != null) { - if (attachmentDictionary.containsKey(PdfDictionaryProperties.ef)) { - final IPdfPrimitive? embedded = PdfCrossTable.dereference( - attachmentDictionary[PdfDictionaryProperties.ef], - ); - if (embedded is PdfDictionary) { - if (embedded.containsKey(PdfDictionaryProperties.f)) { - final IPdfPrimitive? stream = PdfCrossTable.dereference( - embedded[PdfDictionaryProperties.f], - ); - if (stream != null) { - if (objectCollection.contains(stream)) { - final int index = objectCollection.lookFor(stream)!; - if (objectCollection.objectCollection!.length > index) { - objectCollection.objectCollection!.removeAt(index); - } - } - } - } - } - } - if (objectCollection.contains(attachmentDictionary)) { - final int index = objectCollection.lookFor(attachmentDictionary)!; - if (objectCollection.objectCollection!.length > index) { - objectCollection.objectCollection!.removeAt(index); - } - } - if (_dic.isNotEmpty) { - _dic.clear(); - } - } - } - - //Clears the collection. - void _doClear() { - list.clear(); - if (crossTable != null) { - final PdfMainObjectCollection coll = - PdfDocumentHelper.getHelper(crossTable!.document!).objects; - if (coll.count > 0) { - for (int i = 1; i < _array!.count; i = i + 2) { - if (_array![i] is PdfReferenceHolder) { - final IPdfPrimitive? dic = PdfCrossTable.dereference(_array![i]); - if (dic is PdfDictionary) { - _removeAttachementObjects(dic); - } - } - } - } - } - _array!.clear(); - } -} +import 'dart:convert'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../general/pdf_collection.dart'; +import '../../io/pdf_constants.dart'; +import '../../io/pdf_cross_table.dart'; +import '../../io/pdf_main_object_collection.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_reference.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_stream.dart'; +import '../../primitives/pdf_string.dart'; +import '../enums.dart'; +import '../pdf_document.dart'; +import 'pdf_attachment.dart'; + +/// Represents a collection of the attachment objects. +class PdfAttachmentCollection extends PdfObjectCollection + implements IPdfWrapper { + //Constructors. + /// Initializes a new instance of the [PdfAttachmentCollection] class. + PdfAttachmentCollection() : super() { + _helper = PdfAttachmentCollectionHelper(this); + } + + PdfAttachmentCollection._( + PdfDictionary dictionary, + PdfCrossTable? crossTable, + ) { + _helper = PdfAttachmentCollectionHelper._(this, dictionary, crossTable); + } + + //Fields + late PdfAttachmentCollectionHelper _helper; + + //Properties + /// Gets the attachment by index from the collection. Read-Only. + PdfAttachment operator [](int index) => _helper.getValue(index); + + //Public methods. + /// Add [PdfAttachment] in the specified attachment collection. + /// + /// Returns position of the inserted attachment. + int add(PdfAttachment attachment) { + return _helper.add(attachment); + } + + /// Removes the specified attachment from the collection. + void remove(PdfAttachment attachment) { + _helper._doRemove(attachment: attachment); + } + + /// Removes attachment at the specified index. + void removeAt(int index) { + _helper._doRemove(index: index); + } + + /// Search and find the index of the attachment. + int indexOf(PdfAttachment attachment) { + return _helper.indexOf(attachment); + } + + /// Determines whether the attachment collection contains the specified attachment. + /// + /// Returns true if the attachment is present. + bool contains(PdfAttachment attachment) { + return _helper.contains(attachment); + } + + /// Remove all the attachments from the collection. + void clear() { + _helper._doClear(); + } +} + +/// [PdfAttachmentCollection] helper +class PdfAttachmentCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfAttachmentCollectionHelper(this.base) : super(base) { + dictionary = PdfDictionary(); + dictionary.setProperty(PdfDictionaryProperties.names, _array); + } + PdfAttachmentCollectionHelper._(this.base, this.dictionary, this.crossTable) + : super(base) { + _initializeAttachmentCollection(); + } + + /// internal field + late PdfAttachmentCollection base; + + /// internal field + late PdfDictionary dictionary; + + /// internal field + PdfArray? _array = PdfArray(); + + /// internal field + int _count = 0; + + /// internal field + final Map _dic = {}; + + /// internal field + PdfCrossTable? crossTable; + + /// internal method + static PdfAttachmentCollectionHelper getHelper(PdfAttachmentCollection base) { + return base._helper; + } + + /// internal method + static PdfAttachmentCollection load( + PdfDictionary attachmentDictionary, + PdfCrossTable? crossTable, + ) { + return PdfAttachmentCollection._(attachmentDictionary, crossTable); + } + + /// internal property + IPdfPrimitive get element => dictionary; + // ignore: unused_element + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + // ignore: prefer_final_fields + bool conformance = false; + + /// internal method + PdfAttachment getValue(int index) { + if (index < 0 || index >= base.count) { + throw RangeError('index'); + } + return list[index] as PdfAttachment; + } + + /// Add [PdfAttachment] in the specified attachment collection. + /// + /// Returns position of the inserted attachment. + int add(PdfAttachment attachment) { + if (conformance) { + throw ArgumentError( + 'Attachment is not allowed for this conformance level.', + ); + } + final int position = _doAdd(attachment); + dictionary.modify(); + return position; + } + + /// Search and find the index of the attachment. + int indexOf(PdfAttachment attachment) { + return list.indexOf(attachment); + } + + /// Determines whether the attachment collection contains the specified attachment. + /// + /// Returns true if the attachment is present. + bool contains(PdfAttachment attachment) { + return list.contains(attachment); + } + + void _initializeAttachmentCollection() { + IPdfPrimitive? embedDictionary = + dictionary[PdfDictionaryProperties.embeddedFiles]; + if (embedDictionary is PdfReferenceHolder) { + embedDictionary = embedDictionary.object; + } + if (embedDictionary is PdfDictionary) { + final IPdfPrimitive? obj = embedDictionary[PdfDictionaryProperties.names]; + final IPdfPrimitive? kid = embedDictionary[PdfDictionaryProperties.kids]; + if (obj is! PdfArray && kid != null && kid is PdfArray) { + final PdfArray kids = kid; + if (kids.count != 0) { + for (int l = 0; l < kids.count; l++) { + if (kids[l] is PdfReferenceHolder || kids[l] is PdfDictionary) { + embedDictionary = + kids[l] is PdfDictionary + ? kids[l]! as PdfDictionary + : (kids[l]! as PdfReferenceHolder).object != null && + (kids[l]! as PdfReferenceHolder).object + is PdfDictionary + ? (kids[l]! as PdfReferenceHolder).object + : null; + if (embedDictionary != null && embedDictionary is PdfDictionary) { + _array = + embedDictionary[PdfDictionaryProperties.names] as PdfArray?; + if (_array != null) { + _attachmentInformation(_array!); + } + } + } + } + } + } else if (obj is PdfArray) { + _array = obj; + _attachmentInformation(_array!); + } + } + } + + //Internal method to get attachement information. + void _attachmentInformation(PdfArray array) { + if (array.count != 0) { + int k = 1; + for (int i = 0; i < (array.count ~/ 2); i++) { + if (array[k] is PdfReferenceHolder || array[k] is PdfDictionary) { + IPdfPrimitive? streamDictionary = array[k]; + if (array[k] is PdfReferenceHolder) { + streamDictionary = (array[k]! as PdfReferenceHolder).object; + } + if (streamDictionary is PdfDictionary) { + PdfStream? stream = PdfStream(); + PdfDictionary? attachmentStream; + if (streamDictionary.containsKey(PdfDictionaryProperties.ef)) { + if (streamDictionary[PdfDictionaryProperties.ef] + is PdfDictionary) { + attachmentStream = + streamDictionary[PdfDictionaryProperties.ef] + as PdfDictionary?; + } else if (streamDictionary[PdfDictionaryProperties.ef] + is PdfReferenceHolder) { + final PdfReferenceHolder streamHolder = + streamDictionary[PdfDictionaryProperties.ef]! + as PdfReferenceHolder; + attachmentStream = streamHolder.object as PdfDictionary?; + } + final PdfReferenceHolder? holder1 = + attachmentStream![PdfDictionaryProperties.f] + as PdfReferenceHolder?; + if (holder1 != null) { + final IPdfPrimitive? reference = holder1.reference; + if (holder1.object != null && holder1.object is PdfStream) { + stream = holder1.object as PdfStream?; + if (stream != null && + crossTable!.encryptor != null && + crossTable!.encryptor!.encryptAttachmentOnly! && + reference != null && + reference is PdfReference) { + stream.decrypt(crossTable!.encryptor!, reference.objNum); + } + } + } + } + PdfAttachment attachment; + if (stream != null) { + stream.decompress(); + if (streamDictionary.containsKey('F')) { + attachment = PdfAttachment( + (streamDictionary['F']! as PdfString).value!, + stream.dataStream!, + ); + final IPdfPrimitive fileStream = stream; + if (fileStream is PdfDictionary) { + final IPdfPrimitive? subtype = PdfCrossTable.dereference( + fileStream[PdfDictionaryProperties.subtype], + ); + if (subtype is PdfName) { + attachment.mimeType = subtype.name! + .replaceAll('#23', '#') + .replaceAll('#20', ' ') + .replaceAll('#2F', '/'); + } + } + if (fileStream is PdfDictionary && + fileStream.containsKey(PdfDictionaryProperties.params)) { + final IPdfPrimitive? mParams = + PdfCrossTable.dereference( + fileStream[PdfDictionaryProperties.params], + ) + as PdfDictionary?; + if (mParams is PdfDictionary) { + final IPdfPrimitive? creationDate = + PdfCrossTable.dereference( + mParams[PdfDictionaryProperties.creationDate], + ); + final IPdfPrimitive? modifiedDate = + PdfCrossTable.dereference( + mParams[PdfDictionaryProperties.modificationDate], + ); + if (creationDate is PdfString) { + attachment.creationDate = mParams.getDateTime( + creationDate, + ); + } + if (modifiedDate is PdfString) { + attachment.modificationDate = mParams.getDateTime( + modifiedDate, + ); + } + } + } + if (streamDictionary.containsKey( + PdfDictionaryProperties.afRelationship, + )) { + final IPdfPrimitive? relationShip = PdfCrossTable.dereference( + streamDictionary[PdfDictionaryProperties.afRelationship], + ); + if (relationShip is PdfName) { + attachment.relationship = _obtainRelationShip( + relationShip.name, + ); + } + } + if (streamDictionary.containsKey('Desc')) { + attachment.description = + (streamDictionary['Desc']! as PdfString).value!; + } + } else { + attachment = PdfAttachment( + (streamDictionary['Desc']! as PdfString).value!, + stream.dataStream!, + ); + } + } else { + if (streamDictionary.containsKey('Desc')) { + attachment = PdfAttachment( + (streamDictionary['Desc']! as PdfString).value!, + [], + ); + } else { + attachment = PdfAttachment( + (streamDictionary['F']! as PdfString).value!, + [], + ); + } + } + list.add(attachment); + } + } + k = k + 2; + } + } + } + + //Obtain Attachement relation ship + PdfAttachmentRelationship _obtainRelationShip(String? relation) { + PdfAttachmentRelationship relationShip = + PdfAttachmentRelationship.unspecified; + switch (relation) { + case 'Alternative': + relationShip = PdfAttachmentRelationship.alternative; + break; + case 'Data': + relationShip = PdfAttachmentRelationship.data; + break; + case 'Source': + relationShip = PdfAttachmentRelationship.source; + break; + case 'Supplement': + relationShip = PdfAttachmentRelationship.supplement; + break; + case 'Unspecified': + relationShip = PdfAttachmentRelationship.unspecified; + break; + default: + break; + } + return relationShip; + } + + //Adds the attachment. + int _doAdd(PdfAttachment attachment) { + final String fileName = attachment.fileName; + final String converted = + utf8.encode(fileName).length != fileName.length + ? 'Attachment ${_count++}' + : fileName; + if (_dic.isEmpty && _array!.count > 0) { + for (int i = 0; i < _array!.count; i += 2) { + if (!_dic.containsKey((_array![i]! as PdfString).value)) { + _dic[(_array![i]! as PdfString).value!] = + _array![i + 1]! as PdfReferenceHolder; + } else { + final String value = '${(_array![i]! as PdfString).value!}_copy'; + _dic[value] = _array![i + 1]! as PdfReferenceHolder; + } + } + } + !_dic.containsKey(converted) + ? _dic[converted] = PdfReferenceHolder(attachment) + : _dic['${converted}_copy'] = PdfReferenceHolder(attachment); + final List orderList = _dic.keys.toList(); + orderList.sort(); + _array!.clear(); + for (final String? key in orderList) { + _array!.add(PdfString(key!)); + _array!.add(_dic[key]!); + } + list.add(attachment); + return list.length - 1; + } + + //Removes the attachment. + void _doRemove({PdfAttachment? attachment, int? index}) { + if (attachment != null) { + index = list.indexOf(attachment); + } + _array!.removeAt(2 * index!); + IPdfPrimitive? attachmentDictionay = PdfCrossTable.dereference( + _array![2 * index], + ); + if (attachmentDictionay is PdfDictionary) { + _removeAttachementObjects(attachmentDictionay); + attachmentDictionay = null; + } + _array!.removeAt(2 * index); + list.removeAt(index); + } + + //Removing attachment dictionary and stream from main object collection. + void _removeAttachementObjects(PdfDictionary attachmentDictionary) { + PdfMainObjectCollection? objectCollection; + if (crossTable != null && crossTable!.document != null) { + objectCollection = + PdfDocumentHelper.getHelper(crossTable!.document!).objects; + } + if (objectCollection != null) { + if (attachmentDictionary.containsKey(PdfDictionaryProperties.ef)) { + final IPdfPrimitive? embedded = PdfCrossTable.dereference( + attachmentDictionary[PdfDictionaryProperties.ef], + ); + if (embedded is PdfDictionary) { + if (embedded.containsKey(PdfDictionaryProperties.f)) { + final IPdfPrimitive? stream = PdfCrossTable.dereference( + embedded[PdfDictionaryProperties.f], + ); + if (stream != null) { + if (objectCollection.contains(stream)) { + final int index = objectCollection.lookFor(stream)!; + if (objectCollection.objectCollection!.length > index) { + objectCollection.objectCollection!.removeAt(index); + } + } + } + } + } + } + if (objectCollection.contains(attachmentDictionary)) { + final int index = objectCollection.lookFor(attachmentDictionary)!; + if (objectCollection.objectCollection!.length > index) { + objectCollection.objectCollection!.removeAt(index); + } + } + if (_dic.isNotEmpty) { + _dic.clear(); + } + } + } + + //Clears the collection. + void _doClear() { + list.clear(); + if (crossTable != null) { + final PdfMainObjectCollection coll = + PdfDocumentHelper.getHelper(crossTable!.document!).objects; + if (coll.count > 0) { + for (int i = 1; i < _array!.count; i = i + 2) { + if (_array![i] is PdfReferenceHolder) { + final IPdfPrimitive? dic = PdfCrossTable.dereference(_array![i]); + if (dic is PdfDictionary) { + _removeAttachementObjects(dic); + } + } + } + } + } + _array!.clear(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field.dart index a87977db4..35bff4eca 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field.dart @@ -1,516 +1,516 @@ -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/brushes/pdf_brush.dart'; -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/fonts/enums.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_standard_font.dart'; -import '../../graphics/fonts/pdf_string_format.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../graphics/pdf_pen.dart'; -import '../../pages/enum.dart'; -import 'pdf_automatic_field_info.dart'; -import 'pdf_composite_field.dart'; -import 'pdf_date_time_field.dart'; -import 'pdf_destination_page_number_field.dart'; -import 'pdf_multiple_value_field.dart'; -import 'pdf_page_count_field.dart'; -import 'pdf_page_number_field.dart'; -import 'pdf_single_value_field.dart'; -import 'pdf_static_field.dart'; - -/// Represents a fields which is calculated before the document saves. -abstract class PdfAutomaticField { - /// Initialize [PdfAutomaticField] object - void _internal( - PdfFont? font, { - Rect? bounds, - PdfBrush? brush, - PdfAutomaticFieldHelper? helper, - }) { - _helper = helper!; - this.font = font ?? PdfStandardFont(PdfFontFamily.helvetica, 8); - if (bounds != null) { - _bounds = PdfRectangle.fromRect(bounds); - } else { - _bounds = PdfRectangle.empty; - } - this.brush = brush ?? PdfBrushes.black; - } - - // fields - late PdfAutomaticFieldHelper _helper; - late PdfRectangle _bounds; - PdfPen? _pen; - - /// Gets or sets the font of the field. - ///```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// //Create the date and time field - /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); - /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; - /// //Create the composite field. - /// PdfCompositeField compositefields = PdfCompositeField(); - /// //Gets or sets the font. - /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); - /// //Gets or sets the brush. - /// compositefields.brush = PdfSolidBrush(PdfColor(0, 0, 0)); - /// //Gets or sets the text. - /// compositefields.text = '{0} Header'; - /// //Gets or sets the fields. - /// compositefields.fields = [dateAndTimeField]; - /// //Add composite field in header - /// compositefields.draw(header.graphics, - /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - ///``` - late PdfFont font; - - /// Gets or sets the brush of the field. - ///```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// //Create the date and time field - /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); - /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; - /// //Create the composite field. - /// PdfCompositeField compositefields = PdfCompositeField(); - /// //Gets or sets the font. - /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); - /// //Gets or sets the brush. - /// compositefields.brush = PdfSolidBrush(PdfColor(0, 0, 0)); - /// //Gets or sets the text. - /// compositefields.text = '{0} Header'; - /// //Gets or sets the fields. - /// compositefields.fields = [dateAndTimeField]; - /// //Add composite field in header - /// compositefields.draw(header.graphics, - /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - ///``` - late PdfBrush brush; - - /// Gets or sets the stringFormat of the field. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// //Create the date and time field - /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); - /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; - /// //Create the composite field with date field - /// PdfCompositeField compositefields = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: '{0} Header', - /// fields: [dateAndTimeField]); - /// compositefields.stringFormat = - /// PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle); - /// //Add composite field in header - /// compositefields.draw(header.graphics, - /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfStringFormat? stringFormat; - - // properties - /// Gets or sets the bounds of the field. - ///```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// //Create the date and time field - /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); - /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; - /// //Create the composite field. - /// PdfCompositeField compositefields = PdfCompositeField(); - /// //Gets or sets the bounds. - /// compositefields.bounds = Rect.fromLTWH(10, 10, 200, 200); - /// //Gets or sets the font. - /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); - /// //Gets or sets the brush. - /// compositefields.brush = PdfSolidBrush(PdfColor(0, 0, 0)); - /// //Gets or sets the text. - /// compositefields.text = '{0} Header'; - /// //Gets or sets the fields. - /// compositefields.fields = [dateAndTimeField]; - /// //Add composite field in header - /// compositefields.draw(header.graphics, - /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - ///``` - Rect get bounds { - return _bounds.rect; - } - - set bounds(Rect value) { - _bounds = PdfRectangle.fromRect(value); - } - - /// Gets or sets the pen of the field. - ///```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// //Create the date and time field - /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); - /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; - /// //Create the composite field. - /// PdfCompositeField compositefields = PdfCompositeField(); - /// //Gets or sets the font. - /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); - /// //Gets or sets the pen. - /// compositefields.pen = PdfPen(PdfColor(0, 0, 0), width: 2); - /// //Gets or sets the text. - /// compositefields.text = '{0} Header'; - /// //Gets or sets the fields. - /// compositefields.fields = [dateAndTimeField]; - /// //Add composite field in header - /// compositefields.draw(header.graphics, - /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - ///``` - PdfPen? get pen => _pen; - set pen(PdfPen? value) { - _pen = (value == null) ? throw ArgumentError.value('brush') : value; - } - - // implementation - /// Draws an element on the Graphics. - /// Graphics context where the element should be printed. - /// location has contains X co-ordinate of the element, - /// Y co-ordinate of the element. - ///```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// //Create the date and time field - /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); - /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; - /// //Create the composite field with date field - /// PdfCompositeField compositefields = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: '{0} Header', - /// fields: [dateAndTimeField]); - /// //Add composite field in header - /// compositefields.draw(header.graphics, - /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - ///``` - void draw(PdfGraphics graphics, [Offset? location]) { - location ??= Offset.zero; - PdfGraphicsHelper.getHelper(graphics).autoFields!.add( - PdfAutomaticFieldInfo(this, PdfPoint.fromOffset(location)), - ); - } -} - -/// [PdfAutomaticField] helper -class PdfAutomaticFieldHelper { - /// internal constructor - PdfAutomaticFieldHelper(this.base); - - /// internal field - late PdfAutomaticField base; - - /// internal method - static PdfAutomaticFieldHelper getHelper(PdfAutomaticField base) { - return base._helper; - } - - /// internal method - void internal(PdfFont? font, {Rect? bounds, PdfBrush? brush}) { - base._internal(font, bounds: bounds, brush: brush, helper: this); - } - - // fields - static const double _letterLimit = 26.0; - static const int _acsiiStartIndex = 65 - 1; - Size _templateSize = Size.zero; - - // methods - /// internal method - static String convert(int intArabic, PdfNumberStyle numberStyle) { - switch (numberStyle) { - case PdfNumberStyle.none: - return ''; - case PdfNumberStyle.numeric: - return intArabic.toString(); - case PdfNumberStyle.lowerLatin: - return _arabicToLetter(intArabic).toLowerCase(); - case PdfNumberStyle.lowerRoman: - return _arabicToRoman(intArabic).toLowerCase(); - case PdfNumberStyle.upperLatin: - return _arabicToLetter(intArabic); - case PdfNumberStyle.upperRoman: - return _arabicToRoman(intArabic); - } - } - - static String _arabicToRoman(int intArabic) { - final StringBuffer retval = StringBuffer(); - List result = _generateNumber(intArabic, 1000, 'M'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 900, 'CM'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 500, 'D'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 400, 'CD'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 100, 'C'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 90, 'XC'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 50, 'L'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 40, 'XL'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 10, 'X'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 9, 'IX'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 5, 'V'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 4, 'IV'); - retval.write(result.elementAt(0)); - result = _generateNumber(result.elementAt(1) as int, 1, 'I'); - retval.write(result.elementAt(0)); - return retval.toString(); - } - - static List _generateNumber(int value, int magnitude, String letter) { - final StringBuffer numberString = StringBuffer(); - while (value >= magnitude) { - value -= magnitude; - numberString.write(letter); - } - final List result = []; - result.add(numberString.toString()); - result.add(value); - return result; - } - - static String _arabicToLetter(int arabic) { - final List stack = _convertToLetter(arabic.toDouble()); - final StringBuffer result = StringBuffer(); - - while (stack.isNotEmpty) { - final int n = stack.removeLast(); - _appendChar(result, n); - } - return result.toString(); - } - - static List _convertToLetter(double arabic) { - if (arabic <= 0) { - throw ArgumentError.value('arabic value can not be less 0'); - } - final List stack = []; - while ((arabic.toInt()) > _letterLimit) { - double remainder = arabic % _letterLimit; - - if (remainder == 0.0) { - arabic = arabic / _letterLimit - 1; - remainder = _letterLimit; - } else { - arabic /= _letterLimit; - } - - stack.add(remainder.toInt()); - } - if (arabic > 0) { - stack.add(arabic.toInt()); - } - return stack; - } - - static void _appendChar(StringBuffer result, int number) { - if (number <= 0 || number > 26) { - throw ArgumentError.value('Value can not be less 0 and greater 26'); - } - final String letter = (_acsiiStartIndex + number).toString(); - result.write(String.fromCharCode(int.parse(letter))); - } - - /// internal method - String? getValue(PdfGraphics graphics) { - if (base is PdfCompositeField) { - return PdfCompositeFieldHelper.getValue( - base as PdfCompositeField, - graphics, - ); - } else if (base is PdfDateTimeField) { - return PdfDateTimeFieldHelper.getValue( - base as PdfDateTimeField, - graphics, - ); - } else if (base is PdfDestinationPageNumberField) { - return PdfDestinationPageNumberFieldHelper.getValue( - base as PdfDestinationPageNumberField, - graphics, - ); - } else if (base is PdfPageNumberField) { - return PdfPageNumberFieldHelper.getHelper( - base as PdfPageNumberField, - ).getValue(graphics); - } else if (base is PdfPageCountField) { - return PdfPageCountFieldHelper.getValue( - base as PdfPageCountField, - graphics, - ); - } - return graphics as String; - } - - /// internal method - void performDraw( - PdfGraphics graphics, - PdfPoint? location, - double scalingX, - double scalingY, - ) { - if (base.bounds.height == 0 || base.bounds.width == 0) { - final String text = getValue(graphics)!; - _templateSize = base.font.measureString( - text, - layoutArea: base.bounds.size, - format: base.stringFormat, - ); - } - if (base is PdfStaticField) { - PdfStaticFieldHelper.performDraw( - base as PdfStaticField, - graphics, - location, - scalingX, - scalingY, - ); - } else if (base is PdfSingleValueField) { - PdfSingleValueFieldHelper.performDraw( - base as PdfSingleValueField, - graphics, - location, - scalingX, - scalingY, - ); - } else if (base is PdfMultipleValueField) { - PdfMultipleValueFieldHelper.performDraw( - base as PdfMultipleValueField, - graphics, - location, - scalingX, - scalingY, - ); - } - } - - /// internal method - Size obtainSize() { - if (base.bounds.height == 0 || base.bounds.width == 0) { - return _templateSize; - } else { - return base.bounds.size; - } - } -} +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/brushes/pdf_brush.dart'; +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/fonts/enums.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_standard_font.dart'; +import '../../graphics/fonts/pdf_string_format.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../graphics/pdf_pen.dart'; +import '../../pages/enum.dart'; +import 'pdf_automatic_field_info.dart'; +import 'pdf_composite_field.dart'; +import 'pdf_date_time_field.dart'; +import 'pdf_destination_page_number_field.dart'; +import 'pdf_multiple_value_field.dart'; +import 'pdf_page_count_field.dart'; +import 'pdf_page_number_field.dart'; +import 'pdf_single_value_field.dart'; +import 'pdf_static_field.dart'; + +/// Represents a fields which is calculated before the document saves. +abstract class PdfAutomaticField { + /// Initialize [PdfAutomaticField] object + void _internal( + PdfFont? font, { + Rect? bounds, + PdfBrush? brush, + PdfAutomaticFieldHelper? helper, + }) { + _helper = helper!; + this.font = font ?? PdfStandardFont(PdfFontFamily.helvetica, 8); + if (bounds != null) { + _bounds = PdfRectangle.fromRect(bounds); + } else { + _bounds = PdfRectangle.empty; + } + this.brush = brush ?? PdfBrushes.black; + } + + // fields + late PdfAutomaticFieldHelper _helper; + late PdfRectangle _bounds; + PdfPen? _pen; + + /// Gets or sets the font of the field. + ///```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// //Create the date and time field + /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); + /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; + /// //Create the composite field. + /// PdfCompositeField compositefields = PdfCompositeField(); + /// //Gets or sets the font. + /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); + /// //Gets or sets the brush. + /// compositefields.brush = PdfSolidBrush(PdfColor(0, 0, 0)); + /// //Gets or sets the text. + /// compositefields.text = '{0} Header'; + /// //Gets or sets the fields. + /// compositefields.fields = [dateAndTimeField]; + /// //Add composite field in header + /// compositefields.draw(header.graphics, + /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + ///``` + late PdfFont font; + + /// Gets or sets the brush of the field. + ///```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// //Create the date and time field + /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); + /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; + /// //Create the composite field. + /// PdfCompositeField compositefields = PdfCompositeField(); + /// //Gets or sets the font. + /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); + /// //Gets or sets the brush. + /// compositefields.brush = PdfSolidBrush(PdfColor(0, 0, 0)); + /// //Gets or sets the text. + /// compositefields.text = '{0} Header'; + /// //Gets or sets the fields. + /// compositefields.fields = [dateAndTimeField]; + /// //Add composite field in header + /// compositefields.draw(header.graphics, + /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + ///``` + late PdfBrush brush; + + /// Gets or sets the stringFormat of the field. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// //Create the date and time field + /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); + /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; + /// //Create the composite field with date field + /// PdfCompositeField compositefields = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: '{0} Header', + /// fields: [dateAndTimeField]); + /// compositefields.stringFormat = + /// PdfStringFormat(lineAlignment: PdfVerticalAlignment.middle); + /// //Add composite field in header + /// compositefields.draw(header.graphics, + /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfStringFormat? stringFormat; + + // properties + /// Gets or sets the bounds of the field. + ///```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// //Create the date and time field + /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); + /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; + /// //Create the composite field. + /// PdfCompositeField compositefields = PdfCompositeField(); + /// //Gets or sets the bounds. + /// compositefields.bounds = Rect.fromLTWH(10, 10, 200, 200); + /// //Gets or sets the font. + /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); + /// //Gets or sets the brush. + /// compositefields.brush = PdfSolidBrush(PdfColor(0, 0, 0)); + /// //Gets or sets the text. + /// compositefields.text = '{0} Header'; + /// //Gets or sets the fields. + /// compositefields.fields = [dateAndTimeField]; + /// //Add composite field in header + /// compositefields.draw(header.graphics, + /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + ///``` + Rect get bounds { + return _bounds.rect; + } + + set bounds(Rect value) { + _bounds = PdfRectangle.fromRect(value); + } + + /// Gets or sets the pen of the field. + ///```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// //Create the date and time field + /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); + /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; + /// //Create the composite field. + /// PdfCompositeField compositefields = PdfCompositeField(); + /// //Gets or sets the font. + /// compositefields.font = PdfStandardFont(PdfFontFamily.timesRoman, 19); + /// //Gets or sets the pen. + /// compositefields.pen = PdfPen(PdfColor(0, 0, 0), width: 2); + /// //Gets or sets the text. + /// compositefields.text = '{0} Header'; + /// //Gets or sets the fields. + /// compositefields.fields = [dateAndTimeField]; + /// //Add composite field in header + /// compositefields.draw(header.graphics, + /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + ///``` + PdfPen? get pen => _pen; + set pen(PdfPen? value) { + _pen = (value == null) ? throw ArgumentError.value('brush') : value; + } + + // implementation + /// Draws an element on the Graphics. + /// Graphics context where the element should be printed. + /// location has contains X co-ordinate of the element, + /// Y co-ordinate of the element. + ///```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// //Create the date and time field + /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// dateAndTimeField.date = DateTime(2020, 2, 10, 13, 13, 13, 13, 13); + /// dateAndTimeField.dateFormatString = 'E, MM.dd.yyyy'; + /// //Create the composite field with date field + /// PdfCompositeField compositefields = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: '{0} Header', + /// fields: [dateAndTimeField]); + /// //Add composite field in header + /// compositefields.draw(header.graphics, + /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + ///``` + void draw(PdfGraphics graphics, [Offset? location]) { + location ??= Offset.zero; + PdfGraphicsHelper.getHelper(graphics).autoFields!.add( + PdfAutomaticFieldInfo(this, PdfPoint.fromOffset(location)), + ); + } +} + +/// [PdfAutomaticField] helper +class PdfAutomaticFieldHelper { + /// internal constructor + PdfAutomaticFieldHelper(this.base); + + /// internal field + late PdfAutomaticField base; + + /// internal method + static PdfAutomaticFieldHelper getHelper(PdfAutomaticField base) { + return base._helper; + } + + /// internal method + void internal(PdfFont? font, {Rect? bounds, PdfBrush? brush}) { + base._internal(font, bounds: bounds, brush: brush, helper: this); + } + + // fields + static const double _letterLimit = 26.0; + static const int _acsiiStartIndex = 65 - 1; + Size _templateSize = Size.zero; + + // methods + /// internal method + static String convert(int intArabic, PdfNumberStyle numberStyle) { + switch (numberStyle) { + case PdfNumberStyle.none: + return ''; + case PdfNumberStyle.numeric: + return intArabic.toString(); + case PdfNumberStyle.lowerLatin: + return _arabicToLetter(intArabic).toLowerCase(); + case PdfNumberStyle.lowerRoman: + return _arabicToRoman(intArabic).toLowerCase(); + case PdfNumberStyle.upperLatin: + return _arabicToLetter(intArabic); + case PdfNumberStyle.upperRoman: + return _arabicToRoman(intArabic); + } + } + + static String _arabicToRoman(int intArabic) { + final StringBuffer retval = StringBuffer(); + List result = _generateNumber(intArabic, 1000, 'M'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 900, 'CM'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 500, 'D'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 400, 'CD'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 100, 'C'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 90, 'XC'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 50, 'L'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 40, 'XL'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 10, 'X'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 9, 'IX'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 5, 'V'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 4, 'IV'); + retval.write(result.elementAt(0)); + result = _generateNumber(result.elementAt(1) as int, 1, 'I'); + retval.write(result.elementAt(0)); + return retval.toString(); + } + + static List _generateNumber(int value, int magnitude, String letter) { + final StringBuffer numberString = StringBuffer(); + while (value >= magnitude) { + value -= magnitude; + numberString.write(letter); + } + final List result = []; + result.add(numberString.toString()); + result.add(value); + return result; + } + + static String _arabicToLetter(int arabic) { + final List stack = _convertToLetter(arabic.toDouble()); + final StringBuffer result = StringBuffer(); + + while (stack.isNotEmpty) { + final int n = stack.removeLast(); + _appendChar(result, n); + } + return result.toString(); + } + + static List _convertToLetter(double arabic) { + if (arabic <= 0) { + throw ArgumentError.value('arabic value can not be less 0'); + } + final List stack = []; + while ((arabic.toInt()) > _letterLimit) { + double remainder = arabic % _letterLimit; + + if (remainder == 0.0) { + arabic = arabic / _letterLimit - 1; + remainder = _letterLimit; + } else { + arabic /= _letterLimit; + } + + stack.add(remainder.toInt()); + } + if (arabic > 0) { + stack.add(arabic.toInt()); + } + return stack; + } + + static void _appendChar(StringBuffer result, int number) { + if (number <= 0 || number > 26) { + throw ArgumentError.value('Value can not be less 0 and greater 26'); + } + final String letter = (_acsiiStartIndex + number).toString(); + result.write(String.fromCharCode(int.parse(letter))); + } + + /// internal method + String? getValue(PdfGraphics graphics) { + if (base is PdfCompositeField) { + return PdfCompositeFieldHelper.getValue( + base as PdfCompositeField, + graphics, + ); + } else if (base is PdfDateTimeField) { + return PdfDateTimeFieldHelper.getValue( + base as PdfDateTimeField, + graphics, + ); + } else if (base is PdfDestinationPageNumberField) { + return PdfDestinationPageNumberFieldHelper.getValue( + base as PdfDestinationPageNumberField, + graphics, + ); + } else if (base is PdfPageNumberField) { + return PdfPageNumberFieldHelper.getHelper( + base as PdfPageNumberField, + ).getValue(graphics); + } else if (base is PdfPageCountField) { + return PdfPageCountFieldHelper.getValue( + base as PdfPageCountField, + graphics, + ); + } + return graphics as String; + } + + /// internal method + void performDraw( + PdfGraphics graphics, + PdfPoint? location, + double scalingX, + double scalingY, + ) { + if (base.bounds.height == 0 || base.bounds.width == 0) { + final String text = getValue(graphics)!; + _templateSize = base.font.measureString( + text, + layoutArea: base.bounds.size, + format: base.stringFormat, + ); + } + if (base is PdfStaticField) { + PdfStaticFieldHelper.performDraw( + base as PdfStaticField, + graphics, + location, + scalingX, + scalingY, + ); + } else if (base is PdfSingleValueField) { + PdfSingleValueFieldHelper.performDraw( + base as PdfSingleValueField, + graphics, + location, + scalingX, + scalingY, + ); + } else if (base is PdfMultipleValueField) { + PdfMultipleValueFieldHelper.performDraw( + base as PdfMultipleValueField, + graphics, + location, + scalingX, + scalingY, + ); + } + } + + /// internal method + Size obtainSize() { + if (base.bounds.height == 0 || base.bounds.width == 0) { + return _templateSize; + } else { + return base.bounds.size; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field_info.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field_info.dart index 4df42076a..b259fbbf3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field_info.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_automatic_field_info.dart @@ -1,30 +1,30 @@ -import '../../drawing/drawing.dart'; -import 'pdf_automatic_field.dart'; - -/// internal class -class PdfAutomaticFieldInfo { - // constructor - /// internal constructor - PdfAutomaticFieldInfo( - this.field, [ - PdfPoint? location, - double scalingX = 1, - double scalingY = 1, - ]) { - this.location = location ?? PdfPoint.empty; - scalingX = scalingX; - scalingY = scalingY; - } - - /// internal field - double scalingX = 1; - - /// internal field - double scalingY = 1; - - /// internal field - late PdfAutomaticField field; - - /// internal field - late PdfPoint location; -} +import '../../drawing/drawing.dart'; +import 'pdf_automatic_field.dart'; + +/// internal class +class PdfAutomaticFieldInfo { + // constructor + /// internal constructor + PdfAutomaticFieldInfo( + this.field, [ + PdfPoint? location, + double scalingX = 1, + double scalingY = 1, + ]) { + this.location = location ?? PdfPoint.empty; + scalingX = scalingX; + scalingY = scalingY; + } + + /// internal field + double scalingX = 1; + + /// internal field + double scalingY = 1; + + /// internal field + late PdfAutomaticField field; + + /// internal field + late PdfPoint location; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_composite_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_composite_field.dart index b3c9d1c76..b76bdd3bd 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_composite_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_composite_field.dart @@ -1,210 +1,210 @@ -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import 'pdf_automatic_field.dart'; -import 'pdf_multiple_value_field.dart'; - -/// Represents class which can concatenate multiple -/// automatic fields into single string. -/// ```dart -/// //Create a new pdf document -/// PdfDocument document = PdfDocument(); -/// //Add the pages to the document -/// for (int i = 1; i <= 5; i++) { -/// document.pages.add().graphics.drawString( -/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), -/// bounds: Rect.fromLTWH(250, 0, 615, 100)); -/// } -/// //Create the header with specific bounds -/// PdfPageTemplateElement header = PdfPageTemplateElement( -/// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); -/// //Create the date and time field -/// PdfDateTimeField dateAndTimeField = PdfDateTimeField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); -/// //Create the composite field with date field -/// PdfCompositeField compositefields = PdfCompositeField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), -/// text: '{0} Header', -/// fields: [dateAndTimeField]); -/// //Add composite field in header -/// compositefields.draw(header.graphics, -/// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); -/// //Add the header at top of the document -/// document.template.top = header; -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfCompositeField extends PdfMultipleValueField { - // constructor - /// Initializes the new instance of the [PdfCompositeField] class. - /// - /// [font] - Specifies the [PdfFont] to use. - /// [brush] - Specifies the color and texture to the text. - /// [text] - The wide-chracter string to be drawn. - /// [fields] - The list of [PdfAutomaticField] objects. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the header with specific bounds - /// PdfPageTemplateElement header = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); - /// //Create the date and time field - /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Create the composite field with date field - /// PdfCompositeField compositefields = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: '{0} Header', - /// fields: [dateAndTimeField]); - /// //Add composite field in header - /// compositefields.draw(header.graphics, - /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); - /// //Add the header at top of the document - /// document.template.top = header; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfCompositeField({ - super.font, - super.brush, - String? text, - List? fields, - }) { - this.text = (text == null) ? '' : text; - if (fields != null) { - this.fields = fields; - } - } - - // field - /// Internal variable to store list of automatic fields. - List? _fields; - - // properties - /// Get or set the text for user format to display the page details - /// (eg. Input text:page {0} of {1} as dispalyed to page 1 of 5) - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = - /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); - /// //Create the page number field - /// PdfPageNumberField pageNumber = PdfPageNumberField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Sets the number style for page number - /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; - /// //Create the composite field - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Set text to composite field. - /// compositeField.text = 'Page {0}'; - /// //Add page number field to composite fields - /// compositeField.fields.add(pageNumber); - /// //Set bounds to composite field. - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw(footer.graphics, - /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String text = ''; - - /// Gets or sets the automatic fields(like page number, page count and etc.,) - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = - /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); - /// //Create the page number field - /// PdfPageNumberField pageNumber = PdfPageNumberField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Sets the number style for page number - /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; - /// //Create the composite field - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Set text to composite field. - /// compositeField.text = 'Page {0}'; - /// //Sets page number field to composite fields - /// compositeField.fields = [pageNumber]; - /// //Set bounds to composite field. - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw(footer.graphics, - /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - List get fields { - _fields ??= []; - return _fields!; - } - - set fields(List value) { - _fields = value; - } - - // implementation - String _getValue(PdfGraphics graphics) { - String? copyText; - if (fields.isNotEmpty) { - copyText = text; - for (int i = 0; i < fields.length; i++) { - copyText = copyText!.replaceAll( - '{$i}', - PdfAutomaticFieldHelper.getHelper(fields[i]).getValue(graphics)!, - ); - } - } - return (copyText == null) ? text : copyText; - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfCompositeField] helper -class PdfCompositeFieldHelper { - /// internal method - static String getValue(PdfCompositeField field, PdfGraphics graphics) { - return field._getValue(graphics); - } -} +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import 'pdf_automatic_field.dart'; +import 'pdf_multiple_value_field.dart'; + +/// Represents class which can concatenate multiple +/// automatic fields into single string. +/// ```dart +/// //Create a new pdf document +/// PdfDocument document = PdfDocument(); +/// //Add the pages to the document +/// for (int i = 1; i <= 5; i++) { +/// document.pages.add().graphics.drawString( +/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), +/// bounds: Rect.fromLTWH(250, 0, 615, 100)); +/// } +/// //Create the header with specific bounds +/// PdfPageTemplateElement header = PdfPageTemplateElement( +/// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); +/// //Create the date and time field +/// PdfDateTimeField dateAndTimeField = PdfDateTimeField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); +/// //Create the composite field with date field +/// PdfCompositeField compositefields = PdfCompositeField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), +/// text: '{0} Header', +/// fields: [dateAndTimeField]); +/// //Add composite field in header +/// compositefields.draw(header.graphics, +/// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); +/// //Add the header at top of the document +/// document.template.top = header; +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfCompositeField extends PdfMultipleValueField { + // constructor + /// Initializes the new instance of the [PdfCompositeField] class. + /// + /// [font] - Specifies the [PdfFont] to use. + /// [brush] - Specifies the color and texture to the text. + /// [text] - The wide-chracter string to be drawn. + /// [fields] - The list of [PdfAutomaticField] objects. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the header with specific bounds + /// PdfPageTemplateElement header = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 300)); + /// //Create the date and time field + /// PdfDateTimeField dateAndTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Create the composite field with date field + /// PdfCompositeField compositefields = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: '{0} Header', + /// fields: [dateAndTimeField]); + /// //Add composite field in header + /// compositefields.draw(header.graphics, + /// Offset(0, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 11).height)); + /// //Add the header at top of the document + /// document.template.top = header; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfCompositeField({ + super.font, + super.brush, + String? text, + List? fields, + }) { + this.text = (text == null) ? '' : text; + if (fields != null) { + this.fields = fields; + } + } + + // field + /// Internal variable to store list of automatic fields. + List? _fields; + + // properties + /// Get or set the text for user format to display the page details + /// (eg. Input text:page {0} of {1} as dispalyed to page 1 of 5) + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = + /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); + /// //Create the page number field + /// PdfPageNumberField pageNumber = PdfPageNumberField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Sets the number style for page number + /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; + /// //Create the composite field + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Set text to composite field. + /// compositeField.text = 'Page {0}'; + /// //Add page number field to composite fields + /// compositeField.fields.add(pageNumber); + /// //Set bounds to composite field. + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw(footer.graphics, + /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String text = ''; + + /// Gets or sets the automatic fields(like page number, page count and etc.,) + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = + /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); + /// //Create the page number field + /// PdfPageNumberField pageNumber = PdfPageNumberField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Sets the number style for page number + /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; + /// //Create the composite field + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Set text to composite field. + /// compositeField.text = 'Page {0}'; + /// //Sets page number field to composite fields + /// compositeField.fields = [pageNumber]; + /// //Set bounds to composite field. + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw(footer.graphics, + /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + List get fields { + _fields ??= []; + return _fields!; + } + + set fields(List value) { + _fields = value; + } + + // implementation + String _getValue(PdfGraphics graphics) { + String? copyText; + if (fields.isNotEmpty) { + copyText = text; + for (int i = 0; i < fields.length; i++) { + copyText = copyText!.replaceAll( + '{$i}', + PdfAutomaticFieldHelper.getHelper(fields[i]).getValue(graphics)!, + ); + } + } + return (copyText == null) ? text : copyText; + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfCompositeField] helper +class PdfCompositeFieldHelper { + /// internal method + static String getValue(PdfCompositeField field, PdfGraphics graphics) { + return field._getValue(graphics); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_date_time_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_date_time_field.dart index 139999c08..f1adc1e42 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_date_time_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_date_time_field.dart @@ -1,225 +1,225 @@ -import 'package:intl/date_symbol_data_local.dart'; -import 'package:intl/intl.dart'; - -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import 'pdf_static_field.dart'; - -/// Represents date and time automated field. -/// ```dart -/// //Create a new pdf document -/// PdfDocument document = PdfDocument(); -/// //Add the pages to the document -/// for (int i = 1; i <= 5; i++) { -/// document.pages.add().graphics.drawString( -/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), -/// bounds: Rect.fromLTWH(250, 0, 615, 100)); -/// } -/// //Create the footer with specific bounds -/// PdfPageTemplateElement footer = -/// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); -/// //Create the composite field -/// PdfCompositeField compositeField = PdfCompositeField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), -/// text: 'Time:{0}'); -/// //Create the date and time field -/// PdfDateTimeField dateTimeField = PdfDateTimeField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); -/// //Add date&time field to composite fields -/// compositeField.fields.add(dateTimeField); -/// //Set bounds to composite field. -/// compositeField.bounds = footer.bounds; -/// //Add the composite field in footer -/// compositeField.draw(footer.graphics, -/// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); -/// //Add the footer at the bottom of the document -/// document.template.bottom = footer; -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfDateTimeField extends PdfStaticField { - // constructor - /// Initializes a new instance of the [PdfDateTimeField] class. - /// - /// [font] - Specifies the [PdfFont] to use. - /// [brush] - The object that is used to fill the string. - /// [bounds] - Specifies the location and size of the field. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = - /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); - /// //Create the composite field - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Time:{0}'); - /// //Create the date and time field - /// PdfDateTimeField dateTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Add date&time field to composite fields - /// compositeField.fields.add(dateTimeField); - /// //Set bounds to composite field. - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw(footer.graphics, - /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfDateTimeField({super.font, super.brush, super.bounds}); - - /// Get the current date and set the required date. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = - /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); - /// //Create the composite field - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Time:{0}'); - /// //Create the date and time field - /// PdfDateTimeField dateTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Gets the date and time - /// DateTime dateTime = dateTimeField.date; - /// //Add date&time field to composite fields - /// compositeField.fields.add(dateTimeField); - /// //Set bounds to composite field. - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw(footer.graphics, - /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - DateTime date = DateTime.now(); - - // properties - /// Gets or sets the date format string. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = - /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); - /// //Create the composite field - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Time:{0}'); - /// //Create the date and time field - /// PdfDateTimeField dateTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Sets the date and time format - /// dateTimeField.dateFormatString = 'hh\':\'mm\':\'ss'; - /// //Add date&time field to composite fields - /// compositeField.fields.add(dateTimeField); - /// //Set bounds to composite field. - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw(footer.graphics, - /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String dateFormatString = "dd'/'MM'/'yyyy hh':'mm':'ss"; - - /// Gets or sets the locale for date and time culture. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = - /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); - /// //Create the composite field - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Time:{0}'); - /// //Create the date and time field - /// PdfDateTimeField dateTimeField = PdfDateTimeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Sets the date and time locale - /// dateTimeField.locale = 'en_US'; - /// //Add date&time field to composite fields - /// compositeField.fields.add(dateTimeField); - /// //Set bounds to composite field. - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw(footer.graphics, - /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String locale = 'en_US'; - - // implementation - String _getValue(PdfGraphics? graphics) { - initializeDateFormatting(locale); - final DateFormat formatter = DateFormat(dateFormatString, locale); - final String value = formatter.format(date); - return value; - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfDateTimeField] helper -class PdfDateTimeFieldHelper { - /// internal method - static String getValue(PdfDateTimeField field, PdfGraphics? graphics) { - return field._getValue(graphics); - } -} +import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl.dart'; + +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import 'pdf_static_field.dart'; + +/// Represents date and time automated field. +/// ```dart +/// //Create a new pdf document +/// PdfDocument document = PdfDocument(); +/// //Add the pages to the document +/// for (int i = 1; i <= 5; i++) { +/// document.pages.add().graphics.drawString( +/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), +/// bounds: Rect.fromLTWH(250, 0, 615, 100)); +/// } +/// //Create the footer with specific bounds +/// PdfPageTemplateElement footer = +/// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); +/// //Create the composite field +/// PdfCompositeField compositeField = PdfCompositeField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), +/// text: 'Time:{0}'); +/// //Create the date and time field +/// PdfDateTimeField dateTimeField = PdfDateTimeField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); +/// //Add date&time field to composite fields +/// compositeField.fields.add(dateTimeField); +/// //Set bounds to composite field. +/// compositeField.bounds = footer.bounds; +/// //Add the composite field in footer +/// compositeField.draw(footer.graphics, +/// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); +/// //Add the footer at the bottom of the document +/// document.template.bottom = footer; +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfDateTimeField extends PdfStaticField { + // constructor + /// Initializes a new instance of the [PdfDateTimeField] class. + /// + /// [font] - Specifies the [PdfFont] to use. + /// [brush] - The object that is used to fill the string. + /// [bounds] - Specifies the location and size of the field. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = + /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); + /// //Create the composite field + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Time:{0}'); + /// //Create the date and time field + /// PdfDateTimeField dateTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Add date&time field to composite fields + /// compositeField.fields.add(dateTimeField); + /// //Set bounds to composite field. + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw(footer.graphics, + /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfDateTimeField({super.font, super.brush, super.bounds}); + + /// Get the current date and set the required date. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = + /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); + /// //Create the composite field + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Time:{0}'); + /// //Create the date and time field + /// PdfDateTimeField dateTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Gets the date and time + /// DateTime dateTime = dateTimeField.date; + /// //Add date&time field to composite fields + /// compositeField.fields.add(dateTimeField); + /// //Set bounds to composite field. + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw(footer.graphics, + /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + DateTime date = DateTime.now(); + + // properties + /// Gets or sets the date format string. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = + /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); + /// //Create the composite field + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Time:{0}'); + /// //Create the date and time field + /// PdfDateTimeField dateTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Sets the date and time format + /// dateTimeField.dateFormatString = 'hh\':\'mm\':\'ss'; + /// //Add date&time field to composite fields + /// compositeField.fields.add(dateTimeField); + /// //Set bounds to composite field. + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw(footer.graphics, + /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String dateFormatString = "dd'/'MM'/'yyyy hh':'mm':'ss"; + + /// Gets or sets the locale for date and time culture. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = + /// PdfPageTemplateElement(const Rect.fromLTWH(0, 0, 515, 50)); + /// //Create the composite field + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Time:{0}'); + /// //Create the date and time field + /// PdfDateTimeField dateTimeField = PdfDateTimeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Sets the date and time locale + /// dateTimeField.locale = 'en_US'; + /// //Add date&time field to composite fields + /// compositeField.fields.add(dateTimeField); + /// //Set bounds to composite field. + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw(footer.graphics, + /// Offset(290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String locale = 'en_US'; + + // implementation + String _getValue(PdfGraphics? graphics) { + initializeDateFormatting(locale); + final DateFormat formatter = DateFormat(dateFormatString, locale); + final String value = formatter.format(date); + return value; + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfDateTimeField] helper +class PdfDateTimeFieldHelper { + /// internal method + static String getValue(PdfDateTimeField field, PdfGraphics? graphics) { + return field._getValue(graphics); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_destination_page_number_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_destination_page_number_field.dart index 025eab1fb..3a65d52d0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_destination_page_number_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_destination_page_number_field.dart @@ -1,44 +1,44 @@ -import 'dart:ui'; - -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../pages/pdf_page.dart'; -import 'pdf_page_number_field.dart'; - -/// Represents class which displays destination page's number. -class PdfDestinationPageNumberField extends PdfPageNumberField { - // constructor - /// Initializes a new instance of the [PdfDestinationPageNumberField] class - /// may include with [PdfFont], [PdfBrush] and [Rect]. - PdfDestinationPageNumberField({ - PdfPage? page, - super.font, - super.brush, - super.bounds, - }) { - if (page != null) { - this.page = page; - } - } - - /// Gets or sets the page. - PdfPage? page; - - // implementation - String _getValue(PdfGraphics graphics) { - return PdfPageNumberFieldHelper.getHelper(this).internalGetValue(page); - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfDestinationPageNumberField] helper -class PdfDestinationPageNumberFieldHelper { - /// internal method - static String getValue( - PdfDestinationPageNumberField field, - PdfGraphics graphics, - ) { - return field._getValue(graphics); - } -} +import 'dart:ui'; + +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../pages/pdf_page.dart'; +import 'pdf_page_number_field.dart'; + +/// Represents class which displays destination page's number. +class PdfDestinationPageNumberField extends PdfPageNumberField { + // constructor + /// Initializes a new instance of the [PdfDestinationPageNumberField] class + /// may include with [PdfFont], [PdfBrush] and [Rect]. + PdfDestinationPageNumberField({ + PdfPage? page, + super.font, + super.brush, + super.bounds, + }) { + if (page != null) { + this.page = page; + } + } + + /// Gets or sets the page. + PdfPage? page; + + // implementation + String _getValue(PdfGraphics graphics) { + return PdfPageNumberFieldHelper.getHelper(this).internalGetValue(page); + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfDestinationPageNumberField] helper +class PdfDestinationPageNumberFieldHelper { + /// internal method + static String getValue( + PdfDestinationPageNumberField field, + PdfGraphics graphics, + ) { + return field._getValue(graphics); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_dynamic_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_dynamic_field.dart index e9d57882d..27c2afea6 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_dynamic_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_dynamic_field.dart @@ -1,25 +1,25 @@ -import 'dart:ui'; - -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../pages/pdf_page.dart'; -import 'pdf_automatic_field.dart'; - -/// Represents class which can concatenate multiple automatic fields -/// into single string. -abstract class PdfDynamicField extends PdfAutomaticField { - // constructor - /// internal constructor - PdfDynamicField({PdfFont? font, Rect? bounds, PdfBrush? brush}) { - PdfAutomaticFieldHelper(this).internal(font, bounds: bounds, brush: brush); - } - - // public methods - /// internal method - static PdfPage getPageFromGraphics(PdfGraphics graphics) { - final PdfPage? page = PdfGraphicsHelper.getHelper(graphics).page; - ArgumentError.checkNotNull(page, 'page'); - return page!; - } -} +import 'dart:ui'; + +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../pages/pdf_page.dart'; +import 'pdf_automatic_field.dart'; + +/// Represents class which can concatenate multiple automatic fields +/// into single string. +abstract class PdfDynamicField extends PdfAutomaticField { + // constructor + /// internal constructor + PdfDynamicField({PdfFont? font, Rect? bounds, PdfBrush? brush}) { + PdfAutomaticFieldHelper(this).internal(font, bounds: bounds, brush: brush); + } + + // public methods + /// internal method + static PdfPage getPageFromGraphics(PdfGraphics graphics) { + final PdfPage? page = PdfGraphicsHelper.getHelper(graphics).page; + ArgumentError.checkNotNull(page, 'page'); + return page!; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_multiple_value_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_multiple_value_field.dart index a10d94b0e..d2fe3c6ca 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_multiple_value_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_multiple_value_field.dart @@ -1,89 +1,89 @@ -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/figures/pdf_template.dart'; -import '../../graphics/pdf_graphics.dart'; -import 'pdf_automatic_field.dart'; -import 'pdf_dynamic_field.dart'; -import 'pdf_template_value_pair.dart'; - -/// internal class -abstract class PdfMultipleValueField extends PdfDynamicField { - // constructor - /// internal constructor - PdfMultipleValueField({super.font, super.brush, super.bounds}); - - // fields - final Map _list = - {}; - - // implementation - void _performDraw( - PdfGraphics graphics, - PdfPoint? location, - double scalingX, - double scalingY, - ) { - final String? value = PdfAutomaticFieldHelper.getHelper( - this, - ).getValue(graphics); - if (_list.containsKey(graphics)) { - final PdfTemplateValuePair pair = _list[graphics]!; - if (pair.value != value) { - final Size size = PdfAutomaticFieldHelper.getHelper(this).obtainSize(); - pair.template.reset(size.width, size.height); - pair.template.graphics!.drawString( - value!, - font, - pen: pen, - brush: brush, - bounds: Rect.fromLTWH(0, 0, size.width, size.height), - format: stringFormat, - ); - } - } else { - final PdfTemplate template = PdfTemplate( - PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, - PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, - ); - _list[graphics] = PdfTemplateValuePair(template, value!); - template.graphics!.drawString( - value, - font, - pen: pen, - brush: brush, - bounds: Rect.fromLTWH( - 0, - 0, - PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, - PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, - ), - format: stringFormat, - ); - final Offset drawLocation = Offset( - location!.x + bounds.left, - location.y + bounds.top, - ); - graphics.drawPdfTemplate( - template, - drawLocation, - Size(template.size.width * scalingX, template.size.height * scalingY), - ); - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfMultipleValueField] helper -class PdfMultipleValueFieldHelper { - /// internal method - static void performDraw( - PdfMultipleValueField field, - PdfGraphics graphics, - PdfPoint? location, - double scalingX, - double scalingY, - ) { - field._performDraw(graphics, location, scalingX, scalingY); - } -} +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/figures/pdf_template.dart'; +import '../../graphics/pdf_graphics.dart'; +import 'pdf_automatic_field.dart'; +import 'pdf_dynamic_field.dart'; +import 'pdf_template_value_pair.dart'; + +/// internal class +abstract class PdfMultipleValueField extends PdfDynamicField { + // constructor + /// internal constructor + PdfMultipleValueField({super.font, super.brush, super.bounds}); + + // fields + final Map _list = + {}; + + // implementation + void _performDraw( + PdfGraphics graphics, + PdfPoint? location, + double scalingX, + double scalingY, + ) { + final String? value = PdfAutomaticFieldHelper.getHelper( + this, + ).getValue(graphics); + if (_list.containsKey(graphics)) { + final PdfTemplateValuePair pair = _list[graphics]!; + if (pair.value != value) { + final Size size = PdfAutomaticFieldHelper.getHelper(this).obtainSize(); + pair.template.reset(size.width, size.height); + pair.template.graphics!.drawString( + value!, + font, + pen: pen, + brush: brush, + bounds: Rect.fromLTWH(0, 0, size.width, size.height), + format: stringFormat, + ); + } + } else { + final PdfTemplate template = PdfTemplate( + PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, + PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, + ); + _list[graphics] = PdfTemplateValuePair(template, value!); + template.graphics!.drawString( + value, + font, + pen: pen, + brush: brush, + bounds: Rect.fromLTWH( + 0, + 0, + PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, + PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, + ), + format: stringFormat, + ); + final Offset drawLocation = Offset( + location!.x + bounds.left, + location.y + bounds.top, + ); + graphics.drawPdfTemplate( + template, + drawLocation, + Size(template.size.width * scalingX, template.size.height * scalingY), + ); + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfMultipleValueField] helper +class PdfMultipleValueFieldHelper { + /// internal method + static void performDraw( + PdfMultipleValueField field, + PdfGraphics graphics, + PdfPoint? location, + double scalingX, + double scalingY, + ) { + field._performDraw(graphics, location, scalingX, scalingY); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_count_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_count_field.dart index 467af91ca..393712075 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_count_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_count_field.dart @@ -1,180 +1,180 @@ -import 'dart:ui'; - -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../pages/enum.dart'; -import '../../pages/pdf_page.dart'; -import '../../pages/pdf_section.dart'; -import '../../pages/pdf_section_collection.dart'; -import '../pdf_document.dart'; -import 'pdf_automatic_field.dart'; -import 'pdf_dynamic_field.dart'; -import 'pdf_single_value_field.dart'; - -/// Represents total PDF document page count automatic field. -/// Represents an automatic field to display total number of pages -/// in section(if set isSectionPageCount as true). -/// ```dart -/// //Create a new pdf document -/// PdfDocument document = PdfDocument(); -/// //Add the pages to the document -/// for (int i = 1; i <= 5; i++) { -/// document.pages.add().graphics.drawString( -/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), -/// bounds: Rect.fromLTWH(250, 0, 615, 100)); -/// } -/// //Create the footer with specific bounds -/// PdfPageTemplateElement footer = PdfPageTemplateElement( -/// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); -/// //Create the page count field -/// PdfPageCountField count = PdfPageCountField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); -/// //set the number style for page count -/// count.numberStyle = PdfNumberStyle.upperRoman; -/// //Create the composite field with page number page count -/// PdfCompositeField compositeField = PdfCompositeField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), -/// text: 'Page Count: {0}', -/// fields: [count]); -/// compositeField.bounds = footer.bounds; -/// //Add the composite field in footer -/// compositeField.draw( -/// footer.graphics, -/// Offset( -/// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); -/// //Add the footer at the bottom of the document -/// document.template.bottom = footer; -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfPageCountField extends PdfSingleValueField { - // constructor - /// Initializes a new instance of the [PdfPageCountField] class - /// and may also with the classes are [PdfFont], [PdfBrush] and [Rect]. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); - /// //Create the page count field - /// PdfPageCountField count = PdfPageCountField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //set the number style for page count - /// count.numberStyle = PdfNumberStyle.upperRoman; - /// //Create the composite field with page number page count - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Page Count: {0}', - /// fields: [count]); - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw( - /// footer.graphics, - /// Offset( - /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageCountField({ - PdfFont? font, - PdfBrush? brush, - Rect? bounds, - bool? isSectionPageCount, - }) : super(font, brush, bounds) { - _isSectionPageCount = isSectionPageCount != null && isSectionPageCount; - } - - // fields - /// Gets or sets the specific number style. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); - /// //Create the page count field - /// PdfPageCountField count = PdfPageCountField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Gets or Sets the number style for page count - /// count.numberStyle = PdfNumberStyle.upperRoman; - /// //Create the composite field with page number page count - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Page Count: {0}', - /// fields: [count]); - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw( - /// footer.graphics, - /// Offset( - /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfNumberStyle numberStyle = PdfNumberStyle.numeric; - - /// Represents an automatic field to display total number of pages in section. - bool _isSectionPageCount = false; - - // implementation - String? _getValue(PdfGraphics graphics) { - String? result; - if (PdfGraphicsHelper.getHelper(graphics).page is PdfPage) { - final PdfPage page = PdfDynamicField.getPageFromGraphics(graphics); - if (_isSectionPageCount) { - final PdfSection section = PdfPageHelper.getHelper(page).section!; - final int count = PdfSectionHelper.getHelper(section).count; - return PdfAutomaticFieldHelper.convert(count, numberStyle); - } else { - final PdfDocument document = - PdfSectionCollectionHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page).section!, - ).parent!, - ).document!; - final int number = document.pages.count; - return PdfAutomaticFieldHelper.convert(number, numberStyle); - } - } - return result; - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfPageCountField] helper -class PdfPageCountFieldHelper { - /// internal method - static String? getValue(PdfPageCountField field, PdfGraphics graphics) { - return field._getValue(graphics); - } -} +import 'dart:ui'; + +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../pages/enum.dart'; +import '../../pages/pdf_page.dart'; +import '../../pages/pdf_section.dart'; +import '../../pages/pdf_section_collection.dart'; +import '../pdf_document.dart'; +import 'pdf_automatic_field.dart'; +import 'pdf_dynamic_field.dart'; +import 'pdf_single_value_field.dart'; + +/// Represents total PDF document page count automatic field. +/// Represents an automatic field to display total number of pages +/// in section(if set isSectionPageCount as true). +/// ```dart +/// //Create a new pdf document +/// PdfDocument document = PdfDocument(); +/// //Add the pages to the document +/// for (int i = 1; i <= 5; i++) { +/// document.pages.add().graphics.drawString( +/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), +/// bounds: Rect.fromLTWH(250, 0, 615, 100)); +/// } +/// //Create the footer with specific bounds +/// PdfPageTemplateElement footer = PdfPageTemplateElement( +/// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); +/// //Create the page count field +/// PdfPageCountField count = PdfPageCountField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); +/// //set the number style for page count +/// count.numberStyle = PdfNumberStyle.upperRoman; +/// //Create the composite field with page number page count +/// PdfCompositeField compositeField = PdfCompositeField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), +/// text: 'Page Count: {0}', +/// fields: [count]); +/// compositeField.bounds = footer.bounds; +/// //Add the composite field in footer +/// compositeField.draw( +/// footer.graphics, +/// Offset( +/// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); +/// //Add the footer at the bottom of the document +/// document.template.bottom = footer; +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfPageCountField extends PdfSingleValueField { + // constructor + /// Initializes a new instance of the [PdfPageCountField] class + /// and may also with the classes are [PdfFont], [PdfBrush] and [Rect]. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); + /// //Create the page count field + /// PdfPageCountField count = PdfPageCountField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //set the number style for page count + /// count.numberStyle = PdfNumberStyle.upperRoman; + /// //Create the composite field with page number page count + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Page Count: {0}', + /// fields: [count]); + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw( + /// footer.graphics, + /// Offset( + /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageCountField({ + PdfFont? font, + PdfBrush? brush, + Rect? bounds, + bool? isSectionPageCount, + }) : super(font, brush, bounds) { + _isSectionPageCount = isSectionPageCount != null && isSectionPageCount; + } + + // fields + /// Gets or sets the specific number style. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); + /// //Create the page count field + /// PdfPageCountField count = PdfPageCountField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Gets or Sets the number style for page count + /// count.numberStyle = PdfNumberStyle.upperRoman; + /// //Create the composite field with page number page count + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Page Count: {0}', + /// fields: [count]); + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw( + /// footer.graphics, + /// Offset( + /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfNumberStyle numberStyle = PdfNumberStyle.numeric; + + /// Represents an automatic field to display total number of pages in section. + bool _isSectionPageCount = false; + + // implementation + String? _getValue(PdfGraphics graphics) { + String? result; + if (PdfGraphicsHelper.getHelper(graphics).page is PdfPage) { + final PdfPage page = PdfDynamicField.getPageFromGraphics(graphics); + if (_isSectionPageCount) { + final PdfSection section = PdfPageHelper.getHelper(page).section!; + final int count = PdfSectionHelper.getHelper(section).count; + return PdfAutomaticFieldHelper.convert(count, numberStyle); + } else { + final PdfDocument document = + PdfSectionCollectionHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page).section!, + ).parent!, + ).document!; + final int number = document.pages.count; + return PdfAutomaticFieldHelper.convert(number, numberStyle); + } + } + return result; + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfPageCountField] helper +class PdfPageCountFieldHelper { + /// internal method + static String? getValue(PdfPageCountField field, PdfGraphics graphics) { + return field._getValue(graphics); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_number_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_number_field.dart index 244c536b4..775b66a37 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_number_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_page_number_field.dart @@ -1,192 +1,192 @@ -import 'dart:ui'; - -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../pages/enum.dart'; -import '../../pages/pdf_page.dart'; -import '../../pages/pdf_section.dart'; -import '../../pages/pdf_section_collection.dart'; -import '../pdf_document.dart'; -import 'pdf_automatic_field.dart'; -import 'pdf_dynamic_field.dart'; -import 'pdf_multiple_value_field.dart'; - -/// Represents PDF document page number field. -/// Represents an automatic field to display page number within a section. -/// ```dart -/// //Create a new pdf document -/// PdfDocument document = PdfDocument(); -/// //Add the pages to the document -/// for (int i = 1; i <= 5; i++) { -/// document.pages.add().graphics.drawString( -/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), -/// bounds: Rect.fromLTWH(250, 0, 615, 100)); -/// } -/// //Create the footer with specific bounds -/// PdfPageTemplateElement footer = PdfPageTemplateElement( -/// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); -/// //Create the page number field -/// PdfPageNumberField pageNumber = PdfPageNumberField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); -/// //Sets the number style for page number -/// pageNumber.numberStyle = PdfNumberStyle.upperRoman; -/// //Create the composite field with page number page count -/// PdfCompositeField compositeField = PdfCompositeField( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), -/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), -/// text: 'Page No: {0}', -/// fields: [pageNumber]); -/// compositeField.bounds = footer.bounds; -/// //Add the composite field in footer -/// compositeField.draw( -/// footer.graphics, -/// Offset( -/// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); -/// //Add the footer at the bottom of the document -/// document.template.bottom = footer; -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfPageNumberField extends PdfMultipleValueField { - // constructor - /// Initializes a new instance of the [PdfPageNumberField] class - /// and may also with the classes are [PdfFont], [PdfBrush] and [Rect]. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); - /// //Create the page number field - /// PdfPageNumberField pageNumber = PdfPageNumberField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Sets the number style for page number - /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; - /// //Create the composite field with page number page count - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Page No: {0}', - /// fields: [pageNumber]); - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw( - /// footer.graphics, - /// Offset( - /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPageNumberField({ - super.font, - super.brush, - super.bounds, - bool? isSectionPageNumber, - }) { - _helper = PdfPageNumberFieldHelper(this); - _helper._isSectionPageNumber = - isSectionPageNumber != null && isSectionPageNumber; - } - - // fields - /// Gets or sets the specific number style. - /// ```dart - /// //Create a new pdf document - /// PdfDocument document = PdfDocument(); - /// //Add the pages to the document - /// for (int i = 1; i <= 5; i++) { - /// document.pages.add().graphics.drawString( - /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), - /// bounds: Rect.fromLTWH(250, 0, 615, 100)); - /// } - /// //Create the footer with specific bounds - /// PdfPageTemplateElement footer = PdfPageTemplateElement( - /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); - /// //Create the page number field - /// PdfPageNumberField pageNumber = PdfPageNumberField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); - /// //Sets the number style for page number - /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; - /// //Create the composite field with page number page count - /// PdfCompositeField compositeField = PdfCompositeField( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// text: 'Page No: {0}', - /// fields: [pageNumber]); - /// compositeField.bounds = footer.bounds; - /// //Add the composite field in footer - /// compositeField.draw( - /// footer.graphics, - /// Offset( - /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); - /// //Add the footer at the bottom of the document - /// document.template.bottom = footer; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfNumberStyle numberStyle = PdfNumberStyle.numeric; - late PdfPageNumberFieldHelper _helper; -} - -/// [PdfPageNumberField] helper -class PdfPageNumberFieldHelper { - /// internal constructor - PdfPageNumberFieldHelper(this.base); - - /// internal field - PdfPageNumberField base; - - /// Represents an automatic field to display page number within a section. - bool _isSectionPageNumber = false; - - /// internal method - static PdfPageNumberFieldHelper getHelper(PdfPageNumberField field) { - return field._helper; - } - - /// internal method - String? getValue(PdfGraphics graphics) { - String? result; - if (PdfGraphicsHelper.getHelper(graphics).page is PdfPage) { - final PdfPage page = PdfDynamicField.getPageFromGraphics(graphics); - result = internalGetValue(page); - } - return result; - } - - /// internal method - String internalGetValue(PdfPage? page) { - if (_isSectionPageNumber) { - final PdfSection section = PdfPageHelper.getHelper(page!).section!; - final int index = PdfSectionHelper.getHelper(section).indexOf(page) + 1; - return PdfAutomaticFieldHelper.convert(index, base.numberStyle); - } else { - final PdfDocument document = - PdfSectionCollectionHelper.getHelper( - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page!).section!, - ).parent!, - ).document!; - final int pageIndex = document.pages.indexOf(page) + 1; - return PdfAutomaticFieldHelper.convert(pageIndex, base.numberStyle); - } - } -} +import 'dart:ui'; + +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../pages/enum.dart'; +import '../../pages/pdf_page.dart'; +import '../../pages/pdf_section.dart'; +import '../../pages/pdf_section_collection.dart'; +import '../pdf_document.dart'; +import 'pdf_automatic_field.dart'; +import 'pdf_dynamic_field.dart'; +import 'pdf_multiple_value_field.dart'; + +/// Represents PDF document page number field. +/// Represents an automatic field to display page number within a section. +/// ```dart +/// //Create a new pdf document +/// PdfDocument document = PdfDocument(); +/// //Add the pages to the document +/// for (int i = 1; i <= 5; i++) { +/// document.pages.add().graphics.drawString( +/// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), +/// bounds: Rect.fromLTWH(250, 0, 615, 100)); +/// } +/// //Create the footer with specific bounds +/// PdfPageTemplateElement footer = PdfPageTemplateElement( +/// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); +/// //Create the page number field +/// PdfPageNumberField pageNumber = PdfPageNumberField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0))); +/// //Sets the number style for page number +/// pageNumber.numberStyle = PdfNumberStyle.upperRoman; +/// //Create the composite field with page number page count +/// PdfCompositeField compositeField = PdfCompositeField( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), +/// brush: PdfSolidBrush(PdfColor(0, 0, 0)), +/// text: 'Page No: {0}', +/// fields: [pageNumber]); +/// compositeField.bounds = footer.bounds; +/// //Add the composite field in footer +/// compositeField.draw( +/// footer.graphics, +/// Offset( +/// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); +/// //Add the footer at the bottom of the document +/// document.template.bottom = footer; +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfPageNumberField extends PdfMultipleValueField { + // constructor + /// Initializes a new instance of the [PdfPageNumberField] class + /// and may also with the classes are [PdfFont], [PdfBrush] and [Rect]. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); + /// //Create the page number field + /// PdfPageNumberField pageNumber = PdfPageNumberField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Sets the number style for page number + /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; + /// //Create the composite field with page number page count + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Page No: {0}', + /// fields: [pageNumber]); + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw( + /// footer.graphics, + /// Offset( + /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPageNumberField({ + super.font, + super.brush, + super.bounds, + bool? isSectionPageNumber, + }) { + _helper = PdfPageNumberFieldHelper(this); + _helper._isSectionPageNumber = + isSectionPageNumber != null && isSectionPageNumber; + } + + // fields + /// Gets or sets the specific number style. + /// ```dart + /// //Create a new pdf document + /// PdfDocument document = PdfDocument(); + /// //Add the pages to the document + /// for (int i = 1; i <= 5; i++) { + /// document.pages.add().graphics.drawString( + /// 'page$i', PdfStandardFont(PdfFontFamily.timesRoman, 11), + /// bounds: Rect.fromLTWH(250, 0, 615, 100)); + /// } + /// //Create the footer with specific bounds + /// PdfPageTemplateElement footer = PdfPageTemplateElement( + /// Rect.fromLTWH(0, 0, document.pages[0].getClientSize().width, 50)); + /// //Create the page number field + /// PdfPageNumberField pageNumber = PdfPageNumberField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0))); + /// //Sets the number style for page number + /// pageNumber.numberStyle = PdfNumberStyle.upperRoman; + /// //Create the composite field with page number page count + /// PdfCompositeField compositeField = PdfCompositeField( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 19), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// text: 'Page No: {0}', + /// fields: [pageNumber]); + /// compositeField.bounds = footer.bounds; + /// //Add the composite field in footer + /// compositeField.draw( + /// footer.graphics, + /// Offset( + /// 290, 50 - PdfStandardFont(PdfFontFamily.timesRoman, 19).height)); + /// //Add the footer at the bottom of the document + /// document.template.bottom = footer; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfNumberStyle numberStyle = PdfNumberStyle.numeric; + late PdfPageNumberFieldHelper _helper; +} + +/// [PdfPageNumberField] helper +class PdfPageNumberFieldHelper { + /// internal constructor + PdfPageNumberFieldHelper(this.base); + + /// internal field + PdfPageNumberField base; + + /// Represents an automatic field to display page number within a section. + bool _isSectionPageNumber = false; + + /// internal method + static PdfPageNumberFieldHelper getHelper(PdfPageNumberField field) { + return field._helper; + } + + /// internal method + String? getValue(PdfGraphics graphics) { + String? result; + if (PdfGraphicsHelper.getHelper(graphics).page is PdfPage) { + final PdfPage page = PdfDynamicField.getPageFromGraphics(graphics); + result = internalGetValue(page); + } + return result; + } + + /// internal method + String internalGetValue(PdfPage? page) { + if (_isSectionPageNumber) { + final PdfSection section = PdfPageHelper.getHelper(page!).section!; + final int index = PdfSectionHelper.getHelper(section).indexOf(page) + 1; + return PdfAutomaticFieldHelper.convert(index, base.numberStyle); + } else { + final PdfDocument document = + PdfSectionCollectionHelper.getHelper( + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page!).section!, + ).parent!, + ).document!; + final int pageIndex = document.pages.indexOf(page) + 1; + return PdfAutomaticFieldHelper.convert(pageIndex, base.numberStyle); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_single_value_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_single_value_field.dart index 35baa71d9..e3f70c1ec 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_single_value_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_single_value_field.dart @@ -1,122 +1,122 @@ -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/figures/pdf_template.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../pages/pdf_page.dart'; -import '../pdf_document.dart'; -import 'pdf_automatic_field.dart'; -import 'pdf_dynamic_field.dart'; -import 'pdf_template_value_pair.dart'; - -/// internal class -abstract class PdfSingleValueField extends PdfDynamicField { - // constructor - /// internal constructor - PdfSingleValueField([PdfFont? font, PdfBrush? brush, Rect? bounds]) - : super(font: font, bounds: bounds, brush: brush); - - // field - final Map _list = - {}; - final List _painterGraphics = []; - - // implementation - void _performDraw( - PdfGraphics graphics, - PdfPoint? location, - double scalingX, - double scalingY, - ) { - if (PdfGraphicsHelper.getHelper(graphics).page is PdfPage) { - final PdfPage page = PdfDynamicField.getPageFromGraphics(graphics); - final PdfDocument? document = PdfPageHelper.getHelper(page).document; - final String? value = PdfAutomaticFieldHelper.getHelper( - this, - ).getValue(graphics); - - if (_list.containsKey(document)) { - final PdfTemplateValuePair pair = _list[document]!; - if (pair.value != value) { - final Size size = - PdfAutomaticFieldHelper.getHelper(this).obtainSize(); - pair.template.reset(size.width, size.height); - pair.template.graphics!.drawString( - value!, - font, - pen: pen, - brush: brush, - bounds: bounds.topLeft & size, - format: stringFormat, - ); - } - - if (!_painterGraphics.contains(graphics)) { - final Offset drawLocation = Offset( - location!.x + bounds.left, - location.y + bounds.top, - ); - graphics.drawPdfTemplate( - pair.template, - drawLocation, - Size( - pair.template.size.width * scalingX, - pair.template.size.height * scalingY, - ), - ); - _painterGraphics.add(graphics); - } - } else { - final PdfTemplate template = PdfTemplate( - PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, - PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, - ); - _list[document] = PdfTemplateValuePair(template, value!); - final PdfTemplateValuePair pair = _list[document]!; - template.graphics!.drawString( - value, - font, - pen: pen, - brush: brush, - bounds: Rect.fromLTWH( - bounds.left, - bounds.top, - bounds.width, - bounds.height, - ), - format: stringFormat, - ); - final Offset drawLocation = Offset( - location!.x + bounds.left, - location.y + bounds.top, - ); - graphics.drawPdfTemplate( - pair.template, - drawLocation, - Size( - pair.template.size.width * scalingX, - pair.template.size.height * scalingY, - ), - ); - _painterGraphics.add(graphics); - } - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfSingleValueField] value -class PdfSingleValueFieldHelper { - /// internal method - static void performDraw( - PdfSingleValueField field, - PdfGraphics graphics, - PdfPoint? location, - double scalingX, - double scalingY, - ) { - field._performDraw(graphics, location, scalingX, scalingY); - } -} +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/figures/pdf_template.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../pages/pdf_page.dart'; +import '../pdf_document.dart'; +import 'pdf_automatic_field.dart'; +import 'pdf_dynamic_field.dart'; +import 'pdf_template_value_pair.dart'; + +/// internal class +abstract class PdfSingleValueField extends PdfDynamicField { + // constructor + /// internal constructor + PdfSingleValueField([PdfFont? font, PdfBrush? brush, Rect? bounds]) + : super(font: font, bounds: bounds, brush: brush); + + // field + final Map _list = + {}; + final List _painterGraphics = []; + + // implementation + void _performDraw( + PdfGraphics graphics, + PdfPoint? location, + double scalingX, + double scalingY, + ) { + if (PdfGraphicsHelper.getHelper(graphics).page is PdfPage) { + final PdfPage page = PdfDynamicField.getPageFromGraphics(graphics); + final PdfDocument? document = PdfPageHelper.getHelper(page).document; + final String? value = PdfAutomaticFieldHelper.getHelper( + this, + ).getValue(graphics); + + if (_list.containsKey(document)) { + final PdfTemplateValuePair pair = _list[document]!; + if (pair.value != value) { + final Size size = + PdfAutomaticFieldHelper.getHelper(this).obtainSize(); + pair.template.reset(size.width, size.height); + pair.template.graphics!.drawString( + value!, + font, + pen: pen, + brush: brush, + bounds: bounds.topLeft & size, + format: stringFormat, + ); + } + + if (!_painterGraphics.contains(graphics)) { + final Offset drawLocation = Offset( + location!.x + bounds.left, + location.y + bounds.top, + ); + graphics.drawPdfTemplate( + pair.template, + drawLocation, + Size( + pair.template.size.width * scalingX, + pair.template.size.height * scalingY, + ), + ); + _painterGraphics.add(graphics); + } + } else { + final PdfTemplate template = PdfTemplate( + PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, + PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, + ); + _list[document] = PdfTemplateValuePair(template, value!); + final PdfTemplateValuePair pair = _list[document]!; + template.graphics!.drawString( + value, + font, + pen: pen, + brush: brush, + bounds: Rect.fromLTWH( + bounds.left, + bounds.top, + bounds.width, + bounds.height, + ), + format: stringFormat, + ); + final Offset drawLocation = Offset( + location!.x + bounds.left, + location.y + bounds.top, + ); + graphics.drawPdfTemplate( + pair.template, + drawLocation, + Size( + pair.template.size.width * scalingX, + pair.template.size.height * scalingY, + ), + ); + _painterGraphics.add(graphics); + } + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfSingleValueField] value +class PdfSingleValueFieldHelper { + /// internal method + static void performDraw( + PdfSingleValueField field, + PdfGraphics graphics, + PdfPoint? location, + double scalingX, + double scalingY, + ) { + field._performDraw(graphics, location, scalingX, scalingY); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_static_field.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_static_field.dart index 709ac225b..5830f6846 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_static_field.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_static_field.dart @@ -1,94 +1,94 @@ -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/figures/pdf_template.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/pdf_graphics.dart'; -import 'pdf_automatic_field.dart'; - -/// internal class -abstract class PdfStaticField extends PdfAutomaticField { - // constructor - /// Represents automatic field which value can be evaluated - /// in the moment of creation. - PdfStaticField({PdfFont? font, PdfBrush? brush, Rect? bounds}) { - PdfAutomaticFieldHelper(this).internal(font, brush: brush, bounds: bounds); - } - - // fields - PdfTemplate? _template; - final List _graphicsList = []; - - // implementation - void _performDraw( - PdfGraphics graphics, - PdfPoint? location, - double scalingX, - double scalingY, - ) { - final String? value = PdfAutomaticFieldHelper.getHelper( - this, - ).getValue(graphics); - final Offset drawLocation = Offset( - location!.x + bounds.left, - location.y + bounds.top, - ); - - if (_template == null) { - _template = PdfTemplate( - PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, - PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, - ); - _template!.graphics!.drawString( - value!, - font, - pen: pen, - brush: brush, - bounds: Rect.fromLTWH( - 0, - 0, - PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, - PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, - ), - format: stringFormat, - ); - graphics.drawPdfTemplate( - _template!, - drawLocation, - Size( - _template!.size.width * scalingX, - _template!.size.height * scalingY, - ), - ); - _graphicsList.add(graphics); - } else { - if (!_graphicsList.contains(graphics)) { - graphics.drawPdfTemplate( - _template!, - drawLocation, - Size( - _template!.size.width * scalingX, - _template!.size.height * scalingY, - ), - ); - _graphicsList.add(graphics); - } - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfStaticField] helper -class PdfStaticFieldHelper { - /// internal method - static void performDraw( - PdfStaticField staticField, - PdfGraphics graphics, - PdfPoint? location, - double scalingX, - double scalingY, - ) { - staticField._performDraw(graphics, location, scalingX, scalingY); - } -} +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/figures/pdf_template.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/pdf_graphics.dart'; +import 'pdf_automatic_field.dart'; + +/// internal class +abstract class PdfStaticField extends PdfAutomaticField { + // constructor + /// Represents automatic field which value can be evaluated + /// in the moment of creation. + PdfStaticField({PdfFont? font, PdfBrush? brush, Rect? bounds}) { + PdfAutomaticFieldHelper(this).internal(font, brush: brush, bounds: bounds); + } + + // fields + PdfTemplate? _template; + final List _graphicsList = []; + + // implementation + void _performDraw( + PdfGraphics graphics, + PdfPoint? location, + double scalingX, + double scalingY, + ) { + final String? value = PdfAutomaticFieldHelper.getHelper( + this, + ).getValue(graphics); + final Offset drawLocation = Offset( + location!.x + bounds.left, + location.y + bounds.top, + ); + + if (_template == null) { + _template = PdfTemplate( + PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, + PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, + ); + _template!.graphics!.drawString( + value!, + font, + pen: pen, + brush: brush, + bounds: Rect.fromLTWH( + 0, + 0, + PdfAutomaticFieldHelper.getHelper(this).obtainSize().width, + PdfAutomaticFieldHelper.getHelper(this).obtainSize().height, + ), + format: stringFormat, + ); + graphics.drawPdfTemplate( + _template!, + drawLocation, + Size( + _template!.size.width * scalingX, + _template!.size.height * scalingY, + ), + ); + _graphicsList.add(graphics); + } else { + if (!_graphicsList.contains(graphics)) { + graphics.drawPdfTemplate( + _template!, + drawLocation, + Size( + _template!.size.width * scalingX, + _template!.size.height * scalingY, + ), + ); + _graphicsList.add(graphics); + } + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfStaticField] helper +class PdfStaticFieldHelper { + /// internal method + static void performDraw( + PdfStaticField staticField, + PdfGraphics graphics, + PdfPoint? location, + double scalingX, + double scalingY, + ) { + staticField._performDraw(graphics, location, scalingX, scalingY); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_template_value_pair.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_template_value_pair.dart index 5a5d8b2dc..040618cc3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_template_value_pair.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/automatic_fields/pdf_template_value_pair.dart @@ -1,15 +1,15 @@ -import '../../graphics/figures/pdf_template.dart'; - -/// internal class -class PdfTemplateValuePair { - // constructor - /// internal constructor - PdfTemplateValuePair(this.template, this.value); - - // field - /// internal field - late PdfTemplate template; - - /// internal field - late String value; -} +import '../../graphics/figures/pdf_template.dart'; + +/// internal class +class PdfTemplateValuePair { + // constructor + /// internal constructor + PdfTemplateValuePair(this.template, this.value); + + // field + /// internal field + late PdfTemplate template; + + /// internal field + late String value; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/enums.dart index e20616b36..2768ce07c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/enums.dart @@ -1,110 +1,110 @@ -/// Specifies the available PDF versions to save the PDF document. -enum PdfVersion { - /// PDF version 1.0. - version1_0, - - /// PDF version 1.1. - version1_1, - - /// PDF version 1.2. - version1_2, - - /// PDF version 1.3. Adobe Acrobat 4. - version1_3, - - /// PDF version 1.4. Adobe Acrobat 5. - version1_4, - - /// PDF version 1.5. Adobe Acrobat 6. - version1_5, - - /// PDF version 1.6. Adobe Acrobat 7. - version1_6, - - /// PDF version 1.7. Adobe Acrobat 8. - version1_7, - - /// PDF version 2.0. - version2_0, -} - -/// Specifies the type of the PDF cross-reference. -enum PdfCrossReferenceType { - /// The cross-reference table contains information that permits - /// random access to indirect objects within the file so that the entire file - /// need not be read to locate any particular object. - /// The structure is useful for incremental updates, since it allows - /// a new cross-reference section to be added to the PDF file, - /// containing entries only for objects that have been added or deleted. - /// Cross-reference is represented by cross-reference table. - /// The cross-reference table is the traditional way of representing - /// reference type. - crossReferenceTable, - - /// Cross-reference is represented by cross-reference stream. - /// Cross-reference streams are stream objects, and contain a dictionary - /// and a data stream. This leads to more compact representation of the file - /// data especially along with the compression enabled. - /// This format is supported by PDF 1.5 version and higher only. - crossReferenceStream, -} - -/// Specifies the PDF document's conformance-level. -enum PdfConformanceLevel { - /// Specifies default / no conformance. - none, - - /// This PDF/A ISO standard (ISO 19005-1:2005) is based on Adobe PDF version 1.4 - /// and This Level B conformance indicates minimal compliance to ensure that the - /// rendered visual appearance of a conforming file is preservable over the long term. - a1b, - - /// PDF/A-2 Standard is based on a PDF 1.7 (ISO 32000-1) - /// which provides support for transparency effects and layers - /// embedding of OpenType fonts. - a2b, - - /// PDF/A-3 Standard is based on a PDF 1.7 (ISO 32000-1) - /// which provides support for embedding the arbitrary file - /// formats (XML, CSV, CAD, Word Processing documents). - a3b, -} - -/// Specifies the file relationship of attachment. -enum PdfAttachmentRelationship { - ///The original source material for the associated content - source, - - ///Represents information used to derive a visual presentation - data, - - ///Alternative representation of the PDF contents - alternative, - - ///supplemental representation of the original source or data that may be more easily consumable - supplement, - - ///Relationship is not known or cannot be described using one of the other values - unspecified, -} - -/// Compression level. -enum PdfCompressionLevel { - /// Pack without compression - none, - - /// Use high speed compression, reduce of data size is low - bestSpeed, - - /// Something middle between normal and BestSpeed compressions - belowNormal, - - /// Use normal compression, middle between speed and size - normal, - - /// Pack better but require a little more time - aboveNormal, - - /// Use best compression, slow enough - best, -} +/// Specifies the available PDF versions to save the PDF document. +enum PdfVersion { + /// PDF version 1.0. + version1_0, + + /// PDF version 1.1. + version1_1, + + /// PDF version 1.2. + version1_2, + + /// PDF version 1.3. Adobe Acrobat 4. + version1_3, + + /// PDF version 1.4. Adobe Acrobat 5. + version1_4, + + /// PDF version 1.5. Adobe Acrobat 6. + version1_5, + + /// PDF version 1.6. Adobe Acrobat 7. + version1_6, + + /// PDF version 1.7. Adobe Acrobat 8. + version1_7, + + /// PDF version 2.0. + version2_0, +} + +/// Specifies the type of the PDF cross-reference. +enum PdfCrossReferenceType { + /// The cross-reference table contains information that permits + /// random access to indirect objects within the file so that the entire file + /// need not be read to locate any particular object. + /// The structure is useful for incremental updates, since it allows + /// a new cross-reference section to be added to the PDF file, + /// containing entries only for objects that have been added or deleted. + /// Cross-reference is represented by cross-reference table. + /// The cross-reference table is the traditional way of representing + /// reference type. + crossReferenceTable, + + /// Cross-reference is represented by cross-reference stream. + /// Cross-reference streams are stream objects, and contain a dictionary + /// and a data stream. This leads to more compact representation of the file + /// data especially along with the compression enabled. + /// This format is supported by PDF 1.5 version and higher only. + crossReferenceStream, +} + +/// Specifies the PDF document's conformance-level. +enum PdfConformanceLevel { + /// Specifies default / no conformance. + none, + + /// This PDF/A ISO standard (ISO 19005-1:2005) is based on Adobe PDF version 1.4 + /// and This Level B conformance indicates minimal compliance to ensure that the + /// rendered visual appearance of a conforming file is preservable over the long term. + a1b, + + /// PDF/A-2 Standard is based on a PDF 1.7 (ISO 32000-1) + /// which provides support for transparency effects and layers + /// embedding of OpenType fonts. + a2b, + + /// PDF/A-3 Standard is based on a PDF 1.7 (ISO 32000-1) + /// which provides support for embedding the arbitrary file + /// formats (XML, CSV, CAD, Word Processing documents). + a3b, +} + +/// Specifies the file relationship of attachment. +enum PdfAttachmentRelationship { + ///The original source material for the associated content + source, + + ///Represents information used to derive a visual presentation + data, + + ///Alternative representation of the PDF contents + alternative, + + ///supplemental representation of the original source or data that may be more easily consumable + supplement, + + ///Relationship is not known or cannot be described using one of the other values + unspecified, +} + +/// Compression level. +enum PdfCompressionLevel { + /// Pack without compression + none, + + /// Use high speed compression, reduce of data size is low + bestSpeed, + + /// Something middle between normal and BestSpeed compressions + belowNormal, + + /// Use normal compression, middle between speed and size + normal, + + /// Pack better but require a little more time + aboveNormal, + + /// Use best compression, slow enough + best, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/enums.dart index 5ba384b3e..519513ad7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/enums.dart @@ -1,24 +1,24 @@ -/// Allows to choose outline text style. -/// -/// ```dart -/// //Create a new document. -/// PdfDocument document = PdfDocument(); -/// //Create document bookmarks. -/// document.bookmarks.add('Page 1') -/// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) -/// ..textStyle = [PdfTextStyle.bold]; -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -enum PdfTextStyle { - /// Regular text style. - regular, - - /// Italic text style. - italic, - - /// Bold text style. - bold, -} +/// Allows to choose outline text style. +/// +/// ```dart +/// //Create a new document. +/// PdfDocument document = PdfDocument(); +/// //Create document bookmarks. +/// document.bookmarks.add('Page 1') +/// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) +/// ..textStyle = [PdfTextStyle.bold]; +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +enum PdfTextStyle { + /// Regular text style. + regular, + + /// Italic text style. + italic, + + /// Bold text style. + bold, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/pdf_outline.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/pdf_outline.dart index 0fa9c5b2a..75f531a5a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/pdf_outline.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/outlines/pdf_outline.dart @@ -1,1577 +1,1577 @@ -import 'dart:ui'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../actions/pdf_action.dart'; -import '../../drawing/drawing.dart'; -import '../../general/enum.dart'; -import '../../general/pdf_destination.dart'; -import '../../general/pdf_named_destination.dart'; -import '../../general/pdf_named_destination_collection.dart'; -import '../../graphics/pdf_color.dart'; -import '../../io/pdf_constants.dart'; -import '../../io/pdf_cross_table.dart'; -import '../../pages/pdf_page.dart'; -import '../../pages/pdf_page_collection.dart'; -import '../../pdf_document/pdf_document.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_number.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_string.dart'; -import 'enums.dart'; - -/// Each instance of this class represents an bookmark node -/// in the bookmark tree. -/// -/// ```dart -/// //Create a new document. -/// PdfDocument document = PdfDocument(); -/// //Create document bookmarks. -/// PdfBookmark bookmark = document.bookmarks.add('Page 1') -/// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) -/// ..textStyle = [PdfTextStyle.bold] -/// ..color = PdfColor(255, 0, 0); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfBookmark extends PdfBookmarkBase { - //Constructor - /// Initializes a new instance of the [PdfBookmark] class. - PdfBookmark._internal( - String title, - PdfBookmarkBase parent, - PdfBookmark? previous, - PdfBookmark? next, { - bool isExpanded = false, - PdfColor? color, - PdfDestination? destination, - PdfNamedDestination? namedDestination, - PdfAction? action, - List? textStyle, - }) : super._internal() { - _parent = parent; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.parent, - PdfReferenceHolder(parent), - ); - _previous = previous; - _next = next; - this.title = title; - this.isExpanded = isExpanded; - if (color != null) { - this.color = color; - } - if (destination != null) { - this.destination = destination; - } - if (namedDestination != null) { - this.namedDestination = namedDestination; - } - if (action != null) { - this.action = action; - } - if (textStyle != null) { - this.textStyle = textStyle; - } - } - - PdfBookmark._load(super.dictionary, PdfCrossTable super.crossTable) - : super._load(); - - //Fields - /// Internal variable to store destination. - PdfDestination? _destination; - - /// Internal variable to store named destination. - PdfNamedDestination? _namedDestination; - - /// Internal variable to store text Style. - List _textStyle = [PdfTextStyle.regular]; - - /// Internal variable to store previous. - PdfBookmark? _previousBookmark; - - /// Internal variable to store next. - PdfBookmark? _nextBookmark; - - /// Internal variable to store color. - PdfColor _color = PdfColor(0, 0, 0); - - /// Internal variable to store action. - PdfAction? _action; - - /// Internal variable to store RegExp. - final RegExp _regex = RegExp(r'[\u0080-\u00FF]'); - - /// Internal variable to store byte value. - final List _pdfEncodingByteToChar = [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - 62, - 63, - 64, - 65, - 66, - 67, - 68, - 69, - 70, - 71, - 72, - 73, - 74, - 75, - 76, - 77, - 78, - 79, - 80, - 81, - 82, - 83, - 84, - 85, - 86, - 87, - 88, - 89, - 90, - 91, - 92, - 93, - 94, - 95, - 96, - 97, - 98, - 99, - 100, - 101, - 102, - 103, - 104, - 105, - 106, - 107, - 108, - 109, - 110, - 111, - 112, - 113, - 114, - 115, - 116, - 117, - 118, - 119, - 120, - 121, - 122, - 123, - 124, - 125, - 126, - 127, - 0x2022, - 0x2020, - 0x2021, - 0x2026, - 0x2014, - 0x2013, - 0x0192, - 0x2044, - 0x2039, - 0x203a, - 0x2212, - 0x2030, - 0x201e, - 0x201c, - 0x201d, - 0x2018, - 0x2019, - 0x201a, - 0x2122, - 0xfb01, - 0xfb02, - 0x0141, - 0x0152, - 0x0160, - 0x0178, - 0x017d, - 0x0131, - 0x0142, - 0x0153, - 0x0161, - 0x017e, - 65533, - 0x20ac, - 161, - 162, - 163, - 164, - 165, - 166, - 167, - 168, - 169, - 170, - 171, - 172, - 173, - 174, - 175, - 176, - 177, - 178, - 179, - 180, - 181, - 182, - 183, - 184, - 185, - 186, - 187, - 188, - 189, - 190, - 191, - 192, - 193, - 194, - 195, - 196, - 197, - 198, - 199, - 200, - 201, - 202, - 203, - 204, - 205, - 206, - 207, - 208, - 209, - 210, - 211, - 212, - 213, - 214, - 215, - 216, - 217, - 218, - 219, - 220, - 221, - 222, - 223, - 224, - 225, - 226, - 227, - 228, - 229, - 230, - 231, - 232, - 233, - 234, - 235, - 236, - 237, - 238, - 239, - 240, - 241, - 242, - 243, - 244, - 245, - 246, - 247, - 248, - 249, - 250, - 251, - 252, - 253, - 254, - 255, - ]; - - //Properties - /// Gets or sets the outline destination page. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create document bookmarks. - /// PdfBookmark bookmark = document.bookmarks.add('Page 1') - /// //Set the destination page. - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfDestination? get destination { - if (_isLoadedBookmark) { - PdfDestination? destination; - if (_obtainNamedDestination() == null) { - destination = _obtainDestination(); - } - return destination; - } else { - return _destination; - } - } - - set destination(PdfDestination? value) { - if (value != null) { - _destination = value; - _helper.dictionary!.setProperty(PdfDictionaryProperties.dest, value); - } - } - - /// Gets or sets the named destination in outline. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create a named destination. - /// PdfNamedDestination namedDestination = PdfNamedDestination('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(100, 300)); - /// //Add the named destination - /// document.namedDestinationCollection.add(namedDestination); - /// //Create document bookmarks. - /// document.bookmarks.add('Page 1') - /// //Set the named destination. - /// ..namedDestination = namedDestination - /// ..color = PdfColor(255, 0, 0); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfNamedDestination? get namedDestination { - if (_isLoadedBookmark) { - _namedDestination ??= _obtainNamedDestination(); - return _namedDestination; - } else { - return _namedDestination; - } - } - - set namedDestination(PdfNamedDestination? value) { - if (value != null && _namedDestination != value) { - _namedDestination = value; - final PdfDictionary dictionary = PdfDictionary(); - dictionary.setProperty( - PdfDictionaryProperties.d, - PdfString(_namedDestination!.title), - ); - dictionary.setProperty( - PdfDictionaryProperties.s, - PdfName(PdfDictionaryProperties.goTo), - ); - dictionary.setProperty( - PdfDictionaryProperties.a, - PdfReferenceHolder(dictionary), - ); - } - } - - /// Gets or sets the outline title. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create document bookmarks. - /// document.bookmarks.add('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0) - /// //Set the bookmark title. - /// ..title = 'Bookmark'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String get title { - if (_isLoadedBookmark) { - return _obtainTitle(); - } else { - final PdfString? title = - _helper.dictionary![PdfDictionaryProperties.title] as PdfString?; - if (title != null && title.value != null) { - return title.value!; - } else { - return ''; - } - } - } - - set title(String value) { - _helper.dictionary![PdfDictionaryProperties.title] = PdfString(value); - } - - /// Gets or sets the color of bookmark title. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create document bookmarks. - /// document.bookmarks.add('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0) - /// ..title = 'Bookmark'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfColor get color { - if (_isLoadedBookmark) { - return _obtainColor(); - } else { - return _color; - } - } - - set color(PdfColor value) { - if (_isLoadedBookmark) { - _assignColor(value); - } else { - if (_color != value) { - _color = value; - _updateColor(); - } - } - } - - /// Gets or sets the style of the outline title. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create document bookmarks. - /// document.bookmarks.add('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0) - /// ..title = 'Bookmark'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - List get textStyle { - if (_isLoadedBookmark) { - return [_obtainTextStyle()]; - } else { - return _textStyle; - } - } - - set textStyle(List value) { - if (_isLoadedBookmark) { - _assignTextStyle(value); - } else { - if (_textStyle != value) { - _textStyle = value; - _updateTextStyle(); - } - } - } - - /// Gets or sets the action for the outline. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create document bookmarks. - /// document.bookmarks.add('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0) - /// //Set the bookmark action. - /// ..action = PdfUriAction('http://www.google.com'); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfAction? get action => _action; - set action(PdfAction? value) { - if (value != null && _action != value) { - _action = value; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.a, - PdfReferenceHolder(PdfActionHelper.getHelper(_action!).dictionary), - ); - } - } - - /// Gets or sets whether to expand the node or not. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create document bookmarks. - /// PdfBookmark bookmark = document.bookmarks.add('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0); - /// //Get if is expanded. - /// bool expand = bookmark.isExpanded; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool get isExpanded => super._isExpanded; - set isExpanded(bool value) { - super._isExpanded = value; - } - - PdfBookmark? get _previous { - if (_isLoadedBookmark) { - return _obtainPrevious(); - } else { - return _previousBookmark; - } - } - - set _previous(PdfBookmark? value) { - if (_previousBookmark != value) { - _previousBookmark = value; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.prev, - PdfReferenceHolder(value), - ); - } - } - - /// Gets the next outline object. - PdfBookmark? get _next { - if (_isLoadedBookmark) { - return _obtainNext(); - } else { - return _nextBookmark; - } - } - - /// Sets the next outline object. - set _next(PdfBookmark? value) { - if (_nextBookmark != value) { - _nextBookmark = value; - _helper.dictionary!.setProperty( - PdfDictionaryProperties.next, - PdfReferenceHolder(value), - ); - } - } - - //Implementations - @override - List get _list { - final List list = super._list; - if (_isLoadedBookmark) { - if (list.isEmpty) { - _helper.reproduceTree(); - } - return list; - } else { - return list; - } - } - - void _updateColor() { - final PdfArray? array = - _helper.dictionary![PdfDictionaryProperties.c] as PdfArray?; - if (array != null && _color.isEmpty) { - _helper.dictionary!.remove(PdfDictionaryProperties.c); - } else { - _helper.dictionary![PdfDictionaryProperties.c] = PdfColorHelper.toArray( - _color, - ); - } - } - - /// Updates the outline text style. - void _updateTextStyle() { - if (_textStyle.length == 1 && _textStyle[0] == PdfTextStyle.regular) { - _helper.dictionary!.remove(PdfDictionaryProperties.f); - } else { - int value = 0; - for (int i = 0; i < _textStyle.length; i++) { - value |= _textStyle[i].index; - } - _helper.dictionary![PdfDictionaryProperties.f] = PdfNumber(value); - } - } - - String _obtainTitle() { - String title = ''; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.title)) { - final PdfString? str = - PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.title], - ) - as PdfString?; - if (str != null && str.value != null) { - title = str.value!; - if (_regex.hasMatch(title)) { - for (int i = 0; i < title.length; i++) { - if (_regex.hasMatch(title[i])) { - title = title.replaceAll( - title[i], - String.fromCharCode( - _pdfEncodingByteToChar[title.codeUnitAt(i) & 0xff], - ), - ); - } - } - } - } - } - return title; - } - - PdfColor _obtainColor() { - PdfColor color = PdfColor(0, 0, 0); - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.c)) { - final PdfArray? colours = - PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.c], - ) - as PdfArray?; - if (colours != null && colours.count > 2) { - double? red = 0; - double green = 0; - double blue = 0; - PdfNumber? colorValue = - PdfCrossTable.dereference(colours[0]) as PdfNumber?; - if (colorValue != null) { - red = colorValue.value as double?; - } - colorValue = PdfCrossTable.dereference(colours[1]) as PdfNumber?; - if (colorValue != null) { - green = colorValue.value!.toDouble(); - } - colorValue = PdfCrossTable.dereference(colours[2]) as PdfNumber?; - if (colorValue != null) { - blue = colorValue.value!.toDouble(); - } - color = PdfColor(red!.toInt(), green.toInt(), blue.toInt()); - } - } - return color; - } - - PdfTextStyle _obtainTextStyle() { - PdfTextStyle style = PdfTextStyle.regular; - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.f)) { - final PdfNumber? flag = - PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.f], - ) - as PdfNumber?; - int flagValue = 0; - if (flag != null) { - flagValue = flag.value!.toInt() - 1; - } - style = PdfTextStyle.values.elementAt(flagValue); - } - return style; - } - - PdfBookmark? _obtainNext() { - PdfBookmark? nextBookmark; - int index = _parent!._list.indexOf(this); - ++index; - if (index < _parent!._list.length) { - nextBookmark = _parent!._list[index] as PdfBookmark?; - } else { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.next)) { - final PdfDictionary? next = - _helper._crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.next], - ) - as PdfDictionary?; - nextBookmark = PdfBookmark._load(next, _helper._crossTable); - } - } - return nextBookmark; - } - - PdfBookmark? _obtainPrevious() { - PdfBookmark? prevBookmark; - int index = _helper._bookmarkList.indexOf(this); - --index; - if (index >= 0) { - prevBookmark = _helper._bookmarkList[index] as PdfBookmark?; - } else { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.prev)) { - final PdfDictionary? prev = - _helper._crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.prev], - ) - as PdfDictionary?; - prevBookmark = PdfBookmark._load(prev, _helper._crossTable); - } - } - return prevBookmark; - } - - void _assignColor(PdfColor color) { - final List rgb = [ - color.r.toDouble(), - color.g.toDouble(), - color.b.toDouble(), - ]; - final PdfArray colors = PdfArray(rgb); - _helper.dictionary!.setProperty(PdfDictionaryProperties.c, colors); - } - - void _assignTextStyle(List value) { - for (final PdfTextStyle v in value) { - int style = PdfTextStyle.values.indexOf(_obtainTextStyle()); - style |= PdfTextStyle.values.indexOf(v); - _helper.dictionary!.setNumber(PdfDictionaryProperties.f, style); - } - } - - PdfNamedDestination? _obtainNamedDestination() { - final PdfDocument? loadedDocument = _helper._crossTable.document; - PdfNamedDestinationCollection? namedCollection; - if (loadedDocument != null) { - namedCollection = loadedDocument.namedDestinationCollection; - } - PdfNamedDestination? namedDestination; - IPdfPrimitive? destination; - if (namedCollection != null) { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.a)) { - final PdfDictionary? action = - PdfCrossTable.dereference( - _helper.dictionary![PdfDictionaryProperties.a], - ) - as PdfDictionary?; - if (action != null && action.containsKey(PdfDictionaryProperties.d)) { - destination = PdfCrossTable.dereference( - action[PdfDictionaryProperties.d], - ); - } - } else if (_helper.dictionary!.containsKey( - PdfDictionaryProperties.dest, - )) { - destination = _helper._crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.dest], - ); - } - - if (destination != null) { - final PdfName? name = (destination is PdfName) ? destination : null; - final PdfString? str = (destination is PdfString) ? destination : null; - String? title; - if (name != null) { - title = name.name; - } else if (str != null) { - title = str.value; - } - if (title != null) { - for (int i = 0; i < namedCollection.count; i++) { - final PdfNamedDestination nameDest = namedCollection[i]; - if (nameDest.title == title) { - namedDestination = nameDest; - break; - } - } - } - } - } - return namedDestination; - } - - PdfDestination? _obtainDestination() { - if (_helper.dictionary!.containsKey(PdfDictionaryProperties.dest) && - (_destination == null)) { - final IPdfPrimitive? obj = _helper._crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.dest], - ); - PdfArray? array = obj as PdfArray?; - final PdfName? name = (obj is PdfName) ? obj as PdfName? : null; - final PdfDocument? ldDoc = _helper._crossTable.document; - - if (ldDoc != null) { - if (name != null) { - array = PdfDocumentHelper.getHelper(ldDoc).getNamedDestination(name); - } - } - - if (array != null) { - final IPdfPrimitive? holder = array[0]; - PdfPage? page; - if (holder != null && holder is PdfReferenceHolder) { - final IPdfPrimitive? dic = _helper._crossTable.getObject(holder); - if (ldDoc != null && dic != null && dic is PdfDictionary) { - page = PdfPageCollectionHelper.getHelper(ldDoc.pages).getPage(dic); - } - IPdfPrimitive? mode; - if (array.count > 1) { - mode = array[1]; - } - if (mode != null && mode is PdfName) { - if (mode.name == PdfDictionaryProperties.xyz) { - IPdfPrimitive? left; - IPdfPrimitive? top; - if (array.count > 2) { - left = array[2]; - } - if (array.count > 3) { - top = array[3]; - } - IPdfPrimitive? zoom; - if (array.count > 4) { - zoom = array[4]; - } - if (page != null) { - final double topValue = - (top != null && top is PdfNumber) - ? page.size.height - top.value! - : 0; - final double leftValue = - (left != null && left is PdfNumber) - ? left.value! as double - : 0; - _destination = PdfDestination( - page, - Offset(leftValue, topValue), - ); - _destination!.zoom = - (zoom != null && zoom is PdfNumber) - ? zoom.value!.toDouble() - : 0; - } - } else { - if (mode.name == PdfDictionaryProperties.fitR) { - IPdfPrimitive? left; - IPdfPrimitive? bottom; - IPdfPrimitive? right; - IPdfPrimitive? top; - if (array.count > 2) { - left = array[2]; - } - if (array.count > 3) { - bottom = array[3]; - } - if (array.count > 4) { - right = array[4]; - } - if (array.count > 5) { - top = array[5]; - } - if (page != null) { - _destination = PdfDestinationHelper.getDestination( - page, - PdfRectangle( - (left != null && left is PdfNumber) - ? left.value!.toDouble() - : 0, - (bottom != null && bottom is PdfNumber) - ? bottom.value!.toDouble() - : 0, - (right != null && right is PdfNumber) - ? right.value!.toDouble() - : 0, - (top != null && top is PdfNumber) - ? top.value!.toDouble() - : 0, - ), - ); - _destination!.mode = PdfDestinationMode.fitR; - } - } else if (mode.name == PdfDictionaryProperties.fitBH || - mode.name == PdfDictionaryProperties.fitH) { - IPdfPrimitive? top; - if (array.count >= 3) { - top = array[2]; - } - if (page != null) { - final double topValue = - (top != null && top is PdfNumber) - ? page.size.height - top.value! - : 0; - _destination = PdfDestination(page, Offset(0, topValue)); - _destination!.mode = PdfDestinationMode.fitH; - } - } else { - if (page != null && mode.name == PdfDictionaryProperties.fit) { - _destination = PdfDestination(page); - _destination!.mode = PdfDestinationMode.fitToPage; - } - } - } - } else { - if (page != null) { - _destination = PdfDestination(page); - _destination!.mode = PdfDestinationMode.fitToPage; - } - } - } - } - } else if (_helper.dictionary!.containsKey(PdfDictionaryProperties.a) && - (_destination == null)) { - IPdfPrimitive? obj = _helper._crossTable.getObject( - _helper.dictionary![PdfDictionaryProperties.a], - ); - PdfDictionary? destDic; - if (obj is PdfDictionary) { - destDic = obj; - } - if (destDic != null) { - obj = destDic[PdfDictionaryProperties.d]; - } - if (obj is PdfReferenceHolder) { - obj = obj.object; - } - PdfArray? array = (obj is PdfArray) ? obj : null; - final PdfName? name = (obj is PdfName) ? obj : null; - final PdfDocument? ldDoc = _helper._crossTable.document; - if (ldDoc != null) { - if (name != null) { - array = PdfDocumentHelper.getHelper(ldDoc).getNamedDestination(name); - } - } - if (array != null) { - final IPdfPrimitive? holder = array[0]; - PdfPage? page; - if (holder != null && holder is PdfReferenceHolder) { - final IPdfPrimitive? dic = _helper._crossTable.getObject(holder); - if (dic != null && ldDoc != null && dic is PdfDictionary) { - page = PdfPageCollectionHelper.getHelper(ldDoc.pages).getPage(dic); - } - } - IPdfPrimitive? mode; - if (array.count > 1) { - mode = array[1]; - } - if (mode != null && mode is PdfName) { - if (mode.name == PdfDictionaryProperties.fitBH || - mode.name == PdfDictionaryProperties.fitH) { - IPdfPrimitive? top; - if (array.count >= 3) { - top = array[2]; - } - if (page != null) { - final double topValue = - (top != null && top is PdfNumber) - ? page.size.height - top.value! - : 0; - _destination = PdfDestination(page, Offset(0, topValue)); - _destination!.mode = PdfDestinationMode.fitH; - } - } else if (mode.name == PdfDictionaryProperties.xyz) { - IPdfPrimitive? left; - IPdfPrimitive? top; - if (array.count > 2) { - left = array[2]; - } - if (array.count > 3) { - top = array[3]; - } - IPdfPrimitive? zoom; - if (array.count > 4) { - zoom = array[4]; - } - if (page != null) { - final double topValue = - (top != null && top is PdfNumber) - ? page.size.height - top.value! - : 0; - final double leftValue = - (left != null && left is PdfNumber) - ? left.value! as double - : 0; - _destination = PdfDestination(page, Offset(leftValue, topValue)); - _destination!.zoom = - (zoom != null && zoom is PdfNumber) - ? zoom.value!.toDouble() - : 0; - } - } else { - if (page != null && mode.name == PdfDictionaryProperties.fit) { - _destination = PdfDestination(page); - _destination!.mode = PdfDestinationMode.fitToPage; - } - } - } else { - if (page != null) { - _destination = PdfDestination(page); - _destination!.mode = PdfDestinationMode.fitToPage; - } - } - } - } - return _destination; - } -} - -/// This class plays two roles: it's a base class for all bookmarks -/// and it's a root of a bookmarks tree. -/// -/// ```dart -/// //Load the PDF document. -/// PdfDocument document = PdfDocument(inputBytes: inputBytes); -/// //Get the bookmark from index. -/// PdfBookmark bookmarks = document.bookmarks[0] -/// ..destination = PdfDestination(document.pages[1]) -/// ..color = PdfColor(0, 255, 0) -/// ..textStyle = [PdfTextStyle.bold] -/// ..title = 'Changed title'; -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfBookmarkBase implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [PdfBookmarkBase] class. - PdfBookmarkBase._internal() : super() { - _helper = PdfBookmarkBaseHelper(this); - } - - PdfBookmarkBase._load(PdfDictionary? dictionary, PdfCrossTable? crossTable) { - _helper = PdfBookmarkBaseHelper(this); - _isLoadedBookmark = true; - _helper.dictionary = dictionary; - if (crossTable != null) { - _helper._crossTable = crossTable; - } - } - - //Fields - late PdfBookmarkBaseHelper _helper; - - /// Internal variable to store parent. - PdfBookmarkBase? _parent; - - /// Internal variable to store loaded bookmark. - List? _bookmark; - - /// Whether the bookmark tree is expanded or not - bool _expanded = false; - List? _booklist; - bool _isLoadedBookmark = false; - - //Properties - /// Gets number of the elements in the collection. Read-Only. - /// - /// ```dart - /// //Load the PDF document. - /// PdfDocument document = PdfDocument(inputBytes: inputBytes); - /// //get the bookmark count. - /// int count = document.bookmarks.count; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get count { - final PdfDocument? document = _helper._crossTable.document; - if (document != null) { - if (_booklist == null) { - _booklist = []; - for (int n = 0; n < _list.length; n++) { - _booklist!.add(_list[n]); - } - } - return _list.length; - } else { - return _list.length; - } - } - - /// Gets the bookmark at specified index. - /// - /// ```dart - /// //Load the PDF document. - /// PdfDocument document = PdfDocument(inputBytes: inputBytes); - /// //Get the bookmark from index. - /// PdfBookmark bookmarks = document.bookmarks[0] - /// ..destination = PdfDestination(document.pages[1]) - /// ..color = PdfColor(0, 255, 0) - /// ..textStyle = [PdfTextStyle.bold] - /// ..title = 'Changed title'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBookmark operator [](int index) { - if (index < 0 || index >= count) { - throw RangeError('index'); - } - return _list[index] as PdfBookmark; - } - - /// Gets whether to expand the node or not - bool get _isExpanded { - if (_helper.dictionary!.containsKey('Count')) { - final PdfNumber number = - _helper.dictionary![PdfDictionaryProperties.count]! as PdfNumber; - return !(number.value! < 0); - } else { - return _expanded; - } - } - - /// Sets whether to expand the node or not - set _isExpanded(bool value) { - _expanded = value; - if (count > 0) { - final int newCount = _expanded ? _list.length : -_list.length; - _helper.dictionary![PdfDictionaryProperties.count] = PdfNumber(newCount); - } - } - - //Public methods - /// Adds the bookmark from the document. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Add bookmarks to the document. - /// document.bookmarks.add('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBookmark add( - String title, { - bool isExpanded = false, - PdfColor? color, - PdfDestination? destination, - PdfNamedDestination? namedDestination, - PdfAction? action, - List? textStyle, - }) { - final PdfBookmark? previous = (count < 1) ? null : this[count - 1]; - final PdfBookmark outline = PdfBookmark._internal( - title, - this, - previous, - null, - ); - if (previous != null) { - previous._next = outline; - } - _list.add(outline); - _updateFields(); - return outline; - } - - /// Determines whether the specified outline presents in the collection. - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Add bookmarks to the document. - /// PdfBookmark bookmark = document.bookmarks.add('Page 1') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)); - /// //check whether the specified bookmark present in the collection - /// bool contains = document.bookmarks.contains(bookmark); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool contains(PdfBookmark outline) { - return _list.contains(outline); - } - - /// Remove the specified bookmark from the document. - /// - /// ```dart - /// //Load the PDF document. - /// PdfDocument document = PdfDocument(inputBytes: inputBytes); - /// //Get all the bookmarks. - /// PdfBookmarkBase bookmarks = document.bookmarks; - /// //Remove specified bookmark. - /// bookmarks.remove('bookmark'); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void remove(String title) { - int index = -1; - if (_bookmark == null || _bookmark!.length < _list.length) { - _bookmark = []; - for (int n = 0; n < _list.length; n++) { - if (_list[n] is PdfBookmark) { - _bookmark!.add(_list[n] as PdfBookmark); - } - } - } - for (int c = 0; c < _bookmark!.length; c++) { - final PdfBookmark pdfbookmark = _bookmark![c]; - if (pdfbookmark.title == title) { - index = c; - break; - } - } - removeAt(index); - } - - /// Remove the bookmark from the document at the specified index. - /// - /// ```dart - /// //Load the PDF document. - /// PdfDocument document = PdfDocument(inputBytes: inputBytes); - /// //Remove specified bookmark using index. - /// document.bookmarks.removeAt(0); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void removeAt(int index) { - if (_bookmark == null || _bookmark!.length < _list.length) { - _bookmark = []; - for (int n = 0; n < _list.length; n++) { - if (_list[n] is PdfBookmark?) { - _bookmark!.add(_list[n] as PdfBookmark); - } - } - } - if (index < 0 || index >= _bookmark!.length) { - throw RangeError.value(index); - } - final PdfBookmark current = _bookmark![index]; - if (index == 0) { - if (current._helper.dictionary!.containsKey( - PdfDictionaryProperties.next, - )) { - _helper.dictionary!.setProperty( - PdfDictionaryProperties.first, - current._helper.dictionary![PdfDictionaryProperties.next], - ); - } else { - _helper.dictionary!.remove(PdfDictionaryProperties.first); - _helper.dictionary!.remove(PdfDictionaryProperties.last); - } - } else if ((current._parent != null) && - (current._previous != null) && - (current._next != null)) { - current._previous!._helper.dictionary!.setProperty( - PdfDictionaryProperties.next, - current._helper.dictionary![PdfDictionaryProperties.next], - ); - current._next!._helper.dictionary!.setProperty( - PdfDictionaryProperties.prev, - current._helper.dictionary![PdfDictionaryProperties.prev], - ); - } else if ((current._parent != null) && - (current._previous != null) && - (current._next == null)) { - current._previous!._helper.dictionary!.remove( - PdfDictionaryProperties.next, - ); - current._parent!._helper.dictionary!.setProperty( - PdfDictionaryProperties.last, - current._helper.dictionary![PdfDictionaryProperties.prev], - ); - } - if (current._parent != null) { - current._parent!._list.remove(current); - } - _bookmark!.clear(); - _updateFields(); - } - - /// Removes all the bookmark from the collection. - /// - /// ```dart - /// //Load the PDF document. - /// PdfDocument document = PdfDocument(inputBytes: inputBytes); - /// //Clear all the bookmarks. - /// document.bookmarks.clear(); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void clear() { - _list.clear(); - if (_bookmark != null) { - _bookmark!.clear(); - } - if (_booklist != null) { - _booklist!.clear(); - } - _updateFields(); - } - - /// Inserts a new outline at the specified index. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Insert bookmark at specified index - /// document.bookmarks.insert(0, 'bookmark') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBookmark insert(int index, String title) { - if (index < 0 || index > count) { - throw RangeError.value(index); - } - PdfBookmark outline; - if (index == count) { - outline = add(title); - } else { - final PdfBookmark next = this[index]; - final PdfBookmark? prevoius = (index == 0) ? null : this[index - 1]; - outline = PdfBookmark._internal(title, this, prevoius, next); - _list.insert(index, outline); - if (prevoius != null) { - prevoius._next = outline; - } - next._previous = outline; - _updateFields(); - } - return outline; - } - - //Implementations - /// Updates all outline dictionary fields. - void _updateFields() { - if (count > 0) { - final int newCount = _isExpanded ? _list.length : -_list.length; - _helper.dictionary![PdfDictionaryProperties.count] = PdfNumber(newCount); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.first, - PdfReferenceHolder(this[0]), - ); - _helper.dictionary!.setProperty( - PdfDictionaryProperties.last, - PdfReferenceHolder(this[count - 1]), - ); - } else { - _helper.dictionary!.clear(); - } - } - - /// internal method - List get _list { - return _helper._bookmarkList; - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfBookmark] helper -class PdfBookmarkHelper { - /// internal method - static PdfBookmark internal( - String title, - PdfBookmarkBase parent, - PdfBookmark? previous, - PdfBookmark? next, { - bool isExpanded = false, - PdfColor? color, - PdfDestination? destination, - PdfNamedDestination? namedDestination, - PdfAction? action, - List? textStyle, - }) { - return PdfBookmark._internal( - title, - parent, - previous, - next, - isExpanded: isExpanded, - color: color, - destination: destination, - namedDestination: namedDestination, - action: action, - textStyle: textStyle, - ); - } - - /// internal method - static PdfBookmark load(PdfDictionary? dictionary, PdfCrossTable crossTable) { - return PdfBookmark._load(dictionary, crossTable); - } - - /// internal method - static PdfBookmarkBase? getParent(PdfBookmark bookmark) { - return bookmark._parent; - } - - /// internal method - static void setParent(PdfBookmark bookmark, PdfBookmarkBase? base) { - bookmark._parent = base; - } -} - -/// [PdfBookmarkBase] helper -class PdfBookmarkBaseHelper { - /// internal field - PdfBookmarkBaseHelper(this.base); - - /// internal constructor - PdfBookmarkBase base; - - final List _bookmarkList = []; - PdfCrossTable _crossTable = PdfCrossTable(); - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - /// internal method - static PdfBookmarkBaseHelper getHelper(PdfBookmarkBase bookmark) { - return bookmark._helper; - } - - /// internal method - static PdfBookmarkBase loadInternal() { - return PdfBookmarkBase._internal(); - } - - /// internal method - static PdfBookmarkBase loaded( - PdfDictionary? dictionary, - PdfCrossTable crossTable, - ) { - return PdfBookmarkBase._load(dictionary, crossTable); - } - - /// internal method - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - /// internal method - void reproduceTree() { - PdfBookmark? currentBookmark = _getFirstBookMark(base); - bool isBookmark = currentBookmark != null; - while (isBookmark && - PdfBookmarkBaseHelper(currentBookmark!).dictionary != null) { - PdfBookmarkHelper.setParent(currentBookmark, base); - _bookmarkList.add(currentBookmark); - currentBookmark = currentBookmark._next; - isBookmark = currentBookmark != null; - } - } - - PdfBookmark? _getFirstBookMark(PdfBookmarkBase bookmark) { - PdfBookmark? firstBookmark; - final PdfDictionary dictionary = - PdfBookmarkBaseHelper.getHelper(bookmark).dictionary!; - if (dictionary.containsKey(PdfDictionaryProperties.first)) { - final PdfDictionary? first = - _crossTable.getObject(dictionary[PdfDictionaryProperties.first]) - as PdfDictionary?; - firstBookmark = PdfBookmark._load(first, _crossTable); - } - return firstBookmark; - } - - /// internal method - static List getList(PdfBookmarkBase bookmark) { - return bookmark._list; - } -} - -/// internal class -class CurrentNodeInfo { - /// internal constructor - CurrentNodeInfo(this.kids, [int? index]) { - this.index = index ?? 0; - } - //Fields - /// internal field - late List kids; - - /// internal field - late int index; -} +import 'dart:ui'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../actions/pdf_action.dart'; +import '../../drawing/drawing.dart'; +import '../../general/enum.dart'; +import '../../general/pdf_destination.dart'; +import '../../general/pdf_named_destination.dart'; +import '../../general/pdf_named_destination_collection.dart'; +import '../../graphics/pdf_color.dart'; +import '../../io/pdf_constants.dart'; +import '../../io/pdf_cross_table.dart'; +import '../../pages/pdf_page.dart'; +import '../../pages/pdf_page_collection.dart'; +import '../../pdf_document/pdf_document.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_number.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_string.dart'; +import 'enums.dart'; + +/// Each instance of this class represents an bookmark node +/// in the bookmark tree. +/// +/// ```dart +/// //Create a new document. +/// PdfDocument document = PdfDocument(); +/// //Create document bookmarks. +/// PdfBookmark bookmark = document.bookmarks.add('Page 1') +/// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) +/// ..textStyle = [PdfTextStyle.bold] +/// ..color = PdfColor(255, 0, 0); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfBookmark extends PdfBookmarkBase { + //Constructor + /// Initializes a new instance of the [PdfBookmark] class. + PdfBookmark._internal( + String title, + PdfBookmarkBase parent, + PdfBookmark? previous, + PdfBookmark? next, { + bool isExpanded = false, + PdfColor? color, + PdfDestination? destination, + PdfNamedDestination? namedDestination, + PdfAction? action, + List? textStyle, + }) : super._internal() { + _parent = parent; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.parent, + PdfReferenceHolder(parent), + ); + _previous = previous; + _next = next; + this.title = title; + this.isExpanded = isExpanded; + if (color != null) { + this.color = color; + } + if (destination != null) { + this.destination = destination; + } + if (namedDestination != null) { + this.namedDestination = namedDestination; + } + if (action != null) { + this.action = action; + } + if (textStyle != null) { + this.textStyle = textStyle; + } + } + + PdfBookmark._load(super.dictionary, PdfCrossTable super.crossTable) + : super._load(); + + //Fields + /// Internal variable to store destination. + PdfDestination? _destination; + + /// Internal variable to store named destination. + PdfNamedDestination? _namedDestination; + + /// Internal variable to store text Style. + List _textStyle = [PdfTextStyle.regular]; + + /// Internal variable to store previous. + PdfBookmark? _previousBookmark; + + /// Internal variable to store next. + PdfBookmark? _nextBookmark; + + /// Internal variable to store color. + PdfColor _color = PdfColor(0, 0, 0); + + /// Internal variable to store action. + PdfAction? _action; + + /// Internal variable to store RegExp. + final RegExp _regex = RegExp(r'[\u0080-\u00FF]'); + + /// Internal variable to store byte value. + final List _pdfEncodingByteToChar = [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 0x2022, + 0x2020, + 0x2021, + 0x2026, + 0x2014, + 0x2013, + 0x0192, + 0x2044, + 0x2039, + 0x203a, + 0x2212, + 0x2030, + 0x201e, + 0x201c, + 0x201d, + 0x2018, + 0x2019, + 0x201a, + 0x2122, + 0xfb01, + 0xfb02, + 0x0141, + 0x0152, + 0x0160, + 0x0178, + 0x017d, + 0x0131, + 0x0142, + 0x0153, + 0x0161, + 0x017e, + 65533, + 0x20ac, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + ]; + + //Properties + /// Gets or sets the outline destination page. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create document bookmarks. + /// PdfBookmark bookmark = document.bookmarks.add('Page 1') + /// //Set the destination page. + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfDestination? get destination { + if (_isLoadedBookmark) { + PdfDestination? destination; + if (_obtainNamedDestination() == null) { + destination = _obtainDestination(); + } + return destination; + } else { + return _destination; + } + } + + set destination(PdfDestination? value) { + if (value != null) { + _destination = value; + _helper.dictionary!.setProperty(PdfDictionaryProperties.dest, value); + } + } + + /// Gets or sets the named destination in outline. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create a named destination. + /// PdfNamedDestination namedDestination = PdfNamedDestination('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(100, 300)); + /// //Add the named destination + /// document.namedDestinationCollection.add(namedDestination); + /// //Create document bookmarks. + /// document.bookmarks.add('Page 1') + /// //Set the named destination. + /// ..namedDestination = namedDestination + /// ..color = PdfColor(255, 0, 0); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfNamedDestination? get namedDestination { + if (_isLoadedBookmark) { + _namedDestination ??= _obtainNamedDestination(); + return _namedDestination; + } else { + return _namedDestination; + } + } + + set namedDestination(PdfNamedDestination? value) { + if (value != null && _namedDestination != value) { + _namedDestination = value; + final PdfDictionary dictionary = PdfDictionary(); + dictionary.setProperty( + PdfDictionaryProperties.d, + PdfString(_namedDestination!.title), + ); + dictionary.setProperty( + PdfDictionaryProperties.s, + PdfName(PdfDictionaryProperties.goTo), + ); + dictionary.setProperty( + PdfDictionaryProperties.a, + PdfReferenceHolder(dictionary), + ); + } + } + + /// Gets or sets the outline title. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create document bookmarks. + /// document.bookmarks.add('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0) + /// //Set the bookmark title. + /// ..title = 'Bookmark'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String get title { + if (_isLoadedBookmark) { + return _obtainTitle(); + } else { + final PdfString? title = + _helper.dictionary![PdfDictionaryProperties.title] as PdfString?; + if (title != null && title.value != null) { + return title.value!; + } else { + return ''; + } + } + } + + set title(String value) { + _helper.dictionary![PdfDictionaryProperties.title] = PdfString(value); + } + + /// Gets or sets the color of bookmark title. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create document bookmarks. + /// document.bookmarks.add('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0) + /// ..title = 'Bookmark'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfColor get color { + if (_isLoadedBookmark) { + return _obtainColor(); + } else { + return _color; + } + } + + set color(PdfColor value) { + if (_isLoadedBookmark) { + _assignColor(value); + } else { + if (_color != value) { + _color = value; + _updateColor(); + } + } + } + + /// Gets or sets the style of the outline title. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create document bookmarks. + /// document.bookmarks.add('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0) + /// ..title = 'Bookmark'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + List get textStyle { + if (_isLoadedBookmark) { + return [_obtainTextStyle()]; + } else { + return _textStyle; + } + } + + set textStyle(List value) { + if (_isLoadedBookmark) { + _assignTextStyle(value); + } else { + if (_textStyle != value) { + _textStyle = value; + _updateTextStyle(); + } + } + } + + /// Gets or sets the action for the outline. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create document bookmarks. + /// document.bookmarks.add('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0) + /// //Set the bookmark action. + /// ..action = PdfUriAction('http://www.google.com'); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfAction? get action => _action; + set action(PdfAction? value) { + if (value != null && _action != value) { + _action = value; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.a, + PdfReferenceHolder(PdfActionHelper.getHelper(_action!).dictionary), + ); + } + } + + /// Gets or sets whether to expand the node or not. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create document bookmarks. + /// PdfBookmark bookmark = document.bookmarks.add('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0); + /// //Get if is expanded. + /// bool expand = bookmark.isExpanded; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool get isExpanded => super._isExpanded; + set isExpanded(bool value) { + super._isExpanded = value; + } + + PdfBookmark? get _previous { + if (_isLoadedBookmark) { + return _obtainPrevious(); + } else { + return _previousBookmark; + } + } + + set _previous(PdfBookmark? value) { + if (_previousBookmark != value) { + _previousBookmark = value; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.prev, + PdfReferenceHolder(value), + ); + } + } + + /// Gets the next outline object. + PdfBookmark? get _next { + if (_isLoadedBookmark) { + return _obtainNext(); + } else { + return _nextBookmark; + } + } + + /// Sets the next outline object. + set _next(PdfBookmark? value) { + if (_nextBookmark != value) { + _nextBookmark = value; + _helper.dictionary!.setProperty( + PdfDictionaryProperties.next, + PdfReferenceHolder(value), + ); + } + } + + //Implementations + @override + List get _list { + final List list = super._list; + if (_isLoadedBookmark) { + if (list.isEmpty) { + _helper.reproduceTree(); + } + return list; + } else { + return list; + } + } + + void _updateColor() { + final PdfArray? array = + _helper.dictionary![PdfDictionaryProperties.c] as PdfArray?; + if (array != null && _color.isEmpty) { + _helper.dictionary!.remove(PdfDictionaryProperties.c); + } else { + _helper.dictionary![PdfDictionaryProperties.c] = PdfColorHelper.toArray( + _color, + ); + } + } + + /// Updates the outline text style. + void _updateTextStyle() { + if (_textStyle.length == 1 && _textStyle[0] == PdfTextStyle.regular) { + _helper.dictionary!.remove(PdfDictionaryProperties.f); + } else { + int value = 0; + for (int i = 0; i < _textStyle.length; i++) { + value |= _textStyle[i].index; + } + _helper.dictionary![PdfDictionaryProperties.f] = PdfNumber(value); + } + } + + String _obtainTitle() { + String title = ''; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.title)) { + final PdfString? str = + PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.title], + ) + as PdfString?; + if (str != null && str.value != null) { + title = str.value!; + if (_regex.hasMatch(title)) { + for (int i = 0; i < title.length; i++) { + if (_regex.hasMatch(title[i])) { + title = title.replaceAll( + title[i], + String.fromCharCode( + _pdfEncodingByteToChar[title.codeUnitAt(i) & 0xff], + ), + ); + } + } + } + } + } + return title; + } + + PdfColor _obtainColor() { + PdfColor color = PdfColor(0, 0, 0); + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.c)) { + final PdfArray? colours = + PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.c], + ) + as PdfArray?; + if (colours != null && colours.count > 2) { + double? red = 0; + double green = 0; + double blue = 0; + PdfNumber? colorValue = + PdfCrossTable.dereference(colours[0]) as PdfNumber?; + if (colorValue != null) { + red = colorValue.value as double?; + } + colorValue = PdfCrossTable.dereference(colours[1]) as PdfNumber?; + if (colorValue != null) { + green = colorValue.value!.toDouble(); + } + colorValue = PdfCrossTable.dereference(colours[2]) as PdfNumber?; + if (colorValue != null) { + blue = colorValue.value!.toDouble(); + } + color = PdfColor(red!.toInt(), green.toInt(), blue.toInt()); + } + } + return color; + } + + PdfTextStyle _obtainTextStyle() { + PdfTextStyle style = PdfTextStyle.regular; + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.f)) { + final PdfNumber? flag = + PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.f], + ) + as PdfNumber?; + int flagValue = 0; + if (flag != null) { + flagValue = flag.value!.toInt() - 1; + } + style = PdfTextStyle.values.elementAt(flagValue); + } + return style; + } + + PdfBookmark? _obtainNext() { + PdfBookmark? nextBookmark; + int index = _parent!._list.indexOf(this); + ++index; + if (index < _parent!._list.length) { + nextBookmark = _parent!._list[index] as PdfBookmark?; + } else { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.next)) { + final PdfDictionary? next = + _helper._crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.next], + ) + as PdfDictionary?; + nextBookmark = PdfBookmark._load(next, _helper._crossTable); + } + } + return nextBookmark; + } + + PdfBookmark? _obtainPrevious() { + PdfBookmark? prevBookmark; + int index = _helper._bookmarkList.indexOf(this); + --index; + if (index >= 0) { + prevBookmark = _helper._bookmarkList[index] as PdfBookmark?; + } else { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.prev)) { + final PdfDictionary? prev = + _helper._crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.prev], + ) + as PdfDictionary?; + prevBookmark = PdfBookmark._load(prev, _helper._crossTable); + } + } + return prevBookmark; + } + + void _assignColor(PdfColor color) { + final List rgb = [ + color.r.toDouble(), + color.g.toDouble(), + color.b.toDouble(), + ]; + final PdfArray colors = PdfArray(rgb); + _helper.dictionary!.setProperty(PdfDictionaryProperties.c, colors); + } + + void _assignTextStyle(List value) { + for (final PdfTextStyle v in value) { + int style = PdfTextStyle.values.indexOf(_obtainTextStyle()); + style |= PdfTextStyle.values.indexOf(v); + _helper.dictionary!.setNumber(PdfDictionaryProperties.f, style); + } + } + + PdfNamedDestination? _obtainNamedDestination() { + final PdfDocument? loadedDocument = _helper._crossTable.document; + PdfNamedDestinationCollection? namedCollection; + if (loadedDocument != null) { + namedCollection = loadedDocument.namedDestinationCollection; + } + PdfNamedDestination? namedDestination; + IPdfPrimitive? destination; + if (namedCollection != null) { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.a)) { + final PdfDictionary? action = + PdfCrossTable.dereference( + _helper.dictionary![PdfDictionaryProperties.a], + ) + as PdfDictionary?; + if (action != null && action.containsKey(PdfDictionaryProperties.d)) { + destination = PdfCrossTable.dereference( + action[PdfDictionaryProperties.d], + ); + } + } else if (_helper.dictionary!.containsKey( + PdfDictionaryProperties.dest, + )) { + destination = _helper._crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.dest], + ); + } + + if (destination != null) { + final PdfName? name = (destination is PdfName) ? destination : null; + final PdfString? str = (destination is PdfString) ? destination : null; + String? title; + if (name != null) { + title = name.name; + } else if (str != null) { + title = str.value; + } + if (title != null) { + for (int i = 0; i < namedCollection.count; i++) { + final PdfNamedDestination nameDest = namedCollection[i]; + if (nameDest.title == title) { + namedDestination = nameDest; + break; + } + } + } + } + } + return namedDestination; + } + + PdfDestination? _obtainDestination() { + if (_helper.dictionary!.containsKey(PdfDictionaryProperties.dest) && + (_destination == null)) { + final IPdfPrimitive? obj = _helper._crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.dest], + ); + PdfArray? array = obj as PdfArray?; + final PdfName? name = (obj is PdfName) ? obj as PdfName? : null; + final PdfDocument? ldDoc = _helper._crossTable.document; + + if (ldDoc != null) { + if (name != null) { + array = PdfDocumentHelper.getHelper(ldDoc).getNamedDestination(name); + } + } + + if (array != null) { + final IPdfPrimitive? holder = array[0]; + PdfPage? page; + if (holder != null && holder is PdfReferenceHolder) { + final IPdfPrimitive? dic = _helper._crossTable.getObject(holder); + if (ldDoc != null && dic != null && dic is PdfDictionary) { + page = PdfPageCollectionHelper.getHelper(ldDoc.pages).getPage(dic); + } + IPdfPrimitive? mode; + if (array.count > 1) { + mode = array[1]; + } + if (mode != null && mode is PdfName) { + if (mode.name == PdfDictionaryProperties.xyz) { + IPdfPrimitive? left; + IPdfPrimitive? top; + if (array.count > 2) { + left = array[2]; + } + if (array.count > 3) { + top = array[3]; + } + IPdfPrimitive? zoom; + if (array.count > 4) { + zoom = array[4]; + } + if (page != null) { + final double topValue = + (top != null && top is PdfNumber) + ? page.size.height - top.value! + : 0; + final double leftValue = + (left != null && left is PdfNumber) + ? left.value! as double + : 0; + _destination = PdfDestination( + page, + Offset(leftValue, topValue), + ); + _destination!.zoom = + (zoom != null && zoom is PdfNumber) + ? zoom.value!.toDouble() + : 0; + } + } else { + if (mode.name == PdfDictionaryProperties.fitR) { + IPdfPrimitive? left; + IPdfPrimitive? bottom; + IPdfPrimitive? right; + IPdfPrimitive? top; + if (array.count > 2) { + left = array[2]; + } + if (array.count > 3) { + bottom = array[3]; + } + if (array.count > 4) { + right = array[4]; + } + if (array.count > 5) { + top = array[5]; + } + if (page != null) { + _destination = PdfDestinationHelper.getDestination( + page, + PdfRectangle( + (left != null && left is PdfNumber) + ? left.value!.toDouble() + : 0, + (bottom != null && bottom is PdfNumber) + ? bottom.value!.toDouble() + : 0, + (right != null && right is PdfNumber) + ? right.value!.toDouble() + : 0, + (top != null && top is PdfNumber) + ? top.value!.toDouble() + : 0, + ), + ); + _destination!.mode = PdfDestinationMode.fitR; + } + } else if (mode.name == PdfDictionaryProperties.fitBH || + mode.name == PdfDictionaryProperties.fitH) { + IPdfPrimitive? top; + if (array.count >= 3) { + top = array[2]; + } + if (page != null) { + final double topValue = + (top != null && top is PdfNumber) + ? page.size.height - top.value! + : 0; + _destination = PdfDestination(page, Offset(0, topValue)); + _destination!.mode = PdfDestinationMode.fitH; + } + } else { + if (page != null && mode.name == PdfDictionaryProperties.fit) { + _destination = PdfDestination(page); + _destination!.mode = PdfDestinationMode.fitToPage; + } + } + } + } else { + if (page != null) { + _destination = PdfDestination(page); + _destination!.mode = PdfDestinationMode.fitToPage; + } + } + } + } + } else if (_helper.dictionary!.containsKey(PdfDictionaryProperties.a) && + (_destination == null)) { + IPdfPrimitive? obj = _helper._crossTable.getObject( + _helper.dictionary![PdfDictionaryProperties.a], + ); + PdfDictionary? destDic; + if (obj is PdfDictionary) { + destDic = obj; + } + if (destDic != null) { + obj = destDic[PdfDictionaryProperties.d]; + } + if (obj is PdfReferenceHolder) { + obj = obj.object; + } + PdfArray? array = (obj is PdfArray) ? obj : null; + final PdfName? name = (obj is PdfName) ? obj : null; + final PdfDocument? ldDoc = _helper._crossTable.document; + if (ldDoc != null) { + if (name != null) { + array = PdfDocumentHelper.getHelper(ldDoc).getNamedDestination(name); + } + } + if (array != null) { + final IPdfPrimitive? holder = array[0]; + PdfPage? page; + if (holder != null && holder is PdfReferenceHolder) { + final IPdfPrimitive? dic = _helper._crossTable.getObject(holder); + if (dic != null && ldDoc != null && dic is PdfDictionary) { + page = PdfPageCollectionHelper.getHelper(ldDoc.pages).getPage(dic); + } + } + IPdfPrimitive? mode; + if (array.count > 1) { + mode = array[1]; + } + if (mode != null && mode is PdfName) { + if (mode.name == PdfDictionaryProperties.fitBH || + mode.name == PdfDictionaryProperties.fitH) { + IPdfPrimitive? top; + if (array.count >= 3) { + top = array[2]; + } + if (page != null) { + final double topValue = + (top != null && top is PdfNumber) + ? page.size.height - top.value! + : 0; + _destination = PdfDestination(page, Offset(0, topValue)); + _destination!.mode = PdfDestinationMode.fitH; + } + } else if (mode.name == PdfDictionaryProperties.xyz) { + IPdfPrimitive? left; + IPdfPrimitive? top; + if (array.count > 2) { + left = array[2]; + } + if (array.count > 3) { + top = array[3]; + } + IPdfPrimitive? zoom; + if (array.count > 4) { + zoom = array[4]; + } + if (page != null) { + final double topValue = + (top != null && top is PdfNumber) + ? page.size.height - top.value! + : 0; + final double leftValue = + (left != null && left is PdfNumber) + ? left.value! as double + : 0; + _destination = PdfDestination(page, Offset(leftValue, topValue)); + _destination!.zoom = + (zoom != null && zoom is PdfNumber) + ? zoom.value!.toDouble() + : 0; + } + } else { + if (page != null && mode.name == PdfDictionaryProperties.fit) { + _destination = PdfDestination(page); + _destination!.mode = PdfDestinationMode.fitToPage; + } + } + } else { + if (page != null) { + _destination = PdfDestination(page); + _destination!.mode = PdfDestinationMode.fitToPage; + } + } + } + } + return _destination; + } +} + +/// This class plays two roles: it's a base class for all bookmarks +/// and it's a root of a bookmarks tree. +/// +/// ```dart +/// //Load the PDF document. +/// PdfDocument document = PdfDocument(inputBytes: inputBytes); +/// //Get the bookmark from index. +/// PdfBookmark bookmarks = document.bookmarks[0] +/// ..destination = PdfDestination(document.pages[1]) +/// ..color = PdfColor(0, 255, 0) +/// ..textStyle = [PdfTextStyle.bold] +/// ..title = 'Changed title'; +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfBookmarkBase implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [PdfBookmarkBase] class. + PdfBookmarkBase._internal() : super() { + _helper = PdfBookmarkBaseHelper(this); + } + + PdfBookmarkBase._load(PdfDictionary? dictionary, PdfCrossTable? crossTable) { + _helper = PdfBookmarkBaseHelper(this); + _isLoadedBookmark = true; + _helper.dictionary = dictionary; + if (crossTable != null) { + _helper._crossTable = crossTable; + } + } + + //Fields + late PdfBookmarkBaseHelper _helper; + + /// Internal variable to store parent. + PdfBookmarkBase? _parent; + + /// Internal variable to store loaded bookmark. + List? _bookmark; + + /// Whether the bookmark tree is expanded or not + bool _expanded = false; + List? _booklist; + bool _isLoadedBookmark = false; + + //Properties + /// Gets number of the elements in the collection. Read-Only. + /// + /// ```dart + /// //Load the PDF document. + /// PdfDocument document = PdfDocument(inputBytes: inputBytes); + /// //get the bookmark count. + /// int count = document.bookmarks.count; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get count { + final PdfDocument? document = _helper._crossTable.document; + if (document != null) { + if (_booklist == null) { + _booklist = []; + for (int n = 0; n < _list.length; n++) { + _booklist!.add(_list[n]); + } + } + return _list.length; + } else { + return _list.length; + } + } + + /// Gets the bookmark at specified index. + /// + /// ```dart + /// //Load the PDF document. + /// PdfDocument document = PdfDocument(inputBytes: inputBytes); + /// //Get the bookmark from index. + /// PdfBookmark bookmarks = document.bookmarks[0] + /// ..destination = PdfDestination(document.pages[1]) + /// ..color = PdfColor(0, 255, 0) + /// ..textStyle = [PdfTextStyle.bold] + /// ..title = 'Changed title'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBookmark operator [](int index) { + if (index < 0 || index >= count) { + throw RangeError('index'); + } + return _list[index] as PdfBookmark; + } + + /// Gets whether to expand the node or not + bool get _isExpanded { + if (_helper.dictionary!.containsKey('Count')) { + final PdfNumber number = + _helper.dictionary![PdfDictionaryProperties.count]! as PdfNumber; + return !(number.value! < 0); + } else { + return _expanded; + } + } + + /// Sets whether to expand the node or not + set _isExpanded(bool value) { + _expanded = value; + if (count > 0) { + final int newCount = _expanded ? _list.length : -_list.length; + _helper.dictionary![PdfDictionaryProperties.count] = PdfNumber(newCount); + } + } + + //Public methods + /// Adds the bookmark from the document. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Add bookmarks to the document. + /// document.bookmarks.add('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBookmark add( + String title, { + bool isExpanded = false, + PdfColor? color, + PdfDestination? destination, + PdfNamedDestination? namedDestination, + PdfAction? action, + List? textStyle, + }) { + final PdfBookmark? previous = (count < 1) ? null : this[count - 1]; + final PdfBookmark outline = PdfBookmark._internal( + title, + this, + previous, + null, + ); + if (previous != null) { + previous._next = outline; + } + _list.add(outline); + _updateFields(); + return outline; + } + + /// Determines whether the specified outline presents in the collection. + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Add bookmarks to the document. + /// PdfBookmark bookmark = document.bookmarks.add('Page 1') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)); + /// //check whether the specified bookmark present in the collection + /// bool contains = document.bookmarks.contains(bookmark); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool contains(PdfBookmark outline) { + return _list.contains(outline); + } + + /// Remove the specified bookmark from the document. + /// + /// ```dart + /// //Load the PDF document. + /// PdfDocument document = PdfDocument(inputBytes: inputBytes); + /// //Get all the bookmarks. + /// PdfBookmarkBase bookmarks = document.bookmarks; + /// //Remove specified bookmark. + /// bookmarks.remove('bookmark'); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void remove(String title) { + int index = -1; + if (_bookmark == null || _bookmark!.length < _list.length) { + _bookmark = []; + for (int n = 0; n < _list.length; n++) { + if (_list[n] is PdfBookmark) { + _bookmark!.add(_list[n] as PdfBookmark); + } + } + } + for (int c = 0; c < _bookmark!.length; c++) { + final PdfBookmark pdfbookmark = _bookmark![c]; + if (pdfbookmark.title == title) { + index = c; + break; + } + } + removeAt(index); + } + + /// Remove the bookmark from the document at the specified index. + /// + /// ```dart + /// //Load the PDF document. + /// PdfDocument document = PdfDocument(inputBytes: inputBytes); + /// //Remove specified bookmark using index. + /// document.bookmarks.removeAt(0); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void removeAt(int index) { + if (_bookmark == null || _bookmark!.length < _list.length) { + _bookmark = []; + for (int n = 0; n < _list.length; n++) { + if (_list[n] is PdfBookmark?) { + _bookmark!.add(_list[n] as PdfBookmark); + } + } + } + if (index < 0 || index >= _bookmark!.length) { + throw RangeError.value(index); + } + final PdfBookmark current = _bookmark![index]; + if (index == 0) { + if (current._helper.dictionary!.containsKey( + PdfDictionaryProperties.next, + )) { + _helper.dictionary!.setProperty( + PdfDictionaryProperties.first, + current._helper.dictionary![PdfDictionaryProperties.next], + ); + } else { + _helper.dictionary!.remove(PdfDictionaryProperties.first); + _helper.dictionary!.remove(PdfDictionaryProperties.last); + } + } else if ((current._parent != null) && + (current._previous != null) && + (current._next != null)) { + current._previous!._helper.dictionary!.setProperty( + PdfDictionaryProperties.next, + current._helper.dictionary![PdfDictionaryProperties.next], + ); + current._next!._helper.dictionary!.setProperty( + PdfDictionaryProperties.prev, + current._helper.dictionary![PdfDictionaryProperties.prev], + ); + } else if ((current._parent != null) && + (current._previous != null) && + (current._next == null)) { + current._previous!._helper.dictionary!.remove( + PdfDictionaryProperties.next, + ); + current._parent!._helper.dictionary!.setProperty( + PdfDictionaryProperties.last, + current._helper.dictionary![PdfDictionaryProperties.prev], + ); + } + if (current._parent != null) { + current._parent!._list.remove(current); + } + _bookmark!.clear(); + _updateFields(); + } + + /// Removes all the bookmark from the collection. + /// + /// ```dart + /// //Load the PDF document. + /// PdfDocument document = PdfDocument(inputBytes: inputBytes); + /// //Clear all the bookmarks. + /// document.bookmarks.clear(); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void clear() { + _list.clear(); + if (_bookmark != null) { + _bookmark!.clear(); + } + if (_booklist != null) { + _booklist!.clear(); + } + _updateFields(); + } + + /// Inserts a new outline at the specified index. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Insert bookmark at specified index + /// document.bookmarks.insert(0, 'bookmark') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBookmark insert(int index, String title) { + if (index < 0 || index > count) { + throw RangeError.value(index); + } + PdfBookmark outline; + if (index == count) { + outline = add(title); + } else { + final PdfBookmark next = this[index]; + final PdfBookmark? prevoius = (index == 0) ? null : this[index - 1]; + outline = PdfBookmark._internal(title, this, prevoius, next); + _list.insert(index, outline); + if (prevoius != null) { + prevoius._next = outline; + } + next._previous = outline; + _updateFields(); + } + return outline; + } + + //Implementations + /// Updates all outline dictionary fields. + void _updateFields() { + if (count > 0) { + final int newCount = _isExpanded ? _list.length : -_list.length; + _helper.dictionary![PdfDictionaryProperties.count] = PdfNumber(newCount); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.first, + PdfReferenceHolder(this[0]), + ); + _helper.dictionary!.setProperty( + PdfDictionaryProperties.last, + PdfReferenceHolder(this[count - 1]), + ); + } else { + _helper.dictionary!.clear(); + } + } + + /// internal method + List get _list { + return _helper._bookmarkList; + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfBookmark] helper +class PdfBookmarkHelper { + /// internal method + static PdfBookmark internal( + String title, + PdfBookmarkBase parent, + PdfBookmark? previous, + PdfBookmark? next, { + bool isExpanded = false, + PdfColor? color, + PdfDestination? destination, + PdfNamedDestination? namedDestination, + PdfAction? action, + List? textStyle, + }) { + return PdfBookmark._internal( + title, + parent, + previous, + next, + isExpanded: isExpanded, + color: color, + destination: destination, + namedDestination: namedDestination, + action: action, + textStyle: textStyle, + ); + } + + /// internal method + static PdfBookmark load(PdfDictionary? dictionary, PdfCrossTable crossTable) { + return PdfBookmark._load(dictionary, crossTable); + } + + /// internal method + static PdfBookmarkBase? getParent(PdfBookmark bookmark) { + return bookmark._parent; + } + + /// internal method + static void setParent(PdfBookmark bookmark, PdfBookmarkBase? base) { + bookmark._parent = base; + } +} + +/// [PdfBookmarkBase] helper +class PdfBookmarkBaseHelper { + /// internal field + PdfBookmarkBaseHelper(this.base); + + /// internal constructor + PdfBookmarkBase base; + + final List _bookmarkList = []; + PdfCrossTable _crossTable = PdfCrossTable(); + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + /// internal method + static PdfBookmarkBaseHelper getHelper(PdfBookmarkBase bookmark) { + return bookmark._helper; + } + + /// internal method + static PdfBookmarkBase loadInternal() { + return PdfBookmarkBase._internal(); + } + + /// internal method + static PdfBookmarkBase loaded( + PdfDictionary? dictionary, + PdfCrossTable crossTable, + ) { + return PdfBookmarkBase._load(dictionary, crossTable); + } + + /// internal method + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + /// internal method + void reproduceTree() { + PdfBookmark? currentBookmark = _getFirstBookMark(base); + bool isBookmark = currentBookmark != null; + while (isBookmark && + PdfBookmarkBaseHelper(currentBookmark!).dictionary != null) { + PdfBookmarkHelper.setParent(currentBookmark, base); + _bookmarkList.add(currentBookmark); + currentBookmark = currentBookmark._next; + isBookmark = currentBookmark != null; + } + } + + PdfBookmark? _getFirstBookMark(PdfBookmarkBase bookmark) { + PdfBookmark? firstBookmark; + final PdfDictionary dictionary = + PdfBookmarkBaseHelper.getHelper(bookmark).dictionary!; + if (dictionary.containsKey(PdfDictionaryProperties.first)) { + final PdfDictionary? first = + _crossTable.getObject(dictionary[PdfDictionaryProperties.first]) + as PdfDictionary?; + firstBookmark = PdfBookmark._load(first, _crossTable); + } + return firstBookmark; + } + + /// internal method + static List getList(PdfBookmarkBase bookmark) { + return bookmark._list; + } +} + +/// internal class +class CurrentNodeInfo { + /// internal constructor + CurrentNodeInfo(this.kids, [int? index]) { + this.index = index ?? 0; + } + //Fields + /// internal field + late List kids; + + /// internal field + late int index; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog.dart index a92930328..d1b7790aa 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog.dart @@ -1,149 +1,149 @@ -import 'dart:convert'; - -import 'package:xml/xml.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../forms/pdf_form.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pages/pdf_section_collection.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../xmp/xmp_metadata.dart'; -import 'pdf_catalog_names.dart'; -import 'pdf_document.dart'; - -/// Represents internal catalog of the PDF document. -class PdfCatalog extends PdfDictionary { - /// Initializes a new instance of the [PdfCatalog] class. - PdfCatalog() { - this[PdfDictionaryProperties.type] = PdfName('Catalog'); - } - - /// internal constructor - PdfCatalog.fromDocument(PdfDocument this.document, PdfDictionary? catalog) - : super(catalog) { - if (containsKey(PdfDictionaryProperties.names)) { - final IPdfPrimitive? obj = PdfCrossTable.dereference( - this[PdfDictionaryProperties.names], - ); - if (obj is PdfDictionary) { - _catalogNames = PdfCatalogNames(obj); - } - } - readMetadata(); - freezeChanges(this); - } - - PdfSectionCollection? _sections; - // ignore: unused_field - /// internal field - PdfDocument? document; - - /// internal field - XmpMetadata? metadata; - PdfCatalogNames? _catalogNames; - PdfForm? _forms; - // ignore: unused_element - /// internal property - PdfSectionCollection? get pages => _sections; - set pages(PdfSectionCollection? sections) { - if (_sections != sections) { - _sections = sections; - this[PdfDictionaryProperties.pages] = PdfReferenceHolder(sections); - } - } - - /// internal property - PdfDictionary? get destinations { - PdfDictionary? dests; - if (containsKey(PdfDictionaryProperties.dests)) { - dests = - PdfCrossTable.dereference(this[PdfDictionaryProperties.dests]) - as PdfDictionary?; - } - return dests; - } - - /// internal property - PdfCatalogNames? get names { - if (_catalogNames == null) { - _catalogNames = PdfCatalogNames(); - this[PdfDictionaryProperties.names] = PdfReferenceHolder(_catalogNames); - } - return _catalogNames; - } - - /// internal property - PdfForm? get form => _forms; - set form(PdfForm? value) { - if (_forms != value) { - _forms = value; - if (!PdfFormHelper.getHelper(_forms!).isLoadedForm) { - this[PdfDictionaryProperties.acroForm] = PdfReferenceHolder(_forms); - } - } - } - - //Implementation - /// Reads Xmp from the document. - void readMetadata() { - //Read metadata if present. - final IPdfPrimitive? rhMetadata = this[PdfDictionaryProperties.metadata]; - if (PdfCrossTable.dereference(rhMetadata) is PdfStream) { - final PdfStream xmpStream = - PdfCrossTable.dereference(rhMetadata)! as PdfStream; - bool isFlateDecode = false; - if (xmpStream.containsKey(PdfDictionaryProperties.filter)) { - IPdfPrimitive? obj = xmpStream[PdfDictionaryProperties.filter]; - if (obj is PdfReferenceHolder) { - final PdfReferenceHolder rh = obj; - obj = rh.object; - } - if (obj != null) { - if (obj is PdfName) { - final PdfName filter = obj; - - if (filter.name == PdfDictionaryProperties.flateDecode) { - isFlateDecode = true; - } - } else if (obj is PdfArray) { - final PdfArray filter = obj; - IPdfPrimitive? pdfFilter; - for (pdfFilter in filter.elements) { - if (pdfFilter != null && pdfFilter is PdfName) { - final PdfName filtername = pdfFilter; - if (filtername.name == PdfDictionaryProperties.flateDecode) { - isFlateDecode = true; - } - } - } - } - } - } - - if (xmpStream.compress! || isFlateDecode) { - try { - xmpStream.decompress(); - } catch (e) { - //non-compressed stream will throws exception when try to decompress - } - } - XmlDocument xmp; - try { - xmp = XmlDocument.parse(utf8.decode(xmpStream.dataStream!)); - } catch (e) { - xmpStream.decompress(); - try { - xmp = XmlDocument.parse(utf8.decode(xmpStream.dataStream!)); - } catch (e1) { - return; - } - } - metadata = XmpMetadata.fromXmlDocument(xmp); - } - } -} +import 'dart:convert'; + +import 'package:xml/xml.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../forms/pdf_form.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pages/pdf_section_collection.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../xmp/xmp_metadata.dart'; +import 'pdf_catalog_names.dart'; +import 'pdf_document.dart'; + +/// Represents internal catalog of the PDF document. +class PdfCatalog extends PdfDictionary { + /// Initializes a new instance of the [PdfCatalog] class. + PdfCatalog() { + this[PdfDictionaryProperties.type] = PdfName('Catalog'); + } + + /// internal constructor + PdfCatalog.fromDocument(PdfDocument this.document, PdfDictionary? catalog) + : super(catalog) { + if (containsKey(PdfDictionaryProperties.names)) { + final IPdfPrimitive? obj = PdfCrossTable.dereference( + this[PdfDictionaryProperties.names], + ); + if (obj is PdfDictionary) { + _catalogNames = PdfCatalogNames(obj); + } + } + readMetadata(); + freezeChanges(this); + } + + PdfSectionCollection? _sections; + // ignore: unused_field + /// internal field + PdfDocument? document; + + /// internal field + XmpMetadata? metadata; + PdfCatalogNames? _catalogNames; + PdfForm? _forms; + // ignore: unused_element + /// internal property + PdfSectionCollection? get pages => _sections; + set pages(PdfSectionCollection? sections) { + if (_sections != sections) { + _sections = sections; + this[PdfDictionaryProperties.pages] = PdfReferenceHolder(sections); + } + } + + /// internal property + PdfDictionary? get destinations { + PdfDictionary? dests; + if (containsKey(PdfDictionaryProperties.dests)) { + dests = + PdfCrossTable.dereference(this[PdfDictionaryProperties.dests]) + as PdfDictionary?; + } + return dests; + } + + /// internal property + PdfCatalogNames? get names { + if (_catalogNames == null) { + _catalogNames = PdfCatalogNames(); + this[PdfDictionaryProperties.names] = PdfReferenceHolder(_catalogNames); + } + return _catalogNames; + } + + /// internal property + PdfForm? get form => _forms; + set form(PdfForm? value) { + if (_forms != value) { + _forms = value; + if (!PdfFormHelper.getHelper(_forms!).isLoadedForm) { + this[PdfDictionaryProperties.acroForm] = PdfReferenceHolder(_forms); + } + } + } + + //Implementation + /// Reads Xmp from the document. + void readMetadata() { + //Read metadata if present. + final IPdfPrimitive? rhMetadata = this[PdfDictionaryProperties.metadata]; + if (PdfCrossTable.dereference(rhMetadata) is PdfStream) { + final PdfStream xmpStream = + PdfCrossTable.dereference(rhMetadata)! as PdfStream; + bool isFlateDecode = false; + if (xmpStream.containsKey(PdfDictionaryProperties.filter)) { + IPdfPrimitive? obj = xmpStream[PdfDictionaryProperties.filter]; + if (obj is PdfReferenceHolder) { + final PdfReferenceHolder rh = obj; + obj = rh.object; + } + if (obj != null) { + if (obj is PdfName) { + final PdfName filter = obj; + + if (filter.name == PdfDictionaryProperties.flateDecode) { + isFlateDecode = true; + } + } else if (obj is PdfArray) { + final PdfArray filter = obj; + IPdfPrimitive? pdfFilter; + for (pdfFilter in filter.elements) { + if (pdfFilter != null && pdfFilter is PdfName) { + final PdfName filtername = pdfFilter; + if (filtername.name == PdfDictionaryProperties.flateDecode) { + isFlateDecode = true; + } + } + } + } + } + } + + if (xmpStream.compress! || isFlateDecode) { + try { + xmpStream.decompress(); + } catch (e) { + //non-compressed stream will throws exception when try to decompress + } + } + XmlDocument xmp; + try { + xmp = XmlDocument.parse(utf8.decode(xmpStream.dataStream!)); + } catch (e) { + xmpStream.decompress(); + try { + xmp = XmlDocument.parse(utf8.decode(xmpStream.dataStream!)); + } catch (e1) { + return; + } + } + metadata = XmpMetadata.fromXmlDocument(xmp); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog_names.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog_names.dart index 009da509e..32230ed7b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog_names.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_catalog_names.dart @@ -1,166 +1,166 @@ -import 'dart:math'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import 'attachments/pdf_attachment_collection.dart'; - -/// internal class -class PdfCatalogNames implements IPdfWrapper { - /// internal constructor - PdfCatalogNames([PdfDictionary? root]) { - if (root != null) { - dictionary = root; - } - } - //Fields - PdfAttachmentCollection? _attachments; - - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - - //Overrides - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } - - //Properties - //Gets the destinations. - /// internal property - PdfDictionary? get destinations { - final IPdfPrimitive? obj = PdfCrossTable.dereference( - dictionary![PdfDictionaryProperties.dests], - ); - final PdfDictionary? dests = obj as PdfDictionary?; - return dests; - } - - /// internal property - // ignore: avoid_setters_without_getters - set embeddedFiles(PdfAttachmentCollection value) { - if (_attachments != value) { - _attachments = value; - dictionary!.setProperty( - PdfDictionaryProperties.embeddedFiles, - PdfReferenceHolder(_attachments), - ); - } - } - - //Methods - /// Gets the named object from a tree. - IPdfPrimitive? getNamedObjectFromTree(PdfDictionary? root, PdfString name) { - bool found = false; - PdfDictionary? current = root; - IPdfPrimitive? obj; - while (!found && current != null && current.items!.isNotEmpty) { - if (current.containsKey(PdfDictionaryProperties.kids)) { - current = _getProperKid(current, name); - } else if (current.containsKey(PdfDictionaryProperties.names)) { - obj = _findName(current, name); - found = true; - } - } - return obj; - } - - //Finds the name in the tree. - IPdfPrimitive? _findName(PdfDictionary current, PdfString name) { - final PdfArray names = - PdfCrossTable.dereference(current[PdfDictionaryProperties.names])! - as PdfArray; - final int halfLength = names.count ~/ 2; - int lowIndex = 0, topIndex = halfLength - 1, half = 0; - bool found = false; - while (!found) { - half = (lowIndex + topIndex) ~/ 2; - if (lowIndex > topIndex) { - break; - } - final PdfString str = - PdfCrossTable.dereference(names[half * 2])! as PdfString; - final int cmp = _byteCompare(name, str); - if (cmp > 0) { - lowIndex = half + 1; - } else if (cmp < 0) { - topIndex = half - 1; - } else { - found = true; - break; - } - } - IPdfPrimitive? obj; - if (found) { - obj = PdfCrossTable.dereference(names[half * 2 + 1]); - } - return obj; - } - - //Gets the proper kid from an array. - PdfDictionary? _getProperKid(PdfDictionary current, PdfString name) { - final PdfArray kids = - PdfCrossTable.dereference(current[PdfDictionaryProperties.kids])! - as PdfArray; - PdfDictionary? kid; - for (final IPdfPrimitive? obj in kids.elements) { - kid = PdfCrossTable.dereference(obj) as PdfDictionary?; - if (_checkLimits(kid!, name)) { - break; - } else { - kid = null; - } - } - return kid; - } - - // Checks the limits of the named tree node. - bool _checkLimits(PdfDictionary kid, PdfString name) { - IPdfPrimitive? obj = kid[PdfDictionaryProperties.limits]; - bool result = false; - if (obj is PdfArray && obj.count >= 2) { - final PdfArray limits = obj; - obj = limits[0]; - final PdfString lowerLimit = obj! as PdfString; - obj = limits[1]; - final PdfString higherLimit = obj! as PdfString; - final int lowCmp = _byteCompare(lowerLimit, name); - final int hiCmp = _byteCompare(higherLimit, name); - if (lowCmp == 0 || hiCmp == 0) { - result = true; - } else if (lowCmp < 0 && hiCmp > 0) { - result = true; - } - } - return result; - } - - int _byteCompare(PdfString str1, PdfString str2) { - final List data1 = str1.data!; - final List data2 = str2.data!; - final int commonSize = [data1.length, data2.length].reduce(min); - int result = 0; - for (int i = 0; i < commonSize; ++i) { - final int byte1 = data1[i]; - final int byte2 = data2[i]; - result = byte1 - byte2; - if (result != 0) { - break; - } - } - if (result == 0) { - result = data1.length - data2.length; - } - return result; - } - - /// Clear catalog names. - void clear() { - dictionary!.clear(); - } -} +import 'dart:math'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import 'attachments/pdf_attachment_collection.dart'; + +/// internal class +class PdfCatalogNames implements IPdfWrapper { + /// internal constructor + PdfCatalogNames([PdfDictionary? root]) { + if (root != null) { + dictionary = root; + } + } + //Fields + PdfAttachmentCollection? _attachments; + + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + + //Overrides + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } + + //Properties + //Gets the destinations. + /// internal property + PdfDictionary? get destinations { + final IPdfPrimitive? obj = PdfCrossTable.dereference( + dictionary![PdfDictionaryProperties.dests], + ); + final PdfDictionary? dests = obj as PdfDictionary?; + return dests; + } + + /// internal property + // ignore: avoid_setters_without_getters + set embeddedFiles(PdfAttachmentCollection value) { + if (_attachments != value) { + _attachments = value; + dictionary!.setProperty( + PdfDictionaryProperties.embeddedFiles, + PdfReferenceHolder(_attachments), + ); + } + } + + //Methods + /// Gets the named object from a tree. + IPdfPrimitive? getNamedObjectFromTree(PdfDictionary? root, PdfString name) { + bool found = false; + PdfDictionary? current = root; + IPdfPrimitive? obj; + while (!found && current != null && current.items!.isNotEmpty) { + if (current.containsKey(PdfDictionaryProperties.kids)) { + current = _getProperKid(current, name); + } else if (current.containsKey(PdfDictionaryProperties.names)) { + obj = _findName(current, name); + found = true; + } + } + return obj; + } + + //Finds the name in the tree. + IPdfPrimitive? _findName(PdfDictionary current, PdfString name) { + final PdfArray names = + PdfCrossTable.dereference(current[PdfDictionaryProperties.names])! + as PdfArray; + final int halfLength = names.count ~/ 2; + int lowIndex = 0, topIndex = halfLength - 1, half = 0; + bool found = false; + while (!found) { + half = (lowIndex + topIndex) ~/ 2; + if (lowIndex > topIndex) { + break; + } + final PdfString str = + PdfCrossTable.dereference(names[half * 2])! as PdfString; + final int cmp = _byteCompare(name, str); + if (cmp > 0) { + lowIndex = half + 1; + } else if (cmp < 0) { + topIndex = half - 1; + } else { + found = true; + break; + } + } + IPdfPrimitive? obj; + if (found) { + obj = PdfCrossTable.dereference(names[half * 2 + 1]); + } + return obj; + } + + //Gets the proper kid from an array. + PdfDictionary? _getProperKid(PdfDictionary current, PdfString name) { + final PdfArray kids = + PdfCrossTable.dereference(current[PdfDictionaryProperties.kids])! + as PdfArray; + PdfDictionary? kid; + for (final IPdfPrimitive? obj in kids.elements) { + kid = PdfCrossTable.dereference(obj) as PdfDictionary?; + if (_checkLimits(kid!, name)) { + break; + } else { + kid = null; + } + } + return kid; + } + + // Checks the limits of the named tree node. + bool _checkLimits(PdfDictionary kid, PdfString name) { + IPdfPrimitive? obj = kid[PdfDictionaryProperties.limits]; + bool result = false; + if (obj is PdfArray && obj.count >= 2) { + final PdfArray limits = obj; + obj = limits[0]; + final PdfString lowerLimit = obj! as PdfString; + obj = limits[1]; + final PdfString higherLimit = obj! as PdfString; + final int lowCmp = _byteCompare(lowerLimit, name); + final int hiCmp = _byteCompare(higherLimit, name); + if (lowCmp == 0 || hiCmp == 0) { + result = true; + } else if (lowCmp < 0 && hiCmp > 0) { + result = true; + } + } + return result; + } + + int _byteCompare(PdfString str1, PdfString str2) { + final List data1 = str1.data!; + final List data2 = str2.data!; + final int commonSize = [data1.length, data2.length].reduce(min); + int result = 0; + for (int i = 0; i < commonSize; ++i) { + final int byte1 = data1[i]; + final int byte2 = data2[i]; + result = byte1 - byte2; + if (result != 0) { + break; + } + } + if (result == 0) { + result = data1.length - data2.length; + } + return result; + } + + /// Clear catalog names. + void clear() { + dictionary!.clear(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document.dart index d620f3d3a..baa1b959e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document.dart @@ -1,1989 +1,1989 @@ -import 'dart:collection'; -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:xml/xml.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/enum.dart'; -import '../annotations/fdf_document.dart'; -import '../annotations/fdf_parser.dart'; -import '../annotations/json_document.dart'; -import '../annotations/json_parser.dart'; -import '../annotations/pdf_action_annotation.dart'; -import '../annotations/pdf_annotation.dart'; -import '../annotations/pdf_annotation_collection.dart'; -import '../annotations/pdf_text_web_link.dart'; -import '../annotations/xfdf_parser.dart'; -import '../color_space/pdf_icc_color_profile.dart'; -import '../forms/pdf_form.dart'; -import '../forms/pdf_form_field_collection.dart'; -import '../forms/pdf_xfdf_document.dart'; -import '../general/file_specification_base.dart'; -import '../general/pdf_destination.dart'; -import '../general/pdf_named_destination.dart'; -import '../general/pdf_named_destination_collection.dart'; -import '../graphics/brushes/pdf_brush.dart'; -import '../graphics/enums.dart'; -import '../graphics/pdf_pens.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_main_object_collection.dart'; -import '../io/pdf_reader.dart'; -import '../io/pdf_writer.dart'; -import '../pages/pdf_layer_collection.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_collection.dart'; -import '../pages/pdf_page_settings.dart'; -import '../pages/pdf_section_collection.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_reference.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import '../security/digital_signature/pdf_signature_dictionary.dart'; -import '../security/enum.dart'; -import '../security/pdf_encryptor.dart'; -import '../security/pdf_security.dart'; -import 'attachments/pdf_attachment_collection.dart'; -import 'enums.dart'; -import 'outlines/pdf_outline.dart'; -import 'pdf_catalog.dart'; -import 'pdf_catalog_names.dart'; -import 'pdf_document_information.dart'; -import 'pdf_document_template.dart'; -import 'pdf_file_structure.dart'; - -/// Represents a PDF document and can be used to create a new PDF document -/// from the scratch. -class PdfDocument { - //Constructor - /// Initialize a new instance of the [PdfDocument] class - /// from the PDF data as list of bytes - /// - /// To initialize a new instance of the [PdfDocument] class for an exisitng - /// PDF document, we can use the named parameters - /// to load PDF data and password - /// or add conformance level to the PDF - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Add a PDF page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', - /// PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// bounds: Rect.fromLTWH(0, 0, 150, 20)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfDocument({ - List? inputBytes, - PdfConformanceLevel? conformanceLevel, - String? password, - }) { - _helper = PdfDocumentHelper(this); - _helper.isLoadedDocument = inputBytes != null; - _helper.password = password; - _initialize(inputBytes); - if (!_helper.isLoadedDocument && conformanceLevel != null) { - _initializeConformance(conformanceLevel); - } - } - - /// Initialize a new instance of the [PdfDocument] class - /// from the PDF data as base64 string - /// - /// If the document is encrypted, then we have to provide open or permission - /// passwords to load PDF document - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData); - /// //Add a PDF page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', - /// PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), - /// bounds: Rect.fromLTWH(0, 0, 150, 20)); - /// //Save the updated PDF document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfDocument.fromBase64String(String base64String, {String? password}) { - _helper = PdfDocumentHelper(this); - if (base64String.isEmpty) { - ArgumentError.value(base64String, 'PDF data', 'PDF data cannot be null'); - } - _helper.password = password; - _helper.isLoadedDocument = true; - _initialize(base64.decode(base64String)); - } - - //Fields - late PdfDocumentHelper _helper; - PdfPageCollection? _pages; - PdfPageSettings? _settings; - PdfSectionCollection? _sections; - PdfFileStructure? _fileStructure; - PdfColorSpace? _colorSpace; - PdfDocumentTemplate? _template; - PdfBookmarkBase? _outlines; - PdfNamedDestinationCollection? _namedDestinations; - List? _data; - PdfBookmarkBase? _bookmark; - PdfDocumentInformation? _documentInfo; - PdfLayerCollection? _layers; - PdfAttachmentCollection? _attachments; - PdfForm? _form; - - /// Gets or sets the PDF document compression level. - PdfCompressionLevel? compressionLevel; - - /// The event raised on Pdf password. - /// - /// ```dart - /// //Load an existing PDF document - /// PdfDocument document = - /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) - /// //Subsribe the onPdfPassword event - /// ..onPdfPassword = loadOnPdfPassword; - /// //Access the attachments - /// PdfAttachmentCollection attachmentCollection = document.attachments; - /// //Iterates the attachments - /// for (int i = 0; i < attachmentCollection.count; i++) { - /// //Extracts the attachment and saves it to the disk - /// File(attachmentCollection[i].fileName) - /// .writeAsBytesSync(attachmentCollection[i].data); - /// } - /// //Disposes the document - /// document.dispose(); - /// - /// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { - /// //Sets the value of PDF password. - /// args.attachmentOpenPassword = 'syncfusion'; - /// } - /// ``` - PdfPasswordCallback? onPdfPassword; - - //Properties - /// Gets the security features of the document like encryption. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Document security - /// PdfSecurity security = document.security; - /// //Set security options - /// security.keySize = PdfEncryptionKeySize.key128Bit; - /// security.algorithm = PdfEncryptionAlgorithm.rc4; - /// security.userPassword = 'password'; - /// security.ownerPassword = 'syncfusion'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfSecurity get security { - _helper._security ??= PdfSecurityHelper.getSecurity(); - if (_helper.conformanceLevel != PdfConformanceLevel.none) { - PdfSecurityHelper.getHelper(_helper._security!).conformance = true; - } - return _helper._security!; - } - - /// Gets the collection of the sections in the document. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Add a new section. - /// PdfSection section = document.sections!.add(); - /// //Create page for the newly added section and draw text. - /// section.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfSectionCollection? get sections => _sections; - - /// Gets the document's page setting. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Get the document page settings. - /// document.pageSettings.margins.all = 50; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfPageSettings get pageSettings { - if (_settings == null) { - _settings = PdfPageSettings(); - _settings!.setMargins(PdfDocumentHelper.defaultMargin); - } - return _settings!; - } - - /// Sets the document's page setting. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Create a PDF page settings. - /// PdfPageSettings settings = PdfPageSettings(); - /// settings.margins.all = 50; - /// //Set the page settings to document. - /// document.pageSettings = settings; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - set pageSettings(PdfPageSettings settings) { - _settings = settings; - } - - /// Gets a template to all pages in the document. - PdfDocumentTemplate get template { - _template ??= PdfDocumentTemplate(); - return _template!; - } - - /// Sets a template to all pages in the document. - set template(PdfDocumentTemplate value) { - _template = value; - } - - /// Gets the color space of the document. - /// This property can be used to create PDF document in RGB, - /// Grayscale or CMYK color spaces. - /// - /// By default the document uses RGB color space. - PdfColorSpace get colorSpace { - if ((_colorSpace == PdfColorSpace.rgb) || - ((_colorSpace == PdfColorSpace.cmyk) || - (_colorSpace == PdfColorSpace.grayScale))) { - return _colorSpace!; - } else { - return PdfColorSpace.rgb; - } - } - - /// Sets the color space of the document. - /// This property can be used to create PDF document in RGB, - /// Grayscale or CMYK color spaces. - /// - /// By default the document uses RGB color space. - set colorSpace(PdfColorSpace value) { - if ((value == PdfColorSpace.rgb) || - ((value == PdfColorSpace.cmyk) || (value == PdfColorSpace.grayScale))) { - _colorSpace = value; - } else { - _colorSpace = PdfColorSpace.rgb; - } - } - - /// Gets the internal structure of the PDF document. - PdfFileStructure get fileStructure { - _fileStructure ??= PdfFileStructure(); - return _fileStructure!; - } - - /// Sets the internal structure of the PDF document. - set fileStructure(PdfFileStructure value) { - _fileStructure = value; - } - - /// Gets the collection of pages in the document. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Get the page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfPageCollection get pages => _getPageCollection(); - - /// Gets the bookmark collection of the document. - /// - /// ```dart - /// //Create a new document. - /// PdfDocument document = PdfDocument(); - /// //Create document bookmarks. - /// document.bookmarks.add('Interactive Feature') - /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) - /// ..textStyle = [PdfTextStyle.bold] - /// ..color = PdfColor(255, 0, 0); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBookmarkBase get bookmarks { - if (_helper.isLoadedDocument) { - if (_bookmark == null) { - if (_helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { - final IPdfPrimitive? outlines = PdfCrossTable.dereference( - _helper.catalog[PdfDictionaryProperties.outlines], - ); - if (outlines != null && outlines is PdfDictionary) { - _bookmark = PdfBookmarkBaseHelper.loaded( - outlines, - _helper.crossTable, - ); - PdfBookmarkBaseHelper.getHelper(_bookmark!).reproduceTree(); - } else { - _bookmark = _createBookmarkRoot(); - } - } else { - _bookmark = _createBookmarkRoot(); - } - } - return _bookmark!; - } else { - if (_outlines == null) { - _outlines = PdfBookmarkBaseHelper.loadInternal(); - _helper.catalog[PdfDictionaryProperties.outlines] = PdfReferenceHolder( - _outlines, - ); - } - return _outlines!; - } - } - - /// Gets the named destination collection of the document. - PdfNamedDestinationCollection get namedDestinationCollection { - if (_helper.isLoadedDocument) { - if (_namedDestinations == null) { - if (_helper.catalog.containsKey(PdfDictionaryProperties.names) && - (_namedDestinations == null)) { - final PdfDictionary? namedDestinations = - PdfCrossTable.dereference( - _helper.catalog[PdfDictionaryProperties.names], - ) - as PdfDictionary?; - _namedDestinations = PdfNamedDestinationCollectionHelper.load( - namedDestinations, - _helper.crossTable, - ); - } - _namedDestinations ??= _createNamedDestinations(); - } - return _namedDestinations!; - } else { - if (_namedDestinations == null) { - _namedDestinations = PdfNamedDestinationCollection(); - _helper.catalog[PdfDictionaryProperties.names] = PdfReferenceHolder( - _namedDestinations, - ); - final PdfReferenceHolder? names = - _helper.catalog[PdfDictionaryProperties.names] - as PdfReferenceHolder?; - if (names != null) { - final PdfDictionary? dic = names.object as PdfDictionary?; - if (dic != null) { - dic[PdfDictionaryProperties.dests] = PdfReferenceHolder( - _namedDestinations, - ); - } - } - } - return _namedDestinations!; - } - } - - /// Gets document's information and properties such as document's title, subject, keyword etc. - PdfDocumentInformation get documentInformation { - if (_documentInfo == null) { - if (_helper.isLoadedDocument) { - final PdfDictionary trailer = _helper.crossTable.trailer!; - if (PdfCrossTable.dereference(trailer[PdfDictionaryProperties.info]) - is PdfDictionary) { - final PdfDictionary? entry = - PdfCrossTable.dereference(trailer[PdfDictionaryProperties.info]) - as PdfDictionary?; - _documentInfo = PdfDocumentInformationHelper.load( - _helper.catalog, - dictionary: entry, - isLoaded: true, - conformance: _helper.conformanceLevel, - ); - } else { - _documentInfo = PdfDocumentInformationHelper.load( - _helper.catalog, - conformance: _helper.conformanceLevel, - ); - _helper.crossTable.trailer![PdfDictionaryProperties - .info] = PdfReferenceHolder(_documentInfo); - } - // Read document's info dictionary if present. - _readDocumentInfo(); - } else { - _documentInfo = PdfDocumentInformationHelper.load( - _helper.catalog, - conformance: _helper.conformanceLevel, - ); - _helper.crossTable.trailer![PdfDictionaryProperties - .info] = PdfReferenceHolder(_documentInfo); - } - } - return _documentInfo!; - } - - /// Gets the collection of PdfLayer from the PDF document. - PdfLayerCollection get layers { - _layers ??= PdfLayerCollectionHelper.load(this); - return _layers!; - } - - /// Gets the attachment collection of the document. - PdfAttachmentCollection get attachments { - if (_attachments == null) { - if (!_helper.isLoadedDocument) { - _attachments = PdfAttachmentCollection(); - if (_helper.conformanceLevel == PdfConformanceLevel.a1b || - _helper.conformanceLevel == PdfConformanceLevel.a2b) { - PdfAttachmentCollectionHelper.getHelper(_attachments!).conformance = - true; - } - _helper.catalog.names!.embeddedFiles = _attachments!; - } else { - if (onPdfPassword != null && _helper.password == '') { - final PdfPasswordArgs args = PdfPasswordArgs._(); - onPdfPassword!(this, args); - _helper.password = args.attachmentOpenPassword; - } - if (_helper._isAttachOnlyEncryption!) { - _helper.checkEncryption(_helper._isAttachOnlyEncryption); - } - final IPdfPrimitive? attachmentDictionary = PdfCrossTable.dereference( - _helper.catalog[PdfDictionaryProperties.names], - ); - if (attachmentDictionary != null && - attachmentDictionary is PdfDictionary && - attachmentDictionary.containsKey( - PdfDictionaryProperties.embeddedFiles, - )) { - _attachments = PdfAttachmentCollectionHelper.load( - attachmentDictionary, - _helper.crossTable, - ); - } else { - _attachments = PdfAttachmentCollection(); - _helper.catalog.names!.embeddedFiles = _attachments!; - } - } - } - return _attachments!; - } - - /// Gets the interactive form of the document. - PdfForm get form { - if (_helper.isLoadedDocument) { - if (_form == null) { - if (_helper.catalog.containsKey(PdfDictionaryProperties.acroForm)) { - final IPdfPrimitive? formDictionary = PdfCrossTable.dereference( - _helper.catalog[PdfDictionaryProperties.acroForm], - ); - if (formDictionary is PdfDictionary) { - _form = PdfFormHelper.internal(_helper.crossTable, formDictionary); - if (_form != null && _form!.fields.count != 0) { - _helper.catalog.form = _form; - List? widgetReference; - if (PdfFormHelper.getHelper(_form!).crossTable!.document != - null) { - for ( - int i = 0; - i < - PdfFormHelper.getHelper( - _form!, - ).crossTable!.document!.pages.count; - i++ - ) { - final PdfPage page = - PdfFormHelper.getHelper( - _form!, - ).crossTable!.document!.pages[i]; - widgetReference ??= - PdfPageHelper.getHelper(page).getWidgetReferences(); - if (widgetReference.isNotEmpty) { - PdfPageHelper.getHelper( - page, - ).createAnnotations(widgetReference); - } - } - if (widgetReference != null) { - widgetReference.clear(); - } - if (!PdfFormHelper.getHelper(_form!).formHasKids) { - PdfFormFieldCollectionHelper.getHelper( - _form!.fields, - ).createFormFieldsFromWidgets(_form!.fields.count); - } - } - } - return _form!; - } - } - _form = PdfFormHelper.internal(_helper.crossTable); - _helper.catalog.setProperty( - PdfDictionaryProperties.acroForm, - PdfReferenceHolder(_form), - ); - _helper.catalog.form = _form; - return _form!; - } else { - return _form!; - } - } else { - return _helper.catalog.form ??= PdfForm(); - } - } - - //Public methods - /// Saves the document and return the saved bytes as Uint8List. - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Get the page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// Uint8List bytes = document.saveAsBytesSync(); - /// document.dispose(); - /// ``` - Uint8List saveAsBytesSync() { - final PdfBytesBuilder buffer = PdfBytesBuilder(); - final PdfWriter writer = PdfWriter(null, buffer); - _saveDocument(writer); - final Uint8List bytes = buffer.takeBytes(); - buffer.clear(); - return bytes; - } - - /// Saves the document and return the saved bytes as list of int. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Get the page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = document.saveSync(); - /// document.dispose(); - /// ``` - List saveSync() { - final List buffer = []; - final PdfWriter writer = PdfWriter(buffer); - _saveDocument(writer); - return writer.buffer!; - } - - /// Internal method to save the PDF document. - void _saveDocument(PdfWriter writer) { - writer.document = this; - _checkPages(); - if (_helper.isLoadedDocument && - _bookmark != null && - _bookmark!.count > 0 && - _helper.crossTable.documentCatalog != null && - !_helper.crossTable.documentCatalog!.containsKey( - PdfDictionaryProperties.outlines, - )) { - _helper.catalog.setProperty( - PdfDictionaryProperties.outlines, - PdfReferenceHolder(_bookmark), - ); - } else if (_bookmark != null && - _bookmark!.count < 1 && - _helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { - _helper.catalog.remove(PdfDictionaryProperties.outlines); - } - if (PdfSecurityHelper.getHelper(security).encryptAttachments && - security.userPassword == '') { - throw ArgumentError.value( - 'User password cannot be empty for encrypt only attachment.', - ); - } - if (_helper.isLoadedDocument) { - if (_helper._security != null) { - if (PdfSecurityHelper.getHelper( - _helper._security!, - ).encryptAttachments) { - fileStructure.incrementalUpdate = false; - if (PdfSecurityHelper.getHelper( - _helper._security!, - ).encryptor.userPassword.isEmpty) { - PdfSecurityHelper.getHelper(_helper._security!) - .encryptor - .encryptOnlyAttachment = false; - } - } - } - if (fileStructure.incrementalUpdate && - (_helper._security == null || - (_helper._security != null && - !PdfSecurityHelper.getHelper( - _helper._security!, - ).modifiedSecurity && - !PdfPermissionsHelper.isModifiedPermissions( - _helper._security!.permissions, - )))) { - _copyOldStream(writer); - if (_helper.catalog.changed!) { - _readDocumentInfo(); - } - } else { - _helper.crossTable = PdfCrossTable.fromCatalog( - _helper.crossTable.count, - _helper.crossTable.encryptorDictionary, - _helper.crossTable.pdfDocumentCatalog, - ); - _helper.crossTable.document = this; - _helper.crossTable.trailer![PdfDictionaryProperties - .info] = PdfReferenceHolder(documentInformation); - } - _appendDocument(writer); - } else { - if (_helper.conformanceLevel == PdfConformanceLevel.a1b || - _helper.conformanceLevel == PdfConformanceLevel.a2b || - _helper.conformanceLevel == PdfConformanceLevel.a3b) { - PdfDocumentInformationHelper.getHelper(documentInformation).xmpMetadata; - if (_helper.conformanceLevel == PdfConformanceLevel.a3b && - _helper.catalog.names != null && - attachments.count > 0) { - final PdfName fileRelationShip = PdfName( - PdfDictionaryProperties.afRelationship, - ); - final PdfArray fileAttachmentAssociationArray = PdfArray(); - for (int i = 0; i < attachments.count; i++) { - if (!PdfFileSpecificationBaseHelper.getHelper( - attachments[i], - ).dictionary!.items!.containsKey(fileRelationShip)) { - PdfFileSpecificationBaseHelper.getHelper( - attachments[i], - ).dictionary!.items![fileRelationShip] = PdfName('Alternative'); - } - fileAttachmentAssociationArray.add( - PdfReferenceHolder( - PdfFileSpecificationBaseHelper.getHelper( - attachments[i], - ).dictionary, - ), - ); - } - _helper.catalog.items![PdfName(PdfDictionaryProperties.af)] = - fileAttachmentAssociationArray; - } - } - _helper.crossTable.save(writer); - final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); - _onDocumentSaved(argsSaved); - } - } - - /// Saves the document and return the saved bytes as feature Uint8List. - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Get the page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// Uint8List bytes = await document.saveAsBytes(); - /// document.dispose(); - /// ``` - Future saveAsBytes() async { - final PdfBytesBuilder buffer = PdfBytesBuilder(); - final PdfWriter writer = PdfWriter(null, buffer); - await _saveDocumentAsync(writer); - final Uint8List bytes = buffer.takeBytes(); - buffer.clear(); - return bytes; - } - - /// Saves the document and return the saved bytes as future list of int. - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Get the page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - Future> save() async { - final List buffer = []; - final PdfWriter writer = PdfWriter(buffer); - await _saveDocumentAsync(writer); - return writer.buffer!; - } - - /// Internal method to save the PDF document - Future _saveDocumentAsync(PdfWriter writer) async { - writer.document = this; - await _checkPagesAsync(); - if (_helper.isLoadedDocument && - _bookmark != null && - _bookmark!.count > 0 && - _helper.crossTable.documentCatalog != null && - !_helper.crossTable.documentCatalog!.containsKey( - PdfDictionaryProperties.outlines, - )) { - _helper.catalog.setProperty( - PdfDictionaryProperties.outlines, - PdfReferenceHolder(_bookmark), - ); - } else if (_outlines != null && - _outlines!.count < 1 && - _helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { - _helper.catalog.remove(PdfDictionaryProperties.outlines); - } - if (PdfSecurityHelper.getHelper(security).encryptAttachments && - security.userPassword == '') { - throw ArgumentError.value( - 'User password cannot be empty for encrypt only attachment.', - ); - } - if (_helper.isLoadedDocument) { - if (_helper._security != null) { - if (PdfSecurityHelper.getHelper( - _helper._security!, - ).encryptAttachments) { - fileStructure.incrementalUpdate = false; - if (PdfSecurityHelper.getHelper( - _helper._security!, - ).encryptor.userPassword.isEmpty) { - PdfSecurityHelper.getHelper(_helper._security!) - .encryptor - .encryptOnlyAttachment = false; - } - } - } - if (fileStructure.incrementalUpdate && - (_helper._security == null || - (_helper._security != null && - !PdfSecurityHelper.getHelper( - _helper._security!, - ).modifiedSecurity && - !PdfPermissionsHelper.isModifiedPermissions( - _helper._security!.permissions, - )))) { - await _copyOldStreamAsync(writer).then((_) { - if (_helper.catalog.changed!) { - _readDocumentInfoAsync(); - } - }); - } else { - _helper.crossTable = PdfCrossTable.fromCatalog( - _helper.crossTable.count, - _helper.crossTable.encryptorDictionary, - _helper.crossTable.pdfDocumentCatalog, - ); - _helper.crossTable.document = this; - _helper.crossTable.trailer![PdfDictionaryProperties - .info] = PdfReferenceHolder(documentInformation); - } - await _appendDocumentAsync(writer); - } else { - if (_helper.conformanceLevel == PdfConformanceLevel.a1b || - _helper.conformanceLevel == PdfConformanceLevel.a2b || - _helper.conformanceLevel == PdfConformanceLevel.a3b) { - PdfDocumentInformationHelper.getHelper(documentInformation).xmpMetadata; - if (_helper.conformanceLevel == PdfConformanceLevel.a3b && - _helper.catalog.names != null && - attachments.count > 0) { - final PdfName fileRelationShip = PdfName( - PdfDictionaryProperties.afRelationship, - ); - final PdfArray fileAttachmentAssociationArray = PdfArray(); - for (int i = 0; i < attachments.count; i++) { - if (!PdfFileSpecificationBaseHelper.getHelper( - attachments[i], - ).dictionary!.items!.containsKey(fileRelationShip)) { - PdfFileSpecificationBaseHelper.getHelper( - attachments[i], - ).dictionary!.items![fileRelationShip] = PdfName('Alternative'); - } - fileAttachmentAssociationArray.add( - PdfReferenceHolder( - PdfFileSpecificationBaseHelper.getHelper( - attachments[i], - ).dictionary, - ), - ); - } - _helper.catalog.items![PdfName(PdfDictionaryProperties.af)] = - fileAttachmentAssociationArray; - } - } - await _helper.crossTable.saveAsync(writer); - final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); - await _onDocumentSavedAsync(argsSaved); - } - } - - void _checkPages() { - if (!_helper.isLoadedDocument) { - if (pages.count == 0) { - pages.add(); - } - } - } - - Future _checkPagesAsync() async { - if (!_helper.isLoadedDocument) { - if (pages.count == 0) { - pages.add(); - } - } - } - - /// Releases all the resources used by document instances. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Get the page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - void dispose() { - PdfBrushesHelper.dispose(); - PdfPensHelper.dispose(); - _helper.crossTable.dispose(); - _helper._security = null; - _helper.currentSavingObject = null; - } - - /// Export the annotation data to UTF8 bytes with the specific [PdfAnnotationDataFormat]. - /// - /// To export specific annotations, annotation types, appearances, and - /// add a file name to the export format, we can use the named parameters - /// exportList, exportTypes, exportAppearance, and fileName respectively. - /// - /// ```dart - /// //Load an existing PDF document. - /// PdfDocument document = - /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - /// //Export annotations in specific PdfAnnotationDataFormat format. - /// List bytes = document.exportAnnotation(PdfAnnotationDataFormat.fdf, - /// fileName: 'PDFExportDocument'); - /// //Save the exported data. - /// File('export.fdf').writeAsBytesSync(bytes); - /// //Dispose the document. - /// document.dispose(); - /// ``` - List exportAnnotation( - PdfAnnotationDataFormat format, { - String? fileName, - List? exportList, - List? exportTypes, - bool exportAppearance = false, - }) { - List bytes = []; - if (format == PdfAnnotationDataFormat.xfdf) { - bytes = _helper.exportXfdf( - fileName, - exportList, - exportTypes, - exportAppearance, - ); - } else if (format == PdfAnnotationDataFormat.fdf) { - bytes = _helper.exportFdf( - fileName, - exportList, - exportTypes, - exportAppearance, - ); - } else if (format == PdfAnnotationDataFormat.json) { - bytes = _helper.exportJson( - fileName, - exportList, - exportTypes, - exportAppearance, - ); - } - return bytes; - } - - /// Import the annotation data from UTF8 bytes with the specific [PdfAnnotationDataFormat]. - /// - /// ```dart - /// //Load an existing PDF document. - /// PdfDocument document = - /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - /// //Import annotations in specific PdfAnnotationDataFormat format. - /// document.importAnnotation( - /// File('input.fdf').readAsBytesSync(), PdfAnnotationDataFormat.fdf); - /// //Save the document. - /// File('output.pdf').writeAsBytesSync(await document.save()); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void importAnnotation(List data, PdfAnnotationDataFormat format) { - if (format == PdfAnnotationDataFormat.xfdf) { - _helper.importXfdf(data); - } else if (format == PdfAnnotationDataFormat.fdf) { - _helper.importFdf(data); - } else if (format == PdfAnnotationDataFormat.json) { - _helper.importJson(data); - } - } - - //Implementation - void _initialize(List? pdfData) { - _helper._isAttachOnlyEncryption = false; - _helper.isEncrypted = false; - _data = pdfData; - _helper.objects = PdfMainObjectCollection(); - if (_helper.isLoadedDocument) { - _helper.crossTable = PdfCrossTable(this, pdfData); - _helper.isEncrypted = _helper.checkEncryption(false); - final PdfCatalog catalog = _getCatalogValue(); - if (catalog.containsKey(PdfDictionaryProperties.pages) && - !catalog.containsKey(PdfDictionaryProperties.type)) { - catalog.addItems( - PdfDictionaryProperties.type, - PdfName(PdfDictionaryProperties.catalog), - ); - } - if (catalog.containsKey(PdfDictionaryProperties.type)) { - if (!(catalog[PdfDictionaryProperties.type]! as PdfName).name!.contains( - PdfDictionaryProperties.catalog, - )) { - catalog[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.catalog, - ); - } - _setCatalog(catalog); - } else { - throw ArgumentError.value( - catalog, - 'Cannot find the PDF catalog information', - ); - } - bool hasVersion = false; - if (catalog.containsKey(PdfDictionaryProperties.version)) { - final PdfName? version = - catalog[PdfDictionaryProperties.version] as PdfName?; - if (version != null) { - _setFileVersion('PDF-${version.name!}'); - hasVersion = true; - } - } - if (!hasVersion) { - _readFileVersion(); - } - } else { - _helper.crossTable = PdfCrossTable(this); - _helper.crossTable.document = this; - _helper.catalog = PdfCatalog(); - _helper.objects.add(_helper.catalog); - _helper.catalog.position = -1; - _sections = PdfSectionCollectionHelper.load(this); - _pages = PdfPageCollectionHelper.load(this); - _helper.catalog.pages = _sections; - } - compressionLevel = PdfCompressionLevel.normal; - _helper.position = 0; - _helper.orderPosition = 0; - _helper.onPosition = 0; - _helper.offPosition = 0; - _helper.pdfPrimitive = PdfArray(); - _helper.on = PdfArray(); - _helper.off = PdfArray(); - _helper.order = PdfArray(); - _helper.printLayer = PdfArray(); - } - - void _copyOldStream(PdfWriter writer) { - writer.write(_data); - _helper.isStreamCopied = true; - } - - Future _copyOldStreamAsync(PdfWriter writer) async { - writer.writeAsync(_data); - _helper.isStreamCopied = true; - } - - void _appendDocument(PdfWriter writer) { - writer.document = this; - _helper.crossTable.save(writer); - PdfSecurityHelper.getHelper(security).encryptor.encrypt = true; - final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); - _onDocumentSaved(argsSaved); - } - - Future _appendDocumentAsync(PdfWriter writer) async { - writer.document = this; - await _helper.crossTable.saveAsync(writer).then((_) async { - PdfSecurityHelper.getHelper(security).encryptor.encrypt = true; - final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); - await _onDocumentSavedAsync(argsSaved); - }); - } - - void _readFileVersion() { - final PdfReader reader = PdfReader(_data); - reader.position = 0; - String token = reader.getNextToken()!; - if (token.startsWith('%')) { - token = reader.getNextToken()!; - _setFileVersion(token); - } - } - - void _setFileVersion(String token) { - switch (token) { - case 'PDF-1.4': - fileStructure.version = PdfVersion.version1_4; - break; - case 'PDF-1.0': - fileStructure.version = PdfVersion.version1_0; - //fileStructure.incrementalUpdate = false; - break; - case 'PDF-1.1': - fileStructure.version = PdfVersion.version1_1; - //fileStructure.incrementalUpdate = false; - break; - case 'PDF-1.2': - fileStructure.version = PdfVersion.version1_2; - //fileStructure.incrementalUpdate = false; - break; - case 'PDF-1.3': - fileStructure.version = PdfVersion.version1_3; - //fileStructure.incrementalUpdate = false; - break; - case 'PDF-1.5': - fileStructure.version = PdfVersion.version1_5; - break; - case 'PDF-1.6': - fileStructure.version = PdfVersion.version1_6; - break; - case 'PDF-1.7': - fileStructure.version = PdfVersion.version1_7; - break; - case 'PDF-2.0': - fileStructure.version = PdfVersion.version2_0; - break; - } - } - - PdfCatalog _getCatalogValue() { - final PdfCatalog catalog = PdfCatalog.fromDocument( - this, - _helper.crossTable.documentCatalog, - ); - final int index = - _helper.objects.lookFor(_helper.crossTable.documentCatalog!)!; - _helper.objects.reregisterReference(index, catalog); - catalog.position = -1; - return catalog; - } - - void _setCatalog(PdfCatalog catalog) { - _helper.catalog = catalog; - if (_helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { - final PdfReferenceHolder? outlines = - _helper.catalog[PdfDictionaryProperties.outlines] - as PdfReferenceHolder?; - PdfDictionary? dic; - if (outlines == null) { - dic = - _helper.catalog[PdfDictionaryProperties.outlines] as PdfDictionary?; - } else if (outlines.object is PdfDictionary) { - dic = outlines.object as PdfDictionary?; - } - if (dic != null && dic.containsKey(PdfDictionaryProperties.first)) { - final PdfReferenceHolder? first = - dic[PdfDictionaryProperties.first] as PdfReferenceHolder?; - if (first != null) { - final PdfDictionary? firstDic = first.object as PdfDictionary?; - if (firstDic == null) { - dic.remove(PdfDictionaryProperties.first); - } - } - } - } - } - - PdfPageCollection _getPageCollection() { - _pages ??= - _helper.isLoadedDocument - ? PdfPageCollectionHelper.fromCrossTable(this, _helper.crossTable) - : PdfPageCollectionHelper.load(this); - return _pages!; - } - - /// Creates a bookmarks collection to the document. - PdfBookmarkBase? _createBookmarkRoot() { - _bookmark = PdfBookmarkBaseHelper.loadInternal(); - return _bookmark; - } - - PdfNamedDestinationCollection? _createNamedDestinations() { - _namedDestinations = PdfNamedDestinationCollection(); - final PdfReferenceHolder? catalogReference = - _helper.catalog[PdfDictionaryProperties.names] as PdfReferenceHolder?; - - if (catalogReference != null) { - final PdfDictionary? catalogNames = - catalogReference.object as PdfDictionary?; - if (catalogNames != null) { - catalogNames.setProperty( - PdfDictionaryProperties.dests, - PdfReferenceHolder(_namedDestinations), - ); - } - } else { - _helper.catalog.setProperty( - PdfDictionaryProperties.names, - PdfReferenceHolder(_namedDestinations), - ); - } - _helper.catalog.modify(); - return _namedDestinations; - } - - void _readDocumentInfo() { - // Read document's info if present. - final PdfDictionary? info = - PdfCrossTable.dereference( - _helper.crossTable.trailer![PdfDictionaryProperties.info], - ) - as PdfDictionary?; - if (info != null && _documentInfo == null) { - _documentInfo = PdfDocumentInformationHelper.load( - _helper.catalog, - dictionary: info, - isLoaded: true, - conformance: _helper.conformanceLevel, - ); - } - if (info != null && - !info.changed! && - _helper.crossTable.trailer![PdfDictionaryProperties.info] - is PdfReferenceHolder) { - _documentInfo = PdfDocumentInformationHelper.load( - _helper.catalog, - dictionary: info, - isLoaded: true, - conformance: _helper.conformanceLevel, - ); - if (_helper.catalog.changed!) { - _documentInfo!.modificationDate = DateTime.now(); - } - if (_helper.objects.lookFor(IPdfWrapper.getElement(_documentInfo!)!)! > - -1) { - _helper.objects.reregisterReference( - _helper.objects.lookFor(info)!, - IPdfWrapper.getElement(_documentInfo!)!, - ); - IPdfWrapper.getElement(_documentInfo!)!.position = -1; - } - } - } - - Future _readDocumentInfoAsync() async { - // Read document's info if present. - final PdfDictionary? info = - PdfCrossTable.dereference( - _helper.crossTable.trailer![PdfDictionaryProperties.info], - ) - as PdfDictionary?; - if (info != null && _documentInfo == null) { - _documentInfo = PdfDocumentInformationHelper.load( - _helper.catalog, - dictionary: info, - isLoaded: true, - conformance: _helper.conformanceLevel, - ); - } - if (info != null && - !info.changed! && - _helper.crossTable.trailer![PdfDictionaryProperties.info] - is PdfReferenceHolder) { - _documentInfo = PdfDocumentInformationHelper.load( - _helper.catalog, - dictionary: info, - isLoaded: true, - conformance: _helper.conformanceLevel, - ); - if (_helper.catalog.changed!) { - _documentInfo!.modificationDate = DateTime.now(); - } - if ((await _helper.objects.lookForAsync( - IPdfWrapper.getElement(_documentInfo!)!, - ))! > - -1) { - await _helper.objects.reregisterReferenceAsync( - (await _helper.objects.lookForAsync(info))!, - IPdfWrapper.getElement(_documentInfo!)!, - ); - IPdfWrapper.getElement(_documentInfo!)!.position = -1; - } - } - } - - void _initializeConformance(PdfConformanceLevel conformance) { - _helper.conformanceLevel = conformance; - if (_helper.conformanceLevel == PdfConformanceLevel.a1b || - _helper.conformanceLevel == PdfConformanceLevel.a2b || - _helper.conformanceLevel == PdfConformanceLevel.a3b) { - //Note : PDF/A is based on Pdf 1.4. Hence it does not support cross reference - //stream which is an Pdf 1.5 feature. - fileStructure.crossReferenceType = - PdfCrossReferenceType.crossReferenceTable; - if (_helper.conformanceLevel == PdfConformanceLevel.a1b) { - fileStructure.version = PdfVersion.version1_4; - } else { - fileStructure.version = PdfVersion.version1_7; - } - //Embed the Color Profie. - final PdfDictionary dict = PdfDictionary(); - dict['Info'] = PdfString('sRGB IEC61966-2.1'); - dict['S'] = PdfName('GTS_PDFA1'); - dict['OutputConditionIdentifier'] = PdfString('custom'); - dict['Type'] = PdfName('OutputIntent'); - dict['OutputCondition'] = PdfString(''); - dict['RegistryName'] = PdfString(''); - final PdfICCColorProfile srgbProfile = PdfICCColorProfile(); - dict['DestOutputProfile'] = PdfReferenceHolder(srgbProfile); - final PdfArray outputIntent = PdfArray(); - outputIntent.add(dict); - _helper.catalog['OutputIntents'] = outputIntent; - } - } - - //Raises DocumentSaved event. - void _onDocumentSaved(DocumentSavedArgs args) { - if (_helper.documentSavedList != null && - _helper.documentSavedList!.isNotEmpty) { - for (int i = 0; i < _helper.documentSavedList!.length; i++) { - _helper.documentSavedList![i](this, args); - } - } - } - - Future _onDocumentSavedAsync(DocumentSavedArgs args) async { - if (_helper.documentSavedListAsync != null && - _helper.documentSavedListAsync!.isNotEmpty) { - for (int i = 0; i < _helper.documentSavedListAsync!.length; i++) { - await _helper.documentSavedListAsync![i](this, args); - } - } - } -} - -/// Delegate for handling the PDF password -/// -/// ```dart -/// //Load an existing PDF document -/// PdfDocument document = -/// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) -/// //Subsribe the onPdfPassword event -/// ..onPdfPassword = loadOnPdfPassword; -/// //Access the attachments -/// PdfAttachmentCollection attachmentCollection = document.attachments; -/// //Iterates the attachments -/// for (int i = 0; i < attachmentCollection.count; i++) { -/// //Extracts the attachment and saves it to the disk -/// File(attachmentCollection[i].fileName) -/// .writeAsBytesSync(attachmentCollection[i].data); -/// } -/// //Disposes the document -/// document.dispose(); -/// -/// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { -/// //Sets the value of PDF password. -/// args.attachmentOpenPassword = 'syncfusion'; -/// } -/// ``` -typedef PdfPasswordCallback = - void Function(PdfDocument sender, PdfPasswordArgs args); - -/// Arguments of Pdf Password. -/// -/// ```dart -/// //Load an existing PDF document -/// PdfDocument document = -/// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) -/// //Subsribe the onPdfPassword event -/// ..onPdfPassword = loadOnPdfPassword; -/// //Access the attachments -/// PdfAttachmentCollection attachmentCollection = document.attachments; -/// //Iterates the attachments -/// for (int i = 0; i < attachmentCollection.count; i++) { -/// //Extracts the attachment and saves it to the disk -/// File(attachmentCollection[i].fileName) -/// .writeAsBytesSync(attachmentCollection[i].data); -/// } -/// //Disposes the document -/// document.dispose(); -/// -/// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { -/// //Sets the value of PDF password. -/// args.attachmentOpenPassword = 'syncfusion'; -/// } -/// ``` -class PdfPasswordArgs { - PdfPasswordArgs._() { - attachmentOpenPassword = ''; - } - //Fields - /// A value of PDF password. - /// - /// ```dart - /// //Load an existing PDF document - /// PdfDocument document = - /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) - /// //Subsribe the onPdfPassword event - /// ..onPdfPassword = loadOnPdfPassword; - /// //Access the attachments - /// PdfAttachmentCollection attachmentCollection = document.attachments; - /// //Iterates the attachments - /// for (int i = 0; i < attachmentCollection.count; i++) { - /// //Extracts the attachment and saves it to the disk - /// File(attachmentCollection[i].fileName) - /// .writeAsBytesSync(attachmentCollection[i].data); - /// } - /// //Disposes the document - /// document.dispose(); - /// - /// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { - /// //Sets the value of PDF password. - /// args.attachmentOpenPassword = 'syncfusion'; - /// } - /// ``` - String? attachmentOpenPassword; -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfPasswordArgs] helper -class PdfPasswordArgsHelper { - /// internal method - static PdfPasswordArgs load() { - return PdfPasswordArgs._(); - } -} - -/// [PdfDocument] helper -class PdfDocumentHelper { - /// internal constructor - PdfDocumentHelper(this.base); - - /// internal field - PdfDocument base; - - /// internal method - static PdfDocumentHelper getHelper(PdfDocument base) { - return base._helper; - } - - /// internal constant - static const double defaultMargin = 40; - - /// internal field - List? documentSavedList; - - /// internal field - List? documentSavedListAsync; - - /// internal field - late PdfMainObjectCollection objects; - - /// internal field - late PdfCrossTable crossTable; - - /// internal field - late PdfCatalog catalog; - - /// internal field - bool isLoadedDocument = false; - - /// internal field - bool isStreamCopied = false; - - /// internal field - int? position; - - /// internal field - int? orderPosition; - - /// internal field - int? onPosition; - - /// internal field - int? offPosition; - - /// internal field - PdfArray? pdfPrimitive; - - /// internal field - PdfArray? printLayer; - - /// internal field - PdfArray? on; - - /// internal field - PdfArray? off; - - /// internal field - PdfArray? order; - - /// internal field - String? password; - - /// internal field - late bool isEncrypted; - - /// internal field - PdfConformanceLevel conformanceLevel = PdfConformanceLevel.none; - - /// internal method - PdfReference? currentSavingObject; - PdfSecurity? _security; - bool? _isAttachOnlyEncryption; - Map? _bookmarkHashTable; - - /// internal method - bool checkEncryption(bool? isAttachEncryption) { - bool wasEncrypted = false; - if (crossTable.encryptorDictionary != null) { - final PdfDictionary encryptionDict = crossTable.encryptorDictionary!; - password ??= ''; - final PdfDictionary trailerDict = crossTable.trailer!; - PdfArray? obj; - if (trailerDict.containsKey(PdfDictionaryProperties.id)) { - IPdfPrimitive? primitive = trailerDict[PdfDictionaryProperties.id]; - if (primitive is PdfArray) { - obj = primitive; - } else if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfArray) { - obj = primitive; - } - } - } - obj ??= PdfArray()..add(PdfString.fromBytes([])); - final PdfString key = obj[0]! as PdfString; - final PdfEncryptor encryptor = PdfEncryptor(); - if (encryptionDict.containsKey(PdfDictionaryProperties.encryptMetadata)) { - IPdfPrimitive? primitive = - encryptionDict[PdfDictionaryProperties.encryptMetadata]; - if (primitive is PdfBoolean) { - encryptor.encryptMetadata = primitive.value!; - } else if (primitive is PdfReferenceHolder) { - primitive = primitive.object; - if (primitive != null && primitive is PdfBoolean) { - encryptor.encryptMetadata = primitive.value!; - } - } - } - wasEncrypted = true; - encryptor.readFromDictionary(encryptionDict); - bool encryption = true; - if (!isAttachEncryption! && encryptor.encryptAttachmentOnly!) { - encryption = false; - } - if (!encryptor.checkPassword(password!, key, encryption)) { - throw ArgumentError.value( - password, - 'password', - 'Cannot open an encrypted document. The password is invalid.', - ); - } - encryptionDict.encrypt = false; - final PdfSecurity security = PdfSecurityHelper.getSecurity(); - PdfSecurityHelper.getHelper(security).encryptor = encryptor; - _security = security; - PdfSecurityHelper.getHelper(_security!).encryptAttachmentOnly = - encryptor.encryptAttachmentOnly!; - _isAttachOnlyEncryption = encryptor.encryptAttachmentOnly; - if (_isAttachOnlyEncryption!) { - PdfSecurityHelper.getHelper(security).encryptor.encryptionOptions = - PdfEncryptionOptions.encryptOnlyAttachments; - } else if (!encryptor.encryptMetadata) { - PdfSecurityHelper.getHelper(security).encryptor.encryptionOptions = - PdfEncryptionOptions.encryptAllContentsExceptMetadata; - } - crossTable.encryptor = encryptor; - } - return wasEncrypted; - } - - /// internal method - PdfArray? getNamedDestination(IPdfPrimitive obj) { - PdfDictionary? destinations; - PdfArray? destination; - if (obj is PdfName) { - destinations = catalog.destinations; - final IPdfPrimitive? name = destinations![obj]; - destination = _extractDestination(name); - } else if (obj is PdfString) { - final PdfCatalogNames? names = catalog.names; - if (names != null) { - destinations = names.destinations; - final IPdfPrimitive? name = names.getNamedObjectFromTree( - destinations, - obj, - ); - destination = _extractDestination(name); - } - } - return destination; - } - - PdfArray? _extractDestination(IPdfPrimitive? obj) { - PdfDictionary? dic; - if (obj is PdfDictionary) { - dic = obj; - } else if (obj is PdfReferenceHolder) { - final PdfReferenceHolder holder = obj; - if (holder.object is PdfDictionary) { - dic = holder.object as PdfDictionary?; - } else if (holder.object is PdfArray) { - obj = (holder.object! as PdfArray?)! as PdfReferenceHolder; - } - } - PdfArray? destination; - if (obj is PdfArray) { - destination = obj; - } - if (dic != null) { - obj = PdfCrossTable.dereference(dic[PdfDictionaryProperties.d]); - destination = obj as PdfArray?; - } - return destination; - } - - /// internal method - Map? createBookmarkDestinationDictionary() { - PdfBookmarkBase? current = base.bookmarks; - if (_bookmarkHashTable == null) { - _bookmarkHashTable = {}; - final Queue stack = Queue(); - CurrentNodeInfo ni = CurrentNodeInfo( - PdfBookmarkBaseHelper.getList(current), - ); - do { - for (; ni.index < ni.kids.length;) { - current = ni.kids[ni.index]; - final PdfNamedDestination? ndest = - (current! as PdfBookmark).namedDestination; - if (ndest != null) { - if (ndest.destination != null) { - final PdfPage page = ndest.destination!.page; - List? list; - if (_bookmarkHashTable!.containsKey(page)) { - list = _bookmarkHashTable![page] as List?; - } - if (list == null) { - list = []; - _bookmarkHashTable![page] = list; - } - list.add(current); - } - } else { - final PdfDestination? dest = (current as PdfBookmark).destination; - if (dest != null) { - final PdfPage page = dest.page; - List? list = - _bookmarkHashTable!.containsKey(page) - ? _bookmarkHashTable![page] as List? - : null; - if (list == null) { - list = []; - _bookmarkHashTable![page] = list; - } - list.add(current); - } - } - ni.index = ni.index + 1; - if (current.count > 0) { - stack.addLast(ni); - ni = CurrentNodeInfo(PdfBookmarkBaseHelper.getList(current)); - continue; - } - } - if (stack.isNotEmpty) { - ni = stack.removeLast(); - while ((ni.index == ni.kids.length) && (stack.isNotEmpty)) { - ni = stack.removeLast(); - } - } - } while (ni.index < ni.kids.length); - } - return _bookmarkHashTable; - } - - /// internal method - void setUserPassword(PdfPasswordArgs args) { - base.onPdfPassword!(base, args); - } - - /// Imports the FDF file bytes. - void importFdf(List inputBytes) { - final FdfParser parser = FdfParser(inputBytes); - parser.parseAnnotationData(); - parser.importAnnotations(base); - parser.dispose(); - } - - /// Imports the FDF file bytes. - void importJson(List inputBytes) { - final JsonParser parser = JsonParser(base); - parser.importAnnotationData(inputBytes); - } - - /// Imports the XFDF file bytes. - void importXfdf(List data) { - final XfdfParser parser = XfdfParser(data, base); - parser.parseAndImportAnnotationData(); - } - - /// Exports annotation to FDF file bytes. - List exportFdf( - String? fileName, - List? exportAnnotation, - List? exportTypes, - bool exportAppearance, - ) { - const String genNumber = - '${PdfOperators.whiteSpace}0${PdfOperators.whiteSpace}'; - const String startDictionary = '<<${PdfOperators.slash}'; - final List fdfBytes = []; - fdfBytes.addAll(utf8.encode('%FDF-1.2${PdfOperators.newLine}')); - int currentID = 2; - final List annotID = []; - final List annotType = []; - _getExportTypes(exportTypes, annotType); - if (exportAnnotation != null && exportAnnotation.isNotEmpty) { - for (int i = 0; i < exportAnnotation.length; i++) { - final PdfAnnotation annotation = exportAnnotation[i]; - final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( - annotation, - ); - if (helper.isLoadedAnnotation && - (annotType.isEmpty || - annotType.contains(_getAnnotationType(helper.dictionary!))) && - !(annotation is PdfLinkAnnotation || - annotation is PdfTextWebLink) && - annotation.page != null) { - final FdfDocument fdfDocument = FdfDocument( - helper.dictionary!, - annotation.page!, - ); - final Map result = fdfDocument.exportAnnotations( - currentID, - annotID, - base.pages.indexOf(annotation.page!), - _checkForStamp(helper.dictionary!) == 'Stamp' || exportAppearance, - ); - fdfBytes.addAll(result['exportData'] as List); - currentID = result['currentID'] as int; - } - } - } else { - for (int i = 0; i < base.pages.count; i++) { - final PdfPage page = base.pages[i]; - final PdfPageHelper pageHelper = PdfPageHelper.getHelper(page); - pageHelper.createAnnotations(pageHelper.getWidgetReferences()); - for (int j = 0; j < pageHelper.terminalAnnotation.length; j++) { - final PdfDictionary annotationDictionary = - pageHelper.terminalAnnotation[j]; - if ((annotType.isEmpty || - annotType.contains( - _getAnnotationType(annotationDictionary), - )) && - !isLinkAnnotation(annotationDictionary)) { - final FdfDocument fdfDocument = FdfDocument( - annotationDictionary, - page, - ); - final Map result = fdfDocument.exportAnnotations( - currentID, - annotID, - i, - _checkForStamp(annotationDictionary) == 'Stamp' || - exportAppearance, - ); - fdfBytes.addAll(result['exportData'] as List); - currentID = result['currentID'] as int; - } - } - } - } - fileName ??= ''; - if (currentID != 2) { - const String root = '1$genNumber'; - fdfBytes.addAll( - utf8.encode( - '${'$root${PdfOperators.obj}${PdfOperators.newLine}${startDictionary}FDF$startDictionary${PdfDictionaryProperties.annots}'}[', - ), - ); - for (int i = 0; i < annotID.length - 1; i++) { - fdfBytes.addAll( - utf8.encode( - '${annotID[i]}$genNumber${PdfDictionaryProperties.r}${PdfOperators.whiteSpace}', - ), - ); - } - fdfBytes.addAll( - utf8.encode( - '${annotID[annotID.length - 1]}$genNumber${PdfDictionaryProperties.r}]${PdfOperators.slash}${PdfDictionaryProperties.f}($fileName)${PdfOperators.slash}${PdfDictionaryProperties.uf}($fileName)>>${PdfOperators.slash}${PdfDictionaryProperties.type}${PdfOperators.slash}${PdfDictionaryProperties.catalog}>>${PdfOperators.newLine}${PdfOperators.endobj}${PdfOperators.newLine}', - ), - ); - fdfBytes.addAll( - utf8.encode( - '${PdfOperators.trailer}${PdfOperators.newLine}$startDictionary${PdfDictionaryProperties.root}${PdfOperators.whiteSpace}$root${PdfDictionaryProperties.r}>>${PdfOperators.newLine}${PdfOperators.endOfFileMarker}${PdfOperators.newLine}', - ), - ); - } - return fdfBytes; - } - - /// Exports annotation to JSON file bytes. - List exportJson( - String? fileName, - List? exportAnnotation, - List? exportTypes, - bool exportAppearance, - ) { - String json = '{"pdfAnnotation":{'; - bool isAnnotationAdded = false; - JsonDocument? jsonDocument = JsonDocument(base); - final Map table = {}; - final List annotType = []; - _getExportTypes(exportTypes, annotType); - if (exportAnnotation != null && exportAnnotation.isNotEmpty) { - final Map table1 = {}; - String? tempJson = ''; - for (int j = 0; j < exportAnnotation.length; j++) { - final PdfDictionary annotationDictionary = - PdfAnnotationHelper.getHelper(exportAnnotation[j]).dictionary!; - if ((annotType.isEmpty || - annotType.contains(_getAnnotationType(annotationDictionary))) && - exportAnnotation[j].page != null) { - final int pageIndex = base.pages.indexOf(exportAnnotation[j].page!); - if (pageIndex >= 0) { - if (table1.containsKey(pageIndex)) { - tempJson = '${table1[pageIndex]!},'; - } else { - tempJson = '"$pageIndex":{ "shapeAnnotation":['; - } - jsonDocument.exportAnnotationData( - table, - exportAppearance, - base.pages.indexOf(exportAnnotation[j].page!), - annotationDictionary, - ); - tempJson += jsonDocument.convertToJson(table); - table1[pageIndex] = tempJson; - table.clear(); - } - } - } - final List values = table1.values.toList(); - for (int i = 0; i < values.length; i++) { - json += table1[i]! + ((i < values.length - 1) ? ']},' : ']}'); - } - table1.clear(); - values.clear(); - } else { - for (int i = 0; i < base.pages.count; i++) { - final PdfPageHelper pageHelper = PdfPageHelper.getHelper(base.pages[i]); - pageHelper.createAnnotations(pageHelper.getWidgetReferences()); - if (pageHelper.terminalAnnotation.isNotEmpty) { - json += (i != 0 && isAnnotationAdded) ? ',' : ' '; - json += '"$i":{ "shapeAnnotation":['; - isAnnotationAdded = true; - } - for (int j = 0; j < pageHelper.terminalAnnotation.length; j++) { - final PdfDictionary annotationDictionary = - pageHelper.terminalAnnotation[j]; - if (annotType.isEmpty || - annotType.contains(_getAnnotationType(annotationDictionary))) { - jsonDocument.exportAnnotationData( - table, - exportAppearance, - i, - annotationDictionary, - ); - json += jsonDocument.convertToJson(table); - if (j < pageHelper.terminalAnnotation.length - 1) { - json += ','; - } - table.clear(); - } - } - if (pageHelper.terminalAnnotation.isNotEmpty) { - json += ']}'; - } - } - } - jsonDocument = null; - json += '}}'; - return utf8.encode(json); - } - - /// Exports annotation to XFDF file bytes. - List exportXfdf( - String? fileName, - List? exportAnnotation, - List? exportTypes, - bool exportAppearance, - ) { - final XFdfDocument xfdf = XFdfDocument(fileName ?? ''); - final List elements = []; - final List annotType = []; - _getExportTypes(exportTypes, annotType); - if (exportAnnotation != null && exportAnnotation.isNotEmpty) { - for (int j = 0; j < exportAnnotation.length; j++) { - if (annotType.isEmpty || - annotType.contains( - _getAnnotationType( - PdfAnnotationHelper.getHelper(exportAnnotation[j]).dictionary!, - ), - )) { - final XmlElement? element = xfdf.exportAnnotationData( - PdfAnnotationHelper.getHelper(exportAnnotation[j]).dictionary!, - base.pages.indexOf(exportAnnotation[j].page!), - exportAppearance, - base, - ); - if (element != null) { - elements.add(element); - } - } - } - } else { - for (int i = 0; i < base.pages.count; i++) { - final PdfPageHelper pageHelper = PdfPageHelper.getHelper(base.pages[i]); - pageHelper.createAnnotations(pageHelper.getWidgetReferences()); - for (int j = 0; j < pageHelper.terminalAnnotation.length; j++) { - final PdfDictionary annotationDictionary = - pageHelper.terminalAnnotation[j]; - if (annotType.isEmpty || - annotType.contains(_getAnnotationType(annotationDictionary))) { - final XmlElement? element = xfdf.exportAnnotationData( - annotationDictionary, - i, - exportAppearance, - base, - ); - if (element != null) { - elements.add(element); - } - } - } - } - } - return xfdf.save(elements); - } - - void _getExportTypes( - List? types, - List annotType, - ) { - if (types != null && types.isNotEmpty) { - for (int i = 0; i < types.length; i++) { - String annotationType = getEnumName(types[i]); - switch (annotationType) { - case 'HighlightAnnotation': - annotationType = 'Highlight'; - break; - case 'UnderlineAnnotation': - annotationType = 'Underline'; - break; - case 'StrikeOutAnnotation': - annotationType = 'StrikeOut'; - break; - case 'SquigglyAnnotation': - annotationType = 'Squiggly'; - break; - } - annotType.add(annotationType); - } - } - } - - String _getAnnotationType(PdfDictionary dictionary) { - if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final PdfName name = - PdfAnnotationHelper.getValue( - dictionary, - crossTable, - PdfDictionaryProperties.subtype, - true, - )! - as PdfName; - final PdfAnnotationTypes type = - PdfAnnotationCollectionHelper.getAnnotationType( - name, - dictionary, - crossTable, - ); - return getEnumName(type); - } - return ''; - } - - String _checkForStamp(PdfDictionary dictionary) { - if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? name = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.subtype], - ); - if (name != null && name is PdfName) { - return name.name ?? ''; - } - } - return ''; - } - - /// Internal method. - static bool isLinkAnnotation(PdfDictionary annotationDictionary) { - if (annotationDictionary.containsKey(PdfDictionaryProperties.subtype)) { - final IPdfPrimitive? name = PdfCrossTable.dereference( - annotationDictionary[PdfDictionaryProperties.subtype], - ); - if (name != null && name is PdfName) { - return name.name == 'Link'; - } - } - return false; - } -} +import 'dart:collection'; +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:xml/xml.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/enum.dart'; +import '../annotations/fdf_document.dart'; +import '../annotations/fdf_parser.dart'; +import '../annotations/json_document.dart'; +import '../annotations/json_parser.dart'; +import '../annotations/pdf_action_annotation.dart'; +import '../annotations/pdf_annotation.dart'; +import '../annotations/pdf_annotation_collection.dart'; +import '../annotations/pdf_text_web_link.dart'; +import '../annotations/xfdf_parser.dart'; +import '../color_space/pdf_icc_color_profile.dart'; +import '../forms/pdf_form.dart'; +import '../forms/pdf_form_field_collection.dart'; +import '../forms/pdf_xfdf_document.dart'; +import '../general/file_specification_base.dart'; +import '../general/pdf_destination.dart'; +import '../general/pdf_named_destination.dart'; +import '../general/pdf_named_destination_collection.dart'; +import '../graphics/brushes/pdf_brush.dart'; +import '../graphics/enums.dart'; +import '../graphics/pdf_pens.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_main_object_collection.dart'; +import '../io/pdf_reader.dart'; +import '../io/pdf_writer.dart'; +import '../pages/pdf_layer_collection.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_collection.dart'; +import '../pages/pdf_page_settings.dart'; +import '../pages/pdf_section_collection.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_reference.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import '../security/digital_signature/pdf_signature_dictionary.dart'; +import '../security/enum.dart'; +import '../security/pdf_encryptor.dart'; +import '../security/pdf_security.dart'; +import 'attachments/pdf_attachment_collection.dart'; +import 'enums.dart'; +import 'outlines/pdf_outline.dart'; +import 'pdf_catalog.dart'; +import 'pdf_catalog_names.dart'; +import 'pdf_document_information.dart'; +import 'pdf_document_template.dart'; +import 'pdf_file_structure.dart'; + +/// Represents a PDF document and can be used to create a new PDF document +/// from the scratch. +class PdfDocument { + //Constructor + /// Initialize a new instance of the [PdfDocument] class + /// from the PDF data as list of bytes + /// + /// To initialize a new instance of the [PdfDocument] class for an exisitng + /// PDF document, we can use the named parameters + /// to load PDF data and password + /// or add conformance level to the PDF + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Add a PDF page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', + /// PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// bounds: Rect.fromLTWH(0, 0, 150, 20)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfDocument({ + List? inputBytes, + PdfConformanceLevel? conformanceLevel, + String? password, + }) { + _helper = PdfDocumentHelper(this); + _helper.isLoadedDocument = inputBytes != null; + _helper.password = password; + _initialize(inputBytes); + if (!_helper.isLoadedDocument && conformanceLevel != null) { + _initializeConformance(conformanceLevel); + } + } + + /// Initialize a new instance of the [PdfDocument] class + /// from the PDF data as base64 string + /// + /// If the document is encrypted, then we have to provide open or permission + /// passwords to load PDF document + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData); + /// //Add a PDF page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', + /// PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfSolidBrush(PdfColor(0, 0, 0)), + /// bounds: Rect.fromLTWH(0, 0, 150, 20)); + /// //Save the updated PDF document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfDocument.fromBase64String(String base64String, {String? password}) { + _helper = PdfDocumentHelper(this); + if (base64String.isEmpty) { + ArgumentError.value(base64String, 'PDF data', 'PDF data cannot be null'); + } + _helper.password = password; + _helper.isLoadedDocument = true; + _initialize(base64.decode(base64String)); + } + + //Fields + late PdfDocumentHelper _helper; + PdfPageCollection? _pages; + PdfPageSettings? _settings; + PdfSectionCollection? _sections; + PdfFileStructure? _fileStructure; + PdfColorSpace? _colorSpace; + PdfDocumentTemplate? _template; + PdfBookmarkBase? _outlines; + PdfNamedDestinationCollection? _namedDestinations; + List? _data; + PdfBookmarkBase? _bookmark; + PdfDocumentInformation? _documentInfo; + PdfLayerCollection? _layers; + PdfAttachmentCollection? _attachments; + PdfForm? _form; + + /// Gets or sets the PDF document compression level. + PdfCompressionLevel? compressionLevel; + + /// The event raised on Pdf password. + /// + /// ```dart + /// //Load an existing PDF document + /// PdfDocument document = + /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) + /// //Subsribe the onPdfPassword event + /// ..onPdfPassword = loadOnPdfPassword; + /// //Access the attachments + /// PdfAttachmentCollection attachmentCollection = document.attachments; + /// //Iterates the attachments + /// for (int i = 0; i < attachmentCollection.count; i++) { + /// //Extracts the attachment and saves it to the disk + /// File(attachmentCollection[i].fileName) + /// .writeAsBytesSync(attachmentCollection[i].data); + /// } + /// //Disposes the document + /// document.dispose(); + /// + /// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { + /// //Sets the value of PDF password. + /// args.attachmentOpenPassword = 'syncfusion'; + /// } + /// ``` + PdfPasswordCallback? onPdfPassword; + + //Properties + /// Gets the security features of the document like encryption. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Document security + /// PdfSecurity security = document.security; + /// //Set security options + /// security.keySize = PdfEncryptionKeySize.key128Bit; + /// security.algorithm = PdfEncryptionAlgorithm.rc4; + /// security.userPassword = 'password'; + /// security.ownerPassword = 'syncfusion'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfSecurity get security { + _helper._security ??= PdfSecurityHelper.getSecurity(); + if (_helper.conformanceLevel != PdfConformanceLevel.none) { + PdfSecurityHelper.getHelper(_helper._security!).conformance = true; + } + return _helper._security!; + } + + /// Gets the collection of the sections in the document. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Add a new section. + /// PdfSection section = document.sections!.add(); + /// //Create page for the newly added section and draw text. + /// section.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfSectionCollection? get sections => _sections; + + /// Gets the document's page setting. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Get the document page settings. + /// document.pageSettings.margins.all = 50; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfPageSettings get pageSettings { + if (_settings == null) { + _settings = PdfPageSettings(); + _settings!.setMargins(PdfDocumentHelper.defaultMargin); + } + return _settings!; + } + + /// Sets the document's page setting. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Create a PDF page settings. + /// PdfPageSettings settings = PdfPageSettings(); + /// settings.margins.all = 50; + /// //Set the page settings to document. + /// document.pageSettings = settings; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + set pageSettings(PdfPageSettings settings) { + _settings = settings; + } + + /// Gets a template to all pages in the document. + PdfDocumentTemplate get template { + _template ??= PdfDocumentTemplate(); + return _template!; + } + + /// Sets a template to all pages in the document. + set template(PdfDocumentTemplate value) { + _template = value; + } + + /// Gets the color space of the document. + /// This property can be used to create PDF document in RGB, + /// Grayscale or CMYK color spaces. + /// + /// By default the document uses RGB color space. + PdfColorSpace get colorSpace { + if ((_colorSpace == PdfColorSpace.rgb) || + ((_colorSpace == PdfColorSpace.cmyk) || + (_colorSpace == PdfColorSpace.grayScale))) { + return _colorSpace!; + } else { + return PdfColorSpace.rgb; + } + } + + /// Sets the color space of the document. + /// This property can be used to create PDF document in RGB, + /// Grayscale or CMYK color spaces. + /// + /// By default the document uses RGB color space. + set colorSpace(PdfColorSpace value) { + if ((value == PdfColorSpace.rgb) || + ((value == PdfColorSpace.cmyk) || (value == PdfColorSpace.grayScale))) { + _colorSpace = value; + } else { + _colorSpace = PdfColorSpace.rgb; + } + } + + /// Gets the internal structure of the PDF document. + PdfFileStructure get fileStructure { + _fileStructure ??= PdfFileStructure(); + return _fileStructure!; + } + + /// Sets the internal structure of the PDF document. + set fileStructure(PdfFileStructure value) { + _fileStructure = value; + } + + /// Gets the collection of pages in the document. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Get the page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfPageCollection get pages => _getPageCollection(); + + /// Gets the bookmark collection of the document. + /// + /// ```dart + /// //Create a new document. + /// PdfDocument document = PdfDocument(); + /// //Create document bookmarks. + /// document.bookmarks.add('Interactive Feature') + /// ..destination = PdfDestination(document.pages.add(), Offset(20, 20)) + /// ..textStyle = [PdfTextStyle.bold] + /// ..color = PdfColor(255, 0, 0); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBookmarkBase get bookmarks { + if (_helper.isLoadedDocument) { + if (_bookmark == null) { + if (_helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { + final IPdfPrimitive? outlines = PdfCrossTable.dereference( + _helper.catalog[PdfDictionaryProperties.outlines], + ); + if (outlines != null && outlines is PdfDictionary) { + _bookmark = PdfBookmarkBaseHelper.loaded( + outlines, + _helper.crossTable, + ); + PdfBookmarkBaseHelper.getHelper(_bookmark!).reproduceTree(); + } else { + _bookmark = _createBookmarkRoot(); + } + } else { + _bookmark = _createBookmarkRoot(); + } + } + return _bookmark!; + } else { + if (_outlines == null) { + _outlines = PdfBookmarkBaseHelper.loadInternal(); + _helper.catalog[PdfDictionaryProperties.outlines] = PdfReferenceHolder( + _outlines, + ); + } + return _outlines!; + } + } + + /// Gets the named destination collection of the document. + PdfNamedDestinationCollection get namedDestinationCollection { + if (_helper.isLoadedDocument) { + if (_namedDestinations == null) { + if (_helper.catalog.containsKey(PdfDictionaryProperties.names) && + (_namedDestinations == null)) { + final PdfDictionary? namedDestinations = + PdfCrossTable.dereference( + _helper.catalog[PdfDictionaryProperties.names], + ) + as PdfDictionary?; + _namedDestinations = PdfNamedDestinationCollectionHelper.load( + namedDestinations, + _helper.crossTable, + ); + } + _namedDestinations ??= _createNamedDestinations(); + } + return _namedDestinations!; + } else { + if (_namedDestinations == null) { + _namedDestinations = PdfNamedDestinationCollection(); + _helper.catalog[PdfDictionaryProperties.names] = PdfReferenceHolder( + _namedDestinations, + ); + final PdfReferenceHolder? names = + _helper.catalog[PdfDictionaryProperties.names] + as PdfReferenceHolder?; + if (names != null) { + final PdfDictionary? dic = names.object as PdfDictionary?; + if (dic != null) { + dic[PdfDictionaryProperties.dests] = PdfReferenceHolder( + _namedDestinations, + ); + } + } + } + return _namedDestinations!; + } + } + + /// Gets document's information and properties such as document's title, subject, keyword etc. + PdfDocumentInformation get documentInformation { + if (_documentInfo == null) { + if (_helper.isLoadedDocument) { + final PdfDictionary trailer = _helper.crossTable.trailer!; + if (PdfCrossTable.dereference(trailer[PdfDictionaryProperties.info]) + is PdfDictionary) { + final PdfDictionary? entry = + PdfCrossTable.dereference(trailer[PdfDictionaryProperties.info]) + as PdfDictionary?; + _documentInfo = PdfDocumentInformationHelper.load( + _helper.catalog, + dictionary: entry, + isLoaded: true, + conformance: _helper.conformanceLevel, + ); + } else { + _documentInfo = PdfDocumentInformationHelper.load( + _helper.catalog, + conformance: _helper.conformanceLevel, + ); + _helper.crossTable.trailer![PdfDictionaryProperties + .info] = PdfReferenceHolder(_documentInfo); + } + // Read document's info dictionary if present. + _readDocumentInfo(); + } else { + _documentInfo = PdfDocumentInformationHelper.load( + _helper.catalog, + conformance: _helper.conformanceLevel, + ); + _helper.crossTable.trailer![PdfDictionaryProperties + .info] = PdfReferenceHolder(_documentInfo); + } + } + return _documentInfo!; + } + + /// Gets the collection of PdfLayer from the PDF document. + PdfLayerCollection get layers { + _layers ??= PdfLayerCollectionHelper.load(this); + return _layers!; + } + + /// Gets the attachment collection of the document. + PdfAttachmentCollection get attachments { + if (_attachments == null) { + if (!_helper.isLoadedDocument) { + _attachments = PdfAttachmentCollection(); + if (_helper.conformanceLevel == PdfConformanceLevel.a1b || + _helper.conformanceLevel == PdfConformanceLevel.a2b) { + PdfAttachmentCollectionHelper.getHelper(_attachments!).conformance = + true; + } + _helper.catalog.names!.embeddedFiles = _attachments!; + } else { + if (onPdfPassword != null && _helper.password == '') { + final PdfPasswordArgs args = PdfPasswordArgs._(); + onPdfPassword!(this, args); + _helper.password = args.attachmentOpenPassword; + } + if (_helper._isAttachOnlyEncryption!) { + _helper.checkEncryption(_helper._isAttachOnlyEncryption); + } + final IPdfPrimitive? attachmentDictionary = PdfCrossTable.dereference( + _helper.catalog[PdfDictionaryProperties.names], + ); + if (attachmentDictionary != null && + attachmentDictionary is PdfDictionary && + attachmentDictionary.containsKey( + PdfDictionaryProperties.embeddedFiles, + )) { + _attachments = PdfAttachmentCollectionHelper.load( + attachmentDictionary, + _helper.crossTable, + ); + } else { + _attachments = PdfAttachmentCollection(); + _helper.catalog.names!.embeddedFiles = _attachments!; + } + } + } + return _attachments!; + } + + /// Gets the interactive form of the document. + PdfForm get form { + if (_helper.isLoadedDocument) { + if (_form == null) { + if (_helper.catalog.containsKey(PdfDictionaryProperties.acroForm)) { + final IPdfPrimitive? formDictionary = PdfCrossTable.dereference( + _helper.catalog[PdfDictionaryProperties.acroForm], + ); + if (formDictionary is PdfDictionary) { + _form = PdfFormHelper.internal(_helper.crossTable, formDictionary); + if (_form != null && _form!.fields.count != 0) { + _helper.catalog.form = _form; + List? widgetReference; + if (PdfFormHelper.getHelper(_form!).crossTable!.document != + null) { + for ( + int i = 0; + i < + PdfFormHelper.getHelper( + _form!, + ).crossTable!.document!.pages.count; + i++ + ) { + final PdfPage page = + PdfFormHelper.getHelper( + _form!, + ).crossTable!.document!.pages[i]; + widgetReference ??= + PdfPageHelper.getHelper(page).getWidgetReferences(); + if (widgetReference.isNotEmpty) { + PdfPageHelper.getHelper( + page, + ).createAnnotations(widgetReference); + } + } + if (widgetReference != null) { + widgetReference.clear(); + } + if (!PdfFormHelper.getHelper(_form!).formHasKids) { + PdfFormFieldCollectionHelper.getHelper( + _form!.fields, + ).createFormFieldsFromWidgets(_form!.fields.count); + } + } + } + return _form!; + } + } + _form = PdfFormHelper.internal(_helper.crossTable); + _helper.catalog.setProperty( + PdfDictionaryProperties.acroForm, + PdfReferenceHolder(_form), + ); + _helper.catalog.form = _form; + return _form!; + } else { + return _form!; + } + } else { + return _helper.catalog.form ??= PdfForm(); + } + } + + //Public methods + /// Saves the document and return the saved bytes as Uint8List. + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Get the page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// Uint8List bytes = document.saveAsBytesSync(); + /// document.dispose(); + /// ``` + Uint8List saveAsBytesSync() { + final PdfBytesBuilder buffer = PdfBytesBuilder(); + final PdfWriter writer = PdfWriter(null, buffer); + _saveDocument(writer); + final Uint8List bytes = buffer.takeBytes(); + buffer.clear(); + return bytes; + } + + /// Saves the document and return the saved bytes as list of int. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Get the page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = document.saveSync(); + /// document.dispose(); + /// ``` + List saveSync() { + final List buffer = []; + final PdfWriter writer = PdfWriter(buffer); + _saveDocument(writer); + return writer.buffer!; + } + + /// Internal method to save the PDF document. + void _saveDocument(PdfWriter writer) { + writer.document = this; + _checkPages(); + if (_helper.isLoadedDocument && + _bookmark != null && + _bookmark!.count > 0 && + _helper.crossTable.documentCatalog != null && + !_helper.crossTable.documentCatalog!.containsKey( + PdfDictionaryProperties.outlines, + )) { + _helper.catalog.setProperty( + PdfDictionaryProperties.outlines, + PdfReferenceHolder(_bookmark), + ); + } else if (_bookmark != null && + _bookmark!.count < 1 && + _helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { + _helper.catalog.remove(PdfDictionaryProperties.outlines); + } + if (PdfSecurityHelper.getHelper(security).encryptAttachments && + security.userPassword == '') { + throw ArgumentError.value( + 'User password cannot be empty for encrypt only attachment.', + ); + } + if (_helper.isLoadedDocument) { + if (_helper._security != null) { + if (PdfSecurityHelper.getHelper( + _helper._security!, + ).encryptAttachments) { + fileStructure.incrementalUpdate = false; + if (PdfSecurityHelper.getHelper( + _helper._security!, + ).encryptor.userPassword.isEmpty) { + PdfSecurityHelper.getHelper(_helper._security!) + .encryptor + .encryptOnlyAttachment = false; + } + } + } + if (fileStructure.incrementalUpdate && + (_helper._security == null || + (_helper._security != null && + !PdfSecurityHelper.getHelper( + _helper._security!, + ).modifiedSecurity && + !PdfPermissionsHelper.isModifiedPermissions( + _helper._security!.permissions, + )))) { + _copyOldStream(writer); + if (_helper.catalog.changed!) { + _readDocumentInfo(); + } + } else { + _helper.crossTable = PdfCrossTable.fromCatalog( + _helper.crossTable.count, + _helper.crossTable.encryptorDictionary, + _helper.crossTable.pdfDocumentCatalog, + ); + _helper.crossTable.document = this; + _helper.crossTable.trailer![PdfDictionaryProperties + .info] = PdfReferenceHolder(documentInformation); + } + _appendDocument(writer); + } else { + if (_helper.conformanceLevel == PdfConformanceLevel.a1b || + _helper.conformanceLevel == PdfConformanceLevel.a2b || + _helper.conformanceLevel == PdfConformanceLevel.a3b) { + PdfDocumentInformationHelper.getHelper(documentInformation).xmpMetadata; + if (_helper.conformanceLevel == PdfConformanceLevel.a3b && + _helper.catalog.names != null && + attachments.count > 0) { + final PdfName fileRelationShip = PdfName( + PdfDictionaryProperties.afRelationship, + ); + final PdfArray fileAttachmentAssociationArray = PdfArray(); + for (int i = 0; i < attachments.count; i++) { + if (!PdfFileSpecificationBaseHelper.getHelper( + attachments[i], + ).dictionary!.items!.containsKey(fileRelationShip)) { + PdfFileSpecificationBaseHelper.getHelper( + attachments[i], + ).dictionary!.items![fileRelationShip] = PdfName('Alternative'); + } + fileAttachmentAssociationArray.add( + PdfReferenceHolder( + PdfFileSpecificationBaseHelper.getHelper( + attachments[i], + ).dictionary, + ), + ); + } + _helper.catalog.items![PdfName(PdfDictionaryProperties.af)] = + fileAttachmentAssociationArray; + } + } + _helper.crossTable.save(writer); + final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); + _onDocumentSaved(argsSaved); + } + } + + /// Saves the document and return the saved bytes as feature Uint8List. + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Get the page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// Uint8List bytes = await document.saveAsBytes(); + /// document.dispose(); + /// ``` + Future saveAsBytes() async { + final PdfBytesBuilder buffer = PdfBytesBuilder(); + final PdfWriter writer = PdfWriter(null, buffer); + await _saveDocumentAsync(writer); + final Uint8List bytes = buffer.takeBytes(); + buffer.clear(); + return bytes; + } + + /// Saves the document and return the saved bytes as future list of int. + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Get the page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + Future> save() async { + final List buffer = []; + final PdfWriter writer = PdfWriter(buffer); + await _saveDocumentAsync(writer); + return writer.buffer!; + } + + /// Internal method to save the PDF document + Future _saveDocumentAsync(PdfWriter writer) async { + writer.document = this; + await _checkPagesAsync(); + if (_helper.isLoadedDocument && + _bookmark != null && + _bookmark!.count > 0 && + _helper.crossTable.documentCatalog != null && + !_helper.crossTable.documentCatalog!.containsKey( + PdfDictionaryProperties.outlines, + )) { + _helper.catalog.setProperty( + PdfDictionaryProperties.outlines, + PdfReferenceHolder(_bookmark), + ); + } else if (_outlines != null && + _outlines!.count < 1 && + _helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { + _helper.catalog.remove(PdfDictionaryProperties.outlines); + } + if (PdfSecurityHelper.getHelper(security).encryptAttachments && + security.userPassword == '') { + throw ArgumentError.value( + 'User password cannot be empty for encrypt only attachment.', + ); + } + if (_helper.isLoadedDocument) { + if (_helper._security != null) { + if (PdfSecurityHelper.getHelper( + _helper._security!, + ).encryptAttachments) { + fileStructure.incrementalUpdate = false; + if (PdfSecurityHelper.getHelper( + _helper._security!, + ).encryptor.userPassword.isEmpty) { + PdfSecurityHelper.getHelper(_helper._security!) + .encryptor + .encryptOnlyAttachment = false; + } + } + } + if (fileStructure.incrementalUpdate && + (_helper._security == null || + (_helper._security != null && + !PdfSecurityHelper.getHelper( + _helper._security!, + ).modifiedSecurity && + !PdfPermissionsHelper.isModifiedPermissions( + _helper._security!.permissions, + )))) { + await _copyOldStreamAsync(writer).then((_) { + if (_helper.catalog.changed!) { + _readDocumentInfoAsync(); + } + }); + } else { + _helper.crossTable = PdfCrossTable.fromCatalog( + _helper.crossTable.count, + _helper.crossTable.encryptorDictionary, + _helper.crossTable.pdfDocumentCatalog, + ); + _helper.crossTable.document = this; + _helper.crossTable.trailer![PdfDictionaryProperties + .info] = PdfReferenceHolder(documentInformation); + } + await _appendDocumentAsync(writer); + } else { + if (_helper.conformanceLevel == PdfConformanceLevel.a1b || + _helper.conformanceLevel == PdfConformanceLevel.a2b || + _helper.conformanceLevel == PdfConformanceLevel.a3b) { + PdfDocumentInformationHelper.getHelper(documentInformation).xmpMetadata; + if (_helper.conformanceLevel == PdfConformanceLevel.a3b && + _helper.catalog.names != null && + attachments.count > 0) { + final PdfName fileRelationShip = PdfName( + PdfDictionaryProperties.afRelationship, + ); + final PdfArray fileAttachmentAssociationArray = PdfArray(); + for (int i = 0; i < attachments.count; i++) { + if (!PdfFileSpecificationBaseHelper.getHelper( + attachments[i], + ).dictionary!.items!.containsKey(fileRelationShip)) { + PdfFileSpecificationBaseHelper.getHelper( + attachments[i], + ).dictionary!.items![fileRelationShip] = PdfName('Alternative'); + } + fileAttachmentAssociationArray.add( + PdfReferenceHolder( + PdfFileSpecificationBaseHelper.getHelper( + attachments[i], + ).dictionary, + ), + ); + } + _helper.catalog.items![PdfName(PdfDictionaryProperties.af)] = + fileAttachmentAssociationArray; + } + } + await _helper.crossTable.saveAsync(writer); + final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); + await _onDocumentSavedAsync(argsSaved); + } + } + + void _checkPages() { + if (!_helper.isLoadedDocument) { + if (pages.count == 0) { + pages.add(); + } + } + } + + Future _checkPagesAsync() async { + if (!_helper.isLoadedDocument) { + if (pages.count == 0) { + pages.add(); + } + } + } + + /// Releases all the resources used by document instances. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Get the page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + void dispose() { + PdfBrushesHelper.dispose(); + PdfPensHelper.dispose(); + _helper.crossTable.dispose(); + _helper._security = null; + _helper.currentSavingObject = null; + } + + /// Export the annotation data to UTF8 bytes with the specific [PdfAnnotationDataFormat]. + /// + /// To export specific annotations, annotation types, appearances, and + /// add a file name to the export format, we can use the named parameters + /// exportList, exportTypes, exportAppearance, and fileName respectively. + /// + /// ```dart + /// //Load an existing PDF document. + /// PdfDocument document = + /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + /// //Export annotations in specific PdfAnnotationDataFormat format. + /// List bytes = document.exportAnnotation(PdfAnnotationDataFormat.fdf, + /// fileName: 'PDFExportDocument'); + /// //Save the exported data. + /// File('export.fdf').writeAsBytesSync(bytes); + /// //Dispose the document. + /// document.dispose(); + /// ``` + List exportAnnotation( + PdfAnnotationDataFormat format, { + String? fileName, + List? exportList, + List? exportTypes, + bool exportAppearance = false, + }) { + List bytes = []; + if (format == PdfAnnotationDataFormat.xfdf) { + bytes = _helper.exportXfdf( + fileName, + exportList, + exportTypes, + exportAppearance, + ); + } else if (format == PdfAnnotationDataFormat.fdf) { + bytes = _helper.exportFdf( + fileName, + exportList, + exportTypes, + exportAppearance, + ); + } else if (format == PdfAnnotationDataFormat.json) { + bytes = _helper.exportJson( + fileName, + exportList, + exportTypes, + exportAppearance, + ); + } + return bytes; + } + + /// Import the annotation data from UTF8 bytes with the specific [PdfAnnotationDataFormat]. + /// + /// ```dart + /// //Load an existing PDF document. + /// PdfDocument document = + /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + /// //Import annotations in specific PdfAnnotationDataFormat format. + /// document.importAnnotation( + /// File('input.fdf').readAsBytesSync(), PdfAnnotationDataFormat.fdf); + /// //Save the document. + /// File('output.pdf').writeAsBytesSync(await document.save()); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void importAnnotation(List data, PdfAnnotationDataFormat format) { + if (format == PdfAnnotationDataFormat.xfdf) { + _helper.importXfdf(data); + } else if (format == PdfAnnotationDataFormat.fdf) { + _helper.importFdf(data); + } else if (format == PdfAnnotationDataFormat.json) { + _helper.importJson(data); + } + } + + //Implementation + void _initialize(List? pdfData) { + _helper._isAttachOnlyEncryption = false; + _helper.isEncrypted = false; + _data = pdfData; + _helper.objects = PdfMainObjectCollection(); + if (_helper.isLoadedDocument) { + _helper.crossTable = PdfCrossTable(this, pdfData); + _helper.isEncrypted = _helper.checkEncryption(false); + final PdfCatalog catalog = _getCatalogValue(); + if (catalog.containsKey(PdfDictionaryProperties.pages) && + !catalog.containsKey(PdfDictionaryProperties.type)) { + catalog.addItems( + PdfDictionaryProperties.type, + PdfName(PdfDictionaryProperties.catalog), + ); + } + if (catalog.containsKey(PdfDictionaryProperties.type)) { + if (!(catalog[PdfDictionaryProperties.type]! as PdfName).name!.contains( + PdfDictionaryProperties.catalog, + )) { + catalog[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.catalog, + ); + } + _setCatalog(catalog); + } else { + throw ArgumentError.value( + catalog, + 'Cannot find the PDF catalog information', + ); + } + bool hasVersion = false; + if (catalog.containsKey(PdfDictionaryProperties.version)) { + final PdfName? version = + catalog[PdfDictionaryProperties.version] as PdfName?; + if (version != null) { + _setFileVersion('PDF-${version.name!}'); + hasVersion = true; + } + } + if (!hasVersion) { + _readFileVersion(); + } + } else { + _helper.crossTable = PdfCrossTable(this); + _helper.crossTable.document = this; + _helper.catalog = PdfCatalog(); + _helper.objects.add(_helper.catalog); + _helper.catalog.position = -1; + _sections = PdfSectionCollectionHelper.load(this); + _pages = PdfPageCollectionHelper.load(this); + _helper.catalog.pages = _sections; + } + compressionLevel = PdfCompressionLevel.normal; + _helper.position = 0; + _helper.orderPosition = 0; + _helper.onPosition = 0; + _helper.offPosition = 0; + _helper.pdfPrimitive = PdfArray(); + _helper.on = PdfArray(); + _helper.off = PdfArray(); + _helper.order = PdfArray(); + _helper.printLayer = PdfArray(); + } + + void _copyOldStream(PdfWriter writer) { + writer.write(_data); + _helper.isStreamCopied = true; + } + + Future _copyOldStreamAsync(PdfWriter writer) async { + writer.writeAsync(_data); + _helper.isStreamCopied = true; + } + + void _appendDocument(PdfWriter writer) { + writer.document = this; + _helper.crossTable.save(writer); + PdfSecurityHelper.getHelper(security).encryptor.encrypt = true; + final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); + _onDocumentSaved(argsSaved); + } + + Future _appendDocumentAsync(PdfWriter writer) async { + writer.document = this; + await _helper.crossTable.saveAsync(writer).then((_) async { + PdfSecurityHelper.getHelper(security).encryptor.encrypt = true; + final DocumentSavedArgs argsSaved = DocumentSavedArgs(writer); + await _onDocumentSavedAsync(argsSaved); + }); + } + + void _readFileVersion() { + final PdfReader reader = PdfReader(_data); + reader.position = 0; + String token = reader.getNextToken()!; + if (token.startsWith('%')) { + token = reader.getNextToken()!; + _setFileVersion(token); + } + } + + void _setFileVersion(String token) { + switch (token) { + case 'PDF-1.4': + fileStructure.version = PdfVersion.version1_4; + break; + case 'PDF-1.0': + fileStructure.version = PdfVersion.version1_0; + //fileStructure.incrementalUpdate = false; + break; + case 'PDF-1.1': + fileStructure.version = PdfVersion.version1_1; + //fileStructure.incrementalUpdate = false; + break; + case 'PDF-1.2': + fileStructure.version = PdfVersion.version1_2; + //fileStructure.incrementalUpdate = false; + break; + case 'PDF-1.3': + fileStructure.version = PdfVersion.version1_3; + //fileStructure.incrementalUpdate = false; + break; + case 'PDF-1.5': + fileStructure.version = PdfVersion.version1_5; + break; + case 'PDF-1.6': + fileStructure.version = PdfVersion.version1_6; + break; + case 'PDF-1.7': + fileStructure.version = PdfVersion.version1_7; + break; + case 'PDF-2.0': + fileStructure.version = PdfVersion.version2_0; + break; + } + } + + PdfCatalog _getCatalogValue() { + final PdfCatalog catalog = PdfCatalog.fromDocument( + this, + _helper.crossTable.documentCatalog, + ); + final int index = + _helper.objects.lookFor(_helper.crossTable.documentCatalog!)!; + _helper.objects.reregisterReference(index, catalog); + catalog.position = -1; + return catalog; + } + + void _setCatalog(PdfCatalog catalog) { + _helper.catalog = catalog; + if (_helper.catalog.containsKey(PdfDictionaryProperties.outlines)) { + final PdfReferenceHolder? outlines = + _helper.catalog[PdfDictionaryProperties.outlines] + as PdfReferenceHolder?; + PdfDictionary? dic; + if (outlines == null) { + dic = + _helper.catalog[PdfDictionaryProperties.outlines] as PdfDictionary?; + } else if (outlines.object is PdfDictionary) { + dic = outlines.object as PdfDictionary?; + } + if (dic != null && dic.containsKey(PdfDictionaryProperties.first)) { + final PdfReferenceHolder? first = + dic[PdfDictionaryProperties.first] as PdfReferenceHolder?; + if (first != null) { + final PdfDictionary? firstDic = first.object as PdfDictionary?; + if (firstDic == null) { + dic.remove(PdfDictionaryProperties.first); + } + } + } + } + } + + PdfPageCollection _getPageCollection() { + _pages ??= + _helper.isLoadedDocument + ? PdfPageCollectionHelper.fromCrossTable(this, _helper.crossTable) + : PdfPageCollectionHelper.load(this); + return _pages!; + } + + /// Creates a bookmarks collection to the document. + PdfBookmarkBase? _createBookmarkRoot() { + _bookmark = PdfBookmarkBaseHelper.loadInternal(); + return _bookmark; + } + + PdfNamedDestinationCollection? _createNamedDestinations() { + _namedDestinations = PdfNamedDestinationCollection(); + final PdfReferenceHolder? catalogReference = + _helper.catalog[PdfDictionaryProperties.names] as PdfReferenceHolder?; + + if (catalogReference != null) { + final PdfDictionary? catalogNames = + catalogReference.object as PdfDictionary?; + if (catalogNames != null) { + catalogNames.setProperty( + PdfDictionaryProperties.dests, + PdfReferenceHolder(_namedDestinations), + ); + } + } else { + _helper.catalog.setProperty( + PdfDictionaryProperties.names, + PdfReferenceHolder(_namedDestinations), + ); + } + _helper.catalog.modify(); + return _namedDestinations; + } + + void _readDocumentInfo() { + // Read document's info if present. + final PdfDictionary? info = + PdfCrossTable.dereference( + _helper.crossTable.trailer![PdfDictionaryProperties.info], + ) + as PdfDictionary?; + if (info != null && _documentInfo == null) { + _documentInfo = PdfDocumentInformationHelper.load( + _helper.catalog, + dictionary: info, + isLoaded: true, + conformance: _helper.conformanceLevel, + ); + } + if (info != null && + !info.changed! && + _helper.crossTable.trailer![PdfDictionaryProperties.info] + is PdfReferenceHolder) { + _documentInfo = PdfDocumentInformationHelper.load( + _helper.catalog, + dictionary: info, + isLoaded: true, + conformance: _helper.conformanceLevel, + ); + if (_helper.catalog.changed!) { + _documentInfo!.modificationDate = DateTime.now(); + } + if (_helper.objects.lookFor(IPdfWrapper.getElement(_documentInfo!)!)! > + -1) { + _helper.objects.reregisterReference( + _helper.objects.lookFor(info)!, + IPdfWrapper.getElement(_documentInfo!)!, + ); + IPdfWrapper.getElement(_documentInfo!)!.position = -1; + } + } + } + + Future _readDocumentInfoAsync() async { + // Read document's info if present. + final PdfDictionary? info = + PdfCrossTable.dereference( + _helper.crossTable.trailer![PdfDictionaryProperties.info], + ) + as PdfDictionary?; + if (info != null && _documentInfo == null) { + _documentInfo = PdfDocumentInformationHelper.load( + _helper.catalog, + dictionary: info, + isLoaded: true, + conformance: _helper.conformanceLevel, + ); + } + if (info != null && + !info.changed! && + _helper.crossTable.trailer![PdfDictionaryProperties.info] + is PdfReferenceHolder) { + _documentInfo = PdfDocumentInformationHelper.load( + _helper.catalog, + dictionary: info, + isLoaded: true, + conformance: _helper.conformanceLevel, + ); + if (_helper.catalog.changed!) { + _documentInfo!.modificationDate = DateTime.now(); + } + if ((await _helper.objects.lookForAsync( + IPdfWrapper.getElement(_documentInfo!)!, + ))! > + -1) { + await _helper.objects.reregisterReferenceAsync( + (await _helper.objects.lookForAsync(info))!, + IPdfWrapper.getElement(_documentInfo!)!, + ); + IPdfWrapper.getElement(_documentInfo!)!.position = -1; + } + } + } + + void _initializeConformance(PdfConformanceLevel conformance) { + _helper.conformanceLevel = conformance; + if (_helper.conformanceLevel == PdfConformanceLevel.a1b || + _helper.conformanceLevel == PdfConformanceLevel.a2b || + _helper.conformanceLevel == PdfConformanceLevel.a3b) { + //Note : PDF/A is based on Pdf 1.4. Hence it does not support cross reference + //stream which is an Pdf 1.5 feature. + fileStructure.crossReferenceType = + PdfCrossReferenceType.crossReferenceTable; + if (_helper.conformanceLevel == PdfConformanceLevel.a1b) { + fileStructure.version = PdfVersion.version1_4; + } else { + fileStructure.version = PdfVersion.version1_7; + } + //Embed the Color Profie. + final PdfDictionary dict = PdfDictionary(); + dict['Info'] = PdfString('sRGB IEC61966-2.1'); + dict['S'] = PdfName('GTS_PDFA1'); + dict['OutputConditionIdentifier'] = PdfString('custom'); + dict['Type'] = PdfName('OutputIntent'); + dict['OutputCondition'] = PdfString(''); + dict['RegistryName'] = PdfString(''); + final PdfICCColorProfile srgbProfile = PdfICCColorProfile(); + dict['DestOutputProfile'] = PdfReferenceHolder(srgbProfile); + final PdfArray outputIntent = PdfArray(); + outputIntent.add(dict); + _helper.catalog['OutputIntents'] = outputIntent; + } + } + + //Raises DocumentSaved event. + void _onDocumentSaved(DocumentSavedArgs args) { + if (_helper.documentSavedList != null && + _helper.documentSavedList!.isNotEmpty) { + for (int i = 0; i < _helper.documentSavedList!.length; i++) { + _helper.documentSavedList![i](this, args); + } + } + } + + Future _onDocumentSavedAsync(DocumentSavedArgs args) async { + if (_helper.documentSavedListAsync != null && + _helper.documentSavedListAsync!.isNotEmpty) { + for (int i = 0; i < _helper.documentSavedListAsync!.length; i++) { + await _helper.documentSavedListAsync![i](this, args); + } + } + } +} + +/// Delegate for handling the PDF password +/// +/// ```dart +/// //Load an existing PDF document +/// PdfDocument document = +/// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) +/// //Subsribe the onPdfPassword event +/// ..onPdfPassword = loadOnPdfPassword; +/// //Access the attachments +/// PdfAttachmentCollection attachmentCollection = document.attachments; +/// //Iterates the attachments +/// for (int i = 0; i < attachmentCollection.count; i++) { +/// //Extracts the attachment and saves it to the disk +/// File(attachmentCollection[i].fileName) +/// .writeAsBytesSync(attachmentCollection[i].data); +/// } +/// //Disposes the document +/// document.dispose(); +/// +/// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { +/// //Sets the value of PDF password. +/// args.attachmentOpenPassword = 'syncfusion'; +/// } +/// ``` +typedef PdfPasswordCallback = + void Function(PdfDocument sender, PdfPasswordArgs args); + +/// Arguments of Pdf Password. +/// +/// ```dart +/// //Load an existing PDF document +/// PdfDocument document = +/// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) +/// //Subsribe the onPdfPassword event +/// ..onPdfPassword = loadOnPdfPassword; +/// //Access the attachments +/// PdfAttachmentCollection attachmentCollection = document.attachments; +/// //Iterates the attachments +/// for (int i = 0; i < attachmentCollection.count; i++) { +/// //Extracts the attachment and saves it to the disk +/// File(attachmentCollection[i].fileName) +/// .writeAsBytesSync(attachmentCollection[i].data); +/// } +/// //Disposes the document +/// document.dispose(); +/// +/// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { +/// //Sets the value of PDF password. +/// args.attachmentOpenPassword = 'syncfusion'; +/// } +/// ``` +class PdfPasswordArgs { + PdfPasswordArgs._() { + attachmentOpenPassword = ''; + } + //Fields + /// A value of PDF password. + /// + /// ```dart + /// //Load an existing PDF document + /// PdfDocument document = + /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()) + /// //Subsribe the onPdfPassword event + /// ..onPdfPassword = loadOnPdfPassword; + /// //Access the attachments + /// PdfAttachmentCollection attachmentCollection = document.attachments; + /// //Iterates the attachments + /// for (int i = 0; i < attachmentCollection.count; i++) { + /// //Extracts the attachment and saves it to the disk + /// File(attachmentCollection[i].fileName) + /// .writeAsBytesSync(attachmentCollection[i].data); + /// } + /// //Disposes the document + /// document.dispose(); + /// + /// void loadOnPdfPassword(PdfDocument sender, PdfPasswordArgs args) { + /// //Sets the value of PDF password. + /// args.attachmentOpenPassword = 'syncfusion'; + /// } + /// ``` + String? attachmentOpenPassword; +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfPasswordArgs] helper +class PdfPasswordArgsHelper { + /// internal method + static PdfPasswordArgs load() { + return PdfPasswordArgs._(); + } +} + +/// [PdfDocument] helper +class PdfDocumentHelper { + /// internal constructor + PdfDocumentHelper(this.base); + + /// internal field + PdfDocument base; + + /// internal method + static PdfDocumentHelper getHelper(PdfDocument base) { + return base._helper; + } + + /// internal constant + static const double defaultMargin = 40; + + /// internal field + List? documentSavedList; + + /// internal field + List? documentSavedListAsync; + + /// internal field + late PdfMainObjectCollection objects; + + /// internal field + late PdfCrossTable crossTable; + + /// internal field + late PdfCatalog catalog; + + /// internal field + bool isLoadedDocument = false; + + /// internal field + bool isStreamCopied = false; + + /// internal field + int? position; + + /// internal field + int? orderPosition; + + /// internal field + int? onPosition; + + /// internal field + int? offPosition; + + /// internal field + PdfArray? pdfPrimitive; + + /// internal field + PdfArray? printLayer; + + /// internal field + PdfArray? on; + + /// internal field + PdfArray? off; + + /// internal field + PdfArray? order; + + /// internal field + String? password; + + /// internal field + late bool isEncrypted; + + /// internal field + PdfConformanceLevel conformanceLevel = PdfConformanceLevel.none; + + /// internal method + PdfReference? currentSavingObject; + PdfSecurity? _security; + bool? _isAttachOnlyEncryption; + Map? _bookmarkHashTable; + + /// internal method + bool checkEncryption(bool? isAttachEncryption) { + bool wasEncrypted = false; + if (crossTable.encryptorDictionary != null) { + final PdfDictionary encryptionDict = crossTable.encryptorDictionary!; + password ??= ''; + final PdfDictionary trailerDict = crossTable.trailer!; + PdfArray? obj; + if (trailerDict.containsKey(PdfDictionaryProperties.id)) { + IPdfPrimitive? primitive = trailerDict[PdfDictionaryProperties.id]; + if (primitive is PdfArray) { + obj = primitive; + } else if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfArray) { + obj = primitive; + } + } + } + obj ??= PdfArray()..add(PdfString.fromBytes([])); + final PdfString key = obj[0]! as PdfString; + final PdfEncryptor encryptor = PdfEncryptor(); + if (encryptionDict.containsKey(PdfDictionaryProperties.encryptMetadata)) { + IPdfPrimitive? primitive = + encryptionDict[PdfDictionaryProperties.encryptMetadata]; + if (primitive is PdfBoolean) { + encryptor.encryptMetadata = primitive.value!; + } else if (primitive is PdfReferenceHolder) { + primitive = primitive.object; + if (primitive != null && primitive is PdfBoolean) { + encryptor.encryptMetadata = primitive.value!; + } + } + } + wasEncrypted = true; + encryptor.readFromDictionary(encryptionDict); + bool encryption = true; + if (!isAttachEncryption! && encryptor.encryptAttachmentOnly!) { + encryption = false; + } + if (!encryptor.checkPassword(password!, key, encryption)) { + throw ArgumentError.value( + password, + 'password', + 'Cannot open an encrypted document. The password is invalid.', + ); + } + encryptionDict.encrypt = false; + final PdfSecurity security = PdfSecurityHelper.getSecurity(); + PdfSecurityHelper.getHelper(security).encryptor = encryptor; + _security = security; + PdfSecurityHelper.getHelper(_security!).encryptAttachmentOnly = + encryptor.encryptAttachmentOnly!; + _isAttachOnlyEncryption = encryptor.encryptAttachmentOnly; + if (_isAttachOnlyEncryption!) { + PdfSecurityHelper.getHelper(security).encryptor.encryptionOptions = + PdfEncryptionOptions.encryptOnlyAttachments; + } else if (!encryptor.encryptMetadata) { + PdfSecurityHelper.getHelper(security).encryptor.encryptionOptions = + PdfEncryptionOptions.encryptAllContentsExceptMetadata; + } + crossTable.encryptor = encryptor; + } + return wasEncrypted; + } + + /// internal method + PdfArray? getNamedDestination(IPdfPrimitive obj) { + PdfDictionary? destinations; + PdfArray? destination; + if (obj is PdfName) { + destinations = catalog.destinations; + final IPdfPrimitive? name = destinations![obj]; + destination = _extractDestination(name); + } else if (obj is PdfString) { + final PdfCatalogNames? names = catalog.names; + if (names != null) { + destinations = names.destinations; + final IPdfPrimitive? name = names.getNamedObjectFromTree( + destinations, + obj, + ); + destination = _extractDestination(name); + } + } + return destination; + } + + PdfArray? _extractDestination(IPdfPrimitive? obj) { + PdfDictionary? dic; + if (obj is PdfDictionary) { + dic = obj; + } else if (obj is PdfReferenceHolder) { + final PdfReferenceHolder holder = obj; + if (holder.object is PdfDictionary) { + dic = holder.object as PdfDictionary?; + } else if (holder.object is PdfArray) { + obj = (holder.object! as PdfArray?)! as PdfReferenceHolder; + } + } + PdfArray? destination; + if (obj is PdfArray) { + destination = obj; + } + if (dic != null) { + obj = PdfCrossTable.dereference(dic[PdfDictionaryProperties.d]); + destination = obj as PdfArray?; + } + return destination; + } + + /// internal method + Map? createBookmarkDestinationDictionary() { + PdfBookmarkBase? current = base.bookmarks; + if (_bookmarkHashTable == null) { + _bookmarkHashTable = {}; + final Queue stack = Queue(); + CurrentNodeInfo ni = CurrentNodeInfo( + PdfBookmarkBaseHelper.getList(current), + ); + do { + for (; ni.index < ni.kids.length;) { + current = ni.kids[ni.index]; + final PdfNamedDestination? ndest = + (current! as PdfBookmark).namedDestination; + if (ndest != null) { + if (ndest.destination != null) { + final PdfPage page = ndest.destination!.page; + List? list; + if (_bookmarkHashTable!.containsKey(page)) { + list = _bookmarkHashTable![page] as List?; + } + if (list == null) { + list = []; + _bookmarkHashTable![page] = list; + } + list.add(current); + } + } else { + final PdfDestination? dest = (current as PdfBookmark).destination; + if (dest != null) { + final PdfPage page = dest.page; + List? list = + _bookmarkHashTable!.containsKey(page) + ? _bookmarkHashTable![page] as List? + : null; + if (list == null) { + list = []; + _bookmarkHashTable![page] = list; + } + list.add(current); + } + } + ni.index = ni.index + 1; + if (current.count > 0) { + stack.addLast(ni); + ni = CurrentNodeInfo(PdfBookmarkBaseHelper.getList(current)); + continue; + } + } + if (stack.isNotEmpty) { + ni = stack.removeLast(); + while ((ni.index == ni.kids.length) && (stack.isNotEmpty)) { + ni = stack.removeLast(); + } + } + } while (ni.index < ni.kids.length); + } + return _bookmarkHashTable; + } + + /// internal method + void setUserPassword(PdfPasswordArgs args) { + base.onPdfPassword!(base, args); + } + + /// Imports the FDF file bytes. + void importFdf(List inputBytes) { + final FdfParser parser = FdfParser(inputBytes); + parser.parseAnnotationData(); + parser.importAnnotations(base); + parser.dispose(); + } + + /// Imports the FDF file bytes. + void importJson(List inputBytes) { + final JsonParser parser = JsonParser(base); + parser.importAnnotationData(inputBytes); + } + + /// Imports the XFDF file bytes. + void importXfdf(List data) { + final XfdfParser parser = XfdfParser(data, base); + parser.parseAndImportAnnotationData(); + } + + /// Exports annotation to FDF file bytes. + List exportFdf( + String? fileName, + List? exportAnnotation, + List? exportTypes, + bool exportAppearance, + ) { + const String genNumber = + '${PdfOperators.whiteSpace}0${PdfOperators.whiteSpace}'; + const String startDictionary = '<<${PdfOperators.slash}'; + final List fdfBytes = []; + fdfBytes.addAll(utf8.encode('%FDF-1.2${PdfOperators.newLine}')); + int currentID = 2; + final List annotID = []; + final List annotType = []; + _getExportTypes(exportTypes, annotType); + if (exportAnnotation != null && exportAnnotation.isNotEmpty) { + for (int i = 0; i < exportAnnotation.length; i++) { + final PdfAnnotation annotation = exportAnnotation[i]; + final PdfAnnotationHelper helper = PdfAnnotationHelper.getHelper( + annotation, + ); + if (helper.isLoadedAnnotation && + (annotType.isEmpty || + annotType.contains(_getAnnotationType(helper.dictionary!))) && + !(annotation is PdfLinkAnnotation || + annotation is PdfTextWebLink) && + annotation.page != null) { + final FdfDocument fdfDocument = FdfDocument( + helper.dictionary!, + annotation.page!, + ); + final Map result = fdfDocument.exportAnnotations( + currentID, + annotID, + base.pages.indexOf(annotation.page!), + _checkForStamp(helper.dictionary!) == 'Stamp' || exportAppearance, + ); + fdfBytes.addAll(result['exportData'] as List); + currentID = result['currentID'] as int; + } + } + } else { + for (int i = 0; i < base.pages.count; i++) { + final PdfPage page = base.pages[i]; + final PdfPageHelper pageHelper = PdfPageHelper.getHelper(page); + pageHelper.createAnnotations(pageHelper.getWidgetReferences()); + for (int j = 0; j < pageHelper.terminalAnnotation.length; j++) { + final PdfDictionary annotationDictionary = + pageHelper.terminalAnnotation[j]; + if ((annotType.isEmpty || + annotType.contains( + _getAnnotationType(annotationDictionary), + )) && + !isLinkAnnotation(annotationDictionary)) { + final FdfDocument fdfDocument = FdfDocument( + annotationDictionary, + page, + ); + final Map result = fdfDocument.exportAnnotations( + currentID, + annotID, + i, + _checkForStamp(annotationDictionary) == 'Stamp' || + exportAppearance, + ); + fdfBytes.addAll(result['exportData'] as List); + currentID = result['currentID'] as int; + } + } + } + } + fileName ??= ''; + if (currentID != 2) { + const String root = '1$genNumber'; + fdfBytes.addAll( + utf8.encode( + '${'$root${PdfOperators.obj}${PdfOperators.newLine}${startDictionary}FDF$startDictionary${PdfDictionaryProperties.annots}'}[', + ), + ); + for (int i = 0; i < annotID.length - 1; i++) { + fdfBytes.addAll( + utf8.encode( + '${annotID[i]}$genNumber${PdfDictionaryProperties.r}${PdfOperators.whiteSpace}', + ), + ); + } + fdfBytes.addAll( + utf8.encode( + '${annotID[annotID.length - 1]}$genNumber${PdfDictionaryProperties.r}]${PdfOperators.slash}${PdfDictionaryProperties.f}($fileName)${PdfOperators.slash}${PdfDictionaryProperties.uf}($fileName)>>${PdfOperators.slash}${PdfDictionaryProperties.type}${PdfOperators.slash}${PdfDictionaryProperties.catalog}>>${PdfOperators.newLine}${PdfOperators.endobj}${PdfOperators.newLine}', + ), + ); + fdfBytes.addAll( + utf8.encode( + '${PdfOperators.trailer}${PdfOperators.newLine}$startDictionary${PdfDictionaryProperties.root}${PdfOperators.whiteSpace}$root${PdfDictionaryProperties.r}>>${PdfOperators.newLine}${PdfOperators.endOfFileMarker}${PdfOperators.newLine}', + ), + ); + } + return fdfBytes; + } + + /// Exports annotation to JSON file bytes. + List exportJson( + String? fileName, + List? exportAnnotation, + List? exportTypes, + bool exportAppearance, + ) { + String json = '{"pdfAnnotation":{'; + bool isAnnotationAdded = false; + JsonDocument? jsonDocument = JsonDocument(base); + final Map table = {}; + final List annotType = []; + _getExportTypes(exportTypes, annotType); + if (exportAnnotation != null && exportAnnotation.isNotEmpty) { + final Map table1 = {}; + String? tempJson = ''; + for (int j = 0; j < exportAnnotation.length; j++) { + final PdfDictionary annotationDictionary = + PdfAnnotationHelper.getHelper(exportAnnotation[j]).dictionary!; + if ((annotType.isEmpty || + annotType.contains(_getAnnotationType(annotationDictionary))) && + exportAnnotation[j].page != null) { + final int pageIndex = base.pages.indexOf(exportAnnotation[j].page!); + if (pageIndex >= 0) { + if (table1.containsKey(pageIndex)) { + tempJson = '${table1[pageIndex]!},'; + } else { + tempJson = '"$pageIndex":{ "shapeAnnotation":['; + } + jsonDocument.exportAnnotationData( + table, + exportAppearance, + base.pages.indexOf(exportAnnotation[j].page!), + annotationDictionary, + ); + tempJson += jsonDocument.convertToJson(table); + table1[pageIndex] = tempJson; + table.clear(); + } + } + } + final List values = table1.values.toList(); + for (int i = 0; i < values.length; i++) { + json += table1[i]! + ((i < values.length - 1) ? ']},' : ']}'); + } + table1.clear(); + values.clear(); + } else { + for (int i = 0; i < base.pages.count; i++) { + final PdfPageHelper pageHelper = PdfPageHelper.getHelper(base.pages[i]); + pageHelper.createAnnotations(pageHelper.getWidgetReferences()); + if (pageHelper.terminalAnnotation.isNotEmpty) { + json += (i != 0 && isAnnotationAdded) ? ',' : ' '; + json += '"$i":{ "shapeAnnotation":['; + isAnnotationAdded = true; + } + for (int j = 0; j < pageHelper.terminalAnnotation.length; j++) { + final PdfDictionary annotationDictionary = + pageHelper.terminalAnnotation[j]; + if (annotType.isEmpty || + annotType.contains(_getAnnotationType(annotationDictionary))) { + jsonDocument.exportAnnotationData( + table, + exportAppearance, + i, + annotationDictionary, + ); + json += jsonDocument.convertToJson(table); + if (j < pageHelper.terminalAnnotation.length - 1) { + json += ','; + } + table.clear(); + } + } + if (pageHelper.terminalAnnotation.isNotEmpty) { + json += ']}'; + } + } + } + jsonDocument = null; + json += '}}'; + return utf8.encode(json); + } + + /// Exports annotation to XFDF file bytes. + List exportXfdf( + String? fileName, + List? exportAnnotation, + List? exportTypes, + bool exportAppearance, + ) { + final XFdfDocument xfdf = XFdfDocument(fileName ?? ''); + final List elements = []; + final List annotType = []; + _getExportTypes(exportTypes, annotType); + if (exportAnnotation != null && exportAnnotation.isNotEmpty) { + for (int j = 0; j < exportAnnotation.length; j++) { + if (annotType.isEmpty || + annotType.contains( + _getAnnotationType( + PdfAnnotationHelper.getHelper(exportAnnotation[j]).dictionary!, + ), + )) { + final XmlElement? element = xfdf.exportAnnotationData( + PdfAnnotationHelper.getHelper(exportAnnotation[j]).dictionary!, + base.pages.indexOf(exportAnnotation[j].page!), + exportAppearance, + base, + ); + if (element != null) { + elements.add(element); + } + } + } + } else { + for (int i = 0; i < base.pages.count; i++) { + final PdfPageHelper pageHelper = PdfPageHelper.getHelper(base.pages[i]); + pageHelper.createAnnotations(pageHelper.getWidgetReferences()); + for (int j = 0; j < pageHelper.terminalAnnotation.length; j++) { + final PdfDictionary annotationDictionary = + pageHelper.terminalAnnotation[j]; + if (annotType.isEmpty || + annotType.contains(_getAnnotationType(annotationDictionary))) { + final XmlElement? element = xfdf.exportAnnotationData( + annotationDictionary, + i, + exportAppearance, + base, + ); + if (element != null) { + elements.add(element); + } + } + } + } + } + return xfdf.save(elements); + } + + void _getExportTypes( + List? types, + List annotType, + ) { + if (types != null && types.isNotEmpty) { + for (int i = 0; i < types.length; i++) { + String annotationType = getEnumName(types[i]); + switch (annotationType) { + case 'HighlightAnnotation': + annotationType = 'Highlight'; + break; + case 'UnderlineAnnotation': + annotationType = 'Underline'; + break; + case 'StrikeOutAnnotation': + annotationType = 'StrikeOut'; + break; + case 'SquigglyAnnotation': + annotationType = 'Squiggly'; + break; + } + annotType.add(annotationType); + } + } + } + + String _getAnnotationType(PdfDictionary dictionary) { + if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final PdfName name = + PdfAnnotationHelper.getValue( + dictionary, + crossTable, + PdfDictionaryProperties.subtype, + true, + )! + as PdfName; + final PdfAnnotationTypes type = + PdfAnnotationCollectionHelper.getAnnotationType( + name, + dictionary, + crossTable, + ); + return getEnumName(type); + } + return ''; + } + + String _checkForStamp(PdfDictionary dictionary) { + if (dictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? name = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.subtype], + ); + if (name != null && name is PdfName) { + return name.name ?? ''; + } + } + return ''; + } + + /// Internal method. + static bool isLinkAnnotation(PdfDictionary annotationDictionary) { + if (annotationDictionary.containsKey(PdfDictionaryProperties.subtype)) { + final IPdfPrimitive? name = PdfCrossTable.dereference( + annotationDictionary[PdfDictionaryProperties.subtype], + ); + if (name != null && name is PdfName) { + return name.name == 'Link'; + } + } + return false; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_information.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_information.dart index f9c05d66b..946cd1a43 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_information.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_information.dart @@ -1,348 +1,348 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../pages/pdf_section_collection.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import '../xmp/xmp_metadata.dart'; -import 'enums.dart'; -import 'pdf_catalog.dart'; - -/// A class containing the information about the document. -class PdfDocumentInformation implements IPdfWrapper { - //Constructor - PdfDocumentInformation._( - PdfCatalog catalog, { - PdfDictionary? dictionary, - bool isLoaded = false, - PdfConformanceLevel? conformance, - }) { - _helper = PdfDocumentInformationHelper(this); - _helper._catalog = catalog; - if (conformance != null) { - _helper.conformance = conformance; - } - if (isLoaded) { - ArgumentError.checkNotNull(dictionary, 'dictionary'); - _helper._dictionary = dictionary; - } else { - _helper._dictionary = PdfDictionary(); - if (_helper.conformance != PdfConformanceLevel.a1b) { - _helper._dictionary!.setDateTime( - PdfDictionaryProperties.creationDate, - _helper.creationDate, - ); - } - } - } - - //Fields - late PdfDocumentInformationHelper _helper; - String? _title; - String? _author; - String? _subject; - String? _keywords; - String? _creator; - String? _producer; - - //Properties - - /// Gets the creation date of the PDF document - DateTime get creationDate { - if (_helper._dictionary!.containsKey( - PdfDictionaryProperties.creationDate, - ) && - _helper._dictionary![PdfDictionaryProperties.creationDate] - is PdfString) { - return _helper.creationDate = _helper._dictionary!.getDateTime( - _helper._dictionary![PdfDictionaryProperties.creationDate]! - as PdfString, - ); - } - return _helper.creationDate = DateTime.now(); - } - - /// Sets the creation date of the PDF document - set creationDate(DateTime value) { - if (_helper.creationDate != value) { - _helper.creationDate = value; - _helper._dictionary!.setDateTime( - PdfDictionaryProperties.creationDate, - _helper.creationDate, - ); - } - } - - /// Gets the modification date of the PDF document - DateTime get modificationDate { - if (_helper._dictionary!.containsKey( - PdfDictionaryProperties.modificationDate, - ) && - _helper._dictionary![PdfDictionaryProperties.modificationDate] - is PdfString) { - return _helper.modificationDate = _helper._dictionary!.getDateTime( - _helper._dictionary![PdfDictionaryProperties.modificationDate]! - as PdfString, - ); - } - return _helper.modificationDate = DateTime.now(); - } - - /// Sets the modification date of the PDF document - set modificationDate(DateTime value) { - _helper.modificationDate = value; - _helper._dictionary!.setDateTime( - PdfDictionaryProperties.modificationDate, - _helper.modificationDate, - ); - } - - /// Gets the title. - String get title { - if (_helper._dictionary!.containsKey(PdfDictionaryProperties.title) && - _helper._dictionary![PdfDictionaryProperties.title] is PdfString) { - return _title = (_helper._dictionary![PdfDictionaryProperties.title]! - as PdfString) - .value! - .replaceAll('\u0000', ''); - } - return _title = ''; - } - - /// Sets the title. - set title(String value) { - if (_title != value) { - _title = value; - _helper._dictionary!.setString(PdfDictionaryProperties.title, _title); - } - } - - /// Gets the author. - String get author { - _author = ''; - if (_helper._dictionary!.containsKey(PdfDictionaryProperties.author) && - _helper._dictionary![PdfDictionaryProperties.author] is PdfString) { - _author = - (_helper._dictionary![PdfDictionaryProperties.author]! as PdfString) - .value; - } - return _author!; - } - - /// Sets the author. - set author(String value) { - if (_author != value) { - _author = value; - _helper._dictionary!.setString(PdfDictionaryProperties.author, _author); - } - } - - /// Gets the subject. - String get subject { - _subject = ''; - if (_helper._dictionary!.containsKey(PdfDictionaryProperties.subject) && - _helper._dictionary![PdfDictionaryProperties.subject] is PdfString) { - _subject = - (_helper._dictionary![PdfDictionaryProperties.subject]! as PdfString) - .value; - } - return _subject!; - } - - /// Sets the subject. - set subject(String value) { - if (_subject != value) { - _subject = value; - _helper._dictionary!.setString(PdfDictionaryProperties.subject, _subject); - } - } - - /// Gets the keywords. - String get keywords { - _keywords = ''; - if (_helper._dictionary!.containsKey(PdfDictionaryProperties.keywords) && - _helper._dictionary![PdfDictionaryProperties.keywords] is PdfString) { - _keywords = - (_helper._dictionary![PdfDictionaryProperties.keywords]! as PdfString) - .value; - } - return _keywords!; - } - - /// Sets the keywords. - set keywords(String value) { - if (_keywords != value) { - _keywords = value; - _helper._dictionary!.setString( - PdfDictionaryProperties.keywords, - _keywords, - ); - } - if (_helper._catalog != null && _helper._catalog!.metadata != null) { - _helper._xmp = _helper.xmpMetadata; - } - } - - /// Gets the creator. - String get creator { - _creator = ''; - if (_helper._dictionary!.containsKey(PdfDictionaryProperties.creator) && - _helper._dictionary![PdfDictionaryProperties.creator] is PdfString) { - _creator = - (_helper._dictionary![PdfDictionaryProperties.creator]! as PdfString) - .value; - } - return _creator!; - } - - /// Sets the creator. - set creator(String value) { - if (_creator != value) { - _creator = value; - _helper._dictionary!.setString(PdfDictionaryProperties.creator, _creator); - } - } - - /// Gets the producer. - String get producer { - _producer = ''; - if (_helper._dictionary!.containsKey(PdfDictionaryProperties.producer) && - _helper._dictionary![PdfDictionaryProperties.producer] is PdfString) { - _producer = - (_helper._dictionary![PdfDictionaryProperties.producer]! as PdfString) - .value; - } - return _producer!; - } - - /// Sets the producer. - set producer(String value) { - if (_producer != value) { - _producer = value; - _helper._dictionary!.setString( - PdfDictionaryProperties.producer, - _producer, - ); - } - } - - /// Remove the modification date from existing document. - void removeModificationDate() { - if (_helper._dictionary != null && - _helper._dictionary!.containsKey( - PdfDictionaryProperties.modificationDate, - )) { - _helper._dictionary!.remove(PdfDictionaryProperties.modificationDate); - if (_helper._dictionary!.changed! && !_helper._catalog!.changed!) { - PdfDocumentInformationHelper.getHelper( - _helper._catalog!.document!.documentInformation, - )._dictionary!.remove(PdfDictionaryProperties.modificationDate); - PdfDocumentInformationHelper.getHelper( - _helper._catalog!.document!.documentInformation, - ).isRemoveModifyDate = - true; - _helper._xmp = XmpMetadata( - _helper._catalog!.document!.documentInformation, - ); - _helper._catalog!.setProperty( - PdfDictionaryProperties.metadata, - PdfReferenceHolder(_helper._xmp), - ); - } - } - } -} - -/// [PdfDocumentInformation] helper -class PdfDocumentInformationHelper { - /// internal constructor - PdfDocumentInformationHelper(this.base); - - /// internal field - late PdfDocumentInformation base; - - /// internal method - static PdfDocumentInformationHelper getHelper(PdfDocumentInformation base) { - return base._helper; - } - - /// internal method - static PdfDocumentInformation load( - PdfCatalog catalog, { - PdfDictionary? dictionary, - bool isLoaded = false, - PdfConformanceLevel? conformance, - }) { - return PdfDocumentInformation._( - catalog, - dictionary: dictionary, - isLoaded: isLoaded, - conformance: conformance, - ); - } - - /// internal field - DateTime creationDate = DateTime.now(); - - /// internal field - DateTime modificationDate = DateTime.now(); - - /// internal field - bool isRemoveModifyDate = false; - - /// internal field - PdfConformanceLevel? conformance; - PdfDictionary? _dictionary; - XmpMetadata? _xmp; - PdfCatalog? _catalog; - - /// internal field - IPdfPrimitive? get element => _dictionary; - set element(IPdfPrimitive? value) { - if (value != null && value is PdfDictionary) { - _dictionary = value; - } - } - - /// internal method/// Gets Xmp metadata of the document. - /// - /// Represents the document information in Xmp format. - XmpMetadata? get xmpMetadata { - if (_xmp == null) { - if (_catalog!.metadata == null && _catalog!.pages != null) { - _xmp = XmpMetadata( - PdfSectionCollectionHelper.getHelper( - _catalog!.pages!, - ).document!.documentInformation, - ); - _catalog!.setProperty( - PdfDictionaryProperties.metadata, - PdfReferenceHolder(_xmp), - ); - } else { - if (_dictionary!.changed! && !_catalog!.changed!) { - _xmp = XmpMetadata(_catalog!.document!.documentInformation); - _catalog!.setProperty( - PdfDictionaryProperties.metadata, - PdfReferenceHolder(_xmp), - ); - } else { - _xmp = _catalog!.metadata; - _catalog!.setProperty( - PdfDictionaryProperties.metadata, - PdfReferenceHolder(_xmp), - ); - } - } - } else if (_catalog!.metadata != null && _catalog!.document != null) { - if (_dictionary!.changed! && !_catalog!.changed!) { - _xmp = XmpMetadata(_catalog!.document!.documentInformation); - _catalog!.setProperty( - PdfDictionaryProperties.metadata, - PdfReferenceHolder(_xmp), - ); - } - } - return _xmp; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../pages/pdf_section_collection.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import '../xmp/xmp_metadata.dart'; +import 'enums.dart'; +import 'pdf_catalog.dart'; + +/// A class containing the information about the document. +class PdfDocumentInformation implements IPdfWrapper { + //Constructor + PdfDocumentInformation._( + PdfCatalog catalog, { + PdfDictionary? dictionary, + bool isLoaded = false, + PdfConformanceLevel? conformance, + }) { + _helper = PdfDocumentInformationHelper(this); + _helper._catalog = catalog; + if (conformance != null) { + _helper.conformance = conformance; + } + if (isLoaded) { + ArgumentError.checkNotNull(dictionary, 'dictionary'); + _helper._dictionary = dictionary; + } else { + _helper._dictionary = PdfDictionary(); + if (_helper.conformance != PdfConformanceLevel.a1b) { + _helper._dictionary!.setDateTime( + PdfDictionaryProperties.creationDate, + _helper.creationDate, + ); + } + } + } + + //Fields + late PdfDocumentInformationHelper _helper; + String? _title; + String? _author; + String? _subject; + String? _keywords; + String? _creator; + String? _producer; + + //Properties + + /// Gets the creation date of the PDF document + DateTime get creationDate { + if (_helper._dictionary!.containsKey( + PdfDictionaryProperties.creationDate, + ) && + _helper._dictionary![PdfDictionaryProperties.creationDate] + is PdfString) { + return _helper.creationDate = _helper._dictionary!.getDateTime( + _helper._dictionary![PdfDictionaryProperties.creationDate]! + as PdfString, + ); + } + return _helper.creationDate = DateTime.now(); + } + + /// Sets the creation date of the PDF document + set creationDate(DateTime value) { + if (_helper.creationDate != value) { + _helper.creationDate = value; + _helper._dictionary!.setDateTime( + PdfDictionaryProperties.creationDate, + _helper.creationDate, + ); + } + } + + /// Gets the modification date of the PDF document + DateTime get modificationDate { + if (_helper._dictionary!.containsKey( + PdfDictionaryProperties.modificationDate, + ) && + _helper._dictionary![PdfDictionaryProperties.modificationDate] + is PdfString) { + return _helper.modificationDate = _helper._dictionary!.getDateTime( + _helper._dictionary![PdfDictionaryProperties.modificationDate]! + as PdfString, + ); + } + return _helper.modificationDate = DateTime.now(); + } + + /// Sets the modification date of the PDF document + set modificationDate(DateTime value) { + _helper.modificationDate = value; + _helper._dictionary!.setDateTime( + PdfDictionaryProperties.modificationDate, + _helper.modificationDate, + ); + } + + /// Gets the title. + String get title { + if (_helper._dictionary!.containsKey(PdfDictionaryProperties.title) && + _helper._dictionary![PdfDictionaryProperties.title] is PdfString) { + return _title = (_helper._dictionary![PdfDictionaryProperties.title]! + as PdfString) + .value! + .replaceAll('\u0000', ''); + } + return _title = ''; + } + + /// Sets the title. + set title(String value) { + if (_title != value) { + _title = value; + _helper._dictionary!.setString(PdfDictionaryProperties.title, _title); + } + } + + /// Gets the author. + String get author { + _author = ''; + if (_helper._dictionary!.containsKey(PdfDictionaryProperties.author) && + _helper._dictionary![PdfDictionaryProperties.author] is PdfString) { + _author = + (_helper._dictionary![PdfDictionaryProperties.author]! as PdfString) + .value; + } + return _author!; + } + + /// Sets the author. + set author(String value) { + if (_author != value) { + _author = value; + _helper._dictionary!.setString(PdfDictionaryProperties.author, _author); + } + } + + /// Gets the subject. + String get subject { + _subject = ''; + if (_helper._dictionary!.containsKey(PdfDictionaryProperties.subject) && + _helper._dictionary![PdfDictionaryProperties.subject] is PdfString) { + _subject = + (_helper._dictionary![PdfDictionaryProperties.subject]! as PdfString) + .value; + } + return _subject!; + } + + /// Sets the subject. + set subject(String value) { + if (_subject != value) { + _subject = value; + _helper._dictionary!.setString(PdfDictionaryProperties.subject, _subject); + } + } + + /// Gets the keywords. + String get keywords { + _keywords = ''; + if (_helper._dictionary!.containsKey(PdfDictionaryProperties.keywords) && + _helper._dictionary![PdfDictionaryProperties.keywords] is PdfString) { + _keywords = + (_helper._dictionary![PdfDictionaryProperties.keywords]! as PdfString) + .value; + } + return _keywords!; + } + + /// Sets the keywords. + set keywords(String value) { + if (_keywords != value) { + _keywords = value; + _helper._dictionary!.setString( + PdfDictionaryProperties.keywords, + _keywords, + ); + } + if (_helper._catalog != null && _helper._catalog!.metadata != null) { + _helper._xmp = _helper.xmpMetadata; + } + } + + /// Gets the creator. + String get creator { + _creator = ''; + if (_helper._dictionary!.containsKey(PdfDictionaryProperties.creator) && + _helper._dictionary![PdfDictionaryProperties.creator] is PdfString) { + _creator = + (_helper._dictionary![PdfDictionaryProperties.creator]! as PdfString) + .value; + } + return _creator!; + } + + /// Sets the creator. + set creator(String value) { + if (_creator != value) { + _creator = value; + _helper._dictionary!.setString(PdfDictionaryProperties.creator, _creator); + } + } + + /// Gets the producer. + String get producer { + _producer = ''; + if (_helper._dictionary!.containsKey(PdfDictionaryProperties.producer) && + _helper._dictionary![PdfDictionaryProperties.producer] is PdfString) { + _producer = + (_helper._dictionary![PdfDictionaryProperties.producer]! as PdfString) + .value; + } + return _producer!; + } + + /// Sets the producer. + set producer(String value) { + if (_producer != value) { + _producer = value; + _helper._dictionary!.setString( + PdfDictionaryProperties.producer, + _producer, + ); + } + } + + /// Remove the modification date from existing document. + void removeModificationDate() { + if (_helper._dictionary != null && + _helper._dictionary!.containsKey( + PdfDictionaryProperties.modificationDate, + )) { + _helper._dictionary!.remove(PdfDictionaryProperties.modificationDate); + if (_helper._dictionary!.changed! && !_helper._catalog!.changed!) { + PdfDocumentInformationHelper.getHelper( + _helper._catalog!.document!.documentInformation, + )._dictionary!.remove(PdfDictionaryProperties.modificationDate); + PdfDocumentInformationHelper.getHelper( + _helper._catalog!.document!.documentInformation, + ).isRemoveModifyDate = + true; + _helper._xmp = XmpMetadata( + _helper._catalog!.document!.documentInformation, + ); + _helper._catalog!.setProperty( + PdfDictionaryProperties.metadata, + PdfReferenceHolder(_helper._xmp), + ); + } + } + } +} + +/// [PdfDocumentInformation] helper +class PdfDocumentInformationHelper { + /// internal constructor + PdfDocumentInformationHelper(this.base); + + /// internal field + late PdfDocumentInformation base; + + /// internal method + static PdfDocumentInformationHelper getHelper(PdfDocumentInformation base) { + return base._helper; + } + + /// internal method + static PdfDocumentInformation load( + PdfCatalog catalog, { + PdfDictionary? dictionary, + bool isLoaded = false, + PdfConformanceLevel? conformance, + }) { + return PdfDocumentInformation._( + catalog, + dictionary: dictionary, + isLoaded: isLoaded, + conformance: conformance, + ); + } + + /// internal field + DateTime creationDate = DateTime.now(); + + /// internal field + DateTime modificationDate = DateTime.now(); + + /// internal field + bool isRemoveModifyDate = false; + + /// internal field + PdfConformanceLevel? conformance; + PdfDictionary? _dictionary; + XmpMetadata? _xmp; + PdfCatalog? _catalog; + + /// internal field + IPdfPrimitive? get element => _dictionary; + set element(IPdfPrimitive? value) { + if (value != null && value is PdfDictionary) { + _dictionary = value; + } + } + + /// internal method/// Gets Xmp metadata of the document. + /// + /// Represents the document information in Xmp format. + XmpMetadata? get xmpMetadata { + if (_xmp == null) { + if (_catalog!.metadata == null && _catalog!.pages != null) { + _xmp = XmpMetadata( + PdfSectionCollectionHelper.getHelper( + _catalog!.pages!, + ).document!.documentInformation, + ); + _catalog!.setProperty( + PdfDictionaryProperties.metadata, + PdfReferenceHolder(_xmp), + ); + } else { + if (_dictionary!.changed! && !_catalog!.changed!) { + _xmp = XmpMetadata(_catalog!.document!.documentInformation); + _catalog!.setProperty( + PdfDictionaryProperties.metadata, + PdfReferenceHolder(_xmp), + ); + } else { + _xmp = _catalog!.metadata; + _catalog!.setProperty( + PdfDictionaryProperties.metadata, + PdfReferenceHolder(_xmp), + ); + } + } + } else if (_catalog!.metadata != null && _catalog!.document != null) { + if (_dictionary!.changed! && !_catalog!.changed!) { + _xmp = XmpMetadata(_catalog!.document!.documentInformation); + _catalog!.setProperty( + PdfDictionaryProperties.metadata, + PdfReferenceHolder(_xmp), + ); + } + } + return _xmp; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_template.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_template.dart index 4fc1484ed..43a8d1429 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_template.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_document_template.dart @@ -1,354 +1,354 @@ -import '../general/pdf_collection.dart'; -import '../pages/enum.dart'; -import '../pages/pdf_page.dart'; -import '../pages/pdf_page_collection.dart'; -import '../pages/pdf_page_template_element.dart'; -import '../pages/pdf_section.dart'; - -/// Encapsulates a page template for all the pages in the document. -class PdfDocumentTemplate { - //Constructors - /// Initializes a new instance of the [PdfDocumentTemplate] class. - PdfDocumentTemplate({ - PdfPageTemplateElement? left, - PdfPageTemplateElement? top, - PdfPageTemplateElement? right, - PdfPageTemplateElement? bottom, - PdfPageTemplateElement? evenLeft, - PdfPageTemplateElement? evenTop, - PdfPageTemplateElement? evenRight, - PdfPageTemplateElement? evenBottom, - PdfPageTemplateElement? oddLeft, - PdfPageTemplateElement? oddTop, - PdfPageTemplateElement? oddRight, - PdfPageTemplateElement? oddBottom, - PdfStampCollection? stamps, - }) { - _helper = PdfDocumentTemplateHelper(this); - _intialize( - left, - top, - right, - bottom, - evenLeft, - evenTop, - evenRight, - evenBottom, - oddLeft, - oddTop, - oddRight, - oddBottom, - stamps, - ); - } - - //Fields - late PdfDocumentTemplateHelper _helper; - PdfPageTemplateElement? _left; - PdfPageTemplateElement? _top; - PdfPageTemplateElement? _right; - PdfPageTemplateElement? _bottom; - PdfPageTemplateElement? _evenLeft; - PdfPageTemplateElement? _evenTop; - PdfPageTemplateElement? _evenRight; - PdfPageTemplateElement? _evenBottom; - PdfPageTemplateElement? _oddLeft; - PdfPageTemplateElement? _oddTop; - PdfPageTemplateElement? _oddRight; - PdfPageTemplateElement? _oddBottom; - PdfStampCollection? _stamps; - - //Properties - /// Gets a left page template. - PdfPageTemplateElement? get left => _left; - - /// Sets a left page template. - set left(PdfPageTemplateElement? value) { - _left = _checkElement(value, TemplateType.left); - } - - /// Gets a right page template. - PdfPageTemplateElement? get right => _right; - - /// Sets a right page template. - set right(PdfPageTemplateElement? value) { - _right = _checkElement(value, TemplateType.right); - } - - /// Gets a top page template. - PdfPageTemplateElement? get top => _top; - - /// Sets a top page template. - set top(PdfPageTemplateElement? value) { - _top = _checkElement(value, TemplateType.top); - } - - /// Gets a bottom page template. - PdfPageTemplateElement? get bottom => _bottom; - - /// Sets a bottom page template. - set bottom(PdfPageTemplateElement? value) { - _bottom = _checkElement(value, TemplateType.bottom); - } - - /// Gets a even left page template. - PdfPageTemplateElement? get evenLeft => _evenLeft; - - /// Sets a even left page template. - set evenLeft(PdfPageTemplateElement? value) { - _evenLeft = _checkElement(value, TemplateType.left); - } - - /// Gets a even right page template. - PdfPageTemplateElement? get evenRight => _evenRight; - - /// Sets a even right page template. - set evenRight(PdfPageTemplateElement? value) { - _evenRight = _checkElement(value, TemplateType.right); - } - - /// Gets a even top page template. - PdfPageTemplateElement? get evenTop => _evenTop; - - /// Sets a even top page template. - set evenTop(PdfPageTemplateElement? value) { - _evenTop = _checkElement(value, TemplateType.top); - } - - /// Gets a even bottom page template. - PdfPageTemplateElement? get evenBottom => _evenBottom; - - /// Sets a even bottom page template. - set evenBottom(PdfPageTemplateElement? value) { - _evenBottom = _checkElement(value, TemplateType.bottom); - } - - /// Gets a odd left page template. - PdfPageTemplateElement? get oddLeft => _oddLeft; - - /// Sets a odd left page template. - set oddLeft(PdfPageTemplateElement? value) { - _oddLeft = _checkElement(value, TemplateType.left); - } - - /// Gets a odd right page template. - PdfPageTemplateElement? get oddRight => _oddRight; - - /// Sets a odd right page template. - set oddRight(PdfPageTemplateElement? value) { - _oddRight = _checkElement(value, TemplateType.right); - } - - /// Gets a odd top page template. - PdfPageTemplateElement? get oddTop => _oddTop; - - /// Sets a odd top page template. - set oddTop(PdfPageTemplateElement? value) { - _oddTop = _checkElement(value, TemplateType.top); - } - - /// Gets a odd bottom page template. - PdfPageTemplateElement? get oddBottom => _oddBottom; - - /// Sets a odd bottom page template. - set oddBottom(PdfPageTemplateElement? value) { - _oddBottom = _checkElement(value, TemplateType.bottom); - } - - /// Gets a collection of stamp elements. - PdfStampCollection get stamps { - _stamps ??= PdfStampCollection(); - return _stamps!; - } - - //Implementation - void _intialize( - PdfPageTemplateElement? left, - PdfPageTemplateElement? top, - PdfPageTemplateElement? right, - PdfPageTemplateElement? bottom, - PdfPageTemplateElement? evenLeft, - PdfPageTemplateElement? evenTop, - PdfPageTemplateElement? evenRight, - PdfPageTemplateElement? evenBottom, - PdfPageTemplateElement? oddLeft, - PdfPageTemplateElement? oddTop, - PdfPageTemplateElement? oddRight, - PdfPageTemplateElement? oddBottom, - PdfStampCollection? stamps, - ) { - if (left != null) { - this.left = left; - } - if (top != null) { - this.top = top; - } - if (bottom != null) { - this.bottom = bottom; - } - if (right != null) { - this.right = right; - } - if (evenLeft != null) { - this.evenLeft = evenLeft; - } - if (evenTop != null) { - this.evenTop = evenTop; - } - if (evenRight != null) { - this.evenRight = evenRight; - } - if (evenBottom != null) { - this.evenBottom = evenBottom; - } - if (oddLeft != null) { - this.oddLeft = oddLeft; - } - if (oddTop != null) { - this.oddTop = oddTop; - } - if (oddRight != null) { - this.oddRight = oddRight; - } - if (oddBottom != null) { - this.oddBottom = oddBottom; - } - if (stamps != null) { - _stamps = stamps; - } - } - - PdfPageTemplateElement? _checkElement( - PdfPageTemplateElement? templateElement, - TemplateType type, - ) { - if (templateElement != null) { - if (PdfPageTemplateElementHelper.getHelper(templateElement).type != - TemplateType.none) { - throw ArgumentError.value( - type, - "Can't reassign the template element. Please, create new one.", - ); - } - PdfPageTemplateElementHelper.getHelper(templateElement).type = type; - } - return templateElement; - } -} - -/// A collection of stamps that are applied to the page templates. -class PdfStampCollection extends PdfObjectCollection { - /// Initializes a new instance of the [PdfStampCollection] class. - PdfStampCollection() : super() { - _helper = PdfStampCollectionHelper(this); - } - - late PdfStampCollectionHelper _helper; - - /// Adds a stamp element to the collection. - /// [PdfPageTemplateElement] used here to create stamp element. - int add(PdfPageTemplateElement template) { - return _helper.add(template); - } -} - -/// [PdfStampCollection] helper -class PdfStampCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfStampCollectionHelper(this.base) : super(base); - - /// internal field - late PdfStampCollection base; - - /// internal method - int add(PdfPageTemplateElement template) { - list.add(template); - return base.count - 1; - } -} - -/// [PdfDocumentTemplate] helper -class PdfDocumentTemplateHelper { - /// internal constructor - PdfDocumentTemplateHelper(this.base); - - /// internal field - PdfDocumentTemplate base; - - /// internal method - static PdfDocumentTemplateHelper getHelper(PdfDocumentTemplate template) { - return template._helper; - } - - /// internal method - PdfPageTemplateElement? getLeft(PdfPage page) { - PdfPageTemplateElement? template; - if (base.evenLeft != null || base.oddLeft != null || base.left != null) { - if (_isEven(page)) { - template = (base.evenLeft != null) ? base.evenLeft : base.left; - } else { - template = (base.oddLeft != null) ? base.oddLeft : base.left; - } - } - return template; - } - - /// internal method - PdfPageTemplateElement? getRight(PdfPage page) { - PdfPageTemplateElement? template; - if (base.evenRight != null || base.oddRight != null || base.right != null) { - if (_isEven(page)) { - template = (base.evenRight != null) ? base.evenRight : base.right; - } else { - template = (base.oddRight != null) ? base.oddRight : base.right; - } - } - return template; - } - - /// internal method - PdfPageTemplateElement? getTop(PdfPage page) { - PdfPageTemplateElement? template; - if (base.evenTop != null || base.oddTop != null || base.top != null) { - if (_isEven(page)) { - template = (base.evenTop != null) ? base.evenTop : base.top; - } else { - template = (base.oddTop != null) ? base.oddTop : base.top; - } - } - return template; - } - - /// internal method - PdfPageTemplateElement? getBottom(PdfPage page) { - PdfPageTemplateElement? template; - if (base.evenBottom != null || - base.oddBottom != null || - base.bottom != null) { - if (_isEven(page)) { - template = (base.evenBottom != null) ? base.evenBottom : base.bottom; - } else { - template = (base.oddBottom != null) ? base.oddBottom : base.bottom; - } - } - return template; - } - - bool _isEven(PdfPage page) { - final PdfPageCollection pages = - PdfSectionHelper.getHelper( - PdfPageHelper.getHelper(page).section!, - ).document!.pages; - int index = 0; - if (PdfPageCollectionHelper.getHelper( - pages, - ).pageCollectionIndex.containsKey(page)) { - index = - PdfPageCollectionHelper.getHelper(pages).pageCollectionIndex[page]! + - 1; - } else { - index = pages.indexOf(page) + 1; - } - return (index % 2) == 0; - } -} +import '../general/pdf_collection.dart'; +import '../pages/enum.dart'; +import '../pages/pdf_page.dart'; +import '../pages/pdf_page_collection.dart'; +import '../pages/pdf_page_template_element.dart'; +import '../pages/pdf_section.dart'; + +/// Encapsulates a page template for all the pages in the document. +class PdfDocumentTemplate { + //Constructors + /// Initializes a new instance of the [PdfDocumentTemplate] class. + PdfDocumentTemplate({ + PdfPageTemplateElement? left, + PdfPageTemplateElement? top, + PdfPageTemplateElement? right, + PdfPageTemplateElement? bottom, + PdfPageTemplateElement? evenLeft, + PdfPageTemplateElement? evenTop, + PdfPageTemplateElement? evenRight, + PdfPageTemplateElement? evenBottom, + PdfPageTemplateElement? oddLeft, + PdfPageTemplateElement? oddTop, + PdfPageTemplateElement? oddRight, + PdfPageTemplateElement? oddBottom, + PdfStampCollection? stamps, + }) { + _helper = PdfDocumentTemplateHelper(this); + _intialize( + left, + top, + right, + bottom, + evenLeft, + evenTop, + evenRight, + evenBottom, + oddLeft, + oddTop, + oddRight, + oddBottom, + stamps, + ); + } + + //Fields + late PdfDocumentTemplateHelper _helper; + PdfPageTemplateElement? _left; + PdfPageTemplateElement? _top; + PdfPageTemplateElement? _right; + PdfPageTemplateElement? _bottom; + PdfPageTemplateElement? _evenLeft; + PdfPageTemplateElement? _evenTop; + PdfPageTemplateElement? _evenRight; + PdfPageTemplateElement? _evenBottom; + PdfPageTemplateElement? _oddLeft; + PdfPageTemplateElement? _oddTop; + PdfPageTemplateElement? _oddRight; + PdfPageTemplateElement? _oddBottom; + PdfStampCollection? _stamps; + + //Properties + /// Gets a left page template. + PdfPageTemplateElement? get left => _left; + + /// Sets a left page template. + set left(PdfPageTemplateElement? value) { + _left = _checkElement(value, TemplateType.left); + } + + /// Gets a right page template. + PdfPageTemplateElement? get right => _right; + + /// Sets a right page template. + set right(PdfPageTemplateElement? value) { + _right = _checkElement(value, TemplateType.right); + } + + /// Gets a top page template. + PdfPageTemplateElement? get top => _top; + + /// Sets a top page template. + set top(PdfPageTemplateElement? value) { + _top = _checkElement(value, TemplateType.top); + } + + /// Gets a bottom page template. + PdfPageTemplateElement? get bottom => _bottom; + + /// Sets a bottom page template. + set bottom(PdfPageTemplateElement? value) { + _bottom = _checkElement(value, TemplateType.bottom); + } + + /// Gets a even left page template. + PdfPageTemplateElement? get evenLeft => _evenLeft; + + /// Sets a even left page template. + set evenLeft(PdfPageTemplateElement? value) { + _evenLeft = _checkElement(value, TemplateType.left); + } + + /// Gets a even right page template. + PdfPageTemplateElement? get evenRight => _evenRight; + + /// Sets a even right page template. + set evenRight(PdfPageTemplateElement? value) { + _evenRight = _checkElement(value, TemplateType.right); + } + + /// Gets a even top page template. + PdfPageTemplateElement? get evenTop => _evenTop; + + /// Sets a even top page template. + set evenTop(PdfPageTemplateElement? value) { + _evenTop = _checkElement(value, TemplateType.top); + } + + /// Gets a even bottom page template. + PdfPageTemplateElement? get evenBottom => _evenBottom; + + /// Sets a even bottom page template. + set evenBottom(PdfPageTemplateElement? value) { + _evenBottom = _checkElement(value, TemplateType.bottom); + } + + /// Gets a odd left page template. + PdfPageTemplateElement? get oddLeft => _oddLeft; + + /// Sets a odd left page template. + set oddLeft(PdfPageTemplateElement? value) { + _oddLeft = _checkElement(value, TemplateType.left); + } + + /// Gets a odd right page template. + PdfPageTemplateElement? get oddRight => _oddRight; + + /// Sets a odd right page template. + set oddRight(PdfPageTemplateElement? value) { + _oddRight = _checkElement(value, TemplateType.right); + } + + /// Gets a odd top page template. + PdfPageTemplateElement? get oddTop => _oddTop; + + /// Sets a odd top page template. + set oddTop(PdfPageTemplateElement? value) { + _oddTop = _checkElement(value, TemplateType.top); + } + + /// Gets a odd bottom page template. + PdfPageTemplateElement? get oddBottom => _oddBottom; + + /// Sets a odd bottom page template. + set oddBottom(PdfPageTemplateElement? value) { + _oddBottom = _checkElement(value, TemplateType.bottom); + } + + /// Gets a collection of stamp elements. + PdfStampCollection get stamps { + _stamps ??= PdfStampCollection(); + return _stamps!; + } + + //Implementation + void _intialize( + PdfPageTemplateElement? left, + PdfPageTemplateElement? top, + PdfPageTemplateElement? right, + PdfPageTemplateElement? bottom, + PdfPageTemplateElement? evenLeft, + PdfPageTemplateElement? evenTop, + PdfPageTemplateElement? evenRight, + PdfPageTemplateElement? evenBottom, + PdfPageTemplateElement? oddLeft, + PdfPageTemplateElement? oddTop, + PdfPageTemplateElement? oddRight, + PdfPageTemplateElement? oddBottom, + PdfStampCollection? stamps, + ) { + if (left != null) { + this.left = left; + } + if (top != null) { + this.top = top; + } + if (bottom != null) { + this.bottom = bottom; + } + if (right != null) { + this.right = right; + } + if (evenLeft != null) { + this.evenLeft = evenLeft; + } + if (evenTop != null) { + this.evenTop = evenTop; + } + if (evenRight != null) { + this.evenRight = evenRight; + } + if (evenBottom != null) { + this.evenBottom = evenBottom; + } + if (oddLeft != null) { + this.oddLeft = oddLeft; + } + if (oddTop != null) { + this.oddTop = oddTop; + } + if (oddRight != null) { + this.oddRight = oddRight; + } + if (oddBottom != null) { + this.oddBottom = oddBottom; + } + if (stamps != null) { + _stamps = stamps; + } + } + + PdfPageTemplateElement? _checkElement( + PdfPageTemplateElement? templateElement, + TemplateType type, + ) { + if (templateElement != null) { + if (PdfPageTemplateElementHelper.getHelper(templateElement).type != + TemplateType.none) { + throw ArgumentError.value( + type, + "Can't reassign the template element. Please, create new one.", + ); + } + PdfPageTemplateElementHelper.getHelper(templateElement).type = type; + } + return templateElement; + } +} + +/// A collection of stamps that are applied to the page templates. +class PdfStampCollection extends PdfObjectCollection { + /// Initializes a new instance of the [PdfStampCollection] class. + PdfStampCollection() : super() { + _helper = PdfStampCollectionHelper(this); + } + + late PdfStampCollectionHelper _helper; + + /// Adds a stamp element to the collection. + /// [PdfPageTemplateElement] used here to create stamp element. + int add(PdfPageTemplateElement template) { + return _helper.add(template); + } +} + +/// [PdfStampCollection] helper +class PdfStampCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfStampCollectionHelper(this.base) : super(base); + + /// internal field + late PdfStampCollection base; + + /// internal method + int add(PdfPageTemplateElement template) { + list.add(template); + return base.count - 1; + } +} + +/// [PdfDocumentTemplate] helper +class PdfDocumentTemplateHelper { + /// internal constructor + PdfDocumentTemplateHelper(this.base); + + /// internal field + PdfDocumentTemplate base; + + /// internal method + static PdfDocumentTemplateHelper getHelper(PdfDocumentTemplate template) { + return template._helper; + } + + /// internal method + PdfPageTemplateElement? getLeft(PdfPage page) { + PdfPageTemplateElement? template; + if (base.evenLeft != null || base.oddLeft != null || base.left != null) { + if (_isEven(page)) { + template = (base.evenLeft != null) ? base.evenLeft : base.left; + } else { + template = (base.oddLeft != null) ? base.oddLeft : base.left; + } + } + return template; + } + + /// internal method + PdfPageTemplateElement? getRight(PdfPage page) { + PdfPageTemplateElement? template; + if (base.evenRight != null || base.oddRight != null || base.right != null) { + if (_isEven(page)) { + template = (base.evenRight != null) ? base.evenRight : base.right; + } else { + template = (base.oddRight != null) ? base.oddRight : base.right; + } + } + return template; + } + + /// internal method + PdfPageTemplateElement? getTop(PdfPage page) { + PdfPageTemplateElement? template; + if (base.evenTop != null || base.oddTop != null || base.top != null) { + if (_isEven(page)) { + template = (base.evenTop != null) ? base.evenTop : base.top; + } else { + template = (base.oddTop != null) ? base.oddTop : base.top; + } + } + return template; + } + + /// internal method + PdfPageTemplateElement? getBottom(PdfPage page) { + PdfPageTemplateElement? template; + if (base.evenBottom != null || + base.oddBottom != null || + base.bottom != null) { + if (_isEven(page)) { + template = (base.evenBottom != null) ? base.evenBottom : base.bottom; + } else { + template = (base.oddBottom != null) ? base.oddBottom : base.bottom; + } + } + return template; + } + + bool _isEven(PdfPage page) { + final PdfPageCollection pages = + PdfSectionHelper.getHelper( + PdfPageHelper.getHelper(page).section!, + ).document!.pages; + int index = 0; + if (PdfPageCollectionHelper.getHelper( + pages, + ).pageCollectionIndex.containsKey(page)) { + index = + PdfPageCollectionHelper.getHelper(pages).pageCollectionIndex[page]! + + 1; + } else { + index = pages.indexOf(page) + 1; + } + return (index % 2) == 0; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_file_structure.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_file_structure.dart index fe2056da5..db87bca2a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_file_structure.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/pdf_document/pdf_file_structure.dart @@ -1,104 +1,104 @@ -import 'enums.dart'; - -/// This class represents a set of the properties that define -/// the internal structure of PDF file. -class PdfFileStructure { - //Constructor - /// Initializes a new instance of the [PdfFileStructure] class. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Set the PDF document version. - /// document.fileStructure.version = PdfVersion.version1_7; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfFileStructure() { - _version = PdfVersion.version1_7; - crossReferenceType = PdfCrossReferenceType.crossReferenceTable; - incrementalUpdate = true; - _fileID = false; - } - - //Fields - late PdfVersion _version; - late bool _fileID; - - /// Gets or sets a value indicating whether incremental update. - late bool incrementalUpdate; - - /// The type of PDF cross-reference. - /// - /// ```dart - /// //Create a PDF document. - /// PdfDocument document = PdfDocument(); - /// //Set the type of the PDF cross reference. - /// document.fileStructure.crossReferenceType = - /// PdfCrossReferenceType.crossReferenceStream; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - late PdfCrossReferenceType crossReferenceType; - - //Properties - /// Gets the version of the PDF document. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Set the PDF document version. - /// document.fileStructure.version = PdfVersion.version1_7; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - /// ``` - PdfVersion get version => _version; - - /// Sets the version of the PDF document. - /// - /// ```dart - /// //Create a PDF document instance. - /// PdfDocument document = PdfDocument(); - /// //Set the PDF document version. - /// document.fileStructure.version = PdfVersion.version1_7; - /// //Create page and draw text. - /// document.pages.add().graphics.drawString( - /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), - /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); - /// //Save and dispose document. - /// List bytes = await document.save(); - /// document.dispose(); - set version(PdfVersion value) { - _version = value; - if (value.index <= PdfVersion.version1_3.index) { - crossReferenceType = PdfCrossReferenceType.crossReferenceTable; - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfFileStructure] helper -class PdfFileStructureHelper { - /// internal method - static bool fileID(PdfFileStructure fileStructure, [bool? value]) { - if (value != null) { - fileStructure._fileID = value; - } - return fileStructure._fileID; - } -} +import 'enums.dart'; + +/// This class represents a set of the properties that define +/// the internal structure of PDF file. +class PdfFileStructure { + //Constructor + /// Initializes a new instance of the [PdfFileStructure] class. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Set the PDF document version. + /// document.fileStructure.version = PdfVersion.version1_7; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfFileStructure() { + _version = PdfVersion.version1_7; + crossReferenceType = PdfCrossReferenceType.crossReferenceTable; + incrementalUpdate = true; + _fileID = false; + } + + //Fields + late PdfVersion _version; + late bool _fileID; + + /// Gets or sets a value indicating whether incremental update. + late bool incrementalUpdate; + + /// The type of PDF cross-reference. + /// + /// ```dart + /// //Create a PDF document. + /// PdfDocument document = PdfDocument(); + /// //Set the type of the PDF cross reference. + /// document.fileStructure.crossReferenceType = + /// PdfCrossReferenceType.crossReferenceStream; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + late PdfCrossReferenceType crossReferenceType; + + //Properties + /// Gets the version of the PDF document. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Set the PDF document version. + /// document.fileStructure.version = PdfVersion.version1_7; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + /// ``` + PdfVersion get version => _version; + + /// Sets the version of the PDF document. + /// + /// ```dart + /// //Create a PDF document instance. + /// PdfDocument document = PdfDocument(); + /// //Set the PDF document version. + /// document.fileStructure.version = PdfVersion.version1_7; + /// //Create page and draw text. + /// document.pages.add().graphics.drawString( + /// 'Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), + /// brush: PdfBrushes.black, bounds: Rect.fromLTWH(0, 0, 0, 0)); + /// //Save and dispose document. + /// List bytes = await document.save(); + /// document.dispose(); + set version(PdfVersion value) { + _version = value; + if (value.index <= PdfVersion.version1_3.index) { + crossReferenceType = PdfCrossReferenceType.crossReferenceTable; + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfFileStructure] helper +class PdfFileStructureHelper { + /// internal method + static bool fileID(PdfFileStructure fileStructure, [bool? value]) { + if (value != null) { + fileStructure._fileID = value; + } + return fileStructure._fileID; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_array.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_array.dart index 2bc2728bc..9907cf33e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_array.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_array.dart @@ -1,258 +1,258 @@ -import 'dart:math'; - -import '../../interfaces/pdf_interface.dart'; -import '../drawing/drawing.dart'; -import '../io/enums.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_parser.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; - -/// internal class -class PdfArray implements IPdfPrimitive, IPdfChangable { - /// internal constructor - PdfArray([dynamic data]) { - if (data != null) { - if (data is PdfArray) { - elements.addAll(data.elements); - } else if (data is List || data is List) { - for (final num entry in data) { - final PdfNumber pdfNumber = PdfNumber(entry); - elements.add(pdfNumber); - } - } else if (data is List || data is List) { - data.forEach(elements.add); - } - } - } - - //Constants - /// internal field - static const String startMark = '['; - - /// internal field - static const String endMark = ']'; - - //Fields - // ignore: prefer_final_fields - /// internal field - List elements = []; - bool? _isChanged; - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - PdfArray? _clonedObject; - PdfCrossTable? _crossTable; - - //Properties - /// internal property - IPdfPrimitive? operator [](int index) => _getElement(index); - IPdfPrimitive? _getElement(int index) { - return elements[index]; - } - - /// internal method - void add(IPdfPrimitive element) { - elements.add(element); - } - - /// internal method - bool contains(IPdfPrimitive element) { - return elements.contains(element); - } - - /// internal method - void insert(int index, IPdfPrimitive element) { - if (index > elements.length) { - throw ArgumentError.value('index out of range $index'); - } else if (index == elements.length) { - elements.add(element); - } else { - elements.insert(index, element); - } - _isChanged = true; - } - - /// Cleares the array. - void clear() { - elements.clear(); - _isChanged = true; - } - - /// internal method - int indexOf(IPdfPrimitive element) { - return elements.indexOf(element); - } - - /// internal property - int get count => elements.length; - - //Static methods - /// internal method - static PdfArray fromRectangle(PdfRectangle rectangle) { - final List list = [ - rectangle.left, - rectangle.top, - rectangle.right, - rectangle.bottom, - ]; - return PdfArray(list); - } - - /// Converts an instance of the PdfArray to the RectangleF. - PdfRectangle toRectangle() { - if (count < 4) { - throw ArgumentError("Can't convert to rectangle."); - } - double x1, x2, y1, y2; - PdfNumber number = _getNumber(0); - x1 = number.value!.toDouble(); - number = _getNumber(1); - y1 = number.value!.toDouble(); - number = _getNumber(2); - x2 = number.value!.toDouble(); - number = _getNumber(3); - y2 = number.value!.toDouble(); - final double x = [x1, x2].reduce(min); - final double y = [y1, y2].reduce(min); - final double width = (x1 - x2).abs(); - final double height = (y1 - y2).abs(); - final PdfRectangle rect = PdfRectangle(x, y, width, height); - return rect; - } - - // Gets the number from the array. - PdfNumber _getNumber(int index) { - final PdfNumber? number = - PdfCrossTable.dereference(this[index]) as PdfNumber?; - if (number == null) { - throw ArgumentError("Can't convert to rectangle."); - } - return number; - } - - //IPdfPrimitive members - @override - bool? get changed { - _isChanged ??= false; - return _isChanged; - } - - @override - set changed(bool? value) { - _isChanged = value; - } - - @override - IPdfPrimitive? clonedObject; - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - void save(IPdfWriter? writer) { - if (writer != null) { - writer.write(startMark); - for (int i = 0; i < count; i++) { - if (this[i] != null && this[i] is! PdfNull) { - this[i]!.save(writer); - if (i + 1 != count) { - writer.write(PdfOperators.whiteSpace); - } - } - } - writer.write(endMark); - } - } - - /// internal method - void removeAt(int index) { - elements.removeAt(index); - _isChanged = true; - } - - /// internal method - void remove(IPdfPrimitive element) { - final bool hasRemoved = elements.remove(element); - if (elements.isNotEmpty) { - changed = changed! | hasRemoved; - } - } - - @override - void dispose() { - if (elements.isNotEmpty) { - elements.clear(); - } - if (_status != null) { - _status = null; - } - } - - //IPdfChangable members - @override - void freezeChanges(Object? freezer) { - if (freezer is PdfParser || freezer is PdfDictionary) { - _isChanged = false; - } - } - - @override - IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { - if (_clonedObject != null && _clonedObject!._crossTable == crossTable) { - return _clonedObject; - } else { - _clonedObject = null; - } - final PdfArray newArray = PdfArray(); - for (final IPdfPrimitive? obj in elements) { - newArray.add(obj!.cloneObject(crossTable)!); - } - newArray._crossTable = crossTable; - _clonedObject = newArray; - return newArray; - } -} +import 'dart:math'; + +import '../../interfaces/pdf_interface.dart'; +import '../drawing/drawing.dart'; +import '../io/enums.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_parser.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; + +/// internal class +class PdfArray implements IPdfPrimitive, IPdfChangable { + /// internal constructor + PdfArray([dynamic data]) { + if (data != null) { + if (data is PdfArray) { + elements.addAll(data.elements); + } else if (data is List || data is List) { + for (final num entry in data) { + final PdfNumber pdfNumber = PdfNumber(entry); + elements.add(pdfNumber); + } + } else if (data is List || data is List) { + data.forEach(elements.add); + } + } + } + + //Constants + /// internal field + static const String startMark = '['; + + /// internal field + static const String endMark = ']'; + + //Fields + // ignore: prefer_final_fields + /// internal field + List elements = []; + bool? _isChanged; + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + PdfArray? _clonedObject; + PdfCrossTable? _crossTable; + + //Properties + /// internal property + IPdfPrimitive? operator [](int index) => _getElement(index); + IPdfPrimitive? _getElement(int index) { + return elements[index]; + } + + /// internal method + void add(IPdfPrimitive element) { + elements.add(element); + } + + /// internal method + bool contains(IPdfPrimitive element) { + return elements.contains(element); + } + + /// internal method + void insert(int index, IPdfPrimitive element) { + if (index > elements.length) { + throw ArgumentError.value('index out of range $index'); + } else if (index == elements.length) { + elements.add(element); + } else { + elements.insert(index, element); + } + _isChanged = true; + } + + /// Cleares the array. + void clear() { + elements.clear(); + _isChanged = true; + } + + /// internal method + int indexOf(IPdfPrimitive element) { + return elements.indexOf(element); + } + + /// internal property + int get count => elements.length; + + //Static methods + /// internal method + static PdfArray fromRectangle(PdfRectangle rectangle) { + final List list = [ + rectangle.left, + rectangle.top, + rectangle.right, + rectangle.bottom, + ]; + return PdfArray(list); + } + + /// Converts an instance of the PdfArray to the RectangleF. + PdfRectangle toRectangle() { + if (count < 4) { + throw ArgumentError("Can't convert to rectangle."); + } + double x1, x2, y1, y2; + PdfNumber number = _getNumber(0); + x1 = number.value!.toDouble(); + number = _getNumber(1); + y1 = number.value!.toDouble(); + number = _getNumber(2); + x2 = number.value!.toDouble(); + number = _getNumber(3); + y2 = number.value!.toDouble(); + final double x = [x1, x2].reduce(min); + final double y = [y1, y2].reduce(min); + final double width = (x1 - x2).abs(); + final double height = (y1 - y2).abs(); + final PdfRectangle rect = PdfRectangle(x, y, width, height); + return rect; + } + + // Gets the number from the array. + PdfNumber _getNumber(int index) { + final PdfNumber? number = + PdfCrossTable.dereference(this[index]) as PdfNumber?; + if (number == null) { + throw ArgumentError("Can't convert to rectangle."); + } + return number; + } + + //IPdfPrimitive members + @override + bool? get changed { + _isChanged ??= false; + return _isChanged; + } + + @override + set changed(bool? value) { + _isChanged = value; + } + + @override + IPdfPrimitive? clonedObject; + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + void save(IPdfWriter? writer) { + if (writer != null) { + writer.write(startMark); + for (int i = 0; i < count; i++) { + if (this[i] != null && this[i] is! PdfNull) { + this[i]!.save(writer); + if (i + 1 != count) { + writer.write(PdfOperators.whiteSpace); + } + } + } + writer.write(endMark); + } + } + + /// internal method + void removeAt(int index) { + elements.removeAt(index); + _isChanged = true; + } + + /// internal method + void remove(IPdfPrimitive element) { + final bool hasRemoved = elements.remove(element); + if (elements.isNotEmpty) { + changed = changed! | hasRemoved; + } + } + + @override + void dispose() { + if (elements.isNotEmpty) { + elements.clear(); + } + if (_status != null) { + _status = null; + } + } + + //IPdfChangable members + @override + void freezeChanges(Object? freezer) { + if (freezer is PdfParser || freezer is PdfDictionary) { + _isChanged = false; + } + } + + @override + IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { + if (_clonedObject != null && _clonedObject!._crossTable == crossTable) { + return _clonedObject; + } else { + _clonedObject = null; + } + final PdfArray newArray = PdfArray(); + for (final IPdfPrimitive? obj in elements) { + newArray.add(obj!.cloneObject(crossTable)!); + } + newArray._crossTable = crossTable; + _clonedObject = newArray; + return newArray; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_boolean.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_boolean.dart index 28e50bf51..c7ef06b2b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_boolean.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_boolean.dart @@ -1,84 +1,84 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_cross_table.dart'; - -/// internal class -class PdfBoolean implements IPdfPrimitive { - /// internal constructor - PdfBoolean([bool? v]) { - if (v != null) { - value = v; - } - } - - //Fields - /// internal field - bool? value = false; - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - - //IPdfPrimitive members - @override - IPdfPrimitive? clonedObject; - - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - void save(IPdfWriter? writer) { - writer!.write(value! ? 'true' : 'false'); - } - - @override - void dispose() { - if (_status != null) { - _status = null; - } - } - - @override - IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfBoolean(value); -} +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_cross_table.dart'; + +/// internal class +class PdfBoolean implements IPdfPrimitive { + /// internal constructor + PdfBoolean([bool? v]) { + if (v != null) { + value = v; + } + } + + //Fields + /// internal field + bool? value = false; + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + + //IPdfPrimitive members + @override + IPdfPrimitive? clonedObject; + + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + void save(IPdfWriter? writer) { + writer!.write(value! ? 'true' : 'false'); + } + + @override + void dispose() { + if (_status != null) { + _status = null; + } + } + + @override + IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfBoolean(value); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart index 2a4ef2cfd..bb9d06c82 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_dictionary.dart @@ -1,641 +1,641 @@ -import 'package:intl/intl.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_parser.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_stream.dart'; -import '../primitives/pdf_string.dart'; -import '../security/pdf_encryptor.dart'; -import '../security/pdf_security.dart'; - -/// internal class -class PdfDictionary implements IPdfPrimitive, IPdfChangable { - /// Constructor to create a [PdfDictionary] object. - PdfDictionary([PdfDictionary? dictionary]) { - items = {}; - copyDictionary(dictionary); - _encrypt = true; - decrypted = false; - } - - //Constants - /// internal field - static const String prefix = '<<'; - - /// internal field - static const String suffix = '>>'; - - //Fields - /// internal field - Map? items; - - /// internal property - bool? isChanged; - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - bool? _isSkip; - - /// internal field - PdfCrossTable? crossTable; - - /// internal field - bool archive = true; - bool? _encrypt; - - /// internal field - bool? decrypted; - - //Properties - /// Get the PdfDictionary items. - IPdfPrimitive? operator [](dynamic key) => returnValue(checkName(key)); - - /// Set the PdfDictionary items. - operator []=(dynamic key, dynamic value) => addItems(key, value); - - /// internal property - bool get isSkip { - _isSkip ??= false; - return _isSkip!; - } - - set isSkip(bool value) { - _isSkip = value; - } - - /// internal method - dynamic addItems(dynamic key, dynamic value) { - if (key == null) { - throw ArgumentError.value(key, 'key', 'value cannot be null'); - } - if (value == null) { - throw ArgumentError.value(value, 'value', 'value cannot be null'); - } - items![checkName(key)] = value as IPdfPrimitive?; - modify(); - return value; - } - - /// Get the length of the item. - int get count => items!.length; - - /// Get the values of the item. - List get value => items!.values as List; - - /// internal property - bool? get encrypt => _encrypt; - - set encrypt(bool? value) { - _encrypt = value; - modify(); - } - - //Implementation - /// internal method - void copyDictionary(PdfDictionary? dictionary) { - if (dictionary != null) { - dictionary.items!.forEach( - (PdfName? k, IPdfPrimitive? v) => addItems(k, v), - ); - freezeChanges(this); - } - } - - /// Check and return the valid name. - PdfName? checkName(dynamic key) { - if (key is PdfName) { - return key; - } else if (key is String) { - return PdfName(key); - } else { - return null; - } - } - - /// Check key and return the value. - IPdfPrimitive? returnValue(dynamic key) { - if (items!.containsKey(key)) { - return items![key]; - } else { - return null; - } - } - - /// internal method - bool containsKey(dynamic key) { - if (key is String) { - return items!.containsKey(PdfName(key)); - } else if (key is PdfName) { - return items!.containsKey(key); - } - return false; - } - - /// internal method - void remove(dynamic key) { - if (key == null) { - throw ArgumentError.value(key, 'key', 'value cannot be null'); - } - final PdfName name = key is PdfName ? key : PdfName(key); - items!.remove(name); - modify(); - } - - /// internal method - void clear() { - items!.clear(); - modify(); - } - - /// internal method - void modify() { - changed = true; - } - - /// internal method - void setProperty(dynamic key, dynamic value) { - if (value == null) { - if (key is String) { - items!.remove(PdfName(key)); - } else if (key is PdfName) { - items!.remove(key); - } - } else { - if (value is IPdfWrapper) { - value = IPdfWrapper.getElement(value); - } - this[key] = value; - } - modify(); - } - - /// internal method - void setName(dynamic key, String? name) { - if (key is String) { - key = PdfName(key); - } - if (items!.containsKey(key)) { - this[key] = PdfName(name); - modify(); - } else { - this[key] = PdfName(name); - } - } - - /// internal method - void setArray(String key, List list) { - PdfArray? pdfArray = this[key] as PdfArray?; - if (pdfArray != null) { - pdfArray.clear(); - modify(); - } else { - pdfArray = PdfArray(); - this[key] = pdfArray; - } - for (int i = 0; i < list.length; i++) { - pdfArray.add(list.elementAt(i)); - } - } - - /// internal method - void setString(String key, String? str) { - if (containsKey(key) && this[key] is PdfString) { - final IPdfPrimitive? pdfString = this[key]; - if (pdfString != null && pdfString is PdfString) { - pdfString.value = str; - modify(); - } - } else { - this[key] = PdfString(str!); - } - } - - /// internal method - void saveDictionary(IPdfWriter writer, bool enableEvents) { - writer.write(prefix); - if (enableEvents) { - final SavePdfPrimitiveArgs args = SavePdfPrimitiveArgs(writer); - onBeginSave(args); - } - if (count > 0) { - final PdfEncryptor encryptor = - PdfSecurityHelper.getHelper(writer.document!.security).encryptor; - final bool state = encryptor.encrypt; - if (!_encrypt!) { - encryptor.encrypt = false; - } - _saveItems(writer); - if (!_encrypt!) { - encryptor.encrypt = state; - } - } - writer.write(suffix); - writer.write(PdfOperators.newLine); - if (enableEvents) { - final SavePdfPrimitiveArgs args = SavePdfPrimitiveArgs(writer); - onEndSave(args); - } - } - - void _saveItems(IPdfWriter writer) { - writer.write(PdfOperators.newLine); - items!.forEach((PdfName? key, IPdfPrimitive? value) { - key!.save(writer); - writer.write(PdfOperators.whiteSpace); - final PdfName name = key; - if (name.name == 'Fields') { - final IPdfPrimitive? fields = value; - final List fieldCollection = []; - if (fields is PdfArray) { - for (int k = 0; k < fields.count; k++) { - if (fields.elements[k] is PdfReferenceHolder) { - final PdfReferenceHolder referenceHolder = - fields.elements[k]! as PdfReferenceHolder; - fieldCollection.add(referenceHolder); - } - } - for (int i = 0; i < fields.count; i++) { - if (fields.elements[i]! is PdfReferenceHolder) { - final PdfReferenceHolder refHolder = - fields.elements[i]! as PdfReferenceHolder; - final PdfDictionary? field = - refHolder.referenceObject as PdfDictionary?; - if (field != null) { - if (field.beginSave != null) { - final SavePdfPrimitiveArgs args = SavePdfPrimitiveArgs( - writer, - ); - field.beginSave!(field, args); - } - if (!field.containsKey(PdfName(PdfDictionaryProperties.kids))) { - if (field.items!.containsKey( - PdfName(PdfDictionaryProperties.ft), - )) { - final IPdfPrimitive? value = - field.items![PdfName(PdfDictionaryProperties.ft)]; - if (value != null && - value is PdfName && - value.name == 'Sig') { - for (int k = 0; k < fields.count; k++) { - if (k == i) { - continue; - } - final PdfReferenceHolder fieldRef = - fields.elements[k]! as PdfReferenceHolder; - final PdfDictionary field1 = - fieldRef.object! as PdfDictionary; - if (field1.items!.containsKey( - PdfName(PdfDictionaryProperties.t), - ) && - field.items!.containsKey( - PdfName(PdfDictionaryProperties.t), - )) { - final PdfString parentSignatureName = - field1.items![PdfName(PdfDictionaryProperties.t)]! - as PdfString; - final PdfString childName = - field.items![PdfName(PdfDictionaryProperties.t)]! - as PdfString; - if (parentSignatureName.value == childName.value) { - fields.remove(refHolder); - } - } - } - } - } - } - } - } - } - value = fields; - } - } - value!.save(writer); - writer.write(PdfOperators.newLine); - }); - } - - /// internal method - IPdfPrimitive? getValue(String key, String parentKey) { - PdfDictionary? dictionary = this; - IPdfPrimitive? element = PdfCrossTable.dereference(dictionary[key]); - while (element == null) { - dictionary = - PdfCrossTable.dereference(dictionary![parentKey]) as PdfDictionary?; - if (dictionary == null) { - break; - } - element = PdfCrossTable.dereference(dictionary[key]); - } - return element; - } - - /// internal method - int getInt(String propertyName) { - final IPdfPrimitive? primitive = PdfCrossTable.dereference( - this[propertyName], - ); - return (primitive != null && primitive is PdfNumber) - ? primitive.value!.toInt() - : 0; - } - - /// internal method - PdfString? getString(String propertyName) { - final IPdfPrimitive? primitive = PdfCrossTable.dereference( - this[propertyName], - ); - return (primitive != null && primitive is PdfString) ? primitive : null; - } - - /// internal method - bool checkChanges() { - bool result = false; - final List keys = items!.keys.toList(); - for (int i = 0; i < keys.length; i++) { - final IPdfPrimitive? primitive = items![keys[i]]; - if (primitive is IPdfChangable && - (primitive! as IPdfChangable).changed!) { - result = true; - break; - } - } - return result; - } - - /// internal method - void setNumber(String key, num? value) { - final PdfNumber? pdfNumber = this[key] as PdfNumber?; - if (pdfNumber != null) { - pdfNumber.value = value; - modify(); - } else { - this[key] = PdfNumber(value!); - } - } - - /// internal method - void setBoolean(String key, bool? value) { - final PdfBoolean? pdfBoolean = this[key] as PdfBoolean?; - if (pdfBoolean != null) { - pdfBoolean.value = value; - modify(); - } else { - this[key] = PdfBoolean(value); - } - } - - /// internal method - void setDateTime(String key, DateTime dateTime) { - final DateFormat dateFormat = DateFormat('yyyyMMddHHmmss'); - final int regionMinutes = dateTime.timeZoneOffset.inMinutes ~/ 11; - String offsetMinutes = regionMinutes.toString(); - if (regionMinutes >= 0 && regionMinutes <= 9) { - offsetMinutes = '0$offsetMinutes'; - } - final int regionHours = dateTime.timeZoneOffset.inHours; - String offsetHours = regionHours.toString(); - if (regionHours >= 0 && regionHours <= 9) { - offsetHours = '0$offsetHours'; - } - final IPdfPrimitive? primitive = this[key]; - if (primitive != null && primitive is PdfString) { - primitive.value = - "D:${dateFormat.format(dateTime)}+$offsetHours'$offsetMinutes'"; - modify(); - } else { - this[key] = PdfString( - "D:${dateFormat.format(dateTime)}+$offsetHours'$offsetMinutes'", - ); - } - } - - /// Gets the date time from Pdf standard date format. - DateTime getDateTime(PdfString dateTimeStringValue) { - const String prefixD = 'D:'; - final PdfString dateTimeString = PdfString(dateTimeStringValue.value!); - String value = dateTimeString.value!; - while (value.startsWith(RegExp('[:-D-(-)]'))) { - dateTimeString.value = value.replaceFirst(value[0], ''); - value = dateTimeString.value!; - } - while (value[value.length - 1].contains(RegExp('[:-D-(-)]'))) { - dateTimeString.value = value.replaceRange( - value.length - 1, - value.length, - '', - ); - } - if (dateTimeString.value!.startsWith('191')) { - dateTimeString.value = dateTimeString.value!.replaceFirst('191', '20'); - } - final bool containPrefixD = dateTimeString.value!.contains(prefixD); - const String dateTimeFormat = 'yyyyMMddHHmmss'; - dateTimeString.value = dateTimeString.value!.padRight( - dateTimeFormat.length, - '0', - ); - String localTime = ''.padRight(dateTimeFormat.length); - if (dateTimeString.value!.isEmpty) { - return DateTime.now(); - } - if (dateTimeString.value!.length >= localTime.length) { - localTime = - containPrefixD - ? dateTimeString.value!.substring( - prefixD.length, - localTime.length, - ) - : dateTimeString.value!.substring(0, localTime.length); - } - final String dateWithT = - '${localTime.substring(0, 8)}T${localTime.substring(8)}'; - try { - final DateTime dateTime = DateTime.parse(dateWithT); - return dateTime; - } catch (e) { - return DateTime.now(); - } - } - - //IPdfChangable members - @override - bool? get changed { - isChanged ??= false; - if (!isChanged!) { - isChanged = checkChanges(); - } - return isChanged; - } - - @override - set changed(bool? value) { - isChanged = value; - } - - @override - void freezeChanges(dynamic freezer) { - if (freezer is PdfParser || freezer is PdfDictionary) { - isChanged = false; - } - } - - //IPdfPrimitive members - @override - IPdfPrimitive? clonedObject; - - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - void save(IPdfWriter? writer) { - saveDictionary(writer!, true); - } - - @override - void dispose() { - if (items != null && items!.isNotEmpty) { - final List primitives = items!.keys.toList(); - for (int i = 0; i < primitives.length; i++) { - final PdfName? key = primitives[i] as PdfName?; - items![key!]!.dispose(); - } - items!.clear(); - items = null; - } - if (_status != null) { - _status = null; - } - } - - //Events - /// internal field - SavePdfPrimitiveCallback? beginSave; - - /// internal field - List? beginSaveList; - - /// internal field - SavePdfPrimitiveCallback? endSave; - - /// internal method - void onBeginSave(SavePdfPrimitiveArgs args) { - if (beginSave != null) { - beginSave!(this, args); - } - if (beginSaveList != null) { - for (int i = 0; i < beginSaveList!.length; i++) { - beginSaveList![i](this, args); - } - } - } - - /// internal method - void onEndSave(SavePdfPrimitiveArgs args) { - if (endSave != null) { - endSave!(this, args); - } - } - - @override - IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { - if (this is! PdfStream) { - if (clonedObject != null && - (clonedObject is PdfDictionary == true) && - (clonedObject! as PdfDictionary).crossTable == crossTable) { - return clonedObject; - } else { - clonedObject = null; - } - } - final PdfDictionary newDict = PdfDictionary(); - items!.forEach((PdfName? key, IPdfPrimitive? value) { - final PdfName? name = key; - final IPdfPrimitive obj = value!; - final IPdfPrimitive? newObj = obj.cloneObject(crossTable); - if (newObj is! PdfNull) { - newDict[name] = newObj; - } - }); - newDict.archive = archive; - newDict.status = _status; - newDict.freezeChanges(this); - newDict.crossTable = crossTable; - - if (this is! PdfStream) { - clonedObject = newDict; - } - return newDict; - } -} - -/// internal class -class SavePdfPrimitiveArgs { - /// internal constructor - SavePdfPrimitiveArgs(IPdfWriter? writer) { - if (writer == null) { - throw ArgumentError.notNull('writer'); - } else { - _writer = writer; - } - } - - IPdfWriter? _writer; - - /// internal property - IPdfWriter? get writer => _writer; -} - -/// internal type definition -typedef SavePdfPrimitiveCallback = - void Function(Object sender, SavePdfPrimitiveArgs? args); +import 'package:intl/intl.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_parser.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_stream.dart'; +import '../primitives/pdf_string.dart'; +import '../security/pdf_encryptor.dart'; +import '../security/pdf_security.dart'; + +/// internal class +class PdfDictionary implements IPdfPrimitive, IPdfChangable { + /// Constructor to create a [PdfDictionary] object. + PdfDictionary([PdfDictionary? dictionary]) { + items = {}; + copyDictionary(dictionary); + _encrypt = true; + decrypted = false; + } + + //Constants + /// internal field + static const String prefix = '<<'; + + /// internal field + static const String suffix = '>>'; + + //Fields + /// internal field + Map? items; + + /// internal property + bool? isChanged; + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + bool? _isSkip; + + /// internal field + PdfCrossTable? crossTable; + + /// internal field + bool archive = true; + bool? _encrypt; + + /// internal field + bool? decrypted; + + //Properties + /// Get the PdfDictionary items. + IPdfPrimitive? operator [](dynamic key) => returnValue(checkName(key)); + + /// Set the PdfDictionary items. + void operator []=(dynamic key, dynamic value) => addItems(key, value); + + /// internal property + bool get isSkip { + _isSkip ??= false; + return _isSkip!; + } + + set isSkip(bool value) { + _isSkip = value; + } + + /// internal method + dynamic addItems(dynamic key, dynamic value) { + if (key == null) { + throw ArgumentError.value(key, 'key', 'value cannot be null'); + } + if (value == null) { + throw ArgumentError.value(value, 'value', 'value cannot be null'); + } + items![checkName(key)] = value as IPdfPrimitive?; + modify(); + return value; + } + + /// Get the length of the item. + int get count => items!.length; + + /// Get the values of the item. + List get value => items!.values as List; + + /// internal property + bool? get encrypt => _encrypt; + + set encrypt(bool? value) { + _encrypt = value; + modify(); + } + + //Implementation + /// internal method + void copyDictionary(PdfDictionary? dictionary) { + if (dictionary != null) { + dictionary.items!.forEach( + (PdfName? k, IPdfPrimitive? v) => addItems(k, v), + ); + freezeChanges(this); + } + } + + /// Check and return the valid name. + PdfName? checkName(dynamic key) { + if (key is PdfName) { + return key; + } else if (key is String) { + return PdfName(key); + } else { + return null; + } + } + + /// Check key and return the value. + IPdfPrimitive? returnValue(dynamic key) { + if (items!.containsKey(key)) { + return items![key]; + } else { + return null; + } + } + + /// internal method + bool containsKey(dynamic key) { + if (key is String) { + return items!.containsKey(PdfName(key)); + } else if (key is PdfName) { + return items!.containsKey(key); + } + return false; + } + + /// internal method + void remove(dynamic key) { + if (key == null) { + throw ArgumentError.value(key, 'key', 'value cannot be null'); + } + final PdfName name = key is PdfName ? key : PdfName(key); + items!.remove(name); + modify(); + } + + /// internal method + void clear() { + items!.clear(); + modify(); + } + + /// internal method + void modify() { + changed = true; + } + + /// internal method + void setProperty(dynamic key, dynamic value) { + if (value == null) { + if (key is String) { + items!.remove(PdfName(key)); + } else if (key is PdfName) { + items!.remove(key); + } + } else { + if (value is IPdfWrapper) { + value = IPdfWrapper.getElement(value); + } + this[key] = value; + } + modify(); + } + + /// internal method + void setName(dynamic key, String? name) { + if (key is String) { + key = PdfName(key); + } + if (items!.containsKey(key)) { + this[key] = PdfName(name); + modify(); + } else { + this[key] = PdfName(name); + } + } + + /// internal method + void setArray(String key, List list) { + PdfArray? pdfArray = this[key] as PdfArray?; + if (pdfArray != null) { + pdfArray.clear(); + modify(); + } else { + pdfArray = PdfArray(); + this[key] = pdfArray; + } + for (int i = 0; i < list.length; i++) { + pdfArray.add(list.elementAt(i)); + } + } + + /// internal method + void setString(String key, String? str) { + if (containsKey(key) && this[key] is PdfString) { + final IPdfPrimitive? pdfString = this[key]; + if (pdfString != null && pdfString is PdfString) { + pdfString.value = str; + modify(); + } + } else { + this[key] = PdfString(str!); + } + } + + /// internal method + void saveDictionary(IPdfWriter writer, bool enableEvents) { + writer.write(prefix); + if (enableEvents) { + final SavePdfPrimitiveArgs args = SavePdfPrimitiveArgs(writer); + onBeginSave(args); + } + if (count > 0) { + final PdfEncryptor encryptor = + PdfSecurityHelper.getHelper(writer.document!.security).encryptor; + final bool state = encryptor.encrypt; + if (!_encrypt!) { + encryptor.encrypt = false; + } + _saveItems(writer); + if (!_encrypt!) { + encryptor.encrypt = state; + } + } + writer.write(suffix); + writer.write(PdfOperators.newLine); + if (enableEvents) { + final SavePdfPrimitiveArgs args = SavePdfPrimitiveArgs(writer); + onEndSave(args); + } + } + + void _saveItems(IPdfWriter writer) { + writer.write(PdfOperators.newLine); + items!.forEach((PdfName? key, IPdfPrimitive? value) { + key!.save(writer); + writer.write(PdfOperators.whiteSpace); + final PdfName name = key; + if (name.name == 'Fields') { + final IPdfPrimitive? fields = value; + final List fieldCollection = []; + if (fields is PdfArray) { + for (int k = 0; k < fields.count; k++) { + if (fields.elements[k] is PdfReferenceHolder) { + final PdfReferenceHolder referenceHolder = + fields.elements[k]! as PdfReferenceHolder; + fieldCollection.add(referenceHolder); + } + } + for (int i = 0; i < fields.count; i++) { + if (fields.elements[i]! is PdfReferenceHolder) { + final PdfReferenceHolder refHolder = + fields.elements[i]! as PdfReferenceHolder; + final PdfDictionary? field = + refHolder.referenceObject as PdfDictionary?; + if (field != null) { + if (field.beginSave != null) { + final SavePdfPrimitiveArgs args = SavePdfPrimitiveArgs( + writer, + ); + field.beginSave!(field, args); + } + if (!field.containsKey(PdfName(PdfDictionaryProperties.kids))) { + if (field.items!.containsKey( + PdfName(PdfDictionaryProperties.ft), + )) { + final IPdfPrimitive? value = + field.items![PdfName(PdfDictionaryProperties.ft)]; + if (value != null && + value is PdfName && + value.name == 'Sig') { + for (int k = 0; k < fields.count; k++) { + if (k == i) { + continue; + } + final PdfReferenceHolder fieldRef = + fields.elements[k]! as PdfReferenceHolder; + final PdfDictionary field1 = + fieldRef.object! as PdfDictionary; + if (field1.items!.containsKey( + PdfName(PdfDictionaryProperties.t), + ) && + field.items!.containsKey( + PdfName(PdfDictionaryProperties.t), + )) { + final PdfString parentSignatureName = + field1.items![PdfName(PdfDictionaryProperties.t)]! + as PdfString; + final PdfString childName = + field.items![PdfName(PdfDictionaryProperties.t)]! + as PdfString; + if (parentSignatureName.value == childName.value) { + fields.remove(refHolder); + } + } + } + } + } + } + } + } + } + value = fields; + } + } + value!.save(writer); + writer.write(PdfOperators.newLine); + }); + } + + /// internal method + IPdfPrimitive? getValue(String key, String parentKey) { + PdfDictionary? dictionary = this; + IPdfPrimitive? element = PdfCrossTable.dereference(dictionary[key]); + while (element == null) { + dictionary = + PdfCrossTable.dereference(dictionary![parentKey]) as PdfDictionary?; + if (dictionary == null) { + break; + } + element = PdfCrossTable.dereference(dictionary[key]); + } + return element; + } + + /// internal method + int getInt(String propertyName) { + final IPdfPrimitive? primitive = PdfCrossTable.dereference( + this[propertyName], + ); + return (primitive != null && primitive is PdfNumber) + ? primitive.value!.toInt() + : 0; + } + + /// internal method + PdfString? getString(String propertyName) { + final IPdfPrimitive? primitive = PdfCrossTable.dereference( + this[propertyName], + ); + return (primitive != null && primitive is PdfString) ? primitive : null; + } + + /// internal method + bool checkChanges() { + bool result = false; + final List keys = items!.keys.toList(); + for (int i = 0; i < keys.length; i++) { + final IPdfPrimitive? primitive = items![keys[i]]; + if (primitive is IPdfChangable && + (primitive! as IPdfChangable).changed!) { + result = true; + break; + } + } + return result; + } + + /// internal method + void setNumber(String key, num? value) { + final PdfNumber? pdfNumber = this[key] as PdfNumber?; + if (pdfNumber != null) { + pdfNumber.value = value; + modify(); + } else { + this[key] = PdfNumber(value!); + } + } + + /// internal method + void setBoolean(String key, bool? value) { + final PdfBoolean? pdfBoolean = this[key] as PdfBoolean?; + if (pdfBoolean != null) { + pdfBoolean.value = value; + modify(); + } else { + this[key] = PdfBoolean(value); + } + } + + /// internal method + void setDateTime(String key, DateTime dateTime) { + final DateFormat dateFormat = DateFormat('yyyyMMddHHmmss'); + final int regionMinutes = dateTime.timeZoneOffset.inMinutes ~/ 11; + String offsetMinutes = regionMinutes.toString(); + if (regionMinutes >= 0 && regionMinutes <= 9) { + offsetMinutes = '0$offsetMinutes'; + } + final int regionHours = dateTime.timeZoneOffset.inHours; + String offsetHours = regionHours.toString(); + if (regionHours >= 0 && regionHours <= 9) { + offsetHours = '0$offsetHours'; + } + final IPdfPrimitive? primitive = this[key]; + if (primitive != null && primitive is PdfString) { + primitive.value = + "D:${dateFormat.format(dateTime)}+$offsetHours'$offsetMinutes'"; + modify(); + } else { + this[key] = PdfString( + "D:${dateFormat.format(dateTime)}+$offsetHours'$offsetMinutes'", + ); + } + } + + /// Gets the date time from Pdf standard date format. + DateTime getDateTime(PdfString dateTimeStringValue) { + const String prefixD = 'D:'; + final PdfString dateTimeString = PdfString(dateTimeStringValue.value!); + String value = dateTimeString.value!; + while (value.startsWith(RegExp('[:-D-(-)]'))) { + dateTimeString.value = value.replaceFirst(value[0], ''); + value = dateTimeString.value!; + } + while (value[value.length - 1].contains(RegExp('[:-D-(-)]'))) { + dateTimeString.value = value.replaceRange( + value.length - 1, + value.length, + '', + ); + } + if (dateTimeString.value!.startsWith('191')) { + dateTimeString.value = dateTimeString.value!.replaceFirst('191', '20'); + } + final bool containPrefixD = dateTimeString.value!.contains(prefixD); + const String dateTimeFormat = 'yyyyMMddHHmmss'; + dateTimeString.value = dateTimeString.value!.padRight( + dateTimeFormat.length, + '0', + ); + String localTime = ''.padRight(dateTimeFormat.length); + if (dateTimeString.value!.isEmpty) { + return DateTime.now(); + } + if (dateTimeString.value!.length >= localTime.length) { + localTime = + containPrefixD + ? dateTimeString.value!.substring( + prefixD.length, + localTime.length, + ) + : dateTimeString.value!.substring(0, localTime.length); + } + final String dateWithT = + '${localTime.substring(0, 8)}T${localTime.substring(8)}'; + try { + final DateTime dateTime = DateTime.parse(dateWithT); + return dateTime; + } catch (e) { + return DateTime.now(); + } + } + + //IPdfChangable members + @override + bool? get changed { + isChanged ??= false; + if (!isChanged!) { + isChanged = checkChanges(); + } + return isChanged; + } + + @override + set changed(bool? value) { + isChanged = value; + } + + @override + void freezeChanges(dynamic freezer) { + if (freezer is PdfParser || freezer is PdfDictionary) { + isChanged = false; + } + } + + //IPdfPrimitive members + @override + IPdfPrimitive? clonedObject; + + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + void save(IPdfWriter? writer) { + saveDictionary(writer!, true); + } + + @override + void dispose() { + if (items != null && items!.isNotEmpty) { + final List primitives = items!.keys.toList(); + for (int i = 0; i < primitives.length; i++) { + final PdfName? key = primitives[i] as PdfName?; + items![key!]!.dispose(); + } + items!.clear(); + items = null; + } + if (_status != null) { + _status = null; + } + } + + //Events + /// internal field + SavePdfPrimitiveCallback? beginSave; + + /// internal field + List? beginSaveList; + + /// internal field + SavePdfPrimitiveCallback? endSave; + + /// internal method + void onBeginSave(SavePdfPrimitiveArgs args) { + if (beginSave != null) { + beginSave!(this, args); + } + if (beginSaveList != null) { + for (int i = 0; i < beginSaveList!.length; i++) { + beginSaveList![i](this, args); + } + } + } + + /// internal method + void onEndSave(SavePdfPrimitiveArgs args) { + if (endSave != null) { + endSave!(this, args); + } + } + + @override + IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { + if (this is! PdfStream) { + if (clonedObject != null && + (clonedObject is PdfDictionary == true) && + (clonedObject! as PdfDictionary).crossTable == crossTable) { + return clonedObject; + } else { + clonedObject = null; + } + } + final PdfDictionary newDict = PdfDictionary(); + items!.forEach((PdfName? key, IPdfPrimitive? value) { + final PdfName? name = key; + final IPdfPrimitive obj = value!; + final IPdfPrimitive? newObj = obj.cloneObject(crossTable); + if (newObj is! PdfNull) { + newDict[name] = newObj; + } + }); + newDict.archive = archive; + newDict.status = _status; + newDict.freezeChanges(this); + newDict.crossTable = crossTable; + + if (this is! PdfStream) { + clonedObject = newDict; + } + return newDict; + } +} + +/// internal class +class SavePdfPrimitiveArgs { + /// internal constructor + SavePdfPrimitiveArgs(IPdfWriter? writer) { + if (writer == null) { + throw ArgumentError.notNull('writer'); + } else { + _writer = writer; + } + } + + IPdfWriter? _writer; + + /// internal property + IPdfWriter? get writer => _writer; +} + +/// internal type definition +typedef SavePdfPrimitiveCallback = + void Function(Object sender, SavePdfPrimitiveArgs? args); diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_name.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_name.dart index 8e11b1cae..b66930eb6 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_name.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_name.dart @@ -1,159 +1,159 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_cross_table.dart'; - -/// internal class -class PdfName implements IPdfPrimitive { - /// Constructor for creation [PdfName] object. - PdfName([String? name]) { - this.name = name; - } - - //Constants - /// internal field - static const String stringStartMark = '/'; - final List _replacements = [32, 9, 10, 13]; - - //Fields - /// internal field - String? _name; - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - - //Properties - /// Gets or sets the name. - String? get name { - return _name; - } - - set name(String? value) { - _name = normalizeValue(value); - } - - //Implementation - String _escapeString(String value) { - String result = ''; - for (int i = 0; i < value.length; i++) { - final int code = value.codeUnitAt(i); - if (code == _replacements[3]) { - result += r'\r'; - } else if (code == _replacements[2]) { - result += '\n'; - } else { - result += value[i]; - } - } - return result; - } - - /// Replace the characters to hexa decimal format. - static String? normalizeValue(String? value) { - if (value != null && value.isNotEmpty) { - value = value - .replaceAll('\t', '#09') - .replaceAll('\n', '#0A') - .replaceAll('\r', '#0D') - .replaceAll(' ', '#20'); - } - return value; - } - - /// Replace the hexa decimal format to replace characters. - static String? decodeName(String? value) { - if (value != null) { - return value - .replaceAll('#9', '\t') - .replaceAll('#09', '\t') - .replaceAll('#A', '\n') - .replaceAll('#a', '\n') - .replaceAll('#0A', '\n') - .replaceAll('#0a', '\n') - .replaceAll('#D', '\r') - .replaceAll('#d', '\r') - .replaceAll('#0D', '\r') - .replaceAll('#0d', '\r') - .replaceAll('#20', ' '); - } - return null; - } - - @override - String toString() { - return stringStartMark + _escapeString(name!); - } - - //IPdfPrimitive members - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(covariant IPdfPrimitive name) { - return name is PdfName && this.name == name.name; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => name.hashCode; - - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - IPdfPrimitive? clonedObject; - - @override - void save(IPdfWriter? writer) { - writer!.write(toString()); - } - - @override - void dispose() { - if (_status != null) { - _status = null; - } - } - - @override - IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfName(name); -} +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_cross_table.dart'; + +/// internal class +class PdfName implements IPdfPrimitive { + /// Constructor for creation [PdfName] object. + PdfName([String? name]) { + this.name = name; + } + + //Constants + /// internal field + static const String stringStartMark = '/'; + final List _replacements = [32, 9, 10, 13]; + + //Fields + /// internal field + String? _name; + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + + //Properties + /// Gets or sets the name. + String? get name { + return _name; + } + + set name(String? value) { + _name = normalizeValue(value); + } + + //Implementation + String _escapeString(String value) { + String result = ''; + for (int i = 0; i < value.length; i++) { + final int code = value.codeUnitAt(i); + if (code == _replacements[3]) { + result += r'\r'; + } else if (code == _replacements[2]) { + result += '\n'; + } else { + result += value[i]; + } + } + return result; + } + + /// Replace the characters to hexa decimal format. + static String? normalizeValue(String? value) { + if (value != null && value.isNotEmpty) { + value = value + .replaceAll('\t', '#09') + .replaceAll('\n', '#0A') + .replaceAll('\r', '#0D') + .replaceAll(' ', '#20'); + } + return value; + } + + /// Replace the hexa decimal format to replace characters. + static String? decodeName(String? value) { + if (value != null) { + return value + .replaceAll('#9', '\t') + .replaceAll('#09', '\t') + .replaceAll('#A', '\n') + .replaceAll('#a', '\n') + .replaceAll('#0A', '\n') + .replaceAll('#0a', '\n') + .replaceAll('#D', '\r') + .replaceAll('#d', '\r') + .replaceAll('#0D', '\r') + .replaceAll('#0d', '\r') + .replaceAll('#20', ' '); + } + return null; + } + + @override + String toString() { + return stringStartMark + _escapeString(name!); + } + + //IPdfPrimitive members + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(covariant IPdfPrimitive name) { + return name is PdfName && this.name == name.name; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => name.hashCode; + + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + IPdfPrimitive? clonedObject; + + @override + void save(IPdfWriter? writer) { + writer!.write(toString()); + } + + @override + void dispose() { + if (_status != null) { + _status = null; + } + } + + @override + IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfName(name); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_null.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_null.dart index a90824400..53fccf530 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_null.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_null.dart @@ -1,78 +1,78 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_cross_table.dart'; - -/// internal class -class PdfNull implements IPdfPrimitive { - /// internal constructor - PdfNull(); - - //Fields - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - - //IPdfPrimitive members - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - IPdfPrimitive? clonedObject; - - @override - void save(IPdfWriter? writer) { - writer!.write('null'); - } - - @override - void dispose() { - if (_status != null) { - _status = null; - } - } - - @override - IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfNull(); -} +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_cross_table.dart'; + +/// internal class +class PdfNull implements IPdfPrimitive { + /// internal constructor + PdfNull(); + + //Fields + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + + //IPdfPrimitive members + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + IPdfPrimitive? clonedObject; + + @override + void save(IPdfWriter? writer) { + writer!.write('null'); + } + + @override + void dispose() { + if (_status != null) { + _status = null; + } + } + + @override + IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfNull(); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_number.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_number.dart index bc3d8494c..d0bfad02a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_number.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_number.dart @@ -1,96 +1,96 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_cross_table.dart'; - -/// internal class -class PdfNumber implements IPdfPrimitive { - /// internal constructor - PdfNumber(num number) { - if (number.isNaN) { - throw ArgumentError.value(number, 'is not a number'); - } else { - value = number; - } - } - - //Fields - /// internal field - num? value; - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - - //IPdfPrimitive members - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - IPdfPrimitive? clonedObject; - - @override - void save(IPdfWriter? writer) { - if (value is double) { - String numberValue = value! - .toStringAsFixed(10) - .replaceAll(RegExp(r'0*$'), ''); - if (numberValue.endsWith('.')) { - numberValue = numberValue.replaceAll('.', ''); - } - writer!.write(numberValue); - } else { - writer!.write(value.toString()); - } - } - - @override - void dispose() { - if (_status != null) { - _status = null; - } - } - - @override - IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfNumber(value!); -} +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_cross_table.dart'; + +/// internal class +class PdfNumber implements IPdfPrimitive { + /// internal constructor + PdfNumber(num number) { + if (number.isNaN) { + throw ArgumentError.value(number, 'is not a number'); + } else { + value = number; + } + } + + //Fields + /// internal field + num? value; + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + + //IPdfPrimitive members + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + IPdfPrimitive? clonedObject; + + @override + void save(IPdfWriter? writer) { + if (value is double) { + String numberValue = value! + .toStringAsFixed(10) + .replaceAll(RegExp(r'0*$'), ''); + if (numberValue.endsWith('.')) { + numberValue = numberValue.replaceAll('.', ''); + } + writer!.write(numberValue); + } else { + writer!.write(value.toString()); + } + } + + @override + void dispose() { + if (_status != null) { + _status = null; + } + } + + @override + IPdfPrimitive cloneObject(PdfCrossTable crossTable) => PdfNumber(value!); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference.dart index f593d3261..3aa7e763f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference.dart @@ -1,96 +1,96 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_cross_table.dart'; - -/// internal class -class PdfReference implements IPdfPrimitive { - /// internal constructor - PdfReference(this.objNum, this.genNum) { - if (objNum!.isNaN) { - throw ArgumentError.value(objNum, 'not a number'); - } - if (genNum!.isNaN) { - throw ArgumentError.value(genNum, 'not a number'); - } - } - - //Fields - /// internal field - int? objNum; - - /// internal field - int? genNum; - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - - //Implementation - @override - String toString() { - return '$objNum $genNum R'; - } - - //IPdfPrimitive members - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - IPdfPrimitive? clonedObject; - - @override - void save(IPdfWriter? writer) { - writer!.write(toString()); - } - - @override - void dispose() { - if (_status != null) { - _status = null; - } - } - - @override - IPdfPrimitive? cloneObject(PdfCrossTable crossTable) => null; -} +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_cross_table.dart'; + +/// internal class +class PdfReference implements IPdfPrimitive { + /// internal constructor + PdfReference(this.objNum, this.genNum) { + if (objNum!.isNaN) { + throw ArgumentError.value(objNum, 'not a number'); + } + if (genNum!.isNaN) { + throw ArgumentError.value(genNum, 'not a number'); + } + } + + //Fields + /// internal field + int? objNum; + + /// internal field + int? genNum; + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + + //Implementation + @override + String toString() { + return '$objNum $genNum R'; + } + + //IPdfPrimitive members + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + IPdfPrimitive? clonedObject; + + @override + void save(IPdfWriter? writer) { + writer!.write(toString()); + } + + @override + void dispose() { + if (_status != null) { + _status = null; + } + } + + @override + IPdfPrimitive? cloneObject(PdfCrossTable crossTable) => null; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference_holder.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference_holder.dart index 1a1ca63ac..08103426c 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference_holder.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_reference_holder.dart @@ -1,232 +1,232 @@ -import '../../interfaces/pdf_interface.dart'; -import '../io/enums.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../io/pdf_main_object_collection.dart'; -import '../pdf_document/pdf_catalog.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference.dart'; - -/// internal class -class PdfReferenceHolder implements IPdfPrimitive { - /// internal constructor - PdfReferenceHolder(dynamic obj) { - if (obj == null) { - throw ArgumentError.value(obj, 'object', 'value cannot be null'); - } - if (obj is IPdfWrapper) { - object = IPdfWrapper.getElement(obj); - } else if (obj is IPdfPrimitive) { - object = obj; - } else { - throw ArgumentError.value( - 'argument is not set to an instance of an object', - ); - } - } - - /// internal constructor - PdfReferenceHolder.fromReference(this.reference, PdfCrossTable? crossTable) { - if (crossTable != null) { - this.crossTable = crossTable; - } else { - throw ArgumentError.value(crossTable, 'crossTable value cannot be null'); - } - } - - //Fields - /// internal field - IPdfPrimitive? referenceObject; - - /// internal field - PdfReference? reference; - bool? _isSaving; - - /// internal field - int? referenceObjectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - - /// internal field - late PdfCrossTable crossTable; - - /// internal field - int? referenceObjectIndex = -1; - - //IPdfPrimitive members - /// internal property - IPdfPrimitive? get object { - if (reference != null || referenceObject == null) { - referenceObject = _obtainObject(); - } - return referenceObject; - } - - set object(IPdfPrimitive? value) { - referenceObject = value; - } - - /// internal property - int? get index { - final PdfMainObjectCollection items = crossTable.items!; - referenceObjectIndex = items.getObjectIndex(reference!); - if (referenceObjectIndex! < 0) { - crossTable.getObject(reference); - referenceObjectIndex = items.count - 1; - } - return referenceObjectIndex; - } - - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - referenceObjectCollectionIndex ??= 0; - return referenceObjectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - referenceObjectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - IPdfPrimitive? clonedObject; - - @override - void save(IPdfWriter? writer) { - if (writer != null) { - if (!PdfDocumentHelper.getHelper(writer.document!).isLoadedDocument) { - object!.isSaving = true; - } - final PdfCrossTable crossTable = - PdfDocumentHelper.getHelper(writer.document!).crossTable; - PdfReference? pdfReference; - if (writer.document!.fileStructure.incrementalUpdate && - PdfDocumentHelper.getHelper(writer.document!).isStreamCopied) { - if (reference == null) { - pdfReference = crossTable.getReference(object); - } else { - pdfReference = reference; - } - } else { - pdfReference = crossTable.getReference(object); - } - pdfReference!.save(writer); - } - } - - IPdfPrimitive? _obtainObject() { - IPdfPrimitive? obj; - if (reference != null) { - if (index! >= 0) { - obj = crossTable.items!.getObject(reference!); - } - } else if (referenceObject != null) { - obj = referenceObject; - } - return obj; - } - - @override - void dispose() { - if (reference != null) { - reference!.dispose(); - reference = null; - } - if (_status != null) { - _status = null; - } - } - - @override - IPdfPrimitive cloneObject(PdfCrossTable crossTable) { - PdfReferenceHolder refHolder; - IPdfPrimitive? temp; - PdfReference reference; - if (object is PdfNumber) { - return PdfNumber((object! as PdfNumber).value!); - } - - if (object is PdfDictionary) { - // Meaning the referenced page is not available for import. - final PdfName type = PdfName(PdfDictionaryProperties.type); - final PdfDictionary dict = object! as PdfDictionary; - if (dict.containsKey(type)) { - final PdfName? pageName = dict[type] as PdfName?; - if (pageName != null) { - if (pageName.name == 'Page') { - return PdfNull(); - } - } - } - } - if (object is PdfName) { - return PdfName((object! as PdfName).name); - } - - // Resolves circular references. - if (crossTable.prevReference != null && - crossTable.prevReference!.contains(this.reference)) { - IPdfPrimitive? obj; - if (crossTable.document != null) { - obj = this.crossTable.getObject(this.reference); - } else { - obj = this.crossTable.getObject(this.reference)!.clonedObject; - } - if (obj != null) { - reference = crossTable.getReference(obj); - return PdfReferenceHolder.fromReference(reference, crossTable); - } else { - return PdfNull(); - } - } - if (this.reference != null) { - crossTable.prevReference!.add(this.reference); - } - if (object is! PdfCatalog) { - temp = object!.cloneObject(crossTable); - } else { - temp = PdfDocumentHelper.getHelper(crossTable.document!).catalog; - } - - reference = crossTable.getReference(temp); - refHolder = PdfReferenceHolder.fromReference(reference, crossTable); - return refHolder; - } -} +import '../../interfaces/pdf_interface.dart'; +import '../io/enums.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../io/pdf_main_object_collection.dart'; +import '../pdf_document/pdf_catalog.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference.dart'; + +/// internal class +class PdfReferenceHolder implements IPdfPrimitive { + /// internal constructor + PdfReferenceHolder(dynamic obj) { + if (obj == null) { + throw ArgumentError.value(obj, 'object', 'value cannot be null'); + } + if (obj is IPdfWrapper) { + object = IPdfWrapper.getElement(obj); + } else if (obj is IPdfPrimitive) { + object = obj; + } else { + throw ArgumentError.value( + 'argument is not set to an instance of an object', + ); + } + } + + /// internal constructor + PdfReferenceHolder.fromReference(this.reference, PdfCrossTable? crossTable) { + if (crossTable != null) { + this.crossTable = crossTable; + } else { + throw ArgumentError.value(crossTable, 'crossTable value cannot be null'); + } + } + + //Fields + /// internal field + IPdfPrimitive? referenceObject; + + /// internal field + PdfReference? reference; + bool? _isSaving; + + /// internal field + int? referenceObjectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + + /// internal field + late PdfCrossTable crossTable; + + /// internal field + int? referenceObjectIndex = -1; + + //IPdfPrimitive members + /// internal property + IPdfPrimitive? get object { + if (reference != null || referenceObject == null) { + referenceObject = _obtainObject(); + } + return referenceObject; + } + + set object(IPdfPrimitive? value) { + referenceObject = value; + } + + /// internal property + int? get index { + final PdfMainObjectCollection items = crossTable.items!; + referenceObjectIndex = items.getObjectIndex(reference!); + if (referenceObjectIndex! < 0) { + crossTable.getObject(reference); + referenceObjectIndex = items.count - 1; + } + return referenceObjectIndex; + } + + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + referenceObjectCollectionIndex ??= 0; + return referenceObjectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + referenceObjectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + IPdfPrimitive? clonedObject; + + @override + void save(IPdfWriter? writer) { + if (writer != null) { + if (!PdfDocumentHelper.getHelper(writer.document!).isLoadedDocument) { + object!.isSaving = true; + } + final PdfCrossTable crossTable = + PdfDocumentHelper.getHelper(writer.document!).crossTable; + PdfReference? pdfReference; + if (writer.document!.fileStructure.incrementalUpdate && + PdfDocumentHelper.getHelper(writer.document!).isStreamCopied) { + if (reference == null) { + pdfReference = crossTable.getReference(object); + } else { + pdfReference = reference; + } + } else { + pdfReference = crossTable.getReference(object); + } + pdfReference!.save(writer); + } + } + + IPdfPrimitive? _obtainObject() { + IPdfPrimitive? obj; + if (reference != null) { + if (index! >= 0) { + obj = crossTable.items!.getObject(reference!); + } + } else if (referenceObject != null) { + obj = referenceObject; + } + return obj; + } + + @override + void dispose() { + if (reference != null) { + reference!.dispose(); + reference = null; + } + if (_status != null) { + _status = null; + } + } + + @override + IPdfPrimitive cloneObject(PdfCrossTable crossTable) { + PdfReferenceHolder refHolder; + IPdfPrimitive? temp; + PdfReference reference; + if (object is PdfNumber) { + return PdfNumber((object! as PdfNumber).value!); + } + + if (object is PdfDictionary) { + // Meaning the referenced page is not available for import. + final PdfName type = PdfName(PdfDictionaryProperties.type); + final PdfDictionary dict = object! as PdfDictionary; + if (dict.containsKey(type)) { + final PdfName? pageName = dict[type] as PdfName?; + if (pageName != null) { + if (pageName.name == 'Page') { + return PdfNull(); + } + } + } + } + if (object is PdfName) { + return PdfName((object! as PdfName).name); + } + + // Resolves circular references. + if (crossTable.prevReference != null && + crossTable.prevReference!.contains(this.reference)) { + IPdfPrimitive? obj; + if (crossTable.document != null) { + obj = this.crossTable.getObject(this.reference); + } else { + obj = this.crossTable.getObject(this.reference)!.clonedObject; + } + if (obj != null) { + reference = crossTable.getReference(obj); + return PdfReferenceHolder.fromReference(reference, crossTable); + } else { + return PdfNull(); + } + } + if (this.reference != null) { + crossTable.prevReference!.add(this.reference); + } + if (object is! PdfCatalog) { + temp = object!.cloneObject(crossTable); + } else { + temp = PdfDocumentHelper.getHelper(crossTable.document!).catalog; + } + + reference = crossTable.getReference(temp); + refHolder = PdfReferenceHolder.fromReference(reference, crossTable); + return refHolder; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart index c4c5cbcf9..1d08fa654 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_stream.dart @@ -1,569 +1,573 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import '../../interfaces/pdf_interface.dart'; -import '../compression/compressed_stream_writer.dart'; -import '../compression/pdf_png_filter.dart'; -import '../compression/pdf_zlib_compressor.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_null.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_reference_holder.dart'; -import '../primitives/pdf_string.dart'; -import '../security/pdf_encryptor.dart'; -import '../security/pdf_security.dart'; - -/// internal class -class PdfStream extends PdfDictionary { - /// internal constructor - PdfStream([PdfDictionary? dictionary, List? data]) { - if (dictionary == null && data == null) { - this.data = []; - _compress = true; - } else { - ArgumentError.checkNotNull(data, 'data'); - ArgumentError.checkNotNull(dictionary, 'dictionary'); - _compress = false; - this.data = []; - dataStream!.addAll(data!); - copyDictionary(dictionary); - this[PdfDictionaryProperties.length] = PdfNumber(dataStream!.length); - } - decrypted = false; - blockEncryption = false; - } - - //Constants - /// internal field - static const String prefix = 'stream'; - - /// internal field - static const String suffix = 'endstream'; - - //Fields - /// internal field - List? data; - bool? _compress; - PdfStream? _clonedObject; - - /// internal field - late bool blockEncryption; - - /// internal field - int? objNumber; - - //Properties - /// internal property - bool? get compress { - return _compress; - } - - set compress(bool? value) { - _compress = value; - _modify(); - } - - /// internal property - List? get dataStream { - if (!decrypted! && - crossTable != null && - crossTable!.encryptor != null && - objNumber != null && - objNumber! > -1) { - decrypt(crossTable!.encryptor!, objNumber); - } - return data; - } - - //Implementations - void _modify() { - isChanged = true; - } - - List? _compressContent(PdfDocument? document) { - final List? data = - (crossTable != null && - crossTable!.encryptor != null && - crossTable!.encryptor!.encryptAttachmentOnly!) - ? this.data - : dataStream; - if (compress! && document!.compressionLevel != PdfCompressionLevel.none) { - final List outputStream = []; - final CompressedStreamWriter compressedWriter = CompressedStreamWriter( - outputStream, - false, - document.compressionLevel, - false, - ); - compressedWriter.write(data!, 0, data.length, false); - compressedWriter.close(); - addFilter(PdfDictionaryProperties.flateDecode); - compress = false; - return outputStream; - } else { - return data; - } - } - - List? _compressStream() { - final List? streamData = - (crossTable != null && - crossTable!.encryptor != null && - crossTable!.encryptor!.encryptAttachmentOnly!) - ? data - : dataStream; - final List outputStream = []; - if (streamData != null && streamData.isNotEmpty) { - CompressedStreamWriter( - outputStream, - false, - PdfCompressionLevel.best, - false, - ) - ..write(streamData, 0, streamData.length, false) - ..close(); - if (outputStream.isNotEmpty) { - clearStream(); - compress = false; - data = outputStream; - addFilter(PdfDictionaryProperties.flateDecode); - } - } - return dataStream; - } - - /// internal method - void decompress() { - data = getDecompressedData(true); - remove(PdfDictionaryProperties.filter); - _compress = true; - } - - List? getDecompressedData(bool modified) { - String? filterName = ''; - IPdfPrimitive? primitive = this[PdfDictionaryProperties.filter]; - List? decompressedData = dataStream; - if (primitive is PdfReferenceHolder) { - final PdfReferenceHolder holder = primitive; - primitive = holder.object; - } - if (primitive != null) { - if (primitive is PdfName) { - final PdfName name = primitive; - if (name.name == 'ASCIIHexDecode') { - decompressedData = _decode(decompressedData); - } else { - decompressedData = _decompressData(decompressedData!, name.name!); - } - if (modified) { - _modify(); - } - } else if (primitive is PdfArray) { - final PdfArray filter = primitive; - for (int i = 0; i < filter.count; i++) { - final IPdfPrimitive? pdfFilter = filter[i]; - if (pdfFilter != null && pdfFilter is PdfName) { - filterName = pdfFilter.name; - } - if (filterName == 'ASCIIHexDecode') { - decompressedData = _decode(decompressedData); - } else { - decompressedData = _decompressData(decompressedData!, filterName!); - } - if (modified) { - _modify(); - } - } - } else { - throw ArgumentError.value(filterName, 'Invalid format'); - } - } - return decompressedData; - } - - List? _decode(List? data) { - return data; - } - - List _decompressData(List data, String filter) { - if (data.isEmpty || data.length == 1) { - return data; - } - if (filter != PdfDictionaryProperties.crypt) { - if (filter == PdfDictionaryProperties.runLengthDecode) { - return data; - } else if (filter == PdfDictionaryProperties.flateDecode || - filter == PdfDictionaryProperties.flateDecodeShort) { - try { - final PdfZlibCompressor compressor = PdfZlibCompressor(); - data = compressor.decompress(data); - } catch (e) { - //Non-compressed stream throws exception when try to decompress. - } - return _postProcess(data, filter); - } else if (filter == PdfDictionaryProperties.ascii85Decode || - filter == PdfDictionaryProperties.ascii85DecodeShort) { - final PdfAscii85Compressor compressor = PdfAscii85Compressor(); - data = compressor.decompress(data); - data = _postProcess(data, filter); - return data; - } - return data; - } else { - return data; - } - } - - List _postProcess(List data, String filter) { - IPdfPrimitive? obj; - if (filter == PdfDictionaryProperties.flateDecode) { - obj = this[PdfDictionaryProperties.decodeParms]; - if (obj == null) { - return data; - } - PdfDictionary? decodeParams; - PdfArray? decodeParamsArr; - PdfNull? pdfNull; - if (obj is PdfReferenceHolder) { - final IPdfPrimitive? primitive = PdfCrossTable.dereference(obj); - if (primitive is PdfDictionary) { - decodeParams = primitive; - } - if (primitive is PdfArray) { - decodeParamsArr = primitive; - } - if (primitive is PdfNull) { - pdfNull = primitive; - } - } else if (obj is PdfDictionary) { - decodeParams = obj; - } else if (obj is PdfArray) { - decodeParamsArr = obj; - } else if (obj is PdfNull) { - pdfNull = obj; - } - if (pdfNull != null) { - return data; - } - if (decodeParams == null) { - if (decodeParamsArr == null) { - throw ArgumentError.value(filter, 'Invalid Format'); - } - } - if (decodeParamsArr != null) { - final IPdfPrimitive? decode = decodeParamsArr[0]; - if (decode != null && decode is PdfDictionary) { - if (decode.containsKey(PdfDictionaryProperties.name)) { - final IPdfPrimitive? name = decode[PdfDictionaryProperties.name]; - if (name != null && name is PdfName && name.name == 'StdCF') { - return data; - } - } - } - } - int predictor = 1; - if (decodeParams != null) { - if (decodeParams.containsKey(PdfDictionaryProperties.predictor)) { - final IPdfPrimitive? number = - decodeParams[PdfDictionaryProperties.predictor]; - if (number is PdfNumber) { - predictor = number.value!.toInt(); - } - } - } else if (decodeParamsArr != null && decodeParamsArr.count > 0) { - final IPdfPrimitive? dictionary = decodeParamsArr[0]; - if (dictionary != null && - dictionary is PdfDictionary && - dictionary.containsKey(PdfDictionaryProperties.predictor)) { - predictor = dictionary.getInt(PdfDictionaryProperties.predictor); - } else { - predictor = 1; - } - } - if (predictor == 1) { - return data; - } else if (predictor == 2) { - throw ArgumentError.value(predictor, 'Unsupported predictor: TIFF 2.'); - } else if (predictor < 16 && predictor > 2) { - int colors = 1; - int columns = 1; - obj = decodeParams![PdfDictionaryProperties.colors]; - if (obj != null && obj is PdfNumber) { - colors = obj.value!.toInt(); - } - obj = decodeParams[PdfDictionaryProperties.columns]; - if (obj != null && obj is PdfNumber) { - columns = obj.value!.toInt(); - } - data = PdfPngFilter().decompress(data, colors * columns); - return data; - } else { - throw ArgumentError.value(filter, 'Invalid Format'); - } - } - return data; - } - - /// Internal method. - void addFilter(String filterName) { - IPdfPrimitive? filter = this[PdfDictionaryProperties.filter]; - if (filter is PdfReferenceHolder) { - filter = filter.referenceObject; - } - late PdfName name; - PdfArray? array; - if (filter is PdfArray) { - array = filter; - } - if (filter is PdfName) { - name = filter; - } - if (filter != null) { - array = PdfArray(); - array.insert(0, name); - this[PdfDictionaryProperties.filter] = array; - } - name = PdfName(filterName); - if (array == null) { - this[PdfDictionaryProperties.filter] = name; - } else { - array.insert(0, name); - } - } - - /// internal method - void write(dynamic pdfObject) { - if (pdfObject == null) { - throw ArgumentError.value(pdfObject, 'pdfObject', 'value cannot be null'); - } - if (pdfObject is String || pdfObject is String?) { - if ((pdfObject as String).isEmpty) { - throw ArgumentError.value(pdfObject, 'value cannot be empty'); - } - write(utf8.encode(pdfObject)); - } else if (pdfObject is List || pdfObject is List) { - if ((pdfObject as List).isEmpty) { - throw ArgumentError.value(pdfObject, 'value cannot be empty'); - } - data!.addAll(pdfObject); - _modify(); - } else { - throw ArgumentError.value( - pdfObject, - 'The method or operation is not implemented', - ); - } - } - - /// internal method - void clearStream() { - dataStream!.clear(); - if (containsKey(PdfDictionaryProperties.filter)) { - remove(PdfDictionaryProperties.filter); - } - compress = true; - _modify(); - } - - //IPdfPrimitive members - @override - void save(IPdfWriter? writer) { - final SavePdfPrimitiveArgs beginSaveArguments = SavePdfPrimitiveArgs( - writer, - ); - onBeginSave(beginSaveArguments); - List? data = _compressContent(writer!.document); - final PdfSecurity security = writer.document!.security; - if (PdfSecurityHelper.getHelper(security).encryptor.encrypt && - PdfSecurityHelper.getHelper( - security, - ).encryptor.encryptAttachmentOnly!) { - bool attachmentEncrypted = false; - if (containsKey(PdfDictionaryProperties.type)) { - final IPdfPrimitive? primitive = this[PdfDictionaryProperties.type]; - if (primitive != null && - primitive is PdfName && - primitive.name == PdfDictionaryProperties.embeddedFile) { - bool? isArray; - bool? isString; - IPdfPrimitive? filterPrimitive; - if (containsKey(PdfDictionaryProperties.filter)) { - filterPrimitive = this[PdfDictionaryProperties.filter]; - isArray = filterPrimitive is PdfArray; - isString = filterPrimitive is PdfString; - } - if ((isArray == null && isString == null) || - !isArray! || - (isArray && - (filterPrimitive! as PdfArray).contains( - PdfName(PdfDictionaryProperties.crypt), - ))) { - if (_compress! || - !containsKey(PdfDictionaryProperties.filter) || - (isArray! && - (filterPrimitive! as PdfArray).contains( - PdfName(PdfDictionaryProperties.flateDecode), - ) || - (isString! && - (filterPrimitive! as PdfString).value == - PdfDictionaryProperties.flateDecode))) { - data = _compressStream(); - } - attachmentEncrypted = true; - data = _encryptContent(data, writer); - addFilter(PdfDictionaryProperties.crypt); - } - if (!containsKey(PdfDictionaryProperties.decodeParms)) { - final PdfArray decode = PdfArray(); - final PdfDictionary decodeparms = PdfDictionary(); - decodeparms[PdfDictionaryProperties.name] = PdfName( - PdfDictionaryProperties.stdCF, - ); - decode.add(decodeparms); - decode.add(PdfNull()); - this[PdfName(PdfDictionaryProperties.decodeParms)] = decode; - } - } - } - if (!attachmentEncrypted) { - if (containsKey(PdfDictionaryProperties.decodeParms)) { - final IPdfPrimitive? primitive = - this[PdfDictionaryProperties.decodeParms]; - if (primitive is PdfArray) { - final PdfArray decodeParamArray = primitive; - if (decodeParamArray.count > 0 && - decodeParamArray[0] is PdfDictionary) { - final PdfDictionary decode = - decodeParamArray[0]! as PdfDictionary; - if (decode.containsKey(PdfDictionaryProperties.name)) { - final IPdfPrimitive? name = - decode[PdfDictionaryProperties.name]; - if (name is PdfName && - name.name == PdfDictionaryProperties.stdCF) { - PdfArray? filter; - if (containsKey(PdfDictionaryProperties.filter)) { - final IPdfPrimitive? filterType = - this[PdfDictionaryProperties.filter]; - if (filterType is PdfArray) { - filter = filterType; - } - } - if (filter == null || - filter.contains(PdfName(PdfDictionaryProperties.crypt))) { - if (_compress!) { - data = _compressStream(); - } - data = _encryptContent(data, writer); - addFilter(PdfDictionaryProperties.crypt); - } - } - } - } - } - } else if (containsKey(PdfDictionaryProperties.dl)) { - if (_compress!) { - data = _compressStream(); - } - data = _encryptContent(data, writer); - addFilter(PdfDictionaryProperties.crypt); - if (!containsKey(PdfDictionaryProperties.decodeParms)) { - final PdfArray decode = PdfArray(); - final PdfDictionary decodeparms = PdfDictionary(); - decodeparms[PdfDictionaryProperties.name] = PdfName( - PdfDictionaryProperties.stdCF, - ); - decode.add(decodeparms); - decode.add(PdfNull()); - this[PdfName(PdfDictionaryProperties.decodeParms)] = decode; - } - } - } - } else if (!PdfSecurityHelper.getHelper( - security, - ).encryptor.encryptOnlyMetadata! && - containsKey(PdfDictionaryProperties.type)) { - final IPdfPrimitive? primitive = this[PdfDictionaryProperties.type]; - if (primitive != null && primitive is PdfName) { - final PdfName fileType = primitive; - if (fileType.name != PdfDictionaryProperties.metadata) { - data = _encryptContent(data, writer); - } - } - } else { - data = _encryptContent(data, writer); - } - - this[PdfDictionaryProperties.length] = PdfNumber( - data != null ? data.length : 0, - ); - super.saveDictionary(writer, false); - writer.write(prefix); - writer.write(PdfOperators.newLine); - if (data != null && data.isNotEmpty) { - writer.write(data); - writer.write(PdfOperators.newLine); - } - writer.write(suffix); - writer.write(PdfOperators.newLine); - final SavePdfPrimitiveArgs endSaveArguments = SavePdfPrimitiveArgs(writer); - onEndSave(endSaveArguments); - if (_compress!) { - remove(PdfDictionaryProperties.filter); - } - } - - @override - void dispose() { - if (dataStream != null) { - if (dataStream is List && dataStream is! Uint8List) { - dataStream!.clear(); - } - data = null; - } - _clonedObject = null; - objNumber = null; - } - - @override - IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { - if (_clonedObject != null && _clonedObject!.crossTable == crossTable) { - return _clonedObject; - } else { - _clonedObject = null; - } - final PdfDictionary? dict = super.cloneObject(crossTable) as PdfDictionary?; - final PdfStream newStream = PdfStream(dict, dataStream); - newStream.compress = _compress; - _clonedObject = newStream; - return newStream; - } - - /// internal method - void decrypt(PdfEncryptor encryptor, int? currentObjectNumber) { - if (!decrypted!) { - decrypted = true; - data = encryptor.encryptData(currentObjectNumber, dataStream!, false); - _modify(); - } - } - - List? _encryptContent(List? data, IPdfWriter writer) { - final PdfDocument doc = writer.document!; - final PdfEncryptor encryptor = - PdfSecurityHelper.getHelper(doc.security).encryptor; - if (encryptor.encrypt && !blockEncryption) { - data = encryptor.encryptData( - PdfDocumentHelper.getHelper(doc).currentSavingObject!.objNum, - data!, - true, - ); - } - return data; - } -} +import 'dart:convert'; +import 'dart:typed_data'; + +import '../../interfaces/pdf_interface.dart'; +import '../compression/compressed_stream_writer.dart'; +import '../compression/pdf_png_filter.dart'; +import '../compression/pdf_zlib_compressor.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_null.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_reference_holder.dart'; +import '../primitives/pdf_string.dart'; +import '../security/pdf_encryptor.dart'; +import '../security/pdf_security.dart'; + +/// internal class +class PdfStream extends PdfDictionary { + /// internal constructor + PdfStream([PdfDictionary? dictionary, List? data]) { + if (dictionary == null && data == null) { + this.data = []; + _compress = true; + } else { + ArgumentError.checkNotNull(data, 'data'); + ArgumentError.checkNotNull(dictionary, 'dictionary'); + _compress = false; + this.data = []; + dataStream!.addAll(data!); + copyDictionary(dictionary); + this[PdfDictionaryProperties.length] = PdfNumber(dataStream!.length); + } + decrypted = false; + blockEncryption = false; + } + + //Constants + /// internal field + static const String prefix = 'stream'; + + /// internal field + static const String suffix = 'endstream'; + + //Fields + /// internal field + List? data; + bool? _compress; + PdfStream? _clonedObject; + + /// internal field + late bool blockEncryption; + + /// internal field + int? objNumber; + + //Properties + /// internal property + bool? get compress { + return _compress; + } + + set compress(bool? value) { + _compress = value; + _modify(); + } + + /// internal property + List? get dataStream { + if (!decrypted! && + crossTable != null && + crossTable!.encryptor != null && + objNumber != null && + objNumber! > -1) { + decrypt(crossTable!.encryptor!, objNumber); + } + return data; + } + + //Implementations + void _modify() { + isChanged = true; + } + + List? _compressContent(PdfDocument? document) { + final List? data = + (crossTable != null && + crossTable!.encryptor != null && + crossTable!.encryptor!.encryptAttachmentOnly!) + ? this.data + : dataStream; + if (compress! && document!.compressionLevel != PdfCompressionLevel.none) { + final List outputStream = []; + final CompressedStreamWriter compressedWriter = CompressedStreamWriter( + outputStream, + false, + document.compressionLevel, + false, + ); + compressedWriter.write(data!, 0, data.length, false); + compressedWriter.close(); + addFilter(PdfDictionaryProperties.flateDecode); + compress = false; + return outputStream; + } else { + return data; + } + } + + List? _compressStream() { + final List? streamData = + (crossTable != null && + crossTable!.encryptor != null && + crossTable!.encryptor!.encryptAttachmentOnly!) + ? data + : dataStream; + final List outputStream = []; + if (streamData != null && streamData.isNotEmpty) { + CompressedStreamWriter( + outputStream, + false, + PdfCompressionLevel.best, + false, + ) + ..write(streamData, 0, streamData.length, false) + ..close(); + if (outputStream.isNotEmpty) { + clearStream(); + compress = false; + data = outputStream; + addFilter(PdfDictionaryProperties.flateDecode); + } + } + return dataStream; + } + + /// internal method + void decompress() { + data = getDecompressedData(true); + remove(PdfDictionaryProperties.filter); + _compress = true; + } + + List? getDecompressedData(bool modified) { + String? filterName = ''; + IPdfPrimitive? primitive = this[PdfDictionaryProperties.filter]; + List? decompressedData = dataStream; + if (primitive is PdfReferenceHolder) { + final PdfReferenceHolder holder = primitive; + primitive = holder.object; + } + if (primitive != null) { + if (primitive is PdfName) { + final PdfName name = primitive; + if (name.name == 'ASCIIHexDecode') { + decompressedData = _decode(decompressedData); + } else { + decompressedData = _decompressData(decompressedData!, name.name!); + } + if (modified) { + _modify(); + } + } else if (primitive is PdfArray) { + final PdfArray filter = primitive; + for (int i = 0; i < filter.count; i++) { + final IPdfPrimitive? pdfFilter = filter[i]; + if (pdfFilter != null && pdfFilter is PdfName) { + filterName = pdfFilter.name; + } + if (filterName == 'ASCIIHexDecode') { + decompressedData = _decode(decompressedData); + } else { + decompressedData = _decompressData(decompressedData!, filterName!); + } + if (modified) { + _modify(); + } + } + } else { + throw ArgumentError.value(filterName, 'Invalid format'); + } + } + return decompressedData; + } + + List? _decode(List? data) { + return data; + } + + List _decompressData(List data, String filter) { + if (data.isEmpty || data.length == 1) { + return data; + } + if (filter != PdfDictionaryProperties.crypt) { + if (filter == PdfDictionaryProperties.runLengthDecode) { + return data; + } else if (filter == PdfDictionaryProperties.flateDecode || + filter == PdfDictionaryProperties.flateDecodeShort) { + try { + final PdfZlibCompressor compressor = PdfZlibCompressor(); + data = compressor.decompress(data); + } catch (e) { + //Non-compressed stream throws exception when try to decompress. + } + return _postProcess(data, filter); + } else if (filter == PdfDictionaryProperties.ascii85Decode || + filter == PdfDictionaryProperties.ascii85DecodeShort) { + final PdfAscii85Compressor compressor = PdfAscii85Compressor(); + data = compressor.decompress(data); + data = _postProcess(data, filter); + return data; + } + return data; + } else { + return data; + } + } + + List _postProcess(List data, String filter) { + IPdfPrimitive? obj; + if (filter == PdfDictionaryProperties.flateDecode) { + obj = this[PdfDictionaryProperties.decodeParms]; + if (obj == null) { + return data; + } + PdfDictionary? decodeParams; + PdfArray? decodeParamsArr; + PdfNull? pdfNull; + if (obj is PdfReferenceHolder) { + final IPdfPrimitive? primitive = PdfCrossTable.dereference(obj); + if (primitive is PdfDictionary) { + decodeParams = primitive; + } + if (primitive is PdfArray) { + decodeParamsArr = primitive; + } + if (primitive is PdfNull) { + pdfNull = primitive; + } + } else if (obj is PdfDictionary) { + decodeParams = obj; + } else if (obj is PdfArray) { + decodeParamsArr = obj; + } else if (obj is PdfNull) { + pdfNull = obj; + } + if (pdfNull != null) { + return data; + } + if (decodeParams == null) { + if (decodeParamsArr == null) { + throw ArgumentError.value(filter, 'Invalid Format'); + } + } + if (decodeParamsArr != null) { + final IPdfPrimitive? decode = decodeParamsArr[0]; + if (decode != null && decode is PdfDictionary) { + if (decode.containsKey(PdfDictionaryProperties.name)) { + final IPdfPrimitive? name = decode[PdfDictionaryProperties.name]; + if (name != null && name is PdfName && name.name == 'StdCF') { + return data; + } + } + } + } + int predictor = 1; + if (decodeParams != null) { + if (decodeParams.containsKey(PdfDictionaryProperties.predictor)) { + final IPdfPrimitive? number = + decodeParams[PdfDictionaryProperties.predictor]; + if (number is PdfNumber) { + predictor = number.value!.toInt(); + } + } + } else if (decodeParamsArr != null && decodeParamsArr.count > 0) { + final IPdfPrimitive? dictionary = decodeParamsArr[0]; + if (dictionary != null && + dictionary is PdfDictionary && + dictionary.containsKey(PdfDictionaryProperties.predictor)) { + predictor = dictionary.getInt(PdfDictionaryProperties.predictor); + } else { + predictor = 1; + } + } + if (predictor == 1) { + return data; + } else if (predictor == 2) { + throw ArgumentError.value(predictor, 'Unsupported predictor: TIFF 2.'); + } else if (predictor < 16 && predictor > 2) { + int colors = 1; + int columns = 1; + obj = decodeParams![PdfDictionaryProperties.colors]; + if (obj != null && obj is PdfNumber) { + colors = obj.value!.toInt(); + } + obj = decodeParams[PdfDictionaryProperties.columns]; + if (obj != null && obj is PdfNumber) { + columns = obj.value!.toInt(); + } + data = PdfPngFilter().decompress(data, colors * columns); + return data; + } else { + throw ArgumentError.value(filter, 'Invalid Format'); + } + } + return data; + } + + /// Internal method. + void addFilter(String filterName) { + IPdfPrimitive? filter = this[PdfDictionaryProperties.filter]; + if (filter is PdfReferenceHolder) { + filter = filter.referenceObject; + } + late PdfName name; + PdfArray? array; + if (filter is PdfArray) { + array = filter; + } + if (filter is PdfName) { + name = filter; + } + if (filter != null) { + array = PdfArray(); + array.insert(0, name); + this[PdfDictionaryProperties.filter] = array; + } + name = PdfName(filterName); + if (array == null) { + this[PdfDictionaryProperties.filter] = name; + } else { + array.insert(0, name); + } + } + + /// internal method + void write(dynamic pdfObject) { + if (pdfObject == null) { + throw ArgumentError.value(pdfObject, 'pdfObject', 'value cannot be null'); + } + if (pdfObject is String || pdfObject is String?) { + if ((pdfObject as String).isEmpty) { + throw ArgumentError.value(pdfObject, 'value cannot be empty'); + } + write(utf8.encode(pdfObject)); + } else if (pdfObject is List || pdfObject is List) { + if ((pdfObject as List).isEmpty) { + throw ArgumentError.value(pdfObject, 'value cannot be empty'); + } + data!.addAll(pdfObject); + _modify(); + } else { + throw ArgumentError.value( + pdfObject, + 'The method or operation is not implemented', + ); + } + } + + /// internal method + void clearStream() { + dataStream!.clear(); + if (containsKey(PdfDictionaryProperties.filter)) { + remove(PdfDictionaryProperties.filter); + } + compress = true; + _modify(); + } + + //IPdfPrimitive members + @override + void save(IPdfWriter? writer) { + final SavePdfPrimitiveArgs beginSaveArguments = SavePdfPrimitiveArgs( + writer, + ); + onBeginSave(beginSaveArguments); + List? data = _compressContent(writer!.document); + final PdfSecurity security = writer.document!.security; + if (PdfSecurityHelper.getHelper(security).encryptor.encrypt && + PdfSecurityHelper.getHelper( + security, + ).encryptor.encryptAttachmentOnly!) { + bool attachmentEncrypted = false; + if (containsKey(PdfDictionaryProperties.type)) { + final IPdfPrimitive? primitive = this[PdfDictionaryProperties.type]; + if (primitive != null && + primitive is PdfName && + primitive.name == PdfDictionaryProperties.embeddedFile) { + bool? isArray; + bool? isString; + IPdfPrimitive? filterPrimitive; + if (containsKey(PdfDictionaryProperties.filter)) { + filterPrimitive = this[PdfDictionaryProperties.filter]; + isArray = filterPrimitive is PdfArray; + isString = filterPrimitive is PdfString; + } + if ((isArray == null && isString == null) || + !isArray! || + (isArray && + (filterPrimitive! as PdfArray).contains( + PdfName(PdfDictionaryProperties.crypt), + ))) { + if (_compress! || + !containsKey(PdfDictionaryProperties.filter) || + (isArray! && + (filterPrimitive! as PdfArray).contains( + PdfName(PdfDictionaryProperties.flateDecode), + ) || + (isString! && + (filterPrimitive! as PdfString).value == + PdfDictionaryProperties.flateDecode))) { + data = _compressStream(); + } + attachmentEncrypted = true; + data = _encryptContent(data, writer); + addFilter(PdfDictionaryProperties.crypt); + } + if (!containsKey(PdfDictionaryProperties.decodeParms)) { + final PdfArray decode = PdfArray(); + final PdfDictionary decodeparms = PdfDictionary(); + decodeparms[PdfDictionaryProperties.name] = PdfName( + PdfDictionaryProperties.stdCF, + ); + decode.add(decodeparms); + decode.add(PdfNull()); + this[PdfName(PdfDictionaryProperties.decodeParms)] = decode; + } + } + } + if (!attachmentEncrypted) { + if (containsKey(PdfDictionaryProperties.decodeParms)) { + final IPdfPrimitive? primitive = + this[PdfDictionaryProperties.decodeParms]; + if (primitive is PdfArray) { + final PdfArray decodeParamArray = primitive; + if (decodeParamArray.count > 0 && + decodeParamArray[0] is PdfDictionary) { + final PdfDictionary decode = + decodeParamArray[0]! as PdfDictionary; + if (decode.containsKey(PdfDictionaryProperties.name)) { + final IPdfPrimitive? name = + decode[PdfDictionaryProperties.name]; + if (name is PdfName && + name.name == PdfDictionaryProperties.stdCF) { + PdfArray? filter; + if (containsKey(PdfDictionaryProperties.filter)) { + final IPdfPrimitive? filterType = + this[PdfDictionaryProperties.filter]; + if (filterType is PdfArray) { + filter = filterType; + } + } + if (filter == null || + filter.contains(PdfName(PdfDictionaryProperties.crypt))) { + if (_compress!) { + data = _compressStream(); + } + data = _encryptContent(data, writer); + addFilter(PdfDictionaryProperties.crypt); + } + } + } + } + } + } else if (containsKey(PdfDictionaryProperties.dl)) { + if (_compress!) { + data = _compressStream(); + } + data = _encryptContent(data, writer); + addFilter(PdfDictionaryProperties.crypt); + if (!containsKey(PdfDictionaryProperties.decodeParms)) { + final PdfArray decode = PdfArray(); + final PdfDictionary decodeparms = PdfDictionary(); + decodeparms[PdfDictionaryProperties.name] = PdfName( + PdfDictionaryProperties.stdCF, + ); + decode.add(decodeparms); + decode.add(PdfNull()); + this[PdfName(PdfDictionaryProperties.decodeParms)] = decode; + } + } + } + } else if (!PdfSecurityHelper.getHelper( + security, + ).encryptor.encryptOnlyMetadata! && + containsKey(PdfDictionaryProperties.type)) { + final IPdfPrimitive? primitive = this[PdfDictionaryProperties.type]; + if (primitive != null && primitive is PdfName) { + final PdfName fileType = primitive; + if (fileType.name != PdfDictionaryProperties.metadata) { + data = _encryptContent(data, writer); + } + } + } else { + data = _encryptContent(data, writer); + } + + this[PdfDictionaryProperties.length] = PdfNumber( + data != null ? data.length : 0, + ); + super.saveDictionary(writer, false); + writer.write(prefix); + writer.write(PdfOperators.newLine); + if (data != null && data.isNotEmpty) { + writer.write(data); + writer.write(PdfOperators.newLine); + } + writer.write(suffix); + writer.write(PdfOperators.newLine); + final SavePdfPrimitiveArgs endSaveArguments = SavePdfPrimitiveArgs(writer); + onEndSave(endSaveArguments); + if (_compress!) { + remove(PdfDictionaryProperties.filter); + } + } + + @override + void dispose() { + if (dataStream != null) { + if (dataStream is List && dataStream is! Uint8List) { + dataStream!.clear(); + } + data = null; + } + _clonedObject = null; + objNumber = null; + } + + @override + IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { + if (_clonedObject != null && _clonedObject!.crossTable == crossTable) { + return _clonedObject; + } else { + _clonedObject = null; + } + final PdfDictionary? dict = super.cloneObject(crossTable) as PdfDictionary?; + final PdfStream newStream = PdfStream(dict, dataStream); + newStream.compress = _compress; + _clonedObject = newStream; + return newStream; + } + + /// internal method + void decrypt(PdfEncryptor encryptor, int? currentObjectNumber) { + if (!decrypted!) { + decrypted = true; + data = encryptor.encryptData( + currentObjectNumber, + Uint8List.fromList(dataStream!), + false, + ); + _modify(); + } + } + + List? _encryptContent(List? data, IPdfWriter writer) { + final PdfDocument doc = writer.document!; + final PdfEncryptor encryptor = + PdfSecurityHelper.getHelper(doc.security).encryptor; + if (encryptor.encrypt && !blockEncryption) { + data = encryptor.encryptData( + PdfDocumentHelper.getHelper(doc).currentSavingObject!.objNum, + Uint8List.fromList(data!), + true, + ); + } + return data; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart index 8151c6936..872768ee5 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/primitives/pdf_string.dart @@ -1,426 +1,427 @@ -import 'dart:convert'; - -import '../../interfaces/pdf_interface.dart'; -import '../annotations/json_parser.dart'; -import '../io/decode_big_endian.dart'; -import '../io/enums.dart'; -import '../io/pdf_cross_table.dart'; -import '../pdf_document/pdf_document.dart'; -import '../security/pdf_encryptor.dart'; -import '../security/pdf_security.dart'; - -/// internal class -class PdfString implements IPdfPrimitive { - /// internal constructor - PdfString(String value, [bool? encrypted]) { - if (encrypted != null) { - if (!encrypted && value.isNotEmpty) { - data = hexToBytes(value); - if (data!.isNotEmpty) { - if (data![0] == 0xfe && data![1] == 0xff) { - this.value = decodeBigEndian(data, 2, data!.length - 2); - isHex = false; - data = []; - for (int i = 0; i < this.value!.length; i++) { - data!.add(this.value!.codeUnitAt(i).toUnsigned(8)); - } - } else { - this.value = byteToString(data!); - } - } - } else { - this.value = value; - } - isHex = true; - } else { - if (value.isEmpty) { - this.value = ''; - } else { - this.value = value; - data = []; - for (int i = 0; i < value.length; i++) { - data!.add(value.codeUnitAt(i).toUnsigned(8)); - } - } - isHex = false; - } - decrypted = false; - isParentDecrypted = false; - } - - /// internal constructor - PdfString.fromBytes(this.data) { - if (data!.isNotEmpty) { - value = String.fromCharCodes(data!); - } - isHex = true; - decrypted = false; - isParentDecrypted = false; - } - - //Constants - /// internal field - static const String stringMark = '()'; - - /// internal field - static const String hexStringMark = '<>'; - - //Fields - /// internal field - List? data; - - /// internal field - String? value; - - /// internal field - bool isAsciiEncode = false; - bool? _isSaving; - int? _objectCollectionIndex; - int? _position; - PdfObjectStatus? _status; - - /// internal field - bool? isHex; - - /// internal field - ForceEncoding encode = ForceEncoding.none; - PdfCrossTable? _crossTable; - PdfString? _clonedObject; - - /// internal field - late bool isParentDecrypted; - - /// internal field - bool isColorSpace = false; - - //Implementations - /// internal method - List pdfEncode(PdfDocument? document) { - final List result = []; - final PdfSecurity? security = (document == null) ? null : document.security; - result.add( - isHex! - ? PdfString.hexStringMark.codeUnitAt(0) - : PdfString.stringMark.codeUnitAt(0), - ); - if ((data == null || data!.isEmpty) && !isNullOrEmpty(value)) { - data = []; - for (int i = 0; i < value!.length; i++) { - data!.add(value!.codeUnitAt(i).toUnsigned(8)); - } - } - if (data != null && data!.isNotEmpty) { - List tempData; - if (isHex!) { - tempData = _getHexBytes(data!); - } else if (isAsciiEncode) { - final List data = escapeSymbols(value); - tempData = []; - for (int i = 0; i < data.length; i++) { - tempData.add(data[i].toUnsigned(8)); - } - } else if (!isColorSpace && utf8.encode(value!).length != value!.length) { - tempData = toUnicodeArray(value!, true); - tempData = escapeSymbols(tempData); - } else { - tempData = []; - for (int i = 0; i < value!.length; i++) { - tempData.add(value!.codeUnitAt(i).toUnsigned(8)); - } - if (security == null || - !PdfSecurityHelper.getHelper(security).encryptor.encrypt) { - tempData = escapeSymbols(tempData); - } - } - bool hex = false; - tempData = _encryptIfNeeded(tempData, document); - for (int i = 0; i < tempData.length; i++) { - if ((tempData[i] >= 48 && tempData[i] <= 57) || - (tempData[i] >= 65 && tempData[i] <= 70) || - (tempData[i] >= 97 && tempData[i] <= 102)) { - hex = true; - } else { - hex = false; - break; - } - } - if (isHex! && !hex) { - tempData = _getHexBytes(tempData); - } - result.addAll(tempData); - } - result.add( - isHex! - ? PdfString.hexStringMark.codeUnitAt(1) - : PdfString.stringMark.codeUnitAt(1), - ); - return result; - } - - List _getHexBytes(List data) { - final List result = []; - for (int i = 0; i < data.length; i++) { - String radix = data[i].toRadixString(16); - radix = (radix.length == 1 ? '0$radix' : radix).toUpperCase(); - result.add(radix.codeUnitAt(0).toUnsigned(8)); - result.add(radix.codeUnitAt(1).toUnsigned(8)); - } - return result; - } - - /// internal method - static String bytesToHex(List data) { - return data - .map((int byte) => byte.toRadixString(16).padLeft(2, '0')) - .join() - .toUpperCase(); - } - - /// internal method - static Future bytesToHexAsync(List data) async { - return data - .map((int byte) => byte.toRadixString(16).padLeft(2, '0')) - .join() - .toUpperCase(); - } - - /// internal method - static List escapeSymbols(dynamic value) { - if (value == null) { - throw ArgumentError.value(value, 'value', 'value cannot be null'); - } - final List data = []; - int code = 0; - for (int i = 0; i < value.length; i++) { - if (value is String) { - code = value.codeUnitAt(i); - } else if (value is List) { - code = value[i]; - } - switch (code) { - case 40: - case 41: - data.add(92); - data.add(code); - break; - case 13: - data.add(92); - data.add(114); - break; - case 92: - data.add(92); - data.add(code); - break; - - default: - data.add(code); - break; - } - } - return data; - } - - /// internal method - static List toUnicodeArray(String value, [bool addPrefix = false]) { - final List output = []; - if (addPrefix) { - output.add(254); - output.add(255); - } - for (int i = 0; i < value.length; i++) { - final int code = value.codeUnitAt(i); - output.add(code ~/ (256 >> 0)); - output.add(code & 0xff); - } - return output; - } - - /// internal method - static String byteToString(List data, [int? length]) { - length ??= data.length; - if (length > data.length) { - ArgumentError.value(length); - } - return String.fromCharCodes(data, 0, length); - } - - /// internal method - List hexToBytes(String value) { - final List hexNumbers = []; - for (int i = 0; i < value.length; i++) { - final int charCode = value.codeUnitAt(i); - if ((charCode >= 48 && charCode <= 57) || - (charCode >= 65 && charCode <= 70) || - (charCode >= 97 && charCode <= 102)) { - hexNumbers.add(_parseHex(charCode)); - } - } - return _hexDigitsToNumbers(hexNumbers); - } - - List _hexDigitsToNumbers(List hexNumbers) { - int value = 0; - bool start = true; - final List list = []; - hexNumbers.toList().forEach((int digit) { - if (start) { - value = (digit << 4).toUnsigned(8); - start = false; - } else { - value += digit; - list.add(value); - start = true; - } - }); - if (!start) { - list.add(value); - } - return list; - } - - int _parseHex(int c) { - int value = 0; - if (c >= 48 && c <= 57) { - value = (c - 48).toUnsigned(8); - } else if (c >= 65 && c <= 70) { - value = (c - 55).toUnsigned(8); - } else if (c >= 97 && c <= 102) { - value = (c - 87).toUnsigned(8); - } - return value; - } - - //IPdfPrimitive members - @override - bool? get isSaving { - _isSaving ??= false; - return _isSaving; - } - - @override - set isSaving(bool? value) { - _isSaving = value; - } - - @override - int? get objectCollectionIndex { - _objectCollectionIndex ??= 0; - return _objectCollectionIndex; - } - - @override - set objectCollectionIndex(int? value) { - _objectCollectionIndex = value; - } - - @override - int? get position { - _position ??= -1; - return _position; - } - - @override - set position(int? value) { - _position = value; - } - - @override - PdfObjectStatus? get status { - _status ??= PdfObjectStatus.none; - return _status; - } - - @override - set status(PdfObjectStatus? value) { - _status = value; - } - - @override - IPdfPrimitive? clonedObject; - - @override - void save(IPdfWriter? writer) { - if (writer != null) { - writer.write(pdfEncode(writer.document)); - } - } - - @override - void dispose() { - data = data?.map((_) => 0).toList(); - data = null; - _status = null; - } - - @override - IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { - if (_clonedObject != null && _clonedObject!._crossTable == crossTable) { - return _clonedObject; - } else { - _clonedObject = null; - } - final PdfString newString = PdfString(value!); - newString.encode = encode; - newString.isHex = isHex; - newString._crossTable = crossTable; - _clonedObject = newString; - return newString; - } - - List _encryptIfNeeded(List data, PdfDocument? document) { - final PdfSecurity? security = (document == null) ? null : document.security; - if (security == null || - (!PdfSecurityHelper.getHelper(security).encryptor.encrypt || - PdfSecurityHelper.getHelper( - security, - ).encryptor.encryptAttachmentOnly!)) { - return data; - } else { - data = PdfSecurityHelper.getHelper(security).encryptor.encryptData( - PdfDocumentHelper.getHelper(document!).currentSavingObject!.objNum, - data, - true, - ); - } - return escapeSymbols(data); - } - - /// internal field - late bool decrypted; - - /// internal method - void decrypt(PdfEncryptor encryptor, int? currentObjectNumber) { - if (data != null && - !decrypted && - !isParentDecrypted && - !encryptor.encryptAttachmentOnly!) { - decrypted = true; - value = byteToString(data!); - final List bytes = encryptor.encryptData( - currentObjectNumber, - data!, - false, - ); - value = byteToString(bytes); - const String bigEndianPreambleString = 'þÿ'; - if (value!.length > 1 && - !isColorSpace && - value!.startsWith(bigEndianPreambleString)) { - value = decodeBigEndian(bytes, 2, bytes.length - 2); - } - data = bytes; - } - } -} - -/// internal enumerator -enum ForceEncoding { - /// internal enumerator - none, - - /// internal enumerator - ascii, - - /// internal enumerator - unicode, -} +import 'dart:convert'; +import 'dart:typed_data'; + +import '../../interfaces/pdf_interface.dart'; +import '../annotations/json_parser.dart'; +import '../io/decode_big_endian.dart'; +import '../io/enums.dart'; +import '../io/pdf_cross_table.dart'; +import '../pdf_document/pdf_document.dart'; +import '../security/pdf_encryptor.dart'; +import '../security/pdf_security.dart'; + +/// internal class +class PdfString implements IPdfPrimitive { + /// internal constructor + PdfString(String value, [bool? encrypted]) { + if (encrypted != null) { + if (!encrypted && value.isNotEmpty) { + data = hexToBytes(value); + if (data!.isNotEmpty) { + if (data![0] == 0xfe && data![1] == 0xff) { + this.value = decodeBigEndian(data, 2, data!.length - 2); + isHex = false; + data = []; + for (int i = 0; i < this.value!.length; i++) { + data!.add(this.value!.codeUnitAt(i).toUnsigned(8)); + } + } else { + this.value = byteToString(data!); + } + } + } else { + this.value = value; + } + isHex = true; + } else { + if (value.isEmpty) { + this.value = ''; + } else { + this.value = value; + data = []; + for (int i = 0; i < value.length; i++) { + data!.add(value.codeUnitAt(i).toUnsigned(8)); + } + } + isHex = false; + } + decrypted = false; + isParentDecrypted = false; + } + + /// internal constructor + PdfString.fromBytes(this.data) { + if (data!.isNotEmpty) { + value = String.fromCharCodes(data!); + } + isHex = true; + decrypted = false; + isParentDecrypted = false; + } + + //Constants + /// internal field + static const String stringMark = '()'; + + /// internal field + static const String hexStringMark = '<>'; + + //Fields + /// internal field + List? data; + + /// internal field + String? value; + + /// internal field + bool isAsciiEncode = false; + bool? _isSaving; + int? _objectCollectionIndex; + int? _position; + PdfObjectStatus? _status; + + /// internal field + bool? isHex; + + /// internal field + ForceEncoding encode = ForceEncoding.none; + PdfCrossTable? _crossTable; + PdfString? _clonedObject; + + /// internal field + late bool isParentDecrypted; + + /// internal field + bool isColorSpace = false; + + //Implementations + /// internal method + List pdfEncode(PdfDocument? document) { + final List result = []; + final PdfSecurity? security = (document == null) ? null : document.security; + result.add( + isHex! + ? PdfString.hexStringMark.codeUnitAt(0) + : PdfString.stringMark.codeUnitAt(0), + ); + if ((data == null || data!.isEmpty) && !isNullOrEmpty(value)) { + data = []; + for (int i = 0; i < value!.length; i++) { + data!.add(value!.codeUnitAt(i).toUnsigned(8)); + } + } + if (data != null && data!.isNotEmpty) { + List tempData; + if (isHex!) { + tempData = _getHexBytes(data!); + } else if (isAsciiEncode) { + final List data = escapeSymbols(value); + tempData = []; + for (int i = 0; i < data.length; i++) { + tempData.add(data[i].toUnsigned(8)); + } + } else if (!isColorSpace && utf8.encode(value!).length != value!.length) { + tempData = toUnicodeArray(value!, true); + tempData = escapeSymbols(tempData); + } else { + tempData = []; + for (int i = 0; i < value!.length; i++) { + tempData.add(value!.codeUnitAt(i).toUnsigned(8)); + } + if (security == null || + !PdfSecurityHelper.getHelper(security).encryptor.encrypt) { + tempData = escapeSymbols(tempData); + } + } + bool hex = false; + tempData = _encryptIfNeeded(tempData, document); + for (int i = 0; i < tempData.length; i++) { + if ((tempData[i] >= 48 && tempData[i] <= 57) || + (tempData[i] >= 65 && tempData[i] <= 70) || + (tempData[i] >= 97 && tempData[i] <= 102)) { + hex = true; + } else { + hex = false; + break; + } + } + if (isHex! && !hex) { + tempData = _getHexBytes(tempData); + } + result.addAll(tempData); + } + result.add( + isHex! + ? PdfString.hexStringMark.codeUnitAt(1) + : PdfString.stringMark.codeUnitAt(1), + ); + return result; + } + + List _getHexBytes(List data) { + final List result = []; + for (int i = 0; i < data.length; i++) { + String radix = data[i].toRadixString(16); + radix = (radix.length == 1 ? '0$radix' : radix).toUpperCase(); + result.add(radix.codeUnitAt(0).toUnsigned(8)); + result.add(radix.codeUnitAt(1).toUnsigned(8)); + } + return result; + } + + /// internal method + static String bytesToHex(List data) { + return data + .map((int byte) => byte.toRadixString(16).padLeft(2, '0')) + .join() + .toUpperCase(); + } + + /// internal method + static Future bytesToHexAsync(List data) async { + return data + .map((int byte) => byte.toRadixString(16).padLeft(2, '0')) + .join() + .toUpperCase(); + } + + /// internal method + static List escapeSymbols(dynamic value) { + if (value == null) { + throw ArgumentError.value(value, 'value', 'value cannot be null'); + } + final List data = []; + int code = 0; + for (int i = 0; i < value.length; i++) { + if (value is String) { + code = value.codeUnitAt(i); + } else if (value is List) { + code = value[i]; + } + switch (code) { + case 40: + case 41: + data.add(92); + data.add(code); + break; + case 13: + data.add(92); + data.add(114); + break; + case 92: + data.add(92); + data.add(code); + break; + + default: + data.add(code); + break; + } + } + return data; + } + + /// internal method + static List toUnicodeArray(String value, [bool addPrefix = false]) { + final List output = []; + if (addPrefix) { + output.add(254); + output.add(255); + } + for (int i = 0; i < value.length; i++) { + final int code = value.codeUnitAt(i); + output.add(code ~/ (256 >> 0)); + output.add(code & 0xff); + } + return output; + } + + /// internal method + static String byteToString(List data, [int? length]) { + length ??= data.length; + if (length > data.length) { + ArgumentError.value(length); + } + return String.fromCharCodes(data, 0, length); + } + + /// internal method + List hexToBytes(String value) { + final List hexNumbers = []; + for (int i = 0; i < value.length; i++) { + final int charCode = value.codeUnitAt(i); + if ((charCode >= 48 && charCode <= 57) || + (charCode >= 65 && charCode <= 70) || + (charCode >= 97 && charCode <= 102)) { + hexNumbers.add(_parseHex(charCode)); + } + } + return _hexDigitsToNumbers(hexNumbers); + } + + List _hexDigitsToNumbers(List hexNumbers) { + int value = 0; + bool start = true; + final List list = []; + hexNumbers.toList().forEach((int digit) { + if (start) { + value = (digit << 4).toUnsigned(8); + start = false; + } else { + value += digit; + list.add(value); + start = true; + } + }); + if (!start) { + list.add(value); + } + return list; + } + + int _parseHex(int c) { + int value = 0; + if (c >= 48 && c <= 57) { + value = (c - 48).toUnsigned(8); + } else if (c >= 65 && c <= 70) { + value = (c - 55).toUnsigned(8); + } else if (c >= 97 && c <= 102) { + value = (c - 87).toUnsigned(8); + } + return value; + } + + //IPdfPrimitive members + @override + bool? get isSaving { + _isSaving ??= false; + return _isSaving; + } + + @override + set isSaving(bool? value) { + _isSaving = value; + } + + @override + int? get objectCollectionIndex { + _objectCollectionIndex ??= 0; + return _objectCollectionIndex; + } + + @override + set objectCollectionIndex(int? value) { + _objectCollectionIndex = value; + } + + @override + int? get position { + _position ??= -1; + return _position; + } + + @override + set position(int? value) { + _position = value; + } + + @override + PdfObjectStatus? get status { + _status ??= PdfObjectStatus.none; + return _status; + } + + @override + set status(PdfObjectStatus? value) { + _status = value; + } + + @override + IPdfPrimitive? clonedObject; + + @override + void save(IPdfWriter? writer) { + if (writer != null) { + writer.write(pdfEncode(writer.document)); + } + } + + @override + void dispose() { + data = data?.map((_) => 0).toList(); + data = null; + _status = null; + } + + @override + IPdfPrimitive? cloneObject(PdfCrossTable crossTable) { + if (_clonedObject != null && _clonedObject!._crossTable == crossTable) { + return _clonedObject; + } else { + _clonedObject = null; + } + final PdfString newString = PdfString(value!); + newString.encode = encode; + newString.isHex = isHex; + newString._crossTable = crossTable; + _clonedObject = newString; + return newString; + } + + List _encryptIfNeeded(List data, PdfDocument? document) { + final PdfSecurity? security = (document == null) ? null : document.security; + if (security == null || + (!PdfSecurityHelper.getHelper(security).encryptor.encrypt || + PdfSecurityHelper.getHelper( + security, + ).encryptor.encryptAttachmentOnly!)) { + return data; + } else { + data = PdfSecurityHelper.getHelper(security).encryptor.encryptData( + PdfDocumentHelper.getHelper(document!).currentSavingObject!.objNum, + Uint8List.fromList(data), + true, + ); + } + return escapeSymbols(data); + } + + /// internal field + late bool decrypted; + + /// internal method + void decrypt(PdfEncryptor encryptor, int? currentObjectNumber) { + if (data != null && + !decrypted && + !isParentDecrypted && + !encryptor.encryptAttachmentOnly!) { + decrypted = true; + value = byteToString(data!); + final List bytes = encryptor.encryptData( + currentObjectNumber, + Uint8List.fromList(data!), + false, + ); + value = byteToString(bytes); + const String bigEndianPreambleString = 'þÿ'; + if (value!.length > 1 && + !isColorSpace && + value!.startsWith(bigEndianPreambleString)) { + value = decodeBigEndian(bytes, 2, bytes.length - 2); + } + data = bytes; + } + } +} + +/// internal enumerator +enum ForceEncoding { + /// internal enumerator + none, + + /// internal enumerator + ascii, + + /// internal enumerator + unicode, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1.dart index 9b6564ce8..903425f6e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1.dart @@ -1,1366 +1,1366 @@ -import 'dart:convert'; -import 'dart:math'; - -import '../../../io/stream_reader.dart'; -import '../pkcs/pfx_data.dart'; -import 'asn1_stream.dart'; -import 'ber.dart'; -import 'der.dart'; - -/// internal class -class IAsn1 { - /// internal method - Asn1? getAsn1() => null; -} - -/// internal class -class IAsn1Octet implements IAsn1 { - /// internal method - PdfStreamReader? getOctetStream() => null; - @override - Asn1? getAsn1() => null; -} - -/// internal class -class IAsn1Tag implements IAsn1 { - /// internal property - int? get tagNumber => null; - - /// internal method - IAsn1? getParser(int tagNumber, bool isExplicit) => null; - @override - Asn1? getAsn1() => null; -} - -/// internal class -class IAsn1Collection implements IAsn1 { - /// internal method - IAsn1? readObject() => null; - - @override - Asn1? getAsn1() => null; -} - -/// internal class -abstract class Asn1 extends Asn1Encode { - /// internal constructor - Asn1([List? tag]) { - if (tag != null) { - _tag = tag; - } - } - - //Fields - late List _tag; - - /// internal field - List? bytes; - - /// internal field - static const String nullValue = 'NULL'; - - /// internal field - static const String der = 'DER'; - - /// internal field - static const String desEde = 'DESede'; - - /// internal field - static const String des = 'DES'; - - /// internal field - static const String rsa = 'RSA'; - - /// internal field - static const String pkcs7 = 'PKCS7'; - - //Abstract methods - /// internal method - void encode(DerStream derOut); - - //Properties - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode; - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other); - - //Implementation - @override - Asn1 getAsn1() { - return this; - } - - /// internal method - List? asn1Encode(List bytes) { - this.bytes = []; - this.bytes!.add(getTagValue(_tag)); - write(bytes.length); - this.bytes!.addAll(bytes); - final List result = this.bytes!.toList(); - this.bytes!.clear(); - return result; - } - - /// internal method - void write(int length) { - if (length > 127) { - int size = 1; - int value = length; - while ((value >>= 8) != 0) { - size++; - } - bytes!.add((size | 0x80).toUnsigned(8)); - for (int i = (size - 1) * 8; i >= 0; i -= 8) { - bytes!.add((length >> i).toUnsigned(8)); - } - } else { - bytes!.add(length); - } - } - - @override - List? getDerEncoded() { - final DerStream stream = DerStream([])..writeObject(this); - return stream.stream; - } - - /// internal method - int getAsn1Hash() { - return hashCode; - } - - /// internal method - int getTagValue(List tags) { - int value = 0; - for (final Asn1UniversalTags tag in tags) { - switch (tag) { - case Asn1UniversalTags.reservedBER: - value |= 0; - break; - case Asn1UniversalTags.boolean: - value |= 1; - break; - case Asn1UniversalTags.integer: - value |= 2; - break; - case Asn1UniversalTags.bitString: - value |= 3; - break; - case Asn1UniversalTags.octetString: - value |= 4; - break; - case Asn1UniversalTags.nullValue: - value |= 5; - break; - case Asn1UniversalTags.objectIdentifier: - value |= 6; - break; - case Asn1UniversalTags.objectDescriptor: - value |= 7; - break; - case Asn1UniversalTags.externalValue: - value |= 8; - break; - case Asn1UniversalTags.real: - value |= 9; - break; - case Asn1UniversalTags.enumerated: - value |= 10; - break; - case Asn1UniversalTags.embeddedPDV: - value |= 11; - break; - case Asn1UniversalTags.utf8String: - value |= 12; - break; - case Asn1UniversalTags.relativeOid: - value |= 13; - break; - case Asn1UniversalTags.sequence: - value |= 16; - break; - case Asn1UniversalTags.setValue: - value |= 17; - break; - case Asn1UniversalTags.numericString: - value |= 18; - break; - case Asn1UniversalTags.printableString: - value |= 19; - break; - case Asn1UniversalTags.teletexString: - value |= 20; - break; - case Asn1UniversalTags.videotexString: - value |= 21; - break; - case Asn1UniversalTags.ia5String: - value |= 22; - break; - case Asn1UniversalTags.utfTime: - value |= 23; - break; - case Asn1UniversalTags.generalizedTime: - value |= 24; - break; - case Asn1UniversalTags.graphicsString: - value |= 25; - break; - case Asn1UniversalTags.visibleString: - value |= 26; - break; - case Asn1UniversalTags.generalString: - value |= 27; - break; - case Asn1UniversalTags.universalString: - value |= 28; - break; - case Asn1UniversalTags.characterString: - value |= 29; - break; - case Asn1UniversalTags.bmpString: - value |= 30; - break; - case Asn1UniversalTags.constructed: - value |= 32; - break; - case Asn1UniversalTags.application: - value |= 64; - break; - case Asn1UniversalTags.tagged: - value |= 128; - break; - } - } - return value; - } - - /// internal method - static int getHashCode(List? data) { - if (data == null) { - return 0; - } - int i = data.length; - int hc = i + 1; - while (--i >= 0) { - hc = (hc * 257).toSigned(32); - hc = (hc ^ data[i].toUnsigned(8)).toSigned(32); - } - return hc; - } - - /// internal method - static bool areEqual(List? a, List? b) { - if (a == b) { - return true; - } - if (a == null || b == null) { - return false; - } - return haveSameContents(a, b); - } - - /// internal method - static bool haveSameContents(List a, List b) { - int i = a.length; - if (i != b.length) { - return false; - } - while (i != 0) { - --i; - if (a[i] != b[i]) { - return false; - } - } - return true; - } - - /// internal method - static List clone(List data) { - return List.generate(data.length, (int i) => data[i]); - } - - /// internal method - static void uInt32ToBe(int n, List bs, int off) { - bs[off] = (n >> 24).toUnsigned(8); - bs[off + 1] = (n >> 16).toUnsigned(8); - bs[off + 2] = (n >> 8).toUnsigned(8); - bs[off + 3] = n.toUnsigned(8); - } - - /// internal method - static int beToUInt32(List bs, int off) { - return bs[off].toUnsigned(8) << 24 | - bs[off + 1].toUnsigned(8) << 16 | - bs[off + 2].toUnsigned(8) << 8 | - bs[off + 3].toUnsigned(8); - } - - /// internal method - static int beToUInt64(List bs, int off) { - final int hi = beToUInt32(bs, off); - final int lo = beToUInt32(bs, off + 4); - return (hi.toUnsigned(64) << 32) | lo.toUnsigned(64); - } - - /// internal method - static void uInt64ToBe(int n, List bs, int off) { - uInt32ToBe((n >> 32).toUnsigned(32), bs, off); - uInt32ToBe(n.toUnsigned(32), bs, off + 4); - } - - /// internal method - static BigInt leToUInt32(List bs, int off) { - return BigInt.from( - bs[off].toUnsigned(32) | - bs[off + 1].toUnsigned(32) << 8 | - bs[off + 2].toUnsigned(32) << 16 | - bs[off + 3].toUnsigned(32) << 24, - ); - } - - /// internal method - static void uInt32ToLe(BigInt n, List bs, int off) { - bs[off] = n.toUnsigned(8).toInt(); - bs[off + 1] = (n >> 8).toUnsigned(8).toInt(); - bs[off + 2] = (n >> 16).toUnsigned(8).toInt(); - bs[off + 3] = (n >> 24).toUnsigned(8).toInt(); - } - - /// internal method - static Asn1 fromByteArray(List data) { - try { - return Asn1Stream(PdfStreamReader(data)).readAsn1()!; - } catch (e) { - throw Exception('Invalid entry'); - } - } -} - -/// internal class -abstract class Asn1Encode implements IAsn1 { - @override - Asn1? getAsn1(); - - //Implementation - /// internal method - List? getEncoded([String? encoding]) { - if (encoding == null) { - return (Asn1DerStream([])..writeObject(this)).stream; - } else { - if (encoding == Asn1.der) { - final DerStream stream = DerStream([])..writeObject(this); - return stream.stream; - } - return getEncoded(); - } - } - - /// internal method - Future?> getEncodedAsync([String? encoding]) async { - if (encoding == null) { - return (Asn1DerStream([])..writeObject(this)).stream; - } else { - if (encoding == Asn1.der) { - final DerStream stream = DerStream([])..writeObject(this); - return stream.stream; - } - return getEncoded(); - } - } - - /// internal method - List? getDerEncoded() { - return getEncoded(Asn1.der); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return getAsn1()!.getAsn1Hash(); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other); -} - -/// internal class -class Asn1EncodeCollection { - /// internal constructor - Asn1EncodeCollection([List? vector]) { - encodableObjects = []; - if (vector != null) { - add(vector); - } - } - - /// internal field - late List encodableObjects; - - //Properties - /// internal property - Asn1Encode? operator [](int index) => encodableObjects[index] as Asn1Encode?; - - /// internal property - int get count => encodableObjects.length; - - //Implementation - /// internal method - void add(List objs) { - for (final dynamic obj in objs) { - if (obj is Asn1Encode) { - encodableObjects.add(obj); - } - } - } -} - -/// internal class -class Asn1Octet extends Asn1 implements IAsn1Octet { - /// internal constructor - Asn1Octet(this.value) - : super([Asn1UniversalTags.octetString]); - - /// internal constructor - Asn1Octet.fromObject(Asn1Encode obj) { - value = obj.getEncoded(Asn1.der); - } - //Fields - /// internal field - List? value; - - /// internal property - IAsn1Octet get parser => this; - //Implementation - @override - PdfStreamReader getOctetStream() { - return PdfStreamReader(value); - } - - /// internal method - List? getOctets() { - return value; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return Asn1.getHashCode(getOctets()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerOctet) { - return Asn1.areEqual(getOctets(), asn1.getOctets()); - } else { - return false; - } - } - - @override - String toString() { - return value.toString(); - } - - /// internal method - List? asnEncode() { - return super.asn1Encode(value!); - } - - /// internal method - @override - void encode(DerStream stream) { - throw ArgumentError.value(stream, 'stream', 'Not Implemented'); - } - - //Static methods - /// internal method - static Asn1Octet? getOctetString(Asn1Tag tag, bool isExplicit) { - final Asn1? asn1 = tag.getObject(); - if (isExplicit || asn1 is Asn1Octet) { - return getOctetStringFromObject(asn1); - } - return BerOctet.getBerOctet(Asn1Sequence.getSequence(asn1)!); - } - - /// internal method - static Asn1Octet? getOctetStringFromObject(dynamic obj) { - if (obj == null || obj is Asn1Octet) { - return obj as Asn1Octet?; - } - if (obj is Asn1Tag) { - return getOctetStringFromObject(obj.getObject()); - } - throw ArgumentError.value(obj, 'obj', 'Invalid object entry'); - } -} - -/// internal class -abstract class Asn1Null extends Asn1 { - /// internal constructor - Asn1Null() : super([Asn1UniversalTags.nullValue]); - //Implementation - /// internal method - List toArray() { - return []; - } - - /// internal method - List? asnEncode() { - return super.asn1Encode(toArray()); - } - - @override - String toString() { - return Asn1.nullValue; - } - - @override - void encode(DerStream derOut) { - derOut.writeEncoded(5, toArray()); - } -} - -/// internal class -class Asn1Sequence extends Asn1 { - //Constructor - /// internal constructor - Asn1Sequence() - : super([ - Asn1UniversalTags.sequence, - Asn1UniversalTags.constructed, - ]) { - objects = []; - } - //Fields - /// internal field - List? objects; - Asn1SequenceHelper? _parser; - - /// internal field - int get count { - return objects!.length; - } - - /// internal property - IAsn1Collection get parser { - return _parser ??= Asn1SequenceHelper(this); - } - - /// internal property - IAsn1? operator [](int index) { - dynamic result; - if (index < objects!.length) { - result = objects![index]; - } else { - result = null; - } - return result as IAsn1?; - } - - //Implementation - /// internal method - static Asn1Sequence? getSequence(dynamic obj, [bool? explicitly]) { - Asn1Sequence? result; - if (explicitly == null) { - if (obj == null || obj is Asn1Sequence) { - result = obj as Asn1Sequence?; - } else if (obj is IAsn1Collection) { - result = Asn1Sequence.getSequence(obj.getAsn1()); - } else if (obj is List) { - result = Asn1Sequence.getSequence( - Asn1Stream(PdfStreamReader(obj)).readAsn1(), - ); - } else if (obj is Asn1Encode) { - final Asn1? primitive = obj.getAsn1(); - if (primitive != null && primitive is Asn1Sequence) { - return primitive; - } - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); - } - } else if (obj is Asn1Tag) { - final Asn1? inner = obj.getObject(); - if (explicitly) { - if (!obj.explicit!) { - throw ArgumentError.value( - explicitly, - 'explicitly', - 'Invalid entry in sequence', - ); - } - result = inner as Asn1Sequence?; - } else if (obj.explicit!) { - if (obj is DerTag) { - result = BerSequence.fromObject(inner); - } - result = DerSequence.fromObject(inner); - } else { - if (inner is Asn1Sequence) { - result = inner; - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); - } - } - } - return result; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - int hashCode = count; - for (final dynamic o in objects!) { - hashCode *= 17; - if (o == null) { - hashCode ^= DerNull().getAsn1Hash(); - } else { - hashCode ^= o.hashCode; - } - } - return hashCode; - } - - /// internal property - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object asn1) { - if (asn1 is Asn1Sequence) { - if (count != asn1.count) { - return false; - } - for (int i = 0; i < count; i++) { - final Asn1? o1 = getCurrentObject(objects![i]).getAsn1(); - final Asn1? o2 = getCurrentObject(asn1.objects![i]).getAsn1(); - if (o1 != o2) { - return false; - } - } - } else { - return false; - } - return true; - } - - /// internal method - Asn1Encode getCurrentObject(dynamic e) { - if (e != null && e is Asn1Encode) { - return e; - } else { - return DerNull(); - } - } - - @override - String toString([List? e]) { - if (e == null) { - return toString(objects); - } else { - String result = '['; - for (int i = 0; i < objects!.length; i++) { - result += objects![i].toString(); - if (i != objects!.length - 1) { - result += ', '; - } - } - result += ']'; - return result; - } - } - - /// internal method - List toArray() { - final List stream = []; - for (final dynamic obj in objects!) { - List? buffer; - if (obj is Asn1Integer) { - buffer = obj.asnEncode(); - } else if (obj is Asn1Boolean) { - buffer = obj.asnEncode(); - } else if (obj is Asn1Identifier) { - buffer = obj.asnEncode(); - } else if (obj is Asn1Null) { - buffer = obj.asnEncode(); - } else if (obj is Asn1Octet) { - buffer = obj.asnEncode(); - } else if (obj is Asn1Sequence) { - buffer = obj.asnEncode(); - } else if (obj is Algorithms) { - buffer = obj.asnEncode(); - } - if (buffer != null && buffer.isNotEmpty) { - stream.addAll(buffer); - } - } - return stream; - } - - @override - void encode(DerStream derOut) { - throw ArgumentError.value('Not Implemented'); - } - - /// internal method - List? asnEncode() { - return super.asn1Encode(toArray()); - } -} - -/// internal class -class Asn1SequenceCollection extends Asn1Encode { - /// internal constructor - Asn1SequenceCollection(Asn1Sequence sequence) { - id = DerObjectID.getID(sequence[0]); - value = (sequence[1]! as Asn1Tag).getObject(); - if (sequence.count == 3) { - attributes = sequence[2] as DerSet?; - } - } - - /// internal field - DerObjectID? id; - - /// internal field - Asn1? value; - - /// internal field - Asn1Set? attributes; - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection([ - id, - DerTag(0, value), - ]); - if (attributes != null) { - collection.encodableObjects.add(attributes); - } - return DerSequence(collection: collection); - } -} - -/// internal class -class Asn1SequenceHelper implements IAsn1Collection { - /// internal constructor - Asn1SequenceHelper(Asn1Sequence sequence) { - _sequence = sequence; - _max = sequence.count; - } - //Fields - Asn1Sequence? _sequence; - int? _max; - int? _index; - //Implementation - @override - IAsn1? readObject() { - if (_index == _max) { - return null; - } - final IAsn1? obj = _sequence![_index!]; - _index = _index! + 1; - if (obj is Asn1Sequence) { - return obj.parser; - } - if (obj is Asn1Set) { - return obj.parser; - } - return obj; - } - - @override - Asn1? getAsn1() { - return _sequence; - } -} - -/// internal class -class Asn1Set extends Asn1 { - /// internal constructor - Asn1Set([int? capacity]) { - objects = - capacity != null - ? List.generate(capacity, (dynamic i) => null) - : []; - } - //Fields - /// internal field - late List objects; - - //Properties - /// internal property - IAsn1SetHelper get parser { - return Asn1SetHelper(this); - } - - /// internal property - Asn1Encode? operator [](int index) => objects[index] as Asn1Encode?; - - //Implementation - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - int hc = objects.length; - for (final dynamic o in objects) { - hc *= 17; - if (o == null) { - hc ^= DerNull.value.getAsn1Hash(); - } else { - hc ^= o.hashCode; - } - } - return hc; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is Asn1Set) { - if (objects.length != asn1.objects.length) { - return false; - } - for (int i = 0; i < objects.length; i++) { - final Asn1? o1 = getCurrentSet(objects[i]).getAsn1(); - final Asn1? o2 = getCurrentSet(asn1.objects[i]).getAsn1(); - if (o1 != o2) { - return false; - } - } - } else { - return false; - } - return true; - } - - /// internal method - Asn1Encode getCurrentSet(dynamic e) { - if (e is Asn1Encode) { - return e; - } else { - return DerNull.value; - } - } - - /// internal method - bool lessThanOrEqual(List a, List b) { - final int len = min(a.length, b.length); - for (int i = 0; i != len; ++i) { - if (a[i] != b[i]) { - return a[i] < b[i]; - } - } - return len == a.length; - } - - /// internal method - void addObject(Asn1Encode? obj) { - objects.add(obj); - } - - @override - String toString() { - return objects.toString(); - } - - @override - void encode(DerStream derOut) { - throw ArgumentError.value('Not Implemented'); - } - - /// internal method - void sortObjects() { - if (objects.length > 1) { - bool swapped = true; - int lastSwap = objects.length - 1; - while (swapped) { - int index = 0; - int swapIndex = 0; - List? a = (objects[0] as Asn1Encode).getEncoded(); - swapped = false; - while (index != lastSwap) { - final List b = (objects[index + 1] as Asn1Encode).getEncoded()!; - if (lessThanOrEqual(a!, b)) { - a = b; - } else { - final dynamic o = objects[index]; - objects[index] = objects[index + 1]; - objects[index + 1] = o; - swapped = true; - swapIndex = index; - } - index++; - } - lastSwap = swapIndex; - } - } - } - - //static methods - /// internal method - static Asn1Set? getAsn1Set(dynamic obj, [bool? isExplicit]) { - Asn1Set? result; - if (isExplicit == null) { - if (obj == null || obj is Asn1Set) { - result = obj as Asn1Set?; - } else if (obj is IAsn1SetHelper) { - result = Asn1Set.getAsn1Set(obj.getAsn1()); - } else if (obj is List) { - result = Asn1Set.getAsn1Set( - Asn1Stream(PdfStreamReader(obj)).readAsn1(), - ); - } else if (obj is Asn1Encode) { - final Asn1? asn1 = obj.getAsn1(); - if (asn1 != null && asn1 is Asn1Set) { - result = asn1; - } - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); - } - } else if (obj is Asn1Tag) { - final Asn1? inner = obj.getObject(); - if (isExplicit) { - if (!obj.explicit!) { - throw ArgumentError.value(obj, 'obj', 'Tagged object is implicit.'); - } - result = (inner is Asn1Set) ? inner : null; - } else if (obj.explicit! && inner is Asn1Encode) { - result = DerSet(array: [inner]); - } else if (inner is Asn1Set) { - result = inner; - } else if (inner is Asn1Sequence) { - final Asn1EncodeCollection collection = Asn1EncodeCollection(); - // ignore: avoid_function_literals_in_foreach_calls - inner.objects!.toList().forEach( - (dynamic entry) => collection.encodableObjects.add(entry), - ); - result = DerSet(collection: collection, isSort: false); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); - } - } - return result; - } -} - -/// internal class -class Asn1SetHelper implements IAsn1SetHelper { - /// internal constructor - Asn1SetHelper(Asn1Set outer) { - _set = outer; - _max = outer.objects.length; - } - Asn1Set? _set; - int? _max; - int? _index; - @override - IAsn1? readObject() { - if (_index == _max) { - return null; - } else { - final Asn1Encode? obj = _set![_index!]; - _index = _index! + 1; - if (obj is Asn1Sequence) { - return obj.parser; - } - if (obj is Asn1Set) { - return obj.parser; - } - return obj; - } - } - - @override - Asn1? getAsn1() { - return _set; - } -} - -/// internal class -class Asn1Tag extends Asn1 implements IAsn1Tag { - /// internal constructor - Asn1Tag(int? tagNumber, this.object, [bool? isExplicit]) { - explicit = isExplicit ?? true; - _tagNumber = tagNumber; - } - //Fields - int? _tagNumber; - - /// internal field - bool? explicit; - - /// internal field - Asn1Encode? object; - //Properties - @override - int? get tagNumber { - return _tagNumber; - } - - //Static methods - /// internal method - static Asn1Tag? getTag(dynamic obj, [bool? isExplicit]) { - if (isExplicit != null && obj is Asn1Tag) { - if (isExplicit) { - return obj.getObject() as Asn1Tag?; - } - throw ArgumentError.value(obj, 'obj', 'Explicit tag is not used'); - } else { - if (obj == null || obj is Asn1Tag) { - return obj as Asn1Tag?; - } - throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); - } - } - - //Implementation - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is Asn1Tag) { - return _tagNumber == asn1._tagNumber && - explicit == asn1.explicit && - getObject() == asn1.getObject(); - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - int code = _tagNumber.hashCode; - if (object != null) { - code ^= object.hashCode; - } - return code; - } - - @override - String toString() { - return '[$_tagNumber]$object'; - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - throw ArgumentError.value(stream, 'stream', 'Not Implemented'); - } - - /// internal method - Asn1? getObject() { - if (object != null) { - return object!.getAsn1(); - } - return null; - } - - @override - IAsn1? getParser(int tagNumber, bool isExplicit) { - switch (tagNumber) { - case Asn1Tags.setTag: - return Asn1Set.getAsn1Set(this, isExplicit)!.parser; - case Asn1Tags.sequence: - return Asn1Sequence.getSequence(this, isExplicit)!.parser; - case Asn1Tags.octetString: - return Asn1Octet.getOctetString(this, isExplicit)!.parser; - } - if (isExplicit) { - return getObject(); - } - throw ArgumentError.value( - tagNumber, - 'tagNumber', - 'Implicit tagging is not supported', - ); - } -} - -/// internal class -class Asn1DerStream extends DerStream { - /// internal constructor - Asn1DerStream([List? stream]) { - if (stream != null) { - this.stream = stream; - } else { - this.stream = []; - } - } -} - -/// internal class -class Asn1Integer extends Asn1 { - /// internal constructor - Asn1Integer(this._value) - : super([Asn1UniversalTags.integer]); - - /// internal field - late final int _value; - - /// internal property - List _toArray() { - return _value < 255 ? [_value] : _getBytesFromLong(_value); - } - - /// internal method - List? asnEncode() { - return super.asn1Encode(_toArray()); - } - - @override - void encode(DerStream derOut) { - derOut.writeEncoded( - getTagValue([Asn1UniversalTags.integer]), - null, - ); - } - - List _getBytesFromLong(int value) { - final List bytes = []; - for (int i = 0; i < 8; i++) { - bytes.add((value >> (i * 8)) & 0xFF); - } - return bytes; - } -} - -/// internal class -class Asn1Boolean extends Asn1 { - /// internal constructor - Asn1Boolean(this._value) - : super([Asn1UniversalTags.boolean]); - - /// internal field - late final bool _value; - - /// internal method - List _toArray() { - return _value ? [0xff] : [0]; - } - - /// internal method - List? asnEncode() { - return super.asn1Encode(_toArray()); - } - - @override - void encode(DerStream derOut) { - derOut.writeEncoded( - getTagValue([Asn1UniversalTags.boolean]), - _toArray(), - ); - } -} - -/// internal class -class Asn1Identifier extends Asn1 { - /// internal constructor - Asn1Identifier(this._id) - : super([Asn1UniversalTags.objectIdentifier]); - - /// internal field - late final String _id; - - /// internal method - List _toArray() { - final List parts = _id.split('.'); - final int firstPart = int.parse(parts[0]); - final int secondPart = int.parse(parts[1]); - final List bytes = []; - _appendField(firstPart * 40 + secondPart, bytes); - for (int i = 2; i < parts.length; i++) { - final String part = parts[i]; - if (part.length < 18) { - _appendField(int.parse(part), bytes); - } else { - _appendFieldFromString(part, bytes); - } - } - return bytes; - } - - void _appendField(int value, List bytes) { - if (value >= (1 << 7)) { - if (value >= (1 << 14)) { - if (value >= (1 << 21)) { - if (value >= (1 << 28)) { - if (value >= (1 << 35)) { - if (value >= (1 << 42)) { - if (value >= (1 << 49)) { - if (value >= (1 << 56)) { - bytes.add(((value >> 56) | 0x80).toUnsigned(8)); - } - bytes.add(((value >> 49) | 0x80).toUnsigned(8)); - } - bytes.add(((value >> 42) | 0x80).toUnsigned(8)); - } - bytes.add(((value >> 35) | 0x80).toUnsigned(8)); - } - bytes.add(((value >> 28) | 0x80).toUnsigned(8)); - } - bytes.add(((value >> 21) | 0x80).toUnsigned(8)); - } - bytes.add(((value >> 14) | 0x80).toUnsigned(8)); - } - bytes.add(((value >> 7) | 0x80).toUnsigned(8)); - } - bytes.add((value & 0x7f).toUnsigned(8)); - } - - void _appendFieldFromString(String value, List bytes) { - int byteCount; - byteCount = ((utf8.encode(value).length) + 6) ~/ 7; - if (byteCount == 0) { - bytes.add(0); - } else { - int tmpValue = int.parse(value); - final List tmp = List.filled(byteCount, 0); - for (int i = byteCount - 1; i >= 0; i--) { - tmp[i] = (tmpValue & 0x7F) | 0x80; - tmpValue = tmpValue >> 7; - } - tmp[byteCount - 1] &= 0x7F; - bytes.addAll(tmp); - } - } - - /// internal method - List? asnEncode() { - return super.asn1Encode(_toArray()); - } - - @override - void encode(DerStream derOut) { - derOut.writeEncoded( - getTagValue([Asn1UniversalTags.objectIdentifier]), - _toArray(), - ); - } -} - -/// internal class -class GeneralizedTime extends Asn1 { - /// internal constructor - GeneralizedTime(List bytes) { - time = utf8.decode(bytes); - } - //Fields - /// internal field - late String time; - //Implementation - /// internal method - DateTime? toDateTime() { - return DateTime.tryParse(time); - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.generalizedTime, utf8.encode(time)); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1Object) { - throw ArgumentError.value('Not implemented'); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return time.hashCode; - } -} - -/// internal class -class Asn1Tags { - /// internal field - static const int boolean = 0x01; - - /// internal field - static const int integer = 0x02; - - /// internal field - static const int bitString = 0x03; - - /// internal field - static const int octetString = 0x04; - - /// internal field - static const int nullValue = 0x05; - - /// internal field - static const int objectIdentifier = 0x06; - - /// internal field - static const int enumerated = 0x0a; - - /// internal field - static const int sequence = 0x10; - - /// internal field - static const int setTag = 0x11; - - /// internal field - static const int printableString = 0x13; - - /// internal field - static const int teleText = 0x14; - - /// internal field - static const int asciiString = 0x16; - - /// internal field - static const int utcTime = 0x17; - - /// internal field - static const int generalizedTime = 0x18; - - /// internal field - static const int bmpString = 0x1e; - - /// internal field - static const int utf8String = 0x0c; - - /// internal field - static const int constructed = 0x20; - - /// internal field - static const int tagged = 0x80; -} - -enum Asn1UniversalTags { - reservedBER, - boolean, - integer, - bitString, - octetString, - nullValue, - objectIdentifier, - objectDescriptor, - externalValue, - real, - enumerated, - embeddedPDV, - utf8String, - relativeOid, - sequence, - setValue, - numericString, - printableString, - teletexString, - videotexString, - ia5String, - utfTime, - generalizedTime, - graphicsString, - visibleString, - generalString, - universalString, - characterString, - bmpString, - constructed, - application, - tagged, -} +import 'dart:convert'; +import 'dart:math'; + +import '../../../io/stream_reader.dart'; +import '../pkcs/pfx_data.dart'; +import 'asn1_stream.dart'; +import 'ber.dart'; +import 'der.dart'; + +/// internal class +class IAsn1 { + /// internal method + Asn1? getAsn1() => null; +} + +/// internal class +class IAsn1Octet implements IAsn1 { + /// internal method + PdfStreamReader? getOctetStream() => null; + @override + Asn1? getAsn1() => null; +} + +/// internal class +class IAsn1Tag implements IAsn1 { + /// internal property + int? get tagNumber => null; + + /// internal method + IAsn1? getParser(int tagNumber, bool isExplicit) => null; + @override + Asn1? getAsn1() => null; +} + +/// internal class +class IAsn1Collection implements IAsn1 { + /// internal method + IAsn1? readObject() => null; + + @override + Asn1? getAsn1() => null; +} + +/// internal class +abstract class Asn1 extends Asn1Encode { + /// internal constructor + Asn1([List? tag]) { + if (tag != null) { + _tag = tag; + } + } + + //Fields + late List _tag; + + /// internal field + List? bytes; + + /// internal field + static const String nullValue = 'NULL'; + + /// internal field + static const String der = 'DER'; + + /// internal field + static const String desEde = 'DESede'; + + /// internal field + static const String des = 'DES'; + + /// internal field + static const String rsa = 'RSA'; + + /// internal field + static const String pkcs7 = 'PKCS7'; + + //Abstract methods + /// internal method + void encode(DerStream derOut); + + //Properties + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode; + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other); + + //Implementation + @override + Asn1 getAsn1() { + return this; + } + + /// internal method + List? asn1Encode(List bytes) { + this.bytes = []; + this.bytes!.add(getTagValue(_tag)); + write(bytes.length); + this.bytes!.addAll(bytes); + final List result = this.bytes!.toList(); + this.bytes!.clear(); + return result; + } + + /// internal method + void write(int length) { + if (length > 127) { + int size = 1; + int value = length; + while ((value >>= 8) != 0) { + size++; + } + bytes!.add((size | 0x80).toUnsigned(8)); + for (int i = (size - 1) * 8; i >= 0; i -= 8) { + bytes!.add((length >> i).toUnsigned(8)); + } + } else { + bytes!.add(length); + } + } + + @override + List? getDerEncoded() { + final DerStream stream = DerStream([])..writeObject(this); + return stream.stream; + } + + /// internal method + int getAsn1Hash() { + return hashCode; + } + + /// internal method + int getTagValue(List tags) { + int value = 0; + for (final Asn1UniversalTags tag in tags) { + switch (tag) { + case Asn1UniversalTags.reservedBER: + value |= 0; + break; + case Asn1UniversalTags.boolean: + value |= 1; + break; + case Asn1UniversalTags.integer: + value |= 2; + break; + case Asn1UniversalTags.bitString: + value |= 3; + break; + case Asn1UniversalTags.octetString: + value |= 4; + break; + case Asn1UniversalTags.nullValue: + value |= 5; + break; + case Asn1UniversalTags.objectIdentifier: + value |= 6; + break; + case Asn1UniversalTags.objectDescriptor: + value |= 7; + break; + case Asn1UniversalTags.externalValue: + value |= 8; + break; + case Asn1UniversalTags.real: + value |= 9; + break; + case Asn1UniversalTags.enumerated: + value |= 10; + break; + case Asn1UniversalTags.embeddedPDV: + value |= 11; + break; + case Asn1UniversalTags.utf8String: + value |= 12; + break; + case Asn1UniversalTags.relativeOid: + value |= 13; + break; + case Asn1UniversalTags.sequence: + value |= 16; + break; + case Asn1UniversalTags.setValue: + value |= 17; + break; + case Asn1UniversalTags.numericString: + value |= 18; + break; + case Asn1UniversalTags.printableString: + value |= 19; + break; + case Asn1UniversalTags.teletexString: + value |= 20; + break; + case Asn1UniversalTags.videotexString: + value |= 21; + break; + case Asn1UniversalTags.ia5String: + value |= 22; + break; + case Asn1UniversalTags.utfTime: + value |= 23; + break; + case Asn1UniversalTags.generalizedTime: + value |= 24; + break; + case Asn1UniversalTags.graphicsString: + value |= 25; + break; + case Asn1UniversalTags.visibleString: + value |= 26; + break; + case Asn1UniversalTags.generalString: + value |= 27; + break; + case Asn1UniversalTags.universalString: + value |= 28; + break; + case Asn1UniversalTags.characterString: + value |= 29; + break; + case Asn1UniversalTags.bmpString: + value |= 30; + break; + case Asn1UniversalTags.constructed: + value |= 32; + break; + case Asn1UniversalTags.application: + value |= 64; + break; + case Asn1UniversalTags.tagged: + value |= 128; + break; + } + } + return value; + } + + /// internal method + static int getHashCode(List? data) { + if (data == null) { + return 0; + } + int i = data.length; + int hc = i + 1; + while (--i >= 0) { + hc = (hc * 257).toSigned(32); + hc = (hc ^ data[i].toUnsigned(8)).toSigned(32); + } + return hc; + } + + /// internal method + static bool areEqual(List? a, List? b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + return haveSameContents(a, b); + } + + /// internal method + static bool haveSameContents(List a, List b) { + int i = a.length; + if (i != b.length) { + return false; + } + while (i != 0) { + --i; + if (a[i] != b[i]) { + return false; + } + } + return true; + } + + /// internal method + static List clone(List data) { + return List.generate(data.length, (int i) => data[i]); + } + + /// internal method + static void uInt32ToBe(int n, List bs, int off) { + bs[off] = (n >> 24).toUnsigned(8); + bs[off + 1] = (n >> 16).toUnsigned(8); + bs[off + 2] = (n >> 8).toUnsigned(8); + bs[off + 3] = n.toUnsigned(8); + } + + /// internal method + static int beToUInt32(List bs, int off) { + return bs[off].toUnsigned(8) << 24 | + bs[off + 1].toUnsigned(8) << 16 | + bs[off + 2].toUnsigned(8) << 8 | + bs[off + 3].toUnsigned(8); + } + + /// internal method + static int beToUInt64(List bs, int off) { + final int hi = beToUInt32(bs, off); + final int lo = beToUInt32(bs, off + 4); + return (hi.toUnsigned(64) << 32) | lo.toUnsigned(64); + } + + /// internal method + static void uInt64ToBe(int n, List bs, int off) { + uInt32ToBe((n >> 32).toUnsigned(32), bs, off); + uInt32ToBe(n.toUnsigned(32), bs, off + 4); + } + + /// internal method + static BigInt leToUInt32(List bs, int off) { + return BigInt.from( + bs[off].toUnsigned(32) | + bs[off + 1].toUnsigned(32) << 8 | + bs[off + 2].toUnsigned(32) << 16 | + bs[off + 3].toUnsigned(32) << 24, + ); + } + + /// internal method + static void uInt32ToLe(BigInt n, List bs, int off) { + bs[off] = n.toUnsigned(8).toInt(); + bs[off + 1] = (n >> 8).toUnsigned(8).toInt(); + bs[off + 2] = (n >> 16).toUnsigned(8).toInt(); + bs[off + 3] = (n >> 24).toUnsigned(8).toInt(); + } + + /// internal method + static Asn1 fromByteArray(List data) { + try { + return Asn1Stream(PdfStreamReader(data)).readAsn1()!; + } catch (e) { + throw Exception('Invalid entry'); + } + } +} + +/// internal class +abstract class Asn1Encode implements IAsn1 { + @override + Asn1? getAsn1(); + + //Implementation + /// internal method + List? getEncoded([String? encoding]) { + if (encoding == null) { + return (Asn1DerStream([])..writeObject(this)).stream; + } else { + if (encoding == Asn1.der) { + final DerStream stream = DerStream([])..writeObject(this); + return stream.stream; + } + return getEncoded(); + } + } + + /// internal method + Future?> getEncodedAsync([String? encoding]) async { + if (encoding == null) { + return (Asn1DerStream([])..writeObject(this)).stream; + } else { + if (encoding == Asn1.der) { + final DerStream stream = DerStream([])..writeObject(this); + return stream.stream; + } + return getEncoded(); + } + } + + /// internal method + List? getDerEncoded() { + return getEncoded(Asn1.der); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return getAsn1()!.getAsn1Hash(); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other); +} + +/// internal class +class Asn1EncodeCollection { + /// internal constructor + Asn1EncodeCollection([List? vector]) { + encodableObjects = []; + if (vector != null) { + add(vector); + } + } + + /// internal field + late List encodableObjects; + + //Properties + /// internal property + Asn1Encode? operator [](int index) => encodableObjects[index] as Asn1Encode?; + + /// internal property + int get count => encodableObjects.length; + + //Implementation + /// internal method + void add(List objs) { + for (final dynamic obj in objs) { + if (obj is Asn1Encode) { + encodableObjects.add(obj); + } + } + } +} + +/// internal class +class Asn1Octet extends Asn1 implements IAsn1Octet { + /// internal constructor + Asn1Octet(this.value) + : super([Asn1UniversalTags.octetString]); + + /// internal constructor + Asn1Octet.fromObject(Asn1Encode obj) { + value = obj.getEncoded(Asn1.der); + } + //Fields + /// internal field + List? value; + + /// internal property + IAsn1Octet get parser => this; + //Implementation + @override + PdfStreamReader getOctetStream() { + return PdfStreamReader(value); + } + + /// internal method + List? getOctets() { + return value; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return Asn1.getHashCode(getOctets()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerOctet) { + return Asn1.areEqual(getOctets(), asn1.getOctets()); + } else { + return false; + } + } + + @override + String toString() { + return value.toString(); + } + + /// internal method + List? asnEncode() { + return super.asn1Encode(value!); + } + + /// internal method + @override + void encode(DerStream stream) { + throw ArgumentError.value(stream, 'stream', 'Not Implemented'); + } + + //Static methods + /// internal method + static Asn1Octet? getOctetString(Asn1Tag tag, bool isExplicit) { + final Asn1? asn1 = tag.getObject(); + if (isExplicit || asn1 is Asn1Octet) { + return getOctetStringFromObject(asn1); + } + return BerOctet.getBerOctet(Asn1Sequence.getSequence(asn1)!); + } + + /// internal method + static Asn1Octet? getOctetStringFromObject(dynamic obj) { + if (obj == null || obj is Asn1Octet) { + return obj as Asn1Octet?; + } + if (obj is Asn1Tag) { + return getOctetStringFromObject(obj.getObject()); + } + throw ArgumentError.value(obj, 'obj', 'Invalid object entry'); + } +} + +/// internal class +abstract class Asn1Null extends Asn1 { + /// internal constructor + Asn1Null() : super([Asn1UniversalTags.nullValue]); + //Implementation + /// internal method + List toArray() { + return []; + } + + /// internal method + List? asnEncode() { + return super.asn1Encode(toArray()); + } + + @override + String toString() { + return Asn1.nullValue; + } + + @override + void encode(DerStream derOut) { + derOut.writeEncoded(5, toArray()); + } +} + +/// internal class +class Asn1Sequence extends Asn1 { + //Constructor + /// internal constructor + Asn1Sequence() + : super([ + Asn1UniversalTags.sequence, + Asn1UniversalTags.constructed, + ]) { + objects = []; + } + //Fields + /// internal field + List? objects; + Asn1SequenceHelper? _parser; + + /// internal field + int get count { + return objects!.length; + } + + /// internal property + IAsn1Collection get parser { + return _parser ??= Asn1SequenceHelper(this); + } + + /// internal property + IAsn1? operator [](int index) { + dynamic result; + if (index < objects!.length) { + result = objects![index]; + } else { + result = null; + } + return result as IAsn1?; + } + + //Implementation + /// internal method + static Asn1Sequence? getSequence(dynamic obj, [bool? explicitly]) { + Asn1Sequence? result; + if (explicitly == null) { + if (obj == null || obj is Asn1Sequence) { + result = obj as Asn1Sequence?; + } else if (obj is IAsn1Collection) { + result = Asn1Sequence.getSequence(obj.getAsn1()); + } else if (obj is List) { + result = Asn1Sequence.getSequence( + Asn1Stream(PdfStreamReader(obj)).readAsn1(), + ); + } else if (obj is Asn1Encode) { + final Asn1? primitive = obj.getAsn1(); + if (primitive != null && primitive is Asn1Sequence) { + return primitive; + } + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); + } + } else if (obj is Asn1Tag) { + final Asn1? inner = obj.getObject(); + if (explicitly) { + if (!obj.explicit!) { + throw ArgumentError.value( + explicitly, + 'explicitly', + 'Invalid entry in sequence', + ); + } + result = inner as Asn1Sequence?; + } else if (obj.explicit!) { + if (obj is DerTag) { + result = BerSequence.fromObject(inner); + } + result = DerSequence.fromObject(inner); + } else { + if (inner is Asn1Sequence) { + result = inner; + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); + } + } + } + return result; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + int hashCode = count; + for (final dynamic o in objects!) { + hashCode *= 17; + if (o == null) { + hashCode ^= DerNull().getAsn1Hash(); + } else { + hashCode ^= o.hashCode; + } + } + return hashCode; + } + + /// internal property + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object asn1) { + if (asn1 is Asn1Sequence) { + if (count != asn1.count) { + return false; + } + for (int i = 0; i < count; i++) { + final Asn1? o1 = getCurrentObject(objects![i]).getAsn1(); + final Asn1? o2 = getCurrentObject(asn1.objects![i]).getAsn1(); + if (o1 != o2) { + return false; + } + } + } else { + return false; + } + return true; + } + + /// internal method + Asn1Encode getCurrentObject(dynamic e) { + if (e != null && e is Asn1Encode) { + return e; + } else { + return DerNull(); + } + } + + @override + String toString([List? e]) { + if (e == null) { + return toString(objects); + } else { + String result = '['; + for (int i = 0; i < objects!.length; i++) { + result += objects![i].toString(); + if (i != objects!.length - 1) { + result += ', '; + } + } + result += ']'; + return result; + } + } + + /// internal method + List toArray() { + final List stream = []; + for (final dynamic obj in objects!) { + List? buffer; + if (obj is Asn1Integer) { + buffer = obj.asnEncode(); + } else if (obj is Asn1Boolean) { + buffer = obj.asnEncode(); + } else if (obj is Asn1Identifier) { + buffer = obj.asnEncode(); + } else if (obj is Asn1Null) { + buffer = obj.asnEncode(); + } else if (obj is Asn1Octet) { + buffer = obj.asnEncode(); + } else if (obj is Asn1Sequence) { + buffer = obj.asnEncode(); + } else if (obj is Algorithms) { + buffer = obj.asnEncode(); + } + if (buffer != null && buffer.isNotEmpty) { + stream.addAll(buffer); + } + } + return stream; + } + + @override + void encode(DerStream derOut) { + throw ArgumentError.value('Not Implemented'); + } + + /// internal method + List? asnEncode() { + return super.asn1Encode(toArray()); + } +} + +/// internal class +class Asn1SequenceCollection extends Asn1Encode { + /// internal constructor + Asn1SequenceCollection(Asn1Sequence sequence) { + id = DerObjectID.getID(sequence[0]); + value = (sequence[1]! as Asn1Tag).getObject(); + if (sequence.count == 3) { + attributes = sequence[2] as DerSet?; + } + } + + /// internal field + DerObjectID? id; + + /// internal field + Asn1? value; + + /// internal field + Asn1Set? attributes; + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection([ + id, + DerTag(0, value), + ]); + if (attributes != null) { + collection.encodableObjects.add(attributes); + } + return DerSequence(collection: collection); + } +} + +/// internal class +class Asn1SequenceHelper implements IAsn1Collection { + /// internal constructor + Asn1SequenceHelper(Asn1Sequence sequence) { + _sequence = sequence; + _max = sequence.count; + } + //Fields + Asn1Sequence? _sequence; + int? _max; + int? _index; + //Implementation + @override + IAsn1? readObject() { + if (_index == _max) { + return null; + } + final IAsn1? obj = _sequence![_index!]; + _index = _index! + 1; + if (obj is Asn1Sequence) { + return obj.parser; + } + if (obj is Asn1Set) { + return obj.parser; + } + return obj; + } + + @override + Asn1? getAsn1() { + return _sequence; + } +} + +/// internal class +class Asn1Set extends Asn1 { + /// internal constructor + Asn1Set([int? capacity]) { + objects = + capacity != null + ? List.generate(capacity, (dynamic i) => null) + : []; + } + //Fields + /// internal field + late List objects; + + //Properties + /// internal property + IAsn1SetHelper get parser { + return Asn1SetHelper(this); + } + + /// internal property + Asn1Encode? operator [](int index) => objects[index] as Asn1Encode?; + + //Implementation + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + int hc = objects.length; + for (final dynamic o in objects) { + hc *= 17; + if (o == null) { + hc ^= DerNull.value.getAsn1Hash(); + } else { + hc ^= o.hashCode; + } + } + return hc; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is Asn1Set) { + if (objects.length != asn1.objects.length) { + return false; + } + for (int i = 0; i < objects.length; i++) { + final Asn1? o1 = getCurrentSet(objects[i]).getAsn1(); + final Asn1? o2 = getCurrentSet(asn1.objects[i]).getAsn1(); + if (o1 != o2) { + return false; + } + } + } else { + return false; + } + return true; + } + + /// internal method + Asn1Encode getCurrentSet(dynamic e) { + if (e is Asn1Encode) { + return e; + } else { + return DerNull.value; + } + } + + /// internal method + bool lessThanOrEqual(List a, List b) { + final int len = min(a.length, b.length); + for (int i = 0; i != len; ++i) { + if (a[i] != b[i]) { + return a[i] < b[i]; + } + } + return len == a.length; + } + + /// internal method + void addObject(Asn1Encode? obj) { + objects.add(obj); + } + + @override + String toString() { + return objects.toString(); + } + + @override + void encode(DerStream derOut) { + throw ArgumentError.value('Not Implemented'); + } + + /// internal method + void sortObjects() { + if (objects.length > 1) { + bool swapped = true; + int lastSwap = objects.length - 1; + while (swapped) { + int index = 0; + int swapIndex = 0; + List? a = (objects[0] as Asn1Encode).getEncoded(); + swapped = false; + while (index != lastSwap) { + final List b = (objects[index + 1] as Asn1Encode).getEncoded()!; + if (lessThanOrEqual(a!, b)) { + a = b; + } else { + final dynamic o = objects[index]; + objects[index] = objects[index + 1]; + objects[index + 1] = o; + swapped = true; + swapIndex = index; + } + index++; + } + lastSwap = swapIndex; + } + } + } + + //static methods + /// internal method + static Asn1Set? getAsn1Set(dynamic obj, [bool? isExplicit]) { + Asn1Set? result; + if (isExplicit == null) { + if (obj == null || obj is Asn1Set) { + result = obj as Asn1Set?; + } else if (obj is IAsn1SetHelper) { + result = Asn1Set.getAsn1Set(obj.getAsn1()); + } else if (obj is List) { + result = Asn1Set.getAsn1Set( + Asn1Stream(PdfStreamReader(obj)).readAsn1(), + ); + } else if (obj is Asn1Encode) { + final Asn1? asn1 = obj.getAsn1(); + if (asn1 != null && asn1 is Asn1Set) { + result = asn1; + } + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); + } + } else if (obj is Asn1Tag) { + final Asn1? inner = obj.getObject(); + if (isExplicit) { + if (!obj.explicit!) { + throw ArgumentError.value(obj, 'obj', 'Tagged object is implicit.'); + } + result = (inner is Asn1Set) ? inner : null; + } else if (obj.explicit! && inner is Asn1Encode) { + result = DerSet(array: [inner]); + } else if (inner is Asn1Set) { + result = inner; + } else if (inner is Asn1Sequence) { + final Asn1EncodeCollection collection = Asn1EncodeCollection(); + // ignore: avoid_function_literals_in_foreach_calls + inner.objects!.toList().forEach( + (dynamic entry) => collection.encodableObjects.add(entry), + ); + result = DerSet(collection: collection, isSort: false); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); + } + } + return result; + } +} + +/// internal class +class Asn1SetHelper implements IAsn1SetHelper { + /// internal constructor + Asn1SetHelper(Asn1Set outer) { + _set = outer; + _max = outer.objects.length; + } + Asn1Set? _set; + int? _max; + int? _index; + @override + IAsn1? readObject() { + if (_index == _max) { + return null; + } else { + final Asn1Encode? obj = _set![_index!]; + _index = _index! + 1; + if (obj is Asn1Sequence) { + return obj.parser; + } + if (obj is Asn1Set) { + return obj.parser; + } + return obj; + } + } + + @override + Asn1? getAsn1() { + return _set; + } +} + +/// internal class +class Asn1Tag extends Asn1 implements IAsn1Tag { + /// internal constructor + Asn1Tag(int? tagNumber, this.object, [bool? isExplicit]) { + explicit = isExplicit ?? true; + _tagNumber = tagNumber; + } + //Fields + int? _tagNumber; + + /// internal field + bool? explicit; + + /// internal field + Asn1Encode? object; + //Properties + @override + int? get tagNumber { + return _tagNumber; + } + + //Static methods + /// internal method + static Asn1Tag? getTag(dynamic obj, [bool? isExplicit]) { + if (isExplicit != null && obj is Asn1Tag) { + if (isExplicit) { + return obj.getObject() as Asn1Tag?; + } + throw ArgumentError.value(obj, 'obj', 'Explicit tag is not used'); + } else { + if (obj == null || obj is Asn1Tag) { + return obj as Asn1Tag?; + } + throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); + } + } + + //Implementation + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is Asn1Tag) { + return _tagNumber == asn1._tagNumber && + explicit == asn1.explicit && + getObject() == asn1.getObject(); + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + int code = _tagNumber.hashCode; + if (object != null) { + code ^= object.hashCode; + } + return code; + } + + @override + String toString() { + return '[$_tagNumber]$object'; + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + throw ArgumentError.value(stream, 'stream', 'Not Implemented'); + } + + /// internal method + Asn1? getObject() { + if (object != null) { + return object!.getAsn1(); + } + return null; + } + + @override + IAsn1? getParser(int tagNumber, bool isExplicit) { + switch (tagNumber) { + case Asn1Tags.setTag: + return Asn1Set.getAsn1Set(this, isExplicit)!.parser; + case Asn1Tags.sequence: + return Asn1Sequence.getSequence(this, isExplicit)!.parser; + case Asn1Tags.octetString: + return Asn1Octet.getOctetString(this, isExplicit)!.parser; + } + if (isExplicit) { + return getObject(); + } + throw ArgumentError.value( + tagNumber, + 'tagNumber', + 'Implicit tagging is not supported', + ); + } +} + +/// internal class +class Asn1DerStream extends DerStream { + /// internal constructor + Asn1DerStream([List? stream]) { + if (stream != null) { + this.stream = stream; + } else { + this.stream = []; + } + } +} + +/// internal class +class Asn1Integer extends Asn1 { + /// internal constructor + Asn1Integer(this._value) + : super([Asn1UniversalTags.integer]); + + /// internal field + late final int _value; + + /// internal property + List _toArray() { + return _value < 255 ? [_value] : _getBytesFromLong(_value); + } + + /// internal method + List? asnEncode() { + return super.asn1Encode(_toArray()); + } + + @override + void encode(DerStream derOut) { + derOut.writeEncoded( + getTagValue([Asn1UniversalTags.integer]), + null, + ); + } + + List _getBytesFromLong(int value) { + final List bytes = []; + for (int i = 0; i < 8; i++) { + bytes.add((value >> (i * 8)) & 0xFF); + } + return bytes; + } +} + +/// internal class +class Asn1Boolean extends Asn1 { + /// internal constructor + Asn1Boolean(this._value) + : super([Asn1UniversalTags.boolean]); + + /// internal field + late final bool _value; + + /// internal method + List _toArray() { + return _value ? [0xff] : [0]; + } + + /// internal method + List? asnEncode() { + return super.asn1Encode(_toArray()); + } + + @override + void encode(DerStream derOut) { + derOut.writeEncoded( + getTagValue([Asn1UniversalTags.boolean]), + _toArray(), + ); + } +} + +/// internal class +class Asn1Identifier extends Asn1 { + /// internal constructor + Asn1Identifier(this._id) + : super([Asn1UniversalTags.objectIdentifier]); + + /// internal field + late final String _id; + + /// internal method + List _toArray() { + final List parts = _id.split('.'); + final int firstPart = int.parse(parts[0]); + final int secondPart = int.parse(parts[1]); + final List bytes = []; + _appendField(firstPart * 40 + secondPart, bytes); + for (int i = 2; i < parts.length; i++) { + final String part = parts[i]; + if (part.length < 18) { + _appendField(int.parse(part), bytes); + } else { + _appendFieldFromString(part, bytes); + } + } + return bytes; + } + + void _appendField(int value, List bytes) { + if (value >= (1 << 7)) { + if (value >= (1 << 14)) { + if (value >= (1 << 21)) { + if (value >= (1 << 28)) { + if (value >= (1 << 35)) { + if (value >= (1 << 42)) { + if (value >= (1 << 49)) { + if (value >= (1 << 56)) { + bytes.add(((value >> 56) | 0x80).toUnsigned(8)); + } + bytes.add(((value >> 49) | 0x80).toUnsigned(8)); + } + bytes.add(((value >> 42) | 0x80).toUnsigned(8)); + } + bytes.add(((value >> 35) | 0x80).toUnsigned(8)); + } + bytes.add(((value >> 28) | 0x80).toUnsigned(8)); + } + bytes.add(((value >> 21) | 0x80).toUnsigned(8)); + } + bytes.add(((value >> 14) | 0x80).toUnsigned(8)); + } + bytes.add(((value >> 7) | 0x80).toUnsigned(8)); + } + bytes.add((value & 0x7f).toUnsigned(8)); + } + + void _appendFieldFromString(String value, List bytes) { + int byteCount; + byteCount = ((utf8.encode(value).length) + 6) ~/ 7; + if (byteCount == 0) { + bytes.add(0); + } else { + int tmpValue = int.parse(value); + final List tmp = List.filled(byteCount, 0); + for (int i = byteCount - 1; i >= 0; i--) { + tmp[i] = (tmpValue & 0x7F) | 0x80; + tmpValue = tmpValue >> 7; + } + tmp[byteCount - 1] &= 0x7F; + bytes.addAll(tmp); + } + } + + /// internal method + List? asnEncode() { + return super.asn1Encode(_toArray()); + } + + @override + void encode(DerStream derOut) { + derOut.writeEncoded( + getTagValue([Asn1UniversalTags.objectIdentifier]), + _toArray(), + ); + } +} + +/// internal class +class GeneralizedTime extends Asn1 { + /// internal constructor + GeneralizedTime(List bytes) { + time = utf8.decode(bytes); + } + //Fields + /// internal field + late String time; + //Implementation + /// internal method + DateTime? toDateTime() { + return DateTime.tryParse(time); + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.generalizedTime, utf8.encode(time)); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1Object) { + throw ArgumentError.value('Not implemented'); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return time.hashCode; + } +} + +/// internal class +class Asn1Tags { + /// internal field + static const int boolean = 0x01; + + /// internal field + static const int integer = 0x02; + + /// internal field + static const int bitString = 0x03; + + /// internal field + static const int octetString = 0x04; + + /// internal field + static const int nullValue = 0x05; + + /// internal field + static const int objectIdentifier = 0x06; + + /// internal field + static const int enumerated = 0x0a; + + /// internal field + static const int sequence = 0x10; + + /// internal field + static const int setTag = 0x11; + + /// internal field + static const int printableString = 0x13; + + /// internal field + static const int teleText = 0x14; + + /// internal field + static const int asciiString = 0x16; + + /// internal field + static const int utcTime = 0x17; + + /// internal field + static const int generalizedTime = 0x18; + + /// internal field + static const int bmpString = 0x1e; + + /// internal field + static const int utf8String = 0x0c; + + /// internal field + static const int constructed = 0x20; + + /// internal field + static const int tagged = 0x80; +} + +enum Asn1UniversalTags { + reservedBER, + boolean, + integer, + bitString, + octetString, + nullValue, + objectIdentifier, + objectDescriptor, + externalValue, + real, + enumerated, + embeddedPDV, + utf8String, + relativeOid, + sequence, + setValue, + numericString, + printableString, + teletexString, + videotexString, + ia5String, + utfTime, + generalizedTime, + graphicsString, + visibleString, + generalString, + universalString, + characterString, + bmpString, + constructed, + application, + tagged, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_parser.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_parser.dart index b5d3c707a..ee6dab4e1 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_parser.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_parser.dart @@ -1,167 +1,167 @@ -import '../../../io/stream_reader.dart'; -import 'asn1.dart'; -import 'asn1_stream.dart'; -import 'ber.dart'; -import 'der.dart'; - -/// internal class -class Asn1Parser { - /// internal constructor - Asn1Parser(PdfStreamReader stream, [int? limit]) { - _stream = stream; - _limit = limit ?? Asn1Stream.getLimit(stream); - _buffers = List>.generate(16, (int i) => []); - } - - //Fields - PdfStreamReader? _stream; - int? _limit; - List>? _buffers; - - //Implementation - /// internal method - IAsn1 readImplicit(bool? constructed, int tagNumber) { - if (_stream is Asn1LengthStream) { - if (!constructed!) { - throw ArgumentError.value('Invalid length specified'); - } - return readIndefinite(tagNumber); - } - if (constructed!) { - switch (tagNumber) { - case Asn1Tags.setTag: - return DerSetHelper(this); - case Asn1Tags.sequence: - return DerSequenceHelper(this); - case Asn1Tags.octetString: - return BerOctetHelper(this); - } - } else { - switch (tagNumber) { - case Asn1Tags.setTag: - throw ArgumentError.value( - tagNumber, - 'tagNumber', - 'Constructed encoding is not used in the set', - ); - case Asn1Tags.sequence: - throw ArgumentError.value( - tagNumber, - 'tagNumber', - 'Constructed encoding is not used in the sequence', - ); - case Asn1Tags.octetString: - return DerOctetHelper(_stream as Asn1StreamHelper?); - } - } - throw ArgumentError.value( - tagNumber, - 'tagNumber', - 'Implicit tagging is not supported', - ); - } - - /// internal method - Asn1 readTaggedObject(bool constructed, int? tagNumber) { - if (!constructed) { - final Asn1StreamHelper stream = _stream! as Asn1StreamHelper; - return DerTag(tagNumber, DerOctet(stream.toArray()), false); - } - final Asn1EncodeCollection collection = readCollection(); - if (_stream is Asn1LengthStream) { - return collection.count == 1 - ? DerTag(tagNumber, collection[0], true) - : DerTag(tagNumber, BerSequence.fromCollection(collection), false); - } - return collection.count == 1 - ? DerTag(tagNumber, collection[0], true) - : DerTag(tagNumber, DerSequence.fromCollection(collection), false); - } - - /// internal method - IAsn1 readIndefinite(int tagValue) { - switch (tagValue) { - case Asn1Tags.octetString: - return BerOctetHelper(this); - case Asn1Tags.sequence: - return BerSequenceHelper(this); - default: - throw ArgumentError.value( - tagValue, - 'tagValue', - 'Invalid entry in sequence', - ); - } - } - - /// internal method - void setEndOfFile(bool enabled) { - if (_stream is Asn1LengthStream) { - (_stream! as Asn1LengthStream).setEndOfFileOnStart(enabled); - } - } - - /// internal method - Asn1EncodeCollection readCollection() { - final Asn1EncodeCollection collection = Asn1EncodeCollection(); - IAsn1? obj; - while ((obj = readObject()) != null) { - collection.encodableObjects.add(obj!.getAsn1()); - } - return collection; - } - - /// internal method - IAsn1? readObject() { - final int? tag = _stream!.readByte(); - if (tag == -1) { - return null; - } - setEndOfFile(false); - final int tagNumber = Asn1Stream.readTagNumber(_stream, tag!); - final bool isConstructed = (tag & Asn1Tags.constructed) != 0; - final int length = Asn1Stream.getLength(_stream!, _limit); - if (length < 0) { - if (!isConstructed) { - throw ArgumentError.value(length, 'length', 'Invalid length specified'); - } - final Asn1LengthStream stream = Asn1LengthStream(_stream, _limit); - final Asn1Parser helper = Asn1Parser(stream, _limit); - if ((tag & Asn1Tags.tagged) != 0) { - return BerTagHelper(true, tagNumber, helper); - } - return helper.readIndefinite(tagNumber); - } else { - final Asn1StreamHelper stream = Asn1StreamHelper(_stream, length); - if ((tag & Asn1Tags.tagged) != 0) { - return BerTagHelper( - isConstructed, - tagNumber, - Asn1Parser(stream, Asn1Stream.getLimit(stream)), - ); - } - if (isConstructed) { - switch (tagNumber) { - case Asn1Tags.octetString: - return BerOctetHelper( - Asn1Parser(stream, Asn1Stream.getLimit(stream)), - ); - case Asn1Tags.sequence: - return DerSequenceHelper( - Asn1Parser(stream, Asn1Stream.getLimit(stream)), - ); - case Asn1Tags.setTag: - return DerSetHelper( - Asn1Parser(stream, Asn1Stream.getLimit(stream)), - ); - default: - return null; - } - } - if (tagNumber == Asn1Tags.octetString) { - return DerOctetHelper(stream); - } - return Asn1Stream.getPrimitiveObject(tagNumber, stream, _buffers); - } - } -} +import '../../../io/stream_reader.dart'; +import 'asn1.dart'; +import 'asn1_stream.dart'; +import 'ber.dart'; +import 'der.dart'; + +/// internal class +class Asn1Parser { + /// internal constructor + Asn1Parser(PdfStreamReader stream, [int? limit]) { + _stream = stream; + _limit = limit ?? Asn1Stream.getLimit(stream); + _buffers = List>.generate(16, (int i) => []); + } + + //Fields + PdfStreamReader? _stream; + int? _limit; + List>? _buffers; + + //Implementation + /// internal method + IAsn1 readImplicit(bool? constructed, int tagNumber) { + if (_stream is Asn1LengthStream) { + if (!constructed!) { + throw ArgumentError.value('Invalid length specified'); + } + return readIndefinite(tagNumber); + } + if (constructed!) { + switch (tagNumber) { + case Asn1Tags.setTag: + return DerSetHelper(this); + case Asn1Tags.sequence: + return DerSequenceHelper(this); + case Asn1Tags.octetString: + return BerOctetHelper(this); + } + } else { + switch (tagNumber) { + case Asn1Tags.setTag: + throw ArgumentError.value( + tagNumber, + 'tagNumber', + 'Constructed encoding is not used in the set', + ); + case Asn1Tags.sequence: + throw ArgumentError.value( + tagNumber, + 'tagNumber', + 'Constructed encoding is not used in the sequence', + ); + case Asn1Tags.octetString: + return DerOctetHelper(_stream as Asn1StreamHelper?); + } + } + throw ArgumentError.value( + tagNumber, + 'tagNumber', + 'Implicit tagging is not supported', + ); + } + + /// internal method + Asn1 readTaggedObject(bool constructed, int? tagNumber) { + if (!constructed) { + final Asn1StreamHelper stream = _stream! as Asn1StreamHelper; + return DerTag(tagNumber, DerOctet(stream.toArray()), false); + } + final Asn1EncodeCollection collection = readCollection(); + if (_stream is Asn1LengthStream) { + return collection.count == 1 + ? DerTag(tagNumber, collection[0], true) + : DerTag(tagNumber, BerSequence.fromCollection(collection), false); + } + return collection.count == 1 + ? DerTag(tagNumber, collection[0], true) + : DerTag(tagNumber, DerSequence.fromCollection(collection), false); + } + + /// internal method + IAsn1 readIndefinite(int tagValue) { + switch (tagValue) { + case Asn1Tags.octetString: + return BerOctetHelper(this); + case Asn1Tags.sequence: + return BerSequenceHelper(this); + default: + throw ArgumentError.value( + tagValue, + 'tagValue', + 'Invalid entry in sequence', + ); + } + } + + /// internal method + void setEndOfFile(bool enabled) { + if (_stream is Asn1LengthStream) { + (_stream! as Asn1LengthStream).setEndOfFileOnStart(enabled); + } + } + + /// internal method + Asn1EncodeCollection readCollection() { + final Asn1EncodeCollection collection = Asn1EncodeCollection(); + IAsn1? obj; + while ((obj = readObject()) != null) { + collection.encodableObjects.add(obj!.getAsn1()); + } + return collection; + } + + /// internal method + IAsn1? readObject() { + final int? tag = _stream!.readByte(); + if (tag == -1) { + return null; + } + setEndOfFile(false); + final int tagNumber = Asn1Stream.readTagNumber(_stream, tag!); + final bool isConstructed = (tag & Asn1Tags.constructed) != 0; + final int length = Asn1Stream.getLength(_stream!, _limit); + if (length < 0) { + if (!isConstructed) { + throw ArgumentError.value(length, 'length', 'Invalid length specified'); + } + final Asn1LengthStream stream = Asn1LengthStream(_stream, _limit); + final Asn1Parser helper = Asn1Parser(stream, _limit); + if ((tag & Asn1Tags.tagged) != 0) { + return BerTagHelper(true, tagNumber, helper); + } + return helper.readIndefinite(tagNumber); + } else { + final Asn1StreamHelper stream = Asn1StreamHelper(_stream, length); + if ((tag & Asn1Tags.tagged) != 0) { + return BerTagHelper( + isConstructed, + tagNumber, + Asn1Parser(stream, Asn1Stream.getLimit(stream)), + ); + } + if (isConstructed) { + switch (tagNumber) { + case Asn1Tags.octetString: + return BerOctetHelper( + Asn1Parser(stream, Asn1Stream.getLimit(stream)), + ); + case Asn1Tags.sequence: + return DerSequenceHelper( + Asn1Parser(stream, Asn1Stream.getLimit(stream)), + ); + case Asn1Tags.setTag: + return DerSetHelper( + Asn1Parser(stream, Asn1Stream.getLimit(stream)), + ); + default: + return null; + } + } + if (tagNumber == Asn1Tags.octetString) { + return DerOctetHelper(stream); + } + return Asn1Stream.getPrimitiveObject(tagNumber, stream, _buffers); + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_stream.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_stream.dart index 4e53adb17..35c8335d9 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_stream.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/asn1_stream.dart @@ -1,463 +1,463 @@ -import 'dart:convert'; -import 'dart:math'; - -import '../../../io/stream_reader.dart'; -import 'asn1.dart'; -import 'asn1_parser.dart'; -import 'ber.dart'; -import 'der.dart'; - -/// internal class -class Asn1Stream { - /// internal constructor - Asn1Stream(PdfStreamReader stream, [int? limit]) { - _stream = stream; - _limit = limit ?? getLimit(stream); - _buffers = List>.generate(16, (int i) => []); - } - int? _limit; - List>? _buffers; - PdfStreamReader? _stream; - - /// internal method - static int? getLimit(PdfStreamReader input) { - if (input is Asn1BaseStream) { - return input.remaining; - } else { - return input.length! - input.position; - } - } - - /// internal method - static Asn1? getPrimitiveObject( - int tagNumber, - Asn1StreamHelper stream, - List>? buffers, - ) { - switch (tagNumber) { - case Asn1Tags.boolean: - return DerBoolean.fromBytes(getBytes(stream, buffers!)); - case Asn1Tags.enumerated: - return DerCatalogue(getBytes(stream, buffers!)); - case Asn1Tags.objectIdentifier: - return DerObjectID.fromOctetString(getBytes(stream, buffers!)); - } - final List bytes = stream.toArray(); - switch (tagNumber) { - case Asn1Tags.bitString: - return DerBitString.fromAsn1Octets(bytes); - case Asn1Tags.bmpString: - return DerBmpString(bytes); - case Asn1Tags.generalizedTime: - return GeneralizedTime(bytes); - case Asn1Tags.asciiString: - return DerAsciiString.fromBytes(bytes); - case Asn1Tags.integer: - return DerInteger(bytes); - case Asn1Tags.nullValue: - return DerNull.value; - case Asn1Tags.octetString: - return DerOctet(bytes); - case Asn1Tags.printableString: - return DerPrintableString(utf8.decode(bytes)); - case Asn1Tags.teleText: - return DerTeleText(String.fromCharCodes(bytes)); - case Asn1Tags.utcTime: - return DerUtcTime(bytes); - case Asn1Tags.utf8String: - return DerUtf8String(utf8.decode(bytes)); - } - return null; - } - - /// internal method - static List getBytes(Asn1StreamHelper stream, List> buffers) { - final int length = stream.remaining; - if (length >= buffers.length) { - stream.toArray(); - } - List bytes = buffers[length]; - if (bytes.isEmpty) { - bytes = buffers[length] = List.generate(length, (int i) => 0); - } - stream.readAll(bytes); - return bytes; - } - - /// internal method - static int readTagNumber(PdfStreamReader? stream, int tagNumber) { - int result = tagNumber & 0x1f; - if (result == 0x1f) { - result = 0; - int b = stream!.readByte()!; - if ((b & 0x7f) == 0) { - throw Exception('Invalid tag number specified'); - } - while ((b >= 0) && ((b & 0x80) != 0)) { - result |= b & 0x7f; - result <<= 7; - b = stream.readByte()!; - } - if (b < 0) { - throw Exception('End of file detected'); - } - result |= b & 0x7f; - } - return result; - } - - /// internal method - static int getLength(PdfStreamReader stream, int? limit) { - int length = stream.readByte()!; - if (length < 0) { - throw Exception('End of file detected'); - } - if (length == 0x80) { - return -1; - } - if (length > 127) { - final int size = length & 0x7f; - if (size > 4) { - throw Exception('Invalid length detected: $size'); - } - length = 0; - for (int i = 0; i < size; i++) { - final int next = stream.readByte()!; - if (next < 0) { - throw Exception('End of file detected'); - } - length = (length << 8) + next; - } - if (length < 0) { - throw Exception('Invalid length or corrupted input stream detected'); - } - if (length >= limit!) { - throw Exception('Out of bound or corrupted stream detected'); - } - } - return length; - } - - /// internal method - Asn1? buildObject(int tag, int tagNumber, int length) { - final bool isConstructed = (tag & Asn1Tags.constructed) != 0; - final Asn1StreamHelper stream = Asn1StreamHelper(_stream, length); - if ((tag & Asn1Tags.tagged) != 0) { - return Asn1Parser(stream).readTaggedObject(isConstructed, tagNumber); - } - if (isConstructed) { - switch (tagNumber) { - case Asn1Tags.octetString: - return BerOctet( - getBytesfromAsn1EncodeCollection(getDerEncodableCollection(stream)), - ); - case Asn1Tags.sequence: - return createDerSequence(stream); - case Asn1Tags.setTag: - return createDerSet(stream); - } - } - return getPrimitiveObject(tagNumber, stream, _buffers); - } - - /// internal method - Asn1EncodeCollection getEncodableCollection() { - final Asn1EncodeCollection objects = Asn1EncodeCollection(); - Asn1? asn1Object; - while ((asn1Object = readAsn1()) != null) { - objects.encodableObjects.add(asn1Object); - } - return objects; - } - - /// internal method - Asn1? readAsn1() { - final int tag = _stream!.readByte()!; - if (tag > 0) { - final int tagNumber = readTagNumber(_stream, tag); - final bool isConstructed = (tag & Asn1Tags.constructed) != 0; - final int length = getLength(_stream!, _limit); - if (length < 0) { - if (!isConstructed) { - throw ArgumentError.value( - length, - 'length', - 'Encodeing length is invalid', - ); - } - final Asn1Parser sp = Asn1Parser( - Asn1LengthStream(_stream, _limit), - _limit, - ); - if ((tag & Asn1Tags.tagged) != 0) { - return BerTagHelper(true, tagNumber, sp).getAsn1(); - } - switch (tagNumber) { - case Asn1Tags.octetString: - return BerOctetHelper(sp).getAsn1(); - case Asn1Tags.sequence: - return BerSequenceHelper(sp).getAsn1(); - default: - throw ArgumentError.value( - tagNumber, - 'tag', - 'Invalid object in the sequence', - ); - } - } else { - return buildObject(tag, tagNumber, length); - } - } else if (tag < 0) { - return null; - } else if (tag == 0) { - throw ArgumentError.value(tag, 'tag', 'End of contents is invalid'); - } - return null; - } - - /// internal method - List getBytesfromAsn1EncodeCollection(Asn1EncodeCollection octets) { - final List result = []; - for (int i = 0; i < octets.count; i++) { - final DerOctet o = octets[i]! as DerOctet; - result.addAll(o.getOctets()!); - } - return result; - } - - /// internal method - Asn1EncodeCollection getDerEncodableCollection(Asn1StreamHelper stream) { - return Asn1Stream(stream).getEncodableCollection(); - } - - /// internal method - DerSequence createDerSequence(Asn1StreamHelper stream) { - return DerSequence(collection: getDerEncodableCollection(stream)); - } - - /// internal method - DerSet createDerSet(Asn1StreamHelper stream) { - return DerSet(collection: getDerEncodableCollection(stream), isSort: false); - } -} - -/// internal class -class Asn1BaseStream extends PdfStreamReader { - /// internal constructor - Asn1BaseStream(this.input, this.limit); - - /// internal field - int? limit; - - /// internal field - late bool closed; - - /// internal field - PdfStreamReader? input; - - /// internal property - int? get remaining => limit; - - /// internal property - bool get canRead => !closed; - - /// internal property - bool get canSeek => false; - - /// internal property - bool get canWrite => false; - - /// internal method - void close() { - closed = true; - } - - /// internal method - void setParentEndOfFileDetect(bool isDetect) { - if (input is Asn1LengthStream) { - (input! as Asn1LengthStream).setEndOfFileOnStart(isDetect); - } - } - - @override - // ignore: avoid_renaming_method_parameters - int read(List buffer, int offset, int count) { - int pos = offset; - try { - final int end = offset + count; - while (pos < end) { - final int b = input!.readByte()!; - if (b == -1) { - break; - } - buffer[pos++] = b; - } - } catch (e) { - if (pos == offset) { - throw Exception('End of stream'); - } - } - return pos - offset; - } -} - -/// internal class -class Asn1StreamHelper extends Asn1BaseStream { - /// internal constructor - Asn1StreamHelper(PdfStreamReader? stream, int length) - : super(stream, length) { - if (length < 0) { - throw Exception('Invalid length specified.'); - } - _remaining = length; - if (length == 0) { - setParentEndOfFileDetect(true); - } - } - - late int _remaining; - @override - int get remaining => _remaining; - - @override - int readByte() { - if (_remaining == 0) { - return -1; - } - final int result = input!.readByte()!; - if (result < 0) { - throw ArgumentError.value(result, 'result', 'Invalid length in bytes'); - } - _remaining -= 1; - if (_remaining == 0) { - setParentEndOfFileDetect(true); - } - return result; - } - - /// internal method - @override - int read(List bytes, int offset, int length) { - if (remaining == 0) { - return 0; - } - final int count = super.read(bytes, offset, min(length, _remaining)); - if (count < 1) { - throw ArgumentError.value(count, 'count', 'Object truncated'); - } - if ((_remaining -= count) == 0) { - setParentEndOfFileDetect(true); - } - return count; - } - - /// internal method - List toArray() { - if (_remaining == 0) { - return []; - } - final List bytes = List.generate(_remaining, (int i) => 0); - if ((_remaining -= readData(bytes, 0, bytes.length)) != 0) { - throw ArgumentError.value(bytes, 'bytes', 'Object truncated'); - } - setParentEndOfFileDetect(true); - return bytes; - } - - /// internal method - void readAll(List bytes) { - if (_remaining != bytes.length) { - throw ArgumentError.value(bytes, 'bytes', 'Invalid length in bytes'); - } - if ((_remaining -= readData(bytes, 0, bytes.length)) != 0) { - throw ArgumentError.value(bytes, 'bytes', 'Object truncated'); - } - setParentEndOfFileDetect(true); - } - - /// internal method - int readData(List bytes, int offset, int length) { - int total = 0; - while (total < length) { - final int count = read(bytes, offset + total, length - total); - if (count < 1) { - break; - } - total += count; - } - return total; - } -} - -/// internal class -class Asn1LengthStream extends Asn1BaseStream { - /// internal constructor - Asn1LengthStream(super.stream, super.limit) { - byte = requireByte(); - checkEndOfFile(); - } - - /// internal field - int? byte; - - /// internal field - bool isEndOfFile = true; - - /// internal method - int requireByte() { - final int value = input!.readByte()!; - if (value < 0) { - throw ArgumentError.value(value, 'value', 'Invalid data in stream'); - } - return value; - } - - /// internal method - void setEndOfFileOnStart(bool isEOF) { - isEndOfFile = isEOF; - if (isEndOfFile) { - checkEndOfFile(); - } - } - - /// internal method - bool checkEndOfFile() { - if (byte == 0x00) { - final int extra = requireByte(); - if (extra != 0) { - throw Exception('Invalid content'); - } - byte = -1; - setParentEndOfFileDetect(true); - return true; - } - return byte! < 0; - } - - @override - int? readByte() { - if (isEndOfFile && checkEndOfFile()) { - return -1; - } - final int? result = byte; - byte = requireByte(); - return result; - } - - @override - int read(List buffer, int offset, int count) { - if (isEndOfFile || count <= 1) { - return super.read(buffer, offset, count); - } - if (byte! < 0) { - return 0; - } - final int numRead = input!.read(buffer, offset + 1, count - 1)!; - if (numRead <= 0) { - throw Exception(); - } - buffer[offset] = byte!; - byte = requireByte(); - return numRead + 1; - } -} +import 'dart:convert'; +import 'dart:math'; + +import '../../../io/stream_reader.dart'; +import 'asn1.dart'; +import 'asn1_parser.dart'; +import 'ber.dart'; +import 'der.dart'; + +/// internal class +class Asn1Stream { + /// internal constructor + Asn1Stream(PdfStreamReader stream, [int? limit]) { + _stream = stream; + _limit = limit ?? getLimit(stream); + _buffers = List>.generate(16, (int i) => []); + } + int? _limit; + List>? _buffers; + PdfStreamReader? _stream; + + /// internal method + static int? getLimit(PdfStreamReader input) { + if (input is Asn1BaseStream) { + return input.remaining; + } else { + return input.length! - input.position; + } + } + + /// internal method + static Asn1? getPrimitiveObject( + int tagNumber, + Asn1StreamHelper stream, + List>? buffers, + ) { + switch (tagNumber) { + case Asn1Tags.boolean: + return DerBoolean.fromBytes(getBytes(stream, buffers!)); + case Asn1Tags.enumerated: + return DerCatalogue(getBytes(stream, buffers!)); + case Asn1Tags.objectIdentifier: + return DerObjectID.fromOctetString(getBytes(stream, buffers!)); + } + final List bytes = stream.toArray(); + switch (tagNumber) { + case Asn1Tags.bitString: + return DerBitString.fromAsn1Octets(bytes); + case Asn1Tags.bmpString: + return DerBmpString(bytes); + case Asn1Tags.generalizedTime: + return GeneralizedTime(bytes); + case Asn1Tags.asciiString: + return DerAsciiString.fromBytes(bytes); + case Asn1Tags.integer: + return DerInteger(bytes); + case Asn1Tags.nullValue: + return DerNull.value; + case Asn1Tags.octetString: + return DerOctet(bytes); + case Asn1Tags.printableString: + return DerPrintableString(utf8.decode(bytes)); + case Asn1Tags.teleText: + return DerTeleText(String.fromCharCodes(bytes)); + case Asn1Tags.utcTime: + return DerUtcTime(bytes); + case Asn1Tags.utf8String: + return DerUtf8String(utf8.decode(bytes)); + } + return null; + } + + /// internal method + static List getBytes(Asn1StreamHelper stream, List> buffers) { + final int length = stream.remaining; + if (length >= buffers.length) { + stream.toArray(); + } + List bytes = buffers[length]; + if (bytes.isEmpty) { + bytes = buffers[length] = List.generate(length, (int i) => 0); + } + stream.readAll(bytes); + return bytes; + } + + /// internal method + static int readTagNumber(PdfStreamReader? stream, int tagNumber) { + int result = tagNumber & 0x1f; + if (result == 0x1f) { + result = 0; + int b = stream!.readByte()!; + if ((b & 0x7f) == 0) { + throw Exception('Invalid tag number specified'); + } + while ((b >= 0) && ((b & 0x80) != 0)) { + result |= b & 0x7f; + result <<= 7; + b = stream.readByte()!; + } + if (b < 0) { + throw Exception('End of file detected'); + } + result |= b & 0x7f; + } + return result; + } + + /// internal method + static int getLength(PdfStreamReader stream, int? limit) { + int length = stream.readByte()!; + if (length < 0) { + throw Exception('End of file detected'); + } + if (length == 0x80) { + return -1; + } + if (length > 127) { + final int size = length & 0x7f; + if (size > 4) { + throw Exception('Invalid length detected: $size'); + } + length = 0; + for (int i = 0; i < size; i++) { + final int next = stream.readByte()!; + if (next < 0) { + throw Exception('End of file detected'); + } + length = (length << 8) + next; + } + if (length < 0) { + throw Exception('Invalid length or corrupted input stream detected'); + } + if (length >= limit!) { + throw Exception('Out of bound or corrupted stream detected'); + } + } + return length; + } + + /// internal method + Asn1? buildObject(int tag, int tagNumber, int length) { + final bool isConstructed = (tag & Asn1Tags.constructed) != 0; + final Asn1StreamHelper stream = Asn1StreamHelper(_stream, length); + if ((tag & Asn1Tags.tagged) != 0) { + return Asn1Parser(stream).readTaggedObject(isConstructed, tagNumber); + } + if (isConstructed) { + switch (tagNumber) { + case Asn1Tags.octetString: + return BerOctet( + getBytesfromAsn1EncodeCollection(getDerEncodableCollection(stream)), + ); + case Asn1Tags.sequence: + return createDerSequence(stream); + case Asn1Tags.setTag: + return createDerSet(stream); + } + } + return getPrimitiveObject(tagNumber, stream, _buffers); + } + + /// internal method + Asn1EncodeCollection getEncodableCollection() { + final Asn1EncodeCollection objects = Asn1EncodeCollection(); + Asn1? asn1Object; + while ((asn1Object = readAsn1()) != null) { + objects.encodableObjects.add(asn1Object); + } + return objects; + } + + /// internal method + Asn1? readAsn1() { + final int tag = _stream!.readByte()!; + if (tag > 0) { + final int tagNumber = readTagNumber(_stream, tag); + final bool isConstructed = (tag & Asn1Tags.constructed) != 0; + final int length = getLength(_stream!, _limit); + if (length < 0) { + if (!isConstructed) { + throw ArgumentError.value( + length, + 'length', + 'Encodeing length is invalid', + ); + } + final Asn1Parser sp = Asn1Parser( + Asn1LengthStream(_stream, _limit), + _limit, + ); + if ((tag & Asn1Tags.tagged) != 0) { + return BerTagHelper(true, tagNumber, sp).getAsn1(); + } + switch (tagNumber) { + case Asn1Tags.octetString: + return BerOctetHelper(sp).getAsn1(); + case Asn1Tags.sequence: + return BerSequenceHelper(sp).getAsn1(); + default: + throw ArgumentError.value( + tagNumber, + 'tag', + 'Invalid object in the sequence', + ); + } + } else { + return buildObject(tag, tagNumber, length); + } + } else if (tag < 0) { + return null; + } else if (tag == 0) { + throw ArgumentError.value(tag, 'tag', 'End of contents is invalid'); + } + return null; + } + + /// internal method + List getBytesfromAsn1EncodeCollection(Asn1EncodeCollection octets) { + final List result = []; + for (int i = 0; i < octets.count; i++) { + final DerOctet o = octets[i]! as DerOctet; + result.addAll(o.getOctets()!); + } + return result; + } + + /// internal method + Asn1EncodeCollection getDerEncodableCollection(Asn1StreamHelper stream) { + return Asn1Stream(stream).getEncodableCollection(); + } + + /// internal method + DerSequence createDerSequence(Asn1StreamHelper stream) { + return DerSequence(collection: getDerEncodableCollection(stream)); + } + + /// internal method + DerSet createDerSet(Asn1StreamHelper stream) { + return DerSet(collection: getDerEncodableCollection(stream), isSort: false); + } +} + +/// internal class +class Asn1BaseStream extends PdfStreamReader { + /// internal constructor + Asn1BaseStream(this.input, this.limit); + + /// internal field + int? limit; + + /// internal field + late bool closed; + + /// internal field + PdfStreamReader? input; + + /// internal property + int? get remaining => limit; + + /// internal property + bool get canRead => !closed; + + /// internal property + bool get canSeek => false; + + /// internal property + bool get canWrite => false; + + /// internal method + void close() { + closed = true; + } + + /// internal method + void setParentEndOfFileDetect(bool isDetect) { + if (input is Asn1LengthStream) { + (input! as Asn1LengthStream).setEndOfFileOnStart(isDetect); + } + } + + @override + // ignore: avoid_renaming_method_parameters + int read(List buffer, int offset, int count) { + int pos = offset; + try { + final int end = offset + count; + while (pos < end) { + final int b = input!.readByte()!; + if (b == -1) { + break; + } + buffer[pos++] = b; + } + } catch (e) { + if (pos == offset) { + throw Exception('End of stream'); + } + } + return pos - offset; + } +} + +/// internal class +class Asn1StreamHelper extends Asn1BaseStream { + /// internal constructor + Asn1StreamHelper(PdfStreamReader? stream, int length) + : super(stream, length) { + if (length < 0) { + throw Exception('Invalid length specified.'); + } + _remaining = length; + if (length == 0) { + setParentEndOfFileDetect(true); + } + } + + late int _remaining; + @override + int get remaining => _remaining; + + @override + int readByte() { + if (_remaining == 0) { + return -1; + } + final int result = input!.readByte()!; + if (result < 0) { + throw ArgumentError.value(result, 'result', 'Invalid length in bytes'); + } + _remaining -= 1; + if (_remaining == 0) { + setParentEndOfFileDetect(true); + } + return result; + } + + /// internal method + @override + int read(List bytes, int offset, int length) { + if (remaining == 0) { + return 0; + } + final int count = super.read(bytes, offset, min(length, _remaining)); + if (count < 1) { + throw ArgumentError.value(count, 'count', 'Object truncated'); + } + if ((_remaining -= count) == 0) { + setParentEndOfFileDetect(true); + } + return count; + } + + /// internal method + List toArray() { + if (_remaining == 0) { + return []; + } + final List bytes = List.generate(_remaining, (int i) => 0); + if ((_remaining -= readData(bytes, 0, bytes.length)) != 0) { + throw ArgumentError.value(bytes, 'bytes', 'Object truncated'); + } + setParentEndOfFileDetect(true); + return bytes; + } + + /// internal method + void readAll(List bytes) { + if (_remaining != bytes.length) { + throw ArgumentError.value(bytes, 'bytes', 'Invalid length in bytes'); + } + if ((_remaining -= readData(bytes, 0, bytes.length)) != 0) { + throw ArgumentError.value(bytes, 'bytes', 'Object truncated'); + } + setParentEndOfFileDetect(true); + } + + /// internal method + int readData(List bytes, int offset, int length) { + int total = 0; + while (total < length) { + final int count = read(bytes, offset + total, length - total); + if (count < 1) { + break; + } + total += count; + } + return total; + } +} + +/// internal class +class Asn1LengthStream extends Asn1BaseStream { + /// internal constructor + Asn1LengthStream(super.stream, super.limit) { + byte = requireByte(); + checkEndOfFile(); + } + + /// internal field + int? byte; + + /// internal field + bool isEndOfFile = true; + + /// internal method + int requireByte() { + final int value = input!.readByte()!; + if (value < 0) { + throw ArgumentError.value(value, 'value', 'Invalid data in stream'); + } + return value; + } + + /// internal method + void setEndOfFileOnStart(bool isEOF) { + isEndOfFile = isEOF; + if (isEndOfFile) { + checkEndOfFile(); + } + } + + /// internal method + bool checkEndOfFile() { + if (byte == 0x00) { + final int extra = requireByte(); + if (extra != 0) { + throw Exception('Invalid content'); + } + byte = -1; + setParentEndOfFileDetect(true); + return true; + } + return byte! < 0; + } + + @override + int? readByte() { + if (isEndOfFile && checkEndOfFile()) { + return -1; + } + final int? result = byte; + byte = requireByte(); + return result; + } + + @override + int read(List buffer, int offset, int count) { + if (isEndOfFile || count <= 1) { + return super.read(buffer, offset, count); + } + if (byte! < 0) { + return 0; + } + final int numRead = input!.read(buffer, offset + 1, count - 1)!; + if (numRead <= 0) { + throw Exception(); + } + buffer[offset] = byte!; + byte = requireByte(); + return numRead + 1; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/ber.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/ber.dart index 98071e0a3..e61c3ae22 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/ber.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/ber.dart @@ -1,306 +1,306 @@ -import 'dart:math'; - -import '../../../io/stream_reader.dart'; -import 'asn1.dart'; -import 'asn1_parser.dart'; -import 'der.dart'; - -/// internal class -class BerOctet extends DerOctet { - /// internal constructor - BerOctet(super.bytes); - - /// internal constructor - BerOctet.fromCollection(List octets) - : super(BerOctet.getBytes(octets)) { - _octets = octets; - } - - //Fields - late dynamic _octets; - - //Implementation - @override - List? getOctets() { - return value; - } - - /// internal method - List generateOctets() { - final List collection = []; - for (int i = 0; i < value!.length; i += 1000) { - final int endIndex = min(value!.length, i + 1000); - collection.add( - DerOctet( - List.generate( - endIndex - i, - (int index) => - ((i + index) < value!.length) ? value![i + index] : 0, - ), - ), - ); - } - return collection; - } - - @override - void encode(DerStream stream) { - if (stream is Asn1DerStream) { - stream.stream!.add(Asn1Tags.constructed | Asn1Tags.octetString); - stream.stream!.add(0x80); - _octets.forEach((dynamic octet) { - stream.writeObject(octet); - }); - stream.stream!.add(0x00); - stream.stream!.add(0x00); - } else { - super.encode(stream); - } - } - - /// internal method - static BerOctet getBerOctet(Asn1Sequence sequence) { - final List collection = []; - for (int i = 0; i < sequence.objects!.length; i++) { - final dynamic entry = sequence.objects![i]; - if (entry != null && entry is Asn1Encode) { - collection.add(entry); - } - } - return BerOctet.fromCollection(collection); - } - - /// internal method - static List getBytes(List octets) { - final List result = []; - if (octets.isNotEmpty) { - for (final dynamic o in octets) { - if (o is DerOctet) { - result.addAll(o.getOctets()!); - } - } - } - return result; - } -} - -/// [BerOctet] helper -class BerOctetHelper implements IAsn1Octet { - /// internal constructor - BerOctetHelper(Asn1Parser helper) { - _helper = helper; - } - //Fields - Asn1Parser? _helper; - @override - PdfStreamReader getOctetStream() { - return _OctetStream(_helper); - } - - @override - Asn1 getAsn1() { - return BerOctet(readAll(getOctetStream())); - } - - /// internal method - List readAll(PdfStreamReader stream) { - final List output = []; - final List bytes = List.generate(512, (int i) => 0); - int? index; - while ((index = stream.read(bytes, 0, bytes.length))! > 0) { - output.addAll(bytes.sublist(0, index)); - } - return output; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _helper.hashCode; - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is BerOctetHelper) { - return other._helper == _helper; - } else { - return false; - } - } -} - -/// [BerTag] helper -class BerTagHelper implements IAsn1Tag { - /// internal constructor - BerTagHelper(bool isConstructed, int tagNumber, Asn1Parser helper) { - _isConstructed = isConstructed; - _tagNumber = tagNumber; - _helper = helper; - } - //Fields - bool? _isConstructed; - int? _tagNumber; - late Asn1Parser _helper; - //Properties - @override - int? get tagNumber => _tagNumber; - //Implements - @override - IAsn1? getParser(int tagNumber, bool isExplicit) { - if (isExplicit) { - if (!_isConstructed!) { - throw ArgumentError.value( - isExplicit, - 'isExplicit', - 'Implicit tags identified', - ); - } - return _helper.readObject(); - } - return _helper.readImplicit(_isConstructed, tagNumber); - } - - @override - Asn1 getAsn1() { - return _helper.readTaggedObject(_isConstructed!, _tagNumber); - } -} - -/// internal class -class BerSequence extends DerSequence { - /// internal constructor - BerSequence({List? super.array, super.collection}); - - /// internal constructor - BerSequence.fromObject(super.object) : super.fromObject(); - - /// internal constructor - static BerSequence empty = BerSequence(); - - /// internal constructor - static BerSequence fromCollection(Asn1EncodeCollection collection) { - return collection.count < 1 ? empty : BerSequence(collection: collection); - } - - /// internal method - @override - void encode(DerStream stream) { - if (stream is Asn1DerStream) { - stream.stream!.add(Asn1Tags.sequence | Asn1Tags.constructed); - stream.stream!.add(0x80); - // ignore: avoid_function_literals_in_foreach_calls - objects!.forEach((dynamic entry) { - if (entry is Asn1Encode) { - stream.writeObject(entry); - } - }); - stream.stream!.add(0x00); - stream.stream!.add(0x00); - } else { - super.encode(stream); - } - } -} - -/// internal class -class BerSequenceHelper implements IAsn1Collection { - /// internal constructor - BerSequenceHelper(Asn1Parser helper) { - _helper = helper; - } - late Asn1Parser _helper; - - @override - IAsn1? readObject() { - return _helper.readObject(); - } - - @override - Asn1 getAsn1() { - return BerSequence.fromCollection(_helper.readCollection()); - } -} - -class _OctetStream extends PdfStreamReader { - _OctetStream(Asn1Parser? helper) : super([]) { - _helper = helper; - _first = true; - } - Asn1Parser? _helper; - PdfStreamReader? _stream; - late bool _first; - //Implementation - @override - int? read(List buffer, int offset, int count) { - if (_stream == null) { - if (!_first) { - return 0; - } - final IAsn1? octet = _helper!.readObject(); - if (octet != null && octet is IAsn1Octet) { - _first = false; - _stream = octet.getOctetStream(); - } else { - return 0; - } - } - int totalRead = 0; - bool isContinue = true; - int? result; - while (isContinue) { - final int numRead = - _stream!.read(buffer, offset + totalRead, count - totalRead)!; - if (numRead > 0) { - totalRead += numRead; - if (totalRead == count) { - result = totalRead; - isContinue = false; - } - } else { - final IAsn1? octet = _helper!.readObject(); - if (octet != null && octet is IAsn1Octet) { - _stream = octet.getOctetStream(); - } else { - _stream = null; - result = totalRead; - isContinue = false; - } - } - } - return result; - } - - @override - int? readByte() { - if (_stream == null) { - if (!_first) { - return 0; - } - final IAsn1? octet = _helper!.readObject(); - if (octet != null && octet is IAsn1Octet) { - _first = false; - _stream = octet.getOctetStream(); - } else { - return 0; - } - } - bool isContinue = true; - int? result; - while (isContinue) { - final int value = _stream!.readByte()!; - if (value >= 0) { - result = value; - isContinue = false; - } else { - final IAsn1? octet = _helper!.readObject(); - if (octet != null && octet is IAsn1Octet) { - _stream = octet.getOctetStream(); - } else { - _stream = null; - result = -1; - isContinue = false; - } - } - } - return result; - } -} +import 'dart:math'; + +import '../../../io/stream_reader.dart'; +import 'asn1.dart'; +import 'asn1_parser.dart'; +import 'der.dart'; + +/// internal class +class BerOctet extends DerOctet { + /// internal constructor + BerOctet(super.bytes); + + /// internal constructor + BerOctet.fromCollection(List octets) + : super(BerOctet.getBytes(octets)) { + _octets = octets; + } + + //Fields + late dynamic _octets; + + //Implementation + @override + List? getOctets() { + return value; + } + + /// internal method + List generateOctets() { + final List collection = []; + for (int i = 0; i < value!.length; i += 1000) { + final int endIndex = min(value!.length, i + 1000); + collection.add( + DerOctet( + List.generate( + endIndex - i, + (int index) => + ((i + index) < value!.length) ? value![i + index] : 0, + ), + ), + ); + } + return collection; + } + + @override + void encode(DerStream stream) { + if (stream is Asn1DerStream) { + stream.stream!.add(Asn1Tags.constructed | Asn1Tags.octetString); + stream.stream!.add(0x80); + _octets.forEach((dynamic octet) { + stream.writeObject(octet); + }); + stream.stream!.add(0x00); + stream.stream!.add(0x00); + } else { + super.encode(stream); + } + } + + /// internal method + static BerOctet getBerOctet(Asn1Sequence sequence) { + final List collection = []; + for (int i = 0; i < sequence.objects!.length; i++) { + final dynamic entry = sequence.objects![i]; + if (entry != null && entry is Asn1Encode) { + collection.add(entry); + } + } + return BerOctet.fromCollection(collection); + } + + /// internal method + static List getBytes(List octets) { + final List result = []; + if (octets.isNotEmpty) { + for (final dynamic o in octets) { + if (o is DerOctet) { + result.addAll(o.getOctets()!); + } + } + } + return result; + } +} + +/// [BerOctet] helper +class BerOctetHelper implements IAsn1Octet { + /// internal constructor + BerOctetHelper(Asn1Parser helper) { + _helper = helper; + } + //Fields + Asn1Parser? _helper; + @override + PdfStreamReader getOctetStream() { + return _OctetStream(_helper); + } + + @override + Asn1 getAsn1() { + return BerOctet(readAll(getOctetStream())); + } + + /// internal method + List readAll(PdfStreamReader stream) { + final List output = []; + final List bytes = List.generate(512, (int i) => 0); + int? index; + while ((index = stream.read(bytes, 0, bytes.length))! > 0) { + output.addAll(bytes.sublist(0, index)); + } + return output; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _helper.hashCode; + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is BerOctetHelper) { + return other._helper == _helper; + } else { + return false; + } + } +} + +/// [BerTag] helper +class BerTagHelper implements IAsn1Tag { + /// internal constructor + BerTagHelper(bool isConstructed, int tagNumber, Asn1Parser helper) { + _isConstructed = isConstructed; + _tagNumber = tagNumber; + _helper = helper; + } + //Fields + bool? _isConstructed; + int? _tagNumber; + late Asn1Parser _helper; + //Properties + @override + int? get tagNumber => _tagNumber; + //Implements + @override + IAsn1? getParser(int tagNumber, bool isExplicit) { + if (isExplicit) { + if (!_isConstructed!) { + throw ArgumentError.value( + isExplicit, + 'isExplicit', + 'Implicit tags identified', + ); + } + return _helper.readObject(); + } + return _helper.readImplicit(_isConstructed, tagNumber); + } + + @override + Asn1 getAsn1() { + return _helper.readTaggedObject(_isConstructed!, _tagNumber); + } +} + +/// internal class +class BerSequence extends DerSequence { + /// internal constructor + BerSequence({List? super.array, super.collection}); + + /// internal constructor + BerSequence.fromObject(super.object) : super.fromObject(); + + /// internal constructor + static BerSequence empty = BerSequence(); + + /// internal constructor + static BerSequence fromCollection(Asn1EncodeCollection collection) { + return collection.count < 1 ? empty : BerSequence(collection: collection); + } + + /// internal method + @override + void encode(DerStream stream) { + if (stream is Asn1DerStream) { + stream.stream!.add(Asn1Tags.sequence | Asn1Tags.constructed); + stream.stream!.add(0x80); + // ignore: avoid_function_literals_in_foreach_calls + objects!.forEach((dynamic entry) { + if (entry is Asn1Encode) { + stream.writeObject(entry); + } + }); + stream.stream!.add(0x00); + stream.stream!.add(0x00); + } else { + super.encode(stream); + } + } +} + +/// internal class +class BerSequenceHelper implements IAsn1Collection { + /// internal constructor + BerSequenceHelper(Asn1Parser helper) { + _helper = helper; + } + late Asn1Parser _helper; + + @override + IAsn1? readObject() { + return _helper.readObject(); + } + + @override + Asn1 getAsn1() { + return BerSequence.fromCollection(_helper.readCollection()); + } +} + +class _OctetStream extends PdfStreamReader { + _OctetStream(Asn1Parser? helper) : super([]) { + _helper = helper; + _first = true; + } + Asn1Parser? _helper; + PdfStreamReader? _stream; + late bool _first; + //Implementation + @override + int? read(List buffer, int offset, int count) { + if (_stream == null) { + if (!_first) { + return 0; + } + final IAsn1? octet = _helper!.readObject(); + if (octet != null && octet is IAsn1Octet) { + _first = false; + _stream = octet.getOctetStream(); + } else { + return 0; + } + } + int totalRead = 0; + bool isContinue = true; + int? result; + while (isContinue) { + final int numRead = + _stream!.read(buffer, offset + totalRead, count - totalRead)!; + if (numRead > 0) { + totalRead += numRead; + if (totalRead == count) { + result = totalRead; + isContinue = false; + } + } else { + final IAsn1? octet = _helper!.readObject(); + if (octet != null && octet is IAsn1Octet) { + _stream = octet.getOctetStream(); + } else { + _stream = null; + result = totalRead; + isContinue = false; + } + } + } + return result; + } + + @override + int? readByte() { + if (_stream == null) { + if (!_first) { + return 0; + } + final IAsn1? octet = _helper!.readObject(); + if (octet != null && octet is IAsn1Octet) { + _first = false; + _stream = octet.getOctetStream(); + } else { + return 0; + } + } + bool isContinue = true; + int? result; + while (isContinue) { + final int value = _stream!.readByte()!; + if (value >= 0) { + result = value; + isContinue = false; + } else { + final IAsn1? octet = _helper!.readObject(); + if (octet != null && octet is IAsn1Octet) { + _stream = octet.getOctetStream(); + } else { + _stream = null; + result = -1; + isContinue = false; + } + } + } + return result; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/der.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/der.dart index f9900a48a..d1fe8d9a8 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/der.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/asn1/der.dart @@ -1,1167 +1,1167 @@ -import 'dart:convert'; - -import '../../../io/stream_reader.dart'; -import '../cryptography/signature_utilities.dart'; -import 'asn1.dart'; -import 'asn1_parser.dart'; -import 'asn1_stream.dart'; - -/// internal class -class IAsn1String { - /// internal method - String? getString([List? bytes]) => null; -} - -/// internal class -class IAsn1SetHelper implements IAsn1 { - /// internal method - IAsn1? readObject() => null; - @override - Asn1? getAsn1() => null; -} - -class _ObjectIdentityToken { - _ObjectIdentityToken(String? id) { - _id = id; - } - String? _id; - int _index = 0; - bool get hasMoreTokens => _index != -1; - String? nextToken() { - if (_index == -1) { - return null; - } - final int endIndex = _id!.indexOf('.', _index); - if (endIndex == -1) { - final String lastToken = _id!.substring(_index); - _index = -1; - return lastToken; - } - final String nextToken = _id!.substring(_index, endIndex); - _index = endIndex + 1; - return nextToken; - } -} - -/// internal class -abstract class DerString extends Asn1 implements IAsn1String { - @override - String? getString([List? bytes]); - - @override - String toString() { - return getString()!; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return getString().hashCode; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is DerString) { - return getString() == other.getString(); - } else { - return false; - } - } -} - -/// internal class -class DerAsciiString extends DerString { - //Constructor - /// internal constructor - DerAsciiString(String value, bool isValid) { - if (isValid && !isAsciiString(value)) { - throw ArgumentError.value(value, 'value', 'Invalid characters found'); - } - _value = value; - } - - /// internal constructor - DerAsciiString.fromBytes(List bytes) { - _value = utf8.decode(bytes); - } - //Fields - String? _value; - - //Implementation - @override - String? getString([List? bytes]) { - return _value; - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.asciiString, getOctets()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return _value.hashCode; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerAsciiString) { - return _value == asn1._value; - } else { - return false; - } - } - - /// internal method - List? asnEncode() { - return super.asn1Encode(getOctets()); - } - - /// internal method - List getOctets() { - return utf8.encode(_value!); - } - - //Static methods - /// internal method - static bool isAsciiString(String value) { - for (int i = 0; i < value.length; i++) { - if (value.codeUnitAt(i) > 0x007f) { - return false; - } - } - return true; - } - - /// internal method - static DerAsciiString? getAsciiStringFromObj(dynamic obj) { - if (obj == null || obj is DerAsciiString) { - return obj; - } - throw Exception('Invalid entry'); - } - - /// internal method - static DerAsciiString? getAsciiString(Asn1Tag tag, bool isExplicit) { - final Asn1? asn1 = tag.getObject(); - if (asn1 != null) { - if (isExplicit || asn1 is DerAsciiString) { - return getAsciiStringFromObj(asn1); - } - } - if (asn1 is Asn1Octet) { - return DerAsciiString.fromBytes(asn1.getOctets()!); - } - return null; - } -} - -/// internal class -class DerBitString extends DerString { - /// internal constructor - DerBitString(this.data, int? pad) { - extra = pad ?? 0; - _table = [ - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'A', - 'B', - 'C', - 'D', - 'E', - 'F', - ]; - } - - /// internal constructor - DerBitString.fromAsn1(Asn1Encode asn1) { - data = asn1.getDerEncoded(); - } - - //Fields - /// internal field - List? data; - - /// internal field - int? extra; - late List _table; - - //Implementation - /// internal method - List? getBytes() { - return data; - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - final List bytes = List.generate( - getBytes()!.length + 1, - (int i) => 0, - ); - bytes[0] = extra!; - List.copyRange(bytes, 1, getBytes()!, 0, bytes.length - 1); - stream.writeEncoded(Asn1Tags.bitString, bytes); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return extra.hashCode ^ Asn1.getHashCode(data); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerBitString) { - return extra == asn1.extra && Asn1.areEqual(data, asn1.data); - } else { - return false; - } - } - - @override - String getString([List? bytes]) { - String result = '#'; - final List str = getDerEncoded()!; - for (int i = 0; i != str.length; i++) { - final int ubyte = str[i].toUnsigned(16); - result += _table[(ubyte >> 4) & 0xf]; - result += _table[str[i] & 0xf]; - } - return result; - } - - //Static methods - /// internal method - static DerBitString fromAsn1Octets(List bytes) { - final int pad = bytes[0]; - final List data = List.generate(bytes.length - 1, (int i) => 0); - List.copyRange(data, 0, bytes, 1, data.length + 1); - return DerBitString(data, pad); - } - - /// internal method - static DerBitString? getDetBitString(dynamic obj) { - if (obj == null) { - return null; - } else if (obj is DerBitString) { - return obj; - } - throw ArgumentError.value(obj, 'object', 'Invalid Entry'); - } - - /// internal method - static DerBitString? getDerBitStringFromTag(Asn1Tag tag, bool isExplicit) { - final Asn1? asn1 = tag.getObject(); - if (isExplicit || asn1 is DerBitString) { - return getDetBitString(asn1); - } - return fromAsn1Octets((asn1! as Asn1Octet).getOctets()!); - } -} - -/// internal class -class DerBmpString extends DerString { - /// internal constructor - DerBmpString(List bytes) { - String result = ''; - for (int i = 0; i != (bytes.length ~/ 2); i++) { - result += String.fromCharCode( - (bytes[2 * i] << 8) | (bytes[2 * i + 1] & 0xff), - ); - } - _value = result; - } - - //Fields - String? _value; - - //Implementation - @override - String? getString([List? bytes]) { - return _value; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _value.hashCode; - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerBmpString) { - return _value == asn1._value; - } else { - return false; - } - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - final List bytes = List.generate( - _value!.length * 2, - (int i) => 0, - ); - for (int i = 0; i != _value!.length; i++) { - bytes[2 * i] = (_value!.codeUnitAt(i) >> 8).toUnsigned(8); - bytes[2 * i + 1] = _value!.codeUnitAt(i).toUnsigned(8); - } - stream.writeEncoded(Asn1Tags.bmpString, bytes); - } -} - -/// internal class -class DerPrintableString extends DerString { - /// internal constructor - DerPrintableString(String value) { - _value = value; - } - //Fields - String? _value; - //Implementation - @override - String? getString([List? bytes]) { - return _value; - } - - /// internal method - List getBytes() { - return utf8.encode(_value!); - } - - /// internal method - @override - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.printableString, getBytes()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerPrintableString) { - return _value == asn1._value; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _value.hashCode; -} - -/// internal class -class DerBoolean extends Asn1 { - /// internal constructor - DerBoolean(bool value) { - _value = value ? 0xff : 0; - } - - /// internal constructor - DerBoolean.fromBytes(List bytes) { - if (bytes.length != 1) { - throw ArgumentError.value(bytes, 'bytes', 'Invalid length in bytes'); - } - _value = bytes[0]; - } - //Fields - late int _value; - - //Properties - /// internal property - bool get isTrue => _value != 0; - - //Implementation - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.boolean, [_value]); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerBoolean) { - return isTrue == asn1.isTrue; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return isTrue.hashCode; - } - - @override - String toString() { - return isTrue ? 'TRUE' : 'FALSE'; - } -} - -/// internal class -class DerInteger extends Asn1 { - /// internal constructor - DerInteger(this.intValue); - - /// internal constructor - DerInteger.fromNumber(BigInt? value) { - if (value == null) { - throw ArgumentError.value(value, 'value', 'Invalid value'); - } - intValue = bigIntToBytes(value); - } - //Fields - /// internal field - List? intValue; - - //Properties - /// internal property - BigInt get value => bigIntFromBytes(intValue); - - /// internal property - BigInt get positiveValue => bigIntFromBytes(intValue, 1); - - //Implementation - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.integer, intValue); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return Asn1.getHashCode(intValue); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerInteger) { - return Asn1.areEqual(intValue, asn1.intValue); - } else { - return false; - } - } - - @override - String toString() { - return value.toString(); - } - - //Static methods - /// internal method - static DerInteger? getNumber(dynamic obj) { - if (obj == null || obj is DerInteger) { - return obj as DerInteger?; - } - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - - /// internal method - static DerInteger? getNumberFromTag(Asn1Tag tag, bool isExplicit) { - final Asn1? asn1 = tag.getObject(); - if (isExplicit || asn1 is DerInteger) { - return getNumber(asn1); - } - return DerInteger(Asn1Octet.getOctetStringFromObject(asn1)!.getOctets()); - } -} - -/// internal class -class DerNull extends Asn1Null { - /// internal constructor - DerNull() : super() { - bytes = []; - } - //Fields - /// internal field - static DerNull value = DerNull(); - //Implementation - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.nullValue, bytes); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - return asn1 is DerNull; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return -1; - } -} - -/// internal class -class DerObjectID extends Asn1 { - //Contructors - /// internal constructor - DerObjectID(this.id) { - if (!isValidIdentifier(id!)) { - throw ArgumentError.value(id, 'id', 'Invalid ID'); - } - } - - /// internal constructor - DerObjectID.fromBytes(List bytes) { - id = getObjectID(bytes); - bytes = Asn1.clone(bytes); - } - - /// internal constructor - DerObjectID.fromBranch(DerObjectID id, String branchId) { - if (!isValidBranchID(branchId, 0)) { - throw ArgumentError.value(id, 'id', 'Invalid ID'); - } - this.id = '${id.id!}.$branchId'; - } - - /// internal field - String? id; - - // ignore: prefer_final_fields - static List _objects = List.generate( - 1024, - (int i) => null, - ); - //Implemnetation - /// internal method - List? getBytes() { - bytes ??= getOutput(); - return bytes; - } - - /// internal method - List getOutput() { - List stream = []; - final _ObjectIdentityToken oidToken = _ObjectIdentityToken(id); - String token = oidToken.nextToken()!; - final int first = int.parse(token) * 40; - token = oidToken.nextToken()!; - if (token.length <= 18) { - stream = writeField(stream, fieldValue: first + int.parse(token)); - } else { - stream = writeField( - stream, - numberValue: BigInt.parse(token) + BigInt.from(first), - ); - } - while (oidToken.hasMoreTokens) { - token = oidToken.nextToken()!; - if (token.length <= 18) { - stream = writeField(stream, fieldValue: int.parse(token)); - } else { - stream = writeField(stream, numberValue: BigInt.parse(token)); - } - } - return stream; - } - - /// internal method - List writeField( - List stream, { - int? fieldValue, - BigInt? numberValue, - }) { - if (fieldValue != null) { - final List result = []; - result.add((fieldValue & 0x7f).toUnsigned(8)); - while (fieldValue! >= 128) { - fieldValue >>= 7; - result.add(((fieldValue & 0x7f) | 0x80).toUnsigned(8)); - } - stream.addAll(result.reversed.toList()); - } else if (numberValue != null) { - final int byteCount = (numberValue.bitLength + 6) ~/ 7; - if (byteCount == 0) { - stream.add(0); - } else { - BigInt value = numberValue; - final List bytes = List.generate(byteCount, (int i) => 0); - for (int i = byteCount - 1; i >= 0; i--) { - bytes[i] = ((value.toSigned(32).toInt() & 0x7f) | 0x80).toUnsigned(8); - value = value >> 7; - } - bytes[byteCount - 1] &= 0x7f; - stream.addAll(bytes); - } - } - return stream; - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.objectIdentifier, getBytes()); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return id.hashCode; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerObjectID) { - return id == asn1.id; - } else { - return false; - } - } - - @override - String toString() { - return id!; - } - - //Static methods - /// internal method - static DerObjectID? getID(dynamic obj) { - if (obj == null || obj is DerObjectID) { - return obj as DerObjectID?; - } else if (obj is List) { - return fromOctetString(obj); - } - throw ArgumentError.value(obj, 'obj', 'Illegal object'); - } - - /// internal method - static bool isValidBranchID(String branchID, int start) { - bool isAllowed = false; - int position = branchID.length; - while (--position >= start) { - final String entry = branchID[position]; - if ('0'.codeUnitAt(0) <= entry.codeUnitAt(0) && - entry.codeUnitAt(0) <= '9'.codeUnitAt(0)) { - isAllowed = true; - continue; - } - if (entry == '.') { - if (!isAllowed) { - return false; - } - isAllowed = false; - continue; - } - return false; - } - return isAllowed; - } - - /// internal method - static bool isValidIdentifier(String id) { - if (id.length < 3 || id[1] != '.') { - return false; - } - if (id.codeUnitAt(0) < '0'.codeUnitAt(0) || - id.codeUnitAt(0) > '2'.codeUnitAt(0)) { - return false; - } - return isValidBranchID(id, 2); - } - - /// internal method - static String getObjectID(List bytes) { - String result = ''; - int value = 0; - BigInt? number; - bool first = true; - for (int i = 0; i != bytes.length; i++) { - final int entry = bytes[i]; - if (value <= 72057594037927808) { - value += entry & 0x7f; - if ((entry & 0x80) == 0) { - if (first) { - if (value < 40) { - result += '0'; - } else if (value < 80) { - result += '1'; - value -= 40; - } else { - result += '2'; - value -= 80; - } - first = false; - } - result += '.'; - result += value.toString(); - value = 0; - } else { - value <<= 7; - } - } else { - number ??= BigInt.from(value); - number = number | BigInt.from(entry & 0x7f); - if ((entry & 0x80) == 0) { - if (first) { - result += '2'; - number = number - BigInt.from(80); - first = false; - } - result += '.'; - result += number.toSigned(32).toInt().toString(); - number = null; - value = 0; - } else { - number = number << 7; - } - } - } - return result; - } - - /// internal method - static DerObjectID? fromOctetString(List bytes) { - final int hashCode = Asn1.getHashCode(bytes); - final int first = hashCode & 1023; - final DerObjectID? entry = _objects[first]; - if (entry != null && Asn1.areEqual(bytes, entry.getBytes())) { - return entry; - } - _objects[first] = DerObjectID.fromBytes(bytes); - return _objects[first]; - } - - /// internal method - DerObjectID branch(String id) { - return DerObjectID.fromBranch(this, id); - } -} - -/// internal class -class DerOctet extends Asn1Octet { - /// internal constructor - DerOctet(List super.bytes); - - /// internal constructor - DerOctet.fromObject(super.asn1) : super.fromObject(); - @override - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.octetString, value); - } -} - -/// internal class -class DerSequence extends Asn1Sequence { - /// internal constructor - DerSequence({List? array, Asn1EncodeCollection? collection}) - : super() { - if (array != null) { - // ignore: prefer_foreach - for (final Asn1Encode? entry in array) { - objects!.add(entry); - } - } else if (collection != null) { - for (int i = 0; i < collection.count; i++) { - objects!.add(collection[i]); - } - } - } - - /// internal constructor - DerSequence.fromObject(Asn1Encode? encode) : super() { - objects!.add(encode); - } - - /// internal constructor - static DerSequence fromCollection(Asn1EncodeCollection collection) { - return collection.count < 1 ? empty : DerSequence(collection: collection); - } - - /// internal constructor - static DerSequence empty = DerSequence(); - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream outputStream) { - final DerStream stream = DerStream([]); - // ignore: avoid_function_literals_in_foreach_calls - objects!.forEach((dynamic asn1) => stream.writeObject(asn1)); - outputStream.writeEncoded( - Asn1Tags.sequence | Asn1Tags.constructed, - stream.stream, - ); - } -} - -/// internal class -class DerSequenceHelper implements IAsn1Collection { - /// internal constructor - DerSequenceHelper(Asn1Parser helper) { - _helper = helper; - } - //Fields - late Asn1Parser _helper; - //Implementation - @override - IAsn1? readObject() { - return _helper.readObject(); - } - - @override - Asn1 getAsn1() { - return DerSequence(collection: _helper.readCollection()); - } -} - -/// internal class -class DerSet extends Asn1Set { - //Constructor - /// internal constructor - DerSet({ - List? array, - Asn1EncodeCollection? collection, - bool? isSort, - }) : super() { - if (array != null) { - // ignore: avoid_function_literals_in_foreach_calls - array.forEach((Asn1Encode? asn1) => addObject(asn1)); - sortObjects(); - } else if (collection != null) { - isSort ??= true; - for (int i = 0; i < collection.count; i++) { - addObject(collection[i]); - } - if (isSort) { - sortObjects(); - } - } - } - //Implementation - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream outputStream) { - final DerStream stream = DerStream([]); - // ignore: avoid_function_literals_in_foreach_calls - objects.forEach((dynamic entry) => stream.writeObject(entry)); - outputStream.writeEncoded( - Asn1Tags.setTag | Asn1Tags.constructed, - stream.stream, - ); - } -} - -/// internal class -class DerSetHelper implements IAsn1SetHelper { - /// internal constructor - DerSetHelper(Asn1Parser helper) { - _helper = helper; - } - //Fields - late Asn1Parser _helper; - //Implementation - @override - IAsn1? readObject() { - return _helper.readObject(); - } - - @override - Asn1 getAsn1() { - return DerSet(collection: _helper.readCollection(), isSort: false); - } -} - -/// internal class -class DerStream { - /// internal constructor - DerStream([List? stream]) { - if (stream != null) { - this.stream = stream; - } - } - - /// internal field - List? stream; - //Implementation - /// internal method - void writeLength(int length) { - if (length > 127) { - int size = 1; - int value = length.toUnsigned(32); - while ((value >>= 8) != 0) { - size++; - } - stream!.add((size | 0x80).toUnsigned(8)); - for (int i = (size - 1) * 8; i >= 0; i -= 8) { - stream!.add((length >> i).toUnsigned(8)); - } - } else { - stream!.add(length.toUnsigned(8)); - } - } - - /// internal method - void writeEncoded(int? tagNumber, List? bytes, [int? flag]) { - if (flag != null) { - writeTag(flag, tagNumber!); - writeLength(bytes!.length); - stream!.addAll(bytes); - } else { - stream!.add(tagNumber!.toUnsigned(8)); - writeLength(bytes!.length); - stream!.addAll(bytes); - } - } - - /// internal method - void writeTag(int flag, int tagNumber) { - if (tagNumber < 31) { - stream!.add((flag | tagNumber).toUnsigned(8)); - } else { - stream!.add((flag | 0x1f).toUnsigned(8)); - if (tagNumber < 128) { - stream!.add(tagNumber.toUnsigned(8)); - } else { - final List bytes = []; - bytes.add((tagNumber & 0x7F).toUnsigned(8)); - do { - tagNumber >>= 7; - bytes.add((tagNumber & 0x7F | 0x80).toUnsigned(8)); - } while (tagNumber > 127 && bytes.length <= 5); - stream!.addAll(bytes.reversed.toList()); - } - } - } - - /// internal method - void writeObject(dynamic obj) { - if (obj == null) { - stream!.add(Asn1Tags.nullValue); - stream!.add(0x00); - } else if (obj is Asn1) { - obj.encode(this); - } else if (obj is Asn1Encode) { - obj.getAsn1()!.encode(this); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid object specified'); - } - } -} - -/// internal class -class DerTag extends Asn1Tag { - /// internal constructor - DerTag(super.tagNumber, super.asn1, [bool? isExplicit]) { - if (isExplicit != null) { - explicit = isExplicit; - } - } - //Implementation - @override - void encode(DerStream stream) { - final List? bytes = object!.getDerEncoded(); - if (explicit!) { - stream.writeEncoded( - tagNumber, - bytes, - Asn1Tags.constructed | Asn1Tags.tagged, - ); - } else { - final int flag = (bytes![0] & Asn1Tags.constructed) | Asn1Tags.tagged; - stream.writeTag(flag, tagNumber!); - stream.stream!.addAll(bytes.sublist(1)); - } - } -} - -/// internal class -class DerUtcTime extends Asn1 { - /// internal constructor - DerUtcTime(List bytes) { - _time = utf8.decode(bytes); - } - //Fields - String? _time; - //Properties - /// internal property - DateTime? get toAdjustedDateTime { - return DateTime.tryParse(adjustedTimeString); - } - - /// internal property - String get adjustedTimeString { - String timeString = _time!; - final String c = timeString.codeUnitAt(0) < '5'.codeUnitAt(0) ? '20' : '19'; - timeString = c + timeString; - return '${timeString.substring(0, 8)}T${timeString.substring(8)}'; - } - - //Implementation - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.utcTime, utf8.encode(_time!)); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerUtcTime) { - return _time == asn1._time; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return _time.hashCode; - } - - @override - String toString() { - return _time!; - } -} - -/// internal class -class DerCatalogue extends Asn1 { - /// internal constructor - DerCatalogue([List? bytes]) { - this.bytes = bytes; - } - - //Implemnetation - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.enumerated, bytes); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerCatalogue) { - return Asn1.areEqual(bytes, asn1.bytes); - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode { - return Asn1.getHashCode(bytes); - } -} - -/// internal class -class DerOctetHelper implements IAsn1Octet { - /// internal constructor - DerOctetHelper(Asn1StreamHelper? stream) { - _stream = stream; - } - //Fields - Asn1StreamHelper? _stream; - //Implementation - @override - PdfStreamReader? getOctetStream() { - return _stream; - } - - @override - Asn1 getAsn1() { - return DerOctet(_stream!.toArray()); - } -} - -/// internal class -class DerUtf8String extends DerString { - /// internal constructor - DerUtf8String(String value) { - _value = value; - } - //Fields - String? _value; - //Implementation - @override - String? getString([List? bytes]) { - return _value; - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.utf8String, utf8.encode(_value!)); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerUtf8String) { - return _value == asn1._value; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _value.hashCode; -} - -/// internal class -class DerTeleText extends DerString { - /// internal constructor - DerTeleText(String value) { - _value = value; - } - //Fields - String? _value; - //Implementation - @override - String? getString([List? bytes]) { - return _value; - } - - @override - // ignore: avoid_renaming_method_parameters - void encode(DerStream stream) { - stream.writeEncoded(Asn1Tags.teleText, toByteArray(_value!)); - } - - /// internal method - List toByteArray(String value) { - final List result = []; - // ignore: avoid_function_literals_in_foreach_calls - value.codeUnits.forEach((int entry) => result.add(entry.toUnsigned(8))); - return result; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object asn1) { - if (asn1 is DerTeleText) { - return _value == asn1._value; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _value.hashCode; -} +import 'dart:convert'; + +import '../../../io/stream_reader.dart'; +import '../cryptography/signature_utilities.dart'; +import 'asn1.dart'; +import 'asn1_parser.dart'; +import 'asn1_stream.dart'; + +/// internal class +class IAsn1String { + /// internal method + String? getString([List? bytes]) => null; +} + +/// internal class +class IAsn1SetHelper implements IAsn1 { + /// internal method + IAsn1? readObject() => null; + @override + Asn1? getAsn1() => null; +} + +class _ObjectIdentityToken { + _ObjectIdentityToken(String? id) { + _id = id; + } + String? _id; + int _index = 0; + bool get hasMoreTokens => _index != -1; + String? nextToken() { + if (_index == -1) { + return null; + } + final int endIndex = _id!.indexOf('.', _index); + if (endIndex == -1) { + final String lastToken = _id!.substring(_index); + _index = -1; + return lastToken; + } + final String nextToken = _id!.substring(_index, endIndex); + _index = endIndex + 1; + return nextToken; + } +} + +/// internal class +abstract class DerString extends Asn1 implements IAsn1String { + @override + String? getString([List? bytes]); + + @override + String toString() { + return getString()!; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return getString().hashCode; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is DerString) { + return getString() == other.getString(); + } else { + return false; + } + } +} + +/// internal class +class DerAsciiString extends DerString { + //Constructor + /// internal constructor + DerAsciiString(String value, bool isValid) { + if (isValid && !isAsciiString(value)) { + throw ArgumentError.value(value, 'value', 'Invalid characters found'); + } + _value = value; + } + + /// internal constructor + DerAsciiString.fromBytes(List bytes) { + _value = utf8.decode(bytes); + } + //Fields + String? _value; + + //Implementation + @override + String? getString([List? bytes]) { + return _value; + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.asciiString, getOctets()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return _value.hashCode; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerAsciiString) { + return _value == asn1._value; + } else { + return false; + } + } + + /// internal method + List? asnEncode() { + return super.asn1Encode(getOctets()); + } + + /// internal method + List getOctets() { + return utf8.encode(_value!); + } + + //Static methods + /// internal method + static bool isAsciiString(String value) { + for (int i = 0; i < value.length; i++) { + if (value.codeUnitAt(i) > 0x007f) { + return false; + } + } + return true; + } + + /// internal method + static DerAsciiString? getAsciiStringFromObj(dynamic obj) { + if (obj == null || obj is DerAsciiString) { + return obj; + } + throw Exception('Invalid entry'); + } + + /// internal method + static DerAsciiString? getAsciiString(Asn1Tag tag, bool isExplicit) { + final Asn1? asn1 = tag.getObject(); + if (asn1 != null) { + if (isExplicit || asn1 is DerAsciiString) { + return getAsciiStringFromObj(asn1); + } + } + if (asn1 is Asn1Octet) { + return DerAsciiString.fromBytes(asn1.getOctets()!); + } + return null; + } +} + +/// internal class +class DerBitString extends DerString { + /// internal constructor + DerBitString(this.data, int? pad) { + extra = pad ?? 0; + _table = [ + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + ]; + } + + /// internal constructor + DerBitString.fromAsn1(Asn1Encode asn1) { + data = asn1.getDerEncoded(); + } + + //Fields + /// internal field + List? data; + + /// internal field + int? extra; + late List _table; + + //Implementation + /// internal method + List? getBytes() { + return data; + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + final List bytes = List.generate( + getBytes()!.length + 1, + (int i) => 0, + ); + bytes[0] = extra!; + List.copyRange(bytes, 1, getBytes()!, 0, bytes.length - 1); + stream.writeEncoded(Asn1Tags.bitString, bytes); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return extra.hashCode ^ Asn1.getHashCode(data); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerBitString) { + return extra == asn1.extra && Asn1.areEqual(data, asn1.data); + } else { + return false; + } + } + + @override + String getString([List? bytes]) { + String result = '#'; + final List str = getDerEncoded()!; + for (int i = 0; i != str.length; i++) { + final int ubyte = str[i].toUnsigned(16); + result += _table[(ubyte >> 4) & 0xf]; + result += _table[str[i] & 0xf]; + } + return result; + } + + //Static methods + /// internal method + static DerBitString fromAsn1Octets(List bytes) { + final int pad = bytes[0]; + final List data = List.generate(bytes.length - 1, (int i) => 0); + List.copyRange(data, 0, bytes, 1, data.length + 1); + return DerBitString(data, pad); + } + + /// internal method + static DerBitString? getDetBitString(dynamic obj) { + if (obj == null) { + return null; + } else if (obj is DerBitString) { + return obj; + } + throw ArgumentError.value(obj, 'object', 'Invalid Entry'); + } + + /// internal method + static DerBitString? getDerBitStringFromTag(Asn1Tag tag, bool isExplicit) { + final Asn1? asn1 = tag.getObject(); + if (isExplicit || asn1 is DerBitString) { + return getDetBitString(asn1); + } + return fromAsn1Octets((asn1! as Asn1Octet).getOctets()!); + } +} + +/// internal class +class DerBmpString extends DerString { + /// internal constructor + DerBmpString(List bytes) { + String result = ''; + for (int i = 0; i != (bytes.length ~/ 2); i++) { + result += String.fromCharCode( + (bytes[2 * i] << 8) | (bytes[2 * i + 1] & 0xff), + ); + } + _value = result; + } + + //Fields + String? _value; + + //Implementation + @override + String? getString([List? bytes]) { + return _value; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _value.hashCode; + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerBmpString) { + return _value == asn1._value; + } else { + return false; + } + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + final List bytes = List.generate( + _value!.length * 2, + (int i) => 0, + ); + for (int i = 0; i != _value!.length; i++) { + bytes[2 * i] = (_value!.codeUnitAt(i) >> 8).toUnsigned(8); + bytes[2 * i + 1] = _value!.codeUnitAt(i).toUnsigned(8); + } + stream.writeEncoded(Asn1Tags.bmpString, bytes); + } +} + +/// internal class +class DerPrintableString extends DerString { + /// internal constructor + DerPrintableString(String value) { + _value = value; + } + //Fields + String? _value; + //Implementation + @override + String? getString([List? bytes]) { + return _value; + } + + /// internal method + List getBytes() { + return utf8.encode(_value!); + } + + /// internal method + @override + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.printableString, getBytes()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerPrintableString) { + return _value == asn1._value; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _value.hashCode; +} + +/// internal class +class DerBoolean extends Asn1 { + /// internal constructor + DerBoolean(bool value) { + _value = value ? 0xff : 0; + } + + /// internal constructor + DerBoolean.fromBytes(List bytes) { + if (bytes.length != 1) { + throw ArgumentError.value(bytes, 'bytes', 'Invalid length in bytes'); + } + _value = bytes[0]; + } + //Fields + late int _value; + + //Properties + /// internal property + bool get isTrue => _value != 0; + + //Implementation + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.boolean, [_value]); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerBoolean) { + return isTrue == asn1.isTrue; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return isTrue.hashCode; + } + + @override + String toString() { + return isTrue ? 'TRUE' : 'FALSE'; + } +} + +/// internal class +class DerInteger extends Asn1 { + /// internal constructor + DerInteger(this.intValue); + + /// internal constructor + DerInteger.fromNumber(BigInt? value) { + if (value == null) { + throw ArgumentError.value(value, 'value', 'Invalid value'); + } + intValue = bigIntToBytes(value); + } + //Fields + /// internal field + List? intValue; + + //Properties + /// internal property + BigInt get value => bigIntFromBytes(intValue); + + /// internal property + BigInt get positiveValue => bigIntFromBytes(intValue, 1); + + //Implementation + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.integer, intValue); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return Asn1.getHashCode(intValue); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerInteger) { + return Asn1.areEqual(intValue, asn1.intValue); + } else { + return false; + } + } + + @override + String toString() { + return value.toString(); + } + + //Static methods + /// internal method + static DerInteger? getNumber(dynamic obj) { + if (obj == null || obj is DerInteger) { + return obj as DerInteger?; + } + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + + /// internal method + static DerInteger? getNumberFromTag(Asn1Tag tag, bool isExplicit) { + final Asn1? asn1 = tag.getObject(); + if (isExplicit || asn1 is DerInteger) { + return getNumber(asn1); + } + return DerInteger(Asn1Octet.getOctetStringFromObject(asn1)!.getOctets()); + } +} + +/// internal class +class DerNull extends Asn1Null { + /// internal constructor + DerNull() : super() { + bytes = []; + } + //Fields + /// internal field + static DerNull value = DerNull(); + //Implementation + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.nullValue, bytes); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + return asn1 is DerNull; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return -1; + } +} + +/// internal class +class DerObjectID extends Asn1 { + //Contructors + /// internal constructor + DerObjectID(this.id) { + if (!isValidIdentifier(id!)) { + throw ArgumentError.value(id, 'id', 'Invalid ID'); + } + } + + /// internal constructor + DerObjectID.fromBytes(List bytes) { + id = getObjectID(bytes); + bytes = Asn1.clone(bytes); + } + + /// internal constructor + DerObjectID.fromBranch(DerObjectID id, String branchId) { + if (!isValidBranchID(branchId, 0)) { + throw ArgumentError.value(id, 'id', 'Invalid ID'); + } + this.id = '${id.id!}.$branchId'; + } + + /// internal field + String? id; + + // ignore: prefer_final_fields + static List _objects = List.generate( + 1024, + (int i) => null, + ); + //Implemnetation + /// internal method + List? getBytes() { + bytes ??= getOutput(); + return bytes; + } + + /// internal method + List getOutput() { + List stream = []; + final _ObjectIdentityToken oidToken = _ObjectIdentityToken(id); + String token = oidToken.nextToken()!; + final int first = int.parse(token) * 40; + token = oidToken.nextToken()!; + if (token.length <= 18) { + stream = writeField(stream, fieldValue: first + int.parse(token)); + } else { + stream = writeField( + stream, + numberValue: BigInt.parse(token) + BigInt.from(first), + ); + } + while (oidToken.hasMoreTokens) { + token = oidToken.nextToken()!; + if (token.length <= 18) { + stream = writeField(stream, fieldValue: int.parse(token)); + } else { + stream = writeField(stream, numberValue: BigInt.parse(token)); + } + } + return stream; + } + + /// internal method + List writeField( + List stream, { + int? fieldValue, + BigInt? numberValue, + }) { + if (fieldValue != null) { + final List result = []; + result.add((fieldValue & 0x7f).toUnsigned(8)); + while (fieldValue! >= 128) { + fieldValue >>= 7; + result.add(((fieldValue & 0x7f) | 0x80).toUnsigned(8)); + } + stream.addAll(result.reversed.toList()); + } else if (numberValue != null) { + final int byteCount = (numberValue.bitLength + 6) ~/ 7; + if (byteCount == 0) { + stream.add(0); + } else { + BigInt value = numberValue; + final List bytes = List.generate(byteCount, (int i) => 0); + for (int i = byteCount - 1; i >= 0; i--) { + bytes[i] = ((value.toSigned(32).toInt() & 0x7f) | 0x80).toUnsigned(8); + value = value >> 7; + } + bytes[byteCount - 1] &= 0x7f; + stream.addAll(bytes); + } + } + return stream; + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.objectIdentifier, getBytes()); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return id.hashCode; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerObjectID) { + return id == asn1.id; + } else { + return false; + } + } + + @override + String toString() { + return id!; + } + + //Static methods + /// internal method + static DerObjectID? getID(dynamic obj) { + if (obj == null || obj is DerObjectID) { + return obj as DerObjectID?; + } else if (obj is List) { + return fromOctetString(obj); + } + throw ArgumentError.value(obj, 'obj', 'Illegal object'); + } + + /// internal method + static bool isValidBranchID(String branchID, int start) { + bool isAllowed = false; + int position = branchID.length; + while (--position >= start) { + final String entry = branchID[position]; + if ('0'.codeUnitAt(0) <= entry.codeUnitAt(0) && + entry.codeUnitAt(0) <= '9'.codeUnitAt(0)) { + isAllowed = true; + continue; + } + if (entry == '.') { + if (!isAllowed) { + return false; + } + isAllowed = false; + continue; + } + return false; + } + return isAllowed; + } + + /// internal method + static bool isValidIdentifier(String id) { + if (id.length < 3 || id[1] != '.') { + return false; + } + if (id.codeUnitAt(0) < '0'.codeUnitAt(0) || + id.codeUnitAt(0) > '2'.codeUnitAt(0)) { + return false; + } + return isValidBranchID(id, 2); + } + + /// internal method + static String getObjectID(List bytes) { + String result = ''; + int value = 0; + BigInt? number; + bool first = true; + for (int i = 0; i != bytes.length; i++) { + final int entry = bytes[i]; + if (value <= 72057594037927808) { + value += entry & 0x7f; + if ((entry & 0x80) == 0) { + if (first) { + if (value < 40) { + result += '0'; + } else if (value < 80) { + result += '1'; + value -= 40; + } else { + result += '2'; + value -= 80; + } + first = false; + } + result += '.'; + result += value.toString(); + value = 0; + } else { + value <<= 7; + } + } else { + number ??= BigInt.from(value); + number = number | BigInt.from(entry & 0x7f); + if ((entry & 0x80) == 0) { + if (first) { + result += '2'; + number = number - BigInt.from(80); + first = false; + } + result += '.'; + result += number.toSigned(32).toInt().toString(); + number = null; + value = 0; + } else { + number = number << 7; + } + } + } + return result; + } + + /// internal method + static DerObjectID? fromOctetString(List bytes) { + final int hashCode = Asn1.getHashCode(bytes); + final int first = hashCode & 1023; + final DerObjectID? entry = _objects[first]; + if (entry != null && Asn1.areEqual(bytes, entry.getBytes())) { + return entry; + } + _objects[first] = DerObjectID.fromBytes(bytes); + return _objects[first]; + } + + /// internal method + DerObjectID branch(String id) { + return DerObjectID.fromBranch(this, id); + } +} + +/// internal class +class DerOctet extends Asn1Octet { + /// internal constructor + DerOctet(List super.bytes); + + /// internal constructor + DerOctet.fromObject(super.asn1) : super.fromObject(); + @override + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.octetString, value); + } +} + +/// internal class +class DerSequence extends Asn1Sequence { + /// internal constructor + DerSequence({List? array, Asn1EncodeCollection? collection}) + : super() { + if (array != null) { + // ignore: prefer_foreach + for (final Asn1Encode? entry in array) { + objects!.add(entry); + } + } else if (collection != null) { + for (int i = 0; i < collection.count; i++) { + objects!.add(collection[i]); + } + } + } + + /// internal constructor + DerSequence.fromObject(Asn1Encode? encode) : super() { + objects!.add(encode); + } + + /// internal constructor + static DerSequence fromCollection(Asn1EncodeCollection collection) { + return collection.count < 1 ? empty : DerSequence(collection: collection); + } + + /// internal constructor + static DerSequence empty = DerSequence(); + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream outputStream) { + final DerStream stream = DerStream([]); + // ignore: avoid_function_literals_in_foreach_calls + objects!.forEach((dynamic asn1) => stream.writeObject(asn1)); + outputStream.writeEncoded( + Asn1Tags.sequence | Asn1Tags.constructed, + stream.stream, + ); + } +} + +/// internal class +class DerSequenceHelper implements IAsn1Collection { + /// internal constructor + DerSequenceHelper(Asn1Parser helper) { + _helper = helper; + } + //Fields + late Asn1Parser _helper; + //Implementation + @override + IAsn1? readObject() { + return _helper.readObject(); + } + + @override + Asn1 getAsn1() { + return DerSequence(collection: _helper.readCollection()); + } +} + +/// internal class +class DerSet extends Asn1Set { + //Constructor + /// internal constructor + DerSet({ + List? array, + Asn1EncodeCollection? collection, + bool? isSort, + }) : super() { + if (array != null) { + // ignore: avoid_function_literals_in_foreach_calls + array.forEach((Asn1Encode? asn1) => addObject(asn1)); + sortObjects(); + } else if (collection != null) { + isSort ??= true; + for (int i = 0; i < collection.count; i++) { + addObject(collection[i]); + } + if (isSort) { + sortObjects(); + } + } + } + //Implementation + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream outputStream) { + final DerStream stream = DerStream([]); + // ignore: avoid_function_literals_in_foreach_calls + objects.forEach((dynamic entry) => stream.writeObject(entry)); + outputStream.writeEncoded( + Asn1Tags.setTag | Asn1Tags.constructed, + stream.stream, + ); + } +} + +/// internal class +class DerSetHelper implements IAsn1SetHelper { + /// internal constructor + DerSetHelper(Asn1Parser helper) { + _helper = helper; + } + //Fields + late Asn1Parser _helper; + //Implementation + @override + IAsn1? readObject() { + return _helper.readObject(); + } + + @override + Asn1 getAsn1() { + return DerSet(collection: _helper.readCollection(), isSort: false); + } +} + +/// internal class +class DerStream { + /// internal constructor + DerStream([List? stream]) { + if (stream != null) { + this.stream = stream; + } + } + + /// internal field + List? stream; + //Implementation + /// internal method + void writeLength(int length) { + if (length > 127) { + int size = 1; + int value = length.toUnsigned(32); + while ((value >>= 8) != 0) { + size++; + } + stream!.add((size | 0x80).toUnsigned(8)); + for (int i = (size - 1) * 8; i >= 0; i -= 8) { + stream!.add((length >> i).toUnsigned(8)); + } + } else { + stream!.add(length.toUnsigned(8)); + } + } + + /// internal method + void writeEncoded(int? tagNumber, List? bytes, [int? flag]) { + if (flag != null) { + writeTag(flag, tagNumber!); + writeLength(bytes!.length); + stream!.addAll(bytes); + } else { + stream!.add(tagNumber!.toUnsigned(8)); + writeLength(bytes!.length); + stream!.addAll(bytes); + } + } + + /// internal method + void writeTag(int flag, int tagNumber) { + if (tagNumber < 31) { + stream!.add((flag | tagNumber).toUnsigned(8)); + } else { + stream!.add((flag | 0x1f).toUnsigned(8)); + if (tagNumber < 128) { + stream!.add(tagNumber.toUnsigned(8)); + } else { + final List bytes = []; + bytes.add((tagNumber & 0x7F).toUnsigned(8)); + do { + tagNumber >>= 7; + bytes.add((tagNumber & 0x7F | 0x80).toUnsigned(8)); + } while (tagNumber > 127 && bytes.length <= 5); + stream!.addAll(bytes.reversed.toList()); + } + } + } + + /// internal method + void writeObject(dynamic obj) { + if (obj == null) { + stream!.add(Asn1Tags.nullValue); + stream!.add(0x00); + } else if (obj is Asn1) { + obj.encode(this); + } else if (obj is Asn1Encode) { + obj.getAsn1()!.encode(this); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid object specified'); + } + } +} + +/// internal class +class DerTag extends Asn1Tag { + /// internal constructor + DerTag(super.tagNumber, super.asn1, [bool? isExplicit]) { + if (isExplicit != null) { + explicit = isExplicit; + } + } + //Implementation + @override + void encode(DerStream stream) { + final List? bytes = object!.getDerEncoded(); + if (explicit!) { + stream.writeEncoded( + tagNumber, + bytes, + Asn1Tags.constructed | Asn1Tags.tagged, + ); + } else { + final int flag = (bytes![0] & Asn1Tags.constructed) | Asn1Tags.tagged; + stream.writeTag(flag, tagNumber!); + stream.stream!.addAll(bytes.sublist(1)); + } + } +} + +/// internal class +class DerUtcTime extends Asn1 { + /// internal constructor + DerUtcTime(List bytes) { + _time = utf8.decode(bytes); + } + //Fields + String? _time; + //Properties + /// internal property + DateTime? get toAdjustedDateTime { + return DateTime.tryParse(adjustedTimeString); + } + + /// internal property + String get adjustedTimeString { + String timeString = _time!; + final String c = timeString.codeUnitAt(0) < '5'.codeUnitAt(0) ? '20' : '19'; + timeString = c + timeString; + return '${timeString.substring(0, 8)}T${timeString.substring(8)}'; + } + + //Implementation + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.utcTime, utf8.encode(_time!)); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerUtcTime) { + return _time == asn1._time; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return _time.hashCode; + } + + @override + String toString() { + return _time!; + } +} + +/// internal class +class DerCatalogue extends Asn1 { + /// internal constructor + DerCatalogue([List? bytes]) { + this.bytes = bytes; + } + + //Implemnetation + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.enumerated, bytes); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerCatalogue) { + return Asn1.areEqual(bytes, asn1.bytes); + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode { + return Asn1.getHashCode(bytes); + } +} + +/// internal class +class DerOctetHelper implements IAsn1Octet { + /// internal constructor + DerOctetHelper(Asn1StreamHelper? stream) { + _stream = stream; + } + //Fields + Asn1StreamHelper? _stream; + //Implementation + @override + PdfStreamReader? getOctetStream() { + return _stream; + } + + @override + Asn1 getAsn1() { + return DerOctet(_stream!.toArray()); + } +} + +/// internal class +class DerUtf8String extends DerString { + /// internal constructor + DerUtf8String(String value) { + _value = value; + } + //Fields + String? _value; + //Implementation + @override + String? getString([List? bytes]) { + return _value; + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.utf8String, utf8.encode(_value!)); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerUtf8String) { + return _value == asn1._value; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _value.hashCode; +} + +/// internal class +class DerTeleText extends DerString { + /// internal constructor + DerTeleText(String value) { + _value = value; + } + //Fields + String? _value; + //Implementation + @override + String? getString([List? bytes]) { + return _value; + } + + @override + // ignore: avoid_renaming_method_parameters + void encode(DerStream stream) { + stream.writeEncoded(Asn1Tags.teleText, toByteArray(_value!)); + } + + /// internal method + List toByteArray(String value) { + final List result = []; + // ignore: avoid_function_literals_in_foreach_calls + value.codeUnits.forEach((int entry) => result.add(entry.toUnsigned(8))); + return result; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object asn1) { + if (asn1 is DerTeleText) { + return _value == asn1._value; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _value.hashCode; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_cipher.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_cipher.dart index 346b5623e..19f6f83db 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_cipher.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_cipher.dart @@ -1,93 +1,93 @@ -import 'dart:typed_data'; - -import 'aes_engine.dart'; -import 'buffered_block_padding_base.dart'; -import 'cipher_block_chaining_mode.dart'; -import 'ipadding.dart'; - -/// internal class -class AesCipher { - //Constructor - /// internal constructor - AesCipher(bool isEncryption, List key, List iv) { - cipher = PaddedCipherMode( - Pkcs7Padding(), - CipherBlockChainingMode(AesEngine()), - ); - final params = - BlockCipherPaddedParameters( - InvalidParameter( - KeyParameter(Uint8List.fromList(key)), - Uint8List.fromList(iv), - ), - null, - ); - cipher.initialize(isEncryption, params); - } - - //Fields - late PaddedCipherMode cipher; - - //Implementation - /// internal method - List? update(List input, int inputOffset, int inputLength) { - final blockSize = cipher.blockSize; - if (input.length % blockSize != 0) { - throw ArgumentError.value( - 'Data length is not a multiple of block size: ${input.length}', - ); - } - - final output = Uint8List(input.length); - int inOffset = 0; - int outOffset = 0; - - while (inOffset < input.length) { - cipher.processingBlock( - Uint8List.fromList(input), - inOffset, - output, - outOffset, - ); - inOffset += blockSize; - outOffset += blockSize; - } - return output; - } -} - -/// internal class -class AesCipherNoPadding { - //Constructor - /// internal constructor - AesCipherNoPadding(bool isEncryption, KeyParameter parameters) { - _cbc = CipherBlockChainingMode(AesEngine()); - _cbc.initialize(isEncryption, parameters); - } - - //Fields - late CipherBlockChainingMode _cbc; - - //Implementation - /// internal method - Uint8List process(Uint8List data) { - final blockSize = _cbc.blockSize!; - if (data.length % blockSize != 0) { - throw ArgumentError.value( - 'Data length is not a multiple of block size: ${data.length}', - ); - } - - final output = Uint8List(data.length); - int inOffset = 0; - int outOffset = 0; - - while (inOffset < data.length) { - _cbc.processingBlock(data, inOffset, output, outOffset); - inOffset += blockSize; - outOffset += blockSize; - } - - return output; - } -} +import 'dart:typed_data'; + +import 'aes_engine.dart'; +import 'buffered_block_padding_base.dart'; +import 'cipher_block_chaining_mode.dart'; +import 'ipadding.dart'; + +/// internal class +class AesCipher { + //Constructor + /// internal constructor + AesCipher(bool isEncryption, List key, List iv) { + cipher = PaddedCipherMode( + Pkcs7Padding(), + CipherBlockChainingMode(AesEngine()), + ); + final params = + BlockCipherPaddedParameters( + InvalidParameter( + KeyParameter(Uint8List.fromList(key)), + Uint8List.fromList(iv), + ), + null, + ); + cipher.initialize(isEncryption, params); + } + + //Fields + late PaddedCipherMode cipher; + + //Implementation + /// internal method + List? update(List input, int inputOffset, int inputLength) { + final blockSize = cipher.blockSize; + if (input.length % blockSize != 0) { + throw ArgumentError.value( + 'Data length is not a multiple of block size: ${input.length}', + ); + } + + final output = Uint8List(input.length); + int inOffset = 0; + int outOffset = 0; + + while (inOffset < input.length) { + cipher.processingBlock( + Uint8List.fromList(input), + inOffset, + output, + outOffset, + ); + inOffset += blockSize; + outOffset += blockSize; + } + return output; + } +} + +/// internal class +class AesCipherNoPadding { + //Constructor + /// internal constructor + AesCipherNoPadding(bool isEncryption, KeyParameter parameters) { + _cbc = CipherBlockChainingMode(AesEngine()); + _cbc.initialize(isEncryption, parameters); + } + + //Fields + late CipherBlockChainingMode _cbc; + + //Implementation + /// internal method + Uint8List process(Uint8List data) { + final blockSize = _cbc.blockSize!; + if (data.length % blockSize != 0) { + throw ArgumentError.value( + 'Data length is not a multiple of block size: ${data.length}', + ); + } + + final output = Uint8List(data.length); + int inOffset = 0; + int outOffset = 0; + + while (inOffset < data.length) { + _cbc.processingBlock(data, inOffset, output, outOffset); + inOffset += blockSize; + outOffset += blockSize; + } + + return output; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart index 67912dc5c..3d6205bd8 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/aes_engine.dart @@ -1,3264 +1,3264 @@ -import 'dart:typed_data'; -import 'cipher_block_chaining_mode.dart'; -import 'ipadding.dart'; - -/// internal class -class AesEngine extends IBlockCipher { - //Constructor - /// internal constructor - AesEngine() { - _initializeConstants(); - } - - static const _blockSize = 16; - static const int _m1 = 0x80808080; - static const int _m2 = 0x7f7f7f7f; - static const int _m3 = 0x0000001b; - static const int _m4 = 0xC0C0C0C0; - static const int _m5 = 0x3f3f3f3f; - - @override - int get blockSize => _blockSize; - - /// internal field - late List>? _key; - - /// internal field - late int rounds; - late bool? _isEncryption; - - /// internal field - late List rcon; - - /// internal field - late List sBox; - - /// internal field - late int mix1; - - /// internal field - late int mix2; - - /// internal field - late int mix3; - - /// internal field - late int c0; - - /// internal field - late int c1; - - /// internal field - late int c2; - - /// internal field - late int c3; - - /// internal field - int? c4; - - /// internal field - late List r0; - - /// internal field - late List r1; - - /// internal field - late List r2; - - /// internal field - late List r3; - - /// internal field - late List sinv; - - /// internal field - late List rinv0; - - /// internal field - late List rinv1; - - /// internal field - late List rinv2; - - /// internal field - late List rinv3; - - //Properties - @override - String get algorithmName => 'AES'; - - @override - bool get isBlock => false; - - List _s = List.empty(); - - //Initialize - @override - void initialize(bool? isEncryption, covariant KeyParameter? parameter) { - if (parameter != null) { - _key = _generateKey(parameter, isEncryption!); - _isEncryption = isEncryption; - } - if (_isEncryption!) { - _s = List.from(sBox); - } else { - _s = List.from(sinv); - } - } - - int _removeBlock(dynamic inp, int offset, Endian endian) { - if (inp is! ByteData) { - inp = ByteData.view(inp.buffer, inp.offsetInBytes, inp.length); - } - return inp.getUint32(offset, endian); - } - - List> _generateKey(KeyParameter params, bool isEncryption) { - final key = params.keys; - final keyLen = key.length; - if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) { - throw ArgumentError('Invalid key length : $keyLen'); - } - final kc = _shiftRight32(keyLen, 2); - rounds = kc + 6; - final w = List.generate(rounds + 1, (int i) => List.filled(4, 0)); - switch (kc) { - case 4: - var col0 = _removeBlock(key, 0, Endian.little); - w[0][0] = col0; - var col1 = _removeBlock(key, 4, Endian.little); - w[0][1] = col1; - var col2 = _removeBlock(key, 8, Endian.little); - w[0][2] = col2; - var col3 = _removeBlock(key, 12, Endian.little); - w[0][3] = col3; - for (var i = 1; i <= 10; ++i) { - final colx = _subWord(_shift(col3, 8)) ^ rcon[i - 1]; - col0 ^= colx; - w[i][0] = col0; - col1 ^= col0; - w[i][1] = col1; - col2 ^= col1; - w[i][2] = col2; - col3 ^= col2; - w[i][3] = col3; - } - break; - case 6: - var col0 = _removeBlock(key, 0, Endian.little); - w[0][0] = col0; - var col1 = _removeBlock(key, 4, Endian.little); - w[0][1] = col1; - var col2 = _removeBlock(key, 8, Endian.little); - w[0][2] = col2; - var col3 = _removeBlock(key, 12, Endian.little); - w[0][3] = col3; - var col4 = _removeBlock(key, 16, Endian.little); - var col5 = _removeBlock(key, 20, Endian.little); - int i = 1, rcon = 1, colx; - for (;;) { - w[i][0] = col4; - w[i][1] = col5; - colx = _subWord(_shift(col5, 8)) ^ rcon; - rcon <<= 1; - col0 ^= colx; - w[i][2] = col0; - col1 ^= col0; - w[i][3] = col1; - col2 ^= col1; - w[i + 1][0] = col2; - col3 ^= col2; - w[i + 1][1] = col3; - col4 ^= col3; - w[i + 1][2] = col4; - col5 ^= col4; - w[i + 1][3] = col5; - colx = _subWord(_shift(col5, 8)) ^ rcon; - rcon <<= 1; - col0 ^= colx; - w[i + 2][0] = col0; - col1 ^= col0; - w[i + 2][1] = col1; - col2 ^= col1; - w[i + 2][2] = col2; - col3 ^= col2; - w[i + 2][3] = col3; - if ((i += 3) >= 13) { - break; - } - col4 ^= col3; - col5 ^= col4; - } - break; - case 8: - { - var col0 = _removeBlock(key, 0, Endian.little); - w[0][0] = col0; - var col1 = _removeBlock(key, 4, Endian.little); - w[0][1] = col1; - var col2 = _removeBlock(key, 8, Endian.little); - w[0][2] = col2; - var col3 = _removeBlock(key, 12, Endian.little); - w[0][3] = col3; - var col4 = _removeBlock(key, 16, Endian.little); - w[1][0] = col4; - var col5 = _removeBlock(key, 20, Endian.little); - w[1][1] = col5; - var col6 = _removeBlock(key, 24, Endian.little); - w[1][2] = col6; - var col7 = _removeBlock(key, 28, Endian.little); - w[1][3] = col7; - int i = 2, rcon = 1, colx; - for (;;) { - colx = _subWord(_shift(col7, 8)) ^ rcon; - rcon <<= 1; - col0 ^= colx; - w[i][0] = col0; - col1 ^= col0; - w[i][1] = col1; - col2 ^= col1; - w[i][2] = col2; - col3 ^= col2; - w[i][3] = col3; - ++i; - if (i >= 15) { - break; - } - colx = _subWord(col3); - col4 ^= colx; - w[i][0] = col4; - col5 ^= col4; - w[i][1] = col5; - col6 ^= col5; - w[i][2] = col6; - col7 ^= col6; - w[i][3] = col7; - ++i; - } - break; - } - default: - { - throw StateError('Invalid key length: ${key.lengthInBytes}'); - } - } - if (!isEncryption) { - for (var j = 1; j < rounds; j++) { - for (var i = 0; i < 4; i++) { - w[j][i] = _inverseMultiply(w[j][i]); - } - } - } - return w; - } - - @override - int processingBlock([ - Uint8List? inputBytes, - int? inputOffset, - //need to be unit8list - Uint8List? outputBytes, - //List? output, - int? outputOffset, - ]) { - if ((inputOffset! + (32 / 2)) > inputBytes!.lengthInBytes) { - throw ArgumentError( - 'Invalid length in input buffer : ${inputBytes.lengthInBytes}', - ); - } - - if ((outputOffset! + (32 / 2)) > outputBytes!.lengthInBytes) { - throw ArgumentError( - 'Invalid length in output buffer : ${outputBytes.lengthInBytes}', - ); - } - if (_isEncryption!) { - encryptBlock(inputBytes, inputOffset, outputBytes, outputOffset, _key!); - } else { - decryptBlock(inputBytes, inputOffset, outputBytes, outputOffset, _key!); - } - - return _blockSize; - } - - @override - void reset() {} - - /// internal method - void encryptBlock( - input, - int inOff, - Uint8List out, - int outOff, - List> kw, - ) { - var c0 = _removeBlock(input, inOff + 0, Endian.little); - var c1 = _removeBlock(input, inOff + 4, Endian.little); - var c2 = _removeBlock(input, inOff + 8, Endian.little); - var c3 = _removeBlock(input, inOff + 12, Endian.little); - - var t0 = c0 ^ kw[0][0]; - var t1 = c1 ^ kw[0][1]; - var t2 = c2 ^ kw[0][2]; - - int r = 1, r01, r1, r2, r3 = c3 ^ kw[0][3]; - - while (r < rounds - 1) { - r01 = - r0[t0 & 255] ^ - _shift(r0[(t1 >> 8) & 255], 24) ^ - _shift(r0[(t2 >> 16) & 255], 16) ^ - _shift(r0[(r3 >> 24) & 255], 8) ^ - kw[r][0]; - r1 = - r0[t1 & 255] ^ - _shift(r0[(t2 >> 8) & 255], 24) ^ - _shift(r0[(r3 >> 16) & 255], 16) ^ - _shift(r0[(t0 >> 24) & 255], 8) ^ - kw[r][1]; - r2 = - r0[t2 & 255] ^ - _shift(r0[(r3 >> 8) & 255], 24) ^ - _shift(r0[(t0 >> 16) & 255], 16) ^ - _shift(r0[(t1 >> 24) & 255], 8) ^ - kw[r][2]; - r3 = - r0[r3 & 255] ^ - _shift(r0[(t0 >> 8) & 255], 24) ^ - _shift(r0[(t1 >> 16) & 255], 16) ^ - _shift(r0[(t2 >> 24) & 255], 8) ^ - kw[r++][3]; - t0 = - r0[r01 & 255] ^ - _shift(r0[(r1 >> 8) & 255], 24) ^ - _shift(r0[(r2 >> 16) & 255], 16) ^ - _shift(r0[(r3 >> 24) & 255], 8) ^ - kw[r][0]; - t1 = - r0[r1 & 255] ^ - _shift(r0[(r2 >> 8) & 255], 24) ^ - _shift(r0[(r3 >> 16) & 255], 16) ^ - _shift(r0[(r01 >> 24) & 255], 8) ^ - kw[r][1]; - t2 = - r0[r2 & 255] ^ - _shift(r0[(r3 >> 8) & 255], 24) ^ - _shift(r0[(r01 >> 16) & 255], 16) ^ - _shift(r0[(r1 >> 24) & 255], 8) ^ - kw[r][2]; - r3 = - r0[r3 & 255] ^ - _shift(r0[(r01 >> 8) & 255], 24) ^ - _shift(r0[(r1 >> 16) & 255], 16) ^ - _shift(r0[(r2 >> 24) & 255], 8) ^ - kw[r++][3]; - } - - r01 = - r0[t0 & 255] ^ - _shift(r0[(t1 >> 8) & 255], 24) ^ - _shift(r0[(t2 >> 16) & 255], 16) ^ - _shift(r0[(r3 >> 24) & 255], 8) ^ - kw[r][0]; - r1 = - r0[t1 & 255] ^ - _shift(r0[(t2 >> 8) & 255], 24) ^ - _shift(r0[(r3 >> 16) & 255], 16) ^ - _shift(r0[(t0 >> 24) & 255], 8) ^ - kw[r][1]; - r2 = - r0[t2 & 255] ^ - _shift(r0[(r3 >> 8) & 255], 24) ^ - _shift(r0[(t0 >> 16) & 255], 16) ^ - _shift(r0[(t1 >> 24) & 255], 8) ^ - kw[r][2]; - r3 = - r0[r3 & 255] ^ - _shift(r0[(t0 >> 8) & 255], 24) ^ - _shift(r0[(t1 >> 16) & 255], 16) ^ - _shift(r0[(t2 >> 24) & 255], 8) ^ - kw[r++][3]; - - c0 = - (sBox[r01 & 255] & 255) ^ - ((sBox[(r1 >> 8) & 255] & 255) << 8) ^ - ((_s[(r2 >> 16) & 255] & 255) << 16) ^ - (_s[(r3 >> 24) & 255] << 24) ^ - kw[r][0]; - c1 = - (_s[r1 & 255] & 255) ^ - ((sBox[(r2 >> 8) & 255] & 255) << 8) ^ - ((sBox[(r3 >> 16) & 255] & 255) << 16) ^ - (_s[(r01 >> 24) & 255] << 24) ^ - kw[r][1]; - c2 = - (_s[r2 & 255] & 255) ^ - ((sBox[(r3 >> 8) & 255] & 255) << 8) ^ - ((sBox[(r01 >> 16) & 255] & 255) << 16) ^ - (sBox[(r1 >> 24) & 255] << 24) ^ - kw[r][2]; - c3 = - (_s[r3 & 255] & 255) ^ - ((_s[(r01 >> 8) & 255] & 255) << 8) ^ - ((_s[(r1 >> 16) & 255] & 255) << 16) ^ - (sBox[(r2 >> 24) & 255] << 24) ^ - kw[r][3]; - - _addBlock(c0, out, outOff + 0, Endian.little); - _addBlock(c1, out, outOff + 4, Endian.little); - _addBlock(c2, out, outOff + 8, Endian.little); - _addBlock(c3, out, outOff + 12, Endian.little); - } - - /// internal method - void decryptBlock( - input, - int inOff, - Uint8List out, - int outOff, - List> kw, - ) { - var c0 = _removeBlock(input, inOff + 0, Endian.little); - var c1 = _removeBlock(input, inOff + 4, Endian.little); - var c2 = _removeBlock(input, inOff + 8, Endian.little); - var c3 = _removeBlock(input, inOff + 12, Endian.little); - - var t0 = c0 ^ kw[rounds][0]; - var t1 = c1 ^ kw[rounds][1]; - var t2 = c2 ^ kw[rounds][2]; - - int r = rounds - 1, r01, r1, r2, r3 = c3 ^ kw[rounds][3]; - - while (r > 1) { - r01 = - rinv0[t0 & 255] ^ - _shift(rinv0[(r3 >> 8) & 255], 24) ^ - _shift(rinv0[(t2 >> 16) & 255], 16) ^ - _shift(rinv0[(t1 >> 24) & 255], 8) ^ - kw[r][0]; - r1 = - rinv0[t1 & 255] ^ - _shift(rinv0[(t0 >> 8) & 255], 24) ^ - _shift(rinv0[(r3 >> 16) & 255], 16) ^ - _shift(rinv0[(t2 >> 24) & 255], 8) ^ - kw[r][1]; - r2 = - rinv0[t2 & 255] ^ - _shift(rinv0[(t1 >> 8) & 255], 24) ^ - _shift(rinv0[(t0 >> 16) & 255], 16) ^ - _shift(rinv0[(r3 >> 24) & 255], 8) ^ - kw[r][2]; - r3 = - rinv0[r3 & 255] ^ - _shift(rinv0[(t2 >> 8) & 255], 24) ^ - _shift(rinv0[(t1 >> 16) & 255], 16) ^ - _shift(rinv0[(t0 >> 24) & 255], 8) ^ - kw[r--][3]; - t0 = - rinv0[r01 & 255] ^ - _shift(rinv0[(r3 >> 8) & 255], 24) ^ - _shift(rinv0[(r2 >> 16) & 255], 16) ^ - _shift(rinv0[(r1 >> 24) & 255], 8) ^ - kw[r][0]; - t1 = - rinv0[r1 & 255] ^ - _shift(rinv0[(r01 >> 8) & 255], 24) ^ - _shift(rinv0[(r3 >> 16) & 255], 16) ^ - _shift(rinv0[(r2 >> 24) & 255], 8) ^ - kw[r][1]; - t2 = - rinv0[r2 & 255] ^ - _shift(rinv0[(r1 >> 8) & 255], 24) ^ - _shift(rinv0[(r01 >> 16) & 255], 16) ^ - _shift(rinv0[(r3 >> 24) & 255], 8) ^ - kw[r][2]; - r3 = - rinv0[r3 & 255] ^ - _shift(rinv0[(r2 >> 8) & 255], 24) ^ - _shift(rinv0[(r1 >> 16) & 255], 16) ^ - _shift(rinv0[(r01 >> 24) & 255], 8) ^ - kw[r--][3]; - } - - r01 = - rinv0[t0 & 255] ^ - _shift(rinv0[(r3 >> 8) & 255], 24) ^ - _shift(rinv0[(t2 >> 16) & 255], 16) ^ - _shift(rinv0[(t1 >> 24) & 255], 8) ^ - kw[r][0]; - r1 = - rinv0[t1 & 255] ^ - _shift(rinv0[(t0 >> 8) & 255], 24) ^ - _shift(rinv0[(r3 >> 16) & 255], 16) ^ - _shift(rinv0[(t2 >> 24) & 255], 8) ^ - kw[r][1]; - r2 = - rinv0[t2 & 255] ^ - _shift(rinv0[(t1 >> 8) & 255], 24) ^ - _shift(rinv0[(t0 >> 16) & 255], 16) ^ - _shift(rinv0[(r3 >> 24) & 255], 8) ^ - kw[r][2]; - r3 = - rinv0[r3 & 255] ^ - _shift(rinv0[(t2 >> 8) & 255], 24) ^ - _shift(rinv0[(t1 >> 16) & 255], 16) ^ - _shift(rinv0[(t0 >> 24) & 255], 8) ^ - kw[r][3]; - - c0 = - (sinv[r01 & 255] & 255) ^ - ((_s[(r3 >> 8) & 255] & 255) << 8) ^ - ((_s[(r2 >> 16) & 255] & 255) << 16) ^ - (sinv[(r1 >> 24) & 255] << 24) ^ - kw[0][0]; - c1 = - (_s[r1 & 255] & 255) ^ - ((_s[(r01 >> 8) & 255] & 255) << 8) ^ - ((sinv[(r3 >> 16) & 255] & 255) << 16) ^ - (_s[(r2 >> 24) & 255] << 24) ^ - kw[0][1]; - c2 = - (_s[r2 & 255] & 255) ^ - ((sinv[(r1 >> 8) & 255] & 255) << 8) ^ - ((sinv[(r01 >> 16) & 255] & 255) << 16) ^ - (_s[(r3 >> 24) & 255] << 24) ^ - kw[0][2]; - c3 = - (sinv[r3 & 255] & 255) ^ - ((_s[(r2 >> 8) & 255] & 255) << 8) ^ - ((_s[(r1 >> 16) & 255] & 255) << 16) ^ - (_s[(r01 >> 24) & 255] << 24) ^ - kw[0][3]; - - _addBlock(c0, out, outOff + 0, Endian.little); - _addBlock(c1, out, outOff + 4, Endian.little); - _addBlock(c2, out, outOff + 8, Endian.little); - _addBlock(c3, out, outOff + 12, Endian.little); - } - - void _addBlock(int x, dynamic out, int offset, Endian endian) { - assert((x >= 0) && (x <= _mask_32)); - if (out is! ByteData) { - out = ByteData.view( - out.buffer as ByteBuffer, - out.offsetInBytes, - out.length, - ); - } - out.setUint32(offset, x, endian); - } - - int _shift(int r, int shift) => _rotateRight32(r, shift); - - int _rotateRight32(int x, int n) { - assert(n >= 0); - assert((x >= 0) && (x <= _mask_32)); - n &= _mask_5; - return (x >> n) | _shiftLeft32(x, 32 - n); - } - - int _shiftRight32(int x, int n) { - assert((x >= 0) && (x <= _mask_32)); - n &= _mask_5; - return x >> n; - } - - int _shiftLeft32(int x, int n) { - assert((x >= 0) && (x <= _mask_32)); - n &= _mask_5; - x &= _mask_bits[n]; - return (x << n) & _mask_32; - } - - int _subWord(int x) { - return sBox[x & 255] & 255 | - ((sBox[(x >> 8) & 255] & 255) << 8) | - ((sBox[(x >> 16) & 255] & 255) << 16) | - sBox[(x >> 24) & 255] << 24; - } - - int _inverseMultiply(int x) { - int t0, t1; - t0 = x; - t1 = t0 ^ _shift(t0, 8); - t0 ^= _xMultiply(t1); - t1 ^= _x2Multiply(t0); - t0 ^= t1 ^ _shift(t1, 16); - return t0; - } - - int _xMultiply(int x) { - final lsr = _shiftRight32(x & _m1, 7); - return ((x & _m2) << 1) ^ lsr * _m3; - } - - int _x2Multiply(int x) { - final t0 = _shiftLeft32(x & _m5, 2); - var t1 = x & _m4; - t1 ^= _shiftRight32(t1, 1); - return t0 ^ _shiftRight32(t1, 2) ^ _shiftRight32(t1, 5); - } - - void _initializeConstants() { - rounds = 0; - _isEncryption = false; - mix1 = 0x80808080; - mix2 = 0x7f7f7f7f; - mix3 = 0x0000001b; - c0 = 0; - c1 = 0; - c2 = 0; - c3 = 0; - rcon = [ - 0x01, - 0x02, - 0x04, - 0x08, - 0x10, - 0x20, - 0x40, - 0x80, - 0x1b, - 0x36, - 0x6c, - 0xd8, - 0xab, - 0x4d, - 0x9a, - 0x2f, - 0x5e, - 0xbc, - 0x63, - 0xc6, - 0x97, - 0x35, - 0x6a, - 0xd4, - 0xb3, - 0x7d, - 0xfa, - 0xef, - 0xc5, - 0x91, - ]; - sBox = [ - 99, - 124, - 119, - 123, - 242, - 107, - 111, - 197, - 48, - 1, - 103, - 43, - 254, - 215, - 171, - 118, - 202, - 130, - 201, - 125, - 250, - 89, - 71, - 240, - 173, - 212, - 162, - 175, - 156, - 164, - 114, - 192, - 183, - 253, - 147, - 38, - 54, - 63, - 247, - 204, - 52, - 165, - 229, - 241, - 113, - 216, - 49, - 21, - 4, - 199, - 35, - 195, - 24, - 150, - 5, - 154, - 7, - 18, - 128, - 226, - 235, - 39, - 178, - 117, - 9, - 131, - 44, - 26, - 27, - 110, - 90, - 160, - 82, - 59, - 214, - 179, - 41, - 227, - 47, - 132, - 83, - 209, - 0, - 237, - 32, - 252, - 177, - 91, - 106, - 203, - 190, - 57, - 74, - 76, - 88, - 207, - 208, - 239, - 170, - 251, - 67, - 77, - 51, - 133, - 69, - 249, - 2, - 127, - 80, - 60, - 159, - 168, - 81, - 163, - 64, - 143, - 146, - 157, - 56, - 245, - 188, - 182, - 218, - 33, - 16, - 255, - 243, - 210, - 205, - 12, - 19, - 236, - 95, - 151, - 68, - 23, - 196, - 167, - 126, - 61, - 100, - 93, - 25, - 115, - 96, - 129, - 79, - 220, - 34, - 42, - 144, - 136, - 70, - 238, - 184, - 20, - 222, - 94, - 11, - 219, - 224, - 50, - 58, - 10, - 73, - 6, - 36, - 92, - 194, - 211, - 172, - 98, - 145, - 149, - 228, - 121, - 231, - 200, - 55, - 109, - 141, - 213, - 78, - 169, - 108, - 86, - 244, - 234, - 101, - 122, - 174, - 8, - 186, - 120, - 37, - 46, - 28, - 166, - 180, - 198, - 232, - 221, - 116, - 31, - 75, - 189, - 139, - 138, - 112, - 62, - 181, - 102, - 72, - 3, - 246, - 14, - 97, - 53, - 87, - 185, - 134, - 193, - 29, - 158, - 225, - 248, - 152, - 17, - 105, - 217, - 142, - 148, - 155, - 30, - 135, - 233, - 206, - 85, - 40, - 223, - 140, - 161, - 137, - 13, - 191, - 230, - 66, - 104, - 65, - 153, - 45, - 15, - 176, - 84, - 187, - 22, - ]; - r0 = [ - 0xa56363c6, - 0x847c7cf8, - 0x997777ee, - 0x8d7b7bf6, - 0x0df2f2ff, - 0xbd6b6bd6, - 0xb16f6fde, - 0x54c5c591, - 0x50303060, - 0x03010102, - 0xa96767ce, - 0x7d2b2b56, - 0x19fefee7, - 0x62d7d7b5, - 0xe6abab4d, - 0x9a7676ec, - 0x45caca8f, - 0x9d82821f, - 0x40c9c989, - 0x877d7dfa, - 0x15fafaef, - 0xeb5959b2, - 0xc947478e, - 0x0bf0f0fb, - 0xecadad41, - 0x67d4d4b3, - 0xfda2a25f, - 0xeaafaf45, - 0xbf9c9c23, - 0xf7a4a453, - 0x967272e4, - 0x5bc0c09b, - 0xc2b7b775, - 0x1cfdfde1, - 0xae93933d, - 0x6a26264c, - 0x5a36366c, - 0x413f3f7e, - 0x02f7f7f5, - 0x4fcccc83, - 0x5c343468, - 0xf4a5a551, - 0x34e5e5d1, - 0x08f1f1f9, - 0x937171e2, - 0x73d8d8ab, - 0x53313162, - 0x3f15152a, - 0x0c040408, - 0x52c7c795, - 0x65232346, - 0x5ec3c39d, - 0x28181830, - 0xa1969637, - 0x0f05050a, - 0xb59a9a2f, - 0x0907070e, - 0x36121224, - 0x9b80801b, - 0x3de2e2df, - 0x26ebebcd, - 0x6927274e, - 0xcdb2b27f, - 0x9f7575ea, - 0x1b090912, - 0x9e83831d, - 0x742c2c58, - 0x2e1a1a34, - 0x2d1b1b36, - 0xb26e6edc, - 0xee5a5ab4, - 0xfba0a05b, - 0xf65252a4, - 0x4d3b3b76, - 0x61d6d6b7, - 0xceb3b37d, - 0x7b292952, - 0x3ee3e3dd, - 0x712f2f5e, - 0x97848413, - 0xf55353a6, - 0x68d1d1b9, - 0x00000000, - 0x2cededc1, - 0x60202040, - 0x1ffcfce3, - 0xc8b1b179, - 0xed5b5bb6, - 0xbe6a6ad4, - 0x46cbcb8d, - 0xd9bebe67, - 0x4b393972, - 0xde4a4a94, - 0xd44c4c98, - 0xe85858b0, - 0x4acfcf85, - 0x6bd0d0bb, - 0x2aefefc5, - 0xe5aaaa4f, - 0x16fbfbed, - 0xc5434386, - 0xd74d4d9a, - 0x55333366, - 0x94858511, - 0xcf45458a, - 0x10f9f9e9, - 0x06020204, - 0x817f7ffe, - 0xf05050a0, - 0x443c3c78, - 0xba9f9f25, - 0xe3a8a84b, - 0xf35151a2, - 0xfea3a35d, - 0xc0404080, - 0x8a8f8f05, - 0xad92923f, - 0xbc9d9d21, - 0x48383870, - 0x04f5f5f1, - 0xdfbcbc63, - 0xc1b6b677, - 0x75dadaaf, - 0x63212142, - 0x30101020, - 0x1affffe5, - 0x0ef3f3fd, - 0x6dd2d2bf, - 0x4ccdcd81, - 0x140c0c18, - 0x35131326, - 0x2fececc3, - 0xe15f5fbe, - 0xa2979735, - 0xcc444488, - 0x3917172e, - 0x57c4c493, - 0xf2a7a755, - 0x827e7efc, - 0x473d3d7a, - 0xac6464c8, - 0xe75d5dba, - 0x2b191932, - 0x957373e6, - 0xa06060c0, - 0x98818119, - 0xd14f4f9e, - 0x7fdcdca3, - 0x66222244, - 0x7e2a2a54, - 0xab90903b, - 0x8388880b, - 0xca46468c, - 0x29eeeec7, - 0xd3b8b86b, - 0x3c141428, - 0x79dedea7, - 0xe25e5ebc, - 0x1d0b0b16, - 0x76dbdbad, - 0x3be0e0db, - 0x56323264, - 0x4e3a3a74, - 0x1e0a0a14, - 0xdb494992, - 0x0a06060c, - 0x6c242448, - 0xe45c5cb8, - 0x5dc2c29f, - 0x6ed3d3bd, - 0xefacac43, - 0xa66262c4, - 0xa8919139, - 0xa4959531, - 0x37e4e4d3, - 0x8b7979f2, - 0x32e7e7d5, - 0x43c8c88b, - 0x5937376e, - 0xb76d6dda, - 0x8c8d8d01, - 0x64d5d5b1, - 0xd24e4e9c, - 0xe0a9a949, - 0xb46c6cd8, - 0xfa5656ac, - 0x07f4f4f3, - 0x25eaeacf, - 0xaf6565ca, - 0x8e7a7af4, - 0xe9aeae47, - 0x18080810, - 0xd5baba6f, - 0x887878f0, - 0x6f25254a, - 0x722e2e5c, - 0x241c1c38, - 0xf1a6a657, - 0xc7b4b473, - 0x51c6c697, - 0x23e8e8cb, - 0x7cdddda1, - 0x9c7474e8, - 0x211f1f3e, - 0xdd4b4b96, - 0xdcbdbd61, - 0x868b8b0d, - 0x858a8a0f, - 0x907070e0, - 0x423e3e7c, - 0xc4b5b571, - 0xaa6666cc, - 0xd8484890, - 0x05030306, - 0x01f6f6f7, - 0x120e0e1c, - 0xa36161c2, - 0x5f35356a, - 0xf95757ae, - 0xd0b9b969, - 0x91868617, - 0x58c1c199, - 0x271d1d3a, - 0xb99e9e27, - 0x38e1e1d9, - 0x13f8f8eb, - 0xb398982b, - 0x33111122, - 0xbb6969d2, - 0x70d9d9a9, - 0x898e8e07, - 0xa7949433, - 0xb69b9b2d, - 0x221e1e3c, - 0x92878715, - 0x20e9e9c9, - 0x49cece87, - 0xff5555aa, - 0x78282850, - 0x7adfdfa5, - 0x8f8c8c03, - 0xf8a1a159, - 0x80898909, - 0x170d0d1a, - 0xdabfbf65, - 0x31e6e6d7, - 0xc6424284, - 0xb86868d0, - 0xc3414182, - 0xb0999929, - 0x772d2d5a, - 0x110f0f1e, - 0xcbb0b07b, - 0xfc5454a8, - 0xd6bbbb6d, - 0x3a16162c, - ]; - r1 = [ - 0x6363c6a5, - 0x7c7cf884, - 0x7777ee99, - 0x7b7bf68d, - 0xf2f2ff0d, - 0x6b6bd6bd, - 0x6f6fdeb1, - 0xc5c59154, - 0x30306050, - 0x01010203, - 0x6767cea9, - 0x2b2b567d, - 0xfefee719, - 0xd7d7b562, - 0xabab4de6, - 0x7676ec9a, - 0xcaca8f45, - 0x82821f9d, - 0xc9c98940, - 0x7d7dfa87, - 0xfafaef15, - 0x5959b2eb, - 0x47478ec9, - 0xf0f0fb0b, - 0xadad41ec, - 0xd4d4b367, - 0xa2a25ffd, - 0xafaf45ea, - 0x9c9c23bf, - 0xa4a453f7, - 0x7272e496, - 0xc0c09b5b, - 0xb7b775c2, - 0xfdfde11c, - 0x93933dae, - 0x26264c6a, - 0x36366c5a, - 0x3f3f7e41, - 0xf7f7f502, - 0xcccc834f, - 0x3434685c, - 0xa5a551f4, - 0xe5e5d134, - 0xf1f1f908, - 0x7171e293, - 0xd8d8ab73, - 0x31316253, - 0x15152a3f, - 0x0404080c, - 0xc7c79552, - 0x23234665, - 0xc3c39d5e, - 0x18183028, - 0x969637a1, - 0x05050a0f, - 0x9a9a2fb5, - 0x07070e09, - 0x12122436, - 0x80801b9b, - 0xe2e2df3d, - 0xebebcd26, - 0x27274e69, - 0xb2b27fcd, - 0x7575ea9f, - 0x0909121b, - 0x83831d9e, - 0x2c2c5874, - 0x1a1a342e, - 0x1b1b362d, - 0x6e6edcb2, - 0x5a5ab4ee, - 0xa0a05bfb, - 0x5252a4f6, - 0x3b3b764d, - 0xd6d6b761, - 0xb3b37dce, - 0x2929527b, - 0xe3e3dd3e, - 0x2f2f5e71, - 0x84841397, - 0x5353a6f5, - 0xd1d1b968, - 0x00000000, - 0xededc12c, - 0x20204060, - 0xfcfce31f, - 0xb1b179c8, - 0x5b5bb6ed, - 0x6a6ad4be, - 0xcbcb8d46, - 0xbebe67d9, - 0x3939724b, - 0x4a4a94de, - 0x4c4c98d4, - 0x5858b0e8, - 0xcfcf854a, - 0xd0d0bb6b, - 0xefefc52a, - 0xaaaa4fe5, - 0xfbfbed16, - 0x434386c5, - 0x4d4d9ad7, - 0x33336655, - 0x85851194, - 0x45458acf, - 0xf9f9e910, - 0x02020406, - 0x7f7ffe81, - 0x5050a0f0, - 0x3c3c7844, - 0x9f9f25ba, - 0xa8a84be3, - 0x5151a2f3, - 0xa3a35dfe, - 0x404080c0, - 0x8f8f058a, - 0x92923fad, - 0x9d9d21bc, - 0x38387048, - 0xf5f5f104, - 0xbcbc63df, - 0xb6b677c1, - 0xdadaaf75, - 0x21214263, - 0x10102030, - 0xffffe51a, - 0xf3f3fd0e, - 0xd2d2bf6d, - 0xcdcd814c, - 0x0c0c1814, - 0x13132635, - 0xececc32f, - 0x5f5fbee1, - 0x979735a2, - 0x444488cc, - 0x17172e39, - 0xc4c49357, - 0xa7a755f2, - 0x7e7efc82, - 0x3d3d7a47, - 0x6464c8ac, - 0x5d5dbae7, - 0x1919322b, - 0x7373e695, - 0x6060c0a0, - 0x81811998, - 0x4f4f9ed1, - 0xdcdca37f, - 0x22224466, - 0x2a2a547e, - 0x90903bab, - 0x88880b83, - 0x46468cca, - 0xeeeec729, - 0xb8b86bd3, - 0x1414283c, - 0xdedea779, - 0x5e5ebce2, - 0x0b0b161d, - 0xdbdbad76, - 0xe0e0db3b, - 0x32326456, - 0x3a3a744e, - 0x0a0a141e, - 0x494992db, - 0x06060c0a, - 0x2424486c, - 0x5c5cb8e4, - 0xc2c29f5d, - 0xd3d3bd6e, - 0xacac43ef, - 0x6262c4a6, - 0x919139a8, - 0x959531a4, - 0xe4e4d337, - 0x7979f28b, - 0xe7e7d532, - 0xc8c88b43, - 0x37376e59, - 0x6d6ddab7, - 0x8d8d018c, - 0xd5d5b164, - 0x4e4e9cd2, - 0xa9a949e0, - 0x6c6cd8b4, - 0x5656acfa, - 0xf4f4f307, - 0xeaeacf25, - 0x6565caaf, - 0x7a7af48e, - 0xaeae47e9, - 0x08081018, - 0xbaba6fd5, - 0x7878f088, - 0x25254a6f, - 0x2e2e5c72, - 0x1c1c3824, - 0xa6a657f1, - 0xb4b473c7, - 0xc6c69751, - 0xe8e8cb23, - 0xdddda17c, - 0x7474e89c, - 0x1f1f3e21, - 0x4b4b96dd, - 0xbdbd61dc, - 0x8b8b0d86, - 0x8a8a0f85, - 0x7070e090, - 0x3e3e7c42, - 0xb5b571c4, - 0x6666ccaa, - 0x484890d8, - 0x03030605, - 0xf6f6f701, - 0x0e0e1c12, - 0x6161c2a3, - 0x35356a5f, - 0x5757aef9, - 0xb9b969d0, - 0x86861791, - 0xc1c19958, - 0x1d1d3a27, - 0x9e9e27b9, - 0xe1e1d938, - 0xf8f8eb13, - 0x98982bb3, - 0x11112233, - 0x6969d2bb, - 0xd9d9a970, - 0x8e8e0789, - 0x949433a7, - 0x9b9b2db6, - 0x1e1e3c22, - 0x87871592, - 0xe9e9c920, - 0xcece8749, - 0x5555aaff, - 0x28285078, - 0xdfdfa57a, - 0x8c8c038f, - 0xa1a159f8, - 0x89890980, - 0x0d0d1a17, - 0xbfbf65da, - 0xe6e6d731, - 0x424284c6, - 0x6868d0b8, - 0x414182c3, - 0x999929b0, - 0x2d2d5a77, - 0x0f0f1e11, - 0xb0b07bcb, - 0x5454a8fc, - 0xbbbb6dd6, - 0x16162c3a, - ]; - r2 = [ - 0x63c6a563, - 0x7cf8847c, - 0x77ee9977, - 0x7bf68d7b, - 0xf2ff0df2, - 0x6bd6bd6b, - 0x6fdeb16f, - 0xc59154c5, - 0x30605030, - 0x01020301, - 0x67cea967, - 0x2b567d2b, - 0xfee719fe, - 0xd7b562d7, - 0xab4de6ab, - 0x76ec9a76, - 0xca8f45ca, - 0x821f9d82, - 0xc98940c9, - 0x7dfa877d, - 0xfaef15fa, - 0x59b2eb59, - 0x478ec947, - 0xf0fb0bf0, - 0xad41ecad, - 0xd4b367d4, - 0xa25ffda2, - 0xaf45eaaf, - 0x9c23bf9c, - 0xa453f7a4, - 0x72e49672, - 0xc09b5bc0, - 0xb775c2b7, - 0xfde11cfd, - 0x933dae93, - 0x264c6a26, - 0x366c5a36, - 0x3f7e413f, - 0xf7f502f7, - 0xcc834fcc, - 0x34685c34, - 0xa551f4a5, - 0xe5d134e5, - 0xf1f908f1, - 0x71e29371, - 0xd8ab73d8, - 0x31625331, - 0x152a3f15, - 0x04080c04, - 0xc79552c7, - 0x23466523, - 0xc39d5ec3, - 0x18302818, - 0x9637a196, - 0x050a0f05, - 0x9a2fb59a, - 0x070e0907, - 0x12243612, - 0x801b9b80, - 0xe2df3de2, - 0xebcd26eb, - 0x274e6927, - 0xb27fcdb2, - 0x75ea9f75, - 0x09121b09, - 0x831d9e83, - 0x2c58742c, - 0x1a342e1a, - 0x1b362d1b, - 0x6edcb26e, - 0x5ab4ee5a, - 0xa05bfba0, - 0x52a4f652, - 0x3b764d3b, - 0xd6b761d6, - 0xb37dceb3, - 0x29527b29, - 0xe3dd3ee3, - 0x2f5e712f, - 0x84139784, - 0x53a6f553, - 0xd1b968d1, - 0x00000000, - 0xedc12ced, - 0x20406020, - 0xfce31ffc, - 0xb179c8b1, - 0x5bb6ed5b, - 0x6ad4be6a, - 0xcb8d46cb, - 0xbe67d9be, - 0x39724b39, - 0x4a94de4a, - 0x4c98d44c, - 0x58b0e858, - 0xcf854acf, - 0xd0bb6bd0, - 0xefc52aef, - 0xaa4fe5aa, - 0xfbed16fb, - 0x4386c543, - 0x4d9ad74d, - 0x33665533, - 0x85119485, - 0x458acf45, - 0xf9e910f9, - 0x02040602, - 0x7ffe817f, - 0x50a0f050, - 0x3c78443c, - 0x9f25ba9f, - 0xa84be3a8, - 0x51a2f351, - 0xa35dfea3, - 0x4080c040, - 0x8f058a8f, - 0x923fad92, - 0x9d21bc9d, - 0x38704838, - 0xf5f104f5, - 0xbc63dfbc, - 0xb677c1b6, - 0xdaaf75da, - 0x21426321, - 0x10203010, - 0xffe51aff, - 0xf3fd0ef3, - 0xd2bf6dd2, - 0xcd814ccd, - 0x0c18140c, - 0x13263513, - 0xecc32fec, - 0x5fbee15f, - 0x9735a297, - 0x4488cc44, - 0x172e3917, - 0xc49357c4, - 0xa755f2a7, - 0x7efc827e, - 0x3d7a473d, - 0x64c8ac64, - 0x5dbae75d, - 0x19322b19, - 0x73e69573, - 0x60c0a060, - 0x81199881, - 0x4f9ed14f, - 0xdca37fdc, - 0x22446622, - 0x2a547e2a, - 0x903bab90, - 0x880b8388, - 0x468cca46, - 0xeec729ee, - 0xb86bd3b8, - 0x14283c14, - 0xdea779de, - 0x5ebce25e, - 0x0b161d0b, - 0xdbad76db, - 0xe0db3be0, - 0x32645632, - 0x3a744e3a, - 0x0a141e0a, - 0x4992db49, - 0x060c0a06, - 0x24486c24, - 0x5cb8e45c, - 0xc29f5dc2, - 0xd3bd6ed3, - 0xac43efac, - 0x62c4a662, - 0x9139a891, - 0x9531a495, - 0xe4d337e4, - 0x79f28b79, - 0xe7d532e7, - 0xc88b43c8, - 0x376e5937, - 0x6ddab76d, - 0x8d018c8d, - 0xd5b164d5, - 0x4e9cd24e, - 0xa949e0a9, - 0x6cd8b46c, - 0x56acfa56, - 0xf4f307f4, - 0xeacf25ea, - 0x65caaf65, - 0x7af48e7a, - 0xae47e9ae, - 0x08101808, - 0xba6fd5ba, - 0x78f08878, - 0x254a6f25, - 0x2e5c722e, - 0x1c38241c, - 0xa657f1a6, - 0xb473c7b4, - 0xc69751c6, - 0xe8cb23e8, - 0xdda17cdd, - 0x74e89c74, - 0x1f3e211f, - 0x4b96dd4b, - 0xbd61dcbd, - 0x8b0d868b, - 0x8a0f858a, - 0x70e09070, - 0x3e7c423e, - 0xb571c4b5, - 0x66ccaa66, - 0x4890d848, - 0x03060503, - 0xf6f701f6, - 0x0e1c120e, - 0x61c2a361, - 0x356a5f35, - 0x57aef957, - 0xb969d0b9, - 0x86179186, - 0xc19958c1, - 0x1d3a271d, - 0x9e27b99e, - 0xe1d938e1, - 0xf8eb13f8, - 0x982bb398, - 0x11223311, - 0x69d2bb69, - 0xd9a970d9, - 0x8e07898e, - 0x9433a794, - 0x9b2db69b, - 0x1e3c221e, - 0x87159287, - 0xe9c920e9, - 0xce8749ce, - 0x55aaff55, - 0x28507828, - 0xdfa57adf, - 0x8c038f8c, - 0xa159f8a1, - 0x89098089, - 0x0d1a170d, - 0xbf65dabf, - 0xe6d731e6, - 0x4284c642, - 0x68d0b868, - 0x4182c341, - 0x9929b099, - 0x2d5a772d, - 0x0f1e110f, - 0xb07bcbb0, - 0x54a8fc54, - 0xbb6dd6bb, - 0x162c3a16, - ]; - r3 = [ - 0xc6a56363, - 0xf8847c7c, - 0xee997777, - 0xf68d7b7b, - 0xff0df2f2, - 0xd6bd6b6b, - 0xdeb16f6f, - 0x9154c5c5, - 0x60503030, - 0x02030101, - 0xcea96767, - 0x567d2b2b, - 0xe719fefe, - 0xb562d7d7, - 0x4de6abab, - 0xec9a7676, - 0x8f45caca, - 0x1f9d8282, - 0x8940c9c9, - 0xfa877d7d, - 0xef15fafa, - 0xb2eb5959, - 0x8ec94747, - 0xfb0bf0f0, - 0x41ecadad, - 0xb367d4d4, - 0x5ffda2a2, - 0x45eaafaf, - 0x23bf9c9c, - 0x53f7a4a4, - 0xe4967272, - 0x9b5bc0c0, - 0x75c2b7b7, - 0xe11cfdfd, - 0x3dae9393, - 0x4c6a2626, - 0x6c5a3636, - 0x7e413f3f, - 0xf502f7f7, - 0x834fcccc, - 0x685c3434, - 0x51f4a5a5, - 0xd134e5e5, - 0xf908f1f1, - 0xe2937171, - 0xab73d8d8, - 0x62533131, - 0x2a3f1515, - 0x080c0404, - 0x9552c7c7, - 0x46652323, - 0x9d5ec3c3, - 0x30281818, - 0x37a19696, - 0x0a0f0505, - 0x2fb59a9a, - 0x0e090707, - 0x24361212, - 0x1b9b8080, - 0xdf3de2e2, - 0xcd26ebeb, - 0x4e692727, - 0x7fcdb2b2, - 0xea9f7575, - 0x121b0909, - 0x1d9e8383, - 0x58742c2c, - 0x342e1a1a, - 0x362d1b1b, - 0xdcb26e6e, - 0xb4ee5a5a, - 0x5bfba0a0, - 0xa4f65252, - 0x764d3b3b, - 0xb761d6d6, - 0x7dceb3b3, - 0x527b2929, - 0xdd3ee3e3, - 0x5e712f2f, - 0x13978484, - 0xa6f55353, - 0xb968d1d1, - 0x00000000, - 0xc12ceded, - 0x40602020, - 0xe31ffcfc, - 0x79c8b1b1, - 0xb6ed5b5b, - 0xd4be6a6a, - 0x8d46cbcb, - 0x67d9bebe, - 0x724b3939, - 0x94de4a4a, - 0x98d44c4c, - 0xb0e85858, - 0x854acfcf, - 0xbb6bd0d0, - 0xc52aefef, - 0x4fe5aaaa, - 0xed16fbfb, - 0x86c54343, - 0x9ad74d4d, - 0x66553333, - 0x11948585, - 0x8acf4545, - 0xe910f9f9, - 0x04060202, - 0xfe817f7f, - 0xa0f05050, - 0x78443c3c, - 0x25ba9f9f, - 0x4be3a8a8, - 0xa2f35151, - 0x5dfea3a3, - 0x80c04040, - 0x058a8f8f, - 0x3fad9292, - 0x21bc9d9d, - 0x70483838, - 0xf104f5f5, - 0x63dfbcbc, - 0x77c1b6b6, - 0xaf75dada, - 0x42632121, - 0x20301010, - 0xe51affff, - 0xfd0ef3f3, - 0xbf6dd2d2, - 0x814ccdcd, - 0x18140c0c, - 0x26351313, - 0xc32fecec, - 0xbee15f5f, - 0x35a29797, - 0x88cc4444, - 0x2e391717, - 0x9357c4c4, - 0x55f2a7a7, - 0xfc827e7e, - 0x7a473d3d, - 0xc8ac6464, - 0xbae75d5d, - 0x322b1919, - 0xe6957373, - 0xc0a06060, - 0x19988181, - 0x9ed14f4f, - 0xa37fdcdc, - 0x44662222, - 0x547e2a2a, - 0x3bab9090, - 0x0b838888, - 0x8cca4646, - 0xc729eeee, - 0x6bd3b8b8, - 0x283c1414, - 0xa779dede, - 0xbce25e5e, - 0x161d0b0b, - 0xad76dbdb, - 0xdb3be0e0, - 0x64563232, - 0x744e3a3a, - 0x141e0a0a, - 0x92db4949, - 0x0c0a0606, - 0x486c2424, - 0xb8e45c5c, - 0x9f5dc2c2, - 0xbd6ed3d3, - 0x43efacac, - 0xc4a66262, - 0x39a89191, - 0x31a49595, - 0xd337e4e4, - 0xf28b7979, - 0xd532e7e7, - 0x8b43c8c8, - 0x6e593737, - 0xdab76d6d, - 0x018c8d8d, - 0xb164d5d5, - 0x9cd24e4e, - 0x49e0a9a9, - 0xd8b46c6c, - 0xacfa5656, - 0xf307f4f4, - 0xcf25eaea, - 0xcaaf6565, - 0xf48e7a7a, - 0x47e9aeae, - 0x10180808, - 0x6fd5baba, - 0xf0887878, - 0x4a6f2525, - 0x5c722e2e, - 0x38241c1c, - 0x57f1a6a6, - 0x73c7b4b4, - 0x9751c6c6, - 0xcb23e8e8, - 0xa17cdddd, - 0xe89c7474, - 0x3e211f1f, - 0x96dd4b4b, - 0x61dcbdbd, - 0x0d868b8b, - 0x0f858a8a, - 0xe0907070, - 0x7c423e3e, - 0x71c4b5b5, - 0xccaa6666, - 0x90d84848, - 0x06050303, - 0xf701f6f6, - 0x1c120e0e, - 0xc2a36161, - 0x6a5f3535, - 0xaef95757, - 0x69d0b9b9, - 0x17918686, - 0x9958c1c1, - 0x3a271d1d, - 0x27b99e9e, - 0xd938e1e1, - 0xeb13f8f8, - 0x2bb39898, - 0x22331111, - 0xd2bb6969, - 0xa970d9d9, - 0x07898e8e, - 0x33a79494, - 0x2db69b9b, - 0x3c221e1e, - 0x15928787, - 0xc920e9e9, - 0x8749cece, - 0xaaff5555, - 0x50782828, - 0xa57adfdf, - 0x038f8c8c, - 0x59f8a1a1, - 0x09808989, - 0x1a170d0d, - 0x65dabfbf, - 0xd731e6e6, - 0x84c64242, - 0xd0b86868, - 0x82c34141, - 0x29b09999, - 0x5a772d2d, - 0x1e110f0f, - 0x7bcbb0b0, - 0xa8fc5454, - 0x6dd6bbbb, - 0x2c3a1616, - ]; - sinv = [ - 82, - 9, - 106, - 213, - 48, - 54, - 165, - 56, - 191, - 64, - 163, - 158, - 129, - 243, - 215, - 251, - 124, - 227, - 57, - 130, - 155, - 47, - 255, - 135, - 52, - 142, - 67, - 68, - 196, - 222, - 233, - 203, - 84, - 123, - 148, - 50, - 166, - 194, - 35, - 61, - 238, - 76, - 149, - 11, - 66, - 250, - 195, - 78, - 8, - 46, - 161, - 102, - 40, - 217, - 36, - 178, - 118, - 91, - 162, - 73, - 109, - 139, - 209, - 37, - 114, - 248, - 246, - 100, - 134, - 104, - 152, - 22, - 212, - 164, - 92, - 204, - 93, - 101, - 182, - 146, - 108, - 112, - 72, - 80, - 253, - 237, - 185, - 218, - 94, - 21, - 70, - 87, - 167, - 141, - 157, - 132, - 144, - 216, - 171, - 0, - 140, - 188, - 211, - 10, - 247, - 228, - 88, - 5, - 184, - 179, - 69, - 6, - 208, - 44, - 30, - 143, - 202, - 63, - 15, - 2, - 193, - 175, - 189, - 3, - 1, - 19, - 138, - 107, - 58, - 145, - 17, - 65, - 79, - 103, - 220, - 234, - 151, - 242, - 207, - 206, - 240, - 180, - 230, - 115, - 150, - 172, - 116, - 34, - 231, - 173, - 53, - 133, - 226, - 249, - 55, - 232, - 28, - 117, - 223, - 110, - 71, - 241, - 26, - 113, - 29, - 41, - 197, - 137, - 111, - 183, - 98, - 14, - 170, - 24, - 190, - 27, - 252, - 86, - 62, - 75, - 198, - 210, - 121, - 32, - 154, - 219, - 192, - 254, - 120, - 205, - 90, - 244, - 31, - 221, - 168, - 51, - 136, - 7, - 199, - 49, - 177, - 18, - 16, - 89, - 39, - 128, - 236, - 95, - 96, - 81, - 127, - 169, - 25, - 181, - 74, - 13, - 45, - 229, - 122, - 159, - 147, - 201, - 156, - 239, - 160, - 224, - 59, - 77, - 174, - 42, - 245, - 176, - 200, - 235, - 187, - 60, - 131, - 83, - 153, - 97, - 23, - 43, - 4, - 126, - 186, - 119, - 214, - 38, - 225, - 105, - 20, - 99, - 85, - 33, - 12, - 125, - ]; - rinv0 = [ - 0x50a7f451, - 0x5365417e, - 0xc3a4171a, - 0x965e273a, - 0xcb6bab3b, - 0xf1459d1f, - 0xab58faac, - 0x9303e34b, - 0x55fa3020, - 0xf66d76ad, - 0x9176cc88, - 0x254c02f5, - 0xfcd7e54f, - 0xd7cb2ac5, - 0x80443526, - 0x8fa362b5, - 0x495ab1de, - 0x671bba25, - 0x980eea45, - 0xe1c0fe5d, - 0x02752fc3, - 0x12f04c81, - 0xa397468d, - 0xc6f9d36b, - 0xe75f8f03, - 0x959c9215, - 0xeb7a6dbf, - 0xda595295, - 0x2d83bed4, - 0xd3217458, - 0x2969e049, - 0x44c8c98e, - 0x6a89c275, - 0x78798ef4, - 0x6b3e5899, - 0xdd71b927, - 0xb64fe1be, - 0x17ad88f0, - 0x66ac20c9, - 0xb43ace7d, - 0x184adf63, - 0x82311ae5, - 0x60335197, - 0x457f5362, - 0xe07764b1, - 0x84ae6bbb, - 0x1ca081fe, - 0x942b08f9, - 0x58684870, - 0x19fd458f, - 0x876cde94, - 0xb7f87b52, - 0x23d373ab, - 0xe2024b72, - 0x578f1fe3, - 0x2aab5566, - 0x0728ebb2, - 0x03c2b52f, - 0x9a7bc586, - 0xa50837d3, - 0xf2872830, - 0xb2a5bf23, - 0xba6a0302, - 0x5c8216ed, - 0x2b1ccf8a, - 0x92b479a7, - 0xf0f207f3, - 0xa1e2694e, - 0xcdf4da65, - 0xd5be0506, - 0x1f6234d1, - 0x8afea6c4, - 0x9d532e34, - 0xa055f3a2, - 0x32e18a05, - 0x75ebf6a4, - 0x39ec830b, - 0xaaef6040, - 0x069f715e, - 0x51106ebd, - 0xf98a213e, - 0x3d06dd96, - 0xae053edd, - 0x46bde64d, - 0xb58d5491, - 0x055dc471, - 0x6fd40604, - 0xff155060, - 0x24fb9819, - 0x97e9bdd6, - 0xcc434089, - 0x779ed967, - 0xbd42e8b0, - 0x888b8907, - 0x385b19e7, - 0xdbeec879, - 0x470a7ca1, - 0xe90f427c, - 0xc91e84f8, - 0x00000000, - 0x83868009, - 0x48ed2b32, - 0xac70111e, - 0x4e725a6c, - 0xfbff0efd, - 0x5638850f, - 0x1ed5ae3d, - 0x27392d36, - 0x64d90f0a, - 0x21a65c68, - 0xd1545b9b, - 0x3a2e3624, - 0xb1670a0c, - 0x0fe75793, - 0xd296eeb4, - 0x9e919b1b, - 0x4fc5c080, - 0xa220dc61, - 0x694b775a, - 0x161a121c, - 0x0aba93e2, - 0xe52aa0c0, - 0x43e0223c, - 0x1d171b12, - 0x0b0d090e, - 0xadc78bf2, - 0xb9a8b62d, - 0xc8a91e14, - 0x8519f157, - 0x4c0775af, - 0xbbdd99ee, - 0xfd607fa3, - 0x9f2601f7, - 0xbcf5725c, - 0xc53b6644, - 0x347efb5b, - 0x7629438b, - 0xdcc623cb, - 0x68fcedb6, - 0x63f1e4b8, - 0xcadc31d7, - 0x10856342, - 0x40229713, - 0x2011c684, - 0x7d244a85, - 0xf83dbbd2, - 0x1132f9ae, - 0x6da129c7, - 0x4b2f9e1d, - 0xf330b2dc, - 0xec52860d, - 0xd0e3c177, - 0x6c16b32b, - 0x99b970a9, - 0xfa489411, - 0x2264e947, - 0xc48cfca8, - 0x1a3ff0a0, - 0xd82c7d56, - 0xef903322, - 0xc74e4987, - 0xc1d138d9, - 0xfea2ca8c, - 0x360bd498, - 0xcf81f5a6, - 0x28de7aa5, - 0x268eb7da, - 0xa4bfad3f, - 0xe49d3a2c, - 0x0d927850, - 0x9bcc5f6a, - 0x62467e54, - 0xc2138df6, - 0xe8b8d890, - 0x5ef7392e, - 0xf5afc382, - 0xbe805d9f, - 0x7c93d069, - 0xa92dd56f, - 0xb31225cf, - 0x3b99acc8, - 0xa77d1810, - 0x6e639ce8, - 0x7bbb3bdb, - 0x097826cd, - 0xf418596e, - 0x01b79aec, - 0xa89a4f83, - 0x656e95e6, - 0x7ee6ffaa, - 0x08cfbc21, - 0xe6e815ef, - 0xd99be7ba, - 0xce366f4a, - 0xd4099fea, - 0xd67cb029, - 0xafb2a431, - 0x31233f2a, - 0x3094a5c6, - 0xc066a235, - 0x37bc4e74, - 0xa6ca82fc, - 0xb0d090e0, - 0x15d8a733, - 0x4a9804f1, - 0xf7daec41, - 0x0e50cd7f, - 0x2ff69117, - 0x8dd64d76, - 0x4db0ef43, - 0x544daacc, - 0xdf0496e4, - 0xe3b5d19e, - 0x1b886a4c, - 0xb81f2cc1, - 0x7f516546, - 0x04ea5e9d, - 0x5d358c01, - 0x737487fa, - 0x2e410bfb, - 0x5a1d67b3, - 0x52d2db92, - 0x335610e9, - 0x1347d66d, - 0x8c61d79a, - 0x7a0ca137, - 0x8e14f859, - 0x893c13eb, - 0xee27a9ce, - 0x35c961b7, - 0xede51ce1, - 0x3cb1477a, - 0x59dfd29c, - 0x3f73f255, - 0x79ce1418, - 0xbf37c773, - 0xeacdf753, - 0x5baafd5f, - 0x146f3ddf, - 0x86db4478, - 0x81f3afca, - 0x3ec468b9, - 0x2c342438, - 0x5f40a3c2, - 0x72c31d16, - 0x0c25e2bc, - 0x8b493c28, - 0x41950dff, - 0x7101a839, - 0xdeb30c08, - 0x9ce4b4d8, - 0x90c15664, - 0x6184cb7b, - 0x70b632d5, - 0x745c6c48, - 0x4257b8d0, - ]; - rinv1 = [ - 0xa7f45150, - 0x65417e53, - 0xa4171ac3, - 0x5e273a96, - 0x6bab3bcb, - 0x459d1ff1, - 0x58faacab, - 0x03e34b93, - 0xfa302055, - 0x6d76adf6, - 0x76cc8891, - 0x4c02f525, - 0xd7e54ffc, - 0xcb2ac5d7, - 0x44352680, - 0xa362b58f, - 0x5ab1de49, - 0x1bba2567, - 0x0eea4598, - 0xc0fe5de1, - 0x752fc302, - 0xf04c8112, - 0x97468da3, - 0xf9d36bc6, - 0x5f8f03e7, - 0x9c921595, - 0x7a6dbfeb, - 0x595295da, - 0x83bed42d, - 0x217458d3, - 0x69e04929, - 0xc8c98e44, - 0x89c2756a, - 0x798ef478, - 0x3e58996b, - 0x71b927dd, - 0x4fe1beb6, - 0xad88f017, - 0xac20c966, - 0x3ace7db4, - 0x4adf6318, - 0x311ae582, - 0x33519760, - 0x7f536245, - 0x7764b1e0, - 0xae6bbb84, - 0xa081fe1c, - 0x2b08f994, - 0x68487058, - 0xfd458f19, - 0x6cde9487, - 0xf87b52b7, - 0xd373ab23, - 0x024b72e2, - 0x8f1fe357, - 0xab55662a, - 0x28ebb207, - 0xc2b52f03, - 0x7bc5869a, - 0x0837d3a5, - 0x872830f2, - 0xa5bf23b2, - 0x6a0302ba, - 0x8216ed5c, - 0x1ccf8a2b, - 0xb479a792, - 0xf207f3f0, - 0xe2694ea1, - 0xf4da65cd, - 0xbe0506d5, - 0x6234d11f, - 0xfea6c48a, - 0x532e349d, - 0x55f3a2a0, - 0xe18a0532, - 0xebf6a475, - 0xec830b39, - 0xef6040aa, - 0x9f715e06, - 0x106ebd51, - 0x8a213ef9, - 0x06dd963d, - 0x053eddae, - 0xbde64d46, - 0x8d5491b5, - 0x5dc47105, - 0xd406046f, - 0x155060ff, - 0xfb981924, - 0xe9bdd697, - 0x434089cc, - 0x9ed96777, - 0x42e8b0bd, - 0x8b890788, - 0x5b19e738, - 0xeec879db, - 0x0a7ca147, - 0x0f427ce9, - 0x1e84f8c9, - 0x00000000, - 0x86800983, - 0xed2b3248, - 0x70111eac, - 0x725a6c4e, - 0xff0efdfb, - 0x38850f56, - 0xd5ae3d1e, - 0x392d3627, - 0xd90f0a64, - 0xa65c6821, - 0x545b9bd1, - 0x2e36243a, - 0x670a0cb1, - 0xe757930f, - 0x96eeb4d2, - 0x919b1b9e, - 0xc5c0804f, - 0x20dc61a2, - 0x4b775a69, - 0x1a121c16, - 0xba93e20a, - 0x2aa0c0e5, - 0xe0223c43, - 0x171b121d, - 0x0d090e0b, - 0xc78bf2ad, - 0xa8b62db9, - 0xa91e14c8, - 0x19f15785, - 0x0775af4c, - 0xdd99eebb, - 0x607fa3fd, - 0x2601f79f, - 0xf5725cbc, - 0x3b6644c5, - 0x7efb5b34, - 0x29438b76, - 0xc623cbdc, - 0xfcedb668, - 0xf1e4b863, - 0xdc31d7ca, - 0x85634210, - 0x22971340, - 0x11c68420, - 0x244a857d, - 0x3dbbd2f8, - 0x32f9ae11, - 0xa129c76d, - 0x2f9e1d4b, - 0x30b2dcf3, - 0x52860dec, - 0xe3c177d0, - 0x16b32b6c, - 0xb970a999, - 0x489411fa, - 0x64e94722, - 0x8cfca8c4, - 0x3ff0a01a, - 0x2c7d56d8, - 0x903322ef, - 0x4e4987c7, - 0xd138d9c1, - 0xa2ca8cfe, - 0x0bd49836, - 0x81f5a6cf, - 0xde7aa528, - 0x8eb7da26, - 0xbfad3fa4, - 0x9d3a2ce4, - 0x9278500d, - 0xcc5f6a9b, - 0x467e5462, - 0x138df6c2, - 0xb8d890e8, - 0xf7392e5e, - 0xafc382f5, - 0x805d9fbe, - 0x93d0697c, - 0x2dd56fa9, - 0x1225cfb3, - 0x99acc83b, - 0x7d1810a7, - 0x639ce86e, - 0xbb3bdb7b, - 0x7826cd09, - 0x18596ef4, - 0xb79aec01, - 0x9a4f83a8, - 0x6e95e665, - 0xe6ffaa7e, - 0xcfbc2108, - 0xe815efe6, - 0x9be7bad9, - 0x366f4ace, - 0x099fead4, - 0x7cb029d6, - 0xb2a431af, - 0x233f2a31, - 0x94a5c630, - 0x66a235c0, - 0xbc4e7437, - 0xca82fca6, - 0xd090e0b0, - 0xd8a73315, - 0x9804f14a, - 0xdaec41f7, - 0x50cd7f0e, - 0xf691172f, - 0xd64d768d, - 0xb0ef434d, - 0x4daacc54, - 0x0496e4df, - 0xb5d19ee3, - 0x886a4c1b, - 0x1f2cc1b8, - 0x5165467f, - 0xea5e9d04, - 0x358c015d, - 0x7487fa73, - 0x410bfb2e, - 0x1d67b35a, - 0xd2db9252, - 0x5610e933, - 0x47d66d13, - 0x61d79a8c, - 0x0ca1377a, - 0x14f8598e, - 0x3c13eb89, - 0x27a9ceee, - 0xc961b735, - 0xe51ce1ed, - 0xb1477a3c, - 0xdfd29c59, - 0x73f2553f, - 0xce141879, - 0x37c773bf, - 0xcdf753ea, - 0xaafd5f5b, - 0x6f3ddf14, - 0xdb447886, - 0xf3afca81, - 0xc468b93e, - 0x3424382c, - 0x40a3c25f, - 0xc31d1672, - 0x25e2bc0c, - 0x493c288b, - 0x950dff41, - 0x01a83971, - 0xb30c08de, - 0xe4b4d89c, - 0xc1566490, - 0x84cb7b61, - 0xb632d570, - 0x5c6c4874, - 0x57b8d042, - ]; - rinv2 = [ - 0xf45150a7, - 0x417e5365, - 0x171ac3a4, - 0x273a965e, - 0xab3bcb6b, - 0x9d1ff145, - 0xfaacab58, - 0xe34b9303, - 0x302055fa, - 0x76adf66d, - 0xcc889176, - 0x02f5254c, - 0xe54ffcd7, - 0x2ac5d7cb, - 0x35268044, - 0x62b58fa3, - 0xb1de495a, - 0xba25671b, - 0xea45980e, - 0xfe5de1c0, - 0x2fc30275, - 0x4c8112f0, - 0x468da397, - 0xd36bc6f9, - 0x8f03e75f, - 0x9215959c, - 0x6dbfeb7a, - 0x5295da59, - 0xbed42d83, - 0x7458d321, - 0xe0492969, - 0xc98e44c8, - 0xc2756a89, - 0x8ef47879, - 0x58996b3e, - 0xb927dd71, - 0xe1beb64f, - 0x88f017ad, - 0x20c966ac, - 0xce7db43a, - 0xdf63184a, - 0x1ae58231, - 0x51976033, - 0x5362457f, - 0x64b1e077, - 0x6bbb84ae, - 0x81fe1ca0, - 0x08f9942b, - 0x48705868, - 0x458f19fd, - 0xde94876c, - 0x7b52b7f8, - 0x73ab23d3, - 0x4b72e202, - 0x1fe3578f, - 0x55662aab, - 0xebb20728, - 0xb52f03c2, - 0xc5869a7b, - 0x37d3a508, - 0x2830f287, - 0xbf23b2a5, - 0x0302ba6a, - 0x16ed5c82, - 0xcf8a2b1c, - 0x79a792b4, - 0x07f3f0f2, - 0x694ea1e2, - 0xda65cdf4, - 0x0506d5be, - 0x34d11f62, - 0xa6c48afe, - 0x2e349d53, - 0xf3a2a055, - 0x8a0532e1, - 0xf6a475eb, - 0x830b39ec, - 0x6040aaef, - 0x715e069f, - 0x6ebd5110, - 0x213ef98a, - 0xdd963d06, - 0x3eddae05, - 0xe64d46bd, - 0x5491b58d, - 0xc471055d, - 0x06046fd4, - 0x5060ff15, - 0x981924fb, - 0xbdd697e9, - 0x4089cc43, - 0xd967779e, - 0xe8b0bd42, - 0x8907888b, - 0x19e7385b, - 0xc879dbee, - 0x7ca1470a, - 0x427ce90f, - 0x84f8c91e, - 0x00000000, - 0x80098386, - 0x2b3248ed, - 0x111eac70, - 0x5a6c4e72, - 0x0efdfbff, - 0x850f5638, - 0xae3d1ed5, - 0x2d362739, - 0x0f0a64d9, - 0x5c6821a6, - 0x5b9bd154, - 0x36243a2e, - 0x0a0cb167, - 0x57930fe7, - 0xeeb4d296, - 0x9b1b9e91, - 0xc0804fc5, - 0xdc61a220, - 0x775a694b, - 0x121c161a, - 0x93e20aba, - 0xa0c0e52a, - 0x223c43e0, - 0x1b121d17, - 0x090e0b0d, - 0x8bf2adc7, - 0xb62db9a8, - 0x1e14c8a9, - 0xf1578519, - 0x75af4c07, - 0x99eebbdd, - 0x7fa3fd60, - 0x01f79f26, - 0x725cbcf5, - 0x6644c53b, - 0xfb5b347e, - 0x438b7629, - 0x23cbdcc6, - 0xedb668fc, - 0xe4b863f1, - 0x31d7cadc, - 0x63421085, - 0x97134022, - 0xc6842011, - 0x4a857d24, - 0xbbd2f83d, - 0xf9ae1132, - 0x29c76da1, - 0x9e1d4b2f, - 0xb2dcf330, - 0x860dec52, - 0xc177d0e3, - 0xb32b6c16, - 0x70a999b9, - 0x9411fa48, - 0xe9472264, - 0xfca8c48c, - 0xf0a01a3f, - 0x7d56d82c, - 0x3322ef90, - 0x4987c74e, - 0x38d9c1d1, - 0xca8cfea2, - 0xd498360b, - 0xf5a6cf81, - 0x7aa528de, - 0xb7da268e, - 0xad3fa4bf, - 0x3a2ce49d, - 0x78500d92, - 0x5f6a9bcc, - 0x7e546246, - 0x8df6c213, - 0xd890e8b8, - 0x392e5ef7, - 0xc382f5af, - 0x5d9fbe80, - 0xd0697c93, - 0xd56fa92d, - 0x25cfb312, - 0xacc83b99, - 0x1810a77d, - 0x9ce86e63, - 0x3bdb7bbb, - 0x26cd0978, - 0x596ef418, - 0x9aec01b7, - 0x4f83a89a, - 0x95e6656e, - 0xffaa7ee6, - 0xbc2108cf, - 0x15efe6e8, - 0xe7bad99b, - 0x6f4ace36, - 0x9fead409, - 0xb029d67c, - 0xa431afb2, - 0x3f2a3123, - 0xa5c63094, - 0xa235c066, - 0x4e7437bc, - 0x82fca6ca, - 0x90e0b0d0, - 0xa73315d8, - 0x04f14a98, - 0xec41f7da, - 0xcd7f0e50, - 0x91172ff6, - 0x4d768dd6, - 0xef434db0, - 0xaacc544d, - 0x96e4df04, - 0xd19ee3b5, - 0x6a4c1b88, - 0x2cc1b81f, - 0x65467f51, - 0x5e9d04ea, - 0x8c015d35, - 0x87fa7374, - 0x0bfb2e41, - 0x67b35a1d, - 0xdb9252d2, - 0x10e93356, - 0xd66d1347, - 0xd79a8c61, - 0xa1377a0c, - 0xf8598e14, - 0x13eb893c, - 0xa9ceee27, - 0x61b735c9, - 0x1ce1ede5, - 0x477a3cb1, - 0xd29c59df, - 0xf2553f73, - 0x141879ce, - 0xc773bf37, - 0xf753eacd, - 0xfd5f5baa, - 0x3ddf146f, - 0x447886db, - 0xafca81f3, - 0x68b93ec4, - 0x24382c34, - 0xa3c25f40, - 0x1d1672c3, - 0xe2bc0c25, - 0x3c288b49, - 0x0dff4195, - 0xa8397101, - 0x0c08deb3, - 0xb4d89ce4, - 0x566490c1, - 0xcb7b6184, - 0x32d570b6, - 0x6c48745c, - 0xb8d04257, - ]; - rinv3 = [ - 0x5150a7f4, - 0x7e536541, - 0x1ac3a417, - 0x3a965e27, - 0x3bcb6bab, - 0x1ff1459d, - 0xacab58fa, - 0x4b9303e3, - 0x2055fa30, - 0xadf66d76, - 0x889176cc, - 0xf5254c02, - 0x4ffcd7e5, - 0xc5d7cb2a, - 0x26804435, - 0xb58fa362, - 0xde495ab1, - 0x25671bba, - 0x45980eea, - 0x5de1c0fe, - 0xc302752f, - 0x8112f04c, - 0x8da39746, - 0x6bc6f9d3, - 0x03e75f8f, - 0x15959c92, - 0xbfeb7a6d, - 0x95da5952, - 0xd42d83be, - 0x58d32174, - 0x492969e0, - 0x8e44c8c9, - 0x756a89c2, - 0xf478798e, - 0x996b3e58, - 0x27dd71b9, - 0xbeb64fe1, - 0xf017ad88, - 0xc966ac20, - 0x7db43ace, - 0x63184adf, - 0xe582311a, - 0x97603351, - 0x62457f53, - 0xb1e07764, - 0xbb84ae6b, - 0xfe1ca081, - 0xf9942b08, - 0x70586848, - 0x8f19fd45, - 0x94876cde, - 0x52b7f87b, - 0xab23d373, - 0x72e2024b, - 0xe3578f1f, - 0x662aab55, - 0xb20728eb, - 0x2f03c2b5, - 0x869a7bc5, - 0xd3a50837, - 0x30f28728, - 0x23b2a5bf, - 0x02ba6a03, - 0xed5c8216, - 0x8a2b1ccf, - 0xa792b479, - 0xf3f0f207, - 0x4ea1e269, - 0x65cdf4da, - 0x06d5be05, - 0xd11f6234, - 0xc48afea6, - 0x349d532e, - 0xa2a055f3, - 0x0532e18a, - 0xa475ebf6, - 0x0b39ec83, - 0x40aaef60, - 0x5e069f71, - 0xbd51106e, - 0x3ef98a21, - 0x963d06dd, - 0xddae053e, - 0x4d46bde6, - 0x91b58d54, - 0x71055dc4, - 0x046fd406, - 0x60ff1550, - 0x1924fb98, - 0xd697e9bd, - 0x89cc4340, - 0x67779ed9, - 0xb0bd42e8, - 0x07888b89, - 0xe7385b19, - 0x79dbeec8, - 0xa1470a7c, - 0x7ce90f42, - 0xf8c91e84, - 0x00000000, - 0x09838680, - 0x3248ed2b, - 0x1eac7011, - 0x6c4e725a, - 0xfdfbff0e, - 0x0f563885, - 0x3d1ed5ae, - 0x3627392d, - 0x0a64d90f, - 0x6821a65c, - 0x9bd1545b, - 0x243a2e36, - 0x0cb1670a, - 0x930fe757, - 0xb4d296ee, - 0x1b9e919b, - 0x804fc5c0, - 0x61a220dc, - 0x5a694b77, - 0x1c161a12, - 0xe20aba93, - 0xc0e52aa0, - 0x3c43e022, - 0x121d171b, - 0x0e0b0d09, - 0xf2adc78b, - 0x2db9a8b6, - 0x14c8a91e, - 0x578519f1, - 0xaf4c0775, - 0xeebbdd99, - 0xa3fd607f, - 0xf79f2601, - 0x5cbcf572, - 0x44c53b66, - 0x5b347efb, - 0x8b762943, - 0xcbdcc623, - 0xb668fced, - 0xb863f1e4, - 0xd7cadc31, - 0x42108563, - 0x13402297, - 0x842011c6, - 0x857d244a, - 0xd2f83dbb, - 0xae1132f9, - 0xc76da129, - 0x1d4b2f9e, - 0xdcf330b2, - 0x0dec5286, - 0x77d0e3c1, - 0x2b6c16b3, - 0xa999b970, - 0x11fa4894, - 0x472264e9, - 0xa8c48cfc, - 0xa01a3ff0, - 0x56d82c7d, - 0x22ef9033, - 0x87c74e49, - 0xd9c1d138, - 0x8cfea2ca, - 0x98360bd4, - 0xa6cf81f5, - 0xa528de7a, - 0xda268eb7, - 0x3fa4bfad, - 0x2ce49d3a, - 0x500d9278, - 0x6a9bcc5f, - 0x5462467e, - 0xf6c2138d, - 0x90e8b8d8, - 0x2e5ef739, - 0x82f5afc3, - 0x9fbe805d, - 0x697c93d0, - 0x6fa92dd5, - 0xcfb31225, - 0xc83b99ac, - 0x10a77d18, - 0xe86e639c, - 0xdb7bbb3b, - 0xcd097826, - 0x6ef41859, - 0xec01b79a, - 0x83a89a4f, - 0xe6656e95, - 0xaa7ee6ff, - 0x2108cfbc, - 0xefe6e815, - 0xbad99be7, - 0x4ace366f, - 0xead4099f, - 0x29d67cb0, - 0x31afb2a4, - 0x2a31233f, - 0xc63094a5, - 0x35c066a2, - 0x7437bc4e, - 0xfca6ca82, - 0xe0b0d090, - 0x3315d8a7, - 0xf14a9804, - 0x41f7daec, - 0x7f0e50cd, - 0x172ff691, - 0x768dd64d, - 0x434db0ef, - 0xcc544daa, - 0xe4df0496, - 0x9ee3b5d1, - 0x4c1b886a, - 0xc1b81f2c, - 0x467f5165, - 0x9d04ea5e, - 0x015d358c, - 0xfa737487, - 0xfb2e410b, - 0xb35a1d67, - 0x9252d2db, - 0xe9335610, - 0x6d1347d6, - 0x9a8c61d7, - 0x377a0ca1, - 0x598e14f8, - 0xeb893c13, - 0xceee27a9, - 0xb735c961, - 0xe1ede51c, - 0x7a3cb147, - 0x9c59dfd2, - 0x553f73f2, - 0x1879ce14, - 0x73bf37c7, - 0x53eacdf7, - 0x5f5baafd, - 0xdf146f3d, - 0x7886db44, - 0xca81f3af, - 0xb93ec468, - 0x382c3424, - 0xc25f40a3, - 0x1672c31d, - 0xbc0c25e2, - 0x288b493c, - 0xff41950d, - 0x397101a8, - 0x08deb30c, - 0xd89ce4b4, - 0x6490c156, - 0x7b6184cb, - 0xd570b632, - 0x48745c6c, - 0xd04257b8, - ]; - } -} - -const _mask_32 = 0xFFFFFFFF; -const _mask_5 = 0x1F; -const _mask_bits = [ - 0xFFFFFFFF, - 0x7FFFFFFF, - 0x3FFFFFFF, - 0x1FFFFFFF, - 0x0FFFFFFF, - 0x07FFFFFF, - 0x03FFFFFF, - 0x01FFFFFF, - 0x00FFFFFF, - 0x007FFFFF, - 0x003FFFFF, - 0x001FFFFF, - 0x000FFFFF, - 0x0007FFFF, - 0x0003FFFF, - 0x0001FFFF, - 0x0000FFFF, - 0x00007FFF, - 0x00003FFF, - 0x00001FFF, - 0x00000FFF, - 0x000007FF, - 0x000003FF, - 0x000001FF, - 0x000000FF, - 0x0000007F, - 0x0000003F, - 0x0000001F, - 0x0000000F, - 0x00000007, - 0x00000003, - 0x00000001, - 0x00000000, -]; +import 'dart:typed_data'; +import 'cipher_block_chaining_mode.dart'; +import 'ipadding.dart'; + +/// internal class +class AesEngine extends IBlockCipher { + //Constructor + /// internal constructor + AesEngine() { + _initializeConstants(); + } + + static const _blockSize = 16; + static const int _m1 = 0x80808080; + static const int _m2 = 0x7f7f7f7f; + static const int _m3 = 0x0000001b; + static const int _m4 = 0xC0C0C0C0; + static const int _m5 = 0x3f3f3f3f; + + @override + int get blockSize => _blockSize; + + /// internal field + late List>? _key; + + /// internal field + late int rounds; + late bool? _isEncryption; + + /// internal field + late List rcon; + + /// internal field + late List sBox; + + /// internal field + late int mix1; + + /// internal field + late int mix2; + + /// internal field + late int mix3; + + /// internal field + late int c0; + + /// internal field + late int c1; + + /// internal field + late int c2; + + /// internal field + late int c3; + + /// internal field + int? c4; + + /// internal field + late List r0; + + /// internal field + late List r1; + + /// internal field + late List r2; + + /// internal field + late List r3; + + /// internal field + late List sinv; + + /// internal field + late List rinv0; + + /// internal field + late List rinv1; + + /// internal field + late List rinv2; + + /// internal field + late List rinv3; + + //Properties + @override + String get algorithmName => 'AES'; + + @override + bool get isBlock => false; + + List _s = List.empty(); + + //Initialize + @override + void initialize(bool? isEncryption, covariant KeyParameter? parameter) { + if (parameter != null) { + _key = _generateKey(parameter, isEncryption!); + _isEncryption = isEncryption; + } + if (_isEncryption!) { + _s = List.from(sBox); + } else { + _s = List.from(sinv); + } + } + + int _removeBlock(dynamic inp, int offset, Endian endian) { + if (inp is! ByteData) { + inp = ByteData.view(inp.buffer, inp.offsetInBytes, inp.length); + } + return inp.getUint32(offset, endian); + } + + List> _generateKey(KeyParameter params, bool isEncryption) { + final key = params.keys; + final keyLen = key.length; + if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) { + throw ArgumentError('Invalid key length : $keyLen'); + } + final kc = _shiftRight32(keyLen, 2); + rounds = kc + 6; + final w = List.generate(rounds + 1, (int i) => List.filled(4, 0)); + switch (kc) { + case 4: + var col0 = _removeBlock(key, 0, Endian.little); + w[0][0] = col0; + var col1 = _removeBlock(key, 4, Endian.little); + w[0][1] = col1; + var col2 = _removeBlock(key, 8, Endian.little); + w[0][2] = col2; + var col3 = _removeBlock(key, 12, Endian.little); + w[0][3] = col3; + for (var i = 1; i <= 10; ++i) { + final colx = _subWord(_shift(col3, 8)) ^ rcon[i - 1]; + col0 ^= colx; + w[i][0] = col0; + col1 ^= col0; + w[i][1] = col1; + col2 ^= col1; + w[i][2] = col2; + col3 ^= col2; + w[i][3] = col3; + } + break; + case 6: + var col0 = _removeBlock(key, 0, Endian.little); + w[0][0] = col0; + var col1 = _removeBlock(key, 4, Endian.little); + w[0][1] = col1; + var col2 = _removeBlock(key, 8, Endian.little); + w[0][2] = col2; + var col3 = _removeBlock(key, 12, Endian.little); + w[0][3] = col3; + var col4 = _removeBlock(key, 16, Endian.little); + var col5 = _removeBlock(key, 20, Endian.little); + int i = 1, rcon = 1, colx; + for (;;) { + w[i][0] = col4; + w[i][1] = col5; + colx = _subWord(_shift(col5, 8)) ^ rcon; + rcon <<= 1; + col0 ^= colx; + w[i][2] = col0; + col1 ^= col0; + w[i][3] = col1; + col2 ^= col1; + w[i + 1][0] = col2; + col3 ^= col2; + w[i + 1][1] = col3; + col4 ^= col3; + w[i + 1][2] = col4; + col5 ^= col4; + w[i + 1][3] = col5; + colx = _subWord(_shift(col5, 8)) ^ rcon; + rcon <<= 1; + col0 ^= colx; + w[i + 2][0] = col0; + col1 ^= col0; + w[i + 2][1] = col1; + col2 ^= col1; + w[i + 2][2] = col2; + col3 ^= col2; + w[i + 2][3] = col3; + if ((i += 3) >= 13) { + break; + } + col4 ^= col3; + col5 ^= col4; + } + break; + case 8: + { + var col0 = _removeBlock(key, 0, Endian.little); + w[0][0] = col0; + var col1 = _removeBlock(key, 4, Endian.little); + w[0][1] = col1; + var col2 = _removeBlock(key, 8, Endian.little); + w[0][2] = col2; + var col3 = _removeBlock(key, 12, Endian.little); + w[0][3] = col3; + var col4 = _removeBlock(key, 16, Endian.little); + w[1][0] = col4; + var col5 = _removeBlock(key, 20, Endian.little); + w[1][1] = col5; + var col6 = _removeBlock(key, 24, Endian.little); + w[1][2] = col6; + var col7 = _removeBlock(key, 28, Endian.little); + w[1][3] = col7; + int i = 2, rcon = 1, colx; + for (;;) { + colx = _subWord(_shift(col7, 8)) ^ rcon; + rcon <<= 1; + col0 ^= colx; + w[i][0] = col0; + col1 ^= col0; + w[i][1] = col1; + col2 ^= col1; + w[i][2] = col2; + col3 ^= col2; + w[i][3] = col3; + ++i; + if (i >= 15) { + break; + } + colx = _subWord(col3); + col4 ^= colx; + w[i][0] = col4; + col5 ^= col4; + w[i][1] = col5; + col6 ^= col5; + w[i][2] = col6; + col7 ^= col6; + w[i][3] = col7; + ++i; + } + break; + } + default: + { + throw StateError('Invalid key length: ${key.lengthInBytes}'); + } + } + if (!isEncryption) { + for (var j = 1; j < rounds; j++) { + for (var i = 0; i < 4; i++) { + w[j][i] = _inverseMultiply(w[j][i]); + } + } + } + return w; + } + + @override + int processingBlock([ + Uint8List? inputBytes, + int? inputOffset, + //need to be unit8list + Uint8List? outputBytes, + //List? output, + int? outputOffset, + ]) { + if ((inputOffset! + (32 / 2)) > inputBytes!.lengthInBytes) { + throw ArgumentError( + 'Invalid length in input buffer : ${inputBytes.lengthInBytes}', + ); + } + + if ((outputOffset! + (32 / 2)) > outputBytes!.lengthInBytes) { + throw ArgumentError( + 'Invalid length in output buffer : ${outputBytes.lengthInBytes}', + ); + } + if (_isEncryption!) { + encryptBlock(inputBytes, inputOffset, outputBytes, outputOffset, _key!); + } else { + decryptBlock(inputBytes, inputOffset, outputBytes, outputOffset, _key!); + } + + return _blockSize; + } + + @override + void reset() {} + + /// internal method + void encryptBlock( + Uint8List input, + int inOff, + Uint8List out, + int outOff, + List> kw, + ) { + var c0 = _removeBlock(input, inOff + 0, Endian.little); + var c1 = _removeBlock(input, inOff + 4, Endian.little); + var c2 = _removeBlock(input, inOff + 8, Endian.little); + var c3 = _removeBlock(input, inOff + 12, Endian.little); + + var t0 = c0 ^ kw[0][0]; + var t1 = c1 ^ kw[0][1]; + var t2 = c2 ^ kw[0][2]; + + int r = 1, r01, r1, r2, r3 = c3 ^ kw[0][3]; + + while (r < rounds - 1) { + r01 = + r0[t0 & 255] ^ + _shift(r0[(t1 >> 8) & 255], 24) ^ + _shift(r0[(t2 >> 16) & 255], 16) ^ + _shift(r0[(r3 >> 24) & 255], 8) ^ + kw[r][0]; + r1 = + r0[t1 & 255] ^ + _shift(r0[(t2 >> 8) & 255], 24) ^ + _shift(r0[(r3 >> 16) & 255], 16) ^ + _shift(r0[(t0 >> 24) & 255], 8) ^ + kw[r][1]; + r2 = + r0[t2 & 255] ^ + _shift(r0[(r3 >> 8) & 255], 24) ^ + _shift(r0[(t0 >> 16) & 255], 16) ^ + _shift(r0[(t1 >> 24) & 255], 8) ^ + kw[r][2]; + r3 = + r0[r3 & 255] ^ + _shift(r0[(t0 >> 8) & 255], 24) ^ + _shift(r0[(t1 >> 16) & 255], 16) ^ + _shift(r0[(t2 >> 24) & 255], 8) ^ + kw[r++][3]; + t0 = + r0[r01 & 255] ^ + _shift(r0[(r1 >> 8) & 255], 24) ^ + _shift(r0[(r2 >> 16) & 255], 16) ^ + _shift(r0[(r3 >> 24) & 255], 8) ^ + kw[r][0]; + t1 = + r0[r1 & 255] ^ + _shift(r0[(r2 >> 8) & 255], 24) ^ + _shift(r0[(r3 >> 16) & 255], 16) ^ + _shift(r0[(r01 >> 24) & 255], 8) ^ + kw[r][1]; + t2 = + r0[r2 & 255] ^ + _shift(r0[(r3 >> 8) & 255], 24) ^ + _shift(r0[(r01 >> 16) & 255], 16) ^ + _shift(r0[(r1 >> 24) & 255], 8) ^ + kw[r][2]; + r3 = + r0[r3 & 255] ^ + _shift(r0[(r01 >> 8) & 255], 24) ^ + _shift(r0[(r1 >> 16) & 255], 16) ^ + _shift(r0[(r2 >> 24) & 255], 8) ^ + kw[r++][3]; + } + + r01 = + r0[t0 & 255] ^ + _shift(r0[(t1 >> 8) & 255], 24) ^ + _shift(r0[(t2 >> 16) & 255], 16) ^ + _shift(r0[(r3 >> 24) & 255], 8) ^ + kw[r][0]; + r1 = + r0[t1 & 255] ^ + _shift(r0[(t2 >> 8) & 255], 24) ^ + _shift(r0[(r3 >> 16) & 255], 16) ^ + _shift(r0[(t0 >> 24) & 255], 8) ^ + kw[r][1]; + r2 = + r0[t2 & 255] ^ + _shift(r0[(r3 >> 8) & 255], 24) ^ + _shift(r0[(t0 >> 16) & 255], 16) ^ + _shift(r0[(t1 >> 24) & 255], 8) ^ + kw[r][2]; + r3 = + r0[r3 & 255] ^ + _shift(r0[(t0 >> 8) & 255], 24) ^ + _shift(r0[(t1 >> 16) & 255], 16) ^ + _shift(r0[(t2 >> 24) & 255], 8) ^ + kw[r++][3]; + + c0 = + (sBox[r01 & 255] & 255) ^ + ((sBox[(r1 >> 8) & 255] & 255) << 8) ^ + ((_s[(r2 >> 16) & 255] & 255) << 16) ^ + (_s[(r3 >> 24) & 255] << 24) ^ + kw[r][0]; + c1 = + (_s[r1 & 255] & 255) ^ + ((sBox[(r2 >> 8) & 255] & 255) << 8) ^ + ((sBox[(r3 >> 16) & 255] & 255) << 16) ^ + (_s[(r01 >> 24) & 255] << 24) ^ + kw[r][1]; + c2 = + (_s[r2 & 255] & 255) ^ + ((sBox[(r3 >> 8) & 255] & 255) << 8) ^ + ((sBox[(r01 >> 16) & 255] & 255) << 16) ^ + (sBox[(r1 >> 24) & 255] << 24) ^ + kw[r][2]; + c3 = + (_s[r3 & 255] & 255) ^ + ((_s[(r01 >> 8) & 255] & 255) << 8) ^ + ((_s[(r1 >> 16) & 255] & 255) << 16) ^ + (sBox[(r2 >> 24) & 255] << 24) ^ + kw[r][3]; + + _addBlock(c0, out, outOff + 0, Endian.little); + _addBlock(c1, out, outOff + 4, Endian.little); + _addBlock(c2, out, outOff + 8, Endian.little); + _addBlock(c3, out, outOff + 12, Endian.little); + } + + /// internal method + void decryptBlock( + Uint8List input, + int inOff, + Uint8List out, + int outOff, + List> kw, + ) { + var c0 = _removeBlock(input, inOff + 0, Endian.little); + var c1 = _removeBlock(input, inOff + 4, Endian.little); + var c2 = _removeBlock(input, inOff + 8, Endian.little); + var c3 = _removeBlock(input, inOff + 12, Endian.little); + + var t0 = c0 ^ kw[rounds][0]; + var t1 = c1 ^ kw[rounds][1]; + var t2 = c2 ^ kw[rounds][2]; + + int r = rounds - 1, r01, r1, r2, r3 = c3 ^ kw[rounds][3]; + + while (r > 1) { + r01 = + rinv0[t0 & 255] ^ + _shift(rinv0[(r3 >> 8) & 255], 24) ^ + _shift(rinv0[(t2 >> 16) & 255], 16) ^ + _shift(rinv0[(t1 >> 24) & 255], 8) ^ + kw[r][0]; + r1 = + rinv0[t1 & 255] ^ + _shift(rinv0[(t0 >> 8) & 255], 24) ^ + _shift(rinv0[(r3 >> 16) & 255], 16) ^ + _shift(rinv0[(t2 >> 24) & 255], 8) ^ + kw[r][1]; + r2 = + rinv0[t2 & 255] ^ + _shift(rinv0[(t1 >> 8) & 255], 24) ^ + _shift(rinv0[(t0 >> 16) & 255], 16) ^ + _shift(rinv0[(r3 >> 24) & 255], 8) ^ + kw[r][2]; + r3 = + rinv0[r3 & 255] ^ + _shift(rinv0[(t2 >> 8) & 255], 24) ^ + _shift(rinv0[(t1 >> 16) & 255], 16) ^ + _shift(rinv0[(t0 >> 24) & 255], 8) ^ + kw[r--][3]; + t0 = + rinv0[r01 & 255] ^ + _shift(rinv0[(r3 >> 8) & 255], 24) ^ + _shift(rinv0[(r2 >> 16) & 255], 16) ^ + _shift(rinv0[(r1 >> 24) & 255], 8) ^ + kw[r][0]; + t1 = + rinv0[r1 & 255] ^ + _shift(rinv0[(r01 >> 8) & 255], 24) ^ + _shift(rinv0[(r3 >> 16) & 255], 16) ^ + _shift(rinv0[(r2 >> 24) & 255], 8) ^ + kw[r][1]; + t2 = + rinv0[r2 & 255] ^ + _shift(rinv0[(r1 >> 8) & 255], 24) ^ + _shift(rinv0[(r01 >> 16) & 255], 16) ^ + _shift(rinv0[(r3 >> 24) & 255], 8) ^ + kw[r][2]; + r3 = + rinv0[r3 & 255] ^ + _shift(rinv0[(r2 >> 8) & 255], 24) ^ + _shift(rinv0[(r1 >> 16) & 255], 16) ^ + _shift(rinv0[(r01 >> 24) & 255], 8) ^ + kw[r--][3]; + } + + r01 = + rinv0[t0 & 255] ^ + _shift(rinv0[(r3 >> 8) & 255], 24) ^ + _shift(rinv0[(t2 >> 16) & 255], 16) ^ + _shift(rinv0[(t1 >> 24) & 255], 8) ^ + kw[r][0]; + r1 = + rinv0[t1 & 255] ^ + _shift(rinv0[(t0 >> 8) & 255], 24) ^ + _shift(rinv0[(r3 >> 16) & 255], 16) ^ + _shift(rinv0[(t2 >> 24) & 255], 8) ^ + kw[r][1]; + r2 = + rinv0[t2 & 255] ^ + _shift(rinv0[(t1 >> 8) & 255], 24) ^ + _shift(rinv0[(t0 >> 16) & 255], 16) ^ + _shift(rinv0[(r3 >> 24) & 255], 8) ^ + kw[r][2]; + r3 = + rinv0[r3 & 255] ^ + _shift(rinv0[(t2 >> 8) & 255], 24) ^ + _shift(rinv0[(t1 >> 16) & 255], 16) ^ + _shift(rinv0[(t0 >> 24) & 255], 8) ^ + kw[r][3]; + + c0 = + (sinv[r01 & 255] & 255) ^ + ((_s[(r3 >> 8) & 255] & 255) << 8) ^ + ((_s[(r2 >> 16) & 255] & 255) << 16) ^ + (sinv[(r1 >> 24) & 255] << 24) ^ + kw[0][0]; + c1 = + (_s[r1 & 255] & 255) ^ + ((_s[(r01 >> 8) & 255] & 255) << 8) ^ + ((sinv[(r3 >> 16) & 255] & 255) << 16) ^ + (_s[(r2 >> 24) & 255] << 24) ^ + kw[0][1]; + c2 = + (_s[r2 & 255] & 255) ^ + ((sinv[(r1 >> 8) & 255] & 255) << 8) ^ + ((sinv[(r01 >> 16) & 255] & 255) << 16) ^ + (_s[(r3 >> 24) & 255] << 24) ^ + kw[0][2]; + c3 = + (sinv[r3 & 255] & 255) ^ + ((_s[(r2 >> 8) & 255] & 255) << 8) ^ + ((_s[(r1 >> 16) & 255] & 255) << 16) ^ + (_s[(r01 >> 24) & 255] << 24) ^ + kw[0][3]; + + _addBlock(c0, out, outOff + 0, Endian.little); + _addBlock(c1, out, outOff + 4, Endian.little); + _addBlock(c2, out, outOff + 8, Endian.little); + _addBlock(c3, out, outOff + 12, Endian.little); + } + + void _addBlock(int x, dynamic out, int offset, Endian endian) { + assert((x >= 0) && (x <= _mask_32)); + if (out is! ByteData) { + out = ByteData.view( + out.buffer as ByteBuffer, + out.offsetInBytes, + out.length, + ); + } + out.setUint32(offset, x, endian); + } + + int _shift(int r, int shift) => _rotateRight32(r, shift); + + int _rotateRight32(int x, int n) { + assert(n >= 0); + assert((x >= 0) && (x <= _mask_32)); + n &= _mask_5; + return (x >> n) | _shiftLeft32(x, 32 - n); + } + + int _shiftRight32(int x, int n) { + assert((x >= 0) && (x <= _mask_32)); + n &= _mask_5; + return x >> n; + } + + int _shiftLeft32(int x, int n) { + assert((x >= 0) && (x <= _mask_32)); + n &= _mask_5; + x &= _mask_bits[n]; + return (x << n) & _mask_32; + } + + int _subWord(int x) { + return sBox[x & 255] & 255 | + ((sBox[(x >> 8) & 255] & 255) << 8) | + ((sBox[(x >> 16) & 255] & 255) << 16) | + sBox[(x >> 24) & 255] << 24; + } + + int _inverseMultiply(int x) { + int t0, t1; + t0 = x; + t1 = t0 ^ _shift(t0, 8); + t0 ^= _xMultiply(t1); + t1 ^= _x2Multiply(t0); + t0 ^= t1 ^ _shift(t1, 16); + return t0; + } + + int _xMultiply(int x) { + final lsr = _shiftRight32(x & _m1, 7); + return ((x & _m2) << 1) ^ lsr * _m3; + } + + int _x2Multiply(int x) { + final t0 = _shiftLeft32(x & _m5, 2); + var t1 = x & _m4; + t1 ^= _shiftRight32(t1, 1); + return t0 ^ _shiftRight32(t1, 2) ^ _shiftRight32(t1, 5); + } + + void _initializeConstants() { + rounds = 0; + _isEncryption = false; + mix1 = 0x80808080; + mix2 = 0x7f7f7f7f; + mix3 = 0x0000001b; + c0 = 0; + c1 = 0; + c2 = 0; + c3 = 0; + rcon = [ + 0x01, + 0x02, + 0x04, + 0x08, + 0x10, + 0x20, + 0x40, + 0x80, + 0x1b, + 0x36, + 0x6c, + 0xd8, + 0xab, + 0x4d, + 0x9a, + 0x2f, + 0x5e, + 0xbc, + 0x63, + 0xc6, + 0x97, + 0x35, + 0x6a, + 0xd4, + 0xb3, + 0x7d, + 0xfa, + 0xef, + 0xc5, + 0x91, + ]; + sBox = [ + 99, + 124, + 119, + 123, + 242, + 107, + 111, + 197, + 48, + 1, + 103, + 43, + 254, + 215, + 171, + 118, + 202, + 130, + 201, + 125, + 250, + 89, + 71, + 240, + 173, + 212, + 162, + 175, + 156, + 164, + 114, + 192, + 183, + 253, + 147, + 38, + 54, + 63, + 247, + 204, + 52, + 165, + 229, + 241, + 113, + 216, + 49, + 21, + 4, + 199, + 35, + 195, + 24, + 150, + 5, + 154, + 7, + 18, + 128, + 226, + 235, + 39, + 178, + 117, + 9, + 131, + 44, + 26, + 27, + 110, + 90, + 160, + 82, + 59, + 214, + 179, + 41, + 227, + 47, + 132, + 83, + 209, + 0, + 237, + 32, + 252, + 177, + 91, + 106, + 203, + 190, + 57, + 74, + 76, + 88, + 207, + 208, + 239, + 170, + 251, + 67, + 77, + 51, + 133, + 69, + 249, + 2, + 127, + 80, + 60, + 159, + 168, + 81, + 163, + 64, + 143, + 146, + 157, + 56, + 245, + 188, + 182, + 218, + 33, + 16, + 255, + 243, + 210, + 205, + 12, + 19, + 236, + 95, + 151, + 68, + 23, + 196, + 167, + 126, + 61, + 100, + 93, + 25, + 115, + 96, + 129, + 79, + 220, + 34, + 42, + 144, + 136, + 70, + 238, + 184, + 20, + 222, + 94, + 11, + 219, + 224, + 50, + 58, + 10, + 73, + 6, + 36, + 92, + 194, + 211, + 172, + 98, + 145, + 149, + 228, + 121, + 231, + 200, + 55, + 109, + 141, + 213, + 78, + 169, + 108, + 86, + 244, + 234, + 101, + 122, + 174, + 8, + 186, + 120, + 37, + 46, + 28, + 166, + 180, + 198, + 232, + 221, + 116, + 31, + 75, + 189, + 139, + 138, + 112, + 62, + 181, + 102, + 72, + 3, + 246, + 14, + 97, + 53, + 87, + 185, + 134, + 193, + 29, + 158, + 225, + 248, + 152, + 17, + 105, + 217, + 142, + 148, + 155, + 30, + 135, + 233, + 206, + 85, + 40, + 223, + 140, + 161, + 137, + 13, + 191, + 230, + 66, + 104, + 65, + 153, + 45, + 15, + 176, + 84, + 187, + 22, + ]; + r0 = [ + 0xa56363c6, + 0x847c7cf8, + 0x997777ee, + 0x8d7b7bf6, + 0x0df2f2ff, + 0xbd6b6bd6, + 0xb16f6fde, + 0x54c5c591, + 0x50303060, + 0x03010102, + 0xa96767ce, + 0x7d2b2b56, + 0x19fefee7, + 0x62d7d7b5, + 0xe6abab4d, + 0x9a7676ec, + 0x45caca8f, + 0x9d82821f, + 0x40c9c989, + 0x877d7dfa, + 0x15fafaef, + 0xeb5959b2, + 0xc947478e, + 0x0bf0f0fb, + 0xecadad41, + 0x67d4d4b3, + 0xfda2a25f, + 0xeaafaf45, + 0xbf9c9c23, + 0xf7a4a453, + 0x967272e4, + 0x5bc0c09b, + 0xc2b7b775, + 0x1cfdfde1, + 0xae93933d, + 0x6a26264c, + 0x5a36366c, + 0x413f3f7e, + 0x02f7f7f5, + 0x4fcccc83, + 0x5c343468, + 0xf4a5a551, + 0x34e5e5d1, + 0x08f1f1f9, + 0x937171e2, + 0x73d8d8ab, + 0x53313162, + 0x3f15152a, + 0x0c040408, + 0x52c7c795, + 0x65232346, + 0x5ec3c39d, + 0x28181830, + 0xa1969637, + 0x0f05050a, + 0xb59a9a2f, + 0x0907070e, + 0x36121224, + 0x9b80801b, + 0x3de2e2df, + 0x26ebebcd, + 0x6927274e, + 0xcdb2b27f, + 0x9f7575ea, + 0x1b090912, + 0x9e83831d, + 0x742c2c58, + 0x2e1a1a34, + 0x2d1b1b36, + 0xb26e6edc, + 0xee5a5ab4, + 0xfba0a05b, + 0xf65252a4, + 0x4d3b3b76, + 0x61d6d6b7, + 0xceb3b37d, + 0x7b292952, + 0x3ee3e3dd, + 0x712f2f5e, + 0x97848413, + 0xf55353a6, + 0x68d1d1b9, + 0x00000000, + 0x2cededc1, + 0x60202040, + 0x1ffcfce3, + 0xc8b1b179, + 0xed5b5bb6, + 0xbe6a6ad4, + 0x46cbcb8d, + 0xd9bebe67, + 0x4b393972, + 0xde4a4a94, + 0xd44c4c98, + 0xe85858b0, + 0x4acfcf85, + 0x6bd0d0bb, + 0x2aefefc5, + 0xe5aaaa4f, + 0x16fbfbed, + 0xc5434386, + 0xd74d4d9a, + 0x55333366, + 0x94858511, + 0xcf45458a, + 0x10f9f9e9, + 0x06020204, + 0x817f7ffe, + 0xf05050a0, + 0x443c3c78, + 0xba9f9f25, + 0xe3a8a84b, + 0xf35151a2, + 0xfea3a35d, + 0xc0404080, + 0x8a8f8f05, + 0xad92923f, + 0xbc9d9d21, + 0x48383870, + 0x04f5f5f1, + 0xdfbcbc63, + 0xc1b6b677, + 0x75dadaaf, + 0x63212142, + 0x30101020, + 0x1affffe5, + 0x0ef3f3fd, + 0x6dd2d2bf, + 0x4ccdcd81, + 0x140c0c18, + 0x35131326, + 0x2fececc3, + 0xe15f5fbe, + 0xa2979735, + 0xcc444488, + 0x3917172e, + 0x57c4c493, + 0xf2a7a755, + 0x827e7efc, + 0x473d3d7a, + 0xac6464c8, + 0xe75d5dba, + 0x2b191932, + 0x957373e6, + 0xa06060c0, + 0x98818119, + 0xd14f4f9e, + 0x7fdcdca3, + 0x66222244, + 0x7e2a2a54, + 0xab90903b, + 0x8388880b, + 0xca46468c, + 0x29eeeec7, + 0xd3b8b86b, + 0x3c141428, + 0x79dedea7, + 0xe25e5ebc, + 0x1d0b0b16, + 0x76dbdbad, + 0x3be0e0db, + 0x56323264, + 0x4e3a3a74, + 0x1e0a0a14, + 0xdb494992, + 0x0a06060c, + 0x6c242448, + 0xe45c5cb8, + 0x5dc2c29f, + 0x6ed3d3bd, + 0xefacac43, + 0xa66262c4, + 0xa8919139, + 0xa4959531, + 0x37e4e4d3, + 0x8b7979f2, + 0x32e7e7d5, + 0x43c8c88b, + 0x5937376e, + 0xb76d6dda, + 0x8c8d8d01, + 0x64d5d5b1, + 0xd24e4e9c, + 0xe0a9a949, + 0xb46c6cd8, + 0xfa5656ac, + 0x07f4f4f3, + 0x25eaeacf, + 0xaf6565ca, + 0x8e7a7af4, + 0xe9aeae47, + 0x18080810, + 0xd5baba6f, + 0x887878f0, + 0x6f25254a, + 0x722e2e5c, + 0x241c1c38, + 0xf1a6a657, + 0xc7b4b473, + 0x51c6c697, + 0x23e8e8cb, + 0x7cdddda1, + 0x9c7474e8, + 0x211f1f3e, + 0xdd4b4b96, + 0xdcbdbd61, + 0x868b8b0d, + 0x858a8a0f, + 0x907070e0, + 0x423e3e7c, + 0xc4b5b571, + 0xaa6666cc, + 0xd8484890, + 0x05030306, + 0x01f6f6f7, + 0x120e0e1c, + 0xa36161c2, + 0x5f35356a, + 0xf95757ae, + 0xd0b9b969, + 0x91868617, + 0x58c1c199, + 0x271d1d3a, + 0xb99e9e27, + 0x38e1e1d9, + 0x13f8f8eb, + 0xb398982b, + 0x33111122, + 0xbb6969d2, + 0x70d9d9a9, + 0x898e8e07, + 0xa7949433, + 0xb69b9b2d, + 0x221e1e3c, + 0x92878715, + 0x20e9e9c9, + 0x49cece87, + 0xff5555aa, + 0x78282850, + 0x7adfdfa5, + 0x8f8c8c03, + 0xf8a1a159, + 0x80898909, + 0x170d0d1a, + 0xdabfbf65, + 0x31e6e6d7, + 0xc6424284, + 0xb86868d0, + 0xc3414182, + 0xb0999929, + 0x772d2d5a, + 0x110f0f1e, + 0xcbb0b07b, + 0xfc5454a8, + 0xd6bbbb6d, + 0x3a16162c, + ]; + r1 = [ + 0x6363c6a5, + 0x7c7cf884, + 0x7777ee99, + 0x7b7bf68d, + 0xf2f2ff0d, + 0x6b6bd6bd, + 0x6f6fdeb1, + 0xc5c59154, + 0x30306050, + 0x01010203, + 0x6767cea9, + 0x2b2b567d, + 0xfefee719, + 0xd7d7b562, + 0xabab4de6, + 0x7676ec9a, + 0xcaca8f45, + 0x82821f9d, + 0xc9c98940, + 0x7d7dfa87, + 0xfafaef15, + 0x5959b2eb, + 0x47478ec9, + 0xf0f0fb0b, + 0xadad41ec, + 0xd4d4b367, + 0xa2a25ffd, + 0xafaf45ea, + 0x9c9c23bf, + 0xa4a453f7, + 0x7272e496, + 0xc0c09b5b, + 0xb7b775c2, + 0xfdfde11c, + 0x93933dae, + 0x26264c6a, + 0x36366c5a, + 0x3f3f7e41, + 0xf7f7f502, + 0xcccc834f, + 0x3434685c, + 0xa5a551f4, + 0xe5e5d134, + 0xf1f1f908, + 0x7171e293, + 0xd8d8ab73, + 0x31316253, + 0x15152a3f, + 0x0404080c, + 0xc7c79552, + 0x23234665, + 0xc3c39d5e, + 0x18183028, + 0x969637a1, + 0x05050a0f, + 0x9a9a2fb5, + 0x07070e09, + 0x12122436, + 0x80801b9b, + 0xe2e2df3d, + 0xebebcd26, + 0x27274e69, + 0xb2b27fcd, + 0x7575ea9f, + 0x0909121b, + 0x83831d9e, + 0x2c2c5874, + 0x1a1a342e, + 0x1b1b362d, + 0x6e6edcb2, + 0x5a5ab4ee, + 0xa0a05bfb, + 0x5252a4f6, + 0x3b3b764d, + 0xd6d6b761, + 0xb3b37dce, + 0x2929527b, + 0xe3e3dd3e, + 0x2f2f5e71, + 0x84841397, + 0x5353a6f5, + 0xd1d1b968, + 0x00000000, + 0xededc12c, + 0x20204060, + 0xfcfce31f, + 0xb1b179c8, + 0x5b5bb6ed, + 0x6a6ad4be, + 0xcbcb8d46, + 0xbebe67d9, + 0x3939724b, + 0x4a4a94de, + 0x4c4c98d4, + 0x5858b0e8, + 0xcfcf854a, + 0xd0d0bb6b, + 0xefefc52a, + 0xaaaa4fe5, + 0xfbfbed16, + 0x434386c5, + 0x4d4d9ad7, + 0x33336655, + 0x85851194, + 0x45458acf, + 0xf9f9e910, + 0x02020406, + 0x7f7ffe81, + 0x5050a0f0, + 0x3c3c7844, + 0x9f9f25ba, + 0xa8a84be3, + 0x5151a2f3, + 0xa3a35dfe, + 0x404080c0, + 0x8f8f058a, + 0x92923fad, + 0x9d9d21bc, + 0x38387048, + 0xf5f5f104, + 0xbcbc63df, + 0xb6b677c1, + 0xdadaaf75, + 0x21214263, + 0x10102030, + 0xffffe51a, + 0xf3f3fd0e, + 0xd2d2bf6d, + 0xcdcd814c, + 0x0c0c1814, + 0x13132635, + 0xececc32f, + 0x5f5fbee1, + 0x979735a2, + 0x444488cc, + 0x17172e39, + 0xc4c49357, + 0xa7a755f2, + 0x7e7efc82, + 0x3d3d7a47, + 0x6464c8ac, + 0x5d5dbae7, + 0x1919322b, + 0x7373e695, + 0x6060c0a0, + 0x81811998, + 0x4f4f9ed1, + 0xdcdca37f, + 0x22224466, + 0x2a2a547e, + 0x90903bab, + 0x88880b83, + 0x46468cca, + 0xeeeec729, + 0xb8b86bd3, + 0x1414283c, + 0xdedea779, + 0x5e5ebce2, + 0x0b0b161d, + 0xdbdbad76, + 0xe0e0db3b, + 0x32326456, + 0x3a3a744e, + 0x0a0a141e, + 0x494992db, + 0x06060c0a, + 0x2424486c, + 0x5c5cb8e4, + 0xc2c29f5d, + 0xd3d3bd6e, + 0xacac43ef, + 0x6262c4a6, + 0x919139a8, + 0x959531a4, + 0xe4e4d337, + 0x7979f28b, + 0xe7e7d532, + 0xc8c88b43, + 0x37376e59, + 0x6d6ddab7, + 0x8d8d018c, + 0xd5d5b164, + 0x4e4e9cd2, + 0xa9a949e0, + 0x6c6cd8b4, + 0x5656acfa, + 0xf4f4f307, + 0xeaeacf25, + 0x6565caaf, + 0x7a7af48e, + 0xaeae47e9, + 0x08081018, + 0xbaba6fd5, + 0x7878f088, + 0x25254a6f, + 0x2e2e5c72, + 0x1c1c3824, + 0xa6a657f1, + 0xb4b473c7, + 0xc6c69751, + 0xe8e8cb23, + 0xdddda17c, + 0x7474e89c, + 0x1f1f3e21, + 0x4b4b96dd, + 0xbdbd61dc, + 0x8b8b0d86, + 0x8a8a0f85, + 0x7070e090, + 0x3e3e7c42, + 0xb5b571c4, + 0x6666ccaa, + 0x484890d8, + 0x03030605, + 0xf6f6f701, + 0x0e0e1c12, + 0x6161c2a3, + 0x35356a5f, + 0x5757aef9, + 0xb9b969d0, + 0x86861791, + 0xc1c19958, + 0x1d1d3a27, + 0x9e9e27b9, + 0xe1e1d938, + 0xf8f8eb13, + 0x98982bb3, + 0x11112233, + 0x6969d2bb, + 0xd9d9a970, + 0x8e8e0789, + 0x949433a7, + 0x9b9b2db6, + 0x1e1e3c22, + 0x87871592, + 0xe9e9c920, + 0xcece8749, + 0x5555aaff, + 0x28285078, + 0xdfdfa57a, + 0x8c8c038f, + 0xa1a159f8, + 0x89890980, + 0x0d0d1a17, + 0xbfbf65da, + 0xe6e6d731, + 0x424284c6, + 0x6868d0b8, + 0x414182c3, + 0x999929b0, + 0x2d2d5a77, + 0x0f0f1e11, + 0xb0b07bcb, + 0x5454a8fc, + 0xbbbb6dd6, + 0x16162c3a, + ]; + r2 = [ + 0x63c6a563, + 0x7cf8847c, + 0x77ee9977, + 0x7bf68d7b, + 0xf2ff0df2, + 0x6bd6bd6b, + 0x6fdeb16f, + 0xc59154c5, + 0x30605030, + 0x01020301, + 0x67cea967, + 0x2b567d2b, + 0xfee719fe, + 0xd7b562d7, + 0xab4de6ab, + 0x76ec9a76, + 0xca8f45ca, + 0x821f9d82, + 0xc98940c9, + 0x7dfa877d, + 0xfaef15fa, + 0x59b2eb59, + 0x478ec947, + 0xf0fb0bf0, + 0xad41ecad, + 0xd4b367d4, + 0xa25ffda2, + 0xaf45eaaf, + 0x9c23bf9c, + 0xa453f7a4, + 0x72e49672, + 0xc09b5bc0, + 0xb775c2b7, + 0xfde11cfd, + 0x933dae93, + 0x264c6a26, + 0x366c5a36, + 0x3f7e413f, + 0xf7f502f7, + 0xcc834fcc, + 0x34685c34, + 0xa551f4a5, + 0xe5d134e5, + 0xf1f908f1, + 0x71e29371, + 0xd8ab73d8, + 0x31625331, + 0x152a3f15, + 0x04080c04, + 0xc79552c7, + 0x23466523, + 0xc39d5ec3, + 0x18302818, + 0x9637a196, + 0x050a0f05, + 0x9a2fb59a, + 0x070e0907, + 0x12243612, + 0x801b9b80, + 0xe2df3de2, + 0xebcd26eb, + 0x274e6927, + 0xb27fcdb2, + 0x75ea9f75, + 0x09121b09, + 0x831d9e83, + 0x2c58742c, + 0x1a342e1a, + 0x1b362d1b, + 0x6edcb26e, + 0x5ab4ee5a, + 0xa05bfba0, + 0x52a4f652, + 0x3b764d3b, + 0xd6b761d6, + 0xb37dceb3, + 0x29527b29, + 0xe3dd3ee3, + 0x2f5e712f, + 0x84139784, + 0x53a6f553, + 0xd1b968d1, + 0x00000000, + 0xedc12ced, + 0x20406020, + 0xfce31ffc, + 0xb179c8b1, + 0x5bb6ed5b, + 0x6ad4be6a, + 0xcb8d46cb, + 0xbe67d9be, + 0x39724b39, + 0x4a94de4a, + 0x4c98d44c, + 0x58b0e858, + 0xcf854acf, + 0xd0bb6bd0, + 0xefc52aef, + 0xaa4fe5aa, + 0xfbed16fb, + 0x4386c543, + 0x4d9ad74d, + 0x33665533, + 0x85119485, + 0x458acf45, + 0xf9e910f9, + 0x02040602, + 0x7ffe817f, + 0x50a0f050, + 0x3c78443c, + 0x9f25ba9f, + 0xa84be3a8, + 0x51a2f351, + 0xa35dfea3, + 0x4080c040, + 0x8f058a8f, + 0x923fad92, + 0x9d21bc9d, + 0x38704838, + 0xf5f104f5, + 0xbc63dfbc, + 0xb677c1b6, + 0xdaaf75da, + 0x21426321, + 0x10203010, + 0xffe51aff, + 0xf3fd0ef3, + 0xd2bf6dd2, + 0xcd814ccd, + 0x0c18140c, + 0x13263513, + 0xecc32fec, + 0x5fbee15f, + 0x9735a297, + 0x4488cc44, + 0x172e3917, + 0xc49357c4, + 0xa755f2a7, + 0x7efc827e, + 0x3d7a473d, + 0x64c8ac64, + 0x5dbae75d, + 0x19322b19, + 0x73e69573, + 0x60c0a060, + 0x81199881, + 0x4f9ed14f, + 0xdca37fdc, + 0x22446622, + 0x2a547e2a, + 0x903bab90, + 0x880b8388, + 0x468cca46, + 0xeec729ee, + 0xb86bd3b8, + 0x14283c14, + 0xdea779de, + 0x5ebce25e, + 0x0b161d0b, + 0xdbad76db, + 0xe0db3be0, + 0x32645632, + 0x3a744e3a, + 0x0a141e0a, + 0x4992db49, + 0x060c0a06, + 0x24486c24, + 0x5cb8e45c, + 0xc29f5dc2, + 0xd3bd6ed3, + 0xac43efac, + 0x62c4a662, + 0x9139a891, + 0x9531a495, + 0xe4d337e4, + 0x79f28b79, + 0xe7d532e7, + 0xc88b43c8, + 0x376e5937, + 0x6ddab76d, + 0x8d018c8d, + 0xd5b164d5, + 0x4e9cd24e, + 0xa949e0a9, + 0x6cd8b46c, + 0x56acfa56, + 0xf4f307f4, + 0xeacf25ea, + 0x65caaf65, + 0x7af48e7a, + 0xae47e9ae, + 0x08101808, + 0xba6fd5ba, + 0x78f08878, + 0x254a6f25, + 0x2e5c722e, + 0x1c38241c, + 0xa657f1a6, + 0xb473c7b4, + 0xc69751c6, + 0xe8cb23e8, + 0xdda17cdd, + 0x74e89c74, + 0x1f3e211f, + 0x4b96dd4b, + 0xbd61dcbd, + 0x8b0d868b, + 0x8a0f858a, + 0x70e09070, + 0x3e7c423e, + 0xb571c4b5, + 0x66ccaa66, + 0x4890d848, + 0x03060503, + 0xf6f701f6, + 0x0e1c120e, + 0x61c2a361, + 0x356a5f35, + 0x57aef957, + 0xb969d0b9, + 0x86179186, + 0xc19958c1, + 0x1d3a271d, + 0x9e27b99e, + 0xe1d938e1, + 0xf8eb13f8, + 0x982bb398, + 0x11223311, + 0x69d2bb69, + 0xd9a970d9, + 0x8e07898e, + 0x9433a794, + 0x9b2db69b, + 0x1e3c221e, + 0x87159287, + 0xe9c920e9, + 0xce8749ce, + 0x55aaff55, + 0x28507828, + 0xdfa57adf, + 0x8c038f8c, + 0xa159f8a1, + 0x89098089, + 0x0d1a170d, + 0xbf65dabf, + 0xe6d731e6, + 0x4284c642, + 0x68d0b868, + 0x4182c341, + 0x9929b099, + 0x2d5a772d, + 0x0f1e110f, + 0xb07bcbb0, + 0x54a8fc54, + 0xbb6dd6bb, + 0x162c3a16, + ]; + r3 = [ + 0xc6a56363, + 0xf8847c7c, + 0xee997777, + 0xf68d7b7b, + 0xff0df2f2, + 0xd6bd6b6b, + 0xdeb16f6f, + 0x9154c5c5, + 0x60503030, + 0x02030101, + 0xcea96767, + 0x567d2b2b, + 0xe719fefe, + 0xb562d7d7, + 0x4de6abab, + 0xec9a7676, + 0x8f45caca, + 0x1f9d8282, + 0x8940c9c9, + 0xfa877d7d, + 0xef15fafa, + 0xb2eb5959, + 0x8ec94747, + 0xfb0bf0f0, + 0x41ecadad, + 0xb367d4d4, + 0x5ffda2a2, + 0x45eaafaf, + 0x23bf9c9c, + 0x53f7a4a4, + 0xe4967272, + 0x9b5bc0c0, + 0x75c2b7b7, + 0xe11cfdfd, + 0x3dae9393, + 0x4c6a2626, + 0x6c5a3636, + 0x7e413f3f, + 0xf502f7f7, + 0x834fcccc, + 0x685c3434, + 0x51f4a5a5, + 0xd134e5e5, + 0xf908f1f1, + 0xe2937171, + 0xab73d8d8, + 0x62533131, + 0x2a3f1515, + 0x080c0404, + 0x9552c7c7, + 0x46652323, + 0x9d5ec3c3, + 0x30281818, + 0x37a19696, + 0x0a0f0505, + 0x2fb59a9a, + 0x0e090707, + 0x24361212, + 0x1b9b8080, + 0xdf3de2e2, + 0xcd26ebeb, + 0x4e692727, + 0x7fcdb2b2, + 0xea9f7575, + 0x121b0909, + 0x1d9e8383, + 0x58742c2c, + 0x342e1a1a, + 0x362d1b1b, + 0xdcb26e6e, + 0xb4ee5a5a, + 0x5bfba0a0, + 0xa4f65252, + 0x764d3b3b, + 0xb761d6d6, + 0x7dceb3b3, + 0x527b2929, + 0xdd3ee3e3, + 0x5e712f2f, + 0x13978484, + 0xa6f55353, + 0xb968d1d1, + 0x00000000, + 0xc12ceded, + 0x40602020, + 0xe31ffcfc, + 0x79c8b1b1, + 0xb6ed5b5b, + 0xd4be6a6a, + 0x8d46cbcb, + 0x67d9bebe, + 0x724b3939, + 0x94de4a4a, + 0x98d44c4c, + 0xb0e85858, + 0x854acfcf, + 0xbb6bd0d0, + 0xc52aefef, + 0x4fe5aaaa, + 0xed16fbfb, + 0x86c54343, + 0x9ad74d4d, + 0x66553333, + 0x11948585, + 0x8acf4545, + 0xe910f9f9, + 0x04060202, + 0xfe817f7f, + 0xa0f05050, + 0x78443c3c, + 0x25ba9f9f, + 0x4be3a8a8, + 0xa2f35151, + 0x5dfea3a3, + 0x80c04040, + 0x058a8f8f, + 0x3fad9292, + 0x21bc9d9d, + 0x70483838, + 0xf104f5f5, + 0x63dfbcbc, + 0x77c1b6b6, + 0xaf75dada, + 0x42632121, + 0x20301010, + 0xe51affff, + 0xfd0ef3f3, + 0xbf6dd2d2, + 0x814ccdcd, + 0x18140c0c, + 0x26351313, + 0xc32fecec, + 0xbee15f5f, + 0x35a29797, + 0x88cc4444, + 0x2e391717, + 0x9357c4c4, + 0x55f2a7a7, + 0xfc827e7e, + 0x7a473d3d, + 0xc8ac6464, + 0xbae75d5d, + 0x322b1919, + 0xe6957373, + 0xc0a06060, + 0x19988181, + 0x9ed14f4f, + 0xa37fdcdc, + 0x44662222, + 0x547e2a2a, + 0x3bab9090, + 0x0b838888, + 0x8cca4646, + 0xc729eeee, + 0x6bd3b8b8, + 0x283c1414, + 0xa779dede, + 0xbce25e5e, + 0x161d0b0b, + 0xad76dbdb, + 0xdb3be0e0, + 0x64563232, + 0x744e3a3a, + 0x141e0a0a, + 0x92db4949, + 0x0c0a0606, + 0x486c2424, + 0xb8e45c5c, + 0x9f5dc2c2, + 0xbd6ed3d3, + 0x43efacac, + 0xc4a66262, + 0x39a89191, + 0x31a49595, + 0xd337e4e4, + 0xf28b7979, + 0xd532e7e7, + 0x8b43c8c8, + 0x6e593737, + 0xdab76d6d, + 0x018c8d8d, + 0xb164d5d5, + 0x9cd24e4e, + 0x49e0a9a9, + 0xd8b46c6c, + 0xacfa5656, + 0xf307f4f4, + 0xcf25eaea, + 0xcaaf6565, + 0xf48e7a7a, + 0x47e9aeae, + 0x10180808, + 0x6fd5baba, + 0xf0887878, + 0x4a6f2525, + 0x5c722e2e, + 0x38241c1c, + 0x57f1a6a6, + 0x73c7b4b4, + 0x9751c6c6, + 0xcb23e8e8, + 0xa17cdddd, + 0xe89c7474, + 0x3e211f1f, + 0x96dd4b4b, + 0x61dcbdbd, + 0x0d868b8b, + 0x0f858a8a, + 0xe0907070, + 0x7c423e3e, + 0x71c4b5b5, + 0xccaa6666, + 0x90d84848, + 0x06050303, + 0xf701f6f6, + 0x1c120e0e, + 0xc2a36161, + 0x6a5f3535, + 0xaef95757, + 0x69d0b9b9, + 0x17918686, + 0x9958c1c1, + 0x3a271d1d, + 0x27b99e9e, + 0xd938e1e1, + 0xeb13f8f8, + 0x2bb39898, + 0x22331111, + 0xd2bb6969, + 0xa970d9d9, + 0x07898e8e, + 0x33a79494, + 0x2db69b9b, + 0x3c221e1e, + 0x15928787, + 0xc920e9e9, + 0x8749cece, + 0xaaff5555, + 0x50782828, + 0xa57adfdf, + 0x038f8c8c, + 0x59f8a1a1, + 0x09808989, + 0x1a170d0d, + 0x65dabfbf, + 0xd731e6e6, + 0x84c64242, + 0xd0b86868, + 0x82c34141, + 0x29b09999, + 0x5a772d2d, + 0x1e110f0f, + 0x7bcbb0b0, + 0xa8fc5454, + 0x6dd6bbbb, + 0x2c3a1616, + ]; + sinv = [ + 82, + 9, + 106, + 213, + 48, + 54, + 165, + 56, + 191, + 64, + 163, + 158, + 129, + 243, + 215, + 251, + 124, + 227, + 57, + 130, + 155, + 47, + 255, + 135, + 52, + 142, + 67, + 68, + 196, + 222, + 233, + 203, + 84, + 123, + 148, + 50, + 166, + 194, + 35, + 61, + 238, + 76, + 149, + 11, + 66, + 250, + 195, + 78, + 8, + 46, + 161, + 102, + 40, + 217, + 36, + 178, + 118, + 91, + 162, + 73, + 109, + 139, + 209, + 37, + 114, + 248, + 246, + 100, + 134, + 104, + 152, + 22, + 212, + 164, + 92, + 204, + 93, + 101, + 182, + 146, + 108, + 112, + 72, + 80, + 253, + 237, + 185, + 218, + 94, + 21, + 70, + 87, + 167, + 141, + 157, + 132, + 144, + 216, + 171, + 0, + 140, + 188, + 211, + 10, + 247, + 228, + 88, + 5, + 184, + 179, + 69, + 6, + 208, + 44, + 30, + 143, + 202, + 63, + 15, + 2, + 193, + 175, + 189, + 3, + 1, + 19, + 138, + 107, + 58, + 145, + 17, + 65, + 79, + 103, + 220, + 234, + 151, + 242, + 207, + 206, + 240, + 180, + 230, + 115, + 150, + 172, + 116, + 34, + 231, + 173, + 53, + 133, + 226, + 249, + 55, + 232, + 28, + 117, + 223, + 110, + 71, + 241, + 26, + 113, + 29, + 41, + 197, + 137, + 111, + 183, + 98, + 14, + 170, + 24, + 190, + 27, + 252, + 86, + 62, + 75, + 198, + 210, + 121, + 32, + 154, + 219, + 192, + 254, + 120, + 205, + 90, + 244, + 31, + 221, + 168, + 51, + 136, + 7, + 199, + 49, + 177, + 18, + 16, + 89, + 39, + 128, + 236, + 95, + 96, + 81, + 127, + 169, + 25, + 181, + 74, + 13, + 45, + 229, + 122, + 159, + 147, + 201, + 156, + 239, + 160, + 224, + 59, + 77, + 174, + 42, + 245, + 176, + 200, + 235, + 187, + 60, + 131, + 83, + 153, + 97, + 23, + 43, + 4, + 126, + 186, + 119, + 214, + 38, + 225, + 105, + 20, + 99, + 85, + 33, + 12, + 125, + ]; + rinv0 = [ + 0x50a7f451, + 0x5365417e, + 0xc3a4171a, + 0x965e273a, + 0xcb6bab3b, + 0xf1459d1f, + 0xab58faac, + 0x9303e34b, + 0x55fa3020, + 0xf66d76ad, + 0x9176cc88, + 0x254c02f5, + 0xfcd7e54f, + 0xd7cb2ac5, + 0x80443526, + 0x8fa362b5, + 0x495ab1de, + 0x671bba25, + 0x980eea45, + 0xe1c0fe5d, + 0x02752fc3, + 0x12f04c81, + 0xa397468d, + 0xc6f9d36b, + 0xe75f8f03, + 0x959c9215, + 0xeb7a6dbf, + 0xda595295, + 0x2d83bed4, + 0xd3217458, + 0x2969e049, + 0x44c8c98e, + 0x6a89c275, + 0x78798ef4, + 0x6b3e5899, + 0xdd71b927, + 0xb64fe1be, + 0x17ad88f0, + 0x66ac20c9, + 0xb43ace7d, + 0x184adf63, + 0x82311ae5, + 0x60335197, + 0x457f5362, + 0xe07764b1, + 0x84ae6bbb, + 0x1ca081fe, + 0x942b08f9, + 0x58684870, + 0x19fd458f, + 0x876cde94, + 0xb7f87b52, + 0x23d373ab, + 0xe2024b72, + 0x578f1fe3, + 0x2aab5566, + 0x0728ebb2, + 0x03c2b52f, + 0x9a7bc586, + 0xa50837d3, + 0xf2872830, + 0xb2a5bf23, + 0xba6a0302, + 0x5c8216ed, + 0x2b1ccf8a, + 0x92b479a7, + 0xf0f207f3, + 0xa1e2694e, + 0xcdf4da65, + 0xd5be0506, + 0x1f6234d1, + 0x8afea6c4, + 0x9d532e34, + 0xa055f3a2, + 0x32e18a05, + 0x75ebf6a4, + 0x39ec830b, + 0xaaef6040, + 0x069f715e, + 0x51106ebd, + 0xf98a213e, + 0x3d06dd96, + 0xae053edd, + 0x46bde64d, + 0xb58d5491, + 0x055dc471, + 0x6fd40604, + 0xff155060, + 0x24fb9819, + 0x97e9bdd6, + 0xcc434089, + 0x779ed967, + 0xbd42e8b0, + 0x888b8907, + 0x385b19e7, + 0xdbeec879, + 0x470a7ca1, + 0xe90f427c, + 0xc91e84f8, + 0x00000000, + 0x83868009, + 0x48ed2b32, + 0xac70111e, + 0x4e725a6c, + 0xfbff0efd, + 0x5638850f, + 0x1ed5ae3d, + 0x27392d36, + 0x64d90f0a, + 0x21a65c68, + 0xd1545b9b, + 0x3a2e3624, + 0xb1670a0c, + 0x0fe75793, + 0xd296eeb4, + 0x9e919b1b, + 0x4fc5c080, + 0xa220dc61, + 0x694b775a, + 0x161a121c, + 0x0aba93e2, + 0xe52aa0c0, + 0x43e0223c, + 0x1d171b12, + 0x0b0d090e, + 0xadc78bf2, + 0xb9a8b62d, + 0xc8a91e14, + 0x8519f157, + 0x4c0775af, + 0xbbdd99ee, + 0xfd607fa3, + 0x9f2601f7, + 0xbcf5725c, + 0xc53b6644, + 0x347efb5b, + 0x7629438b, + 0xdcc623cb, + 0x68fcedb6, + 0x63f1e4b8, + 0xcadc31d7, + 0x10856342, + 0x40229713, + 0x2011c684, + 0x7d244a85, + 0xf83dbbd2, + 0x1132f9ae, + 0x6da129c7, + 0x4b2f9e1d, + 0xf330b2dc, + 0xec52860d, + 0xd0e3c177, + 0x6c16b32b, + 0x99b970a9, + 0xfa489411, + 0x2264e947, + 0xc48cfca8, + 0x1a3ff0a0, + 0xd82c7d56, + 0xef903322, + 0xc74e4987, + 0xc1d138d9, + 0xfea2ca8c, + 0x360bd498, + 0xcf81f5a6, + 0x28de7aa5, + 0x268eb7da, + 0xa4bfad3f, + 0xe49d3a2c, + 0x0d927850, + 0x9bcc5f6a, + 0x62467e54, + 0xc2138df6, + 0xe8b8d890, + 0x5ef7392e, + 0xf5afc382, + 0xbe805d9f, + 0x7c93d069, + 0xa92dd56f, + 0xb31225cf, + 0x3b99acc8, + 0xa77d1810, + 0x6e639ce8, + 0x7bbb3bdb, + 0x097826cd, + 0xf418596e, + 0x01b79aec, + 0xa89a4f83, + 0x656e95e6, + 0x7ee6ffaa, + 0x08cfbc21, + 0xe6e815ef, + 0xd99be7ba, + 0xce366f4a, + 0xd4099fea, + 0xd67cb029, + 0xafb2a431, + 0x31233f2a, + 0x3094a5c6, + 0xc066a235, + 0x37bc4e74, + 0xa6ca82fc, + 0xb0d090e0, + 0x15d8a733, + 0x4a9804f1, + 0xf7daec41, + 0x0e50cd7f, + 0x2ff69117, + 0x8dd64d76, + 0x4db0ef43, + 0x544daacc, + 0xdf0496e4, + 0xe3b5d19e, + 0x1b886a4c, + 0xb81f2cc1, + 0x7f516546, + 0x04ea5e9d, + 0x5d358c01, + 0x737487fa, + 0x2e410bfb, + 0x5a1d67b3, + 0x52d2db92, + 0x335610e9, + 0x1347d66d, + 0x8c61d79a, + 0x7a0ca137, + 0x8e14f859, + 0x893c13eb, + 0xee27a9ce, + 0x35c961b7, + 0xede51ce1, + 0x3cb1477a, + 0x59dfd29c, + 0x3f73f255, + 0x79ce1418, + 0xbf37c773, + 0xeacdf753, + 0x5baafd5f, + 0x146f3ddf, + 0x86db4478, + 0x81f3afca, + 0x3ec468b9, + 0x2c342438, + 0x5f40a3c2, + 0x72c31d16, + 0x0c25e2bc, + 0x8b493c28, + 0x41950dff, + 0x7101a839, + 0xdeb30c08, + 0x9ce4b4d8, + 0x90c15664, + 0x6184cb7b, + 0x70b632d5, + 0x745c6c48, + 0x4257b8d0, + ]; + rinv1 = [ + 0xa7f45150, + 0x65417e53, + 0xa4171ac3, + 0x5e273a96, + 0x6bab3bcb, + 0x459d1ff1, + 0x58faacab, + 0x03e34b93, + 0xfa302055, + 0x6d76adf6, + 0x76cc8891, + 0x4c02f525, + 0xd7e54ffc, + 0xcb2ac5d7, + 0x44352680, + 0xa362b58f, + 0x5ab1de49, + 0x1bba2567, + 0x0eea4598, + 0xc0fe5de1, + 0x752fc302, + 0xf04c8112, + 0x97468da3, + 0xf9d36bc6, + 0x5f8f03e7, + 0x9c921595, + 0x7a6dbfeb, + 0x595295da, + 0x83bed42d, + 0x217458d3, + 0x69e04929, + 0xc8c98e44, + 0x89c2756a, + 0x798ef478, + 0x3e58996b, + 0x71b927dd, + 0x4fe1beb6, + 0xad88f017, + 0xac20c966, + 0x3ace7db4, + 0x4adf6318, + 0x311ae582, + 0x33519760, + 0x7f536245, + 0x7764b1e0, + 0xae6bbb84, + 0xa081fe1c, + 0x2b08f994, + 0x68487058, + 0xfd458f19, + 0x6cde9487, + 0xf87b52b7, + 0xd373ab23, + 0x024b72e2, + 0x8f1fe357, + 0xab55662a, + 0x28ebb207, + 0xc2b52f03, + 0x7bc5869a, + 0x0837d3a5, + 0x872830f2, + 0xa5bf23b2, + 0x6a0302ba, + 0x8216ed5c, + 0x1ccf8a2b, + 0xb479a792, + 0xf207f3f0, + 0xe2694ea1, + 0xf4da65cd, + 0xbe0506d5, + 0x6234d11f, + 0xfea6c48a, + 0x532e349d, + 0x55f3a2a0, + 0xe18a0532, + 0xebf6a475, + 0xec830b39, + 0xef6040aa, + 0x9f715e06, + 0x106ebd51, + 0x8a213ef9, + 0x06dd963d, + 0x053eddae, + 0xbde64d46, + 0x8d5491b5, + 0x5dc47105, + 0xd406046f, + 0x155060ff, + 0xfb981924, + 0xe9bdd697, + 0x434089cc, + 0x9ed96777, + 0x42e8b0bd, + 0x8b890788, + 0x5b19e738, + 0xeec879db, + 0x0a7ca147, + 0x0f427ce9, + 0x1e84f8c9, + 0x00000000, + 0x86800983, + 0xed2b3248, + 0x70111eac, + 0x725a6c4e, + 0xff0efdfb, + 0x38850f56, + 0xd5ae3d1e, + 0x392d3627, + 0xd90f0a64, + 0xa65c6821, + 0x545b9bd1, + 0x2e36243a, + 0x670a0cb1, + 0xe757930f, + 0x96eeb4d2, + 0x919b1b9e, + 0xc5c0804f, + 0x20dc61a2, + 0x4b775a69, + 0x1a121c16, + 0xba93e20a, + 0x2aa0c0e5, + 0xe0223c43, + 0x171b121d, + 0x0d090e0b, + 0xc78bf2ad, + 0xa8b62db9, + 0xa91e14c8, + 0x19f15785, + 0x0775af4c, + 0xdd99eebb, + 0x607fa3fd, + 0x2601f79f, + 0xf5725cbc, + 0x3b6644c5, + 0x7efb5b34, + 0x29438b76, + 0xc623cbdc, + 0xfcedb668, + 0xf1e4b863, + 0xdc31d7ca, + 0x85634210, + 0x22971340, + 0x11c68420, + 0x244a857d, + 0x3dbbd2f8, + 0x32f9ae11, + 0xa129c76d, + 0x2f9e1d4b, + 0x30b2dcf3, + 0x52860dec, + 0xe3c177d0, + 0x16b32b6c, + 0xb970a999, + 0x489411fa, + 0x64e94722, + 0x8cfca8c4, + 0x3ff0a01a, + 0x2c7d56d8, + 0x903322ef, + 0x4e4987c7, + 0xd138d9c1, + 0xa2ca8cfe, + 0x0bd49836, + 0x81f5a6cf, + 0xde7aa528, + 0x8eb7da26, + 0xbfad3fa4, + 0x9d3a2ce4, + 0x9278500d, + 0xcc5f6a9b, + 0x467e5462, + 0x138df6c2, + 0xb8d890e8, + 0xf7392e5e, + 0xafc382f5, + 0x805d9fbe, + 0x93d0697c, + 0x2dd56fa9, + 0x1225cfb3, + 0x99acc83b, + 0x7d1810a7, + 0x639ce86e, + 0xbb3bdb7b, + 0x7826cd09, + 0x18596ef4, + 0xb79aec01, + 0x9a4f83a8, + 0x6e95e665, + 0xe6ffaa7e, + 0xcfbc2108, + 0xe815efe6, + 0x9be7bad9, + 0x366f4ace, + 0x099fead4, + 0x7cb029d6, + 0xb2a431af, + 0x233f2a31, + 0x94a5c630, + 0x66a235c0, + 0xbc4e7437, + 0xca82fca6, + 0xd090e0b0, + 0xd8a73315, + 0x9804f14a, + 0xdaec41f7, + 0x50cd7f0e, + 0xf691172f, + 0xd64d768d, + 0xb0ef434d, + 0x4daacc54, + 0x0496e4df, + 0xb5d19ee3, + 0x886a4c1b, + 0x1f2cc1b8, + 0x5165467f, + 0xea5e9d04, + 0x358c015d, + 0x7487fa73, + 0x410bfb2e, + 0x1d67b35a, + 0xd2db9252, + 0x5610e933, + 0x47d66d13, + 0x61d79a8c, + 0x0ca1377a, + 0x14f8598e, + 0x3c13eb89, + 0x27a9ceee, + 0xc961b735, + 0xe51ce1ed, + 0xb1477a3c, + 0xdfd29c59, + 0x73f2553f, + 0xce141879, + 0x37c773bf, + 0xcdf753ea, + 0xaafd5f5b, + 0x6f3ddf14, + 0xdb447886, + 0xf3afca81, + 0xc468b93e, + 0x3424382c, + 0x40a3c25f, + 0xc31d1672, + 0x25e2bc0c, + 0x493c288b, + 0x950dff41, + 0x01a83971, + 0xb30c08de, + 0xe4b4d89c, + 0xc1566490, + 0x84cb7b61, + 0xb632d570, + 0x5c6c4874, + 0x57b8d042, + ]; + rinv2 = [ + 0xf45150a7, + 0x417e5365, + 0x171ac3a4, + 0x273a965e, + 0xab3bcb6b, + 0x9d1ff145, + 0xfaacab58, + 0xe34b9303, + 0x302055fa, + 0x76adf66d, + 0xcc889176, + 0x02f5254c, + 0xe54ffcd7, + 0x2ac5d7cb, + 0x35268044, + 0x62b58fa3, + 0xb1de495a, + 0xba25671b, + 0xea45980e, + 0xfe5de1c0, + 0x2fc30275, + 0x4c8112f0, + 0x468da397, + 0xd36bc6f9, + 0x8f03e75f, + 0x9215959c, + 0x6dbfeb7a, + 0x5295da59, + 0xbed42d83, + 0x7458d321, + 0xe0492969, + 0xc98e44c8, + 0xc2756a89, + 0x8ef47879, + 0x58996b3e, + 0xb927dd71, + 0xe1beb64f, + 0x88f017ad, + 0x20c966ac, + 0xce7db43a, + 0xdf63184a, + 0x1ae58231, + 0x51976033, + 0x5362457f, + 0x64b1e077, + 0x6bbb84ae, + 0x81fe1ca0, + 0x08f9942b, + 0x48705868, + 0x458f19fd, + 0xde94876c, + 0x7b52b7f8, + 0x73ab23d3, + 0x4b72e202, + 0x1fe3578f, + 0x55662aab, + 0xebb20728, + 0xb52f03c2, + 0xc5869a7b, + 0x37d3a508, + 0x2830f287, + 0xbf23b2a5, + 0x0302ba6a, + 0x16ed5c82, + 0xcf8a2b1c, + 0x79a792b4, + 0x07f3f0f2, + 0x694ea1e2, + 0xda65cdf4, + 0x0506d5be, + 0x34d11f62, + 0xa6c48afe, + 0x2e349d53, + 0xf3a2a055, + 0x8a0532e1, + 0xf6a475eb, + 0x830b39ec, + 0x6040aaef, + 0x715e069f, + 0x6ebd5110, + 0x213ef98a, + 0xdd963d06, + 0x3eddae05, + 0xe64d46bd, + 0x5491b58d, + 0xc471055d, + 0x06046fd4, + 0x5060ff15, + 0x981924fb, + 0xbdd697e9, + 0x4089cc43, + 0xd967779e, + 0xe8b0bd42, + 0x8907888b, + 0x19e7385b, + 0xc879dbee, + 0x7ca1470a, + 0x427ce90f, + 0x84f8c91e, + 0x00000000, + 0x80098386, + 0x2b3248ed, + 0x111eac70, + 0x5a6c4e72, + 0x0efdfbff, + 0x850f5638, + 0xae3d1ed5, + 0x2d362739, + 0x0f0a64d9, + 0x5c6821a6, + 0x5b9bd154, + 0x36243a2e, + 0x0a0cb167, + 0x57930fe7, + 0xeeb4d296, + 0x9b1b9e91, + 0xc0804fc5, + 0xdc61a220, + 0x775a694b, + 0x121c161a, + 0x93e20aba, + 0xa0c0e52a, + 0x223c43e0, + 0x1b121d17, + 0x090e0b0d, + 0x8bf2adc7, + 0xb62db9a8, + 0x1e14c8a9, + 0xf1578519, + 0x75af4c07, + 0x99eebbdd, + 0x7fa3fd60, + 0x01f79f26, + 0x725cbcf5, + 0x6644c53b, + 0xfb5b347e, + 0x438b7629, + 0x23cbdcc6, + 0xedb668fc, + 0xe4b863f1, + 0x31d7cadc, + 0x63421085, + 0x97134022, + 0xc6842011, + 0x4a857d24, + 0xbbd2f83d, + 0xf9ae1132, + 0x29c76da1, + 0x9e1d4b2f, + 0xb2dcf330, + 0x860dec52, + 0xc177d0e3, + 0xb32b6c16, + 0x70a999b9, + 0x9411fa48, + 0xe9472264, + 0xfca8c48c, + 0xf0a01a3f, + 0x7d56d82c, + 0x3322ef90, + 0x4987c74e, + 0x38d9c1d1, + 0xca8cfea2, + 0xd498360b, + 0xf5a6cf81, + 0x7aa528de, + 0xb7da268e, + 0xad3fa4bf, + 0x3a2ce49d, + 0x78500d92, + 0x5f6a9bcc, + 0x7e546246, + 0x8df6c213, + 0xd890e8b8, + 0x392e5ef7, + 0xc382f5af, + 0x5d9fbe80, + 0xd0697c93, + 0xd56fa92d, + 0x25cfb312, + 0xacc83b99, + 0x1810a77d, + 0x9ce86e63, + 0x3bdb7bbb, + 0x26cd0978, + 0x596ef418, + 0x9aec01b7, + 0x4f83a89a, + 0x95e6656e, + 0xffaa7ee6, + 0xbc2108cf, + 0x15efe6e8, + 0xe7bad99b, + 0x6f4ace36, + 0x9fead409, + 0xb029d67c, + 0xa431afb2, + 0x3f2a3123, + 0xa5c63094, + 0xa235c066, + 0x4e7437bc, + 0x82fca6ca, + 0x90e0b0d0, + 0xa73315d8, + 0x04f14a98, + 0xec41f7da, + 0xcd7f0e50, + 0x91172ff6, + 0x4d768dd6, + 0xef434db0, + 0xaacc544d, + 0x96e4df04, + 0xd19ee3b5, + 0x6a4c1b88, + 0x2cc1b81f, + 0x65467f51, + 0x5e9d04ea, + 0x8c015d35, + 0x87fa7374, + 0x0bfb2e41, + 0x67b35a1d, + 0xdb9252d2, + 0x10e93356, + 0xd66d1347, + 0xd79a8c61, + 0xa1377a0c, + 0xf8598e14, + 0x13eb893c, + 0xa9ceee27, + 0x61b735c9, + 0x1ce1ede5, + 0x477a3cb1, + 0xd29c59df, + 0xf2553f73, + 0x141879ce, + 0xc773bf37, + 0xf753eacd, + 0xfd5f5baa, + 0x3ddf146f, + 0x447886db, + 0xafca81f3, + 0x68b93ec4, + 0x24382c34, + 0xa3c25f40, + 0x1d1672c3, + 0xe2bc0c25, + 0x3c288b49, + 0x0dff4195, + 0xa8397101, + 0x0c08deb3, + 0xb4d89ce4, + 0x566490c1, + 0xcb7b6184, + 0x32d570b6, + 0x6c48745c, + 0xb8d04257, + ]; + rinv3 = [ + 0x5150a7f4, + 0x7e536541, + 0x1ac3a417, + 0x3a965e27, + 0x3bcb6bab, + 0x1ff1459d, + 0xacab58fa, + 0x4b9303e3, + 0x2055fa30, + 0xadf66d76, + 0x889176cc, + 0xf5254c02, + 0x4ffcd7e5, + 0xc5d7cb2a, + 0x26804435, + 0xb58fa362, + 0xde495ab1, + 0x25671bba, + 0x45980eea, + 0x5de1c0fe, + 0xc302752f, + 0x8112f04c, + 0x8da39746, + 0x6bc6f9d3, + 0x03e75f8f, + 0x15959c92, + 0xbfeb7a6d, + 0x95da5952, + 0xd42d83be, + 0x58d32174, + 0x492969e0, + 0x8e44c8c9, + 0x756a89c2, + 0xf478798e, + 0x996b3e58, + 0x27dd71b9, + 0xbeb64fe1, + 0xf017ad88, + 0xc966ac20, + 0x7db43ace, + 0x63184adf, + 0xe582311a, + 0x97603351, + 0x62457f53, + 0xb1e07764, + 0xbb84ae6b, + 0xfe1ca081, + 0xf9942b08, + 0x70586848, + 0x8f19fd45, + 0x94876cde, + 0x52b7f87b, + 0xab23d373, + 0x72e2024b, + 0xe3578f1f, + 0x662aab55, + 0xb20728eb, + 0x2f03c2b5, + 0x869a7bc5, + 0xd3a50837, + 0x30f28728, + 0x23b2a5bf, + 0x02ba6a03, + 0xed5c8216, + 0x8a2b1ccf, + 0xa792b479, + 0xf3f0f207, + 0x4ea1e269, + 0x65cdf4da, + 0x06d5be05, + 0xd11f6234, + 0xc48afea6, + 0x349d532e, + 0xa2a055f3, + 0x0532e18a, + 0xa475ebf6, + 0x0b39ec83, + 0x40aaef60, + 0x5e069f71, + 0xbd51106e, + 0x3ef98a21, + 0x963d06dd, + 0xddae053e, + 0x4d46bde6, + 0x91b58d54, + 0x71055dc4, + 0x046fd406, + 0x60ff1550, + 0x1924fb98, + 0xd697e9bd, + 0x89cc4340, + 0x67779ed9, + 0xb0bd42e8, + 0x07888b89, + 0xe7385b19, + 0x79dbeec8, + 0xa1470a7c, + 0x7ce90f42, + 0xf8c91e84, + 0x00000000, + 0x09838680, + 0x3248ed2b, + 0x1eac7011, + 0x6c4e725a, + 0xfdfbff0e, + 0x0f563885, + 0x3d1ed5ae, + 0x3627392d, + 0x0a64d90f, + 0x6821a65c, + 0x9bd1545b, + 0x243a2e36, + 0x0cb1670a, + 0x930fe757, + 0xb4d296ee, + 0x1b9e919b, + 0x804fc5c0, + 0x61a220dc, + 0x5a694b77, + 0x1c161a12, + 0xe20aba93, + 0xc0e52aa0, + 0x3c43e022, + 0x121d171b, + 0x0e0b0d09, + 0xf2adc78b, + 0x2db9a8b6, + 0x14c8a91e, + 0x578519f1, + 0xaf4c0775, + 0xeebbdd99, + 0xa3fd607f, + 0xf79f2601, + 0x5cbcf572, + 0x44c53b66, + 0x5b347efb, + 0x8b762943, + 0xcbdcc623, + 0xb668fced, + 0xb863f1e4, + 0xd7cadc31, + 0x42108563, + 0x13402297, + 0x842011c6, + 0x857d244a, + 0xd2f83dbb, + 0xae1132f9, + 0xc76da129, + 0x1d4b2f9e, + 0xdcf330b2, + 0x0dec5286, + 0x77d0e3c1, + 0x2b6c16b3, + 0xa999b970, + 0x11fa4894, + 0x472264e9, + 0xa8c48cfc, + 0xa01a3ff0, + 0x56d82c7d, + 0x22ef9033, + 0x87c74e49, + 0xd9c1d138, + 0x8cfea2ca, + 0x98360bd4, + 0xa6cf81f5, + 0xa528de7a, + 0xda268eb7, + 0x3fa4bfad, + 0x2ce49d3a, + 0x500d9278, + 0x6a9bcc5f, + 0x5462467e, + 0xf6c2138d, + 0x90e8b8d8, + 0x2e5ef739, + 0x82f5afc3, + 0x9fbe805d, + 0x697c93d0, + 0x6fa92dd5, + 0xcfb31225, + 0xc83b99ac, + 0x10a77d18, + 0xe86e639c, + 0xdb7bbb3b, + 0xcd097826, + 0x6ef41859, + 0xec01b79a, + 0x83a89a4f, + 0xe6656e95, + 0xaa7ee6ff, + 0x2108cfbc, + 0xefe6e815, + 0xbad99be7, + 0x4ace366f, + 0xead4099f, + 0x29d67cb0, + 0x31afb2a4, + 0x2a31233f, + 0xc63094a5, + 0x35c066a2, + 0x7437bc4e, + 0xfca6ca82, + 0xe0b0d090, + 0x3315d8a7, + 0xf14a9804, + 0x41f7daec, + 0x7f0e50cd, + 0x172ff691, + 0x768dd64d, + 0x434db0ef, + 0xcc544daa, + 0xe4df0496, + 0x9ee3b5d1, + 0x4c1b886a, + 0xc1b81f2c, + 0x467f5165, + 0x9d04ea5e, + 0x015d358c, + 0xfa737487, + 0xfb2e410b, + 0xb35a1d67, + 0x9252d2db, + 0xe9335610, + 0x6d1347d6, + 0x9a8c61d7, + 0x377a0ca1, + 0x598e14f8, + 0xeb893c13, + 0xceee27a9, + 0xb735c961, + 0xe1ede51c, + 0x7a3cb147, + 0x9c59dfd2, + 0x553f73f2, + 0x1879ce14, + 0x73bf37c7, + 0x53eacdf7, + 0x5f5baafd, + 0xdf146f3d, + 0x7886db44, + 0xca81f3af, + 0xb93ec468, + 0x382c3424, + 0xc25f40a3, + 0x1672c31d, + 0xbc0c25e2, + 0x288b493c, + 0xff41950d, + 0x397101a8, + 0x08deb30c, + 0xd89ce4b4, + 0x6490c156, + 0x7b6184cb, + 0xd570b632, + 0x48745c6c, + 0xd04257b8, + ]; + } +} + +const _mask_32 = 0xFFFFFFFF; +const _mask_5 = 0x1F; +const _mask_bits = [ + 0xFFFFFFFF, + 0x7FFFFFFF, + 0x3FFFFFFF, + 0x1FFFFFFF, + 0x0FFFFFFF, + 0x07FFFFFF, + 0x03FFFFFF, + 0x01FFFFFF, + 0x00FFFFFF, + 0x007FFFFF, + 0x003FFFFF, + 0x001FFFFF, + 0x000FFFFF, + 0x0007FFFF, + 0x0003FFFF, + 0x0001FFFF, + 0x0000FFFF, + 0x00007FFF, + 0x00003FFF, + 0x00001FFF, + 0x00000FFF, + 0x000007FF, + 0x000003FF, + 0x000001FF, + 0x000000FF, + 0x0000007F, + 0x0000003F, + 0x0000001F, + 0x0000000F, + 0x00000007, + 0x00000003, + 0x00000001, + 0x00000000, +]; diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/buffered_block_padding_base.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/buffered_block_padding_base.dart index e83b1dff8..4ba4636fb 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/buffered_block_padding_base.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/buffered_block_padding_base.dart @@ -1,682 +1,682 @@ -import 'dart:typed_data'; - -import '../asn1/asn1.dart'; -import 'ipadding.dart'; - -abstract class BufferedBlockPaddingBase extends IBufferedCipher { - /// internal constructor - BufferedBlockPaddingBase(); - //Fields - /// internal field - static List emptyBuffer = []; - - //Implementation - @override - String? get algorithmName => null; - @override - void initialize(bool forEncryption, ICipherParameter? parameters); - @override - int? get blockSize => null; - @override - int? getOutputSize(int inputLen) => null; - @override - int? getUpdateOutputSize(int inputLen) => null; - @override - void reset() {} - @override - List? processByte(int intput) => null; - @override - Map? copyBytes(int input, List output, int outOff) { - final List? outBytes = processByte(input); - if (outBytes == null) { - return {'length': 0, 'output': output}; - } - if (outOff + outBytes.length > output.length) { - throw ArgumentError.value(output, 'output', 'output buffer too short'); - } - int j = 0; - for (int i = outOff; i < output.length && j < outBytes.length; i++) { - output[i] = outBytes[j]; - j++; - } - return {'length': outBytes.length, 'output': output}; - } - - @override - List? readBytesFromInput(List input) { - return readBytes(input, 0, input.length); - } - - @override - List? readBytes(List input, int inOff, int length); - @override - Map processByteFromValues( - List input, - List output, - int outOff, - ) { - return processBytes(input, 0, input.length, output, outOff); - } - - @override - Map processBytes( - List input, - int inOff, - int length, - List? output, - int outOff, - ) { - final List? outBytes = readBytes(input, inOff, length); - if (outBytes == null) { - return {'length': 0, 'output': output}; - } - if (outOff + outBytes.length > output!.length) { - throw ArgumentError.value(output, 'output', 'output buffer too short'); - } - int j = 0; - for (int i = outOff; i < output.length && j < outBytes.length; i++) { - output[i] = outBytes[j]; - j++; - } - return {'length': outBytes.length, 'output': output}; - } - - @override - List? doFinal(); - @override - List? readFinal(List? input, int inOff, int length); - @override - List? doFinalFromInput(List? input) { - return readFinal(input, 0, input!.length); - } - - @override - Map writeFinal(List output, int outOff) { - final List outBytes = doFinal()!; - if (outOff + outBytes.length > output.length) { - throw ArgumentError.value(output, 'output', 'output buffer too short'); - } - int j = 0; - for (int i = outOff; i < output.length && j < outBytes.length; i++) { - output[i] = outBytes[j]; - j++; - } - return {'length': outBytes.length, 'output': output}; - } - - @override - Map copyFinal( - List input, - List output, - int outOff, - ) { - return readFinalValues(input, 0, input.length, output, outOff); - } - - @override - Map readFinalValues( - List input, - int inOff, - int length, - List? output, - int outOff, - ) { - Map result = processBytes( - input, - inOff, - length, - output, - outOff, - ); - int len = result['length'] as int; - output = result['output'] as List?; - result = writeFinal(output!, outOff + len); - len += result['length']! as int; - output = result['output'] as List?; - return {'length': len, 'output': output}; - } -} - -/// internal class -class BufferedCipher extends BufferedBlockPaddingBase { - /// internal constructor - BufferedCipher(ICipher cipher) : super() { - _cipher = cipher; - _bytes = List.generate(cipher.blockSize!, (int i) => 0); - _offset = 0; - } - //Fields - List? _bytes; - int? _offset; - late bool _isEncryption; - late ICipher _cipher; - - //Implementation - @override - String? get algorithmName => _cipher.algorithmName; - @override - int? get blockSize => _cipher.blockSize; - - /// internal method - @override - void initialize(bool isEncryption, ICipherParameter? parameters) { - _isEncryption = isEncryption; - reset(); - _cipher.initialize(isEncryption, parameters); - } - - /// internal method - @override - int getUpdateOutputSize(int length) { - final int total = length + _offset!; - final int leftOver = total % _bytes!.length; - return total - leftOver; - } - - /// internal method - @override - int getOutputSize(int length) { - return length + _offset!; - } - - @override - void reset() { - _bytes = List.generate(_bytes!.length, (int i) => 0); - _offset = 0; - _cipher.reset(); - } - - /// internal method - @override - List? processByte(int input) { - final int length = getUpdateOutputSize(1); - List? bytes = - length > 0 ? List.generate(length, (int i) => 0) : null; - final Map result = copyBytes(input, bytes, 0)!; - final int? position = result['length'] as int?; - bytes = result['output'] as List?; - if (length > 0 && position! < length) { - final List tempBytes = List.generate(position, (int i) => 0); - List.copyRange(tempBytes, 0, bytes!, 0, position); - bytes = tempBytes; - } - return bytes; - } - - @override - Map? copyBytes(int input, List? output, int outOff) { - _bytes![_offset!] = input; - _offset = _offset! + 1; - if (_offset == _bytes!.length) { - if ((outOff + _bytes!.length) > output!.length) { - throw ArgumentError.value(output, 'output', 'output buffer too short'); - } - _offset = 0; - return _cipher.processBlock(_bytes, 0, output, outOff); - } - return {'length': 0, 'output': output}; - } - - @override - List? readBytes(List input, int inOff, int length) { - if (length < 1) { - return null; - } - final int outLength = getUpdateOutputSize(length); - List? outBytes = - outLength > 0 ? List.generate(outLength, (int i) => 0) : null; - final Map result = processBytes( - input, - inOff, - length, - outBytes, - 0, - ); - final int? position = result['length'] as int?; - outBytes = result['output'] as List?; - if (outLength > 0 && position! < outLength) { - final List tempBytes = List.generate(position, (int i) => 0); - List.copyRange(tempBytes, 0, outBytes!, 0, position); - outBytes = tempBytes; - } - return outBytes; - } - - /// internal method - @override - Map processBytes( - List? input, - int inOffset, - int length, - List? output, - int outOffset, - ) { - Map? result; - if (length < 1) { - return {'length': 0, 'output': output}; - } - final int? blockSize = this.blockSize; - getUpdateOutputSize(length); - int resultLength = 0; - final int gapLength = _bytes!.length - _offset!; - if (length > gapLength) { - List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + gapLength); - result = _cipher.processBlock(_bytes, 0, output, outOffset); - resultLength = resultLength + result!['length']! as int; - output = result['output'] as List?; - _offset = 0; - length -= gapLength; - inOffset += gapLength; - while (length > _bytes!.length) { - result = _cipher.processBlock( - input, - inOffset, - output, - outOffset + resultLength, - ); - resultLength = resultLength + result!['length']! as int; - output = result['output'] as List?; - length -= blockSize!; - inOffset += blockSize; - } - } - List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + length); - _offset = _offset! + length; - if (_offset == _bytes!.length) { - result = _cipher.processBlock( - _bytes, - 0, - output, - outOffset + resultLength, - ); - resultLength = resultLength + result!['length']! as int; - output = result['output'] as List?; - _offset = 0; - } - return {'output': output, 'length': resultLength}; - } - - @override - List? doFinal() { - List? bytes = BufferedBlockPaddingBase.emptyBuffer; - final int length = getOutputSize(0); - if (length > 0) { - bytes = List.generate(length, (int i) => 0); - final Map result = writeFinal(bytes, 0); - final int position = result['length'] as int; - bytes = result['output'] as List?; - if (position < bytes!.length) { - final List tempBytes = List.generate(position, (int i) => 0); - List.copyRange(tempBytes, 0, bytes, 0, position); - bytes = tempBytes; - } - } else { - reset(); - } - return bytes; - } - - /// internal method - @override - List? readFinal(List? input, int inOffset, int inLength) { - List? outBytes = BufferedBlockPaddingBase.emptyBuffer; - if (input != null) { - final int length = getOutputSize(inLength); - Map result; - if (length > 0) { - outBytes = List.generate(length, (int i) => 0); - int? position; - if (inLength > 0) { - result = processBytes(input, inOffset, inLength, outBytes, 0); - position = result['length'] as int?; - outBytes = result['output'] as List?; - } else { - position = 0; - } - result = writeFinal(outBytes, position); - position = position! + result['length']! as int; - outBytes = result['output'] as List?; - if (position < outBytes!.length) { - final List tempBytes = List.generate( - position, - (int i) => 0, - ); - List.copyRange(tempBytes, 0, outBytes, 0, position); - outBytes = tempBytes; - } - } else { - reset(); - } - } - return outBytes; - } - - @override - Map writeFinal(List? output, int? outOff) { - try { - if (_offset != 0) { - final Map result = - _cipher.processBlock(_bytes, 0, _bytes, 0)!; - _bytes = result['output'] as List?; - List.copyRange(_bytes!, 0, output!, outOff, _offset); - } - return {'length': _offset, 'output': output}; - } finally { - reset(); - } - } -} - -class BufferedBlockPadding extends BufferedCipher { - /// internal constructor - BufferedBlockPadding(ICipher cipher, [IPadding? padding]) : super(cipher) { - _cipher = cipher; - _padding = padding ?? Pkcs7Padding(); - _bytes = List.generate(cipher.blockSize!, (int i) => 0); - _offset = 0; - } - //Fields - late IPadding _padding; - //Implemntation - @override - void initialize(bool isEncryption, ICipherParameter? parameters) { - _isEncryption = isEncryption; - reset(); - _cipher.initialize(isEncryption, parameters); - _padding.initialize(parameters); - } - - @override - int getOutputSize(int length) { - final int total = length + _offset!; - final int leftOver = total % _bytes!.length; - if (leftOver == 0) { - if (_isEncryption) { - return total + _bytes!.length; - } - return total; - } - return total - leftOver + _bytes!.length; - } - - @override - int getUpdateOutputSize(int length) { - final int total = length + _offset!; - final int leftOver = total % _bytes!.length; - if (leftOver == 0) { - return total - _bytes!.length; - } - return total - leftOver; - } - - @override - Map copyBytes(int input, List? output, int outOff) { - int? resultLen = 0; - if (_offset == _bytes!.length) { - final Map result = - _cipher.processBlock(_bytes, 0, output, outOff)!; - resultLen = result['length'] as int?; - output = result['output'] as List?; - _offset = 0; - } - _bytes![_offset!] = input; - _offset = _offset! + 1; - return {'length': resultLen, 'output': output}; - } - - @override - Map processBytes( - List? input, - int inOffset, - int length, - List? output, - int outOffset, - ) { - if (length < 0) { - throw ArgumentError.value(length, 'length', 'Invalid length'); - } - final int? blockSize = this.blockSize; - final int outLength = getUpdateOutputSize(length); - if (outLength > 0) { - if ((outOffset + outLength) > output!.length) { - throw ArgumentError.value(length, 'length', 'Invalid buffer length'); - } - } - int resultLength = 0; - final int gapLength = _bytes!.length - _offset!; - Map? result; - if (length > gapLength) { - List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + gapLength); - result = _cipher.processBlock(_bytes, 0, output, outOffset); - resultLength += result!['length']! as int; - output = result['output'] as List?; - _offset = 0; - length -= gapLength; - inOffset += gapLength; - while (length > _bytes!.length) { - result = _cipher.processBlock( - input, - inOffset, - output, - outOffset + resultLength, - ); - resultLength += result!['length']! as int; - output = result['output'] as List?; - length -= blockSize!; - inOffset += blockSize; - } - } - List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + length); - _offset = _offset! + length; - return {'length': resultLength, 'output': output}; - } - - @override - Map writeFinal(List? output, int? outOff) { - final int? blockSize = _cipher.blockSize; - int resultLen = 0; - Map? result; - if (_isEncryption) { - if (_offset == blockSize) { - if ((outOff! + 2 * blockSize!) > output!.length) { - reset(); - throw ArgumentError.value( - output, - 'output', - 'output buffer too short', - ); - } - result = _cipher.processBlock(_bytes, 0, output, outOff); - resultLen = result!['length'] as int; - output = result['output'] as List?; - _offset = 0; - } - _padding.addPadding(Uint8List.fromList(_bytes!), _offset!); - result = _cipher.processBlock(_bytes, 0, output, outOff! + resultLen); - resultLen += result!['length'] as int; - output = result['output'] as List?; - reset(); - } else { - if (_offset == blockSize) { - result = _cipher.processBlock(_bytes, 0, _bytes, 0); - resultLen = result!['length'] as int; - _bytes = result['output'] as List?; - _offset = 0; - } else { - reset(); - throw ArgumentError.value(output, 'output', 'incomplete in decryption'); - } - try { - resultLen -= _padding.count(Uint8List.fromList(_bytes!)); - List.copyRange(output!, outOff!, _bytes!, 0, resultLen); - } finally { - reset(); - } - } - return {'length': resultLen, 'output': output}; - } -} - -class PaddedCipherMode extends IBufferedCipher { - /// internal constructor - PaddedCipherMode(this.padding, this.cipher); - @override - final IPadding padding; - @override - final ICipher cipher; - - @override - String get algorithmName => '${cipher.algorithmName}/${padding.paddingName}'; - - @override - int get blockSize => cipher.blockSize!; - - bool? _isEncryption; - - @override - void reset() { - _isEncryption = null; - cipher.reset(); - } - - //Implemntation - @override - void initialize( - bool forEncryption, - covariant BlockCipherPaddedParameters parameters, - ) { - _isEncryption = forEncryption; - cipher.initialize(forEncryption, parameters.underlyingKeyParameters); - padding.initialize(parameters.paddingCipherParameters); - } - - @override - Uint8List process(Uint8List data) { - final inputBlocks = (data.length + blockSize - 1) ~/ blockSize; - int outputBlocks; - if (_isEncryption ?? false) { - outputBlocks = (data.length + blockSize) ~/ blockSize; - } else { - if ((data.length % blockSize) != 0) { - throw ArgumentError( - 'Input data length is not a multiple of the size of cipher block', - ); - } - outputBlocks = inputBlocks; - } - final out = Uint8List(outputBlocks * blockSize); - for (var i = 0; i < (inputBlocks - 1); i++) { - final offset = i * blockSize; - processingBlock(data, offset, out, offset); - } - final lastBlockOffset = (inputBlocks - 1) * blockSize; - final lastBlockSize = doFinalProcess( - data, - lastBlockOffset, - out, - lastBlockOffset, - ); - return out.sublist(0, lastBlockOffset + lastBlockSize); - } - - @override - int? processingBlock( - Uint8List inputBytes, - int inputOffset, - Uint8List outputBytes, - int outputOffset, - ) { - return cipher.processingBlock( - inputBytes, - inputOffset, - outputBytes, - outputOffset, - ); - } - - @override - int doFinalProcess( - Uint8List inputBytes, - int inputOffset, - Uint8List outputBytes, - int outputOffset, - ) { - if (_isEncryption ?? false) { - final lastBlock = Uint8List(blockSize) - ..setAll(0, inputBytes.sublist(inputOffset)); - final remainderBlock = inputBytes.length - inputOffset; - - if (remainderBlock < blockSize) { - padding.addPadding(lastBlock, inputBytes.length - inputOffset); - processingBlock(lastBlock, 0, outputBytes, outputOffset); - return blockSize; - } else { - processingBlock(inputBytes, inputOffset, outputBytes, outputOffset); - padding.addPadding(lastBlock, 0); - processingBlock(lastBlock, 0, outputBytes, outputOffset + blockSize); - return 2 * blockSize; - } - } else { - processingBlock(inputBytes, inputOffset, outputBytes, outputOffset); - final padCount = padding.count(outputBytes.sublist(outputOffset)); - final padOffsetInBlock = blockSize - padCount; - outputBytes.fillRange( - outputOffset + padOffsetInBlock, - outputBytes.length, - 0, - ); - return padOffsetInBlock; - } - } -} - -/// internal class -class Pkcs7Padding implements IPadding { - /// internal constructor - Pkcs7Padding(); - //Properties - @override - String get paddingName => Asn1.pkcs7; - //Implementation - @override - void initialize([ICipherParameter? params]) {} - @override - int addPadding(Uint8List bytes, int offset) { - final int code = bytes.length - offset; - while (offset < bytes.length) { - bytes[offset] = code; - offset++; - } - return code; - } - - @override - int count(Uint8List input) { - final int count = _clipByte(input[input.length - 1]); - if (count < 1 || count > input.length) { - throw ArgumentError.value(input, 'input', 'Invalid pad'); - } - for (int i = 1; i <= count; i++) { - if (input[input.length - i] != count) { - throw ArgumentError.value(input, 'input', 'Invalid pad'); - } - } - return count; - } -} - -int _clipByte(int x) => x & _mask_8; -const _mask_8 = 0xFF; - -class BlockCipherPaddedParameters< - KeyCipherParameters extends ICipherParameter?, - PaddingCipherParameters extends ICipherParameter? -> - implements ICipherParameter { - BlockCipherPaddedParameters( - this.underlyingKeyParameters, - this.paddingCipherParameters, - ); - final KeyCipherParameters? underlyingKeyParameters; - final PaddingCipherParameters? paddingCipherParameters; -} +import 'dart:typed_data'; + +import '../asn1/asn1.dart'; +import 'ipadding.dart'; + +abstract class BufferedBlockPaddingBase extends IBufferedCipher { + /// internal constructor + BufferedBlockPaddingBase(); + //Fields + /// internal field + static List emptyBuffer = []; + + //Implementation + @override + String? get algorithmName => null; + @override + void initialize(bool forEncryption, ICipherParameter? parameters); + @override + int? get blockSize => null; + @override + int? getOutputSize(int inputLen) => null; + @override + int? getUpdateOutputSize(int inputLen) => null; + @override + void reset() {} + @override + List? processByte(int intput) => null; + @override + Map? copyBytes(int input, List output, int outOff) { + final List? outBytes = processByte(input); + if (outBytes == null) { + return {'length': 0, 'output': output}; + } + if (outOff + outBytes.length > output.length) { + throw ArgumentError.value(output, 'output', 'output buffer too short'); + } + int j = 0; + for (int i = outOff; i < output.length && j < outBytes.length; i++) { + output[i] = outBytes[j]; + j++; + } + return {'length': outBytes.length, 'output': output}; + } + + @override + List? readBytesFromInput(List input) { + return readBytes(input, 0, input.length); + } + + @override + List? readBytes(List input, int inOff, int length); + @override + Map processByteFromValues( + List input, + List output, + int outOff, + ) { + return processBytes(input, 0, input.length, output, outOff); + } + + @override + Map processBytes( + List input, + int inOff, + int length, + List? output, + int outOff, + ) { + final List? outBytes = readBytes(input, inOff, length); + if (outBytes == null) { + return {'length': 0, 'output': output}; + } + if (outOff + outBytes.length > output!.length) { + throw ArgumentError.value(output, 'output', 'output buffer too short'); + } + int j = 0; + for (int i = outOff; i < output.length && j < outBytes.length; i++) { + output[i] = outBytes[j]; + j++; + } + return {'length': outBytes.length, 'output': output}; + } + + @override + List? doFinal(); + @override + List? readFinal(List? input, int inOff, int length); + @override + List? doFinalFromInput(List? input) { + return readFinal(input, 0, input!.length); + } + + @override + Map writeFinal(List output, int outOff) { + final List outBytes = doFinal()!; + if (outOff + outBytes.length > output.length) { + throw ArgumentError.value(output, 'output', 'output buffer too short'); + } + int j = 0; + for (int i = outOff; i < output.length && j < outBytes.length; i++) { + output[i] = outBytes[j]; + j++; + } + return {'length': outBytes.length, 'output': output}; + } + + @override + Map copyFinal( + List input, + List output, + int outOff, + ) { + return readFinalValues(input, 0, input.length, output, outOff); + } + + @override + Map readFinalValues( + List input, + int inOff, + int length, + List? output, + int outOff, + ) { + Map result = processBytes( + input, + inOff, + length, + output, + outOff, + ); + int len = result['length'] as int; + output = result['output'] as List?; + result = writeFinal(output!, outOff + len); + len += result['length']! as int; + output = result['output'] as List?; + return {'length': len, 'output': output}; + } +} + +/// internal class +class BufferedCipher extends BufferedBlockPaddingBase { + /// internal constructor + BufferedCipher(ICipher cipher) : super() { + _cipher = cipher; + _bytes = List.generate(cipher.blockSize!, (int i) => 0); + _offset = 0; + } + //Fields + List? _bytes; + int? _offset; + late bool _isEncryption; + late ICipher _cipher; + + //Implementation + @override + String? get algorithmName => _cipher.algorithmName; + @override + int? get blockSize => _cipher.blockSize; + + /// internal method + @override + void initialize(bool isEncryption, ICipherParameter? parameters) { + _isEncryption = isEncryption; + reset(); + _cipher.initialize(isEncryption, parameters); + } + + /// internal method + @override + int getUpdateOutputSize(int length) { + final int total = length + _offset!; + final int leftOver = total % _bytes!.length; + return total - leftOver; + } + + /// internal method + @override + int getOutputSize(int length) { + return length + _offset!; + } + + @override + void reset() { + _bytes = List.generate(_bytes!.length, (int i) => 0); + _offset = 0; + _cipher.reset(); + } + + /// internal method + @override + List? processByte(int input) { + final int length = getUpdateOutputSize(1); + List? bytes = + length > 0 ? List.generate(length, (int i) => 0) : null; + final Map result = copyBytes(input, bytes, 0)!; + final int? position = result['length'] as int?; + bytes = result['output'] as List?; + if (length > 0 && position! < length) { + final List tempBytes = List.generate(position, (int i) => 0); + List.copyRange(tempBytes, 0, bytes!, 0, position); + bytes = tempBytes; + } + return bytes; + } + + @override + Map? copyBytes(int input, List? output, int outOff) { + _bytes![_offset!] = input; + _offset = _offset! + 1; + if (_offset == _bytes!.length) { + if ((outOff + _bytes!.length) > output!.length) { + throw ArgumentError.value(output, 'output', 'output buffer too short'); + } + _offset = 0; + return _cipher.processBlock(_bytes, 0, output, outOff); + } + return {'length': 0, 'output': output}; + } + + @override + List? readBytes(List input, int inOff, int length) { + if (length < 1) { + return null; + } + final int outLength = getUpdateOutputSize(length); + List? outBytes = + outLength > 0 ? List.generate(outLength, (int i) => 0) : null; + final Map result = processBytes( + input, + inOff, + length, + outBytes, + 0, + ); + final int? position = result['length'] as int?; + outBytes = result['output'] as List?; + if (outLength > 0 && position! < outLength) { + final List tempBytes = List.generate(position, (int i) => 0); + List.copyRange(tempBytes, 0, outBytes!, 0, position); + outBytes = tempBytes; + } + return outBytes; + } + + /// internal method + @override + Map processBytes( + List? input, + int inOffset, + int length, + List? output, + int outOffset, + ) { + Map? result; + if (length < 1) { + return {'length': 0, 'output': output}; + } + final int? blockSize = this.blockSize; + getUpdateOutputSize(length); + int resultLength = 0; + final int gapLength = _bytes!.length - _offset!; + if (length > gapLength) { + List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + gapLength); + result = _cipher.processBlock(_bytes, 0, output, outOffset); + resultLength = resultLength + result!['length']! as int; + output = result['output'] as List?; + _offset = 0; + length -= gapLength; + inOffset += gapLength; + while (length > _bytes!.length) { + result = _cipher.processBlock( + input, + inOffset, + output, + outOffset + resultLength, + ); + resultLength = resultLength + result!['length']! as int; + output = result['output'] as List?; + length -= blockSize!; + inOffset += blockSize; + } + } + List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + length); + _offset = _offset! + length; + if (_offset == _bytes!.length) { + result = _cipher.processBlock( + _bytes, + 0, + output, + outOffset + resultLength, + ); + resultLength = resultLength + result!['length']! as int; + output = result['output'] as List?; + _offset = 0; + } + return {'output': output, 'length': resultLength}; + } + + @override + List? doFinal() { + List? bytes = BufferedBlockPaddingBase.emptyBuffer; + final int length = getOutputSize(0); + if (length > 0) { + bytes = List.generate(length, (int i) => 0); + final Map result = writeFinal(bytes, 0); + final int position = result['length'] as int; + bytes = result['output'] as List?; + if (position < bytes!.length) { + final List tempBytes = List.generate(position, (int i) => 0); + List.copyRange(tempBytes, 0, bytes, 0, position); + bytes = tempBytes; + } + } else { + reset(); + } + return bytes; + } + + /// internal method + @override + List? readFinal(List? input, int inOffset, int inLength) { + List? outBytes = BufferedBlockPaddingBase.emptyBuffer; + if (input != null) { + final int length = getOutputSize(inLength); + Map result; + if (length > 0) { + outBytes = List.generate(length, (int i) => 0); + int? position; + if (inLength > 0) { + result = processBytes(input, inOffset, inLength, outBytes, 0); + position = result['length'] as int?; + outBytes = result['output'] as List?; + } else { + position = 0; + } + result = writeFinal(outBytes, position); + position = position! + result['length']! as int; + outBytes = result['output'] as List?; + if (position < outBytes!.length) { + final List tempBytes = List.generate( + position, + (int i) => 0, + ); + List.copyRange(tempBytes, 0, outBytes, 0, position); + outBytes = tempBytes; + } + } else { + reset(); + } + } + return outBytes; + } + + @override + Map writeFinal(List? output, int? outOff) { + try { + if (_offset != 0) { + final Map result = + _cipher.processBlock(_bytes, 0, _bytes, 0)!; + _bytes = result['output'] as List?; + List.copyRange(_bytes!, 0, output!, outOff, _offset); + } + return {'length': _offset, 'output': output}; + } finally { + reset(); + } + } +} + +class BufferedBlockPadding extends BufferedCipher { + /// internal constructor + BufferedBlockPadding(ICipher cipher, [IPadding? padding]) : super(cipher) { + _cipher = cipher; + _padding = padding ?? Pkcs7Padding(); + _bytes = List.generate(cipher.blockSize!, (int i) => 0); + _offset = 0; + } + //Fields + late IPadding _padding; + //Implemntation + @override + void initialize(bool isEncryption, ICipherParameter? parameters) { + _isEncryption = isEncryption; + reset(); + _cipher.initialize(isEncryption, parameters); + _padding.initialize(parameters); + } + + @override + int getOutputSize(int length) { + final int total = length + _offset!; + final int leftOver = total % _bytes!.length; + if (leftOver == 0) { + if (_isEncryption) { + return total + _bytes!.length; + } + return total; + } + return total - leftOver + _bytes!.length; + } + + @override + int getUpdateOutputSize(int length) { + final int total = length + _offset!; + final int leftOver = total % _bytes!.length; + if (leftOver == 0) { + return total - _bytes!.length; + } + return total - leftOver; + } + + @override + Map copyBytes(int input, List? output, int outOff) { + int? resultLen = 0; + if (_offset == _bytes!.length) { + final Map result = + _cipher.processBlock(_bytes, 0, output, outOff)!; + resultLen = result['length'] as int?; + output = result['output'] as List?; + _offset = 0; + } + _bytes![_offset!] = input; + _offset = _offset! + 1; + return {'length': resultLen, 'output': output}; + } + + @override + Map processBytes( + List? input, + int inOffset, + int length, + List? output, + int outOffset, + ) { + if (length < 0) { + throw ArgumentError.value(length, 'length', 'Invalid length'); + } + final int? blockSize = this.blockSize; + final int outLength = getUpdateOutputSize(length); + if (outLength > 0) { + if ((outOffset + outLength) > output!.length) { + throw ArgumentError.value(length, 'length', 'Invalid buffer length'); + } + } + int resultLength = 0; + final int gapLength = _bytes!.length - _offset!; + Map? result; + if (length > gapLength) { + List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + gapLength); + result = _cipher.processBlock(_bytes, 0, output, outOffset); + resultLength += result!['length']! as int; + output = result['output'] as List?; + _offset = 0; + length -= gapLength; + inOffset += gapLength; + while (length > _bytes!.length) { + result = _cipher.processBlock( + input, + inOffset, + output, + outOffset + resultLength, + ); + resultLength += result!['length']! as int; + output = result['output'] as List?; + length -= blockSize!; + inOffset += blockSize; + } + } + List.copyRange(_bytes!, _offset!, input!, inOffset, inOffset + length); + _offset = _offset! + length; + return {'length': resultLength, 'output': output}; + } + + @override + Map writeFinal(List? output, int? outOff) { + final int? blockSize = _cipher.blockSize; + int resultLen = 0; + Map? result; + if (_isEncryption) { + if (_offset == blockSize) { + if ((outOff! + 2 * blockSize!) > output!.length) { + reset(); + throw ArgumentError.value( + output, + 'output', + 'output buffer too short', + ); + } + result = _cipher.processBlock(_bytes, 0, output, outOff); + resultLen = result!['length'] as int; + output = result['output'] as List?; + _offset = 0; + } + _padding.addPadding(Uint8List.fromList(_bytes!), _offset!); + result = _cipher.processBlock(_bytes, 0, output, outOff! + resultLen); + resultLen += result!['length'] as int; + output = result['output'] as List?; + reset(); + } else { + if (_offset == blockSize) { + result = _cipher.processBlock(_bytes, 0, _bytes, 0); + resultLen = result!['length'] as int; + _bytes = result['output'] as List?; + _offset = 0; + } else { + reset(); + throw ArgumentError.value(output, 'output', 'incomplete in decryption'); + } + try { + resultLen -= _padding.count(Uint8List.fromList(_bytes!)); + List.copyRange(output!, outOff!, _bytes!, 0, resultLen); + } finally { + reset(); + } + } + return {'length': resultLen, 'output': output}; + } +} + +class PaddedCipherMode extends IBufferedCipher { + /// internal constructor + PaddedCipherMode(this.padding, this.cipher); + @override + final IPadding padding; + @override + final ICipher cipher; + + @override + String get algorithmName => '${cipher.algorithmName}/${padding.paddingName}'; + + @override + int get blockSize => cipher.blockSize!; + + bool? _isEncryption; + + @override + void reset() { + _isEncryption = null; + cipher.reset(); + } + + //Implemntation + @override + void initialize( + bool forEncryption, + covariant BlockCipherPaddedParameters parameters, + ) { + _isEncryption = forEncryption; + cipher.initialize(forEncryption, parameters.underlyingKeyParameters); + padding.initialize(parameters.paddingCipherParameters); + } + + @override + Uint8List process(Uint8List data) { + final inputBlocks = (data.length + blockSize - 1) ~/ blockSize; + int outputBlocks; + if (_isEncryption ?? false) { + outputBlocks = (data.length + blockSize) ~/ blockSize; + } else { + if ((data.length % blockSize) != 0) { + throw ArgumentError( + 'Input data length is not a multiple of the size of cipher block', + ); + } + outputBlocks = inputBlocks; + } + final out = Uint8List(outputBlocks * blockSize); + for (var i = 0; i < (inputBlocks - 1); i++) { + final offset = i * blockSize; + processingBlock(data, offset, out, offset); + } + final lastBlockOffset = (inputBlocks - 1) * blockSize; + final lastBlockSize = doFinalProcess( + data, + lastBlockOffset, + out, + lastBlockOffset, + ); + return out.sublist(0, lastBlockOffset + lastBlockSize); + } + + @override + int? processingBlock( + Uint8List inputBytes, + int inputOffset, + Uint8List outputBytes, + int outputOffset, + ) { + return cipher.processingBlock( + inputBytes, + inputOffset, + outputBytes, + outputOffset, + ); + } + + @override + int doFinalProcess( + Uint8List inputBytes, + int inputOffset, + Uint8List outputBytes, + int outputOffset, + ) { + if (_isEncryption ?? false) { + final lastBlock = Uint8List(blockSize) + ..setAll(0, inputBytes.sublist(inputOffset)); + final remainderBlock = inputBytes.length - inputOffset; + + if (remainderBlock < blockSize) { + padding.addPadding(lastBlock, inputBytes.length - inputOffset); + processingBlock(lastBlock, 0, outputBytes, outputOffset); + return blockSize; + } else { + processingBlock(inputBytes, inputOffset, outputBytes, outputOffset); + padding.addPadding(lastBlock, 0); + processingBlock(lastBlock, 0, outputBytes, outputOffset + blockSize); + return 2 * blockSize; + } + } else { + processingBlock(inputBytes, inputOffset, outputBytes, outputOffset); + final padCount = padding.count(outputBytes.sublist(outputOffset)); + final padOffsetInBlock = blockSize - padCount; + outputBytes.fillRange( + outputOffset + padOffsetInBlock, + outputBytes.length, + 0, + ); + return padOffsetInBlock; + } + } +} + +/// internal class +class Pkcs7Padding implements IPadding { + /// internal constructor + Pkcs7Padding(); + //Properties + @override + String get paddingName => Asn1.pkcs7; + //Implementation + @override + void initialize([ICipherParameter? params]) {} + @override + int addPadding(Uint8List bytes, int offset) { + final int code = bytes.length - offset; + while (offset < bytes.length) { + bytes[offset] = code; + offset++; + } + return code; + } + + @override + int count(Uint8List input) { + final int count = _clipByte(input[input.length - 1]); + if (count < 1 || count > input.length) { + throw ArgumentError.value(input, 'input', 'Invalid pad'); + } + for (int i = 1; i <= count; i++) { + if (input[input.length - i] != count) { + throw ArgumentError.value(input, 'input', 'Invalid pad'); + } + } + return count; + } +} + +int _clipByte(int x) => x & _mask_8; +const _mask_8 = 0xFF; + +class BlockCipherPaddedParameters< + KeyCipherParameters extends ICipherParameter?, + PaddingCipherParameters extends ICipherParameter? +> + implements ICipherParameter { + BlockCipherPaddedParameters( + this.underlyingKeyParameters, + this.paddingCipherParameters, + ); + final KeyCipherParameters? underlyingKeyParameters; + final PaddingCipherParameters? paddingCipherParameters; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_block_chaining_mode.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_block_chaining_mode.dart index c8a01cea4..d021c00e0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_block_chaining_mode.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_block_chaining_mode.dart @@ -1,405 +1,405 @@ -import 'dart:typed_data'; -import 'ipadding.dart'; - -/// internal class -class CipherBlockChainingMode extends IBlockCipher { - //Constructor - /// internal constructor - CipherBlockChainingMode(ICipher? cipher) { - _cipher = cipher; - _size = _cipher!.blockSize; - - _bytes = Uint8List(_size!); - _cbcBytes = Uint8List(_size!); - _cbcNextBytes = Uint8List(_size!); - - _isEncryption = false; - } - - //Fields - ICipher? _cipher; - int? _size; - late Uint8List _bytes; - Uint8List? _cbcBytes; - Uint8List? _cbcNextBytes; - bool? _isEncryption; - - //Fields - @override - int? get blockSize => _cipher!.blockSize; - @override - String get algorithmName => '${_cipher!.algorithmName}/CBC'; - @override - bool get isBlock => false; - - //Implementation - @override - void initialize(bool isEncryption, ICipherParameter? parameters) { - final bool? oldEncryption = _isEncryption; - _isEncryption = isEncryption; - if (parameters != null) { - if (parameters is InvalidParameter) { - final List iv = parameters.keys!; - if (iv.length != blockSize) { - throw ArgumentError.value( - iv, - 'Initialization vector must be the same length as block size', - ); - } - _bytes.setAll(0, iv); - _cipher!.initialize(isEncryption, parameters.parameters); - } else { - _cipher!.initialize(isEncryption, parameters); - } - reset(); - } else if (oldEncryption != _isEncryption) { - throw ArgumentError.value( - oldEncryption, - 'cannot change encrypting state without providing key.', - ); - } - } - - @override - void reset() { - _cbcBytes!.setAll(0, _bytes); - _cbcNextBytes!.fillRange(0, _cbcNextBytes!.length, 0); - _cipher!.reset(); - } - - @override - Map processBlock( - List? inBytes, - int inOffset, - List? outBytes, - int? outOffset, - ) { - return _isEncryption! - ? encryptionBlock(inBytes!, inOffset, outBytes, outOffset!) - : decryptionBlock(inBytes!, inOffset, outBytes, outOffset); - } - - /// internal method - Map encryptionBlock( - List inputBytes, - int inputOffset, - List? outputBytes, - int outputOffset, - ) { - if ((inputOffset + _size!) > inputBytes.length) { - throw ArgumentError.value('Invalid length in input bytes'); - } - for (int i = 0; i < _size!; i++) { - _cbcBytes![i] ^= inputBytes[inputOffset + i]; - } - final Map result = - _cipher!.processBlock(_cbcBytes, 0, outputBytes, outputOffset)!; - outputBytes = result['output'] as List?; - List.copyRange( - _cbcBytes!, - 0, - outputBytes!, - outputOffset, - outputOffset + _cbcBytes!.length, - ); - return result; - } - - /// internal method - Map decryptionBlock( - List inputBytes, - int inputOffset, - List? outputBytes, - int? outputOffset, - ) { - if ((inputOffset + _size!) > inputBytes.length) { - throw ArgumentError.value('Invalid length in input bytes'); - } - List.copyRange( - _cbcNextBytes!, - 0, - inputBytes, - inputOffset, - inputOffset + _size!, - ); - final Map? result = _cipher!.processBlock( - inputBytes, - inputOffset, - outputBytes, - outputOffset, - ); - outputBytes = result!['output'] as List?; - for (int i = 0; i < _size!; i++) { - outputBytes![outputOffset! + i] ^= _cbcBytes![i]; - } - final Uint8List? tempBytes = _cbcBytes; - _cbcBytes = _cbcNextBytes; - _cbcNextBytes = tempBytes; - return {'length': result['length'], 'output': outputBytes}; - } - - @override - int processingBlock( - Uint8List inputBytes, - int inputOffset, - Uint8List outputBytes, - int outputOffset, - ) { - return _isEncryption! - ? encryptBlock(inputBytes, inputOffset, outputBytes, outputOffset) - : decryptBlock(inputBytes, inputOffset, outputBytes, outputOffset); - } - - /// internal method - int encryptBlock( - Uint8List? inputBytes, - int inputOffset, - Uint8List? outputBytes, - int outputOffset, - ) { - if ((inputOffset + _size!) > inputBytes!.length) { - throw ArgumentError.value('Invalid length in input bytes'); - } - for (int i = 0; i < _size!; i++) { - _cbcBytes![i] ^= inputBytes[inputOffset + i]; - } - final result = _cipher!.processingBlock( - _cbcBytes!, - 0, - outputBytes!, - outputOffset, - ); - _cbcBytes!.setRange( - 0, - _size!, - Uint8List.view( - outputBytes.buffer, - outputBytes.offsetInBytes + outputOffset, - _size, - ), - ); - return result!; - } - - /// internal method - int decryptBlock( - Uint8List inputBytes, - int inputOffset, - Uint8List outputBytes, - int outputOffset, - ) { - if ((inputOffset + _size!) > inputBytes.length) { - throw ArgumentError.value('Invalid length in input bytes'); - } - _cbcNextBytes!.setRange( - 0, - _size!, - Uint8List.view( - inputBytes.buffer, - inputBytes.offsetInBytes + inputOffset, - blockSize, - ), - ); - final result = _cipher!.processingBlock( - inputBytes, - inputOffset, - outputBytes, - outputOffset, - ); - for (int i = 0; i < _size!; i++) { - outputBytes[outputOffset + i] ^= _cbcBytes![i]; - } - final Uint8List? tempBytes = _cbcBytes; - _cbcBytes = _cbcNextBytes; - _cbcNextBytes = tempBytes; - return result!; - } -} - -/// internal class -class InvalidParameter - implements ICipherParameter { - //Constructor - /// internal constructor - InvalidParameter(this.parameters, this.keys); - - //Fields - /// internal field - UnderlyingKeyParameters? parameters; - - /// internal field - Uint8List? keys; -} - -/// internal class -class KeyParameter extends ICipherParameter { - KeyParameter(this.keys); - - KeyParameter.fromLengthValue(Uint8List keys, int keyOff, int keyLen) { - this.keys = Uint8List(keyLen); - copyArray(keys, keyOff, this.keys, 0, keyLen); - } - late Uint8List keys; -} - -void copyArray( - Uint8List? sourceArr, - int sourcePos, - Uint8List? outArr, - int outPos, - int len, -) { - for (var i = 0; i < len; i++) { - outArr![outPos + i] = sourceArr![sourcePos + i]; - } -} - -/// internal class -class CipherParameter implements ICipherParameter { - /// internal constructor - CipherParameter(bool privateKey) { - _privateKey = privateKey; - } - //Fields - bool? _privateKey; - - /// internal property - bool? get isPrivate => _privateKey; - List? get keys => null; - set keys(List? value) {} - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is CipherParameter) { - return _privateKey == other._privateKey; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _privateKey.hashCode; -} - -/// internal class -class RsaKeyParam extends CipherParameter { - /// internal constructor - RsaKeyParam(super.isPrivate, BigInt? modulus, BigInt? exponent) { - _modulus = modulus; - _exponent = exponent; - } - //Fields - BigInt? _modulus; - BigInt? _exponent; - //Properties - /// internal property - BigInt? get modulus => _modulus; - - /// internal property - BigInt? get exponent => _exponent; - @override - List? get keys => null; - @override - set keys(List? value) {} - //Implementation - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is RsaKeyParam) { - return other.isPrivate == isPrivate && - other.modulus == _modulus && - other.exponent == _exponent; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => - _modulus.hashCode ^ _exponent.hashCode ^ isPrivate.hashCode; -} - -/// internal class -class RsaPrivateKeyParam extends RsaKeyParam { - /// internal constructor - RsaPrivateKeyParam( - BigInt? modulus, - this.publicExponent, - BigInt? privateExponent, - this.p, - this.q, - this.dP, - this.dQ, - this.inverse, - ) : super(true, modulus, privateExponent) { - validateValue(publicExponent!); - validateValue(p!); - validateValue(q!); - validateValue(dP!); - validateValue(dQ!); - validateValue(inverse!); - } - - //Fields - /// internal field - BigInt? publicExponent; - - /// internal field - BigInt? p; - - /// internal field - BigInt? q; - - /// internal field - BigInt? dP; - - /// internal field - BigInt? dQ; - - /// internal field - BigInt? inverse; - - //Implementation - /// internal method - void validateValue(BigInt number) { - if (number.sign <= 0) { - throw ArgumentError.value(number, 'number', 'Invalid RSA entry'); - } - } - - @override - List? get keys => null; - @override - set keys(List? value) {} - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is RsaPrivateKeyParam) { - return other.dP == dP && - other.dQ == dQ && - other._exponent == _exponent && - other._modulus == _modulus && - other.p == p && - other.q == q && - other.publicExponent == publicExponent && - other.inverse == inverse; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => - dP.hashCode ^ - dQ.hashCode ^ - _exponent.hashCode ^ - _modulus.hashCode ^ - p.hashCode ^ - q.hashCode ^ - publicExponent.hashCode ^ - inverse.hashCode; -} +import 'dart:typed_data'; +import 'ipadding.dart'; + +/// internal class +class CipherBlockChainingMode extends IBlockCipher { + //Constructor + /// internal constructor + CipherBlockChainingMode(ICipher? cipher) { + _cipher = cipher; + _size = _cipher!.blockSize; + + _bytes = Uint8List(_size!); + _cbcBytes = Uint8List(_size!); + _cbcNextBytes = Uint8List(_size!); + + _isEncryption = false; + } + + //Fields + ICipher? _cipher; + int? _size; + late Uint8List _bytes; + Uint8List? _cbcBytes; + Uint8List? _cbcNextBytes; + bool? _isEncryption; + + //Fields + @override + int? get blockSize => _cipher!.blockSize; + @override + String get algorithmName => '${_cipher!.algorithmName}/CBC'; + @override + bool get isBlock => false; + + //Implementation + @override + void initialize(bool isEncryption, ICipherParameter? parameters) { + final bool? oldEncryption = _isEncryption; + _isEncryption = isEncryption; + if (parameters != null) { + if (parameters is InvalidParameter) { + final List iv = parameters.keys!; + if (iv.length != blockSize) { + throw ArgumentError.value( + iv, + 'Initialization vector must be the same length as block size', + ); + } + _bytes.setAll(0, iv); + _cipher!.initialize(isEncryption, parameters.parameters); + } else { + _cipher!.initialize(isEncryption, parameters); + } + reset(); + } else if (oldEncryption != _isEncryption) { + throw ArgumentError.value( + oldEncryption, + 'cannot change encrypting state without providing key.', + ); + } + } + + @override + void reset() { + _cbcBytes!.setAll(0, _bytes); + _cbcNextBytes!.fillRange(0, _cbcNextBytes!.length, 0); + _cipher!.reset(); + } + + @override + Map processBlock( + List? inBytes, + int inOffset, + List? outBytes, + int? outOffset, + ) { + return _isEncryption! + ? encryptionBlock(inBytes!, inOffset, outBytes, outOffset!) + : decryptionBlock(inBytes!, inOffset, outBytes, outOffset); + } + + /// internal method + Map encryptionBlock( + List inputBytes, + int inputOffset, + List? outputBytes, + int outputOffset, + ) { + if ((inputOffset + _size!) > inputBytes.length) { + throw ArgumentError.value('Invalid length in input bytes'); + } + for (int i = 0; i < _size!; i++) { + _cbcBytes![i] ^= inputBytes[inputOffset + i]; + } + final Map result = + _cipher!.processBlock(_cbcBytes, 0, outputBytes, outputOffset)!; + outputBytes = result['output'] as List?; + List.copyRange( + _cbcBytes!, + 0, + outputBytes!, + outputOffset, + outputOffset + _cbcBytes!.length, + ); + return result; + } + + /// internal method + Map decryptionBlock( + List inputBytes, + int inputOffset, + List? outputBytes, + int? outputOffset, + ) { + if ((inputOffset + _size!) > inputBytes.length) { + throw ArgumentError.value('Invalid length in input bytes'); + } + List.copyRange( + _cbcNextBytes!, + 0, + inputBytes, + inputOffset, + inputOffset + _size!, + ); + final Map? result = _cipher!.processBlock( + inputBytes, + inputOffset, + outputBytes, + outputOffset, + ); + outputBytes = result!['output'] as List?; + for (int i = 0; i < _size!; i++) { + outputBytes![outputOffset! + i] ^= _cbcBytes![i]; + } + final Uint8List? tempBytes = _cbcBytes; + _cbcBytes = _cbcNextBytes; + _cbcNextBytes = tempBytes; + return {'length': result['length'], 'output': outputBytes}; + } + + @override + int processingBlock( + Uint8List inputBytes, + int inputOffset, + Uint8List outputBytes, + int outputOffset, + ) { + return _isEncryption! + ? encryptBlock(inputBytes, inputOffset, outputBytes, outputOffset) + : decryptBlock(inputBytes, inputOffset, outputBytes, outputOffset); + } + + /// internal method + int encryptBlock( + Uint8List? inputBytes, + int inputOffset, + Uint8List? outputBytes, + int outputOffset, + ) { + if ((inputOffset + _size!) > inputBytes!.length) { + throw ArgumentError.value('Invalid length in input bytes'); + } + for (int i = 0; i < _size!; i++) { + _cbcBytes![i] ^= inputBytes[inputOffset + i]; + } + final result = _cipher!.processingBlock( + _cbcBytes!, + 0, + outputBytes!, + outputOffset, + ); + _cbcBytes!.setRange( + 0, + _size!, + Uint8List.view( + outputBytes.buffer, + outputBytes.offsetInBytes + outputOffset, + _size, + ), + ); + return result!; + } + + /// internal method + int decryptBlock( + Uint8List inputBytes, + int inputOffset, + Uint8List outputBytes, + int outputOffset, + ) { + if ((inputOffset + _size!) > inputBytes.length) { + throw ArgumentError.value('Invalid length in input bytes'); + } + _cbcNextBytes!.setRange( + 0, + _size!, + Uint8List.view( + inputBytes.buffer, + inputBytes.offsetInBytes + inputOffset, + blockSize, + ), + ); + final result = _cipher!.processingBlock( + inputBytes, + inputOffset, + outputBytes, + outputOffset, + ); + for (int i = 0; i < _size!; i++) { + outputBytes[outputOffset + i] ^= _cbcBytes![i]; + } + final Uint8List? tempBytes = _cbcBytes; + _cbcBytes = _cbcNextBytes; + _cbcNextBytes = tempBytes; + return result!; + } +} + +/// internal class +class InvalidParameter + implements ICipherParameter { + //Constructor + /// internal constructor + InvalidParameter(this.parameters, this.keys); + + //Fields + /// internal field + UnderlyingKeyParameters? parameters; + + /// internal field + Uint8List? keys; +} + +/// internal class +class KeyParameter extends ICipherParameter { + KeyParameter(this.keys); + + KeyParameter.fromLengthValue(Uint8List keys, int keyOff, int keyLen) { + this.keys = Uint8List(keyLen); + copyArray(keys, keyOff, this.keys, 0, keyLen); + } + late Uint8List keys; +} + +void copyArray( + Uint8List? sourceArr, + int sourcePos, + Uint8List? outArr, + int outPos, + int len, +) { + for (var i = 0; i < len; i++) { + outArr![outPos + i] = sourceArr![sourcePos + i]; + } +} + +/// internal class +class CipherParameter implements ICipherParameter { + /// internal constructor + CipherParameter(bool privateKey) { + _privateKey = privateKey; + } + //Fields + bool? _privateKey; + + /// internal property + bool? get isPrivate => _privateKey; + List? get keys => null; + set keys(List? value) {} + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is CipherParameter) { + return _privateKey == other._privateKey; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _privateKey.hashCode; +} + +/// internal class +class RsaKeyParam extends CipherParameter { + /// internal constructor + RsaKeyParam(super.isPrivate, BigInt? modulus, BigInt? exponent) { + _modulus = modulus; + _exponent = exponent; + } + //Fields + BigInt? _modulus; + BigInt? _exponent; + //Properties + /// internal property + BigInt? get modulus => _modulus; + + /// internal property + BigInt? get exponent => _exponent; + @override + List? get keys => null; + @override + set keys(List? value) {} + //Implementation + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is RsaKeyParam) { + return other.isPrivate == isPrivate && + other.modulus == _modulus && + other.exponent == _exponent; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => + _modulus.hashCode ^ _exponent.hashCode ^ isPrivate.hashCode; +} + +/// internal class +class RsaPrivateKeyParam extends RsaKeyParam { + /// internal constructor + RsaPrivateKeyParam( + BigInt? modulus, + this.publicExponent, + BigInt? privateExponent, + this.p, + this.q, + this.dP, + this.dQ, + this.inverse, + ) : super(true, modulus, privateExponent) { + validateValue(publicExponent!); + validateValue(p!); + validateValue(q!); + validateValue(dP!); + validateValue(dQ!); + validateValue(inverse!); + } + + //Fields + /// internal field + BigInt? publicExponent; + + /// internal field + BigInt? p; + + /// internal field + BigInt? q; + + /// internal field + BigInt? dP; + + /// internal field + BigInt? dQ; + + /// internal field + BigInt? inverse; + + //Implementation + /// internal method + void validateValue(BigInt number) { + if (number.sign <= 0) { + throw ArgumentError.value(number, 'number', 'Invalid RSA entry'); + } + } + + @override + List? get keys => null; + @override + set keys(List? value) {} + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is RsaPrivateKeyParam) { + return other.dP == dP && + other.dQ == dQ && + other._exponent == _exponent && + other._modulus == _modulus && + other.p == p && + other.q == q && + other.publicExponent == publicExponent && + other.inverse == inverse; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => + dP.hashCode ^ + dQ.hashCode ^ + _exponent.hashCode ^ + _modulus.hashCode ^ + p.hashCode ^ + q.hashCode ^ + publicExponent.hashCode ^ + inverse.hashCode; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_utils.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_utils.dart index 07c189a51..4168d0adb 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_utils.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/cipher_utils.dart @@ -1,26 +1,26 @@ -/// internal class -class DigestAlgorithms { - /// internal field - static const String md5 = 'MD5'; - - /// internal field - static const String sha1 = 'SHA-1'; - - /// internal field - static const String sha256 = 'SHA-256'; - - /// internal field - static const String sha384 = 'SHA-384'; - - /// internal field - static const String sha512 = 'SHA-512'; - - /// internal field - static const String hmacWithSha1 = 'HmacWithSHA-1'; - - /// internal field - static const String hmacWithSha256 = 'HmacWithSHA-256'; - - /// internal field - static const String hmacWithMd5 = 'HmacWithMD5'; -} +/// internal class +class DigestAlgorithms { + /// internal field + static const String md5 = 'MD5'; + + /// internal field + static const String sha1 = 'SHA-1'; + + /// internal field + static const String sha256 = 'SHA-256'; + + /// internal field + static const String sha384 = 'SHA-384'; + + /// internal field + static const String sha512 = 'SHA-512'; + + /// internal field + static const String hmacWithSha1 = 'HmacWithSHA-1'; + + /// internal field + static const String hmacWithSha256 = 'HmacWithSHA-256'; + + /// internal field + static const String hmacWithMd5 = 'HmacWithMD5'; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/ipadding.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/ipadding.dart index 1ce939dba..f0fe7956a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/ipadding.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/ipadding.dart @@ -1,196 +1,196 @@ -import 'dart:typed_data'; - -/// internal class -abstract class IPadding { - /// internal method - void initialize([ICipherParameter? params]) {} - - /// internal property - String? get paddingName => null; - - /// internal method - int addPadding(Uint8List data, int offset); - - /// internal method - int count(Uint8List data); -} - -/// internal class -class IBufferedCipher extends ICipher { - IPadding? get padding => null; - - ICipher? get cipher => null; - - @override - Uint8List? process(Uint8List data) => null; - - /// internal method - @override - void initialize(bool forEncryption, ICipherParameter? parameters) {} - - /// internal method - int? getOutputSize(int inputLen) => null; - - /// internal method - int? getUpdateOutputSize(int inputLen) => null; - - /// internal method - List? processByte(int intput) => null; - - /// internal method - Map? copyBytes(int input, List output, int outOff) => - null; - - /// internal method - List? readBytesFromInput(List input) => null; - - /// internal method - List? readBytes(List input, int inOff, int length) => null; - - /// internal method - Map? processByteFromValues( - List input, - List output, - int outOff, - ) => null; - - /// internal method - Map? processBytes( - List input, - int inOff, - int length, - List output, - int outOff, - ) => null; - - /// internal method - List? doFinal() => null; - - int? doFinalProcess( - Uint8List inputBytes, - int inputOffset, - Uint8List outputBytes, - int outputOffset, - ) => null; - - /// internal method - List? doFinalFromInput(List? input) => null; - - /// internal method - List? readFinal(List input, int inOff, int length) => null; - - /// internal method - Map? writeFinal(List output, int outOff) => null; - - /// internal method - Map? copyFinal( - List input, - List output, - int outOff, - ) => null; - - /// internal method - Map? readFinalValues( - List input, - int inOff, - int length, - List output, - int outOff, - ) => null; - - /// internal method - @override - void reset() {} -} - -/// internal class -abstract class ICipher { - String? get algorithmName => null; - - /// Initialize the cipher - void initialize(bool isEncryption, ICipherParameter? parameters); - - /// internal property - int? get blockSize => null; - - /// internal property - bool? get isBlock => null; - - /// Process a full block - int? processingBlock( - Uint8List inputBytes, - int inputOffset, - Uint8List outputBytes, - int outputOffset, - ) => null; - - Map? processBlock( - List? inBytes, - int inOffset, - List? outBytes, - int? outOffset, - ) => null; - - /// Reset cipher - void reset(); - - Uint8List? process(Uint8List data) => null; -} - -abstract class IBlockCipher extends ICipher { - @override - Uint8List process(Uint8List data) { - final out = Uint8List(blockSize!); - final len = processingBlock(data, 0, out, 0); - return out.sublist(0, len); - } -} - -/// internal class -class ICipherBlock { - /// internal property - String? get algorithmName => null; - - /// internal method - void initialize(bool isEncryption, ICipherParameter? parameters) {} - - /// internal property - int? get inputBlock => null; - - /// internal property - int? get outputBlock => null; - - /// internal method - List? processBlock(List bytes, int offset, int length) => null; -} - -/// internal class -abstract class ICipherParameter {} - -/// internal class -class ISigner { - /// internal method - void initialize(bool isSigning, ICipherParameter? parameters) {} - - /// internal method - void blockUpdate(List bytes, int offset, int length) {} - - /// internal method - List? generateSignature() => null; - - /// internal method - bool validateSignature(List bytes) => false; - - /// internal method - void reset() {} -} - -/// internal class -class IRandom { - /// internal method - int? getValue(int position, [List? bytes, int? offset, int? length]) => - null; - - /// internal property - int? get length => null; -} +import 'dart:typed_data'; + +/// internal class +abstract class IPadding { + /// internal method + void initialize([ICipherParameter? params]) {} + + /// internal property + String? get paddingName => null; + + /// internal method + int addPadding(Uint8List data, int offset); + + /// internal method + int count(Uint8List data); +} + +/// internal class +class IBufferedCipher extends ICipher { + IPadding? get padding => null; + + ICipher? get cipher => null; + + @override + Uint8List? process(Uint8List data) => null; + + /// internal method + @override + void initialize(bool forEncryption, ICipherParameter? parameters) {} + + /// internal method + int? getOutputSize(int inputLen) => null; + + /// internal method + int? getUpdateOutputSize(int inputLen) => null; + + /// internal method + List? processByte(int intput) => null; + + /// internal method + Map? copyBytes(int input, List output, int outOff) => + null; + + /// internal method + List? readBytesFromInput(List input) => null; + + /// internal method + List? readBytes(List input, int inOff, int length) => null; + + /// internal method + Map? processByteFromValues( + List input, + List output, + int outOff, + ) => null; + + /// internal method + Map? processBytes( + List input, + int inOff, + int length, + List output, + int outOff, + ) => null; + + /// internal method + List? doFinal() => null; + + int? doFinalProcess( + Uint8List inputBytes, + int inputOffset, + Uint8List outputBytes, + int outputOffset, + ) => null; + + /// internal method + List? doFinalFromInput(List? input) => null; + + /// internal method + List? readFinal(List input, int inOff, int length) => null; + + /// internal method + Map? writeFinal(List output, int outOff) => null; + + /// internal method + Map? copyFinal( + List input, + List output, + int outOff, + ) => null; + + /// internal method + Map? readFinalValues( + List input, + int inOff, + int length, + List output, + int outOff, + ) => null; + + /// internal method + @override + void reset() {} +} + +/// internal class +abstract class ICipher { + String? get algorithmName => null; + + /// Initialize the cipher + void initialize(bool isEncryption, ICipherParameter? parameters); + + /// internal property + int? get blockSize => null; + + /// internal property + bool? get isBlock => null; + + /// Process a full block + int? processingBlock( + Uint8List inputBytes, + int inputOffset, + Uint8List outputBytes, + int outputOffset, + ) => null; + + Map? processBlock( + List? inBytes, + int inOffset, + List? outBytes, + int? outOffset, + ) => null; + + /// Reset cipher + void reset(); + + Uint8List? process(Uint8List data) => null; +} + +abstract class IBlockCipher extends ICipher { + @override + Uint8List process(Uint8List data) { + final out = Uint8List(blockSize!); + final len = processingBlock(data, 0, out, 0); + return out.sublist(0, len); + } +} + +/// internal class +class ICipherBlock { + /// internal property + String? get algorithmName => null; + + /// internal method + void initialize(bool isEncryption, ICipherParameter? parameters) {} + + /// internal property + int? get inputBlock => null; + + /// internal property + int? get outputBlock => null; + + /// internal method + List? processBlock(List bytes, int offset, int length) => null; +} + +/// internal class +abstract class ICipherParameter {} + +/// internal class +class ISigner { + /// internal method + void initialize(bool isSigning, ICipherParameter? parameters) {} + + /// internal method + void blockUpdate(List bytes, int offset, int length) {} + + /// internal method + List? generateSignature() => null; + + /// internal method + bool validateSignature(List bytes) => false; + + /// internal method + void reset() {} +} + +/// internal class +class IRandom { + /// internal method + int? getValue(int position, [List? bytes, int? offset, int? length]) => + null; + + /// internal property + int? get length => null; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/message_digest_utils.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/message_digest_utils.dart index c531da415..9daa1c606 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/message_digest_utils.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/message_digest_utils.dart @@ -1,1306 +1,1306 @@ -import 'package:crypto/crypto.dart'; -import '../asn1/der.dart'; -import '../pdf_signature_dictionary.dart'; -import '../pkcs/pfx_data.dart'; - -/// Internal class -class MessageDigestFinder { - /// Internal constructor - MessageDigestFinder() { - //Initialize the algorithms. - _algorithms['SHA1'] = 'SHA-1'; - _algorithms[DerObjectID('1.3.14.3.2.26').id!] = 'SHA-1'; - _algorithms['SHA256'] = 'SHA-256'; - _algorithms[NistObjectIds.sha256.id!] = 'SHA-256'; - _algorithms['SHA384'] = 'SHA-384'; - _algorithms[NistObjectIds.sha384.id!] = 'SHA-384'; - _algorithms['SHA512'] = 'SHA-512'; - _algorithms[NistObjectIds.sha512.id!] = 'SHA-512'; - _algorithms['MD5'] = 'MD5'; - _algorithms[PkcsObjectId.md5.id!] = 'MD5'; - _algorithms['RIPEMD-160'] = 'RIPEMD160'; - _algorithms['RIPEMD160'] = 'RIPEMD160'; - _algorithms[NistObjectIds.ripeMD160.id!] = 'RIPEMD160'; - //Initialize the ids. - _ids['SHA-1'] = DerObjectID('1.3.14.3.2.26'); - _ids['SHA-256'] = NistObjectIds.sha256; - _ids['SHA-384'] = NistObjectIds.sha384; - _ids['SHA-512'] = NistObjectIds.sha512; - _ids['MD5'] = PkcsObjectId.md5; - _ids['RIPEMD160'] = NistObjectIds.ripeMD160; - } - - /// Internal field - late final Map _algorithms = {}; - late final Map _ids = {}; - - /// Internal method - List getDigest(String algorithm, List bytes) { - final String upper = algorithm.toUpperCase(); - String? digest = _algorithms[upper]; - digest ??= upper; - digest = digest.toLowerCase(); - if (digest == 'sha1' || digest == 'sha-1' || digest == 'sha_1') { - return sha1.convert(bytes).bytes; - } else if (digest == 'sha256' || - digest == 'sha-256' || - digest == 'sha_256') { - return sha256.convert(bytes).bytes; - } else if (digest == 'sha384' || - digest == 'sha-384' || - digest == 'sha_384') { - return sha384.convert(bytes).bytes; - } else if (digest == 'sha512' || - digest == 'sha-512' || - digest == 'sha_512') { - return sha512.convert(bytes).bytes; - } else if (digest == 'md5' || digest == 'md-5' || digest == 'md_5') { - return md5.convert(bytes).bytes; - } else if (digest == 'ripemd160') { - final IMessageDigest digest = RIPEMD160MessageDigest(); - digest.updateWithBytes(bytes, 0, bytes.length); - return doFinal(digest); - } else { - throw ArgumentError.value( - algorithm, - 'hashAlgorithm', - 'Invalid message digest algorithm', - ); - } - } - - /// Internal method - List doFinal(IMessageDigest digest) { - final List bytes = List.filled( - digest.messageDigestSize!, - 0, - growable: true, - ); - digest.doFinal(bytes, 0); - return bytes; - } -} - -/// Internal class -abstract class IMessageDigest { - /// Retuns the agorithm name - String? algorithmName; - - /// Gets the size in bytes - int? messageDigestSize; - - /// Gets the buffer length - int? byteLength; - - /// Updates the message digit - void update(int input); - - /// Updates the message digit - void updateWithBytes(List bytes, int offset, int length); - - /// Updates the message digit with block of bytes - void blockUpdate(List bytes, int offset, int length); - - /// Retruns the final dighit values - int doFinal(List bytes, int offset); - - /// Reset - void reset(); -} - -/// Internal class -abstract class MessageDigest extends IMessageDigest { - /// Internal constructor - MessageDigest() { - _buf = List.filled(4, 0, growable: true); - } - - ///Internal Fields - late List _buf; - int _bufOff = 0; - int _byteCount = 0; - - /// Updates the message digit - @override - void update(int input) { - _buf[_bufOff++] = input; - if (_bufOff == _buf.length) { - processWord(_buf, 0); - _bufOff = 0; - } - _byteCount++; - } - - /// Updates the message digit - @override - void updateWithBytes(List bytes, int offset, int length) { - while ((_bufOff != 0) && (length > 0)) { - update(bytes[offset]); - offset++; - length--; - } - while (length > _buf.length) { - processWord(bytes, offset); - offset += _buf.length; - length -= _buf.length; - _byteCount += _buf.length; - } - while (length > 0) { - update(bytes[offset]); - offset++; - length--; - } - } - - /// Updates the message digit with block of bytes - @override - void blockUpdate(List bytes, int offset, int length) { - while ((_bufOff != 0) && (length > 0)) { - update(bytes[offset]); - offset++; - length--; - } - while (length > _buf.length) { - processWord(bytes, offset); - offset += _buf.length; - length -= _buf.length; - _byteCount += _buf.length; - } - while (length > 0) { - update(bytes[offset]); - offset++; - length--; - } - } - - /// Retruns the final dighit values - @override - int doFinal(List bytes, int offset); - - /// Reset - @override - void reset() { - _byteCount = 0; - _bufOff = 0; - _buf.clear(); - } - - /// Internal method - void finish() { - final int bitLength = _byteCount << 3; - update(128); - while (_bufOff != 0) { - update(0); - } - processLength(bitLength); - processBlock(); - } - - /// Internal method - void processWord(List input, int inOff); - - /// Internal method - void processLength(int bitLength); - - /// Internal method - void processBlock(); -} - -/// Internal class -class RIPEMD160MessageDigest extends MessageDigest { - /// Internal constructor - RIPEMD160MessageDigest() { - reset(); - } - - /// Internal field - // static const int _digestLength = 20; - late int _h0, _h1, _h2, _h3, _h4; - List _x = []; - late int _xOffset; - - /// Retuns the agorithm name - @override - String? get algorithmName => 'RIPEMD160'; - - /// Gets the size in bytes - @override - int? get messageDigestSize => 20; - - @override - void reset() { - super.reset(); - _h0 = 0x67452301; - _h1 = 0xefcdab89; - _h2 = 0x98badcfe; - _h3 = 0x10325476; - _h4 = 0xc3d2e1f0; - _xOffset = 0; - _x.clear(); - _x = List.filled(16, 0, growable: true); - } - - @override - void processWord(List input, int inOff) { - _x[_xOffset++] = - (input[inOff] & 0xff) | - ((input[inOff + 1] & 0xff) << 8) | - ((input[inOff + 2] & 0xff) << 16) | - ((input[inOff + 3] & 0xff) << 24); - if (_xOffset == 16) { - processBlock(); - } - } - - @override - void processLength(int bitLength) { - if (_xOffset > 14) { - processBlock(); - } - _x[14] = bitLength & 0xffffffff; - _x[15] = bitLength.toUnsigned(64) >> 32; - } - - @override - int doFinal(List bytes, int offset) { - finish(); - unpackWord(_h0, bytes, offset); - unpackWord(_h1, bytes, offset + 4); - unpackWord(_h2, bytes, offset + 8); - unpackWord(_h3, bytes, offset + 12); - unpackWord(_h4, bytes, offset + 16); - reset(); - return messageDigestSize!; - } - - @override - void processBlock() { - int a, f; - int b, g; - int c, h; - int d, i; - int e, j; - a = f = _h0; - b = g = _h1; - c = h = _h2; - d = i = _h3; - e = j = _h4; - a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[0], 11) + e; - c = getRightToLeft(c, 10); - e = getRightToLeft(e + getBitLevelEXOR(a, b, c) + _x[1], 14) + d; - b = getRightToLeft(b, 10); - d = getRightToLeft(d + getBitLevelEXOR(e, a, b) + _x[2], 15) + c; - a = getRightToLeft(a, 10); - c = getRightToLeft(c + getBitLevelEXOR(d, e, a) + _x[3], 12) + b; - e = getRightToLeft(e, 10); - b = getRightToLeft(b + getBitLevelEXOR(c, d, e) + _x[4], 5) + a; - d = getRightToLeft(d, 10); - a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[5], 8) + e; - c = getRightToLeft(c, 10); - e = getRightToLeft(e + getBitLevelEXOR(a, b, c) + _x[6], 7) + d; - b = getRightToLeft(b, 10); - d = getRightToLeft(d + getBitLevelEXOR(e, a, b) + _x[7], 9) + c; - a = getRightToLeft(a, 10); - c = getRightToLeft(c + getBitLevelEXOR(d, e, a) + _x[8], 11) + b; - e = getRightToLeft(e, 10); - b = getRightToLeft(b + getBitLevelEXOR(c, d, e) + _x[9], 13) + a; - d = getRightToLeft(d, 10); - a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[10], 14) + e; - c = getRightToLeft(c, 10); - e = getRightToLeft(e + getBitLevelEXOR(a, b, c) + _x[11], 15) + d; - b = getRightToLeft(b, 10); - d = getRightToLeft(d + getBitLevelEXOR(e, a, b) + _x[12], 6) + c; - a = getRightToLeft(a, 10); - c = getRightToLeft(c + getBitLevelEXOR(d, e, a) + _x[13], 7) + b; - e = getRightToLeft(e, 10); - b = getRightToLeft(b + getBitLevelEXOR(c, d, e) + _x[14], 9) + a; - d = getRightToLeft(d, 10); - a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[15], 8) + e; - c = getRightToLeft(c, 10); - - f = - getRightToLeft( - f + getBitlevelReverseNegative(g, h, i) + _x[5] + 1352829926, - 8, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelReverseNegative(f, g, h) + _x[14] + 1352829926, - 9, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelReverseNegative(j, f, g) + _x[7] + 1352829926, - 9, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelReverseNegative(i, j, f) + _x[0] + 1352829926, - 11, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelReverseNegative(h, i, j) + _x[9] + 1352829926, - 13, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelReverseNegative(g, h, i) + _x[2] + 1352829926, - 15, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelReverseNegative(f, g, h) + _x[11] + 1352829926, - 15, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelReverseNegative(j, f, g) + _x[4] + 1352829926, - 5, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelReverseNegative(i, j, f) + _x[13] + 1352829926, - 7, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelReverseNegative(h, i, j) + _x[6] + 1352829926, - 7, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelReverseNegative(g, h, i) + _x[15] + 1352829926, - 8, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelReverseNegative(f, g, h) + _x[8] + 1352829926, - 11, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelReverseNegative(j, f, g) + _x[1] + 1352829926, - 14, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelReverseNegative(i, j, f) + _x[10] + 1352829926, - 14, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelReverseNegative(h, i, j) + _x[3] + 1352829926, - 12, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelReverseNegative(g, h, i) + _x[12] + 1352829926, - 6, - ) + - j; - h = getRightToLeft(h, 10); - - e = - getRightToLeft( - e + getBitlevelMultiplexer(a, b, c) + _x[7] + 1518500249, - 7, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelMultiplexer(e, a, b) + _x[4] + 1518500249, - 6, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelMultiplexer(d, e, a) + _x[13] + 1518500249, - 8, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelMultiplexer(c, d, e) + _x[1] + 1518500249, - 13, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelMultiplexer(b, c, d) + _x[10] + 1518500249, - 11, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelMultiplexer(a, b, c) + _x[6] + 1518500249, - 9, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelMultiplexer(e, a, b) + _x[15] + 1518500249, - 7, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelMultiplexer(d, e, a) + _x[3] + 1518500249, - 15, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelMultiplexer(c, d, e) + _x[12] + 1518500249, - 7, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelMultiplexer(b, c, d) + _x[0] + 1518500249, - 12, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelMultiplexer(a, b, c) + _x[9] + 1518500249, - 15, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelMultiplexer(e, a, b) + _x[5] + 1518500249, - 9, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelMultiplexer(d, e, a) + _x[2] + 1518500249, - 11, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelMultiplexer(c, d, e) + _x[14] + 1518500249, - 7, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelMultiplexer(b, c, d) + _x[11] + 1518500249, - 13, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelMultiplexer(a, b, c) + _x[8] + 1518500249, - 12, - ) + - d; - b = getRightToLeft(b, 10); - - j = - getRightToLeft( - j + getBitlevelDemultiplexer(f, g, h) + _x[6] + 1548603684, - 9, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelDemultiplexer(j, f, g) + _x[11] + 1548603684, - 13, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelDemultiplexer(i, j, f) + _x[3] + 1548603684, - 15, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelDemultiplexer(h, i, j) + _x[7] + 1548603684, - 7, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelDemultiplexer(g, h, i) + _x[0] + 1548603684, - 12, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelDemultiplexer(f, g, h) + _x[13] + 1548603684, - 8, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelDemultiplexer(j, f, g) + _x[5] + 1548603684, - 9, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelDemultiplexer(i, j, f) + _x[10] + 1548603684, - 11, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelDemultiplexer(h, i, j) + _x[14] + 1548603684, - 7, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelDemultiplexer(g, h, i) + _x[15] + 1548603684, - 7, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelDemultiplexer(f, g, h) + _x[8] + 1548603684, - 12, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelDemultiplexer(j, f, g) + _x[12] + 1548603684, - 7, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelDemultiplexer(i, j, f) + _x[4] + 1548603684, - 6, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelDemultiplexer(h, i, j) + _x[9] + 1548603684, - 15, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelDemultiplexer(g, h, i) + _x[1] + 1548603684, - 13, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelDemultiplexer(f, g, h) + _x[2] + 1548603684, - 11, - ) + - i; - g = getRightToLeft(g, 10); - - d = - getRightToLeft( - d + getBitlevelNegative(e, a, b) + _x[3] + 1859775393, - 11, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelNegative(d, e, a) + _x[10] + 1859775393, - 13, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelNegative(c, d, e) + _x[14] + 1859775393, - 6, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelNegative(b, c, d) + _x[4] + 1859775393, - 7, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelNegative(a, b, c) + _x[9] + 1859775393, - 14, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelNegative(e, a, b) + _x[15] + 1859775393, - 9, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelNegative(d, e, a) + _x[8] + 1859775393, - 13, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelNegative(c, d, e) + _x[1] + 1859775393, - 15, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelNegative(b, c, d) + _x[2] + 1859775393, - 14, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelNegative(a, b, c) + _x[7] + 1859775393, - 8, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelNegative(e, a, b) + _x[0] + 1859775393, - 13, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelNegative(d, e, a) + _x[6] + 1859775393, - 6, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelNegative(c, d, e) + _x[13] + 1859775393, - 5, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelNegative(b, c, d) + _x[11] + 1859775393, - 12, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelNegative(a, b, c) + _x[5] + 1859775393, - 7, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelNegative(e, a, b) + _x[12] + 1859775393, - 5, - ) + - c; - a = getRightToLeft(a, 10); - - i = - getRightToLeft( - i + getBitlevelNegative(j, f, g) + _x[15] + 1836072691, - 9, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelNegative(i, j, f) + _x[5] + 1836072691, - 7, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelNegative(h, i, j) + _x[1] + 1836072691, - 15, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelNegative(g, h, i) + _x[3] + 1836072691, - 11, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelNegative(f, g, h) + _x[7] + 1836072691, - 8, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelNegative(j, f, g) + _x[14] + 1836072691, - 6, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelNegative(i, j, f) + _x[6] + 1836072691, - 6, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelNegative(h, i, j) + _x[9] + 1836072691, - 14, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelNegative(g, h, i) + _x[11] + 1836072691, - 12, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelNegative(f, g, h) + _x[8] + 1836072691, - 13, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelNegative(j, f, g) + _x[12] + 1836072691, - 5, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelNegative(i, j, f) + _x[2] + 1836072691, - 14, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelNegative(h, i, j) + _x[10] + 1836072691, - 13, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelNegative(g, h, i) + _x[0] + 1836072691, - 13, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelNegative(f, g, h) + _x[4] + 1836072691, - 7, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelNegative(j, f, g) + _x[13] + 1836072691, - 5, - ) + - h; - f = getRightToLeft(f, 10); - - c = - getRightToLeft( - c + getBitlevelDemultiplexer(d, e, a) + _x[1] - 1894007588, - 11, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelDemultiplexer(c, d, e) + _x[9] - 1894007588, - 12, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelDemultiplexer(b, c, d) + _x[11] - 1894007588, - 14, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelDemultiplexer(a, b, c) + _x[10] - 1894007588, - 15, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelDemultiplexer(e, a, b) + _x[0] - 1894007588, - 14, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelDemultiplexer(d, e, a) + _x[8] - 1894007588, - 15, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelDemultiplexer(c, d, e) + _x[12] - 1894007588, - 9, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelDemultiplexer(b, c, d) + _x[4] - 1894007588, - 8, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelDemultiplexer(a, b, c) + _x[13] - 1894007588, - 9, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelDemultiplexer(e, a, b) + _x[3] - 1894007588, - 14, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelDemultiplexer(d, e, a) + _x[7] - 1894007588, - 5, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelDemultiplexer(c, d, e) + _x[15] - 1894007588, - 6, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelDemultiplexer(b, c, d) + _x[14] - 1894007588, - 8, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelDemultiplexer(a, b, c) + _x[5] - 1894007588, - 6, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelDemultiplexer(e, a, b) + _x[6] - 1894007588, - 5, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelDemultiplexer(d, e, a) + _x[2] - 1894007588, - 12, - ) + - b; - e = getRightToLeft(e, 10); - - h = - getRightToLeft( - h + getBitlevelMultiplexer(i, j, f) + _x[8] + 2053994217, - 15, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelMultiplexer(h, i, j) + _x[6] + 2053994217, - 5, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelMultiplexer(g, h, i) + _x[4] + 2053994217, - 8, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelMultiplexer(f, g, h) + _x[1] + 2053994217, - 11, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelMultiplexer(j, f, g) + _x[3] + 2053994217, - 14, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelMultiplexer(i, j, f) + _x[11] + 2053994217, - 14, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelMultiplexer(h, i, j) + _x[15] + 2053994217, - 6, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelMultiplexer(g, h, i) + _x[0] + 2053994217, - 14, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelMultiplexer(f, g, h) + _x[5] + 2053994217, - 6, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelMultiplexer(j, f, g) + _x[12] + 2053994217, - 9, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelMultiplexer(i, j, f) + _x[2] + 2053994217, - 12, - ) + - g; - j = getRightToLeft(j, 10); - g = - getRightToLeft( - g + getBitlevelMultiplexer(h, i, j) + _x[13] + 2053994217, - 9, - ) + - f; - i = getRightToLeft(i, 10); - f = - getRightToLeft( - f + getBitlevelMultiplexer(g, h, i) + _x[9] + 2053994217, - 12, - ) + - j; - h = getRightToLeft(h, 10); - j = - getRightToLeft( - j + getBitlevelMultiplexer(f, g, h) + _x[7] + 2053994217, - 5, - ) + - i; - g = getRightToLeft(g, 10); - i = - getRightToLeft( - i + getBitlevelMultiplexer(j, f, g) + _x[10] + 2053994217, - 15, - ) + - h; - f = getRightToLeft(f, 10); - h = - getRightToLeft( - h + getBitlevelMultiplexer(i, j, f) + _x[14] + 2053994217, - 8, - ) + - g; - j = getRightToLeft(j, 10); - - b = - getRightToLeft( - b + getBitlevelReverseNegative(c, d, e) + _x[4] - 1454113458, - 9, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelReverseNegative(b, c, d) + _x[0] - 1454113458, - 15, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelReverseNegative(a, b, c) + _x[5] - 1454113458, - 5, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelReverseNegative(e, a, b) + _x[9] - 1454113458, - 11, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelReverseNegative(d, e, a) + _x[7] - 1454113458, - 6, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelReverseNegative(c, d, e) + _x[12] - 1454113458, - 8, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelReverseNegative(b, c, d) + _x[2] - 1454113458, - 13, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelReverseNegative(a, b, c) + _x[10] - 1454113458, - 12, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelReverseNegative(e, a, b) + _x[14] - 1454113458, - 5, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelReverseNegative(d, e, a) + _x[1] - 1454113458, - 12, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelReverseNegative(c, d, e) + _x[3] - 1454113458, - 13, - ) + - a; - d = getRightToLeft(d, 10); - a = - getRightToLeft( - a + getBitlevelReverseNegative(b, c, d) + _x[8] - 1454113458, - 14, - ) + - e; - c = getRightToLeft(c, 10); - e = - getRightToLeft( - e + getBitlevelReverseNegative(a, b, c) + _x[11] - 1454113458, - 11, - ) + - d; - b = getRightToLeft(b, 10); - d = - getRightToLeft( - d + getBitlevelReverseNegative(e, a, b) + _x[6] - 1454113458, - 8, - ) + - c; - a = getRightToLeft(a, 10); - c = - getRightToLeft( - c + getBitlevelReverseNegative(d, e, a) + _x[15] - 1454113458, - 5, - ) + - b; - e = getRightToLeft(e, 10); - b = - getRightToLeft( - b + getBitlevelReverseNegative(c, d, e) + _x[13] - 1454113458, - 6, - ) + - a; - d = getRightToLeft(d, 10); - - g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[12], 8) + f; - i = getRightToLeft(i, 10); - f = getRightToLeft(f + getBitLevelEXOR(g, h, i) + _x[15], 5) + j; - h = getRightToLeft(h, 10); - j = getRightToLeft(j + getBitLevelEXOR(f, g, h) + _x[10], 12) + i; - g = getRightToLeft(g, 10); - i = getRightToLeft(i + getBitLevelEXOR(j, f, g) + _x[4], 9) + h; - f = getRightToLeft(f, 10); - h = getRightToLeft(h + getBitLevelEXOR(i, j, f) + _x[1], 12) + g; - j = getRightToLeft(j, 10); - g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[5], 5) + f; - i = getRightToLeft(i, 10); - f = getRightToLeft(f + getBitLevelEXOR(g, h, i) + _x[8], 14) + j; - h = getRightToLeft(h, 10); - j = getRightToLeft(j + getBitLevelEXOR(f, g, h) + _x[7], 6) + i; - g = getRightToLeft(g, 10); - i = getRightToLeft(i + getBitLevelEXOR(j, f, g) + _x[6], 8) + h; - f = getRightToLeft(f, 10); - h = getRightToLeft(h + getBitLevelEXOR(i, j, f) + _x[2], 13) + g; - j = getRightToLeft(j, 10); - g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[13], 6) + f; - i = getRightToLeft(i, 10); - f = getRightToLeft(f + getBitLevelEXOR(g, h, i) + _x[14], 5) + j; - h = getRightToLeft(h, 10); - j = getRightToLeft(j + getBitLevelEXOR(f, g, h) + _x[0], 15) + i; - g = getRightToLeft(g, 10); - i = getRightToLeft(i + getBitLevelEXOR(j, f, g) + _x[3], 13) + h; - f = getRightToLeft(f, 10); - h = getRightToLeft(h + getBitLevelEXOR(i, j, f) + _x[9], 11) + g; - j = getRightToLeft(j, 10); - g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[11], 11) + f; - i = getRightToLeft(i, 10); - - i += c + _h1; - _h1 = _h2 + d + j; - _h2 = _h3 + e + f; - _h3 = _h4 + a + g; - _h4 = _h0 + b + h; - _h0 = i; - - _xOffset = 0; - _x.fillRange(0, 16, 0); - } - - /// Internal method - void unpackWord(int word, List output, int offset) { - output[offset] = word.toUnsigned(8); - output[offset + 1] = (word.toUnsigned(32) >> 8).toUnsigned(8); - output[offset + 2] = (word.toUnsigned(32) >> 16).toUnsigned(8); - output[offset + 3] = (word.toUnsigned(32) >> 24).toUnsigned(8); - } - - /// Internal method - int getRightToLeft(int x, int n) { - return (x << n) | (x.toUnsigned(32) >> (32 - n)); - } - - /// Internal method - int getBitLevelEXOR(int x, int y, int z) { - return x ^ y ^ z; - } - - /// Internal method - int getBitlevelMultiplexer(int x, int y, int z) { - return (x & y) | (~x & z); - } - - /// Internal method - int getBitlevelNegative(int x, int y, int z) { - return (x | ~y) ^ z; - } - - /// Internal method - int getBitlevelDemultiplexer(int x, int y, int z) { - return (x & z) | (y & ~z); - } - - /// Internal method - int getBitlevelReverseNegative(int x, int y, int z) { - return x ^ (y | ~z); - } -} +import 'package:crypto/crypto.dart'; +import '../asn1/der.dart'; +import '../pdf_signature_dictionary.dart'; +import '../pkcs/pfx_data.dart'; + +/// Internal class +class MessageDigestFinder { + /// Internal constructor + MessageDigestFinder() { + //Initialize the algorithms. + _algorithms['SHA1'] = 'SHA-1'; + _algorithms[DerObjectID('1.3.14.3.2.26').id!] = 'SHA-1'; + _algorithms['SHA256'] = 'SHA-256'; + _algorithms[NistObjectIds.sha256.id!] = 'SHA-256'; + _algorithms['SHA384'] = 'SHA-384'; + _algorithms[NistObjectIds.sha384.id!] = 'SHA-384'; + _algorithms['SHA512'] = 'SHA-512'; + _algorithms[NistObjectIds.sha512.id!] = 'SHA-512'; + _algorithms['MD5'] = 'MD5'; + _algorithms[PkcsObjectId.md5.id!] = 'MD5'; + _algorithms['RIPEMD-160'] = 'RIPEMD160'; + _algorithms['RIPEMD160'] = 'RIPEMD160'; + _algorithms[NistObjectIds.ripeMD160.id!] = 'RIPEMD160'; + //Initialize the ids. + _ids['SHA-1'] = DerObjectID('1.3.14.3.2.26'); + _ids['SHA-256'] = NistObjectIds.sha256; + _ids['SHA-384'] = NistObjectIds.sha384; + _ids['SHA-512'] = NistObjectIds.sha512; + _ids['MD5'] = PkcsObjectId.md5; + _ids['RIPEMD160'] = NistObjectIds.ripeMD160; + } + + /// Internal field + late final Map _algorithms = {}; + late final Map _ids = {}; + + /// Internal method + List getDigest(String algorithm, List bytes) { + final String upper = algorithm.toUpperCase(); + String? digest = _algorithms[upper]; + digest ??= upper; + digest = digest.toLowerCase(); + if (digest == 'sha1' || digest == 'sha-1' || digest == 'sha_1') { + return sha1.convert(bytes).bytes; + } else if (digest == 'sha256' || + digest == 'sha-256' || + digest == 'sha_256') { + return sha256.convert(bytes).bytes; + } else if (digest == 'sha384' || + digest == 'sha-384' || + digest == 'sha_384') { + return sha384.convert(bytes).bytes; + } else if (digest == 'sha512' || + digest == 'sha-512' || + digest == 'sha_512') { + return sha512.convert(bytes).bytes; + } else if (digest == 'md5' || digest == 'md-5' || digest == 'md_5') { + return md5.convert(bytes).bytes; + } else if (digest == 'ripemd160') { + final IMessageDigest digest = RIPEMD160MessageDigest(); + digest.updateWithBytes(bytes, 0, bytes.length); + return doFinal(digest); + } else { + throw ArgumentError.value( + algorithm, + 'hashAlgorithm', + 'Invalid message digest algorithm', + ); + } + } + + /// Internal method + List doFinal(IMessageDigest digest) { + final List bytes = List.filled( + digest.messageDigestSize!, + 0, + growable: true, + ); + digest.doFinal(bytes, 0); + return bytes; + } +} + +/// Internal class +abstract class IMessageDigest { + /// Retuns the agorithm name + String? algorithmName; + + /// Gets the size in bytes + int? messageDigestSize; + + /// Gets the buffer length + int? byteLength; + + /// Updates the message digit + void update(int input); + + /// Updates the message digit + void updateWithBytes(List bytes, int offset, int length); + + /// Updates the message digit with block of bytes + void blockUpdate(List bytes, int offset, int length); + + /// Retruns the final dighit values + int doFinal(List bytes, int offset); + + /// Reset + void reset(); +} + +/// Internal class +abstract class MessageDigest extends IMessageDigest { + /// Internal constructor + MessageDigest() { + _buf = List.filled(4, 0, growable: true); + } + + ///Internal Fields + late List _buf; + int _bufOff = 0; + int _byteCount = 0; + + /// Updates the message digit + @override + void update(int input) { + _buf[_bufOff++] = input; + if (_bufOff == _buf.length) { + processWord(_buf, 0); + _bufOff = 0; + } + _byteCount++; + } + + /// Updates the message digit + @override + void updateWithBytes(List bytes, int offset, int length) { + while ((_bufOff != 0) && (length > 0)) { + update(bytes[offset]); + offset++; + length--; + } + while (length > _buf.length) { + processWord(bytes, offset); + offset += _buf.length; + length -= _buf.length; + _byteCount += _buf.length; + } + while (length > 0) { + update(bytes[offset]); + offset++; + length--; + } + } + + /// Updates the message digit with block of bytes + @override + void blockUpdate(List bytes, int offset, int length) { + while ((_bufOff != 0) && (length > 0)) { + update(bytes[offset]); + offset++; + length--; + } + while (length > _buf.length) { + processWord(bytes, offset); + offset += _buf.length; + length -= _buf.length; + _byteCount += _buf.length; + } + while (length > 0) { + update(bytes[offset]); + offset++; + length--; + } + } + + /// Retruns the final dighit values + @override + int doFinal(List bytes, int offset); + + /// Reset + @override + void reset() { + _byteCount = 0; + _bufOff = 0; + _buf.clear(); + } + + /// Internal method + void finish() { + final int bitLength = _byteCount << 3; + update(128); + while (_bufOff != 0) { + update(0); + } + processLength(bitLength); + processBlock(); + } + + /// Internal method + void processWord(List input, int inOff); + + /// Internal method + void processLength(int bitLength); + + /// Internal method + void processBlock(); +} + +/// Internal class +class RIPEMD160MessageDigest extends MessageDigest { + /// Internal constructor + RIPEMD160MessageDigest() { + reset(); + } + + /// Internal field + // static const int _digestLength = 20; + late int _h0, _h1, _h2, _h3, _h4; + List _x = []; + late int _xOffset; + + /// Retuns the agorithm name + @override + String? get algorithmName => 'RIPEMD160'; + + /// Gets the size in bytes + @override + int? get messageDigestSize => 20; + + @override + void reset() { + super.reset(); + _h0 = 0x67452301; + _h1 = 0xefcdab89; + _h2 = 0x98badcfe; + _h3 = 0x10325476; + _h4 = 0xc3d2e1f0; + _xOffset = 0; + _x.clear(); + _x = List.filled(16, 0, growable: true); + } + + @override + void processWord(List input, int inOff) { + _x[_xOffset++] = + (input[inOff] & 0xff) | + ((input[inOff + 1] & 0xff) << 8) | + ((input[inOff + 2] & 0xff) << 16) | + ((input[inOff + 3] & 0xff) << 24); + if (_xOffset == 16) { + processBlock(); + } + } + + @override + void processLength(int bitLength) { + if (_xOffset > 14) { + processBlock(); + } + _x[14] = bitLength & 0xffffffff; + _x[15] = bitLength.toUnsigned(64) >> 32; + } + + @override + int doFinal(List bytes, int offset) { + finish(); + unpackWord(_h0, bytes, offset); + unpackWord(_h1, bytes, offset + 4); + unpackWord(_h2, bytes, offset + 8); + unpackWord(_h3, bytes, offset + 12); + unpackWord(_h4, bytes, offset + 16); + reset(); + return messageDigestSize!; + } + + @override + void processBlock() { + int a, f; + int b, g; + int c, h; + int d, i; + int e, j; + a = f = _h0; + b = g = _h1; + c = h = _h2; + d = i = _h3; + e = j = _h4; + a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[0], 11) + e; + c = getRightToLeft(c, 10); + e = getRightToLeft(e + getBitLevelEXOR(a, b, c) + _x[1], 14) + d; + b = getRightToLeft(b, 10); + d = getRightToLeft(d + getBitLevelEXOR(e, a, b) + _x[2], 15) + c; + a = getRightToLeft(a, 10); + c = getRightToLeft(c + getBitLevelEXOR(d, e, a) + _x[3], 12) + b; + e = getRightToLeft(e, 10); + b = getRightToLeft(b + getBitLevelEXOR(c, d, e) + _x[4], 5) + a; + d = getRightToLeft(d, 10); + a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[5], 8) + e; + c = getRightToLeft(c, 10); + e = getRightToLeft(e + getBitLevelEXOR(a, b, c) + _x[6], 7) + d; + b = getRightToLeft(b, 10); + d = getRightToLeft(d + getBitLevelEXOR(e, a, b) + _x[7], 9) + c; + a = getRightToLeft(a, 10); + c = getRightToLeft(c + getBitLevelEXOR(d, e, a) + _x[8], 11) + b; + e = getRightToLeft(e, 10); + b = getRightToLeft(b + getBitLevelEXOR(c, d, e) + _x[9], 13) + a; + d = getRightToLeft(d, 10); + a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[10], 14) + e; + c = getRightToLeft(c, 10); + e = getRightToLeft(e + getBitLevelEXOR(a, b, c) + _x[11], 15) + d; + b = getRightToLeft(b, 10); + d = getRightToLeft(d + getBitLevelEXOR(e, a, b) + _x[12], 6) + c; + a = getRightToLeft(a, 10); + c = getRightToLeft(c + getBitLevelEXOR(d, e, a) + _x[13], 7) + b; + e = getRightToLeft(e, 10); + b = getRightToLeft(b + getBitLevelEXOR(c, d, e) + _x[14], 9) + a; + d = getRightToLeft(d, 10); + a = getRightToLeft(a + getBitLevelEXOR(b, c, d) + _x[15], 8) + e; + c = getRightToLeft(c, 10); + + f = + getRightToLeft( + f + getBitlevelReverseNegative(g, h, i) + _x[5] + 1352829926, + 8, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelReverseNegative(f, g, h) + _x[14] + 1352829926, + 9, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelReverseNegative(j, f, g) + _x[7] + 1352829926, + 9, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelReverseNegative(i, j, f) + _x[0] + 1352829926, + 11, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelReverseNegative(h, i, j) + _x[9] + 1352829926, + 13, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelReverseNegative(g, h, i) + _x[2] + 1352829926, + 15, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelReverseNegative(f, g, h) + _x[11] + 1352829926, + 15, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelReverseNegative(j, f, g) + _x[4] + 1352829926, + 5, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelReverseNegative(i, j, f) + _x[13] + 1352829926, + 7, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelReverseNegative(h, i, j) + _x[6] + 1352829926, + 7, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelReverseNegative(g, h, i) + _x[15] + 1352829926, + 8, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelReverseNegative(f, g, h) + _x[8] + 1352829926, + 11, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelReverseNegative(j, f, g) + _x[1] + 1352829926, + 14, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelReverseNegative(i, j, f) + _x[10] + 1352829926, + 14, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelReverseNegative(h, i, j) + _x[3] + 1352829926, + 12, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelReverseNegative(g, h, i) + _x[12] + 1352829926, + 6, + ) + + j; + h = getRightToLeft(h, 10); + + e = + getRightToLeft( + e + getBitlevelMultiplexer(a, b, c) + _x[7] + 1518500249, + 7, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelMultiplexer(e, a, b) + _x[4] + 1518500249, + 6, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelMultiplexer(d, e, a) + _x[13] + 1518500249, + 8, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelMultiplexer(c, d, e) + _x[1] + 1518500249, + 13, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelMultiplexer(b, c, d) + _x[10] + 1518500249, + 11, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelMultiplexer(a, b, c) + _x[6] + 1518500249, + 9, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelMultiplexer(e, a, b) + _x[15] + 1518500249, + 7, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelMultiplexer(d, e, a) + _x[3] + 1518500249, + 15, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelMultiplexer(c, d, e) + _x[12] + 1518500249, + 7, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelMultiplexer(b, c, d) + _x[0] + 1518500249, + 12, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelMultiplexer(a, b, c) + _x[9] + 1518500249, + 15, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelMultiplexer(e, a, b) + _x[5] + 1518500249, + 9, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelMultiplexer(d, e, a) + _x[2] + 1518500249, + 11, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelMultiplexer(c, d, e) + _x[14] + 1518500249, + 7, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelMultiplexer(b, c, d) + _x[11] + 1518500249, + 13, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelMultiplexer(a, b, c) + _x[8] + 1518500249, + 12, + ) + + d; + b = getRightToLeft(b, 10); + + j = + getRightToLeft( + j + getBitlevelDemultiplexer(f, g, h) + _x[6] + 1548603684, + 9, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelDemultiplexer(j, f, g) + _x[11] + 1548603684, + 13, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelDemultiplexer(i, j, f) + _x[3] + 1548603684, + 15, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelDemultiplexer(h, i, j) + _x[7] + 1548603684, + 7, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelDemultiplexer(g, h, i) + _x[0] + 1548603684, + 12, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelDemultiplexer(f, g, h) + _x[13] + 1548603684, + 8, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelDemultiplexer(j, f, g) + _x[5] + 1548603684, + 9, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelDemultiplexer(i, j, f) + _x[10] + 1548603684, + 11, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelDemultiplexer(h, i, j) + _x[14] + 1548603684, + 7, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelDemultiplexer(g, h, i) + _x[15] + 1548603684, + 7, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelDemultiplexer(f, g, h) + _x[8] + 1548603684, + 12, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelDemultiplexer(j, f, g) + _x[12] + 1548603684, + 7, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelDemultiplexer(i, j, f) + _x[4] + 1548603684, + 6, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelDemultiplexer(h, i, j) + _x[9] + 1548603684, + 15, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelDemultiplexer(g, h, i) + _x[1] + 1548603684, + 13, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelDemultiplexer(f, g, h) + _x[2] + 1548603684, + 11, + ) + + i; + g = getRightToLeft(g, 10); + + d = + getRightToLeft( + d + getBitlevelNegative(e, a, b) + _x[3] + 1859775393, + 11, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelNegative(d, e, a) + _x[10] + 1859775393, + 13, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelNegative(c, d, e) + _x[14] + 1859775393, + 6, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelNegative(b, c, d) + _x[4] + 1859775393, + 7, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelNegative(a, b, c) + _x[9] + 1859775393, + 14, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelNegative(e, a, b) + _x[15] + 1859775393, + 9, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelNegative(d, e, a) + _x[8] + 1859775393, + 13, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelNegative(c, d, e) + _x[1] + 1859775393, + 15, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelNegative(b, c, d) + _x[2] + 1859775393, + 14, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelNegative(a, b, c) + _x[7] + 1859775393, + 8, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelNegative(e, a, b) + _x[0] + 1859775393, + 13, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelNegative(d, e, a) + _x[6] + 1859775393, + 6, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelNegative(c, d, e) + _x[13] + 1859775393, + 5, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelNegative(b, c, d) + _x[11] + 1859775393, + 12, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelNegative(a, b, c) + _x[5] + 1859775393, + 7, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelNegative(e, a, b) + _x[12] + 1859775393, + 5, + ) + + c; + a = getRightToLeft(a, 10); + + i = + getRightToLeft( + i + getBitlevelNegative(j, f, g) + _x[15] + 1836072691, + 9, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelNegative(i, j, f) + _x[5] + 1836072691, + 7, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelNegative(h, i, j) + _x[1] + 1836072691, + 15, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelNegative(g, h, i) + _x[3] + 1836072691, + 11, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelNegative(f, g, h) + _x[7] + 1836072691, + 8, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelNegative(j, f, g) + _x[14] + 1836072691, + 6, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelNegative(i, j, f) + _x[6] + 1836072691, + 6, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelNegative(h, i, j) + _x[9] + 1836072691, + 14, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelNegative(g, h, i) + _x[11] + 1836072691, + 12, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelNegative(f, g, h) + _x[8] + 1836072691, + 13, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelNegative(j, f, g) + _x[12] + 1836072691, + 5, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelNegative(i, j, f) + _x[2] + 1836072691, + 14, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelNegative(h, i, j) + _x[10] + 1836072691, + 13, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelNegative(g, h, i) + _x[0] + 1836072691, + 13, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelNegative(f, g, h) + _x[4] + 1836072691, + 7, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelNegative(j, f, g) + _x[13] + 1836072691, + 5, + ) + + h; + f = getRightToLeft(f, 10); + + c = + getRightToLeft( + c + getBitlevelDemultiplexer(d, e, a) + _x[1] - 1894007588, + 11, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelDemultiplexer(c, d, e) + _x[9] - 1894007588, + 12, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelDemultiplexer(b, c, d) + _x[11] - 1894007588, + 14, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelDemultiplexer(a, b, c) + _x[10] - 1894007588, + 15, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelDemultiplexer(e, a, b) + _x[0] - 1894007588, + 14, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelDemultiplexer(d, e, a) + _x[8] - 1894007588, + 15, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelDemultiplexer(c, d, e) + _x[12] - 1894007588, + 9, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelDemultiplexer(b, c, d) + _x[4] - 1894007588, + 8, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelDemultiplexer(a, b, c) + _x[13] - 1894007588, + 9, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelDemultiplexer(e, a, b) + _x[3] - 1894007588, + 14, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelDemultiplexer(d, e, a) + _x[7] - 1894007588, + 5, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelDemultiplexer(c, d, e) + _x[15] - 1894007588, + 6, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelDemultiplexer(b, c, d) + _x[14] - 1894007588, + 8, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelDemultiplexer(a, b, c) + _x[5] - 1894007588, + 6, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelDemultiplexer(e, a, b) + _x[6] - 1894007588, + 5, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelDemultiplexer(d, e, a) + _x[2] - 1894007588, + 12, + ) + + b; + e = getRightToLeft(e, 10); + + h = + getRightToLeft( + h + getBitlevelMultiplexer(i, j, f) + _x[8] + 2053994217, + 15, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelMultiplexer(h, i, j) + _x[6] + 2053994217, + 5, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelMultiplexer(g, h, i) + _x[4] + 2053994217, + 8, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelMultiplexer(f, g, h) + _x[1] + 2053994217, + 11, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelMultiplexer(j, f, g) + _x[3] + 2053994217, + 14, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelMultiplexer(i, j, f) + _x[11] + 2053994217, + 14, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelMultiplexer(h, i, j) + _x[15] + 2053994217, + 6, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelMultiplexer(g, h, i) + _x[0] + 2053994217, + 14, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelMultiplexer(f, g, h) + _x[5] + 2053994217, + 6, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelMultiplexer(j, f, g) + _x[12] + 2053994217, + 9, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelMultiplexer(i, j, f) + _x[2] + 2053994217, + 12, + ) + + g; + j = getRightToLeft(j, 10); + g = + getRightToLeft( + g + getBitlevelMultiplexer(h, i, j) + _x[13] + 2053994217, + 9, + ) + + f; + i = getRightToLeft(i, 10); + f = + getRightToLeft( + f + getBitlevelMultiplexer(g, h, i) + _x[9] + 2053994217, + 12, + ) + + j; + h = getRightToLeft(h, 10); + j = + getRightToLeft( + j + getBitlevelMultiplexer(f, g, h) + _x[7] + 2053994217, + 5, + ) + + i; + g = getRightToLeft(g, 10); + i = + getRightToLeft( + i + getBitlevelMultiplexer(j, f, g) + _x[10] + 2053994217, + 15, + ) + + h; + f = getRightToLeft(f, 10); + h = + getRightToLeft( + h + getBitlevelMultiplexer(i, j, f) + _x[14] + 2053994217, + 8, + ) + + g; + j = getRightToLeft(j, 10); + + b = + getRightToLeft( + b + getBitlevelReverseNegative(c, d, e) + _x[4] - 1454113458, + 9, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelReverseNegative(b, c, d) + _x[0] - 1454113458, + 15, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelReverseNegative(a, b, c) + _x[5] - 1454113458, + 5, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelReverseNegative(e, a, b) + _x[9] - 1454113458, + 11, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelReverseNegative(d, e, a) + _x[7] - 1454113458, + 6, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelReverseNegative(c, d, e) + _x[12] - 1454113458, + 8, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelReverseNegative(b, c, d) + _x[2] - 1454113458, + 13, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelReverseNegative(a, b, c) + _x[10] - 1454113458, + 12, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelReverseNegative(e, a, b) + _x[14] - 1454113458, + 5, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelReverseNegative(d, e, a) + _x[1] - 1454113458, + 12, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelReverseNegative(c, d, e) + _x[3] - 1454113458, + 13, + ) + + a; + d = getRightToLeft(d, 10); + a = + getRightToLeft( + a + getBitlevelReverseNegative(b, c, d) + _x[8] - 1454113458, + 14, + ) + + e; + c = getRightToLeft(c, 10); + e = + getRightToLeft( + e + getBitlevelReverseNegative(a, b, c) + _x[11] - 1454113458, + 11, + ) + + d; + b = getRightToLeft(b, 10); + d = + getRightToLeft( + d + getBitlevelReverseNegative(e, a, b) + _x[6] - 1454113458, + 8, + ) + + c; + a = getRightToLeft(a, 10); + c = + getRightToLeft( + c + getBitlevelReverseNegative(d, e, a) + _x[15] - 1454113458, + 5, + ) + + b; + e = getRightToLeft(e, 10); + b = + getRightToLeft( + b + getBitlevelReverseNegative(c, d, e) + _x[13] - 1454113458, + 6, + ) + + a; + d = getRightToLeft(d, 10); + + g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[12], 8) + f; + i = getRightToLeft(i, 10); + f = getRightToLeft(f + getBitLevelEXOR(g, h, i) + _x[15], 5) + j; + h = getRightToLeft(h, 10); + j = getRightToLeft(j + getBitLevelEXOR(f, g, h) + _x[10], 12) + i; + g = getRightToLeft(g, 10); + i = getRightToLeft(i + getBitLevelEXOR(j, f, g) + _x[4], 9) + h; + f = getRightToLeft(f, 10); + h = getRightToLeft(h + getBitLevelEXOR(i, j, f) + _x[1], 12) + g; + j = getRightToLeft(j, 10); + g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[5], 5) + f; + i = getRightToLeft(i, 10); + f = getRightToLeft(f + getBitLevelEXOR(g, h, i) + _x[8], 14) + j; + h = getRightToLeft(h, 10); + j = getRightToLeft(j + getBitLevelEXOR(f, g, h) + _x[7], 6) + i; + g = getRightToLeft(g, 10); + i = getRightToLeft(i + getBitLevelEXOR(j, f, g) + _x[6], 8) + h; + f = getRightToLeft(f, 10); + h = getRightToLeft(h + getBitLevelEXOR(i, j, f) + _x[2], 13) + g; + j = getRightToLeft(j, 10); + g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[13], 6) + f; + i = getRightToLeft(i, 10); + f = getRightToLeft(f + getBitLevelEXOR(g, h, i) + _x[14], 5) + j; + h = getRightToLeft(h, 10); + j = getRightToLeft(j + getBitLevelEXOR(f, g, h) + _x[0], 15) + i; + g = getRightToLeft(g, 10); + i = getRightToLeft(i + getBitLevelEXOR(j, f, g) + _x[3], 13) + h; + f = getRightToLeft(f, 10); + h = getRightToLeft(h + getBitLevelEXOR(i, j, f) + _x[9], 11) + g; + j = getRightToLeft(j, 10); + g = getRightToLeft(g + getBitLevelEXOR(h, i, j) + _x[11], 11) + f; + i = getRightToLeft(i, 10); + + i += c + _h1; + _h1 = _h2 + d + j; + _h2 = _h3 + e + f; + _h3 = _h4 + a + g; + _h4 = _h0 + b + h; + _h0 = i; + + _xOffset = 0; + _x.fillRange(0, 16, 0); + } + + /// Internal method + void unpackWord(int word, List output, int offset) { + output[offset] = word.toUnsigned(8); + output[offset + 1] = (word.toUnsigned(32) >> 8).toUnsigned(8); + output[offset + 2] = (word.toUnsigned(32) >> 16).toUnsigned(8); + output[offset + 3] = (word.toUnsigned(32) >> 24).toUnsigned(8); + } + + /// Internal method + int getRightToLeft(int x, int n) { + return (x << n) | (x.toUnsigned(32) >> (32 - n)); + } + + /// Internal method + int getBitLevelEXOR(int x, int y, int z) { + return x ^ y ^ z; + } + + /// Internal method + int getBitlevelMultiplexer(int x, int y, int z) { + return (x & y) | (~x & z); + } + + /// Internal method + int getBitlevelNegative(int x, int y, int z) { + return (x | ~y) ^ z; + } + + /// Internal method + int getBitlevelDemultiplexer(int x, int y, int z) { + return (x & z) | (y & ~z); + } + + /// Internal method + int getBitlevelReverseNegative(int x, int y, int z) { + return x ^ (y | ~z); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/pkcs1_encoding.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/pkcs1_encoding.dart index 6820302ab..8040794da 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/pkcs1_encoding.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/pkcs1_encoding.dart @@ -1,110 +1,110 @@ -import 'dart:math'; - -import 'cipher_block_chaining_mode.dart'; -import 'ipadding.dart'; - -/// internal class -class Pkcs1Encoding implements ICipherBlock { - /// internal constructor - Pkcs1Encoding(ICipherBlock? cipher) { - _cipher = cipher; - } - //Fields - ICipherBlock? _cipher; - late bool _isEncryption; - bool? _isPrivateKey; - late Random _random; - //Properties - @override - String get algorithmName => '${_cipher!.algorithmName!}/PKCS1Padding'; - @override - int? get inputBlock => - _isEncryption ? _cipher!.inputBlock! - 10 : _cipher!.inputBlock; - @override - int? get outputBlock => - _isEncryption ? _cipher!.outputBlock : _cipher!.outputBlock! - 10; - //Implmentation - @override - void initialize(bool forEncryption, ICipherParameter? parameters) { - CipherParameter? kParam; - _random = Random.secure(); - kParam = parameters as CipherParameter?; - _cipher!.initialize(forEncryption, parameters); - _isPrivateKey = kParam!.isPrivate; - _isEncryption = forEncryption; - } - - @override - List? processBlock(List input, int inOff, int length) { - return _isEncryption - ? encodeBlock(input, inOff, length) - : decodeBlock(input, inOff, length); - } - - /// internal method - List? encodeBlock(List input, int inOff, int inLen) { - if (inLen > inputBlock!) { - throw ArgumentError.value(inLen, 'inLen', 'Input data too large'); - } - List block = List.generate(_cipher!.inputBlock!, (int i) => 0); - if (_isPrivateKey!) { - block[0] = 0x01; - for (int i = 1; i != block.length - inLen - 1; i++) { - block[i] = 0xFF.toUnsigned(8); - } - } else { - block = List.generate( - _cipher!.inputBlock!, - (int i) => _random.nextInt(256), - ); - block[0] = 0x02; - for (int i = 1; i != block.length - inLen - 1; i++) { - while (block[i] == 0) { - block[i] = _random.nextInt(256); - } - } - } - block[block.length - inLen - 1] = 0x00; - List.copyRange(block, block.length - inLen, input, inOff, inOff + inLen); - return _cipher!.processBlock(block, 0, block.length); - } - - /// internal method - List decodeBlock(List input, int inOff, int inLen) { - final List block = _cipher!.processBlock(input, inOff, inLen)!; - if (block.length < outputBlock!) { - throw ArgumentError.value( - inLen, - 'inLen', - 'Invalid block. Block truncated', - ); - } - final int type = block[0]; - if (type != 1 && type != 2) { - throw ArgumentError.value(type, 'type', 'Invalid block type'); - } - if (block.length != _cipher!.outputBlock) { - throw ArgumentError.value(type, 'type', 'Invalid size'); - } - int start; - for (start = 1; start != block.length; start++) { - final int pad = block[start]; - if (pad == 0) { - break; - } - if (type == 1 && pad != 0xff.toUnsigned(8)) { - throw ArgumentError.value(type, 'type', 'Invalid block padding'); - } - } - start++; - if (start > block.length || start < 10) { - throw ArgumentError.value(start, 'start', 'no data in block'); - } - final List result = List.generate( - block.length - start, - (int i) => 0, - ); - List.copyRange(result, 0, block, start, start + result.length); - return result; - } -} +import 'dart:math'; + +import 'cipher_block_chaining_mode.dart'; +import 'ipadding.dart'; + +/// internal class +class Pkcs1Encoding implements ICipherBlock { + /// internal constructor + Pkcs1Encoding(ICipherBlock? cipher) { + _cipher = cipher; + } + //Fields + ICipherBlock? _cipher; + late bool _isEncryption; + bool? _isPrivateKey; + late Random _random; + //Properties + @override + String get algorithmName => '${_cipher!.algorithmName!}/PKCS1Padding'; + @override + int? get inputBlock => + _isEncryption ? _cipher!.inputBlock! - 10 : _cipher!.inputBlock; + @override + int? get outputBlock => + _isEncryption ? _cipher!.outputBlock : _cipher!.outputBlock! - 10; + //Implmentation + @override + void initialize(bool forEncryption, ICipherParameter? parameters) { + CipherParameter? kParam; + _random = Random.secure(); + kParam = parameters as CipherParameter?; + _cipher!.initialize(forEncryption, parameters); + _isPrivateKey = kParam!.isPrivate; + _isEncryption = forEncryption; + } + + @override + List? processBlock(List input, int inOff, int length) { + return _isEncryption + ? encodeBlock(input, inOff, length) + : decodeBlock(input, inOff, length); + } + + /// internal method + List? encodeBlock(List input, int inOff, int inLen) { + if (inLen > inputBlock!) { + throw ArgumentError.value(inLen, 'inLen', 'Input data too large'); + } + List block = List.generate(_cipher!.inputBlock!, (int i) => 0); + if (_isPrivateKey!) { + block[0] = 0x01; + for (int i = 1; i != block.length - inLen - 1; i++) { + block[i] = 0xFF.toUnsigned(8); + } + } else { + block = List.generate( + _cipher!.inputBlock!, + (int i) => _random.nextInt(256), + ); + block[0] = 0x02; + for (int i = 1; i != block.length - inLen - 1; i++) { + while (block[i] == 0) { + block[i] = _random.nextInt(256); + } + } + } + block[block.length - inLen - 1] = 0x00; + List.copyRange(block, block.length - inLen, input, inOff, inOff + inLen); + return _cipher!.processBlock(block, 0, block.length); + } + + /// internal method + List decodeBlock(List input, int inOff, int inLen) { + final List block = _cipher!.processBlock(input, inOff, inLen)!; + if (block.length < outputBlock!) { + throw ArgumentError.value( + inLen, + 'inLen', + 'Invalid block. Block truncated', + ); + } + final int type = block[0]; + if (type != 1 && type != 2) { + throw ArgumentError.value(type, 'type', 'Invalid block type'); + } + if (block.length != _cipher!.outputBlock) { + throw ArgumentError.value(type, 'type', 'Invalid size'); + } + int start; + for (start = 1; start != block.length; start++) { + final int pad = block[start]; + if (pad == 0) { + break; + } + if (type == 1 && pad != 0xff.toUnsigned(8)) { + throw ArgumentError.value(type, 'type', 'Invalid block padding'); + } + } + start++; + if (start > block.length || start < 10) { + throw ArgumentError.value(start, 'start', 'no data in block'); + } + final List result = List.generate( + block.length - start, + (int i) => 0, + ); + List.copyRange(result, 0, block, start, start + result.length); + return result; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/rsa_algorithm.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/rsa_algorithm.dart index 9298470b6..2bd198c7b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/rsa_algorithm.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/rsa_algorithm.dart @@ -1,173 +1,173 @@ -import 'dart:math'; - -import '../asn1/asn1.dart'; -import 'cipher_block_chaining_mode.dart'; -import 'ipadding.dart'; -import 'signature_utilities.dart'; - -/// internal class -class RsaAlgorithm implements ICipherBlock { - /// internal constructor - RsaAlgorithm() { - _rsaCoreEngine = _RsaCoreAlgorithm(); - } - - //Fields - late _RsaCoreAlgorithm _rsaCoreEngine; - RsaKeyParam? _key; - Random? _random; - - //Properties - @override - String get algorithmName => Asn1.rsa; - @override - int get inputBlock => _rsaCoreEngine.inputBlockSize; - @override - int get outputBlock => _rsaCoreEngine.outputBlockSize; - //Implementation - @override - void initialize(bool isEncryption, ICipherParameter? parameter) { - _rsaCoreEngine.initialize(isEncryption, parameter); - _key = parameter as RsaKeyParam?; - _random = Random.secure(); - } - - //Implementation - @override - List processBlock(List bytes, int offset, int length) { - ArgumentError.checkNotNull(_key); - final BigInt input = _rsaCoreEngine.convertInput(bytes, offset, length); - BigInt result; - if (_key is RsaPrivateKeyParam) { - final BigInt? e = (_key! as RsaPrivateKeyParam).publicExponent; - if (e != null) { - final BigInt m = _key!.modulus!; - final BigInt r = createRandomInRange( - BigInt.one, - m - BigInt.one, - _random, - ); - final BigInt blindedInput = getMod(r.modPow(e, m) * input, m); - final BigInt blindedResult = _rsaCoreEngine.processBlock(blindedInput); - final BigInt reverse = r.modInverse(m); - result = getMod(blindedResult * reverse, m); - } else { - result = _rsaCoreEngine.processBlock(input); - } - } else { - result = _rsaCoreEngine.processBlock(input); - } - return _rsaCoreEngine.convertOutput(result); - } - - /// internal method - BigInt createRandomInRange(BigInt min, BigInt max, Random? random) { - final int cmp = min.compareTo(max); - if (cmp >= 0) { - if (cmp > 0) { - throw ArgumentError.value('Invalid range'); - } - return min; - } - if (min.bitLength > max.bitLength / 2) { - return createRandomInRange(BigInt.zero, max - min, random) + min; - } - for (int i = 0; i < 1000; ++i) { - final BigInt x = bigIntFromRamdom(max.bitLength, random); - if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) { - return x; - } - } - return bigIntFromRamdom((max - min).bitLength - 1, random) + min; - } -} - -class _RsaCoreAlgorithm { - _RsaCoreAlgorithm(); - - //Fields - late RsaKeyParam _key; - late bool _isEncryption; - late int _bitSize; - - //Properties - int get inputBlockSize { - if (_isEncryption) { - return (_bitSize - 1) ~/ 8; - } - return (_bitSize + 7) ~/ 8; - } - - int get outputBlockSize { - if (_isEncryption) { - return (_bitSize + 7) ~/ 8; - } - return (_bitSize - 1) ~/ 8; - } - - //Implementation - void initialize(bool isEncryption, ICipherParameter? parameters) { - if (parameters is! RsaKeyParam) { - throw ArgumentError.value(parameters, 'parameters', 'Invalid RSA key'); - } - _key = parameters; - _isEncryption = isEncryption; - _bitSize = _key.modulus!.bitLength; - } - - BigInt convertInput(List bytes, int offset, int length) { - final int maxLength = (_bitSize + 7) ~/ 8; - if (length > maxLength) { - throw ArgumentError.value(length, 'length', 'Invalid length in inputs'); - } - final BigInt input = bigIntFromBytes( - bytes.sublist(offset, offset + length), - 1, - ); - if (input.compareTo(_key.modulus!) >= 0) { - throw ArgumentError.value(length, 'length', 'Invalid length in inputs'); - } - return input; - } - - List convertOutput(BigInt result) { - List output = bigIntToBytes(result, false); - if (_isEncryption) { - final int outSize = outputBlockSize; - if (output.length < outSize) { - final List bytes = List.generate(outSize, (int i) => 0); - int j = 0; - for ( - int i = bytes.length - output.length; - j < output.length && i < bytes.length; - i++ - ) { - bytes[i] = output[j]; - j += 1; - } - output = bytes; - } - } - return output; - } - - BigInt processBlock(BigInt input) { - if (_key is RsaPrivateKeyParam) { - final RsaPrivateKeyParam privateKey = _key as RsaPrivateKeyParam; - final BigInt p = privateKey.p!; - final BigInt q = privateKey.q!; - final BigInt dP = privateKey.dP!; - final BigInt dQ = privateKey.dQ!; - final BigInt qInv = privateKey.inverse!; - final BigInt mP = input.remainder(p).modPow(dP, p); - final BigInt mQ = input.remainder(q).modPow(dQ, q); - BigInt h = mP - mQ; - h = h * qInv; - h = getMod(h, p); - BigInt m = h * q; - m = m + mQ; - return m; - } - return input.modPow(_key.exponent!, _key.modulus!); - } -} +import 'dart:math'; + +import '../asn1/asn1.dart'; +import 'cipher_block_chaining_mode.dart'; +import 'ipadding.dart'; +import 'signature_utilities.dart'; + +/// internal class +class RsaAlgorithm implements ICipherBlock { + /// internal constructor + RsaAlgorithm() { + _rsaCoreEngine = _RsaCoreAlgorithm(); + } + + //Fields + late _RsaCoreAlgorithm _rsaCoreEngine; + RsaKeyParam? _key; + Random? _random; + + //Properties + @override + String get algorithmName => Asn1.rsa; + @override + int get inputBlock => _rsaCoreEngine.inputBlockSize; + @override + int get outputBlock => _rsaCoreEngine.outputBlockSize; + //Implementation + @override + void initialize(bool isEncryption, ICipherParameter? parameter) { + _rsaCoreEngine.initialize(isEncryption, parameter); + _key = parameter as RsaKeyParam?; + _random = Random.secure(); + } + + //Implementation + @override + List processBlock(List bytes, int offset, int length) { + ArgumentError.checkNotNull(_key); + final BigInt input = _rsaCoreEngine.convertInput(bytes, offset, length); + BigInt result; + if (_key is RsaPrivateKeyParam) { + final BigInt? e = (_key! as RsaPrivateKeyParam).publicExponent; + if (e != null) { + final BigInt m = _key!.modulus!; + final BigInt r = createRandomInRange( + BigInt.one, + m - BigInt.one, + _random, + ); + final BigInt blindedInput = getMod(r.modPow(e, m) * input, m); + final BigInt blindedResult = _rsaCoreEngine.processBlock(blindedInput); + final BigInt reverse = r.modInverse(m); + result = getMod(blindedResult * reverse, m); + } else { + result = _rsaCoreEngine.processBlock(input); + } + } else { + result = _rsaCoreEngine.processBlock(input); + } + return _rsaCoreEngine.convertOutput(result); + } + + /// internal method + BigInt createRandomInRange(BigInt min, BigInt max, Random? random) { + final int cmp = min.compareTo(max); + if (cmp >= 0) { + if (cmp > 0) { + throw ArgumentError.value('Invalid range'); + } + return min; + } + if (min.bitLength > max.bitLength / 2) { + return createRandomInRange(BigInt.zero, max - min, random) + min; + } + for (int i = 0; i < 1000; ++i) { + final BigInt x = bigIntFromRamdom(max.bitLength, random); + if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) { + return x; + } + } + return bigIntFromRamdom((max - min).bitLength - 1, random) + min; + } +} + +class _RsaCoreAlgorithm { + _RsaCoreAlgorithm(); + + //Fields + late RsaKeyParam _key; + late bool _isEncryption; + late int _bitSize; + + //Properties + int get inputBlockSize { + if (_isEncryption) { + return (_bitSize - 1) ~/ 8; + } + return (_bitSize + 7) ~/ 8; + } + + int get outputBlockSize { + if (_isEncryption) { + return (_bitSize + 7) ~/ 8; + } + return (_bitSize - 1) ~/ 8; + } + + //Implementation + void initialize(bool isEncryption, ICipherParameter? parameters) { + if (parameters is! RsaKeyParam) { + throw ArgumentError.value(parameters, 'parameters', 'Invalid RSA key'); + } + _key = parameters; + _isEncryption = isEncryption; + _bitSize = _key.modulus!.bitLength; + } + + BigInt convertInput(List bytes, int offset, int length) { + final int maxLength = (_bitSize + 7) ~/ 8; + if (length > maxLength) { + throw ArgumentError.value(length, 'length', 'Invalid length in inputs'); + } + final BigInt input = bigIntFromBytes( + bytes.sublist(offset, offset + length), + 1, + ); + if (input.compareTo(_key.modulus!) >= 0) { + throw ArgumentError.value(length, 'length', 'Invalid length in inputs'); + } + return input; + } + + List convertOutput(BigInt result) { + List output = bigIntToBytes(result, false); + if (_isEncryption) { + final int outSize = outputBlockSize; + if (output.length < outSize) { + final List bytes = List.generate(outSize, (int i) => 0); + int j = 0; + for ( + int i = bytes.length - output.length; + j < output.length && i < bytes.length; + i++ + ) { + bytes[i] = output[j]; + j += 1; + } + output = bytes; + } + } + return output; + } + + BigInt processBlock(BigInt input) { + if (_key is RsaPrivateKeyParam) { + final RsaPrivateKeyParam privateKey = _key as RsaPrivateKeyParam; + final BigInt p = privateKey.p!; + final BigInt q = privateKey.q!; + final BigInt dP = privateKey.dP!; + final BigInt dQ = privateKey.dQ!; + final BigInt qInv = privateKey.inverse!; + final BigInt mP = input.remainder(p).modPow(dP, p); + final BigInt mQ = input.remainder(q).modPow(dQ, q); + BigInt h = mP - mQ; + h = h * qInv; + h = getMod(h, p); + BigInt m = h * q; + m = m + mQ; + return m; + } + return input.modPow(_key.exponent!, _key.modulus!); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/signature_utilities.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/signature_utilities.dart index 44df4f9e8..64ba32854 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/signature_utilities.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/cryptography/signature_utilities.dart @@ -1,109 +1,109 @@ -import 'dart:math'; - -/// internal method -BigInt bigIntFromBytes(List? data, [int? sign]) { - BigInt result; - if (sign == null) { - final bool isNegative = data!.isNotEmpty && data[0] & 0x80 == 0x80; - if (data.length == 1) { - result = BigInt.from(data[0]); - } else { - result = BigInt.zero; - for (int i = 0; i < data.length; i++) { - final int item = data[data.length - i - 1]; - result |= BigInt.from(item) << (8 * i); - } - } - return result != BigInt.zero - ? isNegative - ? result.toSigned(result.bitLength) - : result - : BigInt.zero; - } else { - if (sign == 0) { - return BigInt.zero; - } - if (data!.length == 1) { - result = BigInt.from(data[0]); - } else { - result = BigInt.from(0); - for (int i = 0; i < data.length; i++) { - final int item = data[data.length - i - 1]; - result |= BigInt.from(item) << (8 * i); - } - } - if (result != BigInt.zero) { - if (sign < 0) { - result = result.toSigned(result.bitLength); - } else { - result = result.toUnsigned(result.bitLength); - } - } - } - return result; -} - -/// internal method -List bigIntToBytes(BigInt number, [bool isSigned = true]) { - List result; - final BigInt mask = BigInt.from(0xff); - final BigInt flag = BigInt.from(0x80); - if (isSigned) { - if (number == BigInt.zero) { - return [0]; - } - int paddingBytes; - int size; - if (number > BigInt.zero) { - size = (number.bitLength + 7) >> 3; - paddingBytes = ((number >> (size - 1) * 8) & flag) == flag ? 1 : 0; - } else { - paddingBytes = 0; - size = (number.bitLength + 8) >> 3; - } - final int length = size + paddingBytes; - result = List.generate(length, (int i) => 0); - for (int i = 0; i < size; i++) { - result[length - i - 1] = (number & mask).toSigned(32).toInt(); - number = number >> 8; - } - } else { - if (number == BigInt.zero) { - return [0]; - } - final int length = number.bitLength + (number.isNegative ? 8 : 7) >> 3; - result = List.generate(length, (int i) => 0); - for (int i = 0; i < length; i++) { - result[length - i - 1] = (number & mask).toSigned(32).toInt(); - number = number >> 8; - } - } - return result; -} - -/// internal method -BigInt getMod(BigInt n, BigInt m) { - final BigInt biggie = n.remainder(m); - return biggie.sign >= 0 ? biggie : biggie + m; -} - -/// internal method -BigInt bigIntFromRamdom(int value, Random? random) { - BigInt result; - if (value < 0) { - throw ArgumentError.value(value, 'value', 'Invalid entry'); - } - if (value == 0) { - result = BigInt.from(0); - } else { - final int nBytes = (value + 8 - 1) ~/ 8; - final List b = List.generate( - nBytes, - (int i) => random!.nextInt(256), - ); - final int xBits = 8 * nBytes - value; - b[0] &= (255 >> xBits).toUnsigned(8); - result = bigIntFromBytes(b); - } - return result; -} +import 'dart:math'; + +/// internal method +BigInt bigIntFromBytes(List? data, [int? sign]) { + BigInt result; + if (sign == null) { + final bool isNegative = data!.isNotEmpty && data[0] & 0x80 == 0x80; + if (data.length == 1) { + result = BigInt.from(data[0]); + } else { + result = BigInt.zero; + for (int i = 0; i < data.length; i++) { + final int item = data[data.length - i - 1]; + result |= BigInt.from(item) << (8 * i); + } + } + return result != BigInt.zero + ? isNegative + ? result.toSigned(result.bitLength) + : result + : BigInt.zero; + } else { + if (sign == 0) { + return BigInt.zero; + } + if (data!.length == 1) { + result = BigInt.from(data[0]); + } else { + result = BigInt.from(0); + for (int i = 0; i < data.length; i++) { + final int item = data[data.length - i - 1]; + result |= BigInt.from(item) << (8 * i); + } + } + if (result != BigInt.zero) { + if (sign < 0) { + result = result.toSigned(result.bitLength); + } else { + result = result.toUnsigned(result.bitLength); + } + } + } + return result; +} + +/// internal method +List bigIntToBytes(BigInt number, [bool isSigned = true]) { + List result; + final BigInt mask = BigInt.from(0xff); + final BigInt flag = BigInt.from(0x80); + if (isSigned) { + if (number == BigInt.zero) { + return [0]; + } + int paddingBytes; + int size; + if (number > BigInt.zero) { + size = (number.bitLength + 7) >> 3; + paddingBytes = ((number >> (size - 1) * 8) & flag) == flag ? 1 : 0; + } else { + paddingBytes = 0; + size = (number.bitLength + 8) >> 3; + } + final int length = size + paddingBytes; + result = List.generate(length, (int i) => 0); + for (int i = 0; i < size; i++) { + result[length - i - 1] = (number & mask).toSigned(32).toInt(); + number = number >> 8; + } + } else { + if (number == BigInt.zero) { + return [0]; + } + final int length = number.bitLength + (number.isNegative ? 8 : 7) >> 3; + result = List.generate(length, (int i) => 0); + for (int i = 0; i < length; i++) { + result[length - i - 1] = (number & mask).toSigned(32).toInt(); + number = number >> 8; + } + } + return result; +} + +/// internal method +BigInt getMod(BigInt n, BigInt m) { + final BigInt biggie = n.remainder(m); + return biggie.sign >= 0 ? biggie : biggie + m; +} + +/// internal method +BigInt bigIntFromRamdom(int value, Random? random) { + BigInt result; + if (value < 0) { + throw ArgumentError.value(value, 'value', 'Invalid entry'); + } + if (value == 0) { + result = BigInt.from(0); + } else { + final int nBytes = (value + 8 - 1) ~/ 8; + final List b = List.generate( + nBytes, + (int i) => random!.nextInt(256), + ); + final int xBits = 8 * nBytes - value; + b[0] &= (255 >> xBits).toUnsigned(8); + result = bigIntFromBytes(b); + } + return result; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_certificate.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_certificate.dart index b936ecb6b..bdbb9018a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_certificate.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_certificate.dart @@ -1,187 +1,187 @@ -import 'pdf_pkcs_certificate.dart'; -import 'x509/x509_certificates.dart'; - -/// Represents the Certificate object. -class PdfCertificate { - /// Initializes a new instance of the [PdfCertificate] class - PdfCertificate(List certificateBytes, String password) { - _initializeCertificate(certificateBytes, password); - } - - //Fields - late PdfPKCSCertificate _pkcsCertificate; - int _version = 0; - late List _serialNumber; - String _issuerName = ''; - String _subjectName = ''; - DateTime? _validFrom; - DateTime? _validTo; - late Map> _distinguishedNameCollection; - - //Properties - /// Gets the certificate's version number. - int get version => _version; - - /// Gets the serial number of a certificate. - List get serialNumber => _serialNumber; - - /// Gets the certificate issuer's name. - String get issuerName => _issuerName; - - /// Gets the certificate subject's name. - String get subjectName => _subjectName; - - /// Gets the date and time before which the certificate is not valid. - DateTime get validTo => _validTo!; - - /// Gets the date and time after which the certificate is not valid. - DateTime get validFrom => _validFrom!; - - /// Gets the certificate chain in raw bytes. - /// - /// ```dart - /// //Load the certificate from the file - /// final PdfCertificate certificate = - /// PdfCertificate(File('PDF.pfx').readAsBytesSync(), 'password'); - /// //Get the certificate chain - /// List>? certificateChain = certificate.getCertificateChain(); - /// ``` - List>? getCertificateChain() { - List>? certificateChain; - try { - certificateChain = >[]; - _pkcsCertificate.getChainCertificates().forEach((X509Certificates entry) { - final List certificateBytes = - entry.certificate!.c!.getDerEncoded()!; - certificateChain!.add(certificateBytes); - }); - } catch (e) { - return null; - } - return certificateChain; - } - - //Implementation - void _initializeCertificate(List certificateBytes, String password) { - _distinguishedNameCollection = >{}; - _pkcsCertificate = PdfPKCSCertificate(certificateBytes, password); - String certificateAlias = ''; - final List keys = _pkcsCertificate.getContentTable().keys.toList(); - bool isContinue = true; - keys.toList().forEach((String key) { - if (isContinue && - _pkcsCertificate.isKey(key) && - _pkcsCertificate.getKey(key)!.key!.isPrivate!) { - certificateAlias = key; - isContinue = false; - } - }); - final X509Certificates entry = - _pkcsCertificate.getCertificate(certificateAlias)!; - _loadDetails(entry.certificate!); - } - - void _loadDetails(X509Certificate certificate) { - _issuerName = _getDistinguishedAttributes( - certificate.c!.issuer.toString(), - 'CN', - ); - _subjectName = _getDistinguishedAttributes( - certificate.c!.subject.toString(), - 'CN', - ); - _validFrom = certificate.c!.startDate!.toDateTime(); - _validTo = certificate.c!.endDate!.toDateTime(); - _version = certificate.c!.version; - final List serialNumber = - [] - // ignore: prefer_spread_collections - ..addAll(certificate.c!.serialNumber!.intValue!.reversed.toList()); - _serialNumber = serialNumber; - } - - String _getDistinguishedAttributes(String name, String key) { - String x509Name = ''; - Map attributesDictionary = {}; - if (key.contains('=')) { - key = key.replaceAll('=', ''); - } - if (!_distinguishedNameCollection.containsKey(name)) { - String result = ''; - bool isInitialSeparator = true; - for (int i = 0; i < name.length; i++) { - if (isInitialSeparator) { - if (name[i] == ',' || name[i] == ';' || name[i] == '+') { - _addStringToDictionary(result, attributesDictionary); - result = ''; - } else { - result += name[i]; - if (name[i] == r'\') { - result += name[++i]; - } else if (name[i] == '"') { - isInitialSeparator = false; - } - } - } else { - result += name[i]; - if (name[i] == r'\') { - result += name[++i]; - } else if (name[i] == '"') { - isInitialSeparator = true; - } - } - } - _addStringToDictionary(result, attributesDictionary); - result = ''; - _distinguishedNameCollection[name] = attributesDictionary; - if (attributesDictionary.containsKey(key)) { - x509Name = attributesDictionary[key]!; - } - } else { - attributesDictionary = _distinguishedNameCollection[name]!; - if (attributesDictionary.containsKey(key)) { - x509Name = attributesDictionary[key]!; - } - } - return x509Name; - } - - void _addStringToDictionary(String name, Map? dictionary) { - int index = name.indexOf('='); - if (index > 0) { - final List keyNameArray = List.generate( - 2, - (int i) => null, - ); - keyNameArray[0] = name.substring(0, index).trimLeft().trimRight(); - index++; - keyNameArray[1] = - name.substring(index, name.length).trimLeft().trimRight(); - if (keyNameArray[0] != null && - keyNameArray[0] != '' && - keyNameArray[1] != null && - keyNameArray[1] != '') { - if (!dictionary!.containsKey(keyNameArray[0])) { - dictionary[keyNameArray[0]] = keyNameArray[1]; - } - } - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfCertificate] helper -class PdfCertificateHelper { - /// internal method - static PdfPKCSCertificate getPkcsCertificate(PdfCertificate certificate) { - return certificate._pkcsCertificate; - } - - /// internal method - static void setPkcsCertificate( - PdfCertificate certificate, - PdfPKCSCertificate pkcsCertificate, - ) { - certificate._pkcsCertificate = pkcsCertificate; - } -} +import 'pdf_pkcs_certificate.dart'; +import 'x509/x509_certificates.dart'; + +/// Represents the Certificate object. +class PdfCertificate { + /// Initializes a new instance of the [PdfCertificate] class + PdfCertificate(List certificateBytes, String password) { + _initializeCertificate(certificateBytes, password); + } + + //Fields + late PdfPKCSCertificate _pkcsCertificate; + int _version = 0; + late List _serialNumber; + String _issuerName = ''; + String _subjectName = ''; + DateTime? _validFrom; + DateTime? _validTo; + late Map> _distinguishedNameCollection; + + //Properties + /// Gets the certificate's version number. + int get version => _version; + + /// Gets the serial number of a certificate. + List get serialNumber => _serialNumber; + + /// Gets the certificate issuer's name. + String get issuerName => _issuerName; + + /// Gets the certificate subject's name. + String get subjectName => _subjectName; + + /// Gets the date and time before which the certificate is not valid. + DateTime get validTo => _validTo!; + + /// Gets the date and time after which the certificate is not valid. + DateTime get validFrom => _validFrom!; + + /// Gets the certificate chain in raw bytes. + /// + /// ```dart + /// //Load the certificate from the file + /// final PdfCertificate certificate = + /// PdfCertificate(File('PDF.pfx').readAsBytesSync(), 'password'); + /// //Get the certificate chain + /// List>? certificateChain = certificate.getCertificateChain(); + /// ``` + List>? getCertificateChain() { + List>? certificateChain; + try { + certificateChain = >[]; + _pkcsCertificate.getChainCertificates().forEach((X509Certificates entry) { + final List certificateBytes = + entry.certificate!.c!.getDerEncoded()!; + certificateChain!.add(certificateBytes); + }); + } catch (e) { + return null; + } + return certificateChain; + } + + //Implementation + void _initializeCertificate(List certificateBytes, String password) { + _distinguishedNameCollection = >{}; + _pkcsCertificate = PdfPKCSCertificate(certificateBytes, password); + String certificateAlias = ''; + final List keys = _pkcsCertificate.getContentTable().keys.toList(); + bool isContinue = true; + keys.toList().forEach((String key) { + if (isContinue && + _pkcsCertificate.isKey(key) && + _pkcsCertificate.getKey(key)!.key!.isPrivate!) { + certificateAlias = key; + isContinue = false; + } + }); + final X509Certificates entry = + _pkcsCertificate.getCertificate(certificateAlias)!; + _loadDetails(entry.certificate!); + } + + void _loadDetails(X509Certificate certificate) { + _issuerName = _getDistinguishedAttributes( + certificate.c!.issuer.toString(), + 'CN', + ); + _subjectName = _getDistinguishedAttributes( + certificate.c!.subject.toString(), + 'CN', + ); + _validFrom = certificate.c!.startDate!.toDateTime(); + _validTo = certificate.c!.endDate!.toDateTime(); + _version = certificate.c!.version; + final List serialNumber = + [] + // ignore: prefer_spread_collections + ..addAll(certificate.c!.serialNumber!.intValue!.reversed.toList()); + _serialNumber = serialNumber; + } + + String _getDistinguishedAttributes(String name, String key) { + String x509Name = ''; + Map attributesDictionary = {}; + if (key.contains('=')) { + key = key.replaceAll('=', ''); + } + if (!_distinguishedNameCollection.containsKey(name)) { + String result = ''; + bool isInitialSeparator = true; + for (int i = 0; i < name.length; i++) { + if (isInitialSeparator) { + if (name[i] == ',' || name[i] == ';' || name[i] == '+') { + _addStringToDictionary(result, attributesDictionary); + result = ''; + } else { + result += name[i]; + if (name[i] == r'\') { + result += name[++i]; + } else if (name[i] == '"') { + isInitialSeparator = false; + } + } + } else { + result += name[i]; + if (name[i] == r'\') { + result += name[++i]; + } else if (name[i] == '"') { + isInitialSeparator = true; + } + } + } + _addStringToDictionary(result, attributesDictionary); + result = ''; + _distinguishedNameCollection[name] = attributesDictionary; + if (attributesDictionary.containsKey(key)) { + x509Name = attributesDictionary[key]!; + } + } else { + attributesDictionary = _distinguishedNameCollection[name]!; + if (attributesDictionary.containsKey(key)) { + x509Name = attributesDictionary[key]!; + } + } + return x509Name; + } + + void _addStringToDictionary(String name, Map? dictionary) { + int index = name.indexOf('='); + if (index > 0) { + final List keyNameArray = List.generate( + 2, + (int i) => null, + ); + keyNameArray[0] = name.substring(0, index).trimLeft().trimRight(); + index++; + keyNameArray[1] = + name.substring(index, name.length).trimLeft().trimRight(); + if (keyNameArray[0] != null && + keyNameArray[0] != '' && + keyNameArray[1] != null && + keyNameArray[1] != '') { + if (!dictionary!.containsKey(keyNameArray[0])) { + dictionary[keyNameArray[0]] = keyNameArray[1]; + } + } + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfCertificate] helper +class PdfCertificateHelper { + /// internal method + static PdfPKCSCertificate getPkcsCertificate(PdfCertificate certificate) { + return certificate._pkcsCertificate; + } + + /// internal method + static void setPkcsCertificate( + PdfCertificate certificate, + PdfPKCSCertificate pkcsCertificate, + ) { + certificate._pkcsCertificate = pkcsCertificate; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_external_signer.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_external_signer.dart index e518af6b2..e54d72a15 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_external_signer.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_external_signer.dart @@ -1,32 +1,32 @@ -import '../enum.dart'; - -/// Interface for external signing to a PDF document -class IPdfExternalSigner { - //Fields - // ignore: prefer_final_fields - DigestAlgorithm _hashAlgorithm = DigestAlgorithm.sha256; - - //Properties - /// Get HashAlgorithm. - DigestAlgorithm get hashAlgorithm => _hashAlgorithm; - - //Public methods - /// Asynchronously returns signed message digest. - Future sign(List message) async { - return null; - } - - /// Synchronously returns signed message digest. - SignerResult? signSync(List message) { - return null; - } -} - -/// External signing result -class SignerResult { - /// Initializes a new instance of the [SignerResult] class with signed data. - SignerResult(this.signedData); - - /// Gets and sets the signed Message Digest. - late List signedData; -} +import '../enum.dart'; + +/// Interface for external signing to a PDF document +class IPdfExternalSigner { + //Fields + // ignore: prefer_final_fields + DigestAlgorithm _hashAlgorithm = DigestAlgorithm.sha256; + + //Properties + /// Get HashAlgorithm. + DigestAlgorithm get hashAlgorithm => _hashAlgorithm; + + //Public methods + /// Asynchronously returns signed message digest. + Future sign(List message) async { + return null; + } + + /// Synchronously returns signed message digest. + SignerResult? signSync(List message) { + return null; + } +} + +/// External signing result +class SignerResult { + /// Initializes a new instance of the [SignerResult] class with signed data. + SignerResult(this.signedData); + + /// Gets and sets the signed Message Digest. + late List signedData; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_pkcs_certificate.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_pkcs_certificate.dart index 5a0eb325c..9a2e1ea0a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_pkcs_certificate.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_pkcs_certificate.dart @@ -1,3711 +1,3711 @@ -import 'dart:convert'; -import 'dart:typed_data'; - -import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; - -import '../../io/decode_big_endian.dart'; -import '../../io/stream_reader.dart'; -import '../../primitives/pdf_string.dart'; -import 'asn1/asn1.dart'; -import 'asn1/asn1_stream.dart'; -import 'asn1/ber.dart'; -import 'asn1/der.dart'; -import 'cryptography/buffered_block_padding_base.dart'; -import 'cryptography/cipher_block_chaining_mode.dart'; -import 'cryptography/cipher_utils.dart'; -import 'cryptography/ipadding.dart'; -import 'cryptography/message_digest_utils.dart'; -import 'cryptography/pkcs1_encoding.dart'; -import 'cryptography/rsa_algorithm.dart'; -import 'cryptography/signature_utilities.dart'; -import 'pkcs/password_utility.dart'; -import 'pkcs/pfx_data.dart'; -import 'x509/x509_certificates.dart'; -import 'x509/x509_name.dart'; - -/// internal class -class PdfPKCSCertificate { - /// internal constructor - PdfPKCSCertificate(List certificateBytes, String password) { - _keys = _CertificateTable(); - _certificates = _CertificateTable(); - _localIdentifiers = {}; - _chainCertificates = <_CertificateIdentifier, X509Certificates>{}; - _keyCertificates = {}; - _loadCertificate(certificateBytes, password); - } - - //Fields - late _CertificateTable _keys; - late _CertificateTable _certificates; - late Map _localIdentifiers; - late Map<_CertificateIdentifier, X509Certificates> _chainCertificates; - late Map _keyCertificates; - - //Implementation - void _loadCertificate(List certificateBytes, String password) { - final Asn1Sequence sequence = - Asn1Stream(PdfStreamReader(certificateBytes)).readAsn1()! - as Asn1Sequence; - final _PfxData pfxData = _PfxData(sequence); - final _ContentInformation information = pfxData._contentInformation!; - bool isUnmarkedKey = false; - final bool isInvalidPassword = password.isEmpty; - final List certificateChain = - []; - if (information._contentType!.id == PkcsObjectId.data.id) { - final List? octs = (information._content! as Asn1Octet).getOctets(); - final Asn1Sequence asn1Sequence = - Asn1Stream(PdfStreamReader(octs)).readAsn1()! as Asn1Sequence; - final List<_ContentInformation?> contentInformation = - <_ContentInformation?>[]; - for (int i = 0; i < asn1Sequence.count; i++) { - contentInformation.add( - _ContentInformation.getInformation(asn1Sequence[i]), - ); - } - // ignore: avoid_function_literals_in_foreach_calls - contentInformation.forEach((_ContentInformation? entry) { - final DerObjectID type = entry!._contentType!; - if (type.id == PkcsObjectId.data.id) { - final List? octets = (entry._content! as Asn1Octet).getOctets(); - final Asn1Sequence asn1SubSequence = - Asn1Stream(PdfStreamReader(octets)).readAsn1()! as Asn1Sequence; - for (int index = 0; index < asn1SubSequence.count; index++) { - final dynamic subSequence = asn1SubSequence[index]; - if (subSequence != null && subSequence is Asn1Sequence) { - final Asn1SequenceCollection subSequenceCollection = - Asn1SequenceCollection(subSequence); - if (subSequenceCollection.id!.id == - PkcsObjectId.pkcs8ShroudedKeyBag.id) { - final EncryptedPrivateKey encryptedInformation = - EncryptedPrivateKey.getEncryptedPrivateKeyInformation( - subSequenceCollection.value, - ); - final KeyInformation privateKeyInformation = - createPrivateKeyInfo( - password, - isInvalidPassword, - encryptedInformation, - )!; - RsaPrivateKeyParam? rsaparam; - if (privateKeyInformation._algorithms!.id!.id == - PkcsObjectId.rsaEncryption.id || - privateKeyInformation._algorithms!.id!.id == - X509Objects.idEARsa.id) { - final _RsaKey keyStructure = _RsaKey.fromSequence( - Asn1Sequence.getSequence( - privateKeyInformation._privateKey, - )!, - ); - rsaparam = RsaPrivateKeyParam( - keyStructure._modulus, - keyStructure._publicExponent, - keyStructure._privateExponent, - keyStructure._prime1, - keyStructure._prime2, - keyStructure._exponent1, - keyStructure._exponent2, - keyStructure._coefficient, - ); - } - final CipherParameter? privateKey = rsaparam; - final Map attributes = {}; - final KeyEntry key = KeyEntry(privateKey); - String? localIdentifier; - Asn1Octet? localId; - if (subSequenceCollection.attributes != null) { - final Asn1Set sq = subSequenceCollection.attributes!; - for (int i = 0; i < sq.objects.length; i++) { - final Asn1Encode? entry = sq.objects[i] as Asn1Encode?; - if (entry is Asn1Sequence) { - final DerObjectID? algorithmId = DerObjectID.getID( - entry[0], - ); - final Asn1Set attributeSet = entry[1]! as Asn1Set; - Asn1Encode? attribute; - if (attributeSet.objects.isNotEmpty) { - attribute = attributeSet[0]; - if (attributes.containsKey(algorithmId!.id)) { - if (attributes[algorithmId.id] != attribute) { - throw ArgumentError.value( - attributes, - 'attributes', - 'attempt to add existing attribute with different value', - ); - } - } else { - attributes[algorithmId.id] = attribute; - } - if (algorithmId.id == - PkcsObjectId.pkcs9AtFriendlyName.id) { - localIdentifier = - (attribute! as DerBmpString).getString(); - _keys.setValue(localIdentifier!, key); - } else if (algorithmId.id == - PkcsObjectId.pkcs9AtLocalKeyID.id) { - localId = attribute as Asn1Octet?; - } - } - } - } - } - if (localId != null) { - final String name = PdfString.bytesToHex( - localId.getOctets()!, - ); - if (localIdentifier == null) { - _keys.setValue(name, key); - } else { - _localIdentifiers[localIdentifier] = name; - } - } else { - isUnmarkedKey = true; - _keys.setValue('unmarked', key); - } - } else if (subSequenceCollection.id!.id == - PkcsObjectId.certBag.id) { - certificateChain.add(subSequenceCollection); - } - } - } - } else if (type.id == PkcsObjectId.encryptedData.id) { - final Asn1Sequence sequence1 = entry._content! as Asn1Sequence; - if (sequence1.count != 2) { - throw ArgumentError.value( - entry, - 'sequence', - 'Invalid length of the sequence', - ); - } - final int version = - (sequence1[0]! as DerInteger).value.toSigned(32).toInt(); - if (version != 0) { - throw ArgumentError.value( - version, - 'version', - 'Invalid sequence version', - ); - } - final Asn1Sequence data = sequence1[1]! as Asn1Sequence; - Asn1Octet? content; - if (data.count == 3) { - final DerTag taggedObject = data[2]! as DerTag; - content = Asn1Octet.getOctetString(taggedObject, false); - } - final List? octets = getCryptographicData( - false, - Algorithms.getAlgorithms(data[1])!, - password, - isInvalidPassword, - content!.getOctets(), - ); - final Asn1Sequence seq = - Asn1Stream(PdfStreamReader(octets)).readAsn1()! as Asn1Sequence; - // ignore: avoid_function_literals_in_foreach_calls - seq.objects!.forEach((dynamic subSequence) { - final Asn1SequenceCollection subSequenceCollection = - Asn1SequenceCollection(subSequence); - if (subSequenceCollection.id!.id == PkcsObjectId.certBag.id) { - certificateChain.add(subSequenceCollection); - } else if (subSequenceCollection.id!.id == - PkcsObjectId.pkcs8ShroudedKeyBag.id) { - final EncryptedPrivateKey encryptedPrivateKeyInformation = - EncryptedPrivateKey.getEncryptedPrivateKeyInformation( - subSequenceCollection.value, - ); - final KeyInformation privateInformation = - createPrivateKeyInfo( - password, - isInvalidPassword, - encryptedPrivateKeyInformation, - )!; - RsaPrivateKeyParam? rsaParameter; - if (privateInformation._algorithms!.id!.id == - PkcsObjectId.rsaEncryption.id || - privateInformation._algorithms!.id!.id == - X509Objects.idEARsa.id) { - final _RsaKey keyStructure = _RsaKey.fromSequence( - Asn1Sequence.getSequence(privateInformation._privateKey)!, - ); - rsaParameter = RsaPrivateKeyParam( - keyStructure._modulus, - keyStructure._publicExponent, - keyStructure._privateExponent, - keyStructure._prime1, - keyStructure._prime2, - keyStructure._exponent1, - keyStructure._exponent2, - keyStructure._coefficient, - ); - } - final CipherParameter? privateKey = rsaParameter; - final Map attributes = {}; - final KeyEntry keyEntry = KeyEntry(privateKey); - String? key; - Asn1Octet? localIdentity; - // ignore: avoid_function_literals_in_foreach_calls - subSequenceCollection.attributes!.objects.forEach((dynamic sq) { - final DerObjectID? asn1Id = sq[0] as DerObjectID?; - final Asn1Set attributeSet = sq[1] as Asn1Set; - Asn1Encode? attribute; - if (attributeSet.objects.isNotEmpty) { - attribute = attributeSet.objects[0] as Asn1Encode?; - if (attributes.containsKey(asn1Id!.id)) { - if (!(attributes[asn1Id.id] == attribute)) { - throw ArgumentError.value( - attributes, - 'attributes', - 'attempt to add existing attribute with different value', - ); - } - } else { - attributes[asn1Id.id] = attribute; - } - if (asn1Id.id == PkcsObjectId.pkcs9AtFriendlyName.id) { - key = (attribute! as DerBmpString).getString(); - _keys.setValue(key!, keyEntry); - } else if (asn1Id.id == PkcsObjectId.pkcs9AtLocalKeyID.id) { - localIdentity = attribute as Asn1Octet?; - } - } - }); - final String name = PdfString.bytesToHex( - localIdentity!.getOctets()!, - ); - if (key == null) { - _keys.setValue(name, keyEntry); - } else { - _localIdentifiers[key] = name; - } - } else if (subSequenceCollection.id!.id == PkcsObjectId.keyBag.id) { - final KeyInformation privateKeyInformation = - KeyInformation.getInformation(subSequenceCollection.value)!; - RsaPrivateKeyParam? rsaParameter; - if (privateKeyInformation._algorithms!.id!.id == - PkcsObjectId.rsaEncryption.id || - privateKeyInformation._algorithms!.id!.id == - X509Objects.idEARsa.id) { - final _RsaKey keyStructure = _RsaKey.fromSequence( - Asn1Sequence.getSequence(privateKeyInformation._privateKey)!, - ); - rsaParameter = RsaPrivateKeyParam( - keyStructure._modulus, - keyStructure._publicExponent, - keyStructure._privateExponent, - keyStructure._prime1, - keyStructure._prime2, - keyStructure._exponent1, - keyStructure._exponent2, - keyStructure._coefficient, - ); - } - final CipherParameter? privateKey = rsaParameter; - String? key; - Asn1Octet? localId; - final Map attributes = {}; - final KeyEntry keyEntry = KeyEntry(privateKey); - // ignore: avoid_function_literals_in_foreach_calls - subSequenceCollection.attributes!.objects.forEach((dynamic sq) { - final DerObjectID? id = sq[0] as DerObjectID?; - final Asn1Set attributeSet = sq[1] as Asn1Set; - Asn1Encode? attribute; - if (attributeSet.objects.isNotEmpty) { - attribute = attributeSet[0]; - if (attributes.containsKey(id!.id)) { - final Asn1Encode? attr = attributes[id.id] as Asn1Encode?; - if (attr != null && attr != attribute) { - throw ArgumentError.value( - sq, - 'sequence', - 'attempt to add existing attribute with different value', - ); - } - } else { - attributes[id.id] = attribute; - } - if (id.id == PkcsObjectId.pkcs9AtFriendlyName.id) { - key = (attribute! as DerBmpString).getString(); - _keys.setValue(key!, keyEntry); - } else if (id.id == PkcsObjectId.pkcs9AtLocalKeyID.id) { - localId = attribute as Asn1Octet?; - } - } - }); - final String name = PdfString.bytesToHex(localId!.getOctets()!); - if (key == null) { - _keys.setValue(name, keyEntry); - } else { - _localIdentifiers[key] = name; - } - } - }); - } - }); - } - _certificates = _CertificateTable(); - _chainCertificates = <_CertificateIdentifier, X509Certificates>{}; - _keyCertificates = {}; - // ignore: avoid_function_literals_in_foreach_calls - certificateChain.forEach((Asn1SequenceCollection asn1Collection) { - final Asn1Sequence asn1Sequence = asn1Collection.value! as Asn1Sequence; - final Asn1 certValue = Asn1Tag.getTag(asn1Sequence[1])!.getObject()!; - final List? octets = (certValue as Asn1Octet).getOctets(); - final X509Certificate certificate = - X509CertificateParser().readCertificate(PdfStreamReader(octets))!; - final Map attributes = {}; - Asn1Octet? localId; - String? key; - final Asn1Set? tempAttributes = asn1Collection.attributes; - if (tempAttributes != null) { - for (int i = 0; i < tempAttributes.objects.length; i++) { - final Asn1Sequence sq = tempAttributes.objects[i] as Asn1Sequence; - final DerObjectID? aOid = DerObjectID.getID(sq[0]); - final Asn1Set attrSet = sq[1]! as Asn1Set; - if (attrSet.objects.isNotEmpty) { - final Asn1Encode? attr = attrSet[0]; - if (attributes.containsKey(aOid!.id)) { - if (attributes[aOid.id] != attr) { - throw ArgumentError.value( - attributes, - 'attributes', - 'attempt to add existing attribute with different value', - ); - } - } else { - attributes[aOid.id] = attr; - } - if (aOid.id == PkcsObjectId.pkcs9AtFriendlyName.id) { - key = (attr! as DerBmpString).getString(); - } else if (aOid.id == PkcsObjectId.pkcs9AtLocalKeyID.id) { - localId = attr as Asn1Octet?; - } - } - } - } - final _CertificateIdentifier certId = _CertificateIdentifier( - pubKey: certificate.getPublicKey(), - ); - final X509Certificates certificateCollection = X509Certificates( - certificate, - ); - _chainCertificates[certId] = certificateCollection; - if (isUnmarkedKey) { - if (_keyCertificates.isEmpty) { - final String name = PdfString.bytesToHex(certId.id!); - _keyCertificates[name] = certificateCollection; - final dynamic temp = _keys['unmarked']; - _keys.remove('unmarked'); - _keys.setValue('name', temp); - } - } else { - if (localId != null) { - final String name = PdfString.bytesToHex(localId.getOctets()!); - _keyCertificates[name] = certificateCollection; - } - if (key != null) { - _certificates.setValue(key, certificateCollection); - } - } - }); - } - - /// internal method - static List? getCryptographicData( - bool forEncryption, - Algorithms id, - String password, - bool isZero, - List? data, - ) { - final _PasswordUtility utility = _PasswordUtility(); - final IBufferedCipher? cipher = - utility.createEncoder(id.id) as IBufferedCipher?; - if (cipher == null) { - throw ArgumentError.value(id, 'id', 'Invalid encryption algorithm'); - } - final _Pkcs12PasswordParameter parameter = - _Pkcs12PasswordParameter.getPbeParameter(id.parameters); - final ICipherParameter? parameters = utility.generateCipherParameters( - id.id!.id!, - password, - isZero, - parameter, - ); - cipher.initialize(forEncryption, parameters); - return cipher.doFinalFromInput(data); - } - - /// internal method - KeyInformation? createPrivateKeyInfo( - String passPhrase, - bool isPkcs12empty, - EncryptedPrivateKey encInfo, - ) { - final Algorithms algID = encInfo._algorithms!; - final _PasswordUtility pbeU = _PasswordUtility(); - final IBufferedCipher? cipher = - pbeU.createEncoder(algID) as IBufferedCipher?; - if (cipher == null) { - throw ArgumentError.value( - cipher, - 'cipher', - 'Unknown encryption algorithm', - ); - } - final ICipherParameter? cipherParameters = pbeU.generateCipherParameters( - algID.id!.id!, - passPhrase, - isPkcs12empty, - algID.parameters, - ); - cipher.initialize(false, cipherParameters); - final List? keyBytes = cipher.doFinalFromInput( - encInfo._octet!.getOctets(), - ); - return KeyInformation.getInformation(keyBytes); - } - - /// internal method - static SubjectKeyID createSubjectKeyID(CipherParameter publicKey) { - SubjectKeyID result; - if (publicKey is RsaKeyParam) { - final PublicKeyInformation information = PublicKeyInformation( - Algorithms(PkcsObjectId.rsaEncryption, DerNull.value), - RsaPublicKey(publicKey.modulus, publicKey.exponent).getAsn1(), - ); - result = SubjectKeyID(information); - } else { - throw ArgumentError.value(publicKey, 'publicKey', 'Invalid Key'); - } - return result; - } - - /// internal method - Map getContentTable() { - final Map result = {}; - // ignore: avoid_function_literals_in_foreach_calls - _certificates.keys.forEach((String key) { - result[key] = 'cert'; - }); - // ignore: avoid_function_literals_in_foreach_calls - _keys.keys.forEach((String key) { - if (!result.containsKey(key)) { - result[key] = 'key'; - } - }); - return result; - } - - /// internal method - Future> getContentTableAsync() async { - final Map result = {}; - // ignore: avoid_function_literals_in_foreach_calls - _certificates.keys.forEach((String key) { - result[key] = 'cert'; - }); - // ignore: avoid_function_literals_in_foreach_calls - _keys.keys.forEach((String key) { - if (!result.containsKey(key)) { - result[key] = 'key'; - } - }); - return result; - } - - /// internal method - bool isKey(String key) { - return _keys[key] != null; - } - - /// internal method - KeyEntry? getKey(String key) { - return _keys[key] is KeyEntry ? _keys[key] as KeyEntry? : null; - } - - /// internal method - X509Certificates? getCertificate(String key) { - dynamic certificates = _certificates[key]; - if (certificates != null && certificates is X509Certificates) { - return certificates; - } else { - String? id; - if (_localIdentifiers.containsKey(key)) { - id = _localIdentifiers[key]; - } - if (id != null) { - if (_keyCertificates.containsKey(id)) { - certificates = - _keyCertificates[id] is X509Certificates - ? _keyCertificates[id] - : null; - } - } else { - if (_keyCertificates.containsKey(key)) { - certificates = - _keyCertificates[key] is X509Certificates - ? _keyCertificates[key] - : null; - } - } - return certificates as X509Certificates?; - } - } - - /// internal method - Future getCertificateAsync(String key) async { - dynamic certificates = _certificates[key]; - if (certificates != null && certificates is X509Certificates) { - return certificates; - } else { - String? id; - if (_localIdentifiers.containsKey(key)) { - id = _localIdentifiers[key]; - } - if (id != null) { - if (_keyCertificates.containsKey(id)) { - certificates = - _keyCertificates[id] is X509Certificates - ? _keyCertificates[id] - : null; - } - } else { - if (_keyCertificates.containsKey(key)) { - certificates = - _keyCertificates[key] is X509Certificates - ? _keyCertificates[key] - : null; - } - } - return certificates as X509Certificates?; - } - } - - /// internal method - List? getCertificateChain(String key) { - if (!isKey(key)) { - return null; - } - X509Certificates? certificates = getCertificate(key); - if (certificates != null) { - final List certificateList = []; - bool isContinue = true; - while (certificates != null) { - final X509Certificate x509Certificate = certificates.certificate!; - X509Certificates? nextCertificate; - final Asn1Octet? x509Extension = x509Certificate.getExtension( - X509Extensions.authorityKeyIdentifier, - ); - if (x509Extension != null) { - final _KeyIdentifier id = _KeyIdentifier.getKeyIdentifier( - Asn1Stream(PdfStreamReader(x509Extension.getOctets())).readAsn1(), - ); - if (id.keyID != null) { - if (_chainCertificates.containsKey( - _CertificateIdentifier(id: id.keyID), - )) { - nextCertificate = - _chainCertificates[_CertificateIdentifier(id: id.keyID)]; - } - } - } - if (nextCertificate == null) { - final X509Name? issuer = x509Certificate.c!.issuer; - final X509Name? subject = x509Certificate.c!.subject; - if (!(issuer == subject)) { - final List<_CertificateIdentifier> keys = - _chainCertificates.keys.toList(); - // ignore: avoid_function_literals_in_foreach_calls - keys.forEach((_CertificateIdentifier certId) { - X509Certificates? x509CertEntry; - if (_chainCertificates.containsKey(certId)) { - x509CertEntry = _chainCertificates[certId]; - } - final X509Certificate certificate = x509CertEntry!.certificate!; - if (certificate.c!.subject == issuer) { - try { - // x509Certificate.verify(certificate.getPublicKey()); - // nextCertificate = x509CertEntry; - isContinue = false; - } catch (e) { - // - } - } - }); - } - } - if (isContinue) { - certificateList.add(certificates); - certificates = - nextCertificate != null && nextCertificate != certificates - ? nextCertificate - : null; - } - } - return List.generate( - certificateList.length, - (int i) => certificateList[i], - ); - } - return null; - } - - /// internal method - Future?> getCertificateChainAsync(String key) async { - if (!isKey(key)) { - return null; - } - List? x509Certificates; - await getCertificateAsync(key).then((X509Certificates? certificates) { - if (certificates != null) { - final List certificateList = []; - bool isContinue = true; - while (certificates != null) { - final X509Certificate x509Certificate = certificates.certificate!; - X509Certificates? nextCertificate; - final Asn1Octet? x509Extension = x509Certificate.getExtension( - X509Extensions.authorityKeyIdentifier, - ); - if (x509Extension != null) { - final _KeyIdentifier id = _KeyIdentifier.getKeyIdentifier( - Asn1Stream(PdfStreamReader(x509Extension.getOctets())).readAsn1(), - ); - if (id.keyID != null) { - if (_chainCertificates.containsKey( - _CertificateIdentifier(id: id.keyID), - )) { - nextCertificate = - _chainCertificates[_CertificateIdentifier(id: id.keyID)]; - } - } - } - if (nextCertificate == null) { - final X509Name? issuer = x509Certificate.c!.issuer; - final X509Name? subject = x509Certificate.c!.subject; - if (!(issuer == subject)) { - final List<_CertificateIdentifier> keys = - _chainCertificates.keys.toList(); - // ignore: avoid_function_literals_in_foreach_calls - keys.forEach((_CertificateIdentifier certId) { - X509Certificates? x509CertEntry; - if (_chainCertificates.containsKey(certId)) { - x509CertEntry = _chainCertificates[certId]; - } - final X509Certificate certificate = x509CertEntry!.certificate!; - if (certificate.c!.subject == issuer) { - try { - // x509Certificate.verify(certificate.getPublicKey()); - // nextCertificate = x509CertEntry; - isContinue = false; - } catch (e) { - // - } - } - }); - } - } - if (isContinue) { - certificateList.add(certificates); - certificates = - nextCertificate != null && nextCertificate != certificates - ? nextCertificate - : null; - } - } - x509Certificates = List.generate( - certificateList.length, - (int i) => certificateList[i], - ); - } - }); - return x509Certificates; - } - - /// internal method - List getChainCertificates() { - return _chainCertificates.values.toList(); - } -} - -class _CertificateTable { - _CertificateTable() { - _orig = {}; - _keys = {}; - } - late Map _orig; - late Map _keys; - - //Implementation - void clear() { - _orig = {}; - _keys = {}; - } - - List get keys { - return _orig.keys.toList(); - } - - dynamic remove(String key) { - final String lower = key.toLowerCase(); - String? k; - _keys.forEach((String tempKey, dynamic tempValue) { - if (lower == tempKey.toLowerCase()) { - k = _keys[tempKey] as String?; - } - }); - if (k == null) { - return null; - } - _keys.remove(lower); - final dynamic obj = _orig[k!]; - _orig.remove(k); - return obj; - } - - dynamic operator [](String key) { - final String lower = key.toLowerCase(); - String? k; - _keys.forEach((String tempKey, dynamic tempValue) { - if (lower == tempKey.toLowerCase()) { - k = tempKey; - } - }); - if (k != null) { - return _orig[_keys[k!]]; - } else { - return null; - } - } - - void setValue(String key, dynamic value) { - final String lower = key.toLowerCase(); - String? k; - _keys.forEach((String tempKey, dynamic tempValue) { - if (lower == tempKey.toLowerCase()) { - k = tempKey; - } - }); - if (k != null) { - _orig.remove(_keys[k!]); - } - _keys[lower] = key; - _orig[key] = value; - } -} - -class _CertificateIdentifier { - _CertificateIdentifier({CipherParameter? pubKey, List? id}) { - this.id = - pubKey != null - ? PdfPKCSCertificate.createSubjectKeyID(pubKey)._bytes - : id; - } - //Fields - List? id; - //Implements - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is _CertificateIdentifier) { - return Asn1.areEqual(id, other.id); - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Asn1.getHashCode(id); -} - -class _PasswordUtility { - _PasswordUtility() { - _cipherUtils = _CipherUtils(); - _pkcs12 = 'Pkcs12'; - _algorithms = {}; - _type = {}; - _ids = {}; - _algorithms['PBEWITHSHAAND40BITRC4'] = 'PBEwithSHA-1and40bitRC4'; - _algorithms['PBEWITHSHA1AND40BITRC4'] = 'PBEwithSHA-1and40bitRC4'; - _algorithms['PBEWITHSHA-1AND40BITRC4'] = 'PBEwithSHA-1and40bitRC4'; - _algorithms[PkcsObjectId.pbeWithShaAnd40BitRC4.id] = - 'PBEwithSHA-1and40bitRC4'; - _algorithms['PBEWITHSHAAND3-KEYDESEDE-CBC'] = - 'PBEwithSHA-1and3-keyDESEDE-CBC'; - _algorithms['PBEWITHSHAAND3-KEYTRIPLEDES-CBC'] = - 'PBEwithSHA-1and3-keyDESEDE-CBC'; - _algorithms['PBEWITHSHA1AND3-KEYDESEDE-CBC'] = - 'PBEwithSHA-1and3-keyDESEDE-CBC'; - _algorithms['PBEWITHSHA1AND3-KEYTRIPLEDES-CBC'] = - 'PBEwithSHA-1and3-keyDESEDE-CBC'; - _algorithms['PBEWITHSHA-1AND3-KEYDESEDE-CBC'] = - 'PBEwithSHA-1and3-keyDESEDE-CBC'; - _algorithms['PBEWITHSHA-1AND3-KEYTRIPLEDES-CBC'] = - 'PBEwithSHA-1and3-keyDESEDE-CBC'; - _algorithms[PkcsObjectId.pbeWithShaAnd3KeyTripleDesCbc.id] = - 'PBEwithSHA-1and3-keyDESEDE-CBC'; - _algorithms['PBEWITHSHAAND40BITRC2-CBC'] = 'PBEwithSHA-1and40bitRC2-CBC'; - _algorithms['PBEWITHSHA1AND40BITRC2-CBC'] = 'PBEwithSHA-1and40bitRC2-CBC'; - _algorithms['PBEWITHSHA-1AND40BITRC2-CBC'] = 'PBEwithSHA-1and40bitRC2-CBC'; - _algorithms[PkcsObjectId.pbewithShaAnd40BitRC2Cbc.id] = - 'PBEwithSHA-1and40bitRC2-CBC'; - _algorithms['PBEWITHSHAAND128BITAES-CBC-BC'] = - 'PBEwithSHA-1and128bitAES-CBC-BC'; - _algorithms['PBEWITHSHA1AND128BITAES-CBC-BC'] = - 'PBEwithSHA-1and128bitAES-CBC-BC'; - _algorithms['PBEWITHSHA-1AND128BITAES-CBC-BC'] = - 'PBEwithSHA-1and128bitAES-CBC-BC'; - _algorithms['PBEWITHSHAAND192BITAES-CBC-BC'] = - 'PBEwithSHA-1and192bitAES-CBC-BC'; - _algorithms['PBEWITHSHA1AND192BITAES-CBC-BC'] = - 'PBEwithSHA-1and192bitAES-CBC-BC'; - _algorithms['PBEWITHSHA-1AND192BITAES-CBC-BC'] = - 'PBEwithSHA-1and192bitAES-CBC-BC'; - _algorithms['PBEWITHSHAAND256BITAES-CBC-BC'] = - 'PBEwithSHA-1and256bitAES-CBC-BC'; - _algorithms['PBEWITHSHA1AND256BITAES-CBC-BC'] = - 'PBEwithSHA-1and256bitAES-CBC-BC'; - _algorithms['PBEWITHSHA-1AND256BITAES-CBC-BC'] = - 'PBEwithSHA-1and256bitAES-CBC-BC'; - _algorithms['PBEWITHSHA256AND128BITAES-CBC-BC'] = - 'PBEwithSHA-256and128bitAES-CBC-BC'; - _algorithms['PBEWITHSHA-256AND128BITAES-CBC-BC'] = - 'PBEwithSHA-256and128bitAES-CBC-BC'; - _algorithms['PBEWITHSHA256AND192BITAES-CBC-BC'] = - 'PBEwithSHA-256and192bitAES-CBC-BC'; - _algorithms['PBEWITHSHA-256AND192BITAES-CBC-BC'] = - 'PBEwithSHA-256and192bitAES-CBC-BC'; - _algorithms['PBEWITHSHA256AND256BITAES-CBC-BC'] = - 'PBEwithSHA-256and256bitAES-CBC-BC'; - _algorithms['PBEWITHSHA-256AND256BITAES-CBC-BC'] = - 'PBEwithSHA-256and256bitAES-CBC-BC'; - _type['Pkcs12'] = _pkcs12; - _type['PBEwithSHA-1and128bitRC4'] = _pkcs12; - _type['PBEwithSHA-1and40bitRC4'] = _pkcs12; - _type['PBEwithSHA-1and3-keyDESEDE-CBC'] = _pkcs12; - _type['PBEwithSHA-1and2-keyDESEDE-CBC'] = _pkcs12; - _type['PBEwithSHA-1and128bitRC2-CBC'] = _pkcs12; - _type['PBEwithSHA-1and40bitRC2-CBC'] = _pkcs12; - _type['PBEwithSHA-1and256bitAES-CBC-BC'] = _pkcs12; - _type['PBEwithSHA-256and128bitAES-CBC-BC'] = _pkcs12; - _type['PBEwithSHA-256and192bitAES-CBC-BC'] = _pkcs12; - _type['PBEwithSHA-256and256bitAES-CBC-BC'] = _pkcs12; - _ids['PBEwithSHA-1and128bitRC4'] = PkcsObjectId.pbeWithShaAnd128BitRC4; - _ids['PBEwithSHA-1and40bitRC4'] = PkcsObjectId.pbeWithShaAnd40BitRC4; - _ids['PBEwithSHA-1and3-keyDESEDE-CBC'] = - PkcsObjectId.pbeWithShaAnd3KeyTripleDesCbc; - _ids['PBEwithSHA-1and2-keyDESEDE-CBC'] = - PkcsObjectId.pbeWithShaAnd2KeyTripleDesCbc; - _ids['PBEwithSHA-1and128bitRC2-CBC'] = - PkcsObjectId.pbeWithShaAnd128BitRC2Cbc; - _ids['PBEwithSHA-1and40bitRC2-CBC'] = PkcsObjectId.pbewithShaAnd40BitRC2Cbc; - } - - //Fields - String? _pkcs12; - late Map _algorithms; - late Map _type; - late Map _ids; - late _CipherUtils _cipherUtils; - - //Implementation - dynamic createEncoder(dynamic obj) { - dynamic result; - if (obj is Algorithms) { - result = createEncoder(obj.id!.id); - } else if (obj is DerObjectID) { - result = createEncoder(obj.id); - } else if (obj is String) { - final String lower = obj.toLowerCase(); - String? mechanism; - bool isContinue = true; - _algorithms.forEach((String? key, String value) { - if (isContinue && lower == key!.toLowerCase()) { - mechanism = _algorithms[key]; - isContinue = false; - } - }); - - if (mechanism != null && - (mechanism!.startsWith('PBEwithMD2') || - mechanism!.startsWith('PBEwithMD5') || - mechanism!.startsWith('PBEwithSHA-1') || - mechanism!.startsWith('PBEwithSHA-256'))) { - if (mechanism!.endsWith('AES-CBC-BC') || - mechanism!.endsWith('AES-CBC-OPENSSL')) { - result = _cipherUtils.getCipher('AES/CBC'); - } else if (mechanism!.endsWith('DES-CBC')) { - result = _cipherUtils.getCipher('DES/CBC'); - } else if (mechanism!.endsWith('DESEDE-CBC')) { - result = _cipherUtils.getCipher('DESEDE/CBC'); - } else if (mechanism!.endsWith('RC2-CBC')) { - result = _cipherUtils.getCipher('RC2/CBC'); - } else if (mechanism!.endsWith('RC4')) { - result = _cipherUtils.getCipher('RC4'); - } - } - } - return result; - } - - ICipherParameter? generateCipherParameters( - String algorithm, - String password, - bool isWrong, - Asn1Encode? pbeParameters, - ) { - final String mechanism = getAlgorithmFromUpeerInvariant(algorithm)!; - late List keyBytes; - List? salt; - int iterationCount = 0; - if (isPkcs12(mechanism)) { - final _Pkcs12PasswordParameter pbeParams = - _Pkcs12PasswordParameter.getPbeParameter(pbeParameters); - salt = pbeParams._octet!.getOctets(); - iterationCount = pbeParams._iterations!.value.toSigned(32).toInt(); - keyBytes = _PasswordGenerator.toBytes(password, isWrong); - } - ICipherParameter? parameters; - _PasswordGenerator generator; - if (mechanism.startsWith('PBEwithSHA-1')) { - generator = getEncoder( - _type[mechanism], - DigestAlgorithms.sha1, - keyBytes, - salt!, - iterationCount, - password, - ); - if (mechanism == 'PBEwithSHA-1and128bitAES-CBC-BC') { - parameters = generator.generateParam(128, 'AES', 128); - } else if (mechanism == 'PBEwithSHA-1and192bitAES-CBC-BC') { - parameters = generator.generateParam(192, 'AES', 128); - } else if (mechanism == 'PBEwithSHA-1and256bitAES-CBC-BC') { - parameters = generator.generateParam(256, 'AES', 128); - } else if (mechanism == 'PBEwithSHA-1and128bitRC4') { - parameters = generator.generateParam(128, 'RC4'); - } else if (mechanism == 'PBEwithSHA-1and40bitRC4') { - parameters = generator.generateParam(40, 'RC4'); - } else if (mechanism == 'PBEwithSHA-1and3-keyDESEDE-CBC') { - parameters = generator.generateParam(192, 'DESEDE', 64); - } else if (mechanism == 'PBEwithSHA-1and2-keyDESEDE-CBC') { - parameters = generator.generateParam(128, 'DESEDE', 64); - } else if (mechanism == 'PBEwithSHA-1and128bitRC2-CBC') { - parameters = generator.generateParam(128, 'RC2', 64); - } else if (mechanism == 'PBEwithSHA-1and40bitRC2-CBC') { - parameters = generator.generateParam(40, 'RC2', 64); - } else if (mechanism == 'PBEwithSHA-1andDES-CBC') { - parameters = generator.generateParam(64, 'DES', 64); - } else if (mechanism == 'PBEwithSHA-1andRC2-CBC') { - parameters = generator.generateParam(64, 'RC2', 64); - } - } else if (mechanism.startsWith('PBEwithSHA-256')) { - generator = getEncoder( - _type[mechanism], - DigestAlgorithms.sha256, - keyBytes, - salt!, - iterationCount, - password, - ); - if (mechanism == 'PBEwithSHA-256and128bitAES-CBC-BC') { - parameters = generator.generateParam(128, 'AES', 128); - } else if (mechanism == 'PBEwithSHA-256and192bitAES-CBC-BC') { - parameters = generator.generateParam(192, 'AES', 128); - } else if (mechanism == 'PBEwithSHA-256and256bitAES-CBC-BC') { - parameters = generator.generateParam(256, 'AES', 128); - } - } else if (mechanism.startsWith('PBEwithHmac')) { - final String digest = getDigest( - mechanism.substring('PBEwithHmac'.length), - ); - generator = getEncoder( - _type[mechanism], - digest, - keyBytes, - salt!, - iterationCount, - password, - ); - final int? bitLen = getBlockSize(digest); - parameters = generator.generateParam(bitLen); - } - keyBytes = List.generate(keyBytes.length, (int i) => 0); - return fixDataEncryptionParity(mechanism, parameters); - } - - static int getByteLength(String digest) { - return (digest == DigestAlgorithms.md5 || - digest == DigestAlgorithms.sha1 || - digest == DigestAlgorithms.sha256 || - digest.contains('Hmac')) - ? 64 - : 128; - } - - static int? getBlockSize(String digest) { - int? result; - if (digest == DigestAlgorithms.md5) { - result = 16; - } else if (digest == DigestAlgorithms.sha1) { - result = 20; - } else if (digest == DigestAlgorithms.sha256) { - result = 32; - } else if (digest == DigestAlgorithms.sha512) { - result = 64; - } else if (digest == DigestAlgorithms.sha384) { - result = 48; - } else if (digest.contains('Hmac')) { - result = 20; - } - return result; - } - - ICipherParameter? fixDataEncryptionParity( - String mechanism, - ICipherParameter? parameters, - ) { - if (!mechanism.endsWith('DES-CBC') & !mechanism.endsWith('DESEDE-CBC')) { - return parameters; - } - if (parameters is InvalidParameter) { - return InvalidParameter( - fixDataEncryptionParity(mechanism, parameters.parameters), - parameters.keys, - ); - } - final KeyParameter kParam = parameters! as KeyParameter; - final List keyBytes = kParam.keys; - for (int i = 0; i < keyBytes.length; i++) { - final int value = keyBytes[i]; - keyBytes[i] = ((value & 0xfe) | - ((((value >> 1) ^ - (value >> 2) ^ - (value >> 3) ^ - (value >> 4) ^ - (value >> 5) ^ - (value >> 6) ^ - (value >> 7)) ^ - 0x01) & - 0x01)) - .toUnsigned(8); - } - return KeyParameter(Uint8List.fromList(keyBytes)); - } - - bool isPkcs12(String algorithm) { - final String? mechanism = getAlgorithmFromUpeerInvariant(algorithm); - return mechanism != null && - _type.containsKey(mechanism) && - _pkcs12 == _type[mechanism]; - } - - String getDigest(String algorithm) { - String? digest = getAlgorithmFromUpeerInvariant(algorithm); - digest ??= algorithm; - if (digest.contains('sha_1') || - digest.contains('sha-1') || - digest.contains('sha1')) { - digest = DigestAlgorithms.hmacWithSha1; - } else if (digest.contains('sha_256') || - digest.contains('sha-256') || - digest.contains('sha256')) { - digest = DigestAlgorithms.hmacWithSha256; - } else if (digest.contains('md5') || - digest.contains('md_5') || - digest.contains('md-5')) { - digest = DigestAlgorithms.hmacWithMd5; - } else { - throw ArgumentError.value(algorithm, 'algorithm', 'Invalid message'); - } - return digest; - } - - _PasswordGenerator getEncoder( - String? type, - String digest, - List key, - List salt, - int iterationCount, - String password, - ) { - _PasswordGenerator generator; - if (type == _pkcs12) { - generator = _Pkcs12AlgorithmGenerator(digest, password); - } else { - throw ArgumentError.value( - type, - 'type', - 'Invalid Password Based Encryption type', - ); - } - generator.init(key, salt, iterationCount); - return generator; - } - - String? getAlgorithmFromUpeerInvariant(String algorithm) { - final String temp = algorithm.toLowerCase(); - String? result; - bool isContinue = true; - _algorithms.forEach((String? key, String value) { - if (isContinue && key!.toLowerCase() == temp) { - result = value; - isContinue = false; - } - }); - return result; - } -} - -abstract class _PasswordGenerator { - List? _password; - List? _value; - int? _count; - ICipherParameter generateParam(int? keySize, [String? algorithm, int? size]); - void init(List password, List value, int count) { - _password = Asn1.clone(password); - _value = Asn1.clone(value); - _count = count; - } - - static List toBytes(String password, bool isWrong) { - if (password.isEmpty) { - return isWrong ? List.generate(2, (int i) => 0) : []; - } - final List bytes = List.generate( - (password.length + 1) * 2, - (int i) => 0, - ); - final List tempBytes = encodeBigEndian(password); - int i = 0; - // ignore: avoid_function_literals_in_foreach_calls - tempBytes.forEach((int tempByte) { - bytes[i] = tempBytes[i]; - i++; - }); - return bytes; - } -} - -class _Pkcs12AlgorithmGenerator extends _PasswordGenerator { - _Pkcs12AlgorithmGenerator(String digest, String password) { - _digest = getDigest(digest, password); - _size = _PasswordUtility.getBlockSize(digest); - _length = _PasswordUtility.getByteLength(digest); - _keyMaterial = 1; - _invaidMaterial = 2; - } - late dynamic _digest; - int? _size; - late int _length; - int? _keyMaterial; - int? _invaidMaterial; - //Implementes - dynamic getDigest(String digest, String password) { - dynamic result; - if (digest == DigestAlgorithms.md5) { - result = md5; - } else if (digest == DigestAlgorithms.sha1) { - result = sha1; - } else if (digest == DigestAlgorithms.sha256) { - result = sha256; - } else if (digest == DigestAlgorithms.sha384) { - result = sha384; - } else if (digest == DigestAlgorithms.sha512) { - result = sha512; - } else if (digest == DigestAlgorithms.hmacWithSha1) { - result = Hmac(sha1, utf8.encode(password)); - } else if (digest == DigestAlgorithms.hmacWithSha256) { - result = Hmac(sha256, utf8.encode(password)); - } else if (digest == DigestAlgorithms.hmacWithMd5) { - result = Hmac(md5, utf8.encode(password)); - } else { - throw ArgumentError.value(digest, 'digest', 'Invalid message digest'); - } - return result; - } - - @override - ICipherParameter generateParam(int? keySize, [String? algorithm, int? size]) { - if (size != null) { - size = size ~/ 8; - keySize = keySize! ~/ 8; - final List bytes = generateDerivedKey(_keyMaterial, keySize); - final _ParamUtility util = _ParamUtility(); - final KeyParameter key = util.createKeyParameter( - algorithm!, - bytes, - 0, - keySize, - ); - final List iv = generateDerivedKey(_invaidMaterial, size); - return InvalidParameter(key, Uint8List.fromList(iv)); - } else if (algorithm != null) { - keySize = keySize! ~/ 8; - final List bytes = generateDerivedKey(_keyMaterial, keySize); - final _ParamUtility util = _ParamUtility(); - return util.createKeyParameter(algorithm, bytes, 0, keySize); - } else { - keySize = keySize! ~/ 8; - final List bytes = generateDerivedKey(_keyMaterial, keySize); - return KeyParameter.fromLengthValue( - Uint8List.fromList(bytes), - 0, - keySize, - ); - } - } - - List generateDerivedKey(int? id, int length) { - final List d = List.generate(_length, (int index) => 0); - final List derivedKey = List.generate(length, (int index) => 0); - for (int index = 0; index != d.length; index++) { - d[index] = id!.toUnsigned(8); - } - List s; - if (_value != null && _value!.isNotEmpty) { - s = List.generate( - _length * ((_value!.length + _length - 1) ~/ _length), - (int index) => 0, - ); - for (int index = 0; index != s.length; index++) { - s[index] = _value![index % _value!.length]; - } - } else { - s = []; - } - List password; - if (_password != null && _password!.isNotEmpty) { - password = List.generate( - _length * ((_password!.length + _length - 1) ~/ _length), - (int index) => 0, - ); - for (int index = 0; index != password.length; index++) { - password[index] = _password![index % _password!.length]; - } - } else { - password = []; - } - List tempBytes = List.generate( - s.length + password.length, - (int index) => 0, - ); - List.copyRange(tempBytes, 0, s, 0, s.length); - List.copyRange(tempBytes, s.length, password, 0, password.length); - final List b = List.generate(_length, (int index) => 0); - final int c = (length + _size! - 1) ~/ _size!; - List? a = List.generate(_size!, (int index) => 0); - for (int i = 1; i <= c; i++) { - final dynamic output = AccumulatorSink(); - final dynamic input = sha1.startChunkedConversion(output); - input.add(d); - input.add(tempBytes); - input.close(); - a = output.events.single.bytes as List?; - for (int j = 1; j != _count; j++) { - a = _digest.convert(a).bytes as List?; - } - for (int j = 0; j != b.length; j++) { - b[j] = a![j % a.length]; - } - for (int j = 0; j != tempBytes.length ~/ _length; j++) { - tempBytes = adjust(tempBytes, j * _length, b); - } - if (i == c) { - List.copyRange( - derivedKey, - (i - 1) * _size!, - a!, - 0, - derivedKey.length - ((i - 1) * _size!), - ); - } else { - List.copyRange(derivedKey, (i - 1) * _size!, a!, 0, a.length); - } - } - return derivedKey; - } - - List adjust(List a, int offset, List b) { - int x = (b[b.length - 1] & 0xff) + (a[offset + b.length - 1] & 0xff) + 1; - a[offset + b.length - 1] = x.toUnsigned(8); - x = (x.toUnsigned(32) >> 8).toSigned(32); - for (int i = b.length - 2; i >= 0; i--) { - x += (b[i] & 0xff) + (a[offset + i] & 0xff); - a[offset + i] = x.toUnsigned(8); - x = (x.toUnsigned(32) >> 8).toSigned(32); - } - return a; - } -} - -class _Pkcs12PasswordParameter extends Asn1Encode { - _Pkcs12PasswordParameter(Asn1Sequence sequence) { - if (sequence.count != 2) { - throw ArgumentError.value( - sequence, - 'sequence', - 'Invalid length in sequence', - ); - } - _octet = Asn1Octet.getOctetStringFromObject(sequence[0]); - _iterations = DerInteger.getNumber(sequence[1]); - } - //Fields - DerInteger? _iterations; - Asn1Octet? _octet; - //Implementation - static _Pkcs12PasswordParameter getPbeParameter(dynamic obj) { - _Pkcs12PasswordParameter result; - if (obj is _Pkcs12PasswordParameter) { - result = obj; - } else if (obj is Asn1Sequence) { - result = _Pkcs12PasswordParameter(obj); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - return result; - } - - @override - Asn1 getAsn1() { - return DerSequence(array: [_octet, _iterations]); - } -} - -class _ParamUtility { - _ParamUtility() { - _algorithms = {}; - addAlgorithm('DESEDE', [ - 'DESEDEWRAP', - 'TDEA', - DerObjectID('1.3.14.3.2.17'), - PkcsObjectId.idAlgCms3DesWrap, - ]); - addAlgorithm('DESEDE3', [PkcsObjectId.desEde3Cbc]); - addAlgorithm('RC2', [ - PkcsObjectId.rc2Cbc, - PkcsObjectId.idAlgCmsRC2Wrap, - ]); - } - - //Fields - late Map _algorithms; - - //Implementation - void addAlgorithm(String name, List objects) { - _algorithms[name] = name; - // ignore: avoid_function_literals_in_foreach_calls - objects.forEach((dynamic entry) { - if (entry is String) { - _algorithms[entry] = name; - } else { - _algorithms[entry.toString()] = name; - } - }); - } - - KeyParameter createKeyParameter( - String algorithm, - List bytes, - int offset, - int? length, - ) { - String? name; - final String lower = algorithm.toLowerCase(); - _algorithms.forEach((String key, String value) { - if (lower == key.toLowerCase()) { - name = value; - } - }); - if (name == null) { - throw ArgumentError.value( - algorithm, - 'algorithm', - 'Invalid entry. Algorithm', - ); - } - if (name == 'DES') { - return _DataEncryptionParameter.fromLengthValue(bytes, offset, length!); - } - if (name == 'DESEDE' || name == 'DESEDE3') { - return _DesedeAlgorithmParameter(bytes, offset, length); - } - return KeyParameter.fromLengthValue( - Uint8List.fromList(bytes), - offset, - length!, - ); - } -} - -class _DataEncryptionParameter extends KeyParameter { - _DataEncryptionParameter(List keys) : super(Uint8List.fromList(keys)) { - if (checkKey(keys, 0)) { - throw ArgumentError.value( - keys, - 'keys', - 'Invalid Data Encryption keys creation', - ); - } - } - _DataEncryptionParameter.fromLengthValue( - List keys, - int offset, - int length, - ) : super.fromLengthValue(Uint8List.fromList(keys), offset, length) { - if (checkKey(keys, 0)) { - throw ArgumentError.value( - keys, - 'keys', - 'Invalid Data Encryption keys creation', - ); - } - } - static List dataEncryptionWeekKeys = [ - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 31, - 31, - 31, - 31, - 14, - 14, - 14, - 14, - 224, - 224, - 224, - 224, - 241, - 241, - 241, - 241, - 254, - 254, - 254, - 254, - 254, - 254, - 254, - 254, - 1, - 254, - 1, - 254, - 1, - 254, - 1, - 254, - 31, - 224, - 31, - 224, - 14, - 241, - 14, - 241, - 1, - 224, - 1, - 224, - 1, - 241, - 1, - 241, - 31, - 254, - 31, - 254, - 14, - 254, - 14, - 254, - 1, - 31, - 1, - 31, - 1, - 14, - 1, - 14, - 224, - 254, - 224, - 254, - 241, - 254, - 241, - 254, - 254, - 1, - 254, - 1, - 254, - 1, - 254, - 1, - 224, - 31, - 224, - 31, - 241, - 14, - 241, - 14, - 224, - 1, - 224, - 1, - 241, - 1, - 241, - 1, - 254, - 31, - 254, - 31, - 254, - 14, - 254, - 14, - 31, - 1, - 31, - 1, - 14, - 1, - 14, - 1, - 254, - 224, - 254, - 224, - 254, - 241, - 254, - 241, - ]; - - static bool checkKey(List bytes, int offset) { - if (bytes.length - offset < 8) { - throw ArgumentError.value(bytes, 'bytes', 'Invalid length in bytes'); - } - for (int i = 0; i < 16; i++) { - bool isMatch = false; - for (int j = 0; j < 8; j++) { - if (bytes[j + offset] != dataEncryptionWeekKeys[i * 8 + j]) { - isMatch = true; - break; - } - } - if (!isMatch) { - return true; - } - } - return false; - } -} - -class _DesedeAlgorithmParameter extends _DataEncryptionParameter { - _DesedeAlgorithmParameter(List key, int keyOffset, int? keyLength) - : super(fixKey(key, keyOffset, keyLength)); - //Implementation - static List fixKey(List key, int keyOffset, int? keyLength) { - final List tmp = List.generate(24, (int i) => 0); - switch (keyLength) { - case 16: - List.copyRange(tmp, 0, key, keyOffset, keyOffset + 16); - List.copyRange(tmp, 16, key, keyOffset, keyOffset + 8); - break; - case 24: - List.copyRange(tmp, 0, key, keyOffset, keyOffset + 24); - break; - default: - throw ArgumentError.value( - keyLength, - 'keyLen', - 'Bad length for DESede key', - ); - } - if (checkKeyValue(tmp, 0, tmp.length)) { - throw ArgumentError.value( - key, - 'key', - 'Attempt to create weak DESede key', - ); - } - return tmp; - } - - static bool checkKeyValue(List key, int offset, int length) { - for (int i = offset; i < length; i += 8) { - if (_DataEncryptionParameter.checkKey(key, i)) { - return true; - } - } - return false; - } -} - -class _CipherUtils { - _CipherUtils() { - _algorithms = {}; - } - //Fields - late Map _algorithms; - //Implementation - IBufferedCipher getCipher(String algorithm) { - String? value; - if (_algorithms.isNotEmpty) { - value = _algorithms[algorithm]; - } - if (value != null) { - algorithm = value; - } - final List parts = algorithm.split('/'); - ICipher? blockCipher; - ICipherBlock? asymBlockCipher; - String algorithmName = parts[0]; - if (_algorithms.isNotEmpty) { - value = _algorithms[algorithmName]; - } - if (value != null) { - algorithmName = value; - } - final _CipherAlgorithm cipherAlgorithm = getAlgorithm(algorithmName); - switch (cipherAlgorithm) { - case _CipherAlgorithm.des: - blockCipher = _DataEncryption(); - break; - case _CipherAlgorithm.desede: - blockCipher = _DesEdeAlogorithm(); - break; - case _CipherAlgorithm.rc2: - blockCipher = _Rc2Algorithm(); - break; - case _CipherAlgorithm.rsa: - asymBlockCipher = RsaAlgorithm(); - break; - } - bool isPadded = true; - IPadding? padding; - if (parts.length > 2) { - final String paddingName = parts[2]; - _CipherPaddingType cipherPadding; - if (paddingName.isEmpty) { - cipherPadding = _CipherPaddingType.raw; - } else if (paddingName == 'X9.23PADDING') { - cipherPadding = _CipherPaddingType.x923Padding; - } else { - cipherPadding = getPaddingType(paddingName); - } - switch (cipherPadding) { - case _CipherPaddingType.noPadding: - isPadded = false; - break; - case _CipherPaddingType.raw: - case _CipherPaddingType.withCipherTextStealing: - break; - case _CipherPaddingType.pkcs1: - case _CipherPaddingType.pkcs1Padding: - asymBlockCipher = Pkcs1Encoding(asymBlockCipher); - break; - case _CipherPaddingType.pkcs5: - case _CipherPaddingType.pkcs5Padding: - case _CipherPaddingType.pkcs7: - case _CipherPaddingType.pkcs7Padding: - padding = Pkcs7Padding(); - break; - // ignore: no_default_cases - default: - throw ArgumentError.value( - cipherPadding, - 'cpiher padding algorithm', - 'Invalid cipher algorithm', - ); - } - } - String mode = ''; - if (parts.length > 1) { - mode = parts[1]; - int digitIngex = -1; - for (int i = 0; i < mode.length; ++i) { - if (isDigit(mode[i])) { - digitIngex = i; - break; - } - } - final String modeName = - digitIngex >= 0 ? mode.substring(0, digitIngex) : mode; - final _CipherMode cipherMode = - modeName == '' ? _CipherMode.none : getCipherMode(modeName); - switch (cipherMode) { - case _CipherMode.ecb: - case _CipherMode.none: - break; - case _CipherMode.cbc: - blockCipher = CipherBlockChainingMode(blockCipher); - break; - case _CipherMode.cts: - blockCipher = CipherBlockChainingMode(blockCipher); - break; - } - } - if (blockCipher != null) { - if (padding != null) { - return BufferedBlockPadding(blockCipher, padding); - } - if (!isPadded || blockCipher.isBlock!) { - return BufferedCipher(blockCipher); - } - return BufferedBlockPadding(blockCipher); - } - throw ArgumentError.value( - blockCipher, - 'Cipher Algorithm', - 'Invalid cipher algorithm', - ); - } - - _CipherAlgorithm getAlgorithm(String name) { - _CipherAlgorithm result; - switch (name.toLowerCase()) { - case 'des': - result = _CipherAlgorithm.des; - break; - case 'desede': - result = _CipherAlgorithm.desede; - break; - case 'rc2': - result = _CipherAlgorithm.rc2; - break; - case 'rsa': - result = _CipherAlgorithm.rsa; - break; - default: - throw ArgumentError.value(name, 'name', 'Invalid algorithm name'); - } - return result; - } - - _CipherMode getCipherMode(String mode) { - _CipherMode result; - switch (mode.toLowerCase()) { - case 'ecb': - result = _CipherMode.ecb; - break; - case 'none': - result = _CipherMode.none; - break; - case 'cbc': - result = _CipherMode.cbc; - break; - case 'cts': - result = _CipherMode.cts; - break; - default: - throw ArgumentError.value(mode, 'CipherMode', 'Invalid mode'); - } - return result; - } - - _CipherPaddingType getPaddingType(String type) { - _CipherPaddingType result; - switch (type.toLowerCase()) { - case 'noPadding': - result = _CipherPaddingType.noPadding; - break; - case 'raw': - result = _CipherPaddingType.raw; - break; - case 'pkcs1': - result = _CipherPaddingType.pkcs1; - break; - case 'pkcs1Padding': - result = _CipherPaddingType.pkcs1Padding; - break; - case 'pkcs5': - result = _CipherPaddingType.pkcs5; - break; - case 'pkcs5Padding': - result = _CipherPaddingType.pkcs5Padding; - break; - case 'pkcs7': - result = _CipherPaddingType.pkcs7; - break; - case 'pkcs7Padding': - result = _CipherPaddingType.pkcs7Padding; - break; - case 'withCipherTextStealing': - result = _CipherPaddingType.withCipherTextStealing; - break; - case 'x923Padding': - result = _CipherPaddingType.x923Padding; - break; - default: - throw ArgumentError.value(type, 'PaddingType', 'Invalid padding type'); - } - return result; - } - - bool isDigit(String s, [int idx = 0]) { - return (s.codeUnitAt(idx) ^ 0x30) <= 9; - } -} - -enum _CipherAlgorithm { des, desede, rc2, rsa } - -enum _CipherMode { ecb, none, cbc, cts } - -enum _CipherPaddingType { - noPadding, - raw, - pkcs1, - pkcs1Padding, - pkcs5, - pkcs5Padding, - pkcs7, - pkcs7Padding, - withCipherTextStealing, - x923Padding, -} - -class _KeyIdentifier extends Asn1Encode { - _KeyIdentifier(Asn1Sequence sequence) { - // ignore: avoid_function_literals_in_foreach_calls - sequence.objects!.forEach((dynamic entry) { - if (entry is Asn1Tag) { - switch (entry.tagNumber) { - case 0: - _keyIdentifier = Asn1Octet.getOctetStringFromObject(entry); - break; - case 1: - break; - case 2: - _serialNumber = DerInteger.getNumberFromTag(entry, false); - break; - default: - throw ArgumentError.value( - sequence, - 'sequence', - 'Invalid entry in sequence', - ); - } - } - }); - } - //Fields - Asn1Octet? _keyIdentifier; - DerInteger? _serialNumber; - //Properties - List? get keyID => _keyIdentifier?.getOctets(); - //Implementation - static _KeyIdentifier getKeyIdentifier(dynamic obj) { - _KeyIdentifier result; - if (obj is _KeyIdentifier) { - result = obj; - } else if (obj is Asn1Sequence) { - result = _KeyIdentifier(obj); - } else if (obj is X509Extension) { - result = getKeyIdentifier(X509Extension.convertValueToObject(obj)); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - return result; - } - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection(); - if (_keyIdentifier != null) { - collection.encodableObjects.add(DerTag(0, _keyIdentifier, false)); - } - if (_serialNumber != null) { - collection.encodableObjects.add(DerTag(2, _serialNumber, false)); - } - return DerSequence(collection: collection); - } - - @override - String toString() { - return 'AuthorityKeyIdentifier: KeyID(${String.fromCharCodes(_keyIdentifier!.getOctets()!)})'; - } -} - -class _DesEdeAlogorithm extends _DataEncryption { - _DesEdeAlogorithm() : super(); - List? _key1; - List? _key2; - List? _key3; - bool? _isEncryption; - - //Properties - @override - int? get blockSize => _blockSize; - @override - String get algorithmName => Asn1.desEde; - //Implementation - @override - void initialize(bool? forEncryption, ICipherParameter? parameters) { - if (parameters is! KeyParameter) { - throw ArgumentError.value(parameters, 'parameters', 'Invalid parameter'); - } - final List keyMaster = parameters.keys; - if (keyMaster.length != 24 && keyMaster.length != 16) { - throw ArgumentError.value( - parameters, - 'parameters', - 'Invalid key size. Size must be 16 or 24 bytes.', - ); - } - _isEncryption = forEncryption; - final List key1 = List.generate(8, (int i) => 0); - List.copyRange(key1, 0, keyMaster, 0, key1.length); - _key1 = generateWorkingKey(forEncryption, key1); - final List key2 = List.generate(8, (int i) => 0); - List.copyRange(key2, 0, keyMaster, 8, 8 + key2.length); - _key2 = generateWorkingKey(!forEncryption!, key2); - if (keyMaster.length == 24) { - final List key3 = List.generate(8, (int i) => 0); - List.copyRange(key3, 0, keyMaster, 16, 16 + key3.length); - _key3 = generateWorkingKey(forEncryption, key3); - } else { - _key3 = _key1; - } - } - - @override - Map processBlock([ - List? inputBytes, - int? inOffset, - List? outputBytes, - int? outOffset, - ]) { - ArgumentError.checkNotNull(_key1); - if ((inOffset! + _blockSize!) > inputBytes!.length) { - throw ArgumentError.value( - inOffset, - 'inOffset', - 'Invalid length in input bytes', - ); - } - if ((outOffset! + _blockSize!) > outputBytes!.length) { - throw ArgumentError.value( - inOffset, - 'inOffset', - 'Invalid length in output bytes', - ); - } - final List tempBytes = List.generate(_blockSize!, (int i) => 0); - if (_isEncryption!) { - encryptData(_key1, inputBytes, inOffset, tempBytes, 0); - encryptData(_key2, tempBytes, 0, tempBytes, 0); - encryptData(_key3, tempBytes, 0, outputBytes, outOffset); - } else { - encryptData(_key3, inputBytes, inOffset, tempBytes, 0); - encryptData(_key2, tempBytes, 0, tempBytes, 0); - encryptData(_key1, tempBytes, 0, outputBytes, outOffset); - } - return {'length': _blockSize, 'output': outputBytes}; - } - - @override - void reset() {} -} - -class _DataEncryption extends ICipher { - _DataEncryption() { - _blockSize = 8; - byteBit = [128, 64, 32, 16, 8, 4, 2, 1]; - bigByte = [ - 0x800000, - 0x400000, - 0x200000, - 0x100000, - 0x80000, - 0x40000, - 0x20000, - 0x10000, - 0x8000, - 0x4000, - 0x2000, - 0x1000, - 0x800, - 0x400, - 0x200, - 0x100, - 0x80, - 0x40, - 0x20, - 0x10, - 0x8, - 0x4, - 0x2, - 0x1, - ]; - pc1 = [ - 56, - 48, - 40, - 32, - 24, - 16, - 8, - 0, - 57, - 49, - 41, - 33, - 25, - 17, - 9, - 1, - 58, - 50, - 42, - 34, - 26, - 18, - 10, - 2, - 59, - 51, - 43, - 35, - 62, - 54, - 46, - 38, - 30, - 22, - 14, - 6, - 61, - 53, - 45, - 37, - 29, - 21, - 13, - 5, - 60, - 52, - 44, - 36, - 28, - 20, - 12, - 4, - 27, - 19, - 11, - 3, - ]; - toTrot = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]; - pc2 = [ - 13, - 16, - 10, - 23, - 0, - 4, - 2, - 27, - 14, - 5, - 20, - 9, - 22, - 18, - 11, - 3, - 25, - 7, - 15, - 6, - 26, - 19, - 12, - 1, - 40, - 51, - 30, - 36, - 46, - 54, - 29, - 39, - 50, - 44, - 32, - 47, - 43, - 48, - 38, - 55, - 33, - 52, - 45, - 41, - 49, - 35, - 28, - 31, - ]; - sp1 = [ - 0x01010400, - 0x00000000, - 0x00010000, - 0x01010404, - 0x01010004, - 0x00010404, - 0x00000004, - 0x00010000, - 0x00000400, - 0x01010400, - 0x01010404, - 0x00000400, - 0x01000404, - 0x01010004, - 0x01000000, - 0x00000004, - 0x00000404, - 0x01000400, - 0x01000400, - 0x00010400, - 0x00010400, - 0x01010000, - 0x01010000, - 0x01000404, - 0x00010004, - 0x01000004, - 0x01000004, - 0x00010004, - 0x00000000, - 0x00000404, - 0x00010404, - 0x01000000, - 0x00010000, - 0x01010404, - 0x00000004, - 0x01010000, - 0x01010400, - 0x01000000, - 0x01000000, - 0x00000400, - 0x01010004, - 0x00010000, - 0x00010400, - 0x01000004, - 0x00000400, - 0x00000004, - 0x01000404, - 0x00010404, - 0x01010404, - 0x00010004, - 0x01010000, - 0x01000404, - 0x01000004, - 0x00000404, - 0x00010404, - 0x01010400, - 0x00000404, - 0x01000400, - 0x01000400, - 0x00000000, - 0x00010004, - 0x00010400, - 0x00000000, - 0x01010004, - ]; - sp2 = [ - 0x80108020, - 0x80008000, - 0x00008000, - 0x00108020, - 0x00100000, - 0x00000020, - 0x80100020, - 0x80008020, - 0x80000020, - 0x80108020, - 0x80108000, - 0x80000000, - 0x80008000, - 0x00100000, - 0x00000020, - 0x80100020, - 0x00108000, - 0x00100020, - 0x80008020, - 0x00000000, - 0x80000000, - 0x00008000, - 0x00108020, - 0x80100000, - 0x00100020, - 0x80000020, - 0x00000000, - 0x00108000, - 0x00008020, - 0x80108000, - 0x80100000, - 0x00008020, - 0x00000000, - 0x00108020, - 0x80100020, - 0x00100000, - 0x80008020, - 0x80100000, - 0x80108000, - 0x00008000, - 0x80100000, - 0x80008000, - 0x00000020, - 0x80108020, - 0x00108020, - 0x00000020, - 0x00008000, - 0x80000000, - 0x00008020, - 0x80108000, - 0x00100000, - 0x80000020, - 0x00100020, - 0x80008020, - 0x80000020, - 0x00100020, - 0x00108000, - 0x00000000, - 0x80008000, - 0x00008020, - 0x80000000, - 0x80100020, - 0x80108020, - 0x00108000, - ]; - sp3 = [ - 0x00000208, - 0x08020200, - 0x00000000, - 0x08020008, - 0x08000200, - 0x00000000, - 0x00020208, - 0x08000200, - 0x00020008, - 0x08000008, - 0x08000008, - 0x00020000, - 0x08020208, - 0x00020008, - 0x08020000, - 0x00000208, - 0x08000000, - 0x00000008, - 0x08020200, - 0x00000200, - 0x00020200, - 0x08020000, - 0x08020008, - 0x00020208, - 0x08000208, - 0x00020200, - 0x00020000, - 0x08000208, - 0x00000008, - 0x08020208, - 0x00000200, - 0x08000000, - 0x08020200, - 0x08000000, - 0x00020008, - 0x00000208, - 0x00020000, - 0x08020200, - 0x08000200, - 0x00000000, - 0x00000200, - 0x00020008, - 0x08020208, - 0x08000200, - 0x08000008, - 0x00000200, - 0x00000000, - 0x08020008, - 0x08000208, - 0x00020000, - 0x08000000, - 0x08020208, - 0x00000008, - 0x00020208, - 0x00020200, - 0x08000008, - 0x08020000, - 0x08000208, - 0x00000208, - 0x08020000, - 0x00020208, - 0x00000008, - 0x08020008, - 0x00020200, - ]; - sp4 = [ - 0x00802001, - 0x00002081, - 0x00002081, - 0x00000080, - 0x00802080, - 0x00800081, - 0x00800001, - 0x00002001, - 0x00000000, - 0x00802000, - 0x00802000, - 0x00802081, - 0x00000081, - 0x00000000, - 0x00800080, - 0x00800001, - 0x00000001, - 0x00002000, - 0x00800000, - 0x00802001, - 0x00000080, - 0x00800000, - 0x00002001, - 0x00002080, - 0x00800081, - 0x00000001, - 0x00002080, - 0x00800080, - 0x00002000, - 0x00802080, - 0x00802081, - 0x00000081, - 0x00800080, - 0x00800001, - 0x00802000, - 0x00802081, - 0x00000081, - 0x00000000, - 0x00000000, - 0x00802000, - 0x00002080, - 0x00800080, - 0x00800081, - 0x00000001, - 0x00802001, - 0x00002081, - 0x00002081, - 0x00000080, - 0x00802081, - 0x00000081, - 0x00000001, - 0x00002000, - 0x00800001, - 0x00002001, - 0x00802080, - 0x00800081, - 0x00002001, - 0x00002080, - 0x00800000, - 0x00802001, - 0x00000080, - 0x00800000, - 0x00002000, - 0x00802080, - ]; - sp5 = [ - 0x00000100, - 0x02080100, - 0x02080000, - 0x42000100, - 0x00080000, - 0x00000100, - 0x40000000, - 0x02080000, - 0x40080100, - 0x00080000, - 0x02000100, - 0x40080100, - 0x42000100, - 0x42080000, - 0x00080100, - 0x40000000, - 0x02000000, - 0x40080000, - 0x40080000, - 0x00000000, - 0x40000100, - 0x42080100, - 0x42080100, - 0x02000100, - 0x42080000, - 0x40000100, - 0x00000000, - 0x42000000, - 0x02080100, - 0x02000000, - 0x42000000, - 0x00080100, - 0x00080000, - 0x42000100, - 0x00000100, - 0x02000000, - 0x40000000, - 0x02080000, - 0x42000100, - 0x40080100, - 0x02000100, - 0x40000000, - 0x42080000, - 0x02080100, - 0x40080100, - 0x00000100, - 0x02000000, - 0x42080000, - 0x42080100, - 0x00080100, - 0x42000000, - 0x42080100, - 0x02080000, - 0x00000000, - 0x40080000, - 0x42000000, - 0x00080100, - 0x02000100, - 0x40000100, - 0x00080000, - 0x00000000, - 0x40080000, - 0x02080100, - 0x40000100, - ]; - sp6 = [ - 0x20000010, - 0x20400000, - 0x00004000, - 0x20404010, - 0x20400000, - 0x00000010, - 0x20404010, - 0x00400000, - 0x20004000, - 0x00404010, - 0x00400000, - 0x20000010, - 0x00400010, - 0x20004000, - 0x20000000, - 0x00004010, - 0x00000000, - 0x00400010, - 0x20004010, - 0x00004000, - 0x00404000, - 0x20004010, - 0x00000010, - 0x20400010, - 0x20400010, - 0x00000000, - 0x00404010, - 0x20404000, - 0x00004010, - 0x00404000, - 0x20404000, - 0x20000000, - 0x20004000, - 0x00000010, - 0x20400010, - 0x00404000, - 0x20404010, - 0x00400000, - 0x00004010, - 0x20000010, - 0x00400000, - 0x20004000, - 0x20000000, - 0x00004010, - 0x20000010, - 0x20404010, - 0x00404000, - 0x20400000, - 0x00404010, - 0x20404000, - 0x00000000, - 0x20400010, - 0x00000010, - 0x00004000, - 0x20400000, - 0x00404010, - 0x00004000, - 0x00400010, - 0x20004010, - 0x00000000, - 0x20404000, - 0x20000000, - 0x00400010, - 0x20004010, - ]; - sp7 = [ - 0x00200000, - 0x04200002, - 0x04000802, - 0x00000000, - 0x00000800, - 0x04000802, - 0x00200802, - 0x04200800, - 0x04200802, - 0x00200000, - 0x00000000, - 0x04000002, - 0x00000002, - 0x04000000, - 0x04200002, - 0x00000802, - 0x04000800, - 0x00200802, - 0x00200002, - 0x04000800, - 0x04000002, - 0x04200000, - 0x04200800, - 0x00200002, - 0x04200000, - 0x00000800, - 0x00000802, - 0x04200802, - 0x00200800, - 0x00000002, - 0x04000000, - 0x00200800, - 0x04000000, - 0x00200800, - 0x00200000, - 0x04000802, - 0x04000802, - 0x04200002, - 0x04200002, - 0x00000002, - 0x00200002, - 0x04000000, - 0x04000800, - 0x00200000, - 0x04200800, - 0x00000802, - 0x00200802, - 0x04200800, - 0x00000802, - 0x04000002, - 0x04200802, - 0x04200000, - 0x00200800, - 0x00000000, - 0x00000002, - 0x04200802, - 0x00000000, - 0x00200802, - 0x04200000, - 0x00000800, - 0x04000002, - 0x04000800, - 0x00000800, - 0x00200002, - ]; - sp8 = [ - 0x10001040, - 0x00001000, - 0x00040000, - 0x10041040, - 0x10000000, - 0x10001040, - 0x00000040, - 0x10000000, - 0x00040040, - 0x10040000, - 0x10041040, - 0x00041000, - 0x10041000, - 0x00041040, - 0x00001000, - 0x00000040, - 0x10040000, - 0x10000040, - 0x10001000, - 0x00001040, - 0x00041000, - 0x00040040, - 0x10040040, - 0x10041000, - 0x00001040, - 0x00000000, - 0x00000000, - 0x10040040, - 0x10000040, - 0x10001000, - 0x00041040, - 0x00040000, - 0x00041040, - 0x00040000, - 0x10041000, - 0x00001000, - 0x00000040, - 0x10040040, - 0x00001000, - 0x00041040, - 0x10001000, - 0x00000040, - 0x10000040, - 0x10040000, - 0x10040040, - 0x10000000, - 0x00040000, - 0x10001040, - 0x00000000, - 0x10041040, - 0x00040040, - 0x10000040, - 0x10040000, - 0x10001000, - 0x10001040, - 0x00000000, - 0x10041040, - 0x00041000, - 0x00041000, - 0x00001040, - 0x00001040, - 0x00040040, - 0x10000000, - 0x10041000, - ]; - } - - //Fields - int? _blockSize; - late List byteBit; - late List bigByte; - late List pc1; - late List toTrot; - late List pc2; - late List sp1; - late List sp2; - late List sp3; - late List sp4; - late List sp5; - late List sp6; - late List sp7; - late List sp8; - List? _keys; - - //Properties - List? get keys => _keys; - @override - String get algorithmName => Asn1.des; - @override - bool get isBlock => false; - @override - int? get blockSize => _blockSize; - - //Implementation - @override - void initialize(bool? isEncryption, ICipherParameter? parameters) { - if (parameters is! KeyParameter) { - throw ArgumentError.value(parameters, 'parameters', 'Invalid parameter'); - } - _keys = generateWorkingKey(isEncryption, parameters.keys); - } - - @override - Map processBlock( - List? inBytes, - int inOffset, - List? outBytes, - int? outOffset, - ) { - ArgumentError.checkNotNull(_keys); - if ((inOffset + _blockSize!) > inBytes!.length) { - throw ArgumentError.value( - inOffset, - 'inOffset', - 'Invalid length in input bytes', - ); - } - if ((outOffset! + _blockSize!) > outBytes!.length) { - throw ArgumentError.value( - outOffset, - 'outOffset', - 'Invalid length in output bytes', - ); - } - encryptData(_keys, inBytes, inOffset, outBytes, outOffset); - return {'length': _blockSize, 'output': outBytes}; - } - - @override - void reset() {} - List generateWorkingKey(bool? isEncrypt, List bytes) { - final List newKeys = List.generate(32, (int i) => 0); - final List bytes1 = List.generate(56, (int i) => false); - final List bytes2 = List.generate(56, (int i) => false); - for (int j = 0; j < 56; j++) { - final int length = pc1[j]; - bytes1[j] = - (bytes[length.toUnsigned(32) >> 3] & byteBit[length & 07]) != 0; - } - for (int i = 0; i < 16; i++) { - int a; - int b; - int c; - if (isEncrypt!) { - b = i << 1; - } else { - b = (15 - i) << 1; - } - c = b + 1; - newKeys[b] = newKeys[c] = 0; - for (int j = 0; j < 28; j++) { - a = j + toTrot[i]; - if (a < 28) { - bytes2[j] = bytes1[a]; - } else { - bytes2[j] = bytes1[a - 28]; - } - } - for (int j = 28; j < 56; j++) { - a = j + toTrot[i]; - if (a < 56) { - bytes2[j] = bytes1[a]; - } else { - bytes2[j] = bytes1[a - 28]; - } - } - for (int j = 0; j < 24; j++) { - if (bytes2[pc2[j]]) { - newKeys[b] |= bigByte[j]; - } - if (bytes2[pc2[j + 24]]) { - newKeys[c] |= bigByte[j]; - } - } - } - for (int i = 0; i != 32; i += 2) { - int value1, value2; - value1 = newKeys[i]; - value2 = newKeys[i + 1]; - newKeys[i] = (((value1 & 0x00fc0000) << 6).toUnsigned(32) | - ((value1 & 0x00000fc0) << 10).toUnsigned(32) | - ((value2 & 0x00fc0000).toUnsigned(32) >> 10) | - ((value2 & 0x00000fc0).toUnsigned(32) >> 6)) - .toSigned(32); - newKeys[i + 1] = (((value1 & 0x0003f000) << 12).toUnsigned(32) | - ((value1 & 0x0000003f) << 16).toUnsigned(32) | - ((value2 & 0x0003f000).toUnsigned(32) >> 4) | - (value2 & 0x0000003f).toUnsigned(32)) - .toSigned(32); - } - return newKeys; - } - - void encryptData( - List? keys, - List inputBytes, - int inOffset, - List outBytes, - int outOffset, - ) { - int left = Asn1.beToUInt32(inputBytes, inOffset); - int right = Asn1.beToUInt32(inputBytes, inOffset + 4); - int data = (((left >> 4) ^ right) & 0x0f0f0f0f).toUnsigned(32); - right ^= data; - left ^= data << 4; - data = ((left >> 16) ^ right) & 0x0000ffff; - right ^= data; - left ^= data << 16; - data = ((right >> 2) ^ left) & 0x33333333; - left ^= data; - right ^= data << 2; - data = ((right >> 8) ^ left) & 0x00ff00ff; - left ^= data; - right ^= data << 8; - right = ((right << 1) | (right >> 31)).toUnsigned(32); - data = (left ^ right) & 0xaaaaaaaa; - left ^= data; - right ^= data; - left = ((left << 1) | (left >> 31)).toUnsigned(32); - for (int round = 0; round < 8; round++) { - data = ((right << 28) | (right >> 4)).toUnsigned(32); - data ^= keys![round * 4 + 0].toUnsigned(32); - int value = sp7[data & 0x3f]; - value |= sp5[(data >> 8) & 0x3f]; - value |= sp3[(data >> 16) & 0x3f]; - value |= sp1[(data >> 24) & 0x3f]; - data = right ^ keys[round * 4 + 1].toUnsigned(32); - value |= sp8[data & 0x3f]; - value |= sp6[(data >> 8) & 0x3f]; - value |= sp4[(data >> 16) & 0x3f]; - value |= sp2[(data >> 24) & 0x3f]; - left ^= value; - data = ((left << 28) | (left >> 4)).toUnsigned(32); - data ^= keys[round * 4 + 2].toUnsigned(32); - value = sp7[data & 0x3f]; - value |= sp5[(data >> 8) & 0x3f]; - value |= sp3[(data >> 16) & 0x3f]; - value |= sp1[(data >> 24) & 0x3f]; - data = left ^ keys[round * 4 + 3].toUnsigned(32); - value |= sp8[data & 0x3f]; - value |= sp6[(data >> 8) & 0x3f]; - value |= sp4[(data >> 16) & 0x3f]; - value |= sp2[(data >> 24) & 0x3f]; - right ^= value; - } - right = ((right << 31) | (right >> 1)).toUnsigned(32); - data = (left ^ right) & 0xaaaaaaaa; - left ^= data; - right ^= data; - left = ((left << 31) | (left >> 1)).toUnsigned(32); - data = ((left >> 8) ^ right) & 0x00ff00ff; - right ^= data; - left ^= data << 8; - data = ((left >> 2) ^ right) & 0x33333333; - right ^= data; - left ^= data << 2; - data = ((right >> 16) ^ left) & 0x0000ffff; - left ^= data; - right ^= data << 16; - data = ((right >> 4) ^ left) & 0x0f0f0f0f; - left ^= data; - right ^= data << 4; - Asn1.uInt32ToBe(right, outBytes, outOffset); - Asn1.uInt32ToBe(left, outBytes, outOffset + 4); - } -} - -class _Rc2Algorithm extends ICipher { - _Rc2Algorithm() { - _piTable = [ - 217, - 120, - 249, - 196, - 25, - 221, - 181, - 237, - 40, - 233, - 253, - 121, - 74, - 160, - 216, - 157, - 198, - 126, - 55, - 131, - 43, - 118, - 83, - 142, - 98, - 76, - 100, - 136, - 68, - 139, - 251, - 162, - 23, - 154, - 89, - 245, - 135, - 179, - 79, - 19, - 97, - 69, - 109, - 141, - 9, - 129, - 125, - 50, - 189, - 143, - 64, - 235, - 134, - 183, - 123, - 11, - 240, - 149, - 33, - 34, - 92, - 107, - 78, - 130, - 84, - 214, - 101, - 147, - 206, - 96, - 178, - 28, - 115, - 86, - 192, - 20, - 167, - 140, - 241, - 220, - 18, - 117, - 202, - 31, - 59, - 190, - 228, - 209, - 66, - 61, - 212, - 48, - 163, - 60, - 182, - 38, - 111, - 191, - 14, - 218, - 70, - 105, - 7, - 87, - 39, - 242, - 29, - 155, - 188, - 148, - 67, - 3, - 248, - 17, - 199, - 246, - 144, - 239, - 62, - 231, - 6, - 195, - 213, - 47, - 200, - 102, - 30, - 215, - 8, - 232, - 234, - 222, - 128, - 82, - 238, - 247, - 132, - 170, - 114, - 172, - 53, - 77, - 106, - 42, - 150, - 26, - 210, - 113, - 90, - 21, - 73, - 116, - 75, - 159, - 208, - 94, - 4, - 24, - 164, - 236, - 194, - 224, - 65, - 110, - 15, - 81, - 203, - 204, - 36, - 145, - 175, - 80, - 161, - 244, - 112, - 57, - 153, - 124, - 58, - 133, - 35, - 184, - 180, - 122, - 252, - 2, - 54, - 91, - 37, - 85, - 151, - 49, - 45, - 93, - 250, - 152, - 227, - 138, - 146, - 174, - 5, - 223, - 41, - 16, - 103, - 108, - 186, - 201, - 211, - 0, - 230, - 207, - 225, - 158, - 168, - 44, - 99, - 22, - 1, - 63, - 88, - 226, - 137, - 169, - 13, - 56, - 52, - 27, - 171, - 51, - 255, - 176, - 187, - 72, - 12, - 95, - 185, - 177, - 205, - 46, - 197, - 243, - 219, - 71, - 229, - 165, - 156, - 119, - 10, - 166, - 32, - 104, - 254, - 127, - 193, - 173, - ]; - _blockSize = 8; - } - //Fields - int? _blockSize; - late List _key; - bool? _isEncrypt; - late List _piTable; - - //Properties - @override - String get algorithmName => 'RC2'; - @override - bool get isBlock => false; - @override - int? get blockSize => _blockSize; - - //Implementation - List generateKey(List key, int bits) { - int x; - final List xKey = List.generate(128, (int i) => 0); - for (int i = 0; i != key.length; i++) { - xKey[i] = key[i] & 0xff; - } - int len = key.length; - if (len < 128) { - int index = 0; - x = xKey[len - 1]; - do { - x = _piTable[(x + xKey[index++]) & 255] & 0xff; - xKey[len++] = x; - } while (len < 128); - } - len = (bits + 7) >> 3; - x = _piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff; - xKey[128 - len] = x; - for (int i = 128 - len - 1; i >= 0; i--) { - x = _piTable[x ^ xKey[i + len]] & 0xff; - xKey[i] = x; - } - final List newKey = []; - for (int i = 0; i < 64; i++) { - newKey.add(xKey[2 * i] + (xKey[2 * i + 1] << 8)); - } - return newKey; - } - - @override - void initialize(bool? forEncryption, ICipherParameter? parameters) { - _isEncrypt = forEncryption; - if (parameters is KeyParameter) { - final List key = parameters.keys; - _key = generateKey(key, key.length * 8); - } - } - - @override - void reset() {} - - @override - Map processBlock( - List? input, - int inOff, - List? output, - int? outOff, - ) { - if (_isEncrypt!) { - encryptBlock(input!, inOff, output!, outOff!); - } else { - decryptBlock(input!, inOff, output!, outOff!); - } - return {'length': _blockSize, 'output': output}; - } - - int rotateWordLeft(int x, int y) { - x &= 0xffff; - return (x << y) | (x >> (16 - y)); - } - - void encryptBlock( - List input, - int inOff, - List outBytes, - int outOff, - ) { - int x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff); - int x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff); - int x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff); - int x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff); - for (int i = 0; i <= 16; i += 4) { - x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + _key[i], 1); - x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + _key[i + 1], 2); - x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + _key[i + 2], 3); - x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + _key[i + 3], 5); - } - x10 += _key[x76 & 63]; - x32 += _key[x10 & 63]; - x54 += _key[x32 & 63]; - x76 += _key[x54 & 63]; - for (int i = 20; i <= 40; i += 4) { - x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + _key[i], 1); - x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + _key[i + 1], 2); - x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + _key[i + 2], 3); - x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + _key[i + 3], 5); - } - x10 += _key[x76 & 63]; - x32 += _key[x10 & 63]; - x54 += _key[x32 & 63]; - x76 += _key[x54 & 63]; - for (int i = 44; i < 64; i += 4) { - x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + _key[i], 1); - x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + _key[i + 1], 2); - x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + _key[i + 2], 3); - x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + _key[i + 3], 5); - } - outBytes[outOff + 0] = x10.toUnsigned(8); - outBytes[outOff + 1] = (x10 >> 8).toUnsigned(8); - outBytes[outOff + 2] = x32.toUnsigned(8); - outBytes[outOff + 3] = (x32 >> 8).toUnsigned(8); - outBytes[outOff + 4] = x54.toUnsigned(8); - outBytes[outOff + 5] = (x54 >> 8).toUnsigned(8); - outBytes[outOff + 6] = x76.toUnsigned(8); - outBytes[outOff + 7] = (x76 >> 8).toUnsigned(8); - } - - void decryptBlock( - List input, - int inOff, - List outBytes, - int outOff, - ) { - int x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff); - int x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff); - int x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff); - int x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff); - for (int i = 60; i >= 44; i -= 4) { - x76 = - rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + _key[i + 3]); - x54 = - rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + _key[i + 2]); - x32 = - rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + _key[i + 1]); - x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + _key[i]); - } - x76 -= _key[x54 & 63]; - x54 -= _key[x32 & 63]; - x32 -= _key[x10 & 63]; - x10 -= _key[x76 & 63]; - for (int i = 40; i >= 20; i -= 4) { - x76 = - rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + _key[i + 3]); - x54 = - rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + _key[i + 2]); - x32 = - rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + _key[i + 1]); - x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + _key[i]); - } - x76 -= _key[x54 & 63]; - x54 -= _key[x32 & 63]; - x32 -= _key[x10 & 63]; - x10 -= _key[x76 & 63]; - for (int i = 16; i >= 0; i -= 4) { - x76 = - rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + _key[i + 3]); - x54 = - rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + _key[i + 2]); - x32 = - rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + _key[i + 1]); - x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + _key[i]); - } - outBytes[outOff + 0] = x10.toUnsigned(8); - outBytes[outOff + 1] = (x10 >> 8).toUnsigned(8); - outBytes[outOff + 2] = x32.toUnsigned(8); - outBytes[outOff + 3] = (x32 >> 8).toUnsigned(8); - outBytes[outOff + 4] = x54.toUnsigned(8); - outBytes[outOff + 5] = (x54 >> 8).toUnsigned(8); - outBytes[outOff + 6] = x76.toUnsigned(8); - outBytes[outOff + 7] = (x76 >> 8).toUnsigned(8); - } -} - -class _PfxData extends Asn1Encode { - _PfxData(Asn1Sequence sequence) { - _contentInformation = _ContentInformation.getInformation(sequence[1]); - if (sequence.count == 3) { - _macInformation = _MacInformation.getInformation(sequence[2]); - } - } - _ContentInformation? _contentInformation; - _MacInformation? _macInformation; - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection([ - DerInteger(bigIntToBytes(BigInt.from(3))), - _contentInformation, - ]); - if (_macInformation != null) { - collection.encodableObjects.add(_macInformation); - } - return BerSequence(collection: collection); - } -} - -class _ContentInformation extends Asn1Encode { - _ContentInformation(Asn1Sequence sequence) { - if (sequence.count < 1 || sequence.count > 2) { - throw ArgumentError.value( - sequence, - 'sequence', - 'Invalid length in sequence', - ); - } - _contentType = sequence[0] as DerObjectID?; - if (sequence.count > 1) { - final Asn1Tag tagged = sequence[1]! as Asn1Tag; - if (!tagged.explicit! || tagged.tagNumber != 0) { - throw ArgumentError.value(tagged, 'tagged', 'Invalid tag'); - } - _content = tagged.getObject(); - } - } - //Fields - DerObjectID? _contentType; - Asn1Encode? _content; - //Implementation - static _ContentInformation? getInformation(dynamic obj) { - _ContentInformation? result; - if (obj == null || obj is _ContentInformation) { - result = obj as _ContentInformation?; - } else if (obj is Asn1Sequence) { - result = _ContentInformation(obj); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - return result; - } - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection([ - _contentType, - ]); - if (_content != null) { - collection.encodableObjects.add(DerTag(0, _content)); - } - return BerSequence(collection: collection); - } -} - -class _MacInformation extends Asn1Encode { - _MacInformation(Asn1Sequence sequence) { - _digest = DigestInformation.getDigestInformation(sequence[0]); - _value = (sequence[1]! as Asn1Octet).getOctets(); - if (sequence.count == 3) { - _count = (sequence[2]! as DerInteger).value; - } else { - _count = BigInt.one; - } - } - //Fields - DigestInformation? _digest; - List? _value; - BigInt? _count; - //Implementation - static _MacInformation getInformation(dynamic obj) { - _MacInformation result; - if (obj is _MacInformation) { - result = obj; - } else if (obj is Asn1Sequence) { - result = _MacInformation(obj); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - return result; - } - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection([ - _digest, - DerOctet(_value!), - ]); - if (_count != BigInt.one) { - collection.encodableObjects.add(DerInteger.fromNumber(_count)); - } - return DerSequence(collection: collection); - } -} - -class EncryptedPrivateKey extends Asn1Encode { - EncryptedPrivateKey(Asn1Sequence sequence) { - if (sequence.count != 2) { - throw ArgumentError.value( - sequence, - 'sequence', - 'Invalid length in sequence', - ); - } - _algorithms = Algorithms.getAlgorithms(sequence[0]); - _octet = Asn1Octet.getOctetStringFromObject(sequence[1]); - } - - //Fields - Algorithms? _algorithms; - Asn1Octet? _octet; - - //Implementation - @override - Asn1 getAsn1() { - return DerSequence(array: [_algorithms, _octet]); - } - - static EncryptedPrivateKey getEncryptedPrivateKeyInformation(dynamic obj) { - if (obj is EncryptedPrivateKey) { - return obj; - } - if (obj is Asn1Sequence) { - return EncryptedPrivateKey(obj); - } - throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); - } -} - -class KeyInformation extends Asn1Encode { - KeyInformation( - Algorithms algorithms, - Asn1 privateKey, [ - Asn1Set? attributes, - ]) { - _privateKey = privateKey; - _algorithms = algorithms; - if (attributes != null) { - _attributes = attributes; - } - } - KeyInformation.fromSequence(Asn1Sequence? sequence) { - if (sequence != null) { - final List objects = sequence.objects!; - if (objects.length >= 3) { - _algorithms = Algorithms.getAlgorithms(objects[1]); - final dynamic privateKeyValue = objects[2]; - try { - _privateKey = - Asn1Stream( - PdfStreamReader(privateKeyValue.getOctets()), - ).readAsn1(); - } catch (e) { - throw ArgumentError.value(sequence, 'sequence', 'Invalid sequence'); - } - if (objects.length > 3) { - _attributes = Asn1Set.getAsn1Set(objects[3]! as Asn1Tag?, false); - } - } else { - throw ArgumentError.value(sequence, 'sequence', 'Invalid sequence'); - } - } - } - - //Fields - Asn1? _privateKey; - Algorithms? _algorithms; - Asn1Set? _attributes; - - //Implementation - static KeyInformation? getInformation(dynamic obj) { - if (obj is KeyInformation) { - return obj; - } - if (obj != null) { - return KeyInformation.fromSequence(Asn1Sequence.getSequence(obj)); - } - return null; - } - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection v = Asn1EncodeCollection([ - DerInteger.fromNumber(BigInt.from(0)), - _algorithms, - DerOctet.fromObject(_privateKey!), - ]); - if (_attributes != null) { - v.encodableObjects.add(DerTag(0, _attributes, false)); - } - return DerSequence(collection: v); - } -} - -class _RsaKey extends Asn1Encode { - _RsaKey( - BigInt modulus, - BigInt publicExponent, - BigInt privateExponent, - BigInt prime1, - BigInt prime2, - BigInt exponent1, - BigInt exponent2, - BigInt coefficient, - ) { - _modulus = modulus; - _publicExponent = publicExponent; - _privateExponent = privateExponent; - _prime1 = prime1; - _prime2 = prime2; - _exponent1 = exponent1; - _exponent2 = exponent2; - _coefficient = coefficient; - } - _RsaKey.fromSequence(Asn1Sequence sequence) { - final BigInt version = (sequence[0]! as DerInteger).value; - if (version.toSigned(32).toInt() != 0) { - throw ArgumentError.value(sequence, 'sequence', 'Invalid RSA key'); - } - _modulus = (sequence[1]! as DerInteger).value; - _publicExponent = (sequence[2]! as DerInteger).value; - _privateExponent = (sequence[3]! as DerInteger).value; - _prime1 = (sequence[4]! as DerInteger).value; - _prime2 = (sequence[5]! as DerInteger).value; - _exponent1 = (sequence[6]! as DerInteger).value; - _exponent2 = (sequence[7]! as DerInteger).value; - _coefficient = (sequence[8]! as DerInteger).value; - } - BigInt? _modulus; - BigInt? _publicExponent; - BigInt? _privateExponent; - BigInt? _prime1; - BigInt? _prime2; - BigInt? _exponent1; - BigInt? _exponent2; - BigInt? _coefficient; - @override - Asn1 getAsn1() { - return DerSequence( - array: [ - DerInteger.fromNumber(BigInt.from(0)), - DerInteger.fromNumber(_modulus), - DerInteger.fromNumber(_publicExponent), - DerInteger.fromNumber(_privateExponent), - DerInteger.fromNumber(_prime1), - DerInteger.fromNumber(_prime2), - DerInteger.fromNumber(_exponent1), - DerInteger.fromNumber(_exponent2), - DerInteger.fromNumber(_coefficient), - ], - ); - } -} - -class SubjectKeyID extends Asn1Encode { - SubjectKeyID(dynamic obj) { - if (obj is Asn1Octet) { - _bytes = obj.getOctets(); - } else if (obj is PublicKeyInformation) { - _bytes = getDigest(obj); - } - } - - List? _bytes; - //Implementation - static List getDigest(PublicKeyInformation publicKey) { - return sha1.convert(publicKey.publicKey!.data!).bytes; - } - - /// internal method - static PublicKeyInformation createSubjectKeyID(CipherParameter publicKey) { - if (publicKey is RsaKeyParam) { - final PublicKeyInformation information = PublicKeyInformation( - Algorithms(PkcsObjectId.rsaEncryption, DerNull.value), - RsaPublicKey(publicKey.modulus, publicKey.exponent).getAsn1(), - ); - return information; - } else { - throw ArgumentError.value(publicKey, 'publicKey', 'Invalid Key'); - } - } - - @override - Asn1 getAsn1() { - return DerOctet(_bytes!); - } -} - -/// Internal class -class CertificateIdentity { - /// Internal constructor - CertificateIdentity( - String hashAlgorithm, - X509Certificate issuerCert, - DerInteger serialNumber, - ) { - final Algorithms algorithms = Algorithms( - DerObjectID(hashAlgorithm), - DerNull.value, - ); - try { - final String algorithm = algorithms.id!.id!; - final X509Name? issuerName = - SingnedCertificate.getCertificate( - Asn1.fromByteArray(issuerCert.getTbsCertificate()!), - )!.subject; - MessageDigestFinder utilities = MessageDigestFinder(); - final List issuerNameHash = utilities.getDigest( - algorithm, - issuerName!.getEncoded()!, - ); - final CipherParameter issuerKey = issuerCert.getPublicKey(); - final PublicKeyInformation info = SubjectKeyID.createSubjectKeyID( - issuerKey, - ); - utilities = MessageDigestFinder(); - final List issuerKeyHash = utilities.getDigest( - algorithm, - info.publicKey!.getBytes()!, - ); - id = CertificateIdentityHelper( - hash: algorithms, - issuerName: DerOctet(issuerNameHash), - issuerKey: DerOctet(issuerKeyHash), - serialNumber: serialNumber, - ); - } catch (e) { - throw Exception('Invalid certificate ID'); - } - } - - /// Internal field - CertificateIdentityHelper? id; - - /// Internal constant - static const String sha1 = '1.3.14.3.2.26'; -} - -/// Internal class -class CertificateIdentityHelper extends Asn1Encode { - /// Internal constructor - CertificateIdentityHelper({ - Algorithms? hash, - Asn1Octet? issuerName, - Asn1Octet? issuerKey, - DerInteger? serialNumber, - }) { - _hash = hash; - _issuerName = issuerName; - _issuerKey = issuerKey; - _serialNumber = serialNumber; - } - - /// Internal field - Algorithms? _hash; - Asn1Octet? _issuerName; - Asn1Octet? _issuerKey; - DerInteger? _serialNumber; - - @override - Asn1 getAsn1() { - return DerSequence( - array: [_hash!, _issuerName!, _issuerKey!, _serialNumber!], - ); - } -} +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; + +import '../../io/decode_big_endian.dart'; +import '../../io/stream_reader.dart'; +import '../../primitives/pdf_string.dart'; +import 'asn1/asn1.dart'; +import 'asn1/asn1_stream.dart'; +import 'asn1/ber.dart'; +import 'asn1/der.dart'; +import 'cryptography/buffered_block_padding_base.dart'; +import 'cryptography/cipher_block_chaining_mode.dart'; +import 'cryptography/cipher_utils.dart'; +import 'cryptography/ipadding.dart'; +import 'cryptography/message_digest_utils.dart'; +import 'cryptography/pkcs1_encoding.dart'; +import 'cryptography/rsa_algorithm.dart'; +import 'cryptography/signature_utilities.dart'; +import 'pkcs/password_utility.dart'; +import 'pkcs/pfx_data.dart'; +import 'x509/x509_certificates.dart'; +import 'x509/x509_name.dart'; + +/// internal class +class PdfPKCSCertificate { + /// internal constructor + PdfPKCSCertificate(List certificateBytes, String password) { + _keys = _CertificateTable(); + _certificates = _CertificateTable(); + _localIdentifiers = {}; + _chainCertificates = <_CertificateIdentifier, X509Certificates>{}; + _keyCertificates = {}; + _loadCertificate(certificateBytes, password); + } + + //Fields + late _CertificateTable _keys; + late _CertificateTable _certificates; + late Map _localIdentifiers; + late Map<_CertificateIdentifier, X509Certificates> _chainCertificates; + late Map _keyCertificates; + + //Implementation + void _loadCertificate(List certificateBytes, String password) { + final Asn1Sequence sequence = + Asn1Stream(PdfStreamReader(certificateBytes)).readAsn1()! + as Asn1Sequence; + final _PfxData pfxData = _PfxData(sequence); + final _ContentInformation information = pfxData._contentInformation!; + bool isUnmarkedKey = false; + final bool isInvalidPassword = password.isEmpty; + final List certificateChain = + []; + if (information._contentType!.id == PkcsObjectId.data.id) { + final List? octs = (information._content! as Asn1Octet).getOctets(); + final Asn1Sequence asn1Sequence = + Asn1Stream(PdfStreamReader(octs)).readAsn1()! as Asn1Sequence; + final List<_ContentInformation?> contentInformation = + <_ContentInformation?>[]; + for (int i = 0; i < asn1Sequence.count; i++) { + contentInformation.add( + _ContentInformation.getInformation(asn1Sequence[i]), + ); + } + // ignore: avoid_function_literals_in_foreach_calls + contentInformation.forEach((_ContentInformation? entry) { + final DerObjectID type = entry!._contentType!; + if (type.id == PkcsObjectId.data.id) { + final List? octets = (entry._content! as Asn1Octet).getOctets(); + final Asn1Sequence asn1SubSequence = + Asn1Stream(PdfStreamReader(octets)).readAsn1()! as Asn1Sequence; + for (int index = 0; index < asn1SubSequence.count; index++) { + final dynamic subSequence = asn1SubSequence[index]; + if (subSequence != null && subSequence is Asn1Sequence) { + final Asn1SequenceCollection subSequenceCollection = + Asn1SequenceCollection(subSequence); + if (subSequenceCollection.id!.id == + PkcsObjectId.pkcs8ShroudedKeyBag.id) { + final EncryptedPrivateKey encryptedInformation = + EncryptedPrivateKey.getEncryptedPrivateKeyInformation( + subSequenceCollection.value, + ); + final KeyInformation privateKeyInformation = + createPrivateKeyInfo( + password, + isInvalidPassword, + encryptedInformation, + )!; + RsaPrivateKeyParam? rsaparam; + if (privateKeyInformation._algorithms!.id!.id == + PkcsObjectId.rsaEncryption.id || + privateKeyInformation._algorithms!.id!.id == + X509Objects.idEARsa.id) { + final _RsaKey keyStructure = _RsaKey.fromSequence( + Asn1Sequence.getSequence( + privateKeyInformation._privateKey, + )!, + ); + rsaparam = RsaPrivateKeyParam( + keyStructure._modulus, + keyStructure._publicExponent, + keyStructure._privateExponent, + keyStructure._prime1, + keyStructure._prime2, + keyStructure._exponent1, + keyStructure._exponent2, + keyStructure._coefficient, + ); + } + final CipherParameter? privateKey = rsaparam; + final Map attributes = {}; + final KeyEntry key = KeyEntry(privateKey); + String? localIdentifier; + Asn1Octet? localId; + if (subSequenceCollection.attributes != null) { + final Asn1Set sq = subSequenceCollection.attributes!; + for (int i = 0; i < sq.objects.length; i++) { + final Asn1Encode? entry = sq.objects[i] as Asn1Encode?; + if (entry is Asn1Sequence) { + final DerObjectID? algorithmId = DerObjectID.getID( + entry[0], + ); + final Asn1Set attributeSet = entry[1]! as Asn1Set; + Asn1Encode? attribute; + if (attributeSet.objects.isNotEmpty) { + attribute = attributeSet[0]; + if (attributes.containsKey(algorithmId!.id)) { + if (attributes[algorithmId.id] != attribute) { + throw ArgumentError.value( + attributes, + 'attributes', + 'attempt to add existing attribute with different value', + ); + } + } else { + attributes[algorithmId.id] = attribute; + } + if (algorithmId.id == + PkcsObjectId.pkcs9AtFriendlyName.id) { + localIdentifier = + (attribute! as DerBmpString).getString(); + _keys.setValue(localIdentifier!, key); + } else if (algorithmId.id == + PkcsObjectId.pkcs9AtLocalKeyID.id) { + localId = attribute as Asn1Octet?; + } + } + } + } + } + if (localId != null) { + final String name = PdfString.bytesToHex( + localId.getOctets()!, + ); + if (localIdentifier == null) { + _keys.setValue(name, key); + } else { + _localIdentifiers[localIdentifier] = name; + } + } else { + isUnmarkedKey = true; + _keys.setValue('unmarked', key); + } + } else if (subSequenceCollection.id!.id == + PkcsObjectId.certBag.id) { + certificateChain.add(subSequenceCollection); + } + } + } + } else if (type.id == PkcsObjectId.encryptedData.id) { + final Asn1Sequence sequence1 = entry._content! as Asn1Sequence; + if (sequence1.count != 2) { + throw ArgumentError.value( + entry, + 'sequence', + 'Invalid length of the sequence', + ); + } + final int version = + (sequence1[0]! as DerInteger).value.toSigned(32).toInt(); + if (version != 0) { + throw ArgumentError.value( + version, + 'version', + 'Invalid sequence version', + ); + } + final Asn1Sequence data = sequence1[1]! as Asn1Sequence; + Asn1Octet? content; + if (data.count == 3) { + final DerTag taggedObject = data[2]! as DerTag; + content = Asn1Octet.getOctetString(taggedObject, false); + } + final List? octets = getCryptographicData( + false, + Algorithms.getAlgorithms(data[1])!, + password, + isInvalidPassword, + content!.getOctets(), + ); + final Asn1Sequence seq = + Asn1Stream(PdfStreamReader(octets)).readAsn1()! as Asn1Sequence; + // ignore: avoid_function_literals_in_foreach_calls + seq.objects!.forEach((dynamic subSequence) { + final Asn1SequenceCollection subSequenceCollection = + Asn1SequenceCollection(subSequence); + if (subSequenceCollection.id!.id == PkcsObjectId.certBag.id) { + certificateChain.add(subSequenceCollection); + } else if (subSequenceCollection.id!.id == + PkcsObjectId.pkcs8ShroudedKeyBag.id) { + final EncryptedPrivateKey encryptedPrivateKeyInformation = + EncryptedPrivateKey.getEncryptedPrivateKeyInformation( + subSequenceCollection.value, + ); + final KeyInformation privateInformation = + createPrivateKeyInfo( + password, + isInvalidPassword, + encryptedPrivateKeyInformation, + )!; + RsaPrivateKeyParam? rsaParameter; + if (privateInformation._algorithms!.id!.id == + PkcsObjectId.rsaEncryption.id || + privateInformation._algorithms!.id!.id == + X509Objects.idEARsa.id) { + final _RsaKey keyStructure = _RsaKey.fromSequence( + Asn1Sequence.getSequence(privateInformation._privateKey)!, + ); + rsaParameter = RsaPrivateKeyParam( + keyStructure._modulus, + keyStructure._publicExponent, + keyStructure._privateExponent, + keyStructure._prime1, + keyStructure._prime2, + keyStructure._exponent1, + keyStructure._exponent2, + keyStructure._coefficient, + ); + } + final CipherParameter? privateKey = rsaParameter; + final Map attributes = {}; + final KeyEntry keyEntry = KeyEntry(privateKey); + String? key; + Asn1Octet? localIdentity; + // ignore: avoid_function_literals_in_foreach_calls + subSequenceCollection.attributes!.objects.forEach((dynamic sq) { + final DerObjectID? asn1Id = sq[0] as DerObjectID?; + final Asn1Set attributeSet = sq[1] as Asn1Set; + Asn1Encode? attribute; + if (attributeSet.objects.isNotEmpty) { + attribute = attributeSet.objects[0] as Asn1Encode?; + if (attributes.containsKey(asn1Id!.id)) { + if (!(attributes[asn1Id.id] == attribute)) { + throw ArgumentError.value( + attributes, + 'attributes', + 'attempt to add existing attribute with different value', + ); + } + } else { + attributes[asn1Id.id] = attribute; + } + if (asn1Id.id == PkcsObjectId.pkcs9AtFriendlyName.id) { + key = (attribute! as DerBmpString).getString(); + _keys.setValue(key!, keyEntry); + } else if (asn1Id.id == PkcsObjectId.pkcs9AtLocalKeyID.id) { + localIdentity = attribute as Asn1Octet?; + } + } + }); + final String name = PdfString.bytesToHex( + localIdentity!.getOctets()!, + ); + if (key == null) { + _keys.setValue(name, keyEntry); + } else { + _localIdentifiers[key] = name; + } + } else if (subSequenceCollection.id!.id == PkcsObjectId.keyBag.id) { + final KeyInformation privateKeyInformation = + KeyInformation.getInformation(subSequenceCollection.value)!; + RsaPrivateKeyParam? rsaParameter; + if (privateKeyInformation._algorithms!.id!.id == + PkcsObjectId.rsaEncryption.id || + privateKeyInformation._algorithms!.id!.id == + X509Objects.idEARsa.id) { + final _RsaKey keyStructure = _RsaKey.fromSequence( + Asn1Sequence.getSequence(privateKeyInformation._privateKey)!, + ); + rsaParameter = RsaPrivateKeyParam( + keyStructure._modulus, + keyStructure._publicExponent, + keyStructure._privateExponent, + keyStructure._prime1, + keyStructure._prime2, + keyStructure._exponent1, + keyStructure._exponent2, + keyStructure._coefficient, + ); + } + final CipherParameter? privateKey = rsaParameter; + String? key; + Asn1Octet? localId; + final Map attributes = {}; + final KeyEntry keyEntry = KeyEntry(privateKey); + // ignore: avoid_function_literals_in_foreach_calls + subSequenceCollection.attributes!.objects.forEach((dynamic sq) { + final DerObjectID? id = sq[0] as DerObjectID?; + final Asn1Set attributeSet = sq[1] as Asn1Set; + Asn1Encode? attribute; + if (attributeSet.objects.isNotEmpty) { + attribute = attributeSet[0]; + if (attributes.containsKey(id!.id)) { + final Asn1Encode? attr = attributes[id.id] as Asn1Encode?; + if (attr != null && attr != attribute) { + throw ArgumentError.value( + sq, + 'sequence', + 'attempt to add existing attribute with different value', + ); + } + } else { + attributes[id.id] = attribute; + } + if (id.id == PkcsObjectId.pkcs9AtFriendlyName.id) { + key = (attribute! as DerBmpString).getString(); + _keys.setValue(key!, keyEntry); + } else if (id.id == PkcsObjectId.pkcs9AtLocalKeyID.id) { + localId = attribute as Asn1Octet?; + } + } + }); + final String name = PdfString.bytesToHex(localId!.getOctets()!); + if (key == null) { + _keys.setValue(name, keyEntry); + } else { + _localIdentifiers[key] = name; + } + } + }); + } + }); + } + _certificates = _CertificateTable(); + _chainCertificates = <_CertificateIdentifier, X509Certificates>{}; + _keyCertificates = {}; + // ignore: avoid_function_literals_in_foreach_calls + certificateChain.forEach((Asn1SequenceCollection asn1Collection) { + final Asn1Sequence asn1Sequence = asn1Collection.value! as Asn1Sequence; + final Asn1 certValue = Asn1Tag.getTag(asn1Sequence[1])!.getObject()!; + final List? octets = (certValue as Asn1Octet).getOctets(); + final X509Certificate certificate = + X509CertificateParser().readCertificate(PdfStreamReader(octets))!; + final Map attributes = {}; + Asn1Octet? localId; + String? key; + final Asn1Set? tempAttributes = asn1Collection.attributes; + if (tempAttributes != null) { + for (int i = 0; i < tempAttributes.objects.length; i++) { + final Asn1Sequence sq = tempAttributes.objects[i] as Asn1Sequence; + final DerObjectID? aOid = DerObjectID.getID(sq[0]); + final Asn1Set attrSet = sq[1]! as Asn1Set; + if (attrSet.objects.isNotEmpty) { + final Asn1Encode? attr = attrSet[0]; + if (attributes.containsKey(aOid!.id)) { + if (attributes[aOid.id] != attr) { + throw ArgumentError.value( + attributes, + 'attributes', + 'attempt to add existing attribute with different value', + ); + } + } else { + attributes[aOid.id] = attr; + } + if (aOid.id == PkcsObjectId.pkcs9AtFriendlyName.id) { + key = (attr! as DerBmpString).getString(); + } else if (aOid.id == PkcsObjectId.pkcs9AtLocalKeyID.id) { + localId = attr as Asn1Octet?; + } + } + } + } + final _CertificateIdentifier certId = _CertificateIdentifier( + pubKey: certificate.getPublicKey(), + ); + final X509Certificates certificateCollection = X509Certificates( + certificate, + ); + _chainCertificates[certId] = certificateCollection; + if (isUnmarkedKey) { + if (_keyCertificates.isEmpty) { + final String name = PdfString.bytesToHex(certId.id!); + _keyCertificates[name] = certificateCollection; + final dynamic temp = _keys['unmarked']; + _keys.remove('unmarked'); + _keys.setValue('name', temp); + } + } else { + if (localId != null) { + final String name = PdfString.bytesToHex(localId.getOctets()!); + _keyCertificates[name] = certificateCollection; + } + if (key != null) { + _certificates.setValue(key, certificateCollection); + } + } + }); + } + + /// internal method + static List? getCryptographicData( + bool forEncryption, + Algorithms id, + String password, + bool isZero, + List? data, + ) { + final _PasswordUtility utility = _PasswordUtility(); + final IBufferedCipher? cipher = + utility.createEncoder(id.id) as IBufferedCipher?; + if (cipher == null) { + throw ArgumentError.value(id, 'id', 'Invalid encryption algorithm'); + } + final _Pkcs12PasswordParameter parameter = + _Pkcs12PasswordParameter.getPbeParameter(id.parameters); + final ICipherParameter? parameters = utility.generateCipherParameters( + id.id!.id!, + password, + isZero, + parameter, + ); + cipher.initialize(forEncryption, parameters); + return cipher.doFinalFromInput(data); + } + + /// internal method + KeyInformation? createPrivateKeyInfo( + String passPhrase, + bool isPkcs12empty, + EncryptedPrivateKey encInfo, + ) { + final Algorithms algID = encInfo._algorithms!; + final _PasswordUtility pbeU = _PasswordUtility(); + final IBufferedCipher? cipher = + pbeU.createEncoder(algID) as IBufferedCipher?; + if (cipher == null) { + throw ArgumentError.value( + cipher, + 'cipher', + 'Unknown encryption algorithm', + ); + } + final ICipherParameter? cipherParameters = pbeU.generateCipherParameters( + algID.id!.id!, + passPhrase, + isPkcs12empty, + algID.parameters, + ); + cipher.initialize(false, cipherParameters); + final List? keyBytes = cipher.doFinalFromInput( + encInfo._octet!.getOctets(), + ); + return KeyInformation.getInformation(keyBytes); + } + + /// internal method + static SubjectKeyID createSubjectKeyID(CipherParameter publicKey) { + SubjectKeyID result; + if (publicKey is RsaKeyParam) { + final PublicKeyInformation information = PublicKeyInformation( + Algorithms(PkcsObjectId.rsaEncryption, DerNull.value), + RsaPublicKey(publicKey.modulus, publicKey.exponent).getAsn1(), + ); + result = SubjectKeyID(information); + } else { + throw ArgumentError.value(publicKey, 'publicKey', 'Invalid Key'); + } + return result; + } + + /// internal method + Map getContentTable() { + final Map result = {}; + // ignore: avoid_function_literals_in_foreach_calls + _certificates.keys.forEach((String key) { + result[key] = 'cert'; + }); + // ignore: avoid_function_literals_in_foreach_calls + _keys.keys.forEach((String key) { + if (!result.containsKey(key)) { + result[key] = 'key'; + } + }); + return result; + } + + /// internal method + Future> getContentTableAsync() async { + final Map result = {}; + // ignore: avoid_function_literals_in_foreach_calls + _certificates.keys.forEach((String key) { + result[key] = 'cert'; + }); + // ignore: avoid_function_literals_in_foreach_calls + _keys.keys.forEach((String key) { + if (!result.containsKey(key)) { + result[key] = 'key'; + } + }); + return result; + } + + /// internal method + bool isKey(String key) { + return _keys[key] != null; + } + + /// internal method + KeyEntry? getKey(String key) { + return _keys[key] is KeyEntry ? _keys[key] as KeyEntry? : null; + } + + /// internal method + X509Certificates? getCertificate(String key) { + dynamic certificates = _certificates[key]; + if (certificates != null && certificates is X509Certificates) { + return certificates; + } else { + String? id; + if (_localIdentifiers.containsKey(key)) { + id = _localIdentifiers[key]; + } + if (id != null) { + if (_keyCertificates.containsKey(id)) { + certificates = + _keyCertificates[id] is X509Certificates + ? _keyCertificates[id] + : null; + } + } else { + if (_keyCertificates.containsKey(key)) { + certificates = + _keyCertificates[key] is X509Certificates + ? _keyCertificates[key] + : null; + } + } + return certificates as X509Certificates?; + } + } + + /// internal method + Future getCertificateAsync(String key) async { + dynamic certificates = _certificates[key]; + if (certificates != null && certificates is X509Certificates) { + return certificates; + } else { + String? id; + if (_localIdentifiers.containsKey(key)) { + id = _localIdentifiers[key]; + } + if (id != null) { + if (_keyCertificates.containsKey(id)) { + certificates = + _keyCertificates[id] is X509Certificates + ? _keyCertificates[id] + : null; + } + } else { + if (_keyCertificates.containsKey(key)) { + certificates = + _keyCertificates[key] is X509Certificates + ? _keyCertificates[key] + : null; + } + } + return certificates as X509Certificates?; + } + } + + /// internal method + List? getCertificateChain(String key) { + if (!isKey(key)) { + return null; + } + X509Certificates? certificates = getCertificate(key); + if (certificates != null) { + final List certificateList = []; + bool isContinue = true; + while (certificates != null) { + final X509Certificate x509Certificate = certificates.certificate!; + X509Certificates? nextCertificate; + final Asn1Octet? x509Extension = x509Certificate.getExtension( + X509Extensions.authorityKeyIdentifier, + ); + if (x509Extension != null) { + final _KeyIdentifier id = _KeyIdentifier.getKeyIdentifier( + Asn1Stream(PdfStreamReader(x509Extension.getOctets())).readAsn1(), + ); + if (id.keyID != null) { + if (_chainCertificates.containsKey( + _CertificateIdentifier(id: id.keyID), + )) { + nextCertificate = + _chainCertificates[_CertificateIdentifier(id: id.keyID)]; + } + } + } + if (nextCertificate == null) { + final X509Name? issuer = x509Certificate.c!.issuer; + final X509Name? subject = x509Certificate.c!.subject; + if (!(issuer == subject)) { + final List<_CertificateIdentifier> keys = + _chainCertificates.keys.toList(); + // ignore: avoid_function_literals_in_foreach_calls + keys.forEach((_CertificateIdentifier certId) { + X509Certificates? x509CertEntry; + if (_chainCertificates.containsKey(certId)) { + x509CertEntry = _chainCertificates[certId]; + } + final X509Certificate certificate = x509CertEntry!.certificate!; + if (certificate.c!.subject == issuer) { + try { + // x509Certificate.verify(certificate.getPublicKey()); + // nextCertificate = x509CertEntry; + isContinue = false; + } catch (e) { + // + } + } + }); + } + } + if (isContinue) { + certificateList.add(certificates); + certificates = + nextCertificate != null && nextCertificate != certificates + ? nextCertificate + : null; + } + } + return List.generate( + certificateList.length, + (int i) => certificateList[i], + ); + } + return null; + } + + /// internal method + Future?> getCertificateChainAsync(String key) async { + if (!isKey(key)) { + return null; + } + List? x509Certificates; + await getCertificateAsync(key).then((X509Certificates? certificates) { + if (certificates != null) { + final List certificateList = []; + bool isContinue = true; + while (certificates != null) { + final X509Certificate x509Certificate = certificates.certificate!; + X509Certificates? nextCertificate; + final Asn1Octet? x509Extension = x509Certificate.getExtension( + X509Extensions.authorityKeyIdentifier, + ); + if (x509Extension != null) { + final _KeyIdentifier id = _KeyIdentifier.getKeyIdentifier( + Asn1Stream(PdfStreamReader(x509Extension.getOctets())).readAsn1(), + ); + if (id.keyID != null) { + if (_chainCertificates.containsKey( + _CertificateIdentifier(id: id.keyID), + )) { + nextCertificate = + _chainCertificates[_CertificateIdentifier(id: id.keyID)]; + } + } + } + if (nextCertificate == null) { + final X509Name? issuer = x509Certificate.c!.issuer; + final X509Name? subject = x509Certificate.c!.subject; + if (!(issuer == subject)) { + final List<_CertificateIdentifier> keys = + _chainCertificates.keys.toList(); + // ignore: avoid_function_literals_in_foreach_calls + keys.forEach((_CertificateIdentifier certId) { + X509Certificates? x509CertEntry; + if (_chainCertificates.containsKey(certId)) { + x509CertEntry = _chainCertificates[certId]; + } + final X509Certificate certificate = x509CertEntry!.certificate!; + if (certificate.c!.subject == issuer) { + try { + // x509Certificate.verify(certificate.getPublicKey()); + // nextCertificate = x509CertEntry; + isContinue = false; + } catch (e) { + // + } + } + }); + } + } + if (isContinue) { + certificateList.add(certificates); + certificates = + nextCertificate != null && nextCertificate != certificates + ? nextCertificate + : null; + } + } + x509Certificates = List.generate( + certificateList.length, + (int i) => certificateList[i], + ); + } + }); + return x509Certificates; + } + + /// internal method + List getChainCertificates() { + return _chainCertificates.values.toList(); + } +} + +class _CertificateTable { + _CertificateTable() { + _orig = {}; + _keys = {}; + } + late Map _orig; + late Map _keys; + + //Implementation + void clear() { + _orig = {}; + _keys = {}; + } + + List get keys { + return _orig.keys.toList(); + } + + dynamic remove(String key) { + final String lower = key.toLowerCase(); + String? k; + _keys.forEach((String tempKey, dynamic tempValue) { + if (lower == tempKey.toLowerCase()) { + k = _keys[tempKey] as String?; + } + }); + if (k == null) { + return null; + } + _keys.remove(lower); + final dynamic obj = _orig[k!]; + _orig.remove(k); + return obj; + } + + dynamic operator [](String key) { + final String lower = key.toLowerCase(); + String? k; + _keys.forEach((String tempKey, dynamic tempValue) { + if (lower == tempKey.toLowerCase()) { + k = tempKey; + } + }); + if (k != null) { + return _orig[_keys[k!]]; + } else { + return null; + } + } + + void setValue(String key, dynamic value) { + final String lower = key.toLowerCase(); + String? k; + _keys.forEach((String tempKey, dynamic tempValue) { + if (lower == tempKey.toLowerCase()) { + k = tempKey; + } + }); + if (k != null) { + _orig.remove(_keys[k!]); + } + _keys[lower] = key; + _orig[key] = value; + } +} + +class _CertificateIdentifier { + _CertificateIdentifier({CipherParameter? pubKey, List? id}) { + this.id = + pubKey != null + ? PdfPKCSCertificate.createSubjectKeyID(pubKey)._bytes + : id; + } + //Fields + List? id; + //Implements + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is _CertificateIdentifier) { + return Asn1.areEqual(id, other.id); + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => Asn1.getHashCode(id); +} + +class _PasswordUtility { + _PasswordUtility() { + _cipherUtils = _CipherUtils(); + _pkcs12 = 'Pkcs12'; + _algorithms = {}; + _type = {}; + _ids = {}; + _algorithms['PBEWITHSHAAND40BITRC4'] = 'PBEwithSHA-1and40bitRC4'; + _algorithms['PBEWITHSHA1AND40BITRC4'] = 'PBEwithSHA-1and40bitRC4'; + _algorithms['PBEWITHSHA-1AND40BITRC4'] = 'PBEwithSHA-1and40bitRC4'; + _algorithms[PkcsObjectId.pbeWithShaAnd40BitRC4.id] = + 'PBEwithSHA-1and40bitRC4'; + _algorithms['PBEWITHSHAAND3-KEYDESEDE-CBC'] = + 'PBEwithSHA-1and3-keyDESEDE-CBC'; + _algorithms['PBEWITHSHAAND3-KEYTRIPLEDES-CBC'] = + 'PBEwithSHA-1and3-keyDESEDE-CBC'; + _algorithms['PBEWITHSHA1AND3-KEYDESEDE-CBC'] = + 'PBEwithSHA-1and3-keyDESEDE-CBC'; + _algorithms['PBEWITHSHA1AND3-KEYTRIPLEDES-CBC'] = + 'PBEwithSHA-1and3-keyDESEDE-CBC'; + _algorithms['PBEWITHSHA-1AND3-KEYDESEDE-CBC'] = + 'PBEwithSHA-1and3-keyDESEDE-CBC'; + _algorithms['PBEWITHSHA-1AND3-KEYTRIPLEDES-CBC'] = + 'PBEwithSHA-1and3-keyDESEDE-CBC'; + _algorithms[PkcsObjectId.pbeWithShaAnd3KeyTripleDesCbc.id] = + 'PBEwithSHA-1and3-keyDESEDE-CBC'; + _algorithms['PBEWITHSHAAND40BITRC2-CBC'] = 'PBEwithSHA-1and40bitRC2-CBC'; + _algorithms['PBEWITHSHA1AND40BITRC2-CBC'] = 'PBEwithSHA-1and40bitRC2-CBC'; + _algorithms['PBEWITHSHA-1AND40BITRC2-CBC'] = 'PBEwithSHA-1and40bitRC2-CBC'; + _algorithms[PkcsObjectId.pbewithShaAnd40BitRC2Cbc.id] = + 'PBEwithSHA-1and40bitRC2-CBC'; + _algorithms['PBEWITHSHAAND128BITAES-CBC-BC'] = + 'PBEwithSHA-1and128bitAES-CBC-BC'; + _algorithms['PBEWITHSHA1AND128BITAES-CBC-BC'] = + 'PBEwithSHA-1and128bitAES-CBC-BC'; + _algorithms['PBEWITHSHA-1AND128BITAES-CBC-BC'] = + 'PBEwithSHA-1and128bitAES-CBC-BC'; + _algorithms['PBEWITHSHAAND192BITAES-CBC-BC'] = + 'PBEwithSHA-1and192bitAES-CBC-BC'; + _algorithms['PBEWITHSHA1AND192BITAES-CBC-BC'] = + 'PBEwithSHA-1and192bitAES-CBC-BC'; + _algorithms['PBEWITHSHA-1AND192BITAES-CBC-BC'] = + 'PBEwithSHA-1and192bitAES-CBC-BC'; + _algorithms['PBEWITHSHAAND256BITAES-CBC-BC'] = + 'PBEwithSHA-1and256bitAES-CBC-BC'; + _algorithms['PBEWITHSHA1AND256BITAES-CBC-BC'] = + 'PBEwithSHA-1and256bitAES-CBC-BC'; + _algorithms['PBEWITHSHA-1AND256BITAES-CBC-BC'] = + 'PBEwithSHA-1and256bitAES-CBC-BC'; + _algorithms['PBEWITHSHA256AND128BITAES-CBC-BC'] = + 'PBEwithSHA-256and128bitAES-CBC-BC'; + _algorithms['PBEWITHSHA-256AND128BITAES-CBC-BC'] = + 'PBEwithSHA-256and128bitAES-CBC-BC'; + _algorithms['PBEWITHSHA256AND192BITAES-CBC-BC'] = + 'PBEwithSHA-256and192bitAES-CBC-BC'; + _algorithms['PBEWITHSHA-256AND192BITAES-CBC-BC'] = + 'PBEwithSHA-256and192bitAES-CBC-BC'; + _algorithms['PBEWITHSHA256AND256BITAES-CBC-BC'] = + 'PBEwithSHA-256and256bitAES-CBC-BC'; + _algorithms['PBEWITHSHA-256AND256BITAES-CBC-BC'] = + 'PBEwithSHA-256and256bitAES-CBC-BC'; + _type['Pkcs12'] = _pkcs12; + _type['PBEwithSHA-1and128bitRC4'] = _pkcs12; + _type['PBEwithSHA-1and40bitRC4'] = _pkcs12; + _type['PBEwithSHA-1and3-keyDESEDE-CBC'] = _pkcs12; + _type['PBEwithSHA-1and2-keyDESEDE-CBC'] = _pkcs12; + _type['PBEwithSHA-1and128bitRC2-CBC'] = _pkcs12; + _type['PBEwithSHA-1and40bitRC2-CBC'] = _pkcs12; + _type['PBEwithSHA-1and256bitAES-CBC-BC'] = _pkcs12; + _type['PBEwithSHA-256and128bitAES-CBC-BC'] = _pkcs12; + _type['PBEwithSHA-256and192bitAES-CBC-BC'] = _pkcs12; + _type['PBEwithSHA-256and256bitAES-CBC-BC'] = _pkcs12; + _ids['PBEwithSHA-1and128bitRC4'] = PkcsObjectId.pbeWithShaAnd128BitRC4; + _ids['PBEwithSHA-1and40bitRC4'] = PkcsObjectId.pbeWithShaAnd40BitRC4; + _ids['PBEwithSHA-1and3-keyDESEDE-CBC'] = + PkcsObjectId.pbeWithShaAnd3KeyTripleDesCbc; + _ids['PBEwithSHA-1and2-keyDESEDE-CBC'] = + PkcsObjectId.pbeWithShaAnd2KeyTripleDesCbc; + _ids['PBEwithSHA-1and128bitRC2-CBC'] = + PkcsObjectId.pbeWithShaAnd128BitRC2Cbc; + _ids['PBEwithSHA-1and40bitRC2-CBC'] = PkcsObjectId.pbewithShaAnd40BitRC2Cbc; + } + + //Fields + String? _pkcs12; + late Map _algorithms; + late Map _type; + late Map _ids; + late _CipherUtils _cipherUtils; + + //Implementation + dynamic createEncoder(dynamic obj) { + dynamic result; + if (obj is Algorithms) { + result = createEncoder(obj.id!.id); + } else if (obj is DerObjectID) { + result = createEncoder(obj.id); + } else if (obj is String) { + final String lower = obj.toLowerCase(); + String? mechanism; + bool isContinue = true; + _algorithms.forEach((String? key, String value) { + if (isContinue && lower == key!.toLowerCase()) { + mechanism = _algorithms[key]; + isContinue = false; + } + }); + + if (mechanism != null && + (mechanism!.startsWith('PBEwithMD2') || + mechanism!.startsWith('PBEwithMD5') || + mechanism!.startsWith('PBEwithSHA-1') || + mechanism!.startsWith('PBEwithSHA-256'))) { + if (mechanism!.endsWith('AES-CBC-BC') || + mechanism!.endsWith('AES-CBC-OPENSSL')) { + result = _cipherUtils.getCipher('AES/CBC'); + } else if (mechanism!.endsWith('DES-CBC')) { + result = _cipherUtils.getCipher('DES/CBC'); + } else if (mechanism!.endsWith('DESEDE-CBC')) { + result = _cipherUtils.getCipher('DESEDE/CBC'); + } else if (mechanism!.endsWith('RC2-CBC')) { + result = _cipherUtils.getCipher('RC2/CBC'); + } else if (mechanism!.endsWith('RC4')) { + result = _cipherUtils.getCipher('RC4'); + } + } + } + return result; + } + + ICipherParameter? generateCipherParameters( + String algorithm, + String password, + bool isWrong, + Asn1Encode? pbeParameters, + ) { + final String mechanism = getAlgorithmFromUpeerInvariant(algorithm)!; + late List keyBytes; + List? salt; + int iterationCount = 0; + if (isPkcs12(mechanism)) { + final _Pkcs12PasswordParameter pbeParams = + _Pkcs12PasswordParameter.getPbeParameter(pbeParameters); + salt = pbeParams._octet!.getOctets(); + iterationCount = pbeParams._iterations!.value.toSigned(32).toInt(); + keyBytes = _PasswordGenerator.toBytes(password, isWrong); + } + ICipherParameter? parameters; + _PasswordGenerator generator; + if (mechanism.startsWith('PBEwithSHA-1')) { + generator = getEncoder( + _type[mechanism], + DigestAlgorithms.sha1, + keyBytes, + salt!, + iterationCount, + password, + ); + if (mechanism == 'PBEwithSHA-1and128bitAES-CBC-BC') { + parameters = generator.generateParam(128, 'AES', 128); + } else if (mechanism == 'PBEwithSHA-1and192bitAES-CBC-BC') { + parameters = generator.generateParam(192, 'AES', 128); + } else if (mechanism == 'PBEwithSHA-1and256bitAES-CBC-BC') { + parameters = generator.generateParam(256, 'AES', 128); + } else if (mechanism == 'PBEwithSHA-1and128bitRC4') { + parameters = generator.generateParam(128, 'RC4'); + } else if (mechanism == 'PBEwithSHA-1and40bitRC4') { + parameters = generator.generateParam(40, 'RC4'); + } else if (mechanism == 'PBEwithSHA-1and3-keyDESEDE-CBC') { + parameters = generator.generateParam(192, 'DESEDE', 64); + } else if (mechanism == 'PBEwithSHA-1and2-keyDESEDE-CBC') { + parameters = generator.generateParam(128, 'DESEDE', 64); + } else if (mechanism == 'PBEwithSHA-1and128bitRC2-CBC') { + parameters = generator.generateParam(128, 'RC2', 64); + } else if (mechanism == 'PBEwithSHA-1and40bitRC2-CBC') { + parameters = generator.generateParam(40, 'RC2', 64); + } else if (mechanism == 'PBEwithSHA-1andDES-CBC') { + parameters = generator.generateParam(64, 'DES', 64); + } else if (mechanism == 'PBEwithSHA-1andRC2-CBC') { + parameters = generator.generateParam(64, 'RC2', 64); + } + } else if (mechanism.startsWith('PBEwithSHA-256')) { + generator = getEncoder( + _type[mechanism], + DigestAlgorithms.sha256, + keyBytes, + salt!, + iterationCount, + password, + ); + if (mechanism == 'PBEwithSHA-256and128bitAES-CBC-BC') { + parameters = generator.generateParam(128, 'AES', 128); + } else if (mechanism == 'PBEwithSHA-256and192bitAES-CBC-BC') { + parameters = generator.generateParam(192, 'AES', 128); + } else if (mechanism == 'PBEwithSHA-256and256bitAES-CBC-BC') { + parameters = generator.generateParam(256, 'AES', 128); + } + } else if (mechanism.startsWith('PBEwithHmac')) { + final String digest = getDigest( + mechanism.substring('PBEwithHmac'.length), + ); + generator = getEncoder( + _type[mechanism], + digest, + keyBytes, + salt!, + iterationCount, + password, + ); + final int? bitLen = getBlockSize(digest); + parameters = generator.generateParam(bitLen); + } + keyBytes = List.generate(keyBytes.length, (int i) => 0); + return fixDataEncryptionParity(mechanism, parameters); + } + + static int getByteLength(String digest) { + return (digest == DigestAlgorithms.md5 || + digest == DigestAlgorithms.sha1 || + digest == DigestAlgorithms.sha256 || + digest.contains('Hmac')) + ? 64 + : 128; + } + + static int? getBlockSize(String digest) { + int? result; + if (digest == DigestAlgorithms.md5) { + result = 16; + } else if (digest == DigestAlgorithms.sha1) { + result = 20; + } else if (digest == DigestAlgorithms.sha256) { + result = 32; + } else if (digest == DigestAlgorithms.sha512) { + result = 64; + } else if (digest == DigestAlgorithms.sha384) { + result = 48; + } else if (digest.contains('Hmac')) { + result = 20; + } + return result; + } + + ICipherParameter? fixDataEncryptionParity( + String mechanism, + ICipherParameter? parameters, + ) { + if (!mechanism.endsWith('DES-CBC') & !mechanism.endsWith('DESEDE-CBC')) { + return parameters; + } + if (parameters is InvalidParameter) { + return InvalidParameter( + fixDataEncryptionParity(mechanism, parameters.parameters), + parameters.keys, + ); + } + final KeyParameter kParam = parameters! as KeyParameter; + final List keyBytes = kParam.keys; + for (int i = 0; i < keyBytes.length; i++) { + final int value = keyBytes[i]; + keyBytes[i] = ((value & 0xfe) | + ((((value >> 1) ^ + (value >> 2) ^ + (value >> 3) ^ + (value >> 4) ^ + (value >> 5) ^ + (value >> 6) ^ + (value >> 7)) ^ + 0x01) & + 0x01)) + .toUnsigned(8); + } + return KeyParameter(Uint8List.fromList(keyBytes)); + } + + bool isPkcs12(String algorithm) { + final String? mechanism = getAlgorithmFromUpeerInvariant(algorithm); + return mechanism != null && + _type.containsKey(mechanism) && + _pkcs12 == _type[mechanism]; + } + + String getDigest(String algorithm) { + String? digest = getAlgorithmFromUpeerInvariant(algorithm); + digest ??= algorithm; + if (digest.contains('sha_1') || + digest.contains('sha-1') || + digest.contains('sha1')) { + digest = DigestAlgorithms.hmacWithSha1; + } else if (digest.contains('sha_256') || + digest.contains('sha-256') || + digest.contains('sha256')) { + digest = DigestAlgorithms.hmacWithSha256; + } else if (digest.contains('md5') || + digest.contains('md_5') || + digest.contains('md-5')) { + digest = DigestAlgorithms.hmacWithMd5; + } else { + throw ArgumentError.value(algorithm, 'algorithm', 'Invalid message'); + } + return digest; + } + + _PasswordGenerator getEncoder( + String? type, + String digest, + List key, + List salt, + int iterationCount, + String password, + ) { + _PasswordGenerator generator; + if (type == _pkcs12) { + generator = _Pkcs12AlgorithmGenerator(digest, password); + } else { + throw ArgumentError.value( + type, + 'type', + 'Invalid Password Based Encryption type', + ); + } + generator.init(key, salt, iterationCount); + return generator; + } + + String? getAlgorithmFromUpeerInvariant(String algorithm) { + final String temp = algorithm.toLowerCase(); + String? result; + bool isContinue = true; + _algorithms.forEach((String? key, String value) { + if (isContinue && key!.toLowerCase() == temp) { + result = value; + isContinue = false; + } + }); + return result; + } +} + +abstract class _PasswordGenerator { + List? _password; + List? _value; + int? _count; + ICipherParameter generateParam(int? keySize, [String? algorithm, int? size]); + void init(List password, List value, int count) { + _password = Asn1.clone(password); + _value = Asn1.clone(value); + _count = count; + } + + static List toBytes(String password, bool isWrong) { + if (password.isEmpty) { + return isWrong ? List.generate(2, (int i) => 0) : []; + } + final List bytes = List.generate( + (password.length + 1) * 2, + (int i) => 0, + ); + final List tempBytes = encodeBigEndian(password); + int i = 0; + // ignore: avoid_function_literals_in_foreach_calls + tempBytes.forEach((int tempByte) { + bytes[i] = tempBytes[i]; + i++; + }); + return bytes; + } +} + +class _Pkcs12AlgorithmGenerator extends _PasswordGenerator { + _Pkcs12AlgorithmGenerator(String digest, String password) { + _digest = getDigest(digest, password); + _size = _PasswordUtility.getBlockSize(digest); + _length = _PasswordUtility.getByteLength(digest); + _keyMaterial = 1; + _invaidMaterial = 2; + } + late dynamic _digest; + int? _size; + late int _length; + int? _keyMaterial; + int? _invaidMaterial; + //Implementes + dynamic getDigest(String digest, String password) { + dynamic result; + if (digest == DigestAlgorithms.md5) { + result = md5; + } else if (digest == DigestAlgorithms.sha1) { + result = sha1; + } else if (digest == DigestAlgorithms.sha256) { + result = sha256; + } else if (digest == DigestAlgorithms.sha384) { + result = sha384; + } else if (digest == DigestAlgorithms.sha512) { + result = sha512; + } else if (digest == DigestAlgorithms.hmacWithSha1) { + result = Hmac(sha1, utf8.encode(password)); + } else if (digest == DigestAlgorithms.hmacWithSha256) { + result = Hmac(sha256, utf8.encode(password)); + } else if (digest == DigestAlgorithms.hmacWithMd5) { + result = Hmac(md5, utf8.encode(password)); + } else { + throw ArgumentError.value(digest, 'digest', 'Invalid message digest'); + } + return result; + } + + @override + ICipherParameter generateParam(int? keySize, [String? algorithm, int? size]) { + if (size != null) { + size = size ~/ 8; + keySize = keySize! ~/ 8; + final List bytes = generateDerivedKey(_keyMaterial, keySize); + final _ParamUtility util = _ParamUtility(); + final KeyParameter key = util.createKeyParameter( + algorithm!, + bytes, + 0, + keySize, + ); + final List iv = generateDerivedKey(_invaidMaterial, size); + return InvalidParameter(key, Uint8List.fromList(iv)); + } else if (algorithm != null) { + keySize = keySize! ~/ 8; + final List bytes = generateDerivedKey(_keyMaterial, keySize); + final _ParamUtility util = _ParamUtility(); + return util.createKeyParameter(algorithm, bytes, 0, keySize); + } else { + keySize = keySize! ~/ 8; + final List bytes = generateDerivedKey(_keyMaterial, keySize); + return KeyParameter.fromLengthValue( + Uint8List.fromList(bytes), + 0, + keySize, + ); + } + } + + List generateDerivedKey(int? id, int length) { + final List d = List.generate(_length, (int index) => 0); + final List derivedKey = List.generate(length, (int index) => 0); + for (int index = 0; index != d.length; index++) { + d[index] = id!.toUnsigned(8); + } + List s; + if (_value != null && _value!.isNotEmpty) { + s = List.generate( + _length * ((_value!.length + _length - 1) ~/ _length), + (int index) => 0, + ); + for (int index = 0; index != s.length; index++) { + s[index] = _value![index % _value!.length]; + } + } else { + s = []; + } + List password; + if (_password != null && _password!.isNotEmpty) { + password = List.generate( + _length * ((_password!.length + _length - 1) ~/ _length), + (int index) => 0, + ); + for (int index = 0; index != password.length; index++) { + password[index] = _password![index % _password!.length]; + } + } else { + password = []; + } + List tempBytes = List.generate( + s.length + password.length, + (int index) => 0, + ); + List.copyRange(tempBytes, 0, s, 0, s.length); + List.copyRange(tempBytes, s.length, password, 0, password.length); + final List b = List.generate(_length, (int index) => 0); + final int c = (length + _size! - 1) ~/ _size!; + List? a = List.generate(_size!, (int index) => 0); + for (int i = 1; i <= c; i++) { + final dynamic output = AccumulatorSink(); + final dynamic input = sha1.startChunkedConversion(output); + input.add(d); + input.add(tempBytes); + input.close(); + a = output.events.single.bytes as List?; + for (int j = 1; j != _count; j++) { + a = _digest.convert(a).bytes as List?; + } + for (int j = 0; j != b.length; j++) { + b[j] = a![j % a.length]; + } + for (int j = 0; j != tempBytes.length ~/ _length; j++) { + tempBytes = adjust(tempBytes, j * _length, b); + } + if (i == c) { + List.copyRange( + derivedKey, + (i - 1) * _size!, + a!, + 0, + derivedKey.length - ((i - 1) * _size!), + ); + } else { + List.copyRange(derivedKey, (i - 1) * _size!, a!, 0, a.length); + } + } + return derivedKey; + } + + List adjust(List a, int offset, List b) { + int x = (b[b.length - 1] & 0xff) + (a[offset + b.length - 1] & 0xff) + 1; + a[offset + b.length - 1] = x.toUnsigned(8); + x = (x.toUnsigned(32) >> 8).toSigned(32); + for (int i = b.length - 2; i >= 0; i--) { + x += (b[i] & 0xff) + (a[offset + i] & 0xff); + a[offset + i] = x.toUnsigned(8); + x = (x.toUnsigned(32) >> 8).toSigned(32); + } + return a; + } +} + +class _Pkcs12PasswordParameter extends Asn1Encode { + _Pkcs12PasswordParameter(Asn1Sequence sequence) { + if (sequence.count != 2) { + throw ArgumentError.value( + sequence, + 'sequence', + 'Invalid length in sequence', + ); + } + _octet = Asn1Octet.getOctetStringFromObject(sequence[0]); + _iterations = DerInteger.getNumber(sequence[1]); + } + //Fields + DerInteger? _iterations; + Asn1Octet? _octet; + //Implementation + static _Pkcs12PasswordParameter getPbeParameter(dynamic obj) { + _Pkcs12PasswordParameter result; + if (obj is _Pkcs12PasswordParameter) { + result = obj; + } else if (obj is Asn1Sequence) { + result = _Pkcs12PasswordParameter(obj); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + return result; + } + + @override + Asn1 getAsn1() { + return DerSequence(array: [_octet, _iterations]); + } +} + +class _ParamUtility { + _ParamUtility() { + _algorithms = {}; + addAlgorithm('DESEDE', [ + 'DESEDEWRAP', + 'TDEA', + DerObjectID('1.3.14.3.2.17'), + PkcsObjectId.idAlgCms3DesWrap, + ]); + addAlgorithm('DESEDE3', [PkcsObjectId.desEde3Cbc]); + addAlgorithm('RC2', [ + PkcsObjectId.rc2Cbc, + PkcsObjectId.idAlgCmsRC2Wrap, + ]); + } + + //Fields + late Map _algorithms; + + //Implementation + void addAlgorithm(String name, List objects) { + _algorithms[name] = name; + // ignore: avoid_function_literals_in_foreach_calls + objects.forEach((dynamic entry) { + if (entry is String) { + _algorithms[entry] = name; + } else { + _algorithms[entry.toString()] = name; + } + }); + } + + KeyParameter createKeyParameter( + String algorithm, + List bytes, + int offset, + int? length, + ) { + String? name; + final String lower = algorithm.toLowerCase(); + _algorithms.forEach((String key, String value) { + if (lower == key.toLowerCase()) { + name = value; + } + }); + if (name == null) { + throw ArgumentError.value( + algorithm, + 'algorithm', + 'Invalid entry. Algorithm', + ); + } + if (name == 'DES') { + return _DataEncryptionParameter.fromLengthValue(bytes, offset, length!); + } + if (name == 'DESEDE' || name == 'DESEDE3') { + return _DesedeAlgorithmParameter(bytes, offset, length); + } + return KeyParameter.fromLengthValue( + Uint8List.fromList(bytes), + offset, + length!, + ); + } +} + +class _DataEncryptionParameter extends KeyParameter { + _DataEncryptionParameter(List keys) : super(Uint8List.fromList(keys)) { + if (checkKey(keys, 0)) { + throw ArgumentError.value( + keys, + 'keys', + 'Invalid Data Encryption keys creation', + ); + } + } + _DataEncryptionParameter.fromLengthValue( + List keys, + int offset, + int length, + ) : super.fromLengthValue(Uint8List.fromList(keys), offset, length) { + if (checkKey(keys, 0)) { + throw ArgumentError.value( + keys, + 'keys', + 'Invalid Data Encryption keys creation', + ); + } + } + static List dataEncryptionWeekKeys = [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 31, + 31, + 31, + 31, + 14, + 14, + 14, + 14, + 224, + 224, + 224, + 224, + 241, + 241, + 241, + 241, + 254, + 254, + 254, + 254, + 254, + 254, + 254, + 254, + 1, + 254, + 1, + 254, + 1, + 254, + 1, + 254, + 31, + 224, + 31, + 224, + 14, + 241, + 14, + 241, + 1, + 224, + 1, + 224, + 1, + 241, + 1, + 241, + 31, + 254, + 31, + 254, + 14, + 254, + 14, + 254, + 1, + 31, + 1, + 31, + 1, + 14, + 1, + 14, + 224, + 254, + 224, + 254, + 241, + 254, + 241, + 254, + 254, + 1, + 254, + 1, + 254, + 1, + 254, + 1, + 224, + 31, + 224, + 31, + 241, + 14, + 241, + 14, + 224, + 1, + 224, + 1, + 241, + 1, + 241, + 1, + 254, + 31, + 254, + 31, + 254, + 14, + 254, + 14, + 31, + 1, + 31, + 1, + 14, + 1, + 14, + 1, + 254, + 224, + 254, + 224, + 254, + 241, + 254, + 241, + ]; + + static bool checkKey(List bytes, int offset) { + if (bytes.length - offset < 8) { + throw ArgumentError.value(bytes, 'bytes', 'Invalid length in bytes'); + } + for (int i = 0; i < 16; i++) { + bool isMatch = false; + for (int j = 0; j < 8; j++) { + if (bytes[j + offset] != dataEncryptionWeekKeys[i * 8 + j]) { + isMatch = true; + break; + } + } + if (!isMatch) { + return true; + } + } + return false; + } +} + +class _DesedeAlgorithmParameter extends _DataEncryptionParameter { + _DesedeAlgorithmParameter(List key, int keyOffset, int? keyLength) + : super(fixKey(key, keyOffset, keyLength)); + //Implementation + static List fixKey(List key, int keyOffset, int? keyLength) { + final List tmp = List.generate(24, (int i) => 0); + switch (keyLength) { + case 16: + List.copyRange(tmp, 0, key, keyOffset, keyOffset + 16); + List.copyRange(tmp, 16, key, keyOffset, keyOffset + 8); + break; + case 24: + List.copyRange(tmp, 0, key, keyOffset, keyOffset + 24); + break; + default: + throw ArgumentError.value( + keyLength, + 'keyLen', + 'Bad length for DESede key', + ); + } + if (checkKeyValue(tmp, 0, tmp.length)) { + throw ArgumentError.value( + key, + 'key', + 'Attempt to create weak DESede key', + ); + } + return tmp; + } + + static bool checkKeyValue(List key, int offset, int length) { + for (int i = offset; i < length; i += 8) { + if (_DataEncryptionParameter.checkKey(key, i)) { + return true; + } + } + return false; + } +} + +class _CipherUtils { + _CipherUtils() { + _algorithms = {}; + } + //Fields + late Map _algorithms; + //Implementation + IBufferedCipher getCipher(String algorithm) { + String? value; + if (_algorithms.isNotEmpty) { + value = _algorithms[algorithm]; + } + if (value != null) { + algorithm = value; + } + final List parts = algorithm.split('/'); + ICipher? blockCipher; + ICipherBlock? asymBlockCipher; + String algorithmName = parts[0]; + if (_algorithms.isNotEmpty) { + value = _algorithms[algorithmName]; + } + if (value != null) { + algorithmName = value; + } + final _CipherAlgorithm cipherAlgorithm = getAlgorithm(algorithmName); + switch (cipherAlgorithm) { + case _CipherAlgorithm.des: + blockCipher = _DataEncryption(); + break; + case _CipherAlgorithm.desede: + blockCipher = _DesEdeAlogorithm(); + break; + case _CipherAlgorithm.rc2: + blockCipher = _Rc2Algorithm(); + break; + case _CipherAlgorithm.rsa: + asymBlockCipher = RsaAlgorithm(); + break; + } + bool isPadded = true; + IPadding? padding; + if (parts.length > 2) { + final String paddingName = parts[2]; + _CipherPaddingType cipherPadding; + if (paddingName.isEmpty) { + cipherPadding = _CipherPaddingType.raw; + } else if (paddingName == 'X9.23PADDING') { + cipherPadding = _CipherPaddingType.x923Padding; + } else { + cipherPadding = getPaddingType(paddingName); + } + switch (cipherPadding) { + case _CipherPaddingType.noPadding: + isPadded = false; + break; + case _CipherPaddingType.raw: + case _CipherPaddingType.withCipherTextStealing: + break; + case _CipherPaddingType.pkcs1: + case _CipherPaddingType.pkcs1Padding: + asymBlockCipher = Pkcs1Encoding(asymBlockCipher); + break; + case _CipherPaddingType.pkcs5: + case _CipherPaddingType.pkcs5Padding: + case _CipherPaddingType.pkcs7: + case _CipherPaddingType.pkcs7Padding: + padding = Pkcs7Padding(); + break; + // ignore: no_default_cases + default: + throw ArgumentError.value( + cipherPadding, + 'cpiher padding algorithm', + 'Invalid cipher algorithm', + ); + } + } + String mode = ''; + if (parts.length > 1) { + mode = parts[1]; + int digitIngex = -1; + for (int i = 0; i < mode.length; ++i) { + if (isDigit(mode[i])) { + digitIngex = i; + break; + } + } + final String modeName = + digitIngex >= 0 ? mode.substring(0, digitIngex) : mode; + final _CipherMode cipherMode = + modeName == '' ? _CipherMode.none : getCipherMode(modeName); + switch (cipherMode) { + case _CipherMode.ecb: + case _CipherMode.none: + break; + case _CipherMode.cbc: + blockCipher = CipherBlockChainingMode(blockCipher); + break; + case _CipherMode.cts: + blockCipher = CipherBlockChainingMode(blockCipher); + break; + } + } + if (blockCipher != null) { + if (padding != null) { + return BufferedBlockPadding(blockCipher, padding); + } + if (!isPadded || blockCipher.isBlock!) { + return BufferedCipher(blockCipher); + } + return BufferedBlockPadding(blockCipher); + } + throw ArgumentError.value( + blockCipher, + 'Cipher Algorithm', + 'Invalid cipher algorithm', + ); + } + + _CipherAlgorithm getAlgorithm(String name) { + _CipherAlgorithm result; + switch (name.toLowerCase()) { + case 'des': + result = _CipherAlgorithm.des; + break; + case 'desede': + result = _CipherAlgorithm.desede; + break; + case 'rc2': + result = _CipherAlgorithm.rc2; + break; + case 'rsa': + result = _CipherAlgorithm.rsa; + break; + default: + throw ArgumentError.value(name, 'name', 'Invalid algorithm name'); + } + return result; + } + + _CipherMode getCipherMode(String mode) { + _CipherMode result; + switch (mode.toLowerCase()) { + case 'ecb': + result = _CipherMode.ecb; + break; + case 'none': + result = _CipherMode.none; + break; + case 'cbc': + result = _CipherMode.cbc; + break; + case 'cts': + result = _CipherMode.cts; + break; + default: + throw ArgumentError.value(mode, 'CipherMode', 'Invalid mode'); + } + return result; + } + + _CipherPaddingType getPaddingType(String type) { + _CipherPaddingType result; + switch (type.toLowerCase()) { + case 'noPadding': + result = _CipherPaddingType.noPadding; + break; + case 'raw': + result = _CipherPaddingType.raw; + break; + case 'pkcs1': + result = _CipherPaddingType.pkcs1; + break; + case 'pkcs1Padding': + result = _CipherPaddingType.pkcs1Padding; + break; + case 'pkcs5': + result = _CipherPaddingType.pkcs5; + break; + case 'pkcs5Padding': + result = _CipherPaddingType.pkcs5Padding; + break; + case 'pkcs7': + result = _CipherPaddingType.pkcs7; + break; + case 'pkcs7Padding': + result = _CipherPaddingType.pkcs7Padding; + break; + case 'withCipherTextStealing': + result = _CipherPaddingType.withCipherTextStealing; + break; + case 'x923Padding': + result = _CipherPaddingType.x923Padding; + break; + default: + throw ArgumentError.value(type, 'PaddingType', 'Invalid padding type'); + } + return result; + } + + bool isDigit(String s, [int idx = 0]) { + return (s.codeUnitAt(idx) ^ 0x30) <= 9; + } +} + +enum _CipherAlgorithm { des, desede, rc2, rsa } + +enum _CipherMode { ecb, none, cbc, cts } + +enum _CipherPaddingType { + noPadding, + raw, + pkcs1, + pkcs1Padding, + pkcs5, + pkcs5Padding, + pkcs7, + pkcs7Padding, + withCipherTextStealing, + x923Padding, +} + +class _KeyIdentifier extends Asn1Encode { + _KeyIdentifier(Asn1Sequence sequence) { + // ignore: avoid_function_literals_in_foreach_calls + sequence.objects!.forEach((dynamic entry) { + if (entry is Asn1Tag) { + switch (entry.tagNumber) { + case 0: + _keyIdentifier = Asn1Octet.getOctetStringFromObject(entry); + break; + case 1: + break; + case 2: + _serialNumber = DerInteger.getNumberFromTag(entry, false); + break; + default: + throw ArgumentError.value( + sequence, + 'sequence', + 'Invalid entry in sequence', + ); + } + } + }); + } + //Fields + Asn1Octet? _keyIdentifier; + DerInteger? _serialNumber; + //Properties + List? get keyID => _keyIdentifier?.getOctets(); + //Implementation + static _KeyIdentifier getKeyIdentifier(dynamic obj) { + _KeyIdentifier result; + if (obj is _KeyIdentifier) { + result = obj; + } else if (obj is Asn1Sequence) { + result = _KeyIdentifier(obj); + } else if (obj is X509Extension) { + result = getKeyIdentifier(X509Extension.convertValueToObject(obj)); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + return result; + } + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection(); + if (_keyIdentifier != null) { + collection.encodableObjects.add(DerTag(0, _keyIdentifier, false)); + } + if (_serialNumber != null) { + collection.encodableObjects.add(DerTag(2, _serialNumber, false)); + } + return DerSequence(collection: collection); + } + + @override + String toString() { + return 'AuthorityKeyIdentifier: KeyID(${String.fromCharCodes(_keyIdentifier!.getOctets()!)})'; + } +} + +class _DesEdeAlogorithm extends _DataEncryption { + _DesEdeAlogorithm() : super(); + List? _key1; + List? _key2; + List? _key3; + bool? _isEncryption; + + //Properties + @override + int? get blockSize => _blockSize; + @override + String get algorithmName => Asn1.desEde; + //Implementation + @override + void initialize(bool? forEncryption, ICipherParameter? parameters) { + if (parameters is! KeyParameter) { + throw ArgumentError.value(parameters, 'parameters', 'Invalid parameter'); + } + final List keyMaster = parameters.keys; + if (keyMaster.length != 24 && keyMaster.length != 16) { + throw ArgumentError.value( + parameters, + 'parameters', + 'Invalid key size. Size must be 16 or 24 bytes.', + ); + } + _isEncryption = forEncryption; + final List key1 = List.generate(8, (int i) => 0); + List.copyRange(key1, 0, keyMaster, 0, key1.length); + _key1 = generateWorkingKey(forEncryption, key1); + final List key2 = List.generate(8, (int i) => 0); + List.copyRange(key2, 0, keyMaster, 8, 8 + key2.length); + _key2 = generateWorkingKey(!forEncryption!, key2); + if (keyMaster.length == 24) { + final List key3 = List.generate(8, (int i) => 0); + List.copyRange(key3, 0, keyMaster, 16, 16 + key3.length); + _key3 = generateWorkingKey(forEncryption, key3); + } else { + _key3 = _key1; + } + } + + @override + Map processBlock([ + List? inputBytes, + int? inOffset, + List? outputBytes, + int? outOffset, + ]) { + ArgumentError.checkNotNull(_key1); + if ((inOffset! + _blockSize!) > inputBytes!.length) { + throw ArgumentError.value( + inOffset, + 'inOffset', + 'Invalid length in input bytes', + ); + } + if ((outOffset! + _blockSize!) > outputBytes!.length) { + throw ArgumentError.value( + inOffset, + 'inOffset', + 'Invalid length in output bytes', + ); + } + final List tempBytes = List.generate(_blockSize!, (int i) => 0); + if (_isEncryption!) { + encryptData(_key1, inputBytes, inOffset, tempBytes, 0); + encryptData(_key2, tempBytes, 0, tempBytes, 0); + encryptData(_key3, tempBytes, 0, outputBytes, outOffset); + } else { + encryptData(_key3, inputBytes, inOffset, tempBytes, 0); + encryptData(_key2, tempBytes, 0, tempBytes, 0); + encryptData(_key1, tempBytes, 0, outputBytes, outOffset); + } + return {'length': _blockSize, 'output': outputBytes}; + } + + @override + void reset() {} +} + +class _DataEncryption extends ICipher { + _DataEncryption() { + _blockSize = 8; + byteBit = [128, 64, 32, 16, 8, 4, 2, 1]; + bigByte = [ + 0x800000, + 0x400000, + 0x200000, + 0x100000, + 0x80000, + 0x40000, + 0x20000, + 0x10000, + 0x8000, + 0x4000, + 0x2000, + 0x1000, + 0x800, + 0x400, + 0x200, + 0x100, + 0x80, + 0x40, + 0x20, + 0x10, + 0x8, + 0x4, + 0x2, + 0x1, + ]; + pc1 = [ + 56, + 48, + 40, + 32, + 24, + 16, + 8, + 0, + 57, + 49, + 41, + 33, + 25, + 17, + 9, + 1, + 58, + 50, + 42, + 34, + 26, + 18, + 10, + 2, + 59, + 51, + 43, + 35, + 62, + 54, + 46, + 38, + 30, + 22, + 14, + 6, + 61, + 53, + 45, + 37, + 29, + 21, + 13, + 5, + 60, + 52, + 44, + 36, + 28, + 20, + 12, + 4, + 27, + 19, + 11, + 3, + ]; + toTrot = [1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28]; + pc2 = [ + 13, + 16, + 10, + 23, + 0, + 4, + 2, + 27, + 14, + 5, + 20, + 9, + 22, + 18, + 11, + 3, + 25, + 7, + 15, + 6, + 26, + 19, + 12, + 1, + 40, + 51, + 30, + 36, + 46, + 54, + 29, + 39, + 50, + 44, + 32, + 47, + 43, + 48, + 38, + 55, + 33, + 52, + 45, + 41, + 49, + 35, + 28, + 31, + ]; + sp1 = [ + 0x01010400, + 0x00000000, + 0x00010000, + 0x01010404, + 0x01010004, + 0x00010404, + 0x00000004, + 0x00010000, + 0x00000400, + 0x01010400, + 0x01010404, + 0x00000400, + 0x01000404, + 0x01010004, + 0x01000000, + 0x00000004, + 0x00000404, + 0x01000400, + 0x01000400, + 0x00010400, + 0x00010400, + 0x01010000, + 0x01010000, + 0x01000404, + 0x00010004, + 0x01000004, + 0x01000004, + 0x00010004, + 0x00000000, + 0x00000404, + 0x00010404, + 0x01000000, + 0x00010000, + 0x01010404, + 0x00000004, + 0x01010000, + 0x01010400, + 0x01000000, + 0x01000000, + 0x00000400, + 0x01010004, + 0x00010000, + 0x00010400, + 0x01000004, + 0x00000400, + 0x00000004, + 0x01000404, + 0x00010404, + 0x01010404, + 0x00010004, + 0x01010000, + 0x01000404, + 0x01000004, + 0x00000404, + 0x00010404, + 0x01010400, + 0x00000404, + 0x01000400, + 0x01000400, + 0x00000000, + 0x00010004, + 0x00010400, + 0x00000000, + 0x01010004, + ]; + sp2 = [ + 0x80108020, + 0x80008000, + 0x00008000, + 0x00108020, + 0x00100000, + 0x00000020, + 0x80100020, + 0x80008020, + 0x80000020, + 0x80108020, + 0x80108000, + 0x80000000, + 0x80008000, + 0x00100000, + 0x00000020, + 0x80100020, + 0x00108000, + 0x00100020, + 0x80008020, + 0x00000000, + 0x80000000, + 0x00008000, + 0x00108020, + 0x80100000, + 0x00100020, + 0x80000020, + 0x00000000, + 0x00108000, + 0x00008020, + 0x80108000, + 0x80100000, + 0x00008020, + 0x00000000, + 0x00108020, + 0x80100020, + 0x00100000, + 0x80008020, + 0x80100000, + 0x80108000, + 0x00008000, + 0x80100000, + 0x80008000, + 0x00000020, + 0x80108020, + 0x00108020, + 0x00000020, + 0x00008000, + 0x80000000, + 0x00008020, + 0x80108000, + 0x00100000, + 0x80000020, + 0x00100020, + 0x80008020, + 0x80000020, + 0x00100020, + 0x00108000, + 0x00000000, + 0x80008000, + 0x00008020, + 0x80000000, + 0x80100020, + 0x80108020, + 0x00108000, + ]; + sp3 = [ + 0x00000208, + 0x08020200, + 0x00000000, + 0x08020008, + 0x08000200, + 0x00000000, + 0x00020208, + 0x08000200, + 0x00020008, + 0x08000008, + 0x08000008, + 0x00020000, + 0x08020208, + 0x00020008, + 0x08020000, + 0x00000208, + 0x08000000, + 0x00000008, + 0x08020200, + 0x00000200, + 0x00020200, + 0x08020000, + 0x08020008, + 0x00020208, + 0x08000208, + 0x00020200, + 0x00020000, + 0x08000208, + 0x00000008, + 0x08020208, + 0x00000200, + 0x08000000, + 0x08020200, + 0x08000000, + 0x00020008, + 0x00000208, + 0x00020000, + 0x08020200, + 0x08000200, + 0x00000000, + 0x00000200, + 0x00020008, + 0x08020208, + 0x08000200, + 0x08000008, + 0x00000200, + 0x00000000, + 0x08020008, + 0x08000208, + 0x00020000, + 0x08000000, + 0x08020208, + 0x00000008, + 0x00020208, + 0x00020200, + 0x08000008, + 0x08020000, + 0x08000208, + 0x00000208, + 0x08020000, + 0x00020208, + 0x00000008, + 0x08020008, + 0x00020200, + ]; + sp4 = [ + 0x00802001, + 0x00002081, + 0x00002081, + 0x00000080, + 0x00802080, + 0x00800081, + 0x00800001, + 0x00002001, + 0x00000000, + 0x00802000, + 0x00802000, + 0x00802081, + 0x00000081, + 0x00000000, + 0x00800080, + 0x00800001, + 0x00000001, + 0x00002000, + 0x00800000, + 0x00802001, + 0x00000080, + 0x00800000, + 0x00002001, + 0x00002080, + 0x00800081, + 0x00000001, + 0x00002080, + 0x00800080, + 0x00002000, + 0x00802080, + 0x00802081, + 0x00000081, + 0x00800080, + 0x00800001, + 0x00802000, + 0x00802081, + 0x00000081, + 0x00000000, + 0x00000000, + 0x00802000, + 0x00002080, + 0x00800080, + 0x00800081, + 0x00000001, + 0x00802001, + 0x00002081, + 0x00002081, + 0x00000080, + 0x00802081, + 0x00000081, + 0x00000001, + 0x00002000, + 0x00800001, + 0x00002001, + 0x00802080, + 0x00800081, + 0x00002001, + 0x00002080, + 0x00800000, + 0x00802001, + 0x00000080, + 0x00800000, + 0x00002000, + 0x00802080, + ]; + sp5 = [ + 0x00000100, + 0x02080100, + 0x02080000, + 0x42000100, + 0x00080000, + 0x00000100, + 0x40000000, + 0x02080000, + 0x40080100, + 0x00080000, + 0x02000100, + 0x40080100, + 0x42000100, + 0x42080000, + 0x00080100, + 0x40000000, + 0x02000000, + 0x40080000, + 0x40080000, + 0x00000000, + 0x40000100, + 0x42080100, + 0x42080100, + 0x02000100, + 0x42080000, + 0x40000100, + 0x00000000, + 0x42000000, + 0x02080100, + 0x02000000, + 0x42000000, + 0x00080100, + 0x00080000, + 0x42000100, + 0x00000100, + 0x02000000, + 0x40000000, + 0x02080000, + 0x42000100, + 0x40080100, + 0x02000100, + 0x40000000, + 0x42080000, + 0x02080100, + 0x40080100, + 0x00000100, + 0x02000000, + 0x42080000, + 0x42080100, + 0x00080100, + 0x42000000, + 0x42080100, + 0x02080000, + 0x00000000, + 0x40080000, + 0x42000000, + 0x00080100, + 0x02000100, + 0x40000100, + 0x00080000, + 0x00000000, + 0x40080000, + 0x02080100, + 0x40000100, + ]; + sp6 = [ + 0x20000010, + 0x20400000, + 0x00004000, + 0x20404010, + 0x20400000, + 0x00000010, + 0x20404010, + 0x00400000, + 0x20004000, + 0x00404010, + 0x00400000, + 0x20000010, + 0x00400010, + 0x20004000, + 0x20000000, + 0x00004010, + 0x00000000, + 0x00400010, + 0x20004010, + 0x00004000, + 0x00404000, + 0x20004010, + 0x00000010, + 0x20400010, + 0x20400010, + 0x00000000, + 0x00404010, + 0x20404000, + 0x00004010, + 0x00404000, + 0x20404000, + 0x20000000, + 0x20004000, + 0x00000010, + 0x20400010, + 0x00404000, + 0x20404010, + 0x00400000, + 0x00004010, + 0x20000010, + 0x00400000, + 0x20004000, + 0x20000000, + 0x00004010, + 0x20000010, + 0x20404010, + 0x00404000, + 0x20400000, + 0x00404010, + 0x20404000, + 0x00000000, + 0x20400010, + 0x00000010, + 0x00004000, + 0x20400000, + 0x00404010, + 0x00004000, + 0x00400010, + 0x20004010, + 0x00000000, + 0x20404000, + 0x20000000, + 0x00400010, + 0x20004010, + ]; + sp7 = [ + 0x00200000, + 0x04200002, + 0x04000802, + 0x00000000, + 0x00000800, + 0x04000802, + 0x00200802, + 0x04200800, + 0x04200802, + 0x00200000, + 0x00000000, + 0x04000002, + 0x00000002, + 0x04000000, + 0x04200002, + 0x00000802, + 0x04000800, + 0x00200802, + 0x00200002, + 0x04000800, + 0x04000002, + 0x04200000, + 0x04200800, + 0x00200002, + 0x04200000, + 0x00000800, + 0x00000802, + 0x04200802, + 0x00200800, + 0x00000002, + 0x04000000, + 0x00200800, + 0x04000000, + 0x00200800, + 0x00200000, + 0x04000802, + 0x04000802, + 0x04200002, + 0x04200002, + 0x00000002, + 0x00200002, + 0x04000000, + 0x04000800, + 0x00200000, + 0x04200800, + 0x00000802, + 0x00200802, + 0x04200800, + 0x00000802, + 0x04000002, + 0x04200802, + 0x04200000, + 0x00200800, + 0x00000000, + 0x00000002, + 0x04200802, + 0x00000000, + 0x00200802, + 0x04200000, + 0x00000800, + 0x04000002, + 0x04000800, + 0x00000800, + 0x00200002, + ]; + sp8 = [ + 0x10001040, + 0x00001000, + 0x00040000, + 0x10041040, + 0x10000000, + 0x10001040, + 0x00000040, + 0x10000000, + 0x00040040, + 0x10040000, + 0x10041040, + 0x00041000, + 0x10041000, + 0x00041040, + 0x00001000, + 0x00000040, + 0x10040000, + 0x10000040, + 0x10001000, + 0x00001040, + 0x00041000, + 0x00040040, + 0x10040040, + 0x10041000, + 0x00001040, + 0x00000000, + 0x00000000, + 0x10040040, + 0x10000040, + 0x10001000, + 0x00041040, + 0x00040000, + 0x00041040, + 0x00040000, + 0x10041000, + 0x00001000, + 0x00000040, + 0x10040040, + 0x00001000, + 0x00041040, + 0x10001000, + 0x00000040, + 0x10000040, + 0x10040000, + 0x10040040, + 0x10000000, + 0x00040000, + 0x10001040, + 0x00000000, + 0x10041040, + 0x00040040, + 0x10000040, + 0x10040000, + 0x10001000, + 0x10001040, + 0x00000000, + 0x10041040, + 0x00041000, + 0x00041000, + 0x00001040, + 0x00001040, + 0x00040040, + 0x10000000, + 0x10041000, + ]; + } + + //Fields + int? _blockSize; + late List byteBit; + late List bigByte; + late List pc1; + late List toTrot; + late List pc2; + late List sp1; + late List sp2; + late List sp3; + late List sp4; + late List sp5; + late List sp6; + late List sp7; + late List sp8; + List? _keys; + + //Properties + List? get keys => _keys; + @override + String get algorithmName => Asn1.des; + @override + bool get isBlock => false; + @override + int? get blockSize => _blockSize; + + //Implementation + @override + void initialize(bool? isEncryption, ICipherParameter? parameters) { + if (parameters is! KeyParameter) { + throw ArgumentError.value(parameters, 'parameters', 'Invalid parameter'); + } + _keys = generateWorkingKey(isEncryption, parameters.keys); + } + + @override + Map processBlock( + List? inBytes, + int inOffset, + List? outBytes, + int? outOffset, + ) { + ArgumentError.checkNotNull(_keys); + if ((inOffset + _blockSize!) > inBytes!.length) { + throw ArgumentError.value( + inOffset, + 'inOffset', + 'Invalid length in input bytes', + ); + } + if ((outOffset! + _blockSize!) > outBytes!.length) { + throw ArgumentError.value( + outOffset, + 'outOffset', + 'Invalid length in output bytes', + ); + } + encryptData(_keys, inBytes, inOffset, outBytes, outOffset); + return {'length': _blockSize, 'output': outBytes}; + } + + @override + void reset() {} + List generateWorkingKey(bool? isEncrypt, List bytes) { + final List newKeys = List.generate(32, (int i) => 0); + final List bytes1 = List.generate(56, (int i) => false); + final List bytes2 = List.generate(56, (int i) => false); + for (int j = 0; j < 56; j++) { + final int length = pc1[j]; + bytes1[j] = + (bytes[length.toUnsigned(32) >> 3] & byteBit[length & 07]) != 0; + } + for (int i = 0; i < 16; i++) { + int a; + int b; + int c; + if (isEncrypt!) { + b = i << 1; + } else { + b = (15 - i) << 1; + } + c = b + 1; + newKeys[b] = newKeys[c] = 0; + for (int j = 0; j < 28; j++) { + a = j + toTrot[i]; + if (a < 28) { + bytes2[j] = bytes1[a]; + } else { + bytes2[j] = bytes1[a - 28]; + } + } + for (int j = 28; j < 56; j++) { + a = j + toTrot[i]; + if (a < 56) { + bytes2[j] = bytes1[a]; + } else { + bytes2[j] = bytes1[a - 28]; + } + } + for (int j = 0; j < 24; j++) { + if (bytes2[pc2[j]]) { + newKeys[b] |= bigByte[j]; + } + if (bytes2[pc2[j + 24]]) { + newKeys[c] |= bigByte[j]; + } + } + } + for (int i = 0; i != 32; i += 2) { + int value1, value2; + value1 = newKeys[i]; + value2 = newKeys[i + 1]; + newKeys[i] = (((value1 & 0x00fc0000) << 6).toUnsigned(32) | + ((value1 & 0x00000fc0) << 10).toUnsigned(32) | + ((value2 & 0x00fc0000).toUnsigned(32) >> 10) | + ((value2 & 0x00000fc0).toUnsigned(32) >> 6)) + .toSigned(32); + newKeys[i + 1] = (((value1 & 0x0003f000) << 12).toUnsigned(32) | + ((value1 & 0x0000003f) << 16).toUnsigned(32) | + ((value2 & 0x0003f000).toUnsigned(32) >> 4) | + (value2 & 0x0000003f).toUnsigned(32)) + .toSigned(32); + } + return newKeys; + } + + void encryptData( + List? keys, + List inputBytes, + int inOffset, + List outBytes, + int outOffset, + ) { + int left = Asn1.beToUInt32(inputBytes, inOffset); + int right = Asn1.beToUInt32(inputBytes, inOffset + 4); + int data = (((left >> 4) ^ right) & 0x0f0f0f0f).toUnsigned(32); + right ^= data; + left ^= data << 4; + data = ((left >> 16) ^ right) & 0x0000ffff; + right ^= data; + left ^= data << 16; + data = ((right >> 2) ^ left) & 0x33333333; + left ^= data; + right ^= data << 2; + data = ((right >> 8) ^ left) & 0x00ff00ff; + left ^= data; + right ^= data << 8; + right = ((right << 1) | (right >> 31)).toUnsigned(32); + data = (left ^ right) & 0xaaaaaaaa; + left ^= data; + right ^= data; + left = ((left << 1) | (left >> 31)).toUnsigned(32); + for (int round = 0; round < 8; round++) { + data = ((right << 28) | (right >> 4)).toUnsigned(32); + data ^= keys![round * 4 + 0].toUnsigned(32); + int value = sp7[data & 0x3f]; + value |= sp5[(data >> 8) & 0x3f]; + value |= sp3[(data >> 16) & 0x3f]; + value |= sp1[(data >> 24) & 0x3f]; + data = right ^ keys[round * 4 + 1].toUnsigned(32); + value |= sp8[data & 0x3f]; + value |= sp6[(data >> 8) & 0x3f]; + value |= sp4[(data >> 16) & 0x3f]; + value |= sp2[(data >> 24) & 0x3f]; + left ^= value; + data = ((left << 28) | (left >> 4)).toUnsigned(32); + data ^= keys[round * 4 + 2].toUnsigned(32); + value = sp7[data & 0x3f]; + value |= sp5[(data >> 8) & 0x3f]; + value |= sp3[(data >> 16) & 0x3f]; + value |= sp1[(data >> 24) & 0x3f]; + data = left ^ keys[round * 4 + 3].toUnsigned(32); + value |= sp8[data & 0x3f]; + value |= sp6[(data >> 8) & 0x3f]; + value |= sp4[(data >> 16) & 0x3f]; + value |= sp2[(data >> 24) & 0x3f]; + right ^= value; + } + right = ((right << 31) | (right >> 1)).toUnsigned(32); + data = (left ^ right) & 0xaaaaaaaa; + left ^= data; + right ^= data; + left = ((left << 31) | (left >> 1)).toUnsigned(32); + data = ((left >> 8) ^ right) & 0x00ff00ff; + right ^= data; + left ^= data << 8; + data = ((left >> 2) ^ right) & 0x33333333; + right ^= data; + left ^= data << 2; + data = ((right >> 16) ^ left) & 0x0000ffff; + left ^= data; + right ^= data << 16; + data = ((right >> 4) ^ left) & 0x0f0f0f0f; + left ^= data; + right ^= data << 4; + Asn1.uInt32ToBe(right, outBytes, outOffset); + Asn1.uInt32ToBe(left, outBytes, outOffset + 4); + } +} + +class _Rc2Algorithm extends ICipher { + _Rc2Algorithm() { + _piTable = [ + 217, + 120, + 249, + 196, + 25, + 221, + 181, + 237, + 40, + 233, + 253, + 121, + 74, + 160, + 216, + 157, + 198, + 126, + 55, + 131, + 43, + 118, + 83, + 142, + 98, + 76, + 100, + 136, + 68, + 139, + 251, + 162, + 23, + 154, + 89, + 245, + 135, + 179, + 79, + 19, + 97, + 69, + 109, + 141, + 9, + 129, + 125, + 50, + 189, + 143, + 64, + 235, + 134, + 183, + 123, + 11, + 240, + 149, + 33, + 34, + 92, + 107, + 78, + 130, + 84, + 214, + 101, + 147, + 206, + 96, + 178, + 28, + 115, + 86, + 192, + 20, + 167, + 140, + 241, + 220, + 18, + 117, + 202, + 31, + 59, + 190, + 228, + 209, + 66, + 61, + 212, + 48, + 163, + 60, + 182, + 38, + 111, + 191, + 14, + 218, + 70, + 105, + 7, + 87, + 39, + 242, + 29, + 155, + 188, + 148, + 67, + 3, + 248, + 17, + 199, + 246, + 144, + 239, + 62, + 231, + 6, + 195, + 213, + 47, + 200, + 102, + 30, + 215, + 8, + 232, + 234, + 222, + 128, + 82, + 238, + 247, + 132, + 170, + 114, + 172, + 53, + 77, + 106, + 42, + 150, + 26, + 210, + 113, + 90, + 21, + 73, + 116, + 75, + 159, + 208, + 94, + 4, + 24, + 164, + 236, + 194, + 224, + 65, + 110, + 15, + 81, + 203, + 204, + 36, + 145, + 175, + 80, + 161, + 244, + 112, + 57, + 153, + 124, + 58, + 133, + 35, + 184, + 180, + 122, + 252, + 2, + 54, + 91, + 37, + 85, + 151, + 49, + 45, + 93, + 250, + 152, + 227, + 138, + 146, + 174, + 5, + 223, + 41, + 16, + 103, + 108, + 186, + 201, + 211, + 0, + 230, + 207, + 225, + 158, + 168, + 44, + 99, + 22, + 1, + 63, + 88, + 226, + 137, + 169, + 13, + 56, + 52, + 27, + 171, + 51, + 255, + 176, + 187, + 72, + 12, + 95, + 185, + 177, + 205, + 46, + 197, + 243, + 219, + 71, + 229, + 165, + 156, + 119, + 10, + 166, + 32, + 104, + 254, + 127, + 193, + 173, + ]; + _blockSize = 8; + } + //Fields + int? _blockSize; + late List _key; + bool? _isEncrypt; + late List _piTable; + + //Properties + @override + String get algorithmName => 'RC2'; + @override + bool get isBlock => false; + @override + int? get blockSize => _blockSize; + + //Implementation + List generateKey(List key, int bits) { + int x; + final List xKey = List.generate(128, (int i) => 0); + for (int i = 0; i != key.length; i++) { + xKey[i] = key[i] & 0xff; + } + int len = key.length; + if (len < 128) { + int index = 0; + x = xKey[len - 1]; + do { + x = _piTable[(x + xKey[index++]) & 255] & 0xff; + xKey[len++] = x; + } while (len < 128); + } + len = (bits + 7) >> 3; + x = _piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff; + xKey[128 - len] = x; + for (int i = 128 - len - 1; i >= 0; i--) { + x = _piTable[x ^ xKey[i + len]] & 0xff; + xKey[i] = x; + } + final List newKey = []; + for (int i = 0; i < 64; i++) { + newKey.add(xKey[2 * i] + (xKey[2 * i + 1] << 8)); + } + return newKey; + } + + @override + void initialize(bool? forEncryption, ICipherParameter? parameters) { + _isEncrypt = forEncryption; + if (parameters is KeyParameter) { + final List key = parameters.keys; + _key = generateKey(key, key.length * 8); + } + } + + @override + void reset() {} + + @override + Map processBlock( + List? input, + int inOff, + List? output, + int? outOff, + ) { + if (_isEncrypt!) { + encryptBlock(input!, inOff, output!, outOff!); + } else { + decryptBlock(input!, inOff, output!, outOff!); + } + return {'length': _blockSize, 'output': output}; + } + + int rotateWordLeft(int x, int y) { + x &= 0xffff; + return (x << y) | (x >> (16 - y)); + } + + void encryptBlock( + List input, + int inOff, + List outBytes, + int outOff, + ) { + int x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff); + int x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff); + int x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff); + int x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff); + for (int i = 0; i <= 16; i += 4) { + x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + _key[i], 1); + x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + _key[i + 1], 2); + x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + _key[i + 2], 3); + x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + _key[i + 3], 5); + } + x10 += _key[x76 & 63]; + x32 += _key[x10 & 63]; + x54 += _key[x32 & 63]; + x76 += _key[x54 & 63]; + for (int i = 20; i <= 40; i += 4) { + x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + _key[i], 1); + x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + _key[i + 1], 2); + x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + _key[i + 2], 3); + x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + _key[i + 3], 5); + } + x10 += _key[x76 & 63]; + x32 += _key[x10 & 63]; + x54 += _key[x32 & 63]; + x76 += _key[x54 & 63]; + for (int i = 44; i < 64; i += 4) { + x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + _key[i], 1); + x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + _key[i + 1], 2); + x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + _key[i + 2], 3); + x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + _key[i + 3], 5); + } + outBytes[outOff + 0] = x10.toUnsigned(8); + outBytes[outOff + 1] = (x10 >> 8).toUnsigned(8); + outBytes[outOff + 2] = x32.toUnsigned(8); + outBytes[outOff + 3] = (x32 >> 8).toUnsigned(8); + outBytes[outOff + 4] = x54.toUnsigned(8); + outBytes[outOff + 5] = (x54 >> 8).toUnsigned(8); + outBytes[outOff + 6] = x76.toUnsigned(8); + outBytes[outOff + 7] = (x76 >> 8).toUnsigned(8); + } + + void decryptBlock( + List input, + int inOff, + List outBytes, + int outOff, + ) { + int x76 = ((input[inOff + 7] & 0xff) << 8) + (input[inOff + 6] & 0xff); + int x54 = ((input[inOff + 5] & 0xff) << 8) + (input[inOff + 4] & 0xff); + int x32 = ((input[inOff + 3] & 0xff) << 8) + (input[inOff + 2] & 0xff); + int x10 = ((input[inOff + 1] & 0xff) << 8) + (input[inOff + 0] & 0xff); + for (int i = 60; i >= 44; i -= 4) { + x76 = + rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + _key[i + 3]); + x54 = + rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + _key[i + 2]); + x32 = + rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + _key[i + 1]); + x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + _key[i]); + } + x76 -= _key[x54 & 63]; + x54 -= _key[x32 & 63]; + x32 -= _key[x10 & 63]; + x10 -= _key[x76 & 63]; + for (int i = 40; i >= 20; i -= 4) { + x76 = + rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + _key[i + 3]); + x54 = + rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + _key[i + 2]); + x32 = + rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + _key[i + 1]); + x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + _key[i]); + } + x76 -= _key[x54 & 63]; + x54 -= _key[x32 & 63]; + x32 -= _key[x10 & 63]; + x10 -= _key[x76 & 63]; + for (int i = 16; i >= 0; i -= 4) { + x76 = + rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + _key[i + 3]); + x54 = + rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + _key[i + 2]); + x32 = + rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + _key[i + 1]); + x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + _key[i]); + } + outBytes[outOff + 0] = x10.toUnsigned(8); + outBytes[outOff + 1] = (x10 >> 8).toUnsigned(8); + outBytes[outOff + 2] = x32.toUnsigned(8); + outBytes[outOff + 3] = (x32 >> 8).toUnsigned(8); + outBytes[outOff + 4] = x54.toUnsigned(8); + outBytes[outOff + 5] = (x54 >> 8).toUnsigned(8); + outBytes[outOff + 6] = x76.toUnsigned(8); + outBytes[outOff + 7] = (x76 >> 8).toUnsigned(8); + } +} + +class _PfxData extends Asn1Encode { + _PfxData(Asn1Sequence sequence) { + _contentInformation = _ContentInformation.getInformation(sequence[1]); + if (sequence.count == 3) { + _macInformation = _MacInformation.getInformation(sequence[2]); + } + } + _ContentInformation? _contentInformation; + _MacInformation? _macInformation; + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection([ + DerInteger(bigIntToBytes(BigInt.from(3))), + _contentInformation, + ]); + if (_macInformation != null) { + collection.encodableObjects.add(_macInformation); + } + return BerSequence(collection: collection); + } +} + +class _ContentInformation extends Asn1Encode { + _ContentInformation(Asn1Sequence sequence) { + if (sequence.count < 1 || sequence.count > 2) { + throw ArgumentError.value( + sequence, + 'sequence', + 'Invalid length in sequence', + ); + } + _contentType = sequence[0] as DerObjectID?; + if (sequence.count > 1) { + final Asn1Tag tagged = sequence[1]! as Asn1Tag; + if (!tagged.explicit! || tagged.tagNumber != 0) { + throw ArgumentError.value(tagged, 'tagged', 'Invalid tag'); + } + _content = tagged.getObject(); + } + } + //Fields + DerObjectID? _contentType; + Asn1Encode? _content; + //Implementation + static _ContentInformation? getInformation(dynamic obj) { + _ContentInformation? result; + if (obj == null || obj is _ContentInformation) { + result = obj as _ContentInformation?; + } else if (obj is Asn1Sequence) { + result = _ContentInformation(obj); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + return result; + } + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection([ + _contentType, + ]); + if (_content != null) { + collection.encodableObjects.add(DerTag(0, _content)); + } + return BerSequence(collection: collection); + } +} + +class _MacInformation extends Asn1Encode { + _MacInformation(Asn1Sequence sequence) { + _digest = DigestInformation.getDigestInformation(sequence[0]); + _value = (sequence[1]! as Asn1Octet).getOctets(); + if (sequence.count == 3) { + _count = (sequence[2]! as DerInteger).value; + } else { + _count = BigInt.one; + } + } + //Fields + DigestInformation? _digest; + List? _value; + BigInt? _count; + //Implementation + static _MacInformation getInformation(dynamic obj) { + _MacInformation result; + if (obj is _MacInformation) { + result = obj; + } else if (obj is Asn1Sequence) { + result = _MacInformation(obj); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + return result; + } + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection([ + _digest, + DerOctet(_value!), + ]); + if (_count != BigInt.one) { + collection.encodableObjects.add(DerInteger.fromNumber(_count)); + } + return DerSequence(collection: collection); + } +} + +class EncryptedPrivateKey extends Asn1Encode { + EncryptedPrivateKey(Asn1Sequence sequence) { + if (sequence.count != 2) { + throw ArgumentError.value( + sequence, + 'sequence', + 'Invalid length in sequence', + ); + } + _algorithms = Algorithms.getAlgorithms(sequence[0]); + _octet = Asn1Octet.getOctetStringFromObject(sequence[1]); + } + + //Fields + Algorithms? _algorithms; + Asn1Octet? _octet; + + //Implementation + @override + Asn1 getAsn1() { + return DerSequence(array: [_algorithms, _octet]); + } + + static EncryptedPrivateKey getEncryptedPrivateKeyInformation(dynamic obj) { + if (obj is EncryptedPrivateKey) { + return obj; + } + if (obj is Asn1Sequence) { + return EncryptedPrivateKey(obj); + } + throw ArgumentError.value(obj, 'obj', 'Invalid entry in sequence'); + } +} + +class KeyInformation extends Asn1Encode { + KeyInformation( + Algorithms algorithms, + Asn1 privateKey, [ + Asn1Set? attributes, + ]) { + _privateKey = privateKey; + _algorithms = algorithms; + if (attributes != null) { + _attributes = attributes; + } + } + KeyInformation.fromSequence(Asn1Sequence? sequence) { + if (sequence != null) { + final List objects = sequence.objects!; + if (objects.length >= 3) { + _algorithms = Algorithms.getAlgorithms(objects[1]); + final dynamic privateKeyValue = objects[2]; + try { + _privateKey = + Asn1Stream( + PdfStreamReader(privateKeyValue.getOctets()), + ).readAsn1(); + } catch (e) { + throw ArgumentError.value(sequence, 'sequence', 'Invalid sequence'); + } + if (objects.length > 3) { + _attributes = Asn1Set.getAsn1Set(objects[3]! as Asn1Tag?, false); + } + } else { + throw ArgumentError.value(sequence, 'sequence', 'Invalid sequence'); + } + } + } + + //Fields + Asn1? _privateKey; + Algorithms? _algorithms; + Asn1Set? _attributes; + + //Implementation + static KeyInformation? getInformation(dynamic obj) { + if (obj is KeyInformation) { + return obj; + } + if (obj != null) { + return KeyInformation.fromSequence(Asn1Sequence.getSequence(obj)); + } + return null; + } + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection v = Asn1EncodeCollection([ + DerInteger.fromNumber(BigInt.from(0)), + _algorithms, + DerOctet.fromObject(_privateKey!), + ]); + if (_attributes != null) { + v.encodableObjects.add(DerTag(0, _attributes, false)); + } + return DerSequence(collection: v); + } +} + +class _RsaKey extends Asn1Encode { + _RsaKey( + BigInt modulus, + BigInt publicExponent, + BigInt privateExponent, + BigInt prime1, + BigInt prime2, + BigInt exponent1, + BigInt exponent2, + BigInt coefficient, + ) { + _modulus = modulus; + _publicExponent = publicExponent; + _privateExponent = privateExponent; + _prime1 = prime1; + _prime2 = prime2; + _exponent1 = exponent1; + _exponent2 = exponent2; + _coefficient = coefficient; + } + _RsaKey.fromSequence(Asn1Sequence sequence) { + final BigInt version = (sequence[0]! as DerInteger).value; + if (version.toSigned(32).toInt() != 0) { + throw ArgumentError.value(sequence, 'sequence', 'Invalid RSA key'); + } + _modulus = (sequence[1]! as DerInteger).value; + _publicExponent = (sequence[2]! as DerInteger).value; + _privateExponent = (sequence[3]! as DerInteger).value; + _prime1 = (sequence[4]! as DerInteger).value; + _prime2 = (sequence[5]! as DerInteger).value; + _exponent1 = (sequence[6]! as DerInteger).value; + _exponent2 = (sequence[7]! as DerInteger).value; + _coefficient = (sequence[8]! as DerInteger).value; + } + BigInt? _modulus; + BigInt? _publicExponent; + BigInt? _privateExponent; + BigInt? _prime1; + BigInt? _prime2; + BigInt? _exponent1; + BigInt? _exponent2; + BigInt? _coefficient; + @override + Asn1 getAsn1() { + return DerSequence( + array: [ + DerInteger.fromNumber(BigInt.from(0)), + DerInteger.fromNumber(_modulus), + DerInteger.fromNumber(_publicExponent), + DerInteger.fromNumber(_privateExponent), + DerInteger.fromNumber(_prime1), + DerInteger.fromNumber(_prime2), + DerInteger.fromNumber(_exponent1), + DerInteger.fromNumber(_exponent2), + DerInteger.fromNumber(_coefficient), + ], + ); + } +} + +class SubjectKeyID extends Asn1Encode { + SubjectKeyID(dynamic obj) { + if (obj is Asn1Octet) { + _bytes = obj.getOctets(); + } else if (obj is PublicKeyInformation) { + _bytes = getDigest(obj); + } + } + + List? _bytes; + //Implementation + static List getDigest(PublicKeyInformation publicKey) { + return sha1.convert(publicKey.publicKey!.data!).bytes; + } + + /// internal method + static PublicKeyInformation createSubjectKeyID(CipherParameter publicKey) { + if (publicKey is RsaKeyParam) { + final PublicKeyInformation information = PublicKeyInformation( + Algorithms(PkcsObjectId.rsaEncryption, DerNull.value), + RsaPublicKey(publicKey.modulus, publicKey.exponent).getAsn1(), + ); + return information; + } else { + throw ArgumentError.value(publicKey, 'publicKey', 'Invalid Key'); + } + } + + @override + Asn1 getAsn1() { + return DerOctet(_bytes!); + } +} + +/// Internal class +class CertificateIdentity { + /// Internal constructor + CertificateIdentity( + String hashAlgorithm, + X509Certificate issuerCert, + DerInteger serialNumber, + ) { + final Algorithms algorithms = Algorithms( + DerObjectID(hashAlgorithm), + DerNull.value, + ); + try { + final String algorithm = algorithms.id!.id!; + final X509Name? issuerName = + SingnedCertificate.getCertificate( + Asn1.fromByteArray(issuerCert.getTbsCertificate()!), + )!.subject; + MessageDigestFinder utilities = MessageDigestFinder(); + final List issuerNameHash = utilities.getDigest( + algorithm, + issuerName!.getEncoded()!, + ); + final CipherParameter issuerKey = issuerCert.getPublicKey(); + final PublicKeyInformation info = SubjectKeyID.createSubjectKeyID( + issuerKey, + ); + utilities = MessageDigestFinder(); + final List issuerKeyHash = utilities.getDigest( + algorithm, + info.publicKey!.getBytes()!, + ); + id = CertificateIdentityHelper( + hash: algorithms, + issuerName: DerOctet(issuerNameHash), + issuerKey: DerOctet(issuerKeyHash), + serialNumber: serialNumber, + ); + } catch (e) { + throw Exception('Invalid certificate ID'); + } + } + + /// Internal field + CertificateIdentityHelper? id; + + /// Internal constant + static const String sha1 = '1.3.14.3.2.26'; +} + +/// Internal class +class CertificateIdentityHelper extends Asn1Encode { + /// Internal constructor + CertificateIdentityHelper({ + Algorithms? hash, + Asn1Octet? issuerName, + Asn1Octet? issuerKey, + DerInteger? serialNumber, + }) { + _hash = hash; + _issuerName = issuerName; + _issuerKey = issuerKey; + _serialNumber = serialNumber; + } + + /// Internal field + Algorithms? _hash; + Asn1Octet? _issuerName; + Asn1Octet? _issuerKey; + DerInteger? _serialNumber; + + @override + Asn1 getAsn1() { + return DerSequence( + array: [_hash!, _issuerName!, _issuerKey!, _serialNumber!], + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature.dart index e8d0e7268..070d72a4a 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature.dart @@ -1,822 +1,822 @@ -import 'dart:convert'; -import 'dart:math'; - -import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../forms/pdf_field.dart'; -import '../../forms/pdf_signature_field.dart'; -import '../../io/pdf_constants.dart'; -import '../../io/pdf_cross_table.dart'; -import '../../io/stream_reader.dart'; -import '../../pages/pdf_page.dart'; -import '../../pdf_document/pdf_document.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_stream.dart'; -import '../../primitives/pdf_string.dart'; -import '../enum.dart'; -import '../pdf_security.dart'; -import 'asn1/asn1.dart'; -import 'asn1/asn1_stream.dart'; -import 'asn1/der.dart'; -import 'pdf_certificate.dart'; -import 'pdf_external_signer.dart'; -import 'pdf_signature_dictionary.dart'; -import 'time_stamp_server/time_stamp_server.dart'; -import 'x509/ocsp_utils.dart'; -import 'x509/x509_certificates.dart'; - -/// Represents a digital signature used for signing a PDF document. -class PdfSignature { - //Constructor - /// Initializes a new instance of the [PdfSignature] class with the page and the signature name. - PdfSignature({ - String? signedName, - String? locationInfo, - String? reason, - String? contactInfo, - List? documentPermissions, - CryptographicStandard cryptographicStandard = CryptographicStandard.cms, - DigestAlgorithm digestAlgorithm = DigestAlgorithm.sha256, - PdfCertificate? certificate, - TimestampServer? timestampServer, - DateTime? signedDate, - }) { - _helper = PdfSignatureHelper(this); - _init( - signedName, - locationInfo, - reason, - contactInfo, - documentPermissions, - cryptographicStandard, - digestAlgorithm, - certificate, - signedDate, - timestampServer, - ); - } - - //Fields - late PdfSignatureHelper _helper; - List>? _externalRootCert; - - //Properties - /// Gets or sets the permission for certificated document. - List documentPermissions = [ - PdfCertificationFlags.forbidChanges, - ]; - - /// Gets or sets reason of signing. - String? reason; - - /// Gets or sets the physical location of the signing. - String? locationInfo; - - /// Gets or sets the signed name - String? signedName; - - /// Gets or sets the signed date. - /// - /// NOTE: The signed date can only be set when signing the PDF document and does not work on existing signatures. - DateTime? get signedDate => _helper.dateOfSign; - - set signedDate(DateTime? value) { - _helper.dateOfSign = value; - } - - /// Gets or sets cryptographic standard. - late CryptographicStandard cryptographicStandard; - - /// Gets or sets digestion algorithm. - late DigestAlgorithm digestAlgorithm; - - /// Gets or sets information provided by the signer to enable a recipient to contact - /// the signer to verify the signature; for example, a phone number. - String? contactInfo; - - /// Gets or sets the certificate - PdfCertificate? certificate; - - /// Gets or sets time stamping server unique resource identifier. - /// - /// The timestamp is only embedded when signing the PDF document and - /// saving asynchronously. - /// - /// ```dart - /// //Creates a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Adds a new page - /// PdfPage page = document.pages.add(); - /// //Creates a digital signature and sets signature information - /// PdfSignatureField field = PdfSignatureField(page, 'signature', - /// bounds: Rect.fromLTWH(0, 0, 200, 100), - /// signature: PdfSignature( - /// //Creates a certificate instance from the PFX file with a private key - /// certificate: PdfCertificate( - /// File('D:/PDF.pfx').readAsBytesSync(), 'syncfusion'), - /// contactInfo: 'johndoe@owned.us', - /// locationInfo: 'Honolulu, Hawaii', - /// reason: 'I am author of this document.', - /// //Create a new PDF time stamp server - /// timestampServer: - /// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')))); - /// //Add a signature field to the form - /// document.form.fields.add(field); - /// //Save and dispose the PDF document - /// File('Output.pdf').writeAsBytes(await document.save()); - /// document.dispose(); - /// ``` - TimestampServer? timestampServer; - - //Implementations - void _init( - String? signedName, - String? locationInfo, - String? reason, - String? contactInfo, - List? documentPermissions, - CryptographicStandard cryptographicStandard, - DigestAlgorithm digestAlgorithm, - PdfCertificate? pdfCertificate, - DateTime? signedDate, - TimestampServer? timestampServer, - ) { - this.cryptographicStandard = cryptographicStandard; - this.digestAlgorithm = digestAlgorithm; - if (signedName != null) { - this.signedName = signedName; - } - if (locationInfo != null) { - this.locationInfo = locationInfo; - } - if (reason != null) { - this.reason = reason; - } - if (contactInfo != null) { - this.contactInfo = contactInfo; - } - if (documentPermissions != null && documentPermissions.isNotEmpty) { - this.documentPermissions = documentPermissions; - } - if (pdfCertificate != null) { - certificate = pdfCertificate; - } - if (signedDate != null) { - this.signedDate = signedDate; - } - if (timestampServer != null) { - this.timestampServer = timestampServer; - } - } - - /// Add external signer for signature. - void addExternalSigner( - IPdfExternalSigner signer, - List> publicCertificatesData, - ) { - _helper.externalSigner = signer; - _externalRootCert = publicCertificatesData; - if (_externalRootCert != null) { - final X509CertificateParser parser = X509CertificateParser(); - _helper.externalChain = []; - _externalRootCert!.toList().forEach( - (List certRawData) => _helper.externalChain!.add( - parser.readCertificate(PdfStreamReader(certRawData)), - ), - ); - } - } - - /// Creates long-term validation of the signature. - /// - /// ``` dart - /// // Load the existing PDF document. - /// PdfDocument document = - /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); - /// // Create a new PDF document. - /// PdfSignatureField field = document.form.fields[0] as PdfSignatureField; - /// // Check if field is signed. - /// if (field.isSigned) { - /// // Create a long-term validation for the signature. - /// bool isLTV = await field.signature! - /// .createLongTermValidity(includePublicCertificates: true); - /// } - /// // Save the document. - /// List bytes = await document.save(); - /// // Dispose the document. - /// document.dispose(); - /// ``` - Future createLongTermValidity({ - List>? publicCertificatesData, - RevocationType type = RevocationType.ocspAndCrl, - bool includePublicCertificates = false, - }) async { - final List x509CertificateList = []; - if (publicCertificatesData != null) { - final X509CertificateParser parser = X509CertificateParser(); - for (final List certRawData in publicCertificatesData) { - final X509Certificate certificate = - parser.readCertificate(PdfStreamReader(certRawData))!; - x509CertificateList.add(certificate); - } - } else { - final List? certChain = - timestampServer != null - ? await _helper.getTimestampCertificateChain() - : _helper.getCertificateChain(); - if (certChain != null) { - for (final X509Certificate? certificate in certChain) { - if (certificate != null) { - x509CertificateList.add(certificate); - } - } - certChain.clear(); - } - } - if (x509CertificateList.isNotEmpty) { - return _helper.getDSSDetails( - x509CertificateList, - type, - includePublicCertificates, - ); - } else { - return false; - } - } -} - -/// [PdfSignature] helper -class PdfSignatureHelper { - /// internal constructor - PdfSignatureHelper(this.base); - - /// internal field - PdfSignature base; - - /// internal method - static PdfSignatureHelper getHelper(PdfSignature signature) { - return signature._helper; - } - - /// internal field - PdfPage? page; - - /// internal method - PdfSignatureField? field; - - /// internal method - PdfDocument? document; - - /// internal method - // ignore: prefer_final_fields - bool certificated = false; - - /// internal method - PdfSignatureDictionary? signatureDictionary; - - /// internal method - PdfArray? byteRange; - - /// internal method - DateTime? dateOfSign; - - /// internal method - IPdfExternalSigner? externalSigner; - - /// internal method - List? externalChain; - List? _nameData; - - /// internal method - /// To check annotation last elements have signature field - void checkAnnotationElementsContainsSignature( - PdfPage page, - String? signatureName, - ) { - if (PdfPageHelper.getHelper( - page, - ).dictionary!.containsKey(PdfDictionaryProperties.annots)) { - final IPdfPrimitive? annotationElements = PdfCrossTable.dereference( - PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties - .annots], - ); - IPdfPrimitive? lastElement; - if (annotationElements != null && - annotationElements is PdfArray && - annotationElements.elements.isNotEmpty) { - lastElement = PdfCrossTable.dereference( - annotationElements[annotationElements.elements.length - 1], - ); - } - if (lastElement != null && - lastElement is PdfDictionary && - lastElement.containsKey(PdfDictionaryProperties.t)) { - final IPdfPrimitive? name = PdfCrossTable.dereference( - lastElement[PdfDictionaryProperties.t], - ); - String tempName = ''; - if (name != null && name is PdfString) { - tempName = utf8.decode(name.data!, allowMalformed: true); - } - if (tempName == signatureName && - annotationElements != null && - annotationElements is PdfArray && - annotationElements.elements.isNotEmpty) { - annotationElements.elements.removeAt( - annotationElements.elements.length - 1, - ); - } - } - } - } - - /// internal method - void catalogBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (certificated) { - IPdfPrimitive? permission = PdfCrossTable.dereference( - PdfDocumentHelper.getHelper(document!).catalog[PdfDictionaryProperties - .perms], - ); - if (permission == null) { - permission = PdfDictionary(); - (permission as PdfDictionary)[PdfDictionaryProperties - .docMDP] = PdfReferenceHolder(signatureDictionary); - PdfDocumentHelper.getHelper(document!).catalog[PdfDictionaryProperties - .perms] = - permission; - } else if (permission is PdfDictionary && - !permission.containsKey(PdfDictionaryProperties.docMDP)) { - permission.setProperty( - PdfDictionaryProperties.docMDP, - PdfReferenceHolder(signatureDictionary), - ); - } - } - } - - /// internal method - void dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { - if (field != null) { - final PdfFieldHelper helper = PdfFieldHelper.getHelper(field!); - helper.dictionary!.encrypt = - PdfSecurityHelper.getHelper(document!.security).encryptor.encrypt; - helper.dictionary!.setProperty( - PdfDictionaryProperties.ap, - field!.appearance, - ); - } - } - - /// internal method - List getCertificateFlags(int value) { - final List result = []; - if (value & _getCertificateFlagValue(PdfCertificationFlags.forbidChanges)! > - 0) { - result.add(PdfCertificationFlags.forbidChanges); - } - if (value & _getCertificateFlagValue(PdfCertificationFlags.allowFormFill)! > - 0) { - result.add(PdfCertificationFlags.allowFormFill); - } - if (value & _getCertificateFlagValue(PdfCertificationFlags.allowComments)! > - 0) { - result.add(PdfCertificationFlags.allowComments); - } - return result; - } - - /// internal method - int getCertificateFlagResult(List flags) { - int result = 0; - flags.toList().forEach((PdfCertificationFlags flag) { - result |= _getCertificateFlagValue(flag)!; - }); - if (result == 0) { - result = 1; - } - return result; - } - - int? _getCertificateFlagValue(PdfCertificationFlags flag) { - int? result; - switch (flag) { - case PdfCertificationFlags.forbidChanges: - result = 1; - break; - case PdfCertificationFlags.allowFormFill: - result = 2; - break; - case PdfCertificationFlags.allowComments: - result = 3; - break; - } - return result; - } - - /// internal method - X509Certificate? getRoot(X509Certificate cert, List certs) { - X509Certificate parent; - for (int i = 0; i < certs.length; i++) { - parent = certs[i]; - if (!(cert.c!.issuer!.toString() == parent.c!.subject!.toString())) { - continue; - } - try { - cert.verify(parent.getPublicKey()); - return parent; - } catch (e) { - return null; - } - } - return null; - } - - /// internal method - Future getDSSDetails( - List certificates, - RevocationType type, - bool includePublicCertificates, - ) async { - final List> crlCollection = >[]; - final List> ocspCollection = >[]; - final List> certCollection = >[]; - if (includePublicCertificates) { - for (int i = 0; i < certificates.length; i++) { - certCollection.add(certificates[i].c!.getDerEncoded()!); - } - } - for (int k = 0; k < certificates.length; ++k) { - if (type == RevocationType.ocsp || - type == RevocationType.ocspAndCrl || - (crlCollection.isEmpty && type == RevocationType.ocspOrCrl)) { - final Ocsp ocsp = Ocsp(); - final List? ocspBytes = await ocsp.getEncodedOcspResponse( - certificates[k], - getRoot(certificates[k], certificates), - ); - if (ocspBytes != null) { - ocspCollection.add(buildOCSPResponse(ocspBytes)); - } - } - if (type == RevocationType.crl || - type == RevocationType.ocspAndCrl || - (ocspCollection.isEmpty && type == RevocationType.ocspOrCrl)) { - final List> cim = await RevocationList().getEncoded( - certificates[k], - ); - if (cim.isNotEmpty) { - for (final List crl in cim) { - bool duplicate = false; - for (final List element in crlCollection) { - if (_listsAreEqual(element, crl)) { - duplicate = true; - continue; - } - } - if (!duplicate) { - crlCollection.add(crl); - } - } - } - } - } - return initializeDssDictionary( - crlCollection, - ocspCollection, - certCollection, - ); - } - - bool _listsAreEqual(List list1, List list2) { - if (list1.length != list2.length) { - return false; - } - for (int i = 0; i < list1.length; i++) { - if (list1[i] != list2[i]) { - return false; - } - } - return true; - } - - /// internal method - bool initializeDssDictionary( - List> crlCollection, - List> ocspCollection, - List> certCollection, - ) { - if (crlCollection.isEmpty && - ocspCollection.isEmpty && - certCollection.isEmpty) { - return false; - } - PdfDictionary? dssDictionary; - if (document != null) { - final PdfDocumentHelper helper = PdfDocumentHelper.getHelper(document!); - if (helper.catalog.containsKey(PdfDictionaryProperties.dss)) { - final IPdfPrimitive? dss = PdfCrossTable.dereference( - helper.catalog[PdfDictionaryProperties.dss], - ); - if (dss != null && dss is PdfDictionary) { - dssDictionary = dss; - } - } - } - dssDictionary ??= PdfDictionary(); - PdfArray ocspArray = PdfArray(); - PdfArray crlArray = PdfArray(); - final PdfArray ocspVRI = PdfArray(); - final PdfArray crlVRI = PdfArray(); - PdfArray cetrsArray = PdfArray(); - if (dssDictionary.containsKey(PdfDictionaryProperties.ocsps)) { - final IPdfPrimitive? dssOcsp = PdfCrossTable.dereference( - dssDictionary[PdfDictionaryProperties.ocsps], - ); - if (dssOcsp != null && dssOcsp is PdfArray) { - ocspArray = dssOcsp; - } - } - if (dssDictionary.containsKey(PdfDictionaryProperties.crls)) { - final IPdfPrimitive? dsscrl = PdfCrossTable.dereference( - dssDictionary[PdfDictionaryProperties.crls], - ); - if (dsscrl != null && dsscrl is PdfArray) { - crlArray = dsscrl; - } - } - PdfDictionary vriDictionary = PdfDictionary(); - if (dssDictionary.containsKey(PdfDictionaryProperties.vri)) { - final IPdfPrimitive? dssVri = PdfCrossTable.dereference( - dssDictionary[PdfDictionaryProperties.vri], - ); - if (dssVri != null && dssVri is PdfDictionary) { - vriDictionary = dssVri; - } - } - if (dssDictionary.containsKey(PdfDictionaryProperties.certs)) { - final IPdfPrimitive? dssCerts = PdfCrossTable.dereference( - dssDictionary[PdfDictionaryProperties.certs], - ); - if (dssCerts != null && dssCerts is PdfArray) { - cetrsArray = dssCerts; - } - } - for (int i = 0; i < ocspCollection.length; i++) { - final PdfDictionary tempDictionary = PdfDictionary(); - final PdfStream stream = PdfStream(tempDictionary, ocspCollection[i]); - stream.compress = true; - final PdfReferenceHolder holder = PdfReferenceHolder(stream); - ocspArray.add(holder); - ocspVRI.add(holder); - } - for (int i = 0; i < crlCollection.length; i++) { - final PdfDictionary tempDictionary = PdfDictionary(); - final PdfStream stream = PdfStream(tempDictionary, crlCollection[i]); - stream.compress = true; - final PdfReferenceHolder holder = PdfReferenceHolder(stream); - crlArray.add(holder); - crlVRI.add(holder); - } - for (int i = 0; i < certCollection.length; i++) { - final PdfDictionary tempDictionary = PdfDictionary(); - final PdfStream stream = PdfStream(tempDictionary, certCollection[i]); - stream.compress = true; - final PdfReferenceHolder holder = PdfReferenceHolder(stream); - cetrsArray.add(holder); - } - final String vriName = getVRIName().toUpperCase(); - PdfDictionary vriDataDictionary = PdfDictionary(); - if (vriDictionary.containsKey(vriName)) { - final IPdfPrimitive? dssVriData = PdfCrossTable.dereference( - vriDictionary[vriName], - ); - if (dssVriData != null && dssVriData is PdfDictionary) { - vriDataDictionary = dssVriData; - } - if (vriDataDictionary.containsKey(PdfDictionaryProperties.ocsp)) { - final IPdfPrimitive? vriOCSP = PdfCrossTable.dereference( - vriDataDictionary[PdfDictionaryProperties.ocsp], - ); - if (vriOCSP != null && vriOCSP is PdfArray) { - for (int i = 0; i < ocspVRI.count; i++) { - if (!vriOCSP.contains(ocspVRI[i]!)) { - vriOCSP.add(ocspVRI[i]!); - } - } - } - } - if (vriDataDictionary.containsKey(PdfDictionaryProperties.crl)) { - final IPdfPrimitive? vriCRL = PdfCrossTable.dereference( - vriDataDictionary[PdfDictionaryProperties.crl], - ); - if (vriCRL != null && vriCRL is PdfArray) { - for (int i = 0; i < crlVRI.count; i++) { - if (!vriCRL.contains(crlVRI[i]!)) { - vriCRL.add(crlVRI[i]!); - } - } - } - } - } else { - vriDataDictionary.items![PdfName( - PdfDictionaryProperties.ocsp, - )] = PdfReferenceHolder(ocspArray); - vriDataDictionary.items![PdfName( - PdfDictionaryProperties.crl, - )] = PdfReferenceHolder(crlArray); - vriDictionary.items![PdfName( - getVRIName().toUpperCase(), - )] = PdfReferenceHolder(vriDataDictionary); - } - vriDictionary.modify(); - dssDictionary.items![PdfName( - PdfDictionaryProperties.ocsps, - )] = PdfReferenceHolder(ocspArray); - dssDictionary.items![PdfName( - PdfDictionaryProperties.crls, - )] = PdfReferenceHolder(crlArray); - dssDictionary.items![PdfName( - PdfDictionaryProperties.vri, - )] = PdfReferenceHolder(vriDictionary); - if (certCollection.isNotEmpty) { - dssDictionary.items![PdfName( - PdfDictionaryProperties.certs, - )] = PdfReferenceHolder(cetrsArray); - } - PdfDocumentHelper.getHelper(document!).catalog[PdfDictionaryProperties - .dss] = PdfReferenceHolder(dssDictionary); - dssDictionary.modify(); - return true; - } - - /// internal method - List buildOCSPResponse(List basicOCSPResponse) { - final DerOctet doctet = DerOctet(basicOCSPResponse); - final Asn1EncodeCollection v2 = Asn1EncodeCollection(); - v2.add([OcspConstants.ocspBasic]); - v2.add([doctet]); - final DerCatalogue den = DerCatalogue([0]); - final Asn1EncodeCollection v3 = Asn1EncodeCollection(); - v3.add([den]); - v3.add([DerTag(0, DerSequence(collection: v2), true)]); - final DerSequence seq = DerSequence(collection: v3); - final List b = seq.getEncoded()!; - return b; - } - - /// internal method - String getVRIName() { - if (_nameData == null && field != null) { - final PdfSignatureFieldHelper helper = PdfSignatureFieldHelper.getHelper( - field!, - ); - if (helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - final IPdfPrimitive? v = PdfCrossTable.dereference( - helper.dictionary![PdfDictionaryProperties.v], - ); - if (v != null && - v is PdfDictionary && - v.containsKey(PdfDictionaryProperties.contents)) { - final IPdfPrimitive? contents = PdfCrossTable.dereference( - v[PdfDictionaryProperties.contents], - ); - if (contents != null && contents is PdfString) { - _nameData = contents.data; - } - } - } - } - _nameData ??= utf8.encode(_generateUuid()); - final dynamic output = AccumulatorSink(); - final dynamic input = sha1.startChunkedConversion(output); - input.add(_nameData); - input.close(); - final List data = output.events.single.bytes as List; - return PdfString.bytesToHex(data); - } - - String _generateUuid() { - final Random random = Random(); - final StringBuffer buffer = StringBuffer(); - for (int i = 0; i < 32; i++) { - if (i == 8 || i == 12 || i == 16 || i == 20) { - buffer.write('-'); - } - final int digit = - i == 12 - ? 4 // Specifies the version (4) for UUID v4 - : (i == 16 ? (random.nextInt(4) + 8) : random.nextInt(16)); - buffer.write(digit.toRadixString(16)); - } - return buffer.toString(); - } - - /// internal method - List? getCertificateChain() { - if (field != null) { - try { - final PdfSignatureFieldHelper helper = - PdfSignatureFieldHelper.getHelper(field!); - if (helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { - final IPdfPrimitive? v = PdfCrossTable.dereference( - helper.dictionary![PdfDictionaryProperties.v], - ); - if (v != null && - v is PdfDictionary && - v.containsKey(PdfDictionaryProperties.contents)) { - final IPdfPrimitive? contents = PdfCrossTable.dereference( - v[PdfDictionaryProperties.contents], - ); - if (contents != null && contents is PdfString) { - final List? sigByte = contents.data; - if (sigByte != null) { - final X509CertificateParser parser = X509CertificateParser(); - final List? certificateChain = parser - .getCertificateChain(PdfStreamReader(sigByte)); - if (certificateChain != null) { - return certificateChain; - } - _nameData = sigByte; - } - } - } - } - } catch (e) { - return null; - } - } - return null; - } - - /// internal method - Future?> getTimestampCertificateChain() async { - try { - final dynamic output = AccumulatorSink(); - final dynamic input = sha256.startChunkedConversion(output); - input.add(base64.decode('VABlAHMAdAAgAGQAYQB0AGEA')); //Test unicode data - input.close(); - final List hash = output.events.single.bytes as List; - final List asnEncodedTimestampRequest = TimeStampRequestCreator() - .getAsnEncodedTimestampRequest(hash); - final List? timeStampResponse = await fetchData( - base.timestampServer!.uri, - 'POST', - contentType: 'application/timestamp-query', - userName: base.timestampServer!.userName, - password: base.timestampServer!.password, - data: asnEncodedTimestampRequest, - timeOutDuration: base.timestampServer!.timeOut, - ); - if (timeStampResponse != null) { - List? encoded; - final Asn1Stream stream = Asn1Stream( - PdfStreamReader(timeStampResponse), - ); - final Asn1? asn1 = stream.readAsn1(); - if (asn1 != null && - asn1 is Asn1Sequence && - asn1.count > 1 && - asn1[1] != null && - asn1[1] is Asn1) { - final Asn1 asn1Sequence = asn1[1]! as Asn1; - final DerStream dOut = DerStream([]); - asn1Sequence.encode(dOut); - encoded = dOut.stream!.toList(); - dOut.stream!.clear(); - } - if (encoded != null) { - final X509CertificateParser parser = X509CertificateParser(); - final List? certificateChain = parser - .getCertificateChain(PdfStreamReader(encoded)); - if (certificateChain != null) { - return certificateChain; - } - _nameData = encoded; - } - } - } catch (e) { - return null; - } - return null; - } -} - -/// Specifies the type of revocation to be considered during the LTV enable process and their corresponding actions. -enum RevocationType { - /// Embeds the OCSP data to the PDF document. - ocsp, - - /// Embeds the CRL data to the PDF document. - crl, - - /// Embeds both OCSP and CRL data to the PDF document. - ocspAndCrl, - - /// Embeds OCSP or CRL data to the PDF document. - ocspOrCrl, -} +import 'dart:convert'; +import 'dart:math'; + +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../forms/pdf_field.dart'; +import '../../forms/pdf_signature_field.dart'; +import '../../io/pdf_constants.dart'; +import '../../io/pdf_cross_table.dart'; +import '../../io/stream_reader.dart'; +import '../../pages/pdf_page.dart'; +import '../../pdf_document/pdf_document.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_stream.dart'; +import '../../primitives/pdf_string.dart'; +import '../enum.dart'; +import '../pdf_security.dart'; +import 'asn1/asn1.dart'; +import 'asn1/asn1_stream.dart'; +import 'asn1/der.dart'; +import 'pdf_certificate.dart'; +import 'pdf_external_signer.dart'; +import 'pdf_signature_dictionary.dart'; +import 'time_stamp_server/time_stamp_server.dart'; +import 'x509/ocsp_utils.dart'; +import 'x509/x509_certificates.dart'; + +/// Represents a digital signature used for signing a PDF document. +class PdfSignature { + //Constructor + /// Initializes a new instance of the [PdfSignature] class with the page and the signature name. + PdfSignature({ + String? signedName, + String? locationInfo, + String? reason, + String? contactInfo, + List? documentPermissions, + CryptographicStandard cryptographicStandard = CryptographicStandard.cms, + DigestAlgorithm digestAlgorithm = DigestAlgorithm.sha256, + PdfCertificate? certificate, + TimestampServer? timestampServer, + DateTime? signedDate, + }) { + _helper = PdfSignatureHelper(this); + _init( + signedName, + locationInfo, + reason, + contactInfo, + documentPermissions, + cryptographicStandard, + digestAlgorithm, + certificate, + signedDate, + timestampServer, + ); + } + + //Fields + late PdfSignatureHelper _helper; + List>? _externalRootCert; + + //Properties + /// Gets or sets the permission for certificated document. + List documentPermissions = [ + PdfCertificationFlags.forbidChanges, + ]; + + /// Gets or sets reason of signing. + String? reason; + + /// Gets or sets the physical location of the signing. + String? locationInfo; + + /// Gets or sets the signed name + String? signedName; + + /// Gets or sets the signed date. + /// + /// NOTE: The signed date can only be set when signing the PDF document and does not work on existing signatures. + DateTime? get signedDate => _helper.dateOfSign; + + set signedDate(DateTime? value) { + _helper.dateOfSign = value; + } + + /// Gets or sets cryptographic standard. + late CryptographicStandard cryptographicStandard; + + /// Gets or sets digestion algorithm. + late DigestAlgorithm digestAlgorithm; + + /// Gets or sets information provided by the signer to enable a recipient to contact + /// the signer to verify the signature; for example, a phone number. + String? contactInfo; + + /// Gets or sets the certificate + PdfCertificate? certificate; + + /// Gets or sets time stamping server unique resource identifier. + /// + /// The timestamp is only embedded when signing the PDF document and + /// saving asynchronously. + /// + /// ```dart + /// //Creates a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Adds a new page + /// PdfPage page = document.pages.add(); + /// //Creates a digital signature and sets signature information + /// PdfSignatureField field = PdfSignatureField(page, 'signature', + /// bounds: Rect.fromLTWH(0, 0, 200, 100), + /// signature: PdfSignature( + /// //Creates a certificate instance from the PFX file with a private key + /// certificate: PdfCertificate( + /// File('D:/PDF.pfx').readAsBytesSync(), 'syncfusion'), + /// contactInfo: 'johndoe@owned.us', + /// locationInfo: 'Honolulu, Hawaii', + /// reason: 'I am author of this document.', + /// //Create a new PDF time stamp server + /// timestampServer: + /// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')))); + /// //Add a signature field to the form + /// document.form.fields.add(field); + /// //Save and dispose the PDF document + /// File('Output.pdf').writeAsBytes(await document.save()); + /// document.dispose(); + /// ``` + TimestampServer? timestampServer; + + //Implementations + void _init( + String? signedName, + String? locationInfo, + String? reason, + String? contactInfo, + List? documentPermissions, + CryptographicStandard cryptographicStandard, + DigestAlgorithm digestAlgorithm, + PdfCertificate? pdfCertificate, + DateTime? signedDate, + TimestampServer? timestampServer, + ) { + this.cryptographicStandard = cryptographicStandard; + this.digestAlgorithm = digestAlgorithm; + if (signedName != null) { + this.signedName = signedName; + } + if (locationInfo != null) { + this.locationInfo = locationInfo; + } + if (reason != null) { + this.reason = reason; + } + if (contactInfo != null) { + this.contactInfo = contactInfo; + } + if (documentPermissions != null && documentPermissions.isNotEmpty) { + this.documentPermissions = documentPermissions; + } + if (pdfCertificate != null) { + certificate = pdfCertificate; + } + if (signedDate != null) { + this.signedDate = signedDate; + } + if (timestampServer != null) { + this.timestampServer = timestampServer; + } + } + + /// Add external signer for signature. + void addExternalSigner( + IPdfExternalSigner signer, + List> publicCertificatesData, + ) { + _helper.externalSigner = signer; + _externalRootCert = publicCertificatesData; + if (_externalRootCert != null) { + final X509CertificateParser parser = X509CertificateParser(); + _helper.externalChain = []; + _externalRootCert!.toList().forEach( + (List certRawData) => _helper.externalChain!.add( + parser.readCertificate(PdfStreamReader(certRawData)), + ), + ); + } + } + + /// Creates long-term validation of the signature. + /// + /// ``` dart + /// // Load the existing PDF document. + /// PdfDocument document = + /// PdfDocument(inputBytes: File('input.pdf').readAsBytesSync()); + /// // Create a new PDF document. + /// PdfSignatureField field = document.form.fields[0] as PdfSignatureField; + /// // Check if field is signed. + /// if (field.isSigned) { + /// // Create a long-term validation for the signature. + /// bool isLTV = await field.signature! + /// .createLongTermValidity(includePublicCertificates: true); + /// } + /// // Save the document. + /// List bytes = await document.save(); + /// // Dispose the document. + /// document.dispose(); + /// ``` + Future createLongTermValidity({ + List>? publicCertificatesData, + RevocationType type = RevocationType.ocspAndCrl, + bool includePublicCertificates = false, + }) async { + final List x509CertificateList = []; + if (publicCertificatesData != null) { + final X509CertificateParser parser = X509CertificateParser(); + for (final List certRawData in publicCertificatesData) { + final X509Certificate certificate = + parser.readCertificate(PdfStreamReader(certRawData))!; + x509CertificateList.add(certificate); + } + } else { + final List? certChain = + timestampServer != null + ? await _helper.getTimestampCertificateChain() + : _helper.getCertificateChain(); + if (certChain != null) { + for (final X509Certificate? certificate in certChain) { + if (certificate != null) { + x509CertificateList.add(certificate); + } + } + certChain.clear(); + } + } + if (x509CertificateList.isNotEmpty) { + return _helper.getDSSDetails( + x509CertificateList, + type, + includePublicCertificates, + ); + } else { + return false; + } + } +} + +/// [PdfSignature] helper +class PdfSignatureHelper { + /// internal constructor + PdfSignatureHelper(this.base); + + /// internal field + PdfSignature base; + + /// internal method + static PdfSignatureHelper getHelper(PdfSignature signature) { + return signature._helper; + } + + /// internal field + PdfPage? page; + + /// internal method + PdfSignatureField? field; + + /// internal method + PdfDocument? document; + + /// internal method + // ignore: prefer_final_fields + bool certificated = false; + + /// internal method + PdfSignatureDictionary? signatureDictionary; + + /// internal method + PdfArray? byteRange; + + /// internal method + DateTime? dateOfSign; + + /// internal method + IPdfExternalSigner? externalSigner; + + /// internal method + List? externalChain; + List? _nameData; + + /// internal method + /// To check annotation last elements have signature field + void checkAnnotationElementsContainsSignature( + PdfPage page, + String? signatureName, + ) { + if (PdfPageHelper.getHelper( + page, + ).dictionary!.containsKey(PdfDictionaryProperties.annots)) { + final IPdfPrimitive? annotationElements = PdfCrossTable.dereference( + PdfPageHelper.getHelper(page).dictionary![PdfDictionaryProperties + .annots], + ); + IPdfPrimitive? lastElement; + if (annotationElements != null && + annotationElements is PdfArray && + annotationElements.elements.isNotEmpty) { + lastElement = PdfCrossTable.dereference( + annotationElements[annotationElements.elements.length - 1], + ); + } + if (lastElement != null && + lastElement is PdfDictionary && + lastElement.containsKey(PdfDictionaryProperties.t)) { + final IPdfPrimitive? name = PdfCrossTable.dereference( + lastElement[PdfDictionaryProperties.t], + ); + String tempName = ''; + if (name != null && name is PdfString) { + tempName = utf8.decode(name.data!, allowMalformed: true); + } + if (tempName == signatureName && + annotationElements != null && + annotationElements is PdfArray && + annotationElements.elements.isNotEmpty) { + annotationElements.elements.removeAt( + annotationElements.elements.length - 1, + ); + } + } + } + } + + /// internal method + void catalogBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (certificated) { + IPdfPrimitive? permission = PdfCrossTable.dereference( + PdfDocumentHelper.getHelper(document!).catalog[PdfDictionaryProperties + .perms], + ); + if (permission == null) { + permission = PdfDictionary(); + (permission as PdfDictionary)[PdfDictionaryProperties + .docMDP] = PdfReferenceHolder(signatureDictionary); + PdfDocumentHelper.getHelper(document!).catalog[PdfDictionaryProperties + .perms] = + permission; + } else if (permission is PdfDictionary && + !permission.containsKey(PdfDictionaryProperties.docMDP)) { + permission.setProperty( + PdfDictionaryProperties.docMDP, + PdfReferenceHolder(signatureDictionary), + ); + } + } + } + + /// internal method + void dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? ars) { + if (field != null) { + final PdfFieldHelper helper = PdfFieldHelper.getHelper(field!); + helper.dictionary!.encrypt = + PdfSecurityHelper.getHelper(document!.security).encryptor.encrypt; + helper.dictionary!.setProperty( + PdfDictionaryProperties.ap, + field!.appearance, + ); + } + } + + /// internal method + List getCertificateFlags(int value) { + final List result = []; + if (value & _getCertificateFlagValue(PdfCertificationFlags.forbidChanges)! > + 0) { + result.add(PdfCertificationFlags.forbidChanges); + } + if (value & _getCertificateFlagValue(PdfCertificationFlags.allowFormFill)! > + 0) { + result.add(PdfCertificationFlags.allowFormFill); + } + if (value & _getCertificateFlagValue(PdfCertificationFlags.allowComments)! > + 0) { + result.add(PdfCertificationFlags.allowComments); + } + return result; + } + + /// internal method + int getCertificateFlagResult(List flags) { + int result = 0; + flags.toList().forEach((PdfCertificationFlags flag) { + result |= _getCertificateFlagValue(flag)!; + }); + if (result == 0) { + result = 1; + } + return result; + } + + int? _getCertificateFlagValue(PdfCertificationFlags flag) { + int? result; + switch (flag) { + case PdfCertificationFlags.forbidChanges: + result = 1; + break; + case PdfCertificationFlags.allowFormFill: + result = 2; + break; + case PdfCertificationFlags.allowComments: + result = 3; + break; + } + return result; + } + + /// internal method + X509Certificate? getRoot(X509Certificate cert, List certs) { + X509Certificate parent; + for (int i = 0; i < certs.length; i++) { + parent = certs[i]; + if (!(cert.c!.issuer!.toString() == parent.c!.subject!.toString())) { + continue; + } + try { + cert.verify(parent.getPublicKey()); + return parent; + } catch (e) { + return null; + } + } + return null; + } + + /// internal method + Future getDSSDetails( + List certificates, + RevocationType type, + bool includePublicCertificates, + ) async { + final List> crlCollection = >[]; + final List> ocspCollection = >[]; + final List> certCollection = >[]; + if (includePublicCertificates) { + for (int i = 0; i < certificates.length; i++) { + certCollection.add(certificates[i].c!.getDerEncoded()!); + } + } + for (int k = 0; k < certificates.length; ++k) { + if (type == RevocationType.ocsp || + type == RevocationType.ocspAndCrl || + (crlCollection.isEmpty && type == RevocationType.ocspOrCrl)) { + final Ocsp ocsp = Ocsp(); + final List? ocspBytes = await ocsp.getEncodedOcspResponse( + certificates[k], + getRoot(certificates[k], certificates), + ); + if (ocspBytes != null) { + ocspCollection.add(buildOCSPResponse(ocspBytes)); + } + } + if (type == RevocationType.crl || + type == RevocationType.ocspAndCrl || + (ocspCollection.isEmpty && type == RevocationType.ocspOrCrl)) { + final List> cim = await RevocationList().getEncoded( + certificates[k], + ); + if (cim.isNotEmpty) { + for (final List crl in cim) { + bool duplicate = false; + for (final List element in crlCollection) { + if (_listsAreEqual(element, crl)) { + duplicate = true; + continue; + } + } + if (!duplicate) { + crlCollection.add(crl); + } + } + } + } + } + return initializeDssDictionary( + crlCollection, + ocspCollection, + certCollection, + ); + } + + bool _listsAreEqual(List list1, List list2) { + if (list1.length != list2.length) { + return false; + } + for (int i = 0; i < list1.length; i++) { + if (list1[i] != list2[i]) { + return false; + } + } + return true; + } + + /// internal method + bool initializeDssDictionary( + List> crlCollection, + List> ocspCollection, + List> certCollection, + ) { + if (crlCollection.isEmpty && + ocspCollection.isEmpty && + certCollection.isEmpty) { + return false; + } + PdfDictionary? dssDictionary; + if (document != null) { + final PdfDocumentHelper helper = PdfDocumentHelper.getHelper(document!); + if (helper.catalog.containsKey(PdfDictionaryProperties.dss)) { + final IPdfPrimitive? dss = PdfCrossTable.dereference( + helper.catalog[PdfDictionaryProperties.dss], + ); + if (dss != null && dss is PdfDictionary) { + dssDictionary = dss; + } + } + } + dssDictionary ??= PdfDictionary(); + PdfArray ocspArray = PdfArray(); + PdfArray crlArray = PdfArray(); + final PdfArray ocspVRI = PdfArray(); + final PdfArray crlVRI = PdfArray(); + PdfArray cetrsArray = PdfArray(); + if (dssDictionary.containsKey(PdfDictionaryProperties.ocsps)) { + final IPdfPrimitive? dssOcsp = PdfCrossTable.dereference( + dssDictionary[PdfDictionaryProperties.ocsps], + ); + if (dssOcsp != null && dssOcsp is PdfArray) { + ocspArray = dssOcsp; + } + } + if (dssDictionary.containsKey(PdfDictionaryProperties.crls)) { + final IPdfPrimitive? dsscrl = PdfCrossTable.dereference( + dssDictionary[PdfDictionaryProperties.crls], + ); + if (dsscrl != null && dsscrl is PdfArray) { + crlArray = dsscrl; + } + } + PdfDictionary vriDictionary = PdfDictionary(); + if (dssDictionary.containsKey(PdfDictionaryProperties.vri)) { + final IPdfPrimitive? dssVri = PdfCrossTable.dereference( + dssDictionary[PdfDictionaryProperties.vri], + ); + if (dssVri != null && dssVri is PdfDictionary) { + vriDictionary = dssVri; + } + } + if (dssDictionary.containsKey(PdfDictionaryProperties.certs)) { + final IPdfPrimitive? dssCerts = PdfCrossTable.dereference( + dssDictionary[PdfDictionaryProperties.certs], + ); + if (dssCerts != null && dssCerts is PdfArray) { + cetrsArray = dssCerts; + } + } + for (int i = 0; i < ocspCollection.length; i++) { + final PdfDictionary tempDictionary = PdfDictionary(); + final PdfStream stream = PdfStream(tempDictionary, ocspCollection[i]); + stream.compress = true; + final PdfReferenceHolder holder = PdfReferenceHolder(stream); + ocspArray.add(holder); + ocspVRI.add(holder); + } + for (int i = 0; i < crlCollection.length; i++) { + final PdfDictionary tempDictionary = PdfDictionary(); + final PdfStream stream = PdfStream(tempDictionary, crlCollection[i]); + stream.compress = true; + final PdfReferenceHolder holder = PdfReferenceHolder(stream); + crlArray.add(holder); + crlVRI.add(holder); + } + for (int i = 0; i < certCollection.length; i++) { + final PdfDictionary tempDictionary = PdfDictionary(); + final PdfStream stream = PdfStream(tempDictionary, certCollection[i]); + stream.compress = true; + final PdfReferenceHolder holder = PdfReferenceHolder(stream); + cetrsArray.add(holder); + } + final String vriName = getVRIName().toUpperCase(); + PdfDictionary vriDataDictionary = PdfDictionary(); + if (vriDictionary.containsKey(vriName)) { + final IPdfPrimitive? dssVriData = PdfCrossTable.dereference( + vriDictionary[vriName], + ); + if (dssVriData != null && dssVriData is PdfDictionary) { + vriDataDictionary = dssVriData; + } + if (vriDataDictionary.containsKey(PdfDictionaryProperties.ocsp)) { + final IPdfPrimitive? vriOCSP = PdfCrossTable.dereference( + vriDataDictionary[PdfDictionaryProperties.ocsp], + ); + if (vriOCSP != null && vriOCSP is PdfArray) { + for (int i = 0; i < ocspVRI.count; i++) { + if (!vriOCSP.contains(ocspVRI[i]!)) { + vriOCSP.add(ocspVRI[i]!); + } + } + } + } + if (vriDataDictionary.containsKey(PdfDictionaryProperties.crl)) { + final IPdfPrimitive? vriCRL = PdfCrossTable.dereference( + vriDataDictionary[PdfDictionaryProperties.crl], + ); + if (vriCRL != null && vriCRL is PdfArray) { + for (int i = 0; i < crlVRI.count; i++) { + if (!vriCRL.contains(crlVRI[i]!)) { + vriCRL.add(crlVRI[i]!); + } + } + } + } + } else { + vriDataDictionary.items![PdfName( + PdfDictionaryProperties.ocsp, + )] = PdfReferenceHolder(ocspArray); + vriDataDictionary.items![PdfName( + PdfDictionaryProperties.crl, + )] = PdfReferenceHolder(crlArray); + vriDictionary.items![PdfName( + getVRIName().toUpperCase(), + )] = PdfReferenceHolder(vriDataDictionary); + } + vriDictionary.modify(); + dssDictionary.items![PdfName( + PdfDictionaryProperties.ocsps, + )] = PdfReferenceHolder(ocspArray); + dssDictionary.items![PdfName( + PdfDictionaryProperties.crls, + )] = PdfReferenceHolder(crlArray); + dssDictionary.items![PdfName( + PdfDictionaryProperties.vri, + )] = PdfReferenceHolder(vriDictionary); + if (certCollection.isNotEmpty) { + dssDictionary.items![PdfName( + PdfDictionaryProperties.certs, + )] = PdfReferenceHolder(cetrsArray); + } + PdfDocumentHelper.getHelper(document!).catalog[PdfDictionaryProperties + .dss] = PdfReferenceHolder(dssDictionary); + dssDictionary.modify(); + return true; + } + + /// internal method + List buildOCSPResponse(List basicOCSPResponse) { + final DerOctet doctet = DerOctet(basicOCSPResponse); + final Asn1EncodeCollection v2 = Asn1EncodeCollection(); + v2.add([OcspConstants.ocspBasic]); + v2.add([doctet]); + final DerCatalogue den = DerCatalogue([0]); + final Asn1EncodeCollection v3 = Asn1EncodeCollection(); + v3.add([den]); + v3.add([DerTag(0, DerSequence(collection: v2), true)]); + final DerSequence seq = DerSequence(collection: v3); + final List b = seq.getEncoded()!; + return b; + } + + /// internal method + String getVRIName() { + if (_nameData == null && field != null) { + final PdfSignatureFieldHelper helper = PdfSignatureFieldHelper.getHelper( + field!, + ); + if (helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + final IPdfPrimitive? v = PdfCrossTable.dereference( + helper.dictionary![PdfDictionaryProperties.v], + ); + if (v != null && + v is PdfDictionary && + v.containsKey(PdfDictionaryProperties.contents)) { + final IPdfPrimitive? contents = PdfCrossTable.dereference( + v[PdfDictionaryProperties.contents], + ); + if (contents != null && contents is PdfString) { + _nameData = contents.data; + } + } + } + } + _nameData ??= utf8.encode(_generateUuid()); + final dynamic output = AccumulatorSink(); + final dynamic input = sha1.startChunkedConversion(output); + input.add(_nameData); + input.close(); + final List data = output.events.single.bytes as List; + return PdfString.bytesToHex(data); + } + + String _generateUuid() { + final Random random = Random(); + final StringBuffer buffer = StringBuffer(); + for (int i = 0; i < 32; i++) { + if (i == 8 || i == 12 || i == 16 || i == 20) { + buffer.write('-'); + } + final int digit = + i == 12 + ? 4 // Specifies the version (4) for UUID v4 + : (i == 16 ? (random.nextInt(4) + 8) : random.nextInt(16)); + buffer.write(digit.toRadixString(16)); + } + return buffer.toString(); + } + + /// internal method + List? getCertificateChain() { + if (field != null) { + try { + final PdfSignatureFieldHelper helper = + PdfSignatureFieldHelper.getHelper(field!); + if (helper.dictionary!.containsKey(PdfDictionaryProperties.v)) { + final IPdfPrimitive? v = PdfCrossTable.dereference( + helper.dictionary![PdfDictionaryProperties.v], + ); + if (v != null && + v is PdfDictionary && + v.containsKey(PdfDictionaryProperties.contents)) { + final IPdfPrimitive? contents = PdfCrossTable.dereference( + v[PdfDictionaryProperties.contents], + ); + if (contents != null && contents is PdfString) { + final List? sigByte = contents.data; + if (sigByte != null) { + final X509CertificateParser parser = X509CertificateParser(); + final List? certificateChain = parser + .getCertificateChain(PdfStreamReader(sigByte)); + if (certificateChain != null) { + return certificateChain; + } + _nameData = sigByte; + } + } + } + } + } catch (e) { + return null; + } + } + return null; + } + + /// internal method + Future?> getTimestampCertificateChain() async { + try { + final dynamic output = AccumulatorSink(); + final dynamic input = sha256.startChunkedConversion(output); + input.add(base64.decode('VABlAHMAdAAgAGQAYQB0AGEA')); //Test unicode data + input.close(); + final List hash = output.events.single.bytes as List; + final List asnEncodedTimestampRequest = TimeStampRequestCreator() + .getAsnEncodedTimestampRequest(hash); + final List? timeStampResponse = await fetchData( + base.timestampServer!.uri, + 'POST', + contentType: 'application/timestamp-query', + userName: base.timestampServer!.userName, + password: base.timestampServer!.password, + data: asnEncodedTimestampRequest, + timeOutDuration: base.timestampServer!.timeOut, + ); + if (timeStampResponse != null) { + List? encoded; + final Asn1Stream stream = Asn1Stream( + PdfStreamReader(timeStampResponse), + ); + final Asn1? asn1 = stream.readAsn1(); + if (asn1 != null && + asn1 is Asn1Sequence && + asn1.count > 1 && + asn1[1] != null && + asn1[1] is Asn1) { + final Asn1 asn1Sequence = asn1[1]! as Asn1; + final DerStream dOut = DerStream([]); + asn1Sequence.encode(dOut); + encoded = dOut.stream!.toList(); + dOut.stream!.clear(); + } + if (encoded != null) { + final X509CertificateParser parser = X509CertificateParser(); + final List? certificateChain = parser + .getCertificateChain(PdfStreamReader(encoded)); + if (certificateChain != null) { + return certificateChain; + } + _nameData = encoded; + } + } + } catch (e) { + return null; + } + return null; + } +} + +/// Specifies the type of revocation to be considered during the LTV enable process and their corresponding actions. +enum RevocationType { + /// Embeds the OCSP data to the PDF document. + ocsp, + + /// Embeds the CRL data to the PDF document. + crl, + + /// Embeds both OCSP and CRL data to the PDF document. + ocspAndCrl, + + /// Embeds OCSP or CRL data to the PDF document. + ocspOrCrl, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart index ac3d63ed3..fed8e2ebc 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pdf_signature_dictionary.dart @@ -1,2084 +1,2081 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:math'; - -import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; -import 'package:intl/intl.dart'; - -import '../../../interfaces/pdf_interface.dart'; -import '../../io/pdf_constants.dart'; -import '../../io/pdf_cross_table.dart'; -import '../../io/pdf_writer.dart'; -import '../../io/stream_reader.dart'; -import '../../pdf_document/pdf_document.dart'; -import '../../primitives/pdf_array.dart'; -import '../../primitives/pdf_dictionary.dart'; -import '../../primitives/pdf_name.dart'; -import '../../primitives/pdf_number.dart'; -import '../../primitives/pdf_reference_holder.dart'; -import '../../primitives/pdf_string.dart'; -import '../enum.dart'; -import '../pdf_security.dart'; -import 'asn1/asn1.dart'; -import 'asn1/asn1_stream.dart'; -import 'asn1/der.dart'; -import 'cryptography/cipher_block_chaining_mode.dart'; -import 'cryptography/cipher_utils.dart'; -import 'cryptography/ipadding.dart'; -import 'cryptography/pkcs1_encoding.dart'; -import 'cryptography/rsa_algorithm.dart'; -import 'cryptography/signature_utilities.dart'; -import 'pdf_certificate.dart'; -import 'pdf_external_signer.dart'; -import 'pdf_signature.dart'; -import 'pkcs/password_utility.dart'; -import 'pkcs/pfx_data.dart'; -import 'time_stamp_server/time_stamp_server.dart'; -import 'x509/ocsp_utils.dart'; -import 'x509/x509_certificates.dart'; - -/// Represents signature dictionary. -class PdfSignatureDictionary implements IPdfWrapper { - /// internal constructor - PdfSignatureDictionary(PdfDocument doc, PdfSignature sig) { - _doc = doc; - _sig = sig; - (PdfDocumentHelper.getHelper(doc).documentSavedList ??= - []) - .add(_documentSaved); - (PdfDocumentHelper.getHelper(doc).documentSavedListAsync ??= - []) - .add(_documentSavedAsync); - dictionary!.beginSaveList ??= []; - dictionary!.beginSaveList!.add(_dictionaryBeginSave); - _cert = sig.certificate; - } - - /// internal constructor - PdfSignatureDictionary.fromDictionary(PdfDocument doc, this.dictionary) { - _doc = doc; - (PdfDocumentHelper.getHelper(doc).documentSavedList ??= - []) - .add(_documentSaved); - (PdfDocumentHelper.getHelper(doc).documentSavedListAsync ??= - []) - .add(_documentSavedAsync); - dictionary!.beginSaveList ??= []; - dictionary!.beginSaveList!.add(_dictionaryBeginSave); - } - - //Fields - /// internal field - PdfDictionary? dictionary = PdfDictionary(); - late PdfDocument _doc; - PdfSignature? _sig; - final String _transParam = 'TransformParams'; - final String _docMdp = 'DocMDP'; - final String _cmsFilterType = 'adbe.pkcs7.detached'; - final String _cadasFilterType = 'ETSI.CAdES.detached'; - final String _rfcFilterType = 'ETSI.RFC3161'; - int? _firstRangeLength; - int? _secondRangeIndex; - int? _startPositionByteRange; - final int _estimatedSize = 8192; - PdfCertificate? _cert; - late List _range; - List? _stream; - - //Implementations - void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? args) { - final bool state = - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt; - dictionary!.encrypt = state; - if (_sig != null) { - _addRequiredItems(); - _addOptionalItems(); - } - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = false; - _addContents(args!.writer!); - _addRange(args.writer!); - if (_sig != null) { - if (PdfSignatureHelper.getHelper(_sig!).certificated) { - _addDigest(args.writer); - } - } - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = state; - } - - void _addRequiredItems() { - if (PdfSignatureHelper.getHelper(_sig!).certificated && _allowMDP()) { - _addReference(); - } - _addType(); - _addDate(); - _addFilter(); - _addSubFilter(); - } - - void _addOptionalItems() { - if (_sig != null) { - if (_sig!.reason != null) { - dictionary!.setProperty( - PdfDictionaryProperties.reason, - PdfString(_sig!.reason!), - ); - } - if (_sig!.locationInfo != null) { - dictionary!.setProperty( - PdfDictionaryProperties.location, - PdfString(_sig!.locationInfo!), - ); - } - if (_sig!.contactInfo != null) { - dictionary!.setProperty( - PdfDictionaryProperties.contactInfo, - PdfString(_sig!.contactInfo!), - ); - } - if (_sig!.signedName != null) { - dictionary!.setString(PdfDictionaryProperties.name, _sig!.signedName); - final PdfDictionary tempDictionary = PdfDictionary(); - final PdfDictionary appDictionary = PdfDictionary(); - tempDictionary.setName( - PdfName(PdfDictionaryProperties.name), - _sig!.signedName, - ); - appDictionary.setProperty('App', PdfReferenceHolder(tempDictionary)); - dictionary!.setProperty( - PdfName('Prop_Build'), - PdfReferenceHolder(appDictionary), - ); - } - } - } - - bool _allowMDP() { - final IPdfPrimitive? perms = PdfCrossTable.dereference( - PdfDocumentHelper.getHelper(_doc).catalog[PdfDictionaryProperties.perms], - ); - if (perms != null && perms is PdfDictionary) { - final IPdfPrimitive? docMDP = PdfCrossTable.dereference( - perms[PdfDictionaryProperties.docMDP], - ); - final IPdfPrimitive dicSig = dictionary!; - return dicSig == docMDP; - } - return false; - } - - void _addReference() { - final PdfDictionary trans = PdfDictionary(); - final PdfDictionary reference = PdfDictionary(); - final PdfArray array = PdfArray(); - trans[PdfDictionaryProperties.v] = PdfName('1.2'); - trans[PdfDictionaryProperties.p] = PdfNumber( - PdfSignatureHelper.getHelper( - _sig!, - ).getCertificateFlagResult(_sig!.documentPermissions), - ); - trans[PdfDictionaryProperties.type] = PdfName(_transParam); - reference[PdfDictionaryProperties.transformMethod] = PdfName(_docMdp); - reference[PdfDictionaryProperties.type] = PdfName('SigRef'); - reference[_transParam] = trans; - array.add(reference); - dictionary!.setProperty('Reference', array); - } - - void _addType() { - if (_sig != null && _sig!.timestampServer != null && _cert == null) { - dictionary!.setName( - PdfName(PdfDictionaryProperties.type), - 'DocTimeStamp', - ); - } else { - dictionary!.setName(PdfName(PdfDictionaryProperties.type), 'Sig'); - } - } - - void _addDate() { - DateTime dateTime = DateTime.now(); - if (_sig != null && _sig!.signedDate != null) { - dateTime = _sig!.signedDate!; - } - final DateFormat dateFormat = DateFormat('yyyyMMddHHmmss'); - final int regionMinutes = dateTime.timeZoneOffset.inMinutes ~/ 11; - String offsetMinutes = regionMinutes.toString(); - if (regionMinutes >= 0 && regionMinutes <= 9) { - offsetMinutes = '0$offsetMinutes'; - } - final int regionHours = dateTime.timeZoneOffset.inHours; - String offsetHours = regionHours.toString(); - if (regionHours >= 0 && regionHours <= 9) { - offsetHours = '0$offsetHours'; - } - dictionary!.setProperty( - PdfDictionaryProperties.m, - PdfString( - "D:${dateFormat.format(dateTime)}+$offsetHours'$offsetMinutes'", - ), - ); - } - - void _addFilter() { - dictionary!.setName( - PdfName(PdfDictionaryProperties.filter), - 'Adobe.PPKLite', - ); - } - - void _addSubFilter() { - if (_sig != null && _sig!.timestampServer != null && _cert == null) { - dictionary!.setName( - PdfName(PdfDictionaryProperties.subFilter), - _rfcFilterType, - ); - } else { - dictionary!.setName( - PdfName(PdfDictionaryProperties.subFilter), - _sig!.cryptographicStandard == CryptographicStandard.cades - ? _cadasFilterType - : _cmsFilterType, - ); - } - } - - void _addContents(IPdfWriter writer) { - writer.write( - PdfOperators.slash + - PdfDictionaryProperties.contents + - PdfOperators.whiteSpace, - ); - _firstRangeLength = writer.position; - int length = _estimatedSize * 2; - if (_sig != null && _cert != null) { - length = _estimatedSize; - if (_sig!.timestampServer != null) { - length += 4192; - } - } - final List contents = List.filled( - length * 2 + 2, - 0, - growable: true, - ); - writer.write(contents); - _secondRangeIndex = writer.position; - writer.write(PdfOperators.newLine); - } - - void _addRange(IPdfWriter writer) { - writer.write( - PdfOperators.slash + - PdfDictionaryProperties.byteRange + - PdfOperators.whiteSpace + - PdfArray.startMark, - ); - _startPositionByteRange = writer.position; - for (int i = 0; i < 32; i++) { - writer.write(PdfOperators.whiteSpace); - } - writer.write(PdfArray.endMark + PdfOperators.newLine); - } - - void _addDigest(IPdfWriter? writer) { - if (_allowMDP()) { - final PdfDictionary cat = - PdfDocumentHelper.getHelper(writer!.document!).catalog; - writer.write(PdfName(PdfDictionaryProperties.reference)); - writer.write(PdfArray.startMark); - writer.write('<<'); - writer.write(PdfOperators.slash + _transParam); - PdfDictionary trans = PdfDictionary(); - trans[PdfDictionaryProperties.v] = PdfName('1.2'); - trans[PdfDictionaryProperties.p] = PdfNumber( - PdfSignatureHelper.getHelper( - _sig!, - ).getCertificateFlagResult(_sig!.documentPermissions), - ); - trans[PdfDictionaryProperties.type] = PdfName(_transParam); - writer.write(trans); - writer.write(PdfName(PdfDictionaryProperties.transformMethod)); - writer.write(PdfName(_docMdp)); - writer.write(PdfName(PdfDictionaryProperties.type)); - writer.write(PdfName(PdfDictionaryProperties.sigRef)); - writer.write(PdfName('DigestValue')); - int position = writer.position!; - // _docDigestPosition = position; - writer.write( - PdfString.fromBytes(List.filled(16, 0, growable: true)), - ); - PdfArray digestLocation = PdfArray(); - digestLocation.add(PdfNumber(position)); - digestLocation.add(PdfNumber(34)); - writer.write(PdfName('DigestLocation')); - writer.write(digestLocation); - writer.write(PdfName('DigestMethod')); - writer.write(PdfName('MD5')); - writer.write(PdfName(PdfDictionaryProperties.data)); - final PdfReferenceHolder refh = PdfReferenceHolder(cat); - writer.write(PdfOperators.whiteSpace); - writer.write(refh); - writer.write('>>'); - writer.write('<<'); - writer.write(PdfName(_transParam)); - trans = PdfDictionary(); - trans[PdfDictionaryProperties.v] = PdfName('1.2'); - final PdfArray fields = PdfArray(); - fields.add(PdfString(PdfSignatureHelper.getHelper(_sig!).field!.name!)); - trans[PdfDictionaryProperties.fields] = fields; - trans[PdfDictionaryProperties.type] = PdfName(_transParam); - trans[PdfDictionaryProperties.action] = PdfName('Include'); - writer.write(trans); - writer.write(PdfName(PdfDictionaryProperties.transformMethod)); - writer.write(PdfName('FieldMDP')); - writer.write(PdfName(PdfDictionaryProperties.type)); - writer.write(PdfName(PdfDictionaryProperties.sigRef)); - writer.write(PdfName('DigestValue')); - position = writer.position!; - // _fieldsDigestPosition = position; - writer.write( - PdfString.fromBytes(List.filled(16, 0, growable: true)), - ); - digestLocation = PdfArray(); - digestLocation.add(PdfNumber(position)); - digestLocation.add(PdfNumber(34)); - writer.write(PdfName('DigestLocation')); - writer.write(digestLocation); - writer.write(PdfName('DigestMethod')); - writer.write(PdfName('MD5')); - writer.write(PdfName(PdfDictionaryProperties.data)); - writer.write(PdfOperators.whiteSpace); - writer.write(PdfReferenceHolder(cat)); - writer.write('>>'); - writer.write(PdfArray.endMark); - writer.write(PdfOperators.whiteSpace); - } - } - - void _documentSaved(Object sender, DocumentSavedArgs e) { - final bool enabled = - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt; - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = false; - final PdfWriter writer = e.writer! as PdfWriter; - final int number = e.writer!.length! - _secondRangeIndex!; - const String str = '0 '; - final String str2 = '$_firstRangeLength '; - final String str3 = '$_secondRangeIndex '; - final String str4 = number.toString(); - int startPosition = _saveRangeItem(writer, str, _startPositionByteRange!); - startPosition = _saveRangeItem(writer, str2, startPosition); - startPosition = _saveRangeItem(writer, str3, startPosition); - _saveRangeItem(e.writer! as PdfWriter, str4, startPosition); - _range = [0, int.parse(str2), int.parse(str3), int.parse(str4)]; - _stream = writer.buffer; - final String text = PdfString.bytesToHex(getPkcs7Content()!); - _stream!.replaceRange( - _firstRangeLength!, - _firstRangeLength! + 1, - utf8.encode('<'), - ); - final int newPos = _firstRangeLength! + 1 + text.length; - _stream!.replaceRange(_firstRangeLength! + 1, newPos, utf8.encode(text)); - final int num3 = (_secondRangeIndex! - newPos) ~/ 2; - final String emptyText = PdfString.bytesToHex( - List.generate(num3, (int i) => 0), - ); - _stream!.replaceRange( - newPos, - newPos + emptyText.length, - utf8.encode(emptyText), - ); - _stream!.replaceRange( - newPos + emptyText.length, - newPos + emptyText.length + 1, - utf8.encode('>'), - ); - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = enabled; - } - - Future _documentSavedAsync(Object sender, DocumentSavedArgs e) async { - final bool enabled = - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt; - PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = false; - final PdfWriter writer = e.writer! as PdfWriter; - final int number = e.writer!.length! - _secondRangeIndex!; - const String str = '0 '; - final String str2 = '$_firstRangeLength '; - final String str3 = '$_secondRangeIndex '; - final String str4 = number.toString(); - await _saveRangeItemAsync(writer, str, _startPositionByteRange!).then(( - int startPosition, - ) async { - await _saveRangeItemAsync(writer, str2, startPosition).then(( - int startPosition, - ) async { - await _saveRangeItemAsync(writer, str3, startPosition).then(( - int startPosition, - ) async { - await _saveRangeItemAsync( - e.writer! as PdfWriter, - str4, - startPosition, - ).then((int startPosition) async { - _range = [ - 0, - int.parse(str2), - int.parse(str3), - int.parse(str4), - ]; - _stream = writer.buffer; - if (_cert != null || - (_sig != null && - PdfSignatureHelper.getHelper(_sig!).externalSigner != - null)) { - await getPkcs7ContentAsync().then((List? value) async { - await PdfString.bytesToHexAsync(value!).then(( - String text, - ) async { - _stream!.replaceRange( - _firstRangeLength!, - _firstRangeLength! + 1, - utf8.encode('<'), - ); - final int newPos = _firstRangeLength! + 1 + text.length; - _stream!.replaceRange( - _firstRangeLength! + 1, - newPos, - utf8.encode(text), - ); - final int num3 = (_secondRangeIndex! - newPos) ~/ 2; - await PdfString.bytesToHexAsync( - List.generate(num3, (int i) => 0), - ).then((String emptyText) async { - _stream!.replaceRange( - newPos, - newPos + emptyText.length, - utf8.encode(emptyText), - ); - _stream!.replaceRange( - newPos + emptyText.length, - newPos + emptyText.length + 1, - utf8.encode('>'), - ); - PdfSecurityHelper.getHelper(_doc.security) - .encryptor - .encrypt = enabled; - }); - }); - }); - } else if (_sig != null && _sig!.timestampServer != null) { - await _getPKCS7TimeStampContent().then((List? value) async { - await PdfString.bytesToHexAsync(value!).then(( - String text, - ) async { - _stream!.replaceRange( - _firstRangeLength!, - _firstRangeLength! + 1, - utf8.encode('<'), - ); - final int newPos = _firstRangeLength! + 1 + text.length; - _stream!.replaceRange( - _firstRangeLength! + 1, - newPos, - utf8.encode(text), - ); - final int num3 = (_secondRangeIndex! - newPos) ~/ 2; - await PdfString.bytesToHexAsync( - List.generate(num3, (int i) => 0), - ).then((String emptyText) async { - _stream!.replaceRange( - newPos, - newPos + emptyText.length, - utf8.encode(emptyText), - ); - _stream!.replaceRange( - newPos + emptyText.length, - newPos + emptyText.length + 1, - utf8.encode('>'), - ); - PdfSecurityHelper.getHelper(_doc.security) - .encryptor - .encrypt = enabled; - }); - }); - }); - } - }); - }); - }); - }); - } - - /// internal method - List? getPkcs7Content() { - String? hashAlgorithm = ''; - _SignaturePrivateKey externalSignature; - List>? crlBytes; - List? ocspByte; - List? chain = []; - final IPdfExternalSigner? externalSigner = - PdfSignatureHelper.getHelper(_sig!).externalSigner; - if (externalSigner != null && - PdfSignatureHelper.getHelper(_sig!).externalChain != null) { - chain = PdfSignatureHelper.getHelper(_sig!).externalChain; - final String digest = getDigestAlgorithm(externalSigner.hashAlgorithm); - final _SignaturePrivateKey pks = _SignaturePrivateKey(digest); - hashAlgorithm = pks.getHashAlgorithm(); - externalSignature = pks; - } else { - String certificateAlias = ''; - final List keys = - PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getContentTable().keys.toList(); - bool isContinue = true; - // ignore: avoid_function_literals_in_foreach_calls - keys.forEach((String key) { - if (isContinue && - PdfCertificateHelper.getPkcsCertificate(_cert!).isKey(key) && - PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getKey(key)!.key!.isPrivate!) { - certificateAlias = key; - isContinue = false; - } - }); - final KeyEntry pk = - PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getKey(certificateAlias)!; - final List certificates = - PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getCertificateChain(certificateAlias)!; - // ignore: avoid_function_literals_in_foreach_calls - certificates.forEach((X509Certificates c) { - chain!.add(c.certificate); - }); - final RsaPrivateKeyParam? parameters = pk.key as RsaPrivateKeyParam?; - final String digest = - _sig != null - ? getDigestAlgorithm(_sig!.digestAlgorithm) - : MessageDigestAlgorithms.secureHash256; - final _SignaturePrivateKey pks = _SignaturePrivateKey(digest, parameters); - hashAlgorithm = pks.getHashAlgorithm(); - externalSignature = pks; - } - final _PdfCmsSigner pkcs7 = _PdfCmsSigner( - null, - chain, - hashAlgorithm!, - false, - ); - final IRandom source = getUnderlyingSource(); - final List sources = List.generate( - _range.length ~/ 2, - (int i) => null, - ); - for (int j = 0; j < _range.length; j += 2) { - sources[j ~/ 2] = _WindowRandom(source, _range[j], _range[j + 1]); - } - final PdfStreamReader data = _RandomStream(_RandomGroup(sources)); - final List hash = pkcs7._digestAlgorithm.digest(data, hashAlgorithm)!; - final List? sh = pkcs7 - .getSequenceDataSet( - hash, - ocspByte, - crlBytes, - _sig!.cryptographicStandard, - ) - .getEncoded(Asn1.der); - List? extSignature; - if (externalSigner != null) { - final SignerResult? signerResult = externalSigner.signSync(sh!); - if (signerResult != null && signerResult.signedData.isNotEmpty) { - extSignature = signerResult.signedData; - } - if (extSignature != null) { - pkcs7.setSignedData( - extSignature, - null, - externalSignature.getEncryptionAlgorithm(), - ); - } else { - return List.filled(_estimatedSize, 0, growable: true); - } - } else { - extSignature = externalSignature.sign(sh!); - } - pkcs7.setSignedData( - extSignature!, - null, - externalSignature.getEncryptionAlgorithm(), - ); - return pkcs7.sign( - hash, - _sig!.timestampServer, - null, - ocspByte, - crlBytes, - _sig!.cryptographicStandard, - hashAlgorithm, - ); - } - - /// internal method - Future?> getPkcs7ContentAsync() async { - List? pkcs7Content; - String? hashAlgorithm = ''; - _SignaturePrivateKey? externalSignature; - List>? crlBytes; - List? ocspByte; - List? chain = []; - final IPdfExternalSigner? externalSigner = - PdfSignatureHelper.getHelper(_sig!).externalSigner; - if (externalSigner != null && - PdfSignatureHelper.getHelper(_sig!).externalChain != null) { - chain = PdfSignatureHelper.getHelper(_sig!).externalChain; - final String digest = getDigestAlgorithm(externalSigner.hashAlgorithm); - final _SignaturePrivateKey pks = _SignaturePrivateKey(digest); - hashAlgorithm = pks.getHashAlgorithm(); - externalSignature = pks; - } else { - String certificateAlias = ''; - await PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getContentTableAsync().then((Map contentTable) async { - final List keys = contentTable.keys.toList(); - bool isContinue = true; - // ignore: avoid_function_literals_in_foreach_calls - keys.forEach((String key) { - if (isContinue && - PdfCertificateHelper.getPkcsCertificate(_cert!).isKey(key) && - PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getKey(key)!.key!.isPrivate!) { - certificateAlias = key; - isContinue = false; - } - }); - final KeyEntry pk = - PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getKey(certificateAlias)!; - await PdfCertificateHelper.getPkcsCertificate( - _cert!, - ).getCertificateChainAsync(certificateAlias).then(( - List? certificates, - ) { - // ignore: avoid_function_literals_in_foreach_calls - certificates!.forEach((X509Certificates c) { - chain!.add(c.certificate); - }); - final RsaPrivateKeyParam? parameters = pk.key as RsaPrivateKeyParam?; - final String digest = - _sig != null - ? getDigestAlgorithm(_sig!.digestAlgorithm) - : MessageDigestAlgorithms.secureHash256; - final _SignaturePrivateKey pks = _SignaturePrivateKey( - digest, - parameters, - ); - hashAlgorithm = pks.getHashAlgorithm(); - externalSignature = pks; - }); - }); - } - final _PdfCmsSigner pkcs7 = _PdfCmsSigner( - null, - chain, - hashAlgorithm!, - false, - ); - final IRandom source = getUnderlyingSource(); - final List sources = List.generate( - _range.length ~/ 2, - (int i) => null, - ); - for (int j = 0; j < _range.length; j += 2) { - sources[j ~/ 2] = _WindowRandom(source, _range[j], _range[j + 1]); - } - final PdfStreamReader data = _RandomStream(_RandomGroup(sources)); - await pkcs7._digestAlgorithm.digestAsync(data, hashAlgorithm).then(( - List? hash, - ) async { - await pkcs7 - .getSequenceDataSetAsync( - hash!, - ocspByte, - crlBytes, - _sig!.cryptographicStandard, - ) - .then((DerSet derSet) async { - await derSet.getEncodedAsync(Asn1.der).then((List? sh) async { - List? extSignature; - if (externalSigner != null) { - await externalSigner.sign(sh!).then(( - SignerResult? signerResult, - ) async { - signerResult ??= externalSigner.signSync(sh); - if (signerResult != null && - signerResult.signedData.isNotEmpty) { - extSignature = signerResult.signedData; - } - if (extSignature != null) { - await pkcs7.setSignedDataAsync( - extSignature!, - null, - externalSignature!.getEncryptionAlgorithm(), - ); - } else { - pkcs7Content = List.filled( - _estimatedSize, - 0, - growable: true, - ); - } - }); - } else { - await externalSignature! - .signAsync(sh!) - .then((List? value) => extSignature = value); - } - if (pkcs7Content == null) { - await pkcs7.setSignedDataAsync( - extSignature!, - null, - externalSignature!.getEncryptionAlgorithm(), - ); - pkcs7Content = await pkcs7.signAsync( - hash, - _sig!.timestampServer, - null, - ocspByte, - crlBytes, - _sig!.cryptographicStandard, - hashAlgorithm, - ); - } - }); - }); - }); - return pkcs7Content; - } - - Future?> _getPKCS7TimeStampContent() async { - final _SignaturePrivateKey externalSignature = _SignaturePrivateKey( - MessageDigestAlgorithms.secureHash256, - ); - final String? hashAlgorithm = externalSignature.getHashAlgorithm(); - final _PdfCmsSigner pkcs7 = _PdfCmsSigner( - null, - null, - hashAlgorithm!, - false, - ); - final IRandom source = getUnderlyingSource(); - final List sources = List.filled( - _range.length ~/ 2, - null, - ); - for (int j = 0; j < _range.length; j += 2) { - sources[j ~/ 2] = _WindowRandom(source, _range[j], _range[j + 1]); - } - final PdfStreamReader data = _RandomStream(_RandomGroup(sources)); - final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); - final List? hash = alg.digest(data, hashAlgorithm); - if (hash != null) { - pkcs7.setSignedData( - hash, - null, - externalSignature.getEncryptionAlgorithm(), - ); - return pkcs7.getEncodedTimestamp(hash, _sig!.timestampServer!); - } - return null; - } - - /// internal method - IRandom getUnderlyingSource() { - return _RandomArray(_stream!.sublist(0)); - } - - /// internal method - String getDigestAlgorithm(DigestAlgorithm? digest) { - String digestAlgorithm; - switch (digest) { - case DigestAlgorithm.sha1: - digestAlgorithm = MessageDigestAlgorithms.secureHash1; - break; - case DigestAlgorithm.sha384: - digestAlgorithm = MessageDigestAlgorithms.secureHash384; - break; - case DigestAlgorithm.sha512: - digestAlgorithm = MessageDigestAlgorithms.secureHash512; - break; - // ignore: no_default_cases - default: - digestAlgorithm = MessageDigestAlgorithms.secureHash256; - break; - } - return digestAlgorithm; - } - - int _saveRangeItem(PdfWriter writer, String str, int startPosition) { - final List date = utf8.encode(str); - writer.buffer!.replaceRange( - startPosition, - startPosition + date.length, - date, - ); - return startPosition + str.length; - } - - Future _saveRangeItemAsync( - PdfWriter writer, - String str, - int startPosition, - ) async { - final List date = utf8.encode(str); - writer.buffer!.replaceRange( - startPosition, - startPosition + date.length, - date, - ); - return startPosition + str.length; - } - - /// internal property - IPdfPrimitive? get element => dictionary; - set element(IPdfPrimitive? value) { - throw ArgumentError("Primitive element can't be set"); - } -} - -/// internal class -class MessageDigestAlgorithms { - /// internal constructor - MessageDigestAlgorithms() { - _names = {}; - _names['1.2.840.113549.2.5'] = 'MD5'; - _names['1.3.14.3.2.26'] = 'SHA1'; - _names['2.16.840.1.101.3.4.2.1'] = 'SHA256'; - _names['2.16.840.1.101.3.4.2.2'] = 'SHA384'; - _names['2.16.840.1.101.3.4.2.3'] = 'SHA512'; - _names['1.3.36.3.2.1'] = 'RIPEMD160'; - _names['1.2.840.113549.1.1.4'] = 'MD5'; - _names['1.2.840.113549.1.1.5'] = 'SHA1'; - _names['1.2.840.113549.1.1.11'] = 'SHA256'; - _names['1.2.840.113549.1.1.12'] = 'SHA384'; - _names['1.2.840.113549.1.1.13'] = 'SHA512'; - _names['1.2.840.113549.2.5'] = 'MD5'; - _names['1.2.840.10040.4.3'] = 'SHA1'; - _names['2.16.840.1.101.3.4.3.2'] = 'SHA256'; - _names['2.16.840.1.101.3.4.3.3'] = 'SHA384'; - _names['2.16.840.1.101.3.4.3.4'] = 'SHA512'; - _names['1.3.36.3.3.1.2'] = 'RIPEMD160'; - _digests = {}; - _digests['MD5'] = '1.2.840.113549.2.5'; - _digests['MD-5'] = '1.2.840.113549.2.5'; - _digests['SHA1'] = '1.3.14.3.2.26'; - _digests['SHA-1'] = '1.3.14.3.2.26'; - _digests['SHA256'] = '2.16.840.1.101.3.4.2.1'; - _digests['SHA-256'] = '2.16.840.1.101.3.4.2.1'; - _digests['SHA384'] = '2.16.840.1.101.3.4.2.2'; - _digests['SHA-384'] = '2.16.840.1.101.3.4.2.2'; - _digests['SHA512'] = '2.16.840.1.101.3.4.2.3'; - _digests['SHA-512'] = '2.16.840.1.101.3.4.2.3'; - _digests['RIPEMD160'] = '1.3.36.3.2.1'; - _digests['RIPEMD-160'] = '1.3.36.3.2.1'; - _algorithms = {}; - _algorithms['SHA1'] = 'SHA-1'; - _algorithms[DerObjectID('1.3.14.3.2.26').id] = 'SHA-1'; - _algorithms['SHA256'] = 'SHA-256'; - _algorithms[NistObjectIds.sha256.id] = 'SHA-256'; - _algorithms['SHA384'] = 'SHA-384'; - _algorithms[NistObjectIds.sha384.id] = 'SHA-384'; - _algorithms['SHA512'] = 'SHA-512'; - _algorithms[NistObjectIds.sha512.id] = 'SHA-512'; - _algorithms['MD5'] = 'MD5'; - _algorithms[PkcsObjectId.md5.id] = 'MD5'; - _algorithms['RIPEMD-160'] = 'RIPEMD160'; - _algorithms['RIPEMD160'] = 'RIPEMD160'; - _algorithms[NistObjectIds.ripeMD160.id] = 'RIPEMD160'; - } - - /// internal field - static const String secureHash1 = 'SHA-1'; - - /// internal field - static const String secureHash256 = 'SHA-256'; - - /// internal field - static const String secureHash384 = 'SHA-384'; - - /// internal field - static const String secureHash512 = 'SHA-512'; - late Map _names; - late Map _digests; - late Map _algorithms; - - /// internal method - String? getDigest(String? id) { - String? result; - if (_names.containsKey(id)) { - result = _names[id!]; - } else { - result = id; - } - return result; - } - - /// internal method - String? getAllowedDigests(String name) { - String? result; - final String lower = name.toLowerCase(); - _digests.forEach((String key, String value) { - if (lower == key.toLowerCase()) { - result = _digests[key]; - } - }); - return result; - } - - /// internal method - Future getAllowedDigestsAsync(String name) async { - String? result; - final String lower = name.toLowerCase(); - _digests.forEach((String key, String value) { - if (lower == key.toLowerCase()) { - result = _digests[key]; - } - }); - return result; - } - - /// internal method - dynamic getMessageDigest(String hashAlgorithm) { - String lower = hashAlgorithm.toLowerCase(); - String? digest = lower; - bool isContinue = true; - _algorithms.forEach((String? key, String value) { - if (isContinue && key!.toLowerCase() == lower) { - digest = _algorithms[key]; - isContinue = false; - } - }); - dynamic result; - lower = digest!.toLowerCase(); - if (lower == 'sha1' || lower == 'sha-1' || lower == 'sha_1') { - result = sha1; - } else if (lower == 'sha256' || lower == 'sha-256' || lower == 'sha_256') { - result = sha256; - } else if (lower == 'sha384' || lower == 'sha-384' || lower == 'sha_384') { - result = sha384; - } else if (lower == 'sha512' || lower == 'sha-512' || lower == 'sha_512') { - result = sha512; - } else if (lower == 'md5' || lower == 'md-5' || lower == 'md_5') { - result = md5; - } else { - throw ArgumentError.value( - hashAlgorithm, - 'hashAlgorithm', - 'Invalid message digest algorithm', - ); - } - return result; - } - - /// internal method - Future getMessageDigestAsync(String hashAlgorithm) async { - String lower = hashAlgorithm.toLowerCase(); - String? digest = lower; - bool isContinue = true; - _algorithms.forEach((String? key, String value) { - if (isContinue && key!.toLowerCase() == lower) { - digest = _algorithms[key]; - isContinue = false; - } - }); - dynamic result; - lower = digest!.toLowerCase(); - if (lower == 'sha1' || lower == 'sha-1' || lower == 'sha_1') { - result = sha1; - } else if (lower == 'sha256' || lower == 'sha-256' || lower == 'sha_256') { - result = sha256; - } else if (lower == 'sha384' || lower == 'sha-384' || lower == 'sha_384') { - result = sha384; - } else if (lower == 'sha512' || lower == 'sha-512' || lower == 'sha_512') { - result = sha512; - } else if (lower == 'md5' || lower == 'md-5' || lower == 'md_5') { - result = md5; - } else { - throw ArgumentError.value( - hashAlgorithm, - 'hashAlgorithm', - 'Invalid message digest algorithm', - ); - } - return result; - } - - /// internal method - List? digest(PdfStreamReader data, dynamic hashAlgorithm) { - dynamic algorithm; - if (hashAlgorithm is String) { - algorithm = getMessageDigest(hashAlgorithm); - } else { - algorithm = hashAlgorithm; - } - final dynamic output = AccumulatorSink(); - final dynamic input = algorithm.startChunkedConversion(output); - int? count; - final List bytes = List.generate(8192, (int i) => 0); - while ((count = data.read(bytes, 0, bytes.length))! > 0) { - input.add(bytes.sublist(0, count)); - } - input.close(); - return output.events.single.bytes as List?; - } - - /// internal method - Future?> digestAsync( - PdfStreamReader data, - dynamic hashAlgorithm, - ) async { - dynamic algorithm; - algorithm = - hashAlgorithm is String - ? await getMessageDigestAsync(hashAlgorithm) - : hashAlgorithm; - final dynamic output = AccumulatorSink(); - final dynamic input = algorithm.startChunkedConversion(output); - int? count; - final List bytes = List.generate(8192, (int i) => 0); - while ((count = data.read(bytes, 0, bytes.length))! > 0) { - input.add(bytes.sublist(0, count)); - } - input.close(); - return output.events.single.bytes as List?; - } -} - -class _SignaturePrivateKey { - _SignaturePrivateKey(String hashAlgorithm, [ICipherParameter? key]) { - _key = key; - final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); - _hashAlgorithm = alg.getDigest(alg.getAllowedDigests(hashAlgorithm)); - if (key == null || key is RsaKeyParam) { - _encryptionAlgorithm = 'RSA'; - } else { - throw ArgumentError.value(key, 'key', 'Invalid key'); - } - } - //Fields - ICipherParameter? _key; - String? _hashAlgorithm; - String? _encryptionAlgorithm; - //Implementation - List? sign(List bytes) { - final String signMode = '${_hashAlgorithm!}with${_encryptionAlgorithm!}'; - final SignerUtilities util = SignerUtilities(); - final ISigner signer = util.getSigner(signMode); - signer.initialize(true, _key); - signer.blockUpdate(bytes, 0, bytes.length); - return signer.generateSignature(); - } - - Future?> signAsync(List bytes) async { - final String signMode = '${_hashAlgorithm!}with${_encryptionAlgorithm!}'; - final SignerUtilities util = SignerUtilities(); - final ISigner signer = util.getSigner(signMode); - signer.initialize(true, _key); - signer.blockUpdate(bytes, 0, bytes.length); - return signer.generateSignature(); - } - - String? getHashAlgorithm() { - return _hashAlgorithm; - } - - String? getEncryptionAlgorithm() { - return _encryptionAlgorithm; - } -} - -/// Internal class -class SignerUtilities { - /// Internal consturctor - SignerUtilities() { - _algms['MD2WITHRSA'] = 'MD2withRSA'; - _algms['MD2WITHRSAENCRYPTION'] = 'MD2withRSA'; - _algms[PkcsObjectId.md2WithRsaEncryption.id] = 'MD2withRSA'; - _algms[PkcsObjectId.rsaEncryption.id] = 'RSA'; - _algms['SHA1WITHRSA'] = 'SHA-1withRSA'; - _algms['SHA1WITHRSAENCRYPTION'] = 'SHA-1withRSA'; - _algms[PkcsObjectId.sha1WithRsaEncryption.id] = 'SHA-1withRSA'; - _algms['SHA-1WITHRSA'] = 'SHA-1withRSA'; - _algms['SHA256WITHRSA'] = 'SHA-256withRSA'; - _algms['SHA256WITHRSAENCRYPTION'] = 'SHA-256withRSA'; - _algms[PkcsObjectId.sha256WithRsaEncryption.id] = 'SHA-256withRSA'; - _algms['SHA-256WITHRSA'] = 'SHA-256withRSA'; - _algms['SHA1WITHRSAANDMGF1'] = 'SHA-1withRSAandMGF1'; - _algms['SHA-1WITHRSAANDMGF1'] = 'SHA-1withRSAandMGF1'; - _algms['SHA1WITHRSA/PSS'] = 'SHA-1withRSAandMGF1'; - _algms['SHA-1WITHRSA/PSS'] = 'SHA-1withRSAandMGF1'; - _algms['SHA224WITHRSAANDMGF1'] = 'SHA-224withRSAandMGF1'; - _algms['SHA-224WITHRSAANDMGF1'] = 'SHA-224withRSAandMGF1'; - _algms['SHA224WITHRSA/PSS'] = 'SHA-224withRSAandMGF1'; - _algms['SHA-224WITHRSA/PSS'] = 'SHA-224withRSAandMGF1'; - _algms['SHA256WITHRSAANDMGF1'] = 'SHA-256withRSAandMGF1'; - _algms['SHA-256WITHRSAANDMGF1'] = 'SHA-256withRSAandMGF1'; - _algms['SHA256WITHRSA/PSS'] = 'SHA-256withRSAandMGF1'; - _algms['SHA-256WITHRSA/PSS'] = 'SHA-256withRSAandMGF1'; - _algms['SHA384WITHRSA'] = 'SHA-384withRSA'; - _algms['SHA512WITHRSA'] = 'SHA-512withRSA'; - _algms['SHA384WITHRSAENCRYPTION'] = 'SHA-384withRSA'; - _algms[PkcsObjectId.sha384WithRsaEncryption.id] = 'SHA-384withRSA'; - _algms['SHA-384WITHRSA'] = 'SHA-384withRSA'; - _algms['SHA-512WITHRSA'] = 'SHA-512withRSA'; - _algms['SHA384WITHRSAANDMGF1'] = 'SHA-384withRSAandMGF1'; - _algms['SHA-384WITHRSAANDMGF1'] = 'SHA-384withRSAandMGF1'; - _algms['SHA384WITHRSA/PSS'] = 'SHA-384withRSAandMGF1'; - _algms['SHA-384WITHRSA/PSS'] = 'SHA-384withRSAandMGF1'; - _algms['SHA512WITHRSAANDMGF1'] = 'SHA-512withRSAandMGF1'; - _algms['SHA-512WITHRSAANDMGF1'] = 'SHA-512withRSAandMGF1'; - _algms['SHA512WITHRSA/PSS'] = 'SHA-512withRSAandMGF1'; - _algms['SHA-512WITHRSA/PSS'] = 'SHA-512withRSAandMGF1'; - _algms['DSAWITHSHA256'] = 'SHA-256withDSA'; - _algms['DSAWITHSHA-256'] = 'SHA-256withDSA'; - _algms['SHA256/DSA'] = 'SHA-256withDSA'; - _algms['SHA-256/DSA'] = 'SHA-256withDSA'; - _algms['SHA256WITHDSA'] = 'SHA-256withDSA'; - _algms['SHA-256WITHDSA'] = 'SHA-256withDSA'; - _algms[NistObjectIds.dsaWithSHA256.id] = 'SHA-256withDSA'; - _algms['RIPEMD160WITHRSA'] = 'RIPEMD160withRSA'; - _algms['RIPEMD160WITHRSAENCRYPTION'] = 'RIPEMD160withRSA'; - _algms[NistObjectIds.rsaSignatureWithRipeMD160.id] = 'RIPEMD160withRSA'; - _oids['SHA-1withRSA'] = PkcsObjectId.sha1WithRsaEncryption; - _oids['SHA-256withRSA'] = PkcsObjectId.sha256WithRsaEncryption; - _oids['SHA-384withRSA'] = PkcsObjectId.sha384WithRsaEncryption; - _oids['SHA-512withRSA'] = PkcsObjectId.sha512WithRsaEncryption; - _oids['RIPEMD160withRSA'] = NistObjectIds.rsaSignatureWithRipeMD160; - } - //Fields - final Map _algms = {}; - final Map _oids = {}; - //Implementation - /// Internal method - ISigner getSigner(String algorithm) { - ISigner result; - final String lower = algorithm.toLowerCase(); - String? mechanism = algorithm; - bool isContinue = true; - _algms.forEach((String? key, String value) { - if (isContinue && key!.toLowerCase() == lower) { - mechanism = _algms[key]; - isContinue = false; - } - }); - if (mechanism == 'SHA-1withRSA') { - result = _RmdSigner(DigestAlgorithms.sha1); - } else if (mechanism == 'SHA-256withRSA') { - return _RmdSigner(DigestAlgorithms.sha256); - } else if (mechanism == 'SHA-384withRSA') { - return _RmdSigner(DigestAlgorithms.sha384); - } else if (mechanism == 'SHA-512withRSA') { - return _RmdSigner(DigestAlgorithms.sha512); - } else { - throw ArgumentError.value('Signer $algorithm not recognised.'); - } - return result; - } - - /// Internal method - Future getSignerAsync(String algorithm) async { - ISigner result; - final String lower = algorithm.toLowerCase(); - String? mechanism = algorithm; - bool isContinue = true; - _algms.forEach((String? key, String value) { - if (isContinue && key!.toLowerCase() == lower) { - mechanism = _algms[key]; - isContinue = false; - } - }); - if (mechanism == 'SHA-1withRSA') { - result = _RmdSigner(DigestAlgorithms.sha1); - } else if (mechanism == 'SHA-256withRSA') { - return _RmdSigner(DigestAlgorithms.sha256); - } else if (mechanism == 'SHA-384withRSA') { - return _RmdSigner(DigestAlgorithms.sha384); - } else if (mechanism == 'SHA-512withRSA') { - return _RmdSigner(DigestAlgorithms.sha512); - } else { - throw ArgumentError.value('Signer $algorithm not recognised.'); - } - return result; - } -} - -class _PdfCmsSigner { - _PdfCmsSigner( - ICipherParameter? privateKey, - List? certChain, - String hashAlgorithm, - bool hasRSAdata, - ) { - _digestAlgorithm = MessageDigestAlgorithms(); - _digestAlgorithmOid = _digestAlgorithm.getAllowedDigests(hashAlgorithm); - if (_digestAlgorithmOid == null) { - throw ArgumentError.value( - hashAlgorithm, - 'hashAlgorithm', - 'Unknown Hash Algorithm', - ); - } - _version = 1; - _signerVersion = 1; - _digestOid = {}; - _digestOid[_digestAlgorithmOid] = null; - if (certChain != null) { - _certificates = List.generate( - certChain.length, - (int i) => certChain[i], - ); - _signCert = _certificates[0]; - } - if (privateKey != null) { - if (privateKey is RsaKeyParam) { - _encryptionAlgorithmOid = _DigitalIdentifiers.rsa; - } else { - throw ArgumentError.value( - privateKey, - 'privateKey', - 'Unknown key algorithm', - ); - } - } - if (hasRSAdata) { - _rsaData = []; - } - } - - //Fields - late MessageDigestAlgorithms _digestAlgorithm; - late int _version; - late int _signerVersion; - late List _certificates; - late Map _digestOid; - String? _digestAlgorithmOid; - X509Certificate? _signCert; - late String _encryptionAlgorithmOid; - String? _hashAlgorithm; - List? _rsaData; - List? _signedData; - List? _signedRsaData; - List? _digest; - - //Properties - String? get hashAlgorithm { - _hashAlgorithm ??= _digestAlgorithm.getDigest(_digestAlgorithmOid); - return _hashAlgorithm; - } - - //Implementation - DerSet getSequenceDataSet( - List secondDigest, - List? ocsp, - List>? crlBytes, - CryptographicStandard? sigtype, - ) { - final Asn1EncodeCollection attribute = Asn1EncodeCollection(); - Asn1EncodeCollection v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.contentType)); - v.encodableObjects.add( - DerSet(array: [DerObjectID(_DigitalIdentifiers.pkcs7Data)]), - ); - attribute.encodableObjects.add(DerSequence(collection: v)); - v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.messageDigest)); - v.encodableObjects.add(DerSet(array: [DerOctet(secondDigest)])); - attribute.encodableObjects.add(DerSequence(collection: v)); - if (sigtype == CryptographicStandard.cades) { - v = Asn1EncodeCollection(); - v.encodableObjects.add( - DerObjectID(_DigitalIdentifiers.aaSigningCertificateV2), - ); - final Asn1EncodeCollection aaV2 = Asn1EncodeCollection(); - final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); - final String? sha256Oid = alg.getAllowedDigests( - MessageDigestAlgorithms.secureHash256, - ); - if (sha256Oid != _digestAlgorithmOid) { - aaV2.encodableObjects.add(Algorithms(DerObjectID(_digestAlgorithmOid))); - } - final List dig = - alg - .getMessageDigest(hashAlgorithm!) - .convert(_signCert!.c!.getEncoded(Asn1.der)) - .bytes - as List; - aaV2.encodableObjects.add(DerOctet(dig)); - v.encodableObjects.add( - DerSet( - array: [ - DerSequence.fromObject( - DerSequence.fromObject(DerSequence(collection: aaV2)), - ), - ], - ), - ); - attribute.encodableObjects.add(DerSequence(collection: v)); - } - return DerSet(collection: attribute); - } - - //Implementation - Future getSequenceDataSetAsync( - List secondDigest, - List? ocsp, - List>? crlBytes, - CryptographicStandard? sigtype, - ) async { - final Asn1EncodeCollection attribute = Asn1EncodeCollection(); - Asn1EncodeCollection v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.contentType)); - v.encodableObjects.add( - DerSet(array: [DerObjectID(_DigitalIdentifiers.pkcs7Data)]), - ); - attribute.encodableObjects.add(DerSequence(collection: v)); - v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.messageDigest)); - v.encodableObjects.add(DerSet(array: [DerOctet(secondDigest)])); - attribute.encodableObjects.add(DerSequence(collection: v)); - if (sigtype == CryptographicStandard.cades) { - v = Asn1EncodeCollection(); - v.encodableObjects.add( - DerObjectID(_DigitalIdentifiers.aaSigningCertificateV2), - ); - final Asn1EncodeCollection aaV2 = Asn1EncodeCollection(); - final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); - await alg - .getAllowedDigestsAsync(MessageDigestAlgorithms.secureHash256) - .then((String? sha256Oid) async { - if (sha256Oid != _digestAlgorithmOid) { - aaV2.encodableObjects.add( - Algorithms(DerObjectID(_digestAlgorithmOid)), - ); - } - await alg.getMessageDigestAsync(hashAlgorithm!).then(( - dynamic value, - ) { - aaV2.encodableObjects.add( - DerOctet( - value.convert(_signCert!.c!.getEncoded(Asn1.der)).bytes - as List, - ), - ); - v.encodableObjects.add( - DerSet( - array: [ - DerSequence.fromObject( - DerSequence.fromObject(DerSequence(collection: aaV2)), - ), - ], - ), - ); - attribute.encodableObjects.add(DerSequence(collection: v)); - }); - }); - } - return DerSet(collection: attribute); - } - - void setSignedData( - List digest, - List? rsaData, - String? digestEncryptionAlgorithm, - ) { - _signedData = digest; - _signedRsaData = rsaData; - if (digestEncryptionAlgorithm != null) { - if (digestEncryptionAlgorithm == 'RSA') { - _encryptionAlgorithmOid = _DigitalIdentifiers.rsa; - } else if (digestEncryptionAlgorithm == 'DSA') { - _encryptionAlgorithmOid = _DigitalIdentifiers.dsa; - } else if (digestEncryptionAlgorithm == 'ECDSA') { - _encryptionAlgorithmOid = _DigitalIdentifiers.ecdsa; - } else { - throw ArgumentError.value( - digestEncryptionAlgorithm, - 'algorithm', - 'Invalid entry', - ); - } - } - } - - Future setSignedDataAsync( - List digest, - List? rsaData, - String? digestEncryptionAlgorithm, - ) async { - _signedData = digest; - _signedRsaData = rsaData; - if (digestEncryptionAlgorithm != null) { - if (digestEncryptionAlgorithm == 'RSA') { - _encryptionAlgorithmOid = _DigitalIdentifiers.rsa; - } else if (digestEncryptionAlgorithm == 'DSA') { - _encryptionAlgorithmOid = _DigitalIdentifiers.dsa; - } else if (digestEncryptionAlgorithm == 'ECDSA') { - _encryptionAlgorithmOid = _DigitalIdentifiers.ecdsa; - } else { - throw ArgumentError.value( - digestEncryptionAlgorithm, - 'algorithm', - 'Invalid entry', - ); - } - } - } - - List? sign( - List secondDigest, - TimestampServer? server, - List? timeStampResponse, - List? ocsp, - List>? crls, - CryptographicStandard? sigtype, - String? hashAlgorithm, - ) { - if (_signedData != null) { - _digest = _signedData; - if (_rsaData != null) { - _rsaData = _signedRsaData; - } - } - final Asn1EncodeCollection digestAlgorithms = Asn1EncodeCollection(); - final List keys = _digestOid.keys.toList(); - // ignore: avoid_function_literals_in_foreach_calls - keys.forEach((String? dal) { - final Asn1EncodeCollection algos = Asn1EncodeCollection(); - algos.encodableObjects.add(DerObjectID(dal)); - algos.encodableObjects.add(DerNull.value); - digestAlgorithms.encodableObjects.add(DerSequence(collection: algos)); - }); - Asn1EncodeCollection v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.pkcs7Data)); - if (_rsaData != null) { - v.encodableObjects.add(DerTag(0, DerOctet(_rsaData!))); - } - final DerSequence contentinfo = DerSequence(collection: v); - - v = Asn1EncodeCollection(); - // ignore: avoid_function_literals_in_foreach_calls - _certificates.forEach((X509Certificate? xcert) { - v.encodableObjects.add( - Asn1Stream(PdfStreamReader(xcert!.c!.getEncoded(Asn1.der))).readAsn1(), - ); - }); - final DerSet dercertificates = DerSet(collection: v); - final Asn1EncodeCollection signerinfo = Asn1EncodeCollection(); - signerinfo.encodableObjects.add( - DerInteger(bigIntToBytes(BigInt.from(_signerVersion))), - ); - v = Asn1EncodeCollection(); - v.encodableObjects.add( - getIssuer(_signCert!.c!.tbsCertificate!.getEncoded(Asn1.der)), - ); - v.encodableObjects.add( - DerInteger(bigIntToBytes(_signCert!.c!.serialNumber!.value)), - ); - signerinfo.encodableObjects.add(DerSequence(collection: v)); - v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_digestAlgorithmOid)); - v.encodableObjects.add(DerNull.value); - signerinfo.encodableObjects.add(DerSequence(collection: v)); - signerinfo.encodableObjects.add( - DerTag(0, getSequenceDataSet(secondDigest, ocsp, crls, sigtype), false), - ); - v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_encryptionAlgorithmOid)); - v.encodableObjects.add(DerNull.value); - signerinfo.encodableObjects.add(DerSequence(collection: v)); - signerinfo.encodableObjects.add(DerOctet(_digest!)); - final Asn1EncodeCollection body = Asn1EncodeCollection(); - body.encodableObjects.add(DerInteger(bigIntToBytes(BigInt.from(_version)))); - body.encodableObjects.add(DerSet(collection: digestAlgorithms)); - body.encodableObjects.add(contentinfo); - body.encodableObjects.add(DerTag(0, dercertificates, false)); - body.encodableObjects.add( - DerSet(array: [DerSequence(collection: signerinfo)]), - ); - final Asn1EncodeCollection whole = Asn1EncodeCollection(); - whole.encodableObjects.add( - DerObjectID(_DigitalIdentifiers.pkcs7SignedData), - ); - whole.encodableObjects.add(DerTag(0, DerSequence(collection: body))); - final Asn1DerStream dout = Asn1DerStream([]); - dout.writeObject(DerSequence(collection: whole)); - return dout.stream; - } - - Asn1EncodeCollection? getAttributes(List timeStampToken) { - final Asn1Stream tempstream = Asn1Stream(PdfStreamReader(timeStampToken)); - final Asn1EncodeCollection attributes = Asn1EncodeCollection(); - final Asn1EncodeCollection asn1Encode = Asn1EncodeCollection(); - asn1Encode.add([DerObjectID('1.2.840.113549.1.9.16.2.14')]); - final Asn1? seq = tempstream.readAsn1(); - if (seq != null && seq is Asn1Sequence) { - asn1Encode.add([ - DerSet(array: [seq]), - ]); - attributes.add([DerSequence(collection: asn1Encode)]); - } - return attributes; - } - - Future?> signAsync( - List secondDigest, - TimestampServer? server, - List? timeStampResponse, - List? ocsp, - List>? crls, - CryptographicStandard? sigtype, - String? hashAlgorithm, - ) async { - if (_signedData != null) { - _digest = _signedData; - if (_rsaData != null) { - _rsaData = _signedRsaData; - } - } - final Asn1EncodeCollection digestAlgorithms = Asn1EncodeCollection(); - final List keys = _digestOid.keys.toList(); - // ignore: avoid_function_literals_in_foreach_calls - keys.forEach((String? dal) { - final Asn1EncodeCollection algos = Asn1EncodeCollection(); - algos.encodableObjects.add(DerObjectID(dal)); - algos.encodableObjects.add(DerNull.value); - digestAlgorithms.encodableObjects.add(DerSequence(collection: algos)); - }); - Asn1EncodeCollection v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.pkcs7Data)); - if (_rsaData != null) { - v.encodableObjects.add(DerTag(0, DerOctet(_rsaData!))); - } - final DerSequence contentinfo = DerSequence(collection: v); - - v = Asn1EncodeCollection(); - // ignore: avoid_function_literals_in_foreach_calls - _certificates.forEach((X509Certificate? xcert) { - v.encodableObjects.add( - Asn1Stream(PdfStreamReader(xcert!.c!.getEncoded(Asn1.der))).readAsn1(), - ); - }); - final DerSet dercertificates = DerSet(collection: v); - final Asn1EncodeCollection signerinfo = Asn1EncodeCollection(); - signerinfo.encodableObjects.add( - DerInteger(bigIntToBytes(BigInt.from(_signerVersion))), - ); - v = Asn1EncodeCollection(); - v.encodableObjects.add( - getIssuer(_signCert!.c!.tbsCertificate!.getEncoded(Asn1.der)), - ); - v.encodableObjects.add( - DerInteger(bigIntToBytes(_signCert!.c!.serialNumber!.value)), - ); - signerinfo.encodableObjects.add(DerSequence(collection: v)); - v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_digestAlgorithmOid)); - v.encodableObjects.add(DerNull.value); - signerinfo.encodableObjects.add(DerSequence(collection: v)); - signerinfo.encodableObjects.add( - DerTag(0, getSequenceDataSet(secondDigest, ocsp, crls, sigtype), false), - ); - v = Asn1EncodeCollection(); - v.encodableObjects.add(DerObjectID(_encryptionAlgorithmOid)); - v.encodableObjects.add(DerNull.value); - signerinfo.encodableObjects.add(DerSequence(collection: v)); - signerinfo.encodableObjects.add(DerOctet(_digest!)); - if (timeStampResponse == null && server != null) { - final dynamic output = AccumulatorSink(); - final dynamic input = sha256.startChunkedConversion(output); - input.add(_digest); - input.close(); - final List hash = output.events.single.bytes as List; - final List asnEncodedTimestampRequest = TimeStampRequestCreator() - .getAsnEncodedTimestampRequest(hash); - timeStampResponse = await fetchData( - server.uri, - 'POST', - contentType: 'application/timestamp-query', - userName: server.userName, - password: server.password, - data: asnEncodedTimestampRequest, - timeOutDuration: server.timeOut, - ); - if (timeStampResponse != null) { - final Asn1Stream stream = Asn1Stream( - PdfStreamReader(timeStampResponse), - ); - final Asn1? asn1 = stream.readAsn1(); - if (asn1 != null && - asn1 is Asn1Sequence && - asn1.count > 1 && - asn1[1] != null && - asn1[1] is Asn1) { - final Asn1 asn1Sequence = asn1[1]! as Asn1; - final DerStream dOut = DerStream([]); - asn1Sequence.encode(dOut); - timeStampResponse = dOut.stream!.toList(); - dOut.stream!.clear(); - } - } - } - if (timeStampResponse != null) { - final Asn1EncodeCollection? timeAsn1Encoded = getAttributes( - timeStampResponse, - ); - if (timeAsn1Encoded != null) { - signerinfo.add([ - DerTag(1, DerSet(collection: timeAsn1Encoded), false), - ]); - } - } - final Asn1EncodeCollection body = Asn1EncodeCollection(); - body.encodableObjects.add(DerInteger(bigIntToBytes(BigInt.from(_version)))); - body.encodableObjects.add(DerSet(collection: digestAlgorithms)); - body.encodableObjects.add(contentinfo); - body.encodableObjects.add(DerTag(0, dercertificates, false)); - body.encodableObjects.add( - DerSet(array: [DerSequence(collection: signerinfo)]), - ); - final Asn1EncodeCollection whole = Asn1EncodeCollection(); - whole.encodableObjects.add( - DerObjectID(_DigitalIdentifiers.pkcs7SignedData), - ); - whole.encodableObjects.add(DerTag(0, DerSequence(collection: body))); - final Asn1DerStream dout = Asn1DerStream([]); - dout.writeObject(DerSequence(collection: whole)); - return dout.stream; - } - - Asn1? getIssuer(List? data) { - final Asn1Sequence seq = - Asn1Stream(PdfStreamReader(data)).readAsn1()! as Asn1Sequence; - return seq[seq[0] is Asn1Tag ? 3 : 2] as Asn1?; - } - - /// Internal method - Future?> getEncodedTimestamp( - List secondDigest, - TimestampServer server, - ) async { - List? encoded; - final List asnEncodedTimestampRequest = TimeStampRequestCreator() - .getAsnEncodedTimestampRequest(secondDigest); - final List? respBytes = await fetchData( - server.uri, - 'POST', - contentType: 'application/timestamp-query', - userName: server.userName, - password: server.password, - data: asnEncodedTimestampRequest, - timeOutDuration: server.timeOut, - ); - if (respBytes != null) { - final Asn1Stream stream = Asn1Stream(PdfStreamReader(respBytes)); - final Asn1? asn1 = stream.readAsn1(); - if (asn1 != null && - asn1 is Asn1Sequence && - asn1.count > 1 && - asn1[1] != null && - asn1[1] is Asn1) { - final Asn1 asn1Sequence = asn1[1]! as Asn1; - final DerStream dOut = DerStream([]); - asn1Sequence.encode(dOut); - encoded = dOut.stream!.toList(); - dOut.stream!.clear(); - } - } - return encoded; - } -} - -class _DigitalIdentifiers { - static const String pkcs7Data = '1.2.840.113549.1.7.1'; - static const String pkcs7SignedData = '1.2.840.113549.1.7.2'; - static const String rsa = '1.2.840.113549.1.1.1'; - static const String dsa = '1.2.840.10040.4.1'; - static const String ecdsa = '1.2.840.10045.2.1'; - static const String contentType = '1.2.840.113549.1.9.3'; - static const String messageDigest = '1.2.840.113549.1.9.4'; - static const String aaSigningCertificateV2 = '1.2.840.113549.1.9.16.2.47'; -} - -class _RandomArray implements IRandom { - _RandomArray(List array) { - _array = array; - } - //Fields - late List _array; - //Properties - @override - int get length => _array.length; - //Implementation - @override - int? getValue(int offset, [List? bytes, int? off, int? length]) { - if (bytes == null) { - if (offset >= _array.length) { - return -1; - } - return 0xff & _array[offset]; - } else { - if (offset >= _array.length) { - return -1; - } - if (offset + length! > _array.length) { - length = (_array.length - offset).toSigned(32); - } - List.copyRange(bytes, off!, _array, offset, offset + length); - return length; - } - } -} - -class _WindowRandom implements IRandom { - _WindowRandom(IRandom source, int offset, int length) { - _source = source; - _offset = offset; - _length = length; - } - //Fields - late IRandom _source; - late int _offset; - int? _length; - //Properties - @override - int? get length => _length; - //Implementation - @override - int? getValue(int position, [List? bytes, int? off, int? len]) { - if (position >= _length!) { - return -1; - } - if (bytes == null) { - return _source.getValue(_offset + position); - } else { - final int toRead = min(len!, _length! - position); - return _source.getValue(_offset + position, bytes, off, toRead); - } - } -} - -class _RandomGroup implements IRandom { - _RandomGroup(List sources) { - _sources = <_SourceEntry>[]; - int totalSize = 0; - int i = 0; - sources.toList().forEach((IRandom? ras) { - _sources.add(_SourceEntry(i, ras!, totalSize)); - ++i; - totalSize += ras.length!; - }); - _size = totalSize; - _cse = _sources[sources.length - 1]; - } - //Fields - late List<_SourceEntry> _sources; - _SourceEntry? _cse; - int? _size; - //Properties - @override - int? get length => _size; - //Implementation - @override - int getValue(int position, [List? bytes, int? off, int? len]) { - _SourceEntry? entry = getEntry(position); - if (entry == null) { - return -1; - } - int offN = entry.offsetN(position); - int? remaining = len; - bool isContinue = true; - while (isContinue && remaining! > 0) { - if (entry == null || offN > entry._source.length!) { - isContinue = false; - } else { - final int? count = entry._source.getValue(offN, bytes, off, remaining); - if (count == -1) { - isContinue = false; - } else { - off = off! + count!; - position += count; - remaining -= count; - offN = 0; - entry = getEntry(position); - } - } - } - return remaining == len ? -1 : len! - remaining!; - } - - int? getStartIndex(int offset) { - if (offset >= _cse!._startByte) { - return _cse!._index; - } - return 0; - } - - _SourceEntry? getEntry(int offset) { - if (offset >= _size!) { - return null; - } - if (offset >= _cse!._startByte && offset <= _cse!._endByte) { - return _cse; - } - final int startAt = getStartIndex(offset)!; - for (int i = startAt; i < _sources.length; i++) { - if (offset >= _sources[i]._startByte && offset <= _sources[i]._endByte) { - _cse = _sources[i]; - return _cse; - } - } - return null; - } -} - -class _SourceEntry { - _SourceEntry(int index, IRandom source, int offset) { - _index = index; - _source = source; - _startByte = offset; - _endByte = offset + source.length! - 1; - } - //Fields - late IRandom _source; - late int _startByte; - late int _endByte; - int? _index; - //Implementation - int offsetN(int absoluteOffset) { - return absoluteOffset - _startByte; - } -} - -class _RandomStream extends PdfStreamReader { - _RandomStream(IRandom source) - : super(List.generate(source.length!, (int i) => 0)) { - _random = source; - } - //Fields - late IRandom _random; - @override - int position = 0; - //Properties - @override - int? get length => _random.length; - - //Implementation - @override - int? read(List buffer, int offset, int length) { - final int? count = _random.getValue(position, buffer, offset, length); - if (count == -1) { - return 0; - } - position += count!; - return count; - } - - @override - int readByte() { - final int c = _random.getValue(position)!; - if (c >= 0) { - ++position; - } - return c; - } -} - -class _RmdSigner implements ISigner { - _RmdSigner(String digest) { - _digest = getDigest(digest); - _output = AccumulatorSink(); - _input = _digest.startChunkedConversion(_output); - _rsaEngine = Pkcs1Encoding(RsaAlgorithm()); - _id = Algorithms(map![digest], DerNull.value); - } - Map? _map; - late ICipherBlock _rsaEngine; - Algorithms? _id; - late dynamic _digest; - late dynamic _output; - dynamic _input; - late bool _isSigning; - //Properties - Map? get map { - if (_map == null) { - _map = {}; - _map![DigestAlgorithms.sha1] = X509Objects.idSha1; - _map![DigestAlgorithms.sha256] = NistObjectIds.sha256; - _map![DigestAlgorithms.sha384] = NistObjectIds.sha384; - _map![DigestAlgorithms.sha512] = NistObjectIds.sha512; - } - return _map; - } - - dynamic getDigest(String digest) { - dynamic result; - if (digest == DigestAlgorithms.sha1) { - result = sha1; - } else if (digest == DigestAlgorithms.sha256) { - result = sha256; - } else if (digest == DigestAlgorithms.sha384) { - result = sha384; - } else if (digest == DigestAlgorithms.sha512) { - result = sha512; - } else { - throw ArgumentError.value(digest, 'digest', 'Invalid digest'); - } - return result; - } - - @override - void initialize(bool isSigning, ICipherParameter? parameters) { - _isSigning = isSigning; - final CipherParameter? k = parameters as CipherParameter?; - if (isSigning && !k!.isPrivate!) { - throw ArgumentError.value('Private key required.'); - } - if (!isSigning && k!.isPrivate!) { - throw ArgumentError.value('Public key required.'); - } - reset(); - _rsaEngine.initialize(isSigning, parameters); - } - - @override - void blockUpdate(List input, int inOff, int length) { - _input.add(input.sublist(inOff, inOff + length)); - } - - @override - List? generateSignature() { - if (!_isSigning) { - throw ArgumentError.value('Invalid entry'); - } - _input.close(); - final List? hash = _output.events.single.bytes as List?; - final List data = derEncode(hash)!; - return _rsaEngine.processBlock(data, 0, data.length); - } - - @override - bool validateSignature(List signature) { - if (_isSigning) { - throw Exception('Invalid entry'); - } - _input.close(); - final List? hash = _output.events.single.bytes as List?; - List sig; - List expected; - try { - sig = _rsaEngine.processBlock(signature, 0, signature.length)!; - expected = derEncode(hash)!; - } catch (e) { - return false; - } - if (sig.length == expected.length) { - for (int i = 0; i < sig.length; i++) { - if (sig[i] != expected[i]) { - return false; - } - } - } else if (sig.length == expected.length - 2) { - final int sigOffset = sig.length - hash!.length - 2; - final int expectedOffset = expected.length - hash.length - 2; - expected[1] -= 2; - expected[3] -= 2; - for (int i = 0; i < hash.length; i++) { - if (sig[sigOffset + i] != expected[expectedOffset + i]) { - return false; - } - } - for (int i = 0; i < sigOffset; i++) { - if (sig[i] != expected[i]) { - return false; - } - } - } else { - return false; - } - return true; - } - - List? derEncode(List? hash) { - if (_id == null) { - return hash; - } - return DigestInformation(_id, hash).getDerEncoded(); - } - - @override - void reset() { - _output = AccumulatorSink(); - _input = _digest.startChunkedConversion(_output); - } -} - -// ignore: avoid_classes_with_only_static_members -/// internal class -class NistObjectIds { - // ignore: public_member_api_docs - static DerObjectID nistAlgorithm = DerObjectID('2.16.840.1.101.3.4'); - // ignore: public_member_api_docs - static DerObjectID hashAlgs = DerObjectID('${nistAlgorithm.id!}.2'); - // ignore: public_member_api_docs - static DerObjectID sha256 = DerObjectID('${hashAlgs.id!}.1'); - // ignore: public_member_api_docs - static DerObjectID sha384 = DerObjectID('${hashAlgs.id!}.2'); - // ignore: public_member_api_docs - static DerObjectID sha512 = DerObjectID('${hashAlgs.id!}.3'); - // ignore: public_member_api_docs - static DerObjectID dsaWithSHA2 = DerObjectID('${nistAlgorithm.id!}.3'); - // ignore: public_member_api_docs - static DerObjectID dsaWithSHA256 = DerObjectID('${dsaWithSHA2.id!}.2'); - // ignore: public_member_api_docs - static DerObjectID tttAlgorithm = DerObjectID('1.3.36.3'); - // ignore: public_member_api_docs - static DerObjectID ripeMD160 = DerObjectID('${tttAlgorithm.id!}.2.1'); - // ignore: public_member_api_docs - static DerObjectID tttRsaSignatureAlgorithm = DerObjectID( - '${tttAlgorithm.id!}.3.1', - ); - // ignore: public_member_api_docs - static DerObjectID rsaSignatureWithRipeMD160 = DerObjectID( - '${tttRsaSignatureAlgorithm.id!}.2', - ); -} - -/// internal type definition -typedef DocumentSavedHandler = - void Function(Object sender, DocumentSavedArgs args); - -/// internal type definition -typedef DocumentSavedHandlerAsync = - Future Function(Object sender, DocumentSavedArgs args); - -/// internal class -class DocumentSavedArgs { - /// internal constructor - DocumentSavedArgs(IPdfWriter writer) { - _writer = writer; - } - - //Fields - IPdfWriter? _writer; - - //Properties - /// internal property - IPdfWriter? get writer => _writer; -} +import 'dart:async'; +import 'dart:convert'; +import 'dart:math'; + +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; +import 'package:intl/intl.dart'; + +import '../../../interfaces/pdf_interface.dart'; +import '../../io/pdf_constants.dart'; +import '../../io/pdf_cross_table.dart'; +import '../../io/pdf_writer.dart'; +import '../../io/stream_reader.dart'; +import '../../pdf_document/pdf_document.dart'; +import '../../primitives/pdf_array.dart'; +import '../../primitives/pdf_dictionary.dart'; +import '../../primitives/pdf_name.dart'; +import '../../primitives/pdf_number.dart'; +import '../../primitives/pdf_reference_holder.dart'; +import '../../primitives/pdf_string.dart'; +import '../enum.dart'; +import '../pdf_security.dart'; +import 'asn1/asn1.dart'; +import 'asn1/asn1_stream.dart'; +import 'asn1/der.dart'; +import 'cryptography/cipher_block_chaining_mode.dart'; +import 'cryptography/cipher_utils.dart'; +import 'cryptography/ipadding.dart'; +import 'cryptography/pkcs1_encoding.dart'; +import 'cryptography/rsa_algorithm.dart'; +import 'cryptography/signature_utilities.dart'; +import 'pdf_certificate.dart'; +import 'pdf_external_signer.dart'; +import 'pdf_signature.dart'; +import 'pkcs/password_utility.dart'; +import 'pkcs/pfx_data.dart'; +import 'time_stamp_server/time_stamp_server.dart'; +import 'x509/ocsp_utils.dart'; +import 'x509/x509_certificates.dart'; + +/// Represents signature dictionary. +class PdfSignatureDictionary implements IPdfWrapper { + /// internal constructor + PdfSignatureDictionary(PdfDocument doc, PdfSignature sig) { + _doc = doc; + _sig = sig; + (PdfDocumentHelper.getHelper(doc).documentSavedList ??= + []) + .add(_documentSaved); + (PdfDocumentHelper.getHelper(doc).documentSavedListAsync ??= + []) + .add(_documentSavedAsync); + dictionary!.beginSaveList ??= []; + dictionary!.beginSaveList!.add(_dictionaryBeginSave); + _cert = sig.certificate; + } + + /// internal constructor + PdfSignatureDictionary.fromDictionary(PdfDocument doc, this.dictionary) { + _doc = doc; + (PdfDocumentHelper.getHelper(doc).documentSavedList ??= + []) + .add(_documentSaved); + (PdfDocumentHelper.getHelper(doc).documentSavedListAsync ??= + []) + .add(_documentSavedAsync); + dictionary!.beginSaveList ??= []; + dictionary!.beginSaveList!.add(_dictionaryBeginSave); + } + + //Fields + /// internal field + PdfDictionary? dictionary = PdfDictionary(); + late PdfDocument _doc; + PdfSignature? _sig; + final String _transParam = 'TransformParams'; + final String _docMdp = 'DocMDP'; + final String _cmsFilterType = 'adbe.pkcs7.detached'; + final String _cadasFilterType = 'ETSI.CAdES.detached'; + final String _rfcFilterType = 'ETSI.RFC3161'; + int? _firstRangeLength; + int? _secondRangeIndex; + int? _startPositionByteRange; + final int _estimatedSize = 8192; + PdfCertificate? _cert; + late List _range; + List? _stream; + + //Implementations + void _dictionaryBeginSave(Object sender, SavePdfPrimitiveArgs? args) { + final bool state = + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt; + dictionary!.encrypt = state; + if (_sig != null) { + _addRequiredItems(); + _addOptionalItems(); + } + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = false; + _addContents(args!.writer!); + _addRange(args.writer!); + if (_sig != null) { + if (PdfSignatureHelper.getHelper(_sig!).certificated) { + _addDigest(args.writer); + } + } + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = state; + } + + void _addRequiredItems() { + if (PdfSignatureHelper.getHelper(_sig!).certificated && _allowMDP()) { + _addReference(); + } + _addType(); + _addDate(); + _addFilter(); + _addSubFilter(); + } + + void _addOptionalItems() { + if (_sig != null) { + if (_sig!.reason != null) { + dictionary!.setProperty( + PdfDictionaryProperties.reason, + PdfString(_sig!.reason!), + ); + } + if (_sig!.locationInfo != null) { + dictionary!.setProperty( + PdfDictionaryProperties.location, + PdfString(_sig!.locationInfo!), + ); + } + if (_sig!.contactInfo != null) { + dictionary!.setProperty( + PdfDictionaryProperties.contactInfo, + PdfString(_sig!.contactInfo!), + ); + } + if (_sig!.signedName != null) { + dictionary!.setString(PdfDictionaryProperties.name, _sig!.signedName); + final PdfDictionary tempDictionary = PdfDictionary(); + final PdfDictionary appDictionary = PdfDictionary(); + tempDictionary.setName( + PdfName(PdfDictionaryProperties.name), + _sig!.signedName, + ); + appDictionary.setProperty('App', PdfReferenceHolder(tempDictionary)); + dictionary!.setProperty( + PdfName('Prop_Build'), + PdfReferenceHolder(appDictionary), + ); + } + } + } + + bool _allowMDP() { + final IPdfPrimitive? perms = PdfCrossTable.dereference( + PdfDocumentHelper.getHelper(_doc).catalog[PdfDictionaryProperties.perms], + ); + if (perms != null && perms is PdfDictionary) { + final IPdfPrimitive? docMDP = PdfCrossTable.dereference( + perms[PdfDictionaryProperties.docMDP], + ); + final IPdfPrimitive dicSig = dictionary!; + return dicSig == docMDP; + } + return false; + } + + void _addReference() { + final PdfDictionary trans = PdfDictionary(); + final PdfDictionary reference = PdfDictionary(); + final PdfArray array = PdfArray(); + trans[PdfDictionaryProperties.v] = PdfName('1.2'); + trans[PdfDictionaryProperties.p] = PdfNumber( + PdfSignatureHelper.getHelper( + _sig!, + ).getCertificateFlagResult(_sig!.documentPermissions), + ); + trans[PdfDictionaryProperties.type] = PdfName(_transParam); + reference[PdfDictionaryProperties.transformMethod] = PdfName(_docMdp); + reference[PdfDictionaryProperties.type] = PdfName('SigRef'); + reference[_transParam] = trans; + array.add(reference); + dictionary!.setProperty('Reference', array); + } + + void _addType() { + if (_sig != null && _sig!.timestampServer != null && _cert == null) { + dictionary!.setName( + PdfName(PdfDictionaryProperties.type), + 'DocTimeStamp', + ); + } else { + dictionary!.setName(PdfName(PdfDictionaryProperties.type), 'Sig'); + } + } + + void _addDate() { + DateTime dateTime = DateTime.now(); + if (_sig != null && _sig!.signedDate != null) { + dateTime = _sig!.signedDate!; + } + final DateFormat dateFormat = DateFormat('yyyyMMddHHmmss'); + final Duration offset = dateTime.timeZoneOffset; + final String sign = offset.isNegative ? '-' : '+'; + final String offsetHours = offset.inHours.abs().toString().padLeft(2, '0'); + final String offsetMinutes = (offset.inMinutes.abs() % 60) + .toString() + .padLeft(2, '0'); + + dictionary!.setProperty( + PdfDictionaryProperties.m, + PdfString( + "D:${dateFormat.format(dateTime)}$sign$offsetHours'$offsetMinutes'", + ), + ); + } + + void _addFilter() { + dictionary!.setName( + PdfName(PdfDictionaryProperties.filter), + 'Adobe.PPKLite', + ); + } + + void _addSubFilter() { + if (_sig != null && _sig!.timestampServer != null && _cert == null) { + dictionary!.setName( + PdfName(PdfDictionaryProperties.subFilter), + _rfcFilterType, + ); + } else { + dictionary!.setName( + PdfName(PdfDictionaryProperties.subFilter), + _sig!.cryptographicStandard == CryptographicStandard.cades + ? _cadasFilterType + : _cmsFilterType, + ); + } + } + + void _addContents(IPdfWriter writer) { + writer.write( + PdfOperators.slash + + PdfDictionaryProperties.contents + + PdfOperators.whiteSpace, + ); + _firstRangeLength = writer.position; + int length = _estimatedSize * 2; + if (_sig != null && _cert != null) { + length = _estimatedSize; + if (_sig!.timestampServer != null) { + length += 4192; + } + } + final List contents = List.filled( + length * 2 + 2, + 0, + growable: true, + ); + writer.write(contents); + _secondRangeIndex = writer.position; + writer.write(PdfOperators.newLine); + } + + void _addRange(IPdfWriter writer) { + writer.write( + PdfOperators.slash + + PdfDictionaryProperties.byteRange + + PdfOperators.whiteSpace + + PdfArray.startMark, + ); + _startPositionByteRange = writer.position; + for (int i = 0; i < 32; i++) { + writer.write(PdfOperators.whiteSpace); + } + writer.write(PdfArray.endMark + PdfOperators.newLine); + } + + void _addDigest(IPdfWriter? writer) { + if (_allowMDP()) { + final PdfDictionary cat = + PdfDocumentHelper.getHelper(writer!.document!).catalog; + writer.write(PdfName(PdfDictionaryProperties.reference)); + writer.write(PdfArray.startMark); + writer.write('<<'); + writer.write(PdfOperators.slash + _transParam); + PdfDictionary trans = PdfDictionary(); + trans[PdfDictionaryProperties.v] = PdfName('1.2'); + trans[PdfDictionaryProperties.p] = PdfNumber( + PdfSignatureHelper.getHelper( + _sig!, + ).getCertificateFlagResult(_sig!.documentPermissions), + ); + trans[PdfDictionaryProperties.type] = PdfName(_transParam); + writer.write(trans); + writer.write(PdfName(PdfDictionaryProperties.transformMethod)); + writer.write(PdfName(_docMdp)); + writer.write(PdfName(PdfDictionaryProperties.type)); + writer.write(PdfName(PdfDictionaryProperties.sigRef)); + writer.write(PdfName('DigestValue')); + int position = writer.position!; + // _docDigestPosition = position; + writer.write( + PdfString.fromBytes(List.filled(16, 0, growable: true)), + ); + PdfArray digestLocation = PdfArray(); + digestLocation.add(PdfNumber(position)); + digestLocation.add(PdfNumber(34)); + writer.write(PdfName('DigestLocation')); + writer.write(digestLocation); + writer.write(PdfName('DigestMethod')); + writer.write(PdfName('MD5')); + writer.write(PdfName(PdfDictionaryProperties.data)); + final PdfReferenceHolder refh = PdfReferenceHolder(cat); + writer.write(PdfOperators.whiteSpace); + writer.write(refh); + writer.write('>>'); + writer.write('<<'); + writer.write(PdfName(_transParam)); + trans = PdfDictionary(); + trans[PdfDictionaryProperties.v] = PdfName('1.2'); + final PdfArray fields = PdfArray(); + fields.add(PdfString(PdfSignatureHelper.getHelper(_sig!).field!.name!)); + trans[PdfDictionaryProperties.fields] = fields; + trans[PdfDictionaryProperties.type] = PdfName(_transParam); + trans[PdfDictionaryProperties.action] = PdfName('Include'); + writer.write(trans); + writer.write(PdfName(PdfDictionaryProperties.transformMethod)); + writer.write(PdfName('FieldMDP')); + writer.write(PdfName(PdfDictionaryProperties.type)); + writer.write(PdfName(PdfDictionaryProperties.sigRef)); + writer.write(PdfName('DigestValue')); + position = writer.position!; + // _fieldsDigestPosition = position; + writer.write( + PdfString.fromBytes(List.filled(16, 0, growable: true)), + ); + digestLocation = PdfArray(); + digestLocation.add(PdfNumber(position)); + digestLocation.add(PdfNumber(34)); + writer.write(PdfName('DigestLocation')); + writer.write(digestLocation); + writer.write(PdfName('DigestMethod')); + writer.write(PdfName('MD5')); + writer.write(PdfName(PdfDictionaryProperties.data)); + writer.write(PdfOperators.whiteSpace); + writer.write(PdfReferenceHolder(cat)); + writer.write('>>'); + writer.write(PdfArray.endMark); + writer.write(PdfOperators.whiteSpace); + } + } + + void _documentSaved(Object sender, DocumentSavedArgs e) { + final bool enabled = + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt; + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = false; + final PdfWriter writer = e.writer! as PdfWriter; + final int number = e.writer!.length! - _secondRangeIndex!; + const String str = '0 '; + final String str2 = '$_firstRangeLength '; + final String str3 = '$_secondRangeIndex '; + final String str4 = number.toString(); + int startPosition = _saveRangeItem(writer, str, _startPositionByteRange!); + startPosition = _saveRangeItem(writer, str2, startPosition); + startPosition = _saveRangeItem(writer, str3, startPosition); + _saveRangeItem(e.writer! as PdfWriter, str4, startPosition); + _range = [0, int.parse(str2), int.parse(str3), int.parse(str4)]; + _stream = writer.buffer; + final String text = PdfString.bytesToHex(getPkcs7Content()!); + _stream!.replaceRange( + _firstRangeLength!, + _firstRangeLength! + 1, + utf8.encode('<'), + ); + final int newPos = _firstRangeLength! + 1 + text.length; + _stream!.replaceRange(_firstRangeLength! + 1, newPos, utf8.encode(text)); + final int num3 = (_secondRangeIndex! - newPos) ~/ 2; + final String emptyText = PdfString.bytesToHex( + List.generate(num3, (int i) => 0), + ); + _stream!.replaceRange( + newPos, + newPos + emptyText.length, + utf8.encode(emptyText), + ); + _stream!.replaceRange( + newPos + emptyText.length, + newPos + emptyText.length + 1, + utf8.encode('>'), + ); + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = enabled; + } + + Future _documentSavedAsync(Object sender, DocumentSavedArgs e) async { + final bool enabled = + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt; + PdfSecurityHelper.getHelper(_doc.security).encryptor.encrypt = false; + final PdfWriter writer = e.writer! as PdfWriter; + final int number = e.writer!.length! - _secondRangeIndex!; + const String str = '0 '; + final String str2 = '$_firstRangeLength '; + final String str3 = '$_secondRangeIndex '; + final String str4 = number.toString(); + await _saveRangeItemAsync(writer, str, _startPositionByteRange!).then(( + int startPosition, + ) async { + await _saveRangeItemAsync(writer, str2, startPosition).then(( + int startPosition, + ) async { + await _saveRangeItemAsync(writer, str3, startPosition).then(( + int startPosition, + ) async { + await _saveRangeItemAsync( + e.writer! as PdfWriter, + str4, + startPosition, + ).then((int startPosition) async { + _range = [ + 0, + int.parse(str2), + int.parse(str3), + int.parse(str4), + ]; + _stream = writer.buffer; + if (_cert != null || + (_sig != null && + PdfSignatureHelper.getHelper(_sig!).externalSigner != + null)) { + await getPkcs7ContentAsync().then((List? value) async { + await PdfString.bytesToHexAsync(value!).then(( + String text, + ) async { + _stream!.replaceRange( + _firstRangeLength!, + _firstRangeLength! + 1, + utf8.encode('<'), + ); + final int newPos = _firstRangeLength! + 1 + text.length; + _stream!.replaceRange( + _firstRangeLength! + 1, + newPos, + utf8.encode(text), + ); + final int num3 = (_secondRangeIndex! - newPos) ~/ 2; + await PdfString.bytesToHexAsync( + List.generate(num3, (int i) => 0), + ).then((String emptyText) async { + _stream!.replaceRange( + newPos, + newPos + emptyText.length, + utf8.encode(emptyText), + ); + _stream!.replaceRange( + newPos + emptyText.length, + newPos + emptyText.length + 1, + utf8.encode('>'), + ); + PdfSecurityHelper.getHelper(_doc.security) + .encryptor + .encrypt = enabled; + }); + }); + }); + } else if (_sig != null && _sig!.timestampServer != null) { + await _getPKCS7TimeStampContent().then((List? value) async { + await PdfString.bytesToHexAsync(value!).then(( + String text, + ) async { + _stream!.replaceRange( + _firstRangeLength!, + _firstRangeLength! + 1, + utf8.encode('<'), + ); + final int newPos = _firstRangeLength! + 1 + text.length; + _stream!.replaceRange( + _firstRangeLength! + 1, + newPos, + utf8.encode(text), + ); + final int num3 = (_secondRangeIndex! - newPos) ~/ 2; + await PdfString.bytesToHexAsync( + List.generate(num3, (int i) => 0), + ).then((String emptyText) async { + _stream!.replaceRange( + newPos, + newPos + emptyText.length, + utf8.encode(emptyText), + ); + _stream!.replaceRange( + newPos + emptyText.length, + newPos + emptyText.length + 1, + utf8.encode('>'), + ); + PdfSecurityHelper.getHelper(_doc.security) + .encryptor + .encrypt = enabled; + }); + }); + }); + } + }); + }); + }); + }); + } + + /// internal method + List? getPkcs7Content() { + String? hashAlgorithm = ''; + _SignaturePrivateKey externalSignature; + List>? crlBytes; + List? ocspByte; + List? chain = []; + final IPdfExternalSigner? externalSigner = + PdfSignatureHelper.getHelper(_sig!).externalSigner; + if (externalSigner != null && + PdfSignatureHelper.getHelper(_sig!).externalChain != null) { + chain = PdfSignatureHelper.getHelper(_sig!).externalChain; + final String digest = getDigestAlgorithm(externalSigner.hashAlgorithm); + final _SignaturePrivateKey pks = _SignaturePrivateKey(digest); + hashAlgorithm = pks.getHashAlgorithm(); + externalSignature = pks; + } else { + String certificateAlias = ''; + final List keys = + PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getContentTable().keys.toList(); + bool isContinue = true; + // ignore: avoid_function_literals_in_foreach_calls + keys.forEach((String key) { + if (isContinue && + PdfCertificateHelper.getPkcsCertificate(_cert!).isKey(key) && + PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getKey(key)!.key!.isPrivate!) { + certificateAlias = key; + isContinue = false; + } + }); + final KeyEntry pk = + PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getKey(certificateAlias)!; + final List certificates = + PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getCertificateChain(certificateAlias)!; + // ignore: avoid_function_literals_in_foreach_calls + certificates.forEach((X509Certificates c) { + chain!.add(c.certificate); + }); + final RsaPrivateKeyParam? parameters = pk.key as RsaPrivateKeyParam?; + final String digest = + _sig != null + ? getDigestAlgorithm(_sig!.digestAlgorithm) + : MessageDigestAlgorithms.secureHash256; + final _SignaturePrivateKey pks = _SignaturePrivateKey(digest, parameters); + hashAlgorithm = pks.getHashAlgorithm(); + externalSignature = pks; + } + final _PdfCmsSigner pkcs7 = _PdfCmsSigner( + null, + chain, + hashAlgorithm!, + false, + ); + final IRandom source = getUnderlyingSource(); + final List sources = List.generate( + _range.length ~/ 2, + (int i) => null, + ); + for (int j = 0; j < _range.length; j += 2) { + sources[j ~/ 2] = _WindowRandom(source, _range[j], _range[j + 1]); + } + final PdfStreamReader data = _RandomStream(_RandomGroup(sources)); + final List hash = pkcs7._digestAlgorithm.digest(data, hashAlgorithm)!; + final List? sh = pkcs7 + .getSequenceDataSet( + hash, + ocspByte, + crlBytes, + _sig!.cryptographicStandard, + ) + .getEncoded(Asn1.der); + List? extSignature; + if (externalSigner != null) { + final SignerResult? signerResult = externalSigner.signSync(sh!); + if (signerResult != null && signerResult.signedData.isNotEmpty) { + extSignature = signerResult.signedData; + } + if (extSignature != null) { + pkcs7.setSignedData( + extSignature, + null, + externalSignature.getEncryptionAlgorithm(), + ); + } else { + return List.filled(_estimatedSize, 0, growable: true); + } + } else { + extSignature = externalSignature.sign(sh!); + } + pkcs7.setSignedData( + extSignature!, + null, + externalSignature.getEncryptionAlgorithm(), + ); + return pkcs7.sign( + hash, + _sig!.timestampServer, + null, + ocspByte, + crlBytes, + _sig!.cryptographicStandard, + hashAlgorithm, + ); + } + + /// internal method + Future?> getPkcs7ContentAsync() async { + List? pkcs7Content; + String? hashAlgorithm = ''; + _SignaturePrivateKey? externalSignature; + List>? crlBytes; + List? ocspByte; + List? chain = []; + final IPdfExternalSigner? externalSigner = + PdfSignatureHelper.getHelper(_sig!).externalSigner; + if (externalSigner != null && + PdfSignatureHelper.getHelper(_sig!).externalChain != null) { + chain = PdfSignatureHelper.getHelper(_sig!).externalChain; + final String digest = getDigestAlgorithm(externalSigner.hashAlgorithm); + final _SignaturePrivateKey pks = _SignaturePrivateKey(digest); + hashAlgorithm = pks.getHashAlgorithm(); + externalSignature = pks; + } else { + String certificateAlias = ''; + await PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getContentTableAsync().then((Map contentTable) async { + final List keys = contentTable.keys.toList(); + bool isContinue = true; + // ignore: avoid_function_literals_in_foreach_calls + keys.forEach((String key) { + if (isContinue && + PdfCertificateHelper.getPkcsCertificate(_cert!).isKey(key) && + PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getKey(key)!.key!.isPrivate!) { + certificateAlias = key; + isContinue = false; + } + }); + final KeyEntry pk = + PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getKey(certificateAlias)!; + await PdfCertificateHelper.getPkcsCertificate( + _cert!, + ).getCertificateChainAsync(certificateAlias).then(( + List? certificates, + ) { + // ignore: avoid_function_literals_in_foreach_calls + certificates!.forEach((X509Certificates c) { + chain!.add(c.certificate); + }); + final RsaPrivateKeyParam? parameters = pk.key as RsaPrivateKeyParam?; + final String digest = + _sig != null + ? getDigestAlgorithm(_sig!.digestAlgorithm) + : MessageDigestAlgorithms.secureHash256; + final _SignaturePrivateKey pks = _SignaturePrivateKey( + digest, + parameters, + ); + hashAlgorithm = pks.getHashAlgorithm(); + externalSignature = pks; + }); + }); + } + final _PdfCmsSigner pkcs7 = _PdfCmsSigner( + null, + chain, + hashAlgorithm!, + false, + ); + final IRandom source = getUnderlyingSource(); + final List sources = List.generate( + _range.length ~/ 2, + (int i) => null, + ); + for (int j = 0; j < _range.length; j += 2) { + sources[j ~/ 2] = _WindowRandom(source, _range[j], _range[j + 1]); + } + final PdfStreamReader data = _RandomStream(_RandomGroup(sources)); + await pkcs7._digestAlgorithm.digestAsync(data, hashAlgorithm).then(( + List? hash, + ) async { + await pkcs7 + .getSequenceDataSetAsync( + hash!, + ocspByte, + crlBytes, + _sig!.cryptographicStandard, + ) + .then((DerSet derSet) async { + await derSet.getEncodedAsync(Asn1.der).then((List? sh) async { + List? extSignature; + if (externalSigner != null) { + await externalSigner.sign(sh!).then(( + SignerResult? signerResult, + ) async { + signerResult ??= externalSigner.signSync(sh); + if (signerResult != null && + signerResult.signedData.isNotEmpty) { + extSignature = signerResult.signedData; + } + if (extSignature != null) { + await pkcs7.setSignedDataAsync( + extSignature!, + null, + externalSignature!.getEncryptionAlgorithm(), + ); + } else { + pkcs7Content = List.filled( + _estimatedSize, + 0, + growable: true, + ); + } + }); + } else { + await externalSignature! + .signAsync(sh!) + .then((List? value) => extSignature = value); + } + if (pkcs7Content == null) { + await pkcs7.setSignedDataAsync( + extSignature!, + null, + externalSignature!.getEncryptionAlgorithm(), + ); + pkcs7Content = await pkcs7.signAsync( + hash, + _sig!.timestampServer, + null, + ocspByte, + crlBytes, + _sig!.cryptographicStandard, + hashAlgorithm, + ); + } + }); + }); + }); + return pkcs7Content; + } + + Future?> _getPKCS7TimeStampContent() async { + final _SignaturePrivateKey externalSignature = _SignaturePrivateKey( + MessageDigestAlgorithms.secureHash256, + ); + final String? hashAlgorithm = externalSignature.getHashAlgorithm(); + final _PdfCmsSigner pkcs7 = _PdfCmsSigner( + null, + null, + hashAlgorithm!, + false, + ); + final IRandom source = getUnderlyingSource(); + final List sources = List.filled( + _range.length ~/ 2, + null, + ); + for (int j = 0; j < _range.length; j += 2) { + sources[j ~/ 2] = _WindowRandom(source, _range[j], _range[j + 1]); + } + final PdfStreamReader data = _RandomStream(_RandomGroup(sources)); + final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); + final List? hash = alg.digest(data, hashAlgorithm); + if (hash != null) { + pkcs7.setSignedData( + hash, + null, + externalSignature.getEncryptionAlgorithm(), + ); + return pkcs7.getEncodedTimestamp(hash, _sig!.timestampServer!); + } + return null; + } + + /// internal method + IRandom getUnderlyingSource() { + return _RandomArray(_stream!.sublist(0)); + } + + /// internal method + String getDigestAlgorithm(DigestAlgorithm? digest) { + String digestAlgorithm; + switch (digest) { + case DigestAlgorithm.sha1: + digestAlgorithm = MessageDigestAlgorithms.secureHash1; + break; + case DigestAlgorithm.sha384: + digestAlgorithm = MessageDigestAlgorithms.secureHash384; + break; + case DigestAlgorithm.sha512: + digestAlgorithm = MessageDigestAlgorithms.secureHash512; + break; + // ignore: no_default_cases + default: + digestAlgorithm = MessageDigestAlgorithms.secureHash256; + break; + } + return digestAlgorithm; + } + + int _saveRangeItem(PdfWriter writer, String str, int startPosition) { + final List date = utf8.encode(str); + writer.buffer!.replaceRange( + startPosition, + startPosition + date.length, + date, + ); + return startPosition + str.length; + } + + Future _saveRangeItemAsync( + PdfWriter writer, + String str, + int startPosition, + ) async { + final List date = utf8.encode(str); + writer.buffer!.replaceRange( + startPosition, + startPosition + date.length, + date, + ); + return startPosition + str.length; + } + + /// internal property + IPdfPrimitive? get element => dictionary; + set element(IPdfPrimitive? value) { + throw ArgumentError("Primitive element can't be set"); + } +} + +/// internal class +class MessageDigestAlgorithms { + /// internal constructor + MessageDigestAlgorithms() { + _names = {}; + _names['1.2.840.113549.2.5'] = 'MD5'; + _names['1.3.14.3.2.26'] = 'SHA1'; + _names['2.16.840.1.101.3.4.2.1'] = 'SHA256'; + _names['2.16.840.1.101.3.4.2.2'] = 'SHA384'; + _names['2.16.840.1.101.3.4.2.3'] = 'SHA512'; + _names['1.3.36.3.2.1'] = 'RIPEMD160'; + _names['1.2.840.113549.1.1.4'] = 'MD5'; + _names['1.2.840.113549.1.1.5'] = 'SHA1'; + _names['1.2.840.113549.1.1.11'] = 'SHA256'; + _names['1.2.840.113549.1.1.12'] = 'SHA384'; + _names['1.2.840.113549.1.1.13'] = 'SHA512'; + _names['1.2.840.113549.2.5'] = 'MD5'; + _names['1.2.840.10040.4.3'] = 'SHA1'; + _names['2.16.840.1.101.3.4.3.2'] = 'SHA256'; + _names['2.16.840.1.101.3.4.3.3'] = 'SHA384'; + _names['2.16.840.1.101.3.4.3.4'] = 'SHA512'; + _names['1.3.36.3.3.1.2'] = 'RIPEMD160'; + _digests = {}; + _digests['MD5'] = '1.2.840.113549.2.5'; + _digests['MD-5'] = '1.2.840.113549.2.5'; + _digests['SHA1'] = '1.3.14.3.2.26'; + _digests['SHA-1'] = '1.3.14.3.2.26'; + _digests['SHA256'] = '2.16.840.1.101.3.4.2.1'; + _digests['SHA-256'] = '2.16.840.1.101.3.4.2.1'; + _digests['SHA384'] = '2.16.840.1.101.3.4.2.2'; + _digests['SHA-384'] = '2.16.840.1.101.3.4.2.2'; + _digests['SHA512'] = '2.16.840.1.101.3.4.2.3'; + _digests['SHA-512'] = '2.16.840.1.101.3.4.2.3'; + _digests['RIPEMD160'] = '1.3.36.3.2.1'; + _digests['RIPEMD-160'] = '1.3.36.3.2.1'; + _algorithms = {}; + _algorithms['SHA1'] = 'SHA-1'; + _algorithms[DerObjectID('1.3.14.3.2.26').id] = 'SHA-1'; + _algorithms['SHA256'] = 'SHA-256'; + _algorithms[NistObjectIds.sha256.id] = 'SHA-256'; + _algorithms['SHA384'] = 'SHA-384'; + _algorithms[NistObjectIds.sha384.id] = 'SHA-384'; + _algorithms['SHA512'] = 'SHA-512'; + _algorithms[NistObjectIds.sha512.id] = 'SHA-512'; + _algorithms['MD5'] = 'MD5'; + _algorithms[PkcsObjectId.md5.id] = 'MD5'; + _algorithms['RIPEMD-160'] = 'RIPEMD160'; + _algorithms['RIPEMD160'] = 'RIPEMD160'; + _algorithms[NistObjectIds.ripeMD160.id] = 'RIPEMD160'; + } + + /// internal field + static const String secureHash1 = 'SHA-1'; + + /// internal field + static const String secureHash256 = 'SHA-256'; + + /// internal field + static const String secureHash384 = 'SHA-384'; + + /// internal field + static const String secureHash512 = 'SHA-512'; + late Map _names; + late Map _digests; + late Map _algorithms; + + /// internal method + String? getDigest(String? id) { + String? result; + if (_names.containsKey(id)) { + result = _names[id!]; + } else { + result = id; + } + return result; + } + + /// internal method + String? getAllowedDigests(String name) { + String? result; + final String lower = name.toLowerCase(); + _digests.forEach((String key, String value) { + if (lower == key.toLowerCase()) { + result = _digests[key]; + } + }); + return result; + } + + /// internal method + Future getAllowedDigestsAsync(String name) async { + String? result; + final String lower = name.toLowerCase(); + _digests.forEach((String key, String value) { + if (lower == key.toLowerCase()) { + result = _digests[key]; + } + }); + return result; + } + + /// internal method + dynamic getMessageDigest(String hashAlgorithm) { + String lower = hashAlgorithm.toLowerCase(); + String? digest = lower; + bool isContinue = true; + _algorithms.forEach((String? key, String value) { + if (isContinue && key!.toLowerCase() == lower) { + digest = _algorithms[key]; + isContinue = false; + } + }); + dynamic result; + lower = digest!.toLowerCase(); + if (lower == 'sha1' || lower == 'sha-1' || lower == 'sha_1') { + result = sha1; + } else if (lower == 'sha256' || lower == 'sha-256' || lower == 'sha_256') { + result = sha256; + } else if (lower == 'sha384' || lower == 'sha-384' || lower == 'sha_384') { + result = sha384; + } else if (lower == 'sha512' || lower == 'sha-512' || lower == 'sha_512') { + result = sha512; + } else if (lower == 'md5' || lower == 'md-5' || lower == 'md_5') { + result = md5; + } else { + throw ArgumentError.value( + hashAlgorithm, + 'hashAlgorithm', + 'Invalid message digest algorithm', + ); + } + return result; + } + + /// internal method + Future getMessageDigestAsync(String hashAlgorithm) async { + String lower = hashAlgorithm.toLowerCase(); + String? digest = lower; + bool isContinue = true; + _algorithms.forEach((String? key, String value) { + if (isContinue && key!.toLowerCase() == lower) { + digest = _algorithms[key]; + isContinue = false; + } + }); + dynamic result; + lower = digest!.toLowerCase(); + if (lower == 'sha1' || lower == 'sha-1' || lower == 'sha_1') { + result = sha1; + } else if (lower == 'sha256' || lower == 'sha-256' || lower == 'sha_256') { + result = sha256; + } else if (lower == 'sha384' || lower == 'sha-384' || lower == 'sha_384') { + result = sha384; + } else if (lower == 'sha512' || lower == 'sha-512' || lower == 'sha_512') { + result = sha512; + } else if (lower == 'md5' || lower == 'md-5' || lower == 'md_5') { + result = md5; + } else { + throw ArgumentError.value( + hashAlgorithm, + 'hashAlgorithm', + 'Invalid message digest algorithm', + ); + } + return result; + } + + /// internal method + List? digest(PdfStreamReader data, dynamic hashAlgorithm) { + dynamic algorithm; + if (hashAlgorithm is String) { + algorithm = getMessageDigest(hashAlgorithm); + } else { + algorithm = hashAlgorithm; + } + final dynamic output = AccumulatorSink(); + final dynamic input = algorithm.startChunkedConversion(output); + int? count; + final List bytes = List.generate(8192, (int i) => 0); + while ((count = data.read(bytes, 0, bytes.length))! > 0) { + input.add(bytes.sublist(0, count)); + } + input.close(); + return output.events.single.bytes as List?; + } + + /// internal method + Future?> digestAsync( + PdfStreamReader data, + dynamic hashAlgorithm, + ) async { + dynamic algorithm; + algorithm = + hashAlgorithm is String + ? await getMessageDigestAsync(hashAlgorithm) + : hashAlgorithm; + final dynamic output = AccumulatorSink(); + final dynamic input = algorithm.startChunkedConversion(output); + int? count; + final List bytes = List.generate(8192, (int i) => 0); + while ((count = data.read(bytes, 0, bytes.length))! > 0) { + input.add(bytes.sublist(0, count)); + } + input.close(); + return output.events.single.bytes as List?; + } +} + +class _SignaturePrivateKey { + _SignaturePrivateKey(String hashAlgorithm, [ICipherParameter? key]) { + _key = key; + final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); + _hashAlgorithm = alg.getDigest(alg.getAllowedDigests(hashAlgorithm)); + if (key == null || key is RsaKeyParam) { + _encryptionAlgorithm = 'RSA'; + } else { + throw ArgumentError.value(key, 'key', 'Invalid key'); + } + } + //Fields + ICipherParameter? _key; + String? _hashAlgorithm; + String? _encryptionAlgorithm; + //Implementation + List? sign(List bytes) { + final String signMode = '${_hashAlgorithm!}with${_encryptionAlgorithm!}'; + final SignerUtilities util = SignerUtilities(); + final ISigner signer = util.getSigner(signMode); + signer.initialize(true, _key); + signer.blockUpdate(bytes, 0, bytes.length); + return signer.generateSignature(); + } + + Future?> signAsync(List bytes) async { + final String signMode = '${_hashAlgorithm!}with${_encryptionAlgorithm!}'; + final SignerUtilities util = SignerUtilities(); + final ISigner signer = util.getSigner(signMode); + signer.initialize(true, _key); + signer.blockUpdate(bytes, 0, bytes.length); + return signer.generateSignature(); + } + + String? getHashAlgorithm() { + return _hashAlgorithm; + } + + String? getEncryptionAlgorithm() { + return _encryptionAlgorithm; + } +} + +/// Internal class +class SignerUtilities { + /// Internal consturctor + SignerUtilities() { + _algms['MD2WITHRSA'] = 'MD2withRSA'; + _algms['MD2WITHRSAENCRYPTION'] = 'MD2withRSA'; + _algms[PkcsObjectId.md2WithRsaEncryption.id] = 'MD2withRSA'; + _algms[PkcsObjectId.rsaEncryption.id] = 'RSA'; + _algms['SHA1WITHRSA'] = 'SHA-1withRSA'; + _algms['SHA1WITHRSAENCRYPTION'] = 'SHA-1withRSA'; + _algms[PkcsObjectId.sha1WithRsaEncryption.id] = 'SHA-1withRSA'; + _algms['SHA-1WITHRSA'] = 'SHA-1withRSA'; + _algms['SHA256WITHRSA'] = 'SHA-256withRSA'; + _algms['SHA256WITHRSAENCRYPTION'] = 'SHA-256withRSA'; + _algms[PkcsObjectId.sha256WithRsaEncryption.id] = 'SHA-256withRSA'; + _algms['SHA-256WITHRSA'] = 'SHA-256withRSA'; + _algms['SHA1WITHRSAANDMGF1'] = 'SHA-1withRSAandMGF1'; + _algms['SHA-1WITHRSAANDMGF1'] = 'SHA-1withRSAandMGF1'; + _algms['SHA1WITHRSA/PSS'] = 'SHA-1withRSAandMGF1'; + _algms['SHA-1WITHRSA/PSS'] = 'SHA-1withRSAandMGF1'; + _algms['SHA224WITHRSAANDMGF1'] = 'SHA-224withRSAandMGF1'; + _algms['SHA-224WITHRSAANDMGF1'] = 'SHA-224withRSAandMGF1'; + _algms['SHA224WITHRSA/PSS'] = 'SHA-224withRSAandMGF1'; + _algms['SHA-224WITHRSA/PSS'] = 'SHA-224withRSAandMGF1'; + _algms['SHA256WITHRSAANDMGF1'] = 'SHA-256withRSAandMGF1'; + _algms['SHA-256WITHRSAANDMGF1'] = 'SHA-256withRSAandMGF1'; + _algms['SHA256WITHRSA/PSS'] = 'SHA-256withRSAandMGF1'; + _algms['SHA-256WITHRSA/PSS'] = 'SHA-256withRSAandMGF1'; + _algms['SHA384WITHRSA'] = 'SHA-384withRSA'; + _algms['SHA512WITHRSA'] = 'SHA-512withRSA'; + _algms['SHA384WITHRSAENCRYPTION'] = 'SHA-384withRSA'; + _algms[PkcsObjectId.sha384WithRsaEncryption.id] = 'SHA-384withRSA'; + _algms['SHA-384WITHRSA'] = 'SHA-384withRSA'; + _algms['SHA-512WITHRSA'] = 'SHA-512withRSA'; + _algms['SHA384WITHRSAANDMGF1'] = 'SHA-384withRSAandMGF1'; + _algms['SHA-384WITHRSAANDMGF1'] = 'SHA-384withRSAandMGF1'; + _algms['SHA384WITHRSA/PSS'] = 'SHA-384withRSAandMGF1'; + _algms['SHA-384WITHRSA/PSS'] = 'SHA-384withRSAandMGF1'; + _algms['SHA512WITHRSAANDMGF1'] = 'SHA-512withRSAandMGF1'; + _algms['SHA-512WITHRSAANDMGF1'] = 'SHA-512withRSAandMGF1'; + _algms['SHA512WITHRSA/PSS'] = 'SHA-512withRSAandMGF1'; + _algms['SHA-512WITHRSA/PSS'] = 'SHA-512withRSAandMGF1'; + _algms['DSAWITHSHA256'] = 'SHA-256withDSA'; + _algms['DSAWITHSHA-256'] = 'SHA-256withDSA'; + _algms['SHA256/DSA'] = 'SHA-256withDSA'; + _algms['SHA-256/DSA'] = 'SHA-256withDSA'; + _algms['SHA256WITHDSA'] = 'SHA-256withDSA'; + _algms['SHA-256WITHDSA'] = 'SHA-256withDSA'; + _algms[NistObjectIds.dsaWithSHA256.id] = 'SHA-256withDSA'; + _algms['RIPEMD160WITHRSA'] = 'RIPEMD160withRSA'; + _algms['RIPEMD160WITHRSAENCRYPTION'] = 'RIPEMD160withRSA'; + _algms[NistObjectIds.rsaSignatureWithRipeMD160.id] = 'RIPEMD160withRSA'; + _oids['SHA-1withRSA'] = PkcsObjectId.sha1WithRsaEncryption; + _oids['SHA-256withRSA'] = PkcsObjectId.sha256WithRsaEncryption; + _oids['SHA-384withRSA'] = PkcsObjectId.sha384WithRsaEncryption; + _oids['SHA-512withRSA'] = PkcsObjectId.sha512WithRsaEncryption; + _oids['RIPEMD160withRSA'] = NistObjectIds.rsaSignatureWithRipeMD160; + } + //Fields + final Map _algms = {}; + final Map _oids = {}; + //Implementation + /// Internal method + ISigner getSigner(String algorithm) { + ISigner result; + final String lower = algorithm.toLowerCase(); + String? mechanism = algorithm; + bool isContinue = true; + _algms.forEach((String? key, String value) { + if (isContinue && key!.toLowerCase() == lower) { + mechanism = _algms[key]; + isContinue = false; + } + }); + if (mechanism == 'SHA-1withRSA') { + result = _RmdSigner(DigestAlgorithms.sha1); + } else if (mechanism == 'SHA-256withRSA') { + return _RmdSigner(DigestAlgorithms.sha256); + } else if (mechanism == 'SHA-384withRSA') { + return _RmdSigner(DigestAlgorithms.sha384); + } else if (mechanism == 'SHA-512withRSA') { + return _RmdSigner(DigestAlgorithms.sha512); + } else { + throw ArgumentError.value('Signer $algorithm not recognised.'); + } + return result; + } + + /// Internal method + Future getSignerAsync(String algorithm) async { + ISigner result; + final String lower = algorithm.toLowerCase(); + String? mechanism = algorithm; + bool isContinue = true; + _algms.forEach((String? key, String value) { + if (isContinue && key!.toLowerCase() == lower) { + mechanism = _algms[key]; + isContinue = false; + } + }); + if (mechanism == 'SHA-1withRSA') { + result = _RmdSigner(DigestAlgorithms.sha1); + } else if (mechanism == 'SHA-256withRSA') { + return _RmdSigner(DigestAlgorithms.sha256); + } else if (mechanism == 'SHA-384withRSA') { + return _RmdSigner(DigestAlgorithms.sha384); + } else if (mechanism == 'SHA-512withRSA') { + return _RmdSigner(DigestAlgorithms.sha512); + } else { + throw ArgumentError.value('Signer $algorithm not recognised.'); + } + return result; + } +} + +class _PdfCmsSigner { + _PdfCmsSigner( + ICipherParameter? privateKey, + List? certChain, + String hashAlgorithm, + bool hasRSAdata, + ) { + _digestAlgorithm = MessageDigestAlgorithms(); + _digestAlgorithmOid = _digestAlgorithm.getAllowedDigests(hashAlgorithm); + if (_digestAlgorithmOid == null) { + throw ArgumentError.value( + hashAlgorithm, + 'hashAlgorithm', + 'Unknown Hash Algorithm', + ); + } + _version = 1; + _signerVersion = 1; + _digestOid = {}; + _digestOid[_digestAlgorithmOid] = null; + if (certChain != null) { + _certificates = List.generate( + certChain.length, + (int i) => certChain[i], + ); + _signCert = _certificates[0]; + } + if (privateKey != null) { + if (privateKey is RsaKeyParam) { + _encryptionAlgorithmOid = _DigitalIdentifiers.rsa; + } else { + throw ArgumentError.value( + privateKey, + 'privateKey', + 'Unknown key algorithm', + ); + } + } + if (hasRSAdata) { + _rsaData = []; + } + } + + //Fields + late MessageDigestAlgorithms _digestAlgorithm; + late int _version; + late int _signerVersion; + late List _certificates; + late Map _digestOid; + String? _digestAlgorithmOid; + X509Certificate? _signCert; + late String _encryptionAlgorithmOid; + String? _hashAlgorithm; + List? _rsaData; + List? _signedData; + List? _signedRsaData; + List? _digest; + + //Properties + String? get hashAlgorithm { + _hashAlgorithm ??= _digestAlgorithm.getDigest(_digestAlgorithmOid); + return _hashAlgorithm; + } + + //Implementation + DerSet getSequenceDataSet( + List secondDigest, + List? ocsp, + List>? crlBytes, + CryptographicStandard? sigtype, + ) { + final Asn1EncodeCollection attribute = Asn1EncodeCollection(); + Asn1EncodeCollection v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.contentType)); + v.encodableObjects.add( + DerSet(array: [DerObjectID(_DigitalIdentifiers.pkcs7Data)]), + ); + attribute.encodableObjects.add(DerSequence(collection: v)); + v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.messageDigest)); + v.encodableObjects.add(DerSet(array: [DerOctet(secondDigest)])); + attribute.encodableObjects.add(DerSequence(collection: v)); + if (sigtype == CryptographicStandard.cades) { + v = Asn1EncodeCollection(); + v.encodableObjects.add( + DerObjectID(_DigitalIdentifiers.aaSigningCertificateV2), + ); + final Asn1EncodeCollection aaV2 = Asn1EncodeCollection(); + final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); + final String? sha256Oid = alg.getAllowedDigests( + MessageDigestAlgorithms.secureHash256, + ); + if (sha256Oid != _digestAlgorithmOid) { + aaV2.encodableObjects.add(Algorithms(DerObjectID(_digestAlgorithmOid))); + } + final List dig = + alg + .getMessageDigest(hashAlgorithm!) + .convert(_signCert!.c!.getEncoded(Asn1.der)) + .bytes + as List; + aaV2.encodableObjects.add(DerOctet(dig)); + v.encodableObjects.add( + DerSet( + array: [ + DerSequence.fromObject( + DerSequence.fromObject(DerSequence(collection: aaV2)), + ), + ], + ), + ); + attribute.encodableObjects.add(DerSequence(collection: v)); + } + return DerSet(collection: attribute); + } + + //Implementation + Future getSequenceDataSetAsync( + List secondDigest, + List? ocsp, + List>? crlBytes, + CryptographicStandard? sigtype, + ) async { + final Asn1EncodeCollection attribute = Asn1EncodeCollection(); + Asn1EncodeCollection v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.contentType)); + v.encodableObjects.add( + DerSet(array: [DerObjectID(_DigitalIdentifiers.pkcs7Data)]), + ); + attribute.encodableObjects.add(DerSequence(collection: v)); + v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.messageDigest)); + v.encodableObjects.add(DerSet(array: [DerOctet(secondDigest)])); + attribute.encodableObjects.add(DerSequence(collection: v)); + if (sigtype == CryptographicStandard.cades) { + v = Asn1EncodeCollection(); + v.encodableObjects.add( + DerObjectID(_DigitalIdentifiers.aaSigningCertificateV2), + ); + final Asn1EncodeCollection aaV2 = Asn1EncodeCollection(); + final MessageDigestAlgorithms alg = MessageDigestAlgorithms(); + await alg + .getAllowedDigestsAsync(MessageDigestAlgorithms.secureHash256) + .then((String? sha256Oid) async { + if (sha256Oid != _digestAlgorithmOid) { + aaV2.encodableObjects.add( + Algorithms(DerObjectID(_digestAlgorithmOid)), + ); + } + await alg.getMessageDigestAsync(hashAlgorithm!).then(( + dynamic value, + ) { + aaV2.encodableObjects.add( + DerOctet( + value.convert(_signCert!.c!.getEncoded(Asn1.der)).bytes + as List, + ), + ); + v.encodableObjects.add( + DerSet( + array: [ + DerSequence.fromObject( + DerSequence.fromObject(DerSequence(collection: aaV2)), + ), + ], + ), + ); + attribute.encodableObjects.add(DerSequence(collection: v)); + }); + }); + } + return DerSet(collection: attribute); + } + + void setSignedData( + List digest, + List? rsaData, + String? digestEncryptionAlgorithm, + ) { + _signedData = digest; + _signedRsaData = rsaData; + if (digestEncryptionAlgorithm != null) { + if (digestEncryptionAlgorithm == 'RSA') { + _encryptionAlgorithmOid = _DigitalIdentifiers.rsa; + } else if (digestEncryptionAlgorithm == 'DSA') { + _encryptionAlgorithmOid = _DigitalIdentifiers.dsa; + } else if (digestEncryptionAlgorithm == 'ECDSA') { + _encryptionAlgorithmOid = _DigitalIdentifiers.ecdsa; + } else { + throw ArgumentError.value( + digestEncryptionAlgorithm, + 'algorithm', + 'Invalid entry', + ); + } + } + } + + Future setSignedDataAsync( + List digest, + List? rsaData, + String? digestEncryptionAlgorithm, + ) async { + _signedData = digest; + _signedRsaData = rsaData; + if (digestEncryptionAlgorithm != null) { + if (digestEncryptionAlgorithm == 'RSA') { + _encryptionAlgorithmOid = _DigitalIdentifiers.rsa; + } else if (digestEncryptionAlgorithm == 'DSA') { + _encryptionAlgorithmOid = _DigitalIdentifiers.dsa; + } else if (digestEncryptionAlgorithm == 'ECDSA') { + _encryptionAlgorithmOid = _DigitalIdentifiers.ecdsa; + } else { + throw ArgumentError.value( + digestEncryptionAlgorithm, + 'algorithm', + 'Invalid entry', + ); + } + } + } + + List? sign( + List secondDigest, + TimestampServer? server, + List? timeStampResponse, + List? ocsp, + List>? crls, + CryptographicStandard? sigtype, + String? hashAlgorithm, + ) { + if (_signedData != null) { + _digest = _signedData; + if (_rsaData != null) { + _rsaData = _signedRsaData; + } + } + final Asn1EncodeCollection digestAlgorithms = Asn1EncodeCollection(); + final List keys = _digestOid.keys.toList(); + // ignore: avoid_function_literals_in_foreach_calls + keys.forEach((String? dal) { + final Asn1EncodeCollection algos = Asn1EncodeCollection(); + algos.encodableObjects.add(DerObjectID(dal)); + algos.encodableObjects.add(DerNull.value); + digestAlgorithms.encodableObjects.add(DerSequence(collection: algos)); + }); + Asn1EncodeCollection v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.pkcs7Data)); + if (_rsaData != null) { + v.encodableObjects.add(DerTag(0, DerOctet(_rsaData!))); + } + final DerSequence contentinfo = DerSequence(collection: v); + + v = Asn1EncodeCollection(); + // ignore: avoid_function_literals_in_foreach_calls + _certificates.forEach((X509Certificate? xcert) { + v.encodableObjects.add( + Asn1Stream(PdfStreamReader(xcert!.c!.getEncoded(Asn1.der))).readAsn1(), + ); + }); + final DerSet dercertificates = DerSet(collection: v); + final Asn1EncodeCollection signerinfo = Asn1EncodeCollection(); + signerinfo.encodableObjects.add( + DerInteger(bigIntToBytes(BigInt.from(_signerVersion))), + ); + v = Asn1EncodeCollection(); + v.encodableObjects.add( + getIssuer(_signCert!.c!.tbsCertificate!.getEncoded(Asn1.der)), + ); + v.encodableObjects.add( + DerInteger(bigIntToBytes(_signCert!.c!.serialNumber!.value)), + ); + signerinfo.encodableObjects.add(DerSequence(collection: v)); + v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_digestAlgorithmOid)); + v.encodableObjects.add(DerNull.value); + signerinfo.encodableObjects.add(DerSequence(collection: v)); + signerinfo.encodableObjects.add( + DerTag(0, getSequenceDataSet(secondDigest, ocsp, crls, sigtype), false), + ); + v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_encryptionAlgorithmOid)); + v.encodableObjects.add(DerNull.value); + signerinfo.encodableObjects.add(DerSequence(collection: v)); + signerinfo.encodableObjects.add(DerOctet(_digest!)); + final Asn1EncodeCollection body = Asn1EncodeCollection(); + body.encodableObjects.add(DerInteger(bigIntToBytes(BigInt.from(_version)))); + body.encodableObjects.add(DerSet(collection: digestAlgorithms)); + body.encodableObjects.add(contentinfo); + body.encodableObjects.add(DerTag(0, dercertificates, false)); + body.encodableObjects.add( + DerSet(array: [DerSequence(collection: signerinfo)]), + ); + final Asn1EncodeCollection whole = Asn1EncodeCollection(); + whole.encodableObjects.add( + DerObjectID(_DigitalIdentifiers.pkcs7SignedData), + ); + whole.encodableObjects.add(DerTag(0, DerSequence(collection: body))); + final Asn1DerStream dout = Asn1DerStream([]); + dout.writeObject(DerSequence(collection: whole)); + return dout.stream; + } + + Asn1EncodeCollection? getAttributes(List timeStampToken) { + final Asn1Stream tempstream = Asn1Stream(PdfStreamReader(timeStampToken)); + final Asn1EncodeCollection attributes = Asn1EncodeCollection(); + final Asn1EncodeCollection asn1Encode = Asn1EncodeCollection(); + asn1Encode.add([DerObjectID('1.2.840.113549.1.9.16.2.14')]); + final Asn1? seq = tempstream.readAsn1(); + if (seq != null && seq is Asn1Sequence) { + asn1Encode.add([ + DerSet(array: [seq]), + ]); + attributes.add([DerSequence(collection: asn1Encode)]); + } + return attributes; + } + + Future?> signAsync( + List secondDigest, + TimestampServer? server, + List? timeStampResponse, + List? ocsp, + List>? crls, + CryptographicStandard? sigtype, + String? hashAlgorithm, + ) async { + if (_signedData != null) { + _digest = _signedData; + if (_rsaData != null) { + _rsaData = _signedRsaData; + } + } + final Asn1EncodeCollection digestAlgorithms = Asn1EncodeCollection(); + final List keys = _digestOid.keys.toList(); + // ignore: avoid_function_literals_in_foreach_calls + keys.forEach((String? dal) { + final Asn1EncodeCollection algos = Asn1EncodeCollection(); + algos.encodableObjects.add(DerObjectID(dal)); + algos.encodableObjects.add(DerNull.value); + digestAlgorithms.encodableObjects.add(DerSequence(collection: algos)); + }); + Asn1EncodeCollection v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_DigitalIdentifiers.pkcs7Data)); + if (_rsaData != null) { + v.encodableObjects.add(DerTag(0, DerOctet(_rsaData!))); + } + final DerSequence contentinfo = DerSequence(collection: v); + + v = Asn1EncodeCollection(); + // ignore: avoid_function_literals_in_foreach_calls + _certificates.forEach((X509Certificate? xcert) { + v.encodableObjects.add( + Asn1Stream(PdfStreamReader(xcert!.c!.getEncoded(Asn1.der))).readAsn1(), + ); + }); + final DerSet dercertificates = DerSet(collection: v); + final Asn1EncodeCollection signerinfo = Asn1EncodeCollection(); + signerinfo.encodableObjects.add( + DerInteger(bigIntToBytes(BigInt.from(_signerVersion))), + ); + v = Asn1EncodeCollection(); + v.encodableObjects.add( + getIssuer(_signCert!.c!.tbsCertificate!.getEncoded(Asn1.der)), + ); + v.encodableObjects.add( + DerInteger(bigIntToBytes(_signCert!.c!.serialNumber!.value)), + ); + signerinfo.encodableObjects.add(DerSequence(collection: v)); + v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_digestAlgorithmOid)); + v.encodableObjects.add(DerNull.value); + signerinfo.encodableObjects.add(DerSequence(collection: v)); + signerinfo.encodableObjects.add( + DerTag(0, getSequenceDataSet(secondDigest, ocsp, crls, sigtype), false), + ); + v = Asn1EncodeCollection(); + v.encodableObjects.add(DerObjectID(_encryptionAlgorithmOid)); + v.encodableObjects.add(DerNull.value); + signerinfo.encodableObjects.add(DerSequence(collection: v)); + signerinfo.encodableObjects.add(DerOctet(_digest!)); + if (timeStampResponse == null && server != null) { + final dynamic output = AccumulatorSink(); + final dynamic input = sha256.startChunkedConversion(output); + input.add(_digest); + input.close(); + final List hash = output.events.single.bytes as List; + final List asnEncodedTimestampRequest = TimeStampRequestCreator() + .getAsnEncodedTimestampRequest(hash); + timeStampResponse = await fetchData( + server.uri, + 'POST', + contentType: 'application/timestamp-query', + userName: server.userName, + password: server.password, + data: asnEncodedTimestampRequest, + timeOutDuration: server.timeOut, + ); + if (timeStampResponse != null) { + final Asn1Stream stream = Asn1Stream( + PdfStreamReader(timeStampResponse), + ); + final Asn1? asn1 = stream.readAsn1(); + if (asn1 != null && + asn1 is Asn1Sequence && + asn1.count > 1 && + asn1[1] != null && + asn1[1] is Asn1) { + final Asn1 asn1Sequence = asn1[1]! as Asn1; + final DerStream dOut = DerStream([]); + asn1Sequence.encode(dOut); + timeStampResponse = dOut.stream!.toList(); + dOut.stream!.clear(); + } + } + } + if (timeStampResponse != null) { + final Asn1EncodeCollection? timeAsn1Encoded = getAttributes( + timeStampResponse, + ); + if (timeAsn1Encoded != null) { + signerinfo.add([ + DerTag(1, DerSet(collection: timeAsn1Encoded), false), + ]); + } + } + final Asn1EncodeCollection body = Asn1EncodeCollection(); + body.encodableObjects.add(DerInteger(bigIntToBytes(BigInt.from(_version)))); + body.encodableObjects.add(DerSet(collection: digestAlgorithms)); + body.encodableObjects.add(contentinfo); + body.encodableObjects.add(DerTag(0, dercertificates, false)); + body.encodableObjects.add( + DerSet(array: [DerSequence(collection: signerinfo)]), + ); + final Asn1EncodeCollection whole = Asn1EncodeCollection(); + whole.encodableObjects.add( + DerObjectID(_DigitalIdentifiers.pkcs7SignedData), + ); + whole.encodableObjects.add(DerTag(0, DerSequence(collection: body))); + final Asn1DerStream dout = Asn1DerStream([]); + dout.writeObject(DerSequence(collection: whole)); + return dout.stream; + } + + Asn1? getIssuer(List? data) { + final Asn1Sequence seq = + Asn1Stream(PdfStreamReader(data)).readAsn1()! as Asn1Sequence; + return seq[seq[0] is Asn1Tag ? 3 : 2] as Asn1?; + } + + /// Internal method + Future?> getEncodedTimestamp( + List secondDigest, + TimestampServer server, + ) async { + List? encoded; + final List asnEncodedTimestampRequest = TimeStampRequestCreator() + .getAsnEncodedTimestampRequest(secondDigest); + final List? respBytes = await fetchData( + server.uri, + 'POST', + contentType: 'application/timestamp-query', + userName: server.userName, + password: server.password, + data: asnEncodedTimestampRequest, + timeOutDuration: server.timeOut, + ); + if (respBytes != null) { + final Asn1Stream stream = Asn1Stream(PdfStreamReader(respBytes)); + final Asn1? asn1 = stream.readAsn1(); + if (asn1 != null && + asn1 is Asn1Sequence && + asn1.count > 1 && + asn1[1] != null && + asn1[1] is Asn1) { + final Asn1 asn1Sequence = asn1[1]! as Asn1; + final DerStream dOut = DerStream([]); + asn1Sequence.encode(dOut); + encoded = dOut.stream!.toList(); + dOut.stream!.clear(); + } + } + return encoded; + } +} + +class _DigitalIdentifiers { + static const String pkcs7Data = '1.2.840.113549.1.7.1'; + static const String pkcs7SignedData = '1.2.840.113549.1.7.2'; + static const String rsa = '1.2.840.113549.1.1.1'; + static const String dsa = '1.2.840.10040.4.1'; + static const String ecdsa = '1.2.840.10045.2.1'; + static const String contentType = '1.2.840.113549.1.9.3'; + static const String messageDigest = '1.2.840.113549.1.9.4'; + static const String aaSigningCertificateV2 = '1.2.840.113549.1.9.16.2.47'; +} + +class _RandomArray implements IRandom { + _RandomArray(List array) { + _array = array; + } + //Fields + late List _array; + //Properties + @override + int get length => _array.length; + //Implementation + @override + int? getValue(int offset, [List? bytes, int? off, int? length]) { + if (bytes == null) { + if (offset >= _array.length) { + return -1; + } + return 0xff & _array[offset]; + } else { + if (offset >= _array.length) { + return -1; + } + if (offset + length! > _array.length) { + length = (_array.length - offset).toSigned(32); + } + List.copyRange(bytes, off!, _array, offset, offset + length); + return length; + } + } +} + +class _WindowRandom implements IRandom { + _WindowRandom(IRandom source, int offset, int length) { + _source = source; + _offset = offset; + _length = length; + } + //Fields + late IRandom _source; + late int _offset; + int? _length; + //Properties + @override + int? get length => _length; + //Implementation + @override + int? getValue(int position, [List? bytes, int? off, int? len]) { + if (position >= _length!) { + return -1; + } + if (bytes == null) { + return _source.getValue(_offset + position); + } else { + final int toRead = min(len!, _length! - position); + return _source.getValue(_offset + position, bytes, off, toRead); + } + } +} + +class _RandomGroup implements IRandom { + _RandomGroup(List sources) { + _sources = <_SourceEntry>[]; + int totalSize = 0; + int i = 0; + sources.toList().forEach((IRandom? ras) { + _sources.add(_SourceEntry(i, ras!, totalSize)); + ++i; + totalSize += ras.length!; + }); + _size = totalSize; + _cse = _sources[sources.length - 1]; + } + //Fields + late List<_SourceEntry> _sources; + _SourceEntry? _cse; + int? _size; + //Properties + @override + int? get length => _size; + //Implementation + @override + int getValue(int position, [List? bytes, int? off, int? len]) { + _SourceEntry? entry = getEntry(position); + if (entry == null) { + return -1; + } + int offN = entry.offsetN(position); + int? remaining = len; + bool isContinue = true; + while (isContinue && remaining! > 0) { + if (entry == null || offN > entry._source.length!) { + isContinue = false; + } else { + final int? count = entry._source.getValue(offN, bytes, off, remaining); + if (count == -1) { + isContinue = false; + } else { + off = off! + count!; + position += count; + remaining -= count; + offN = 0; + entry = getEntry(position); + } + } + } + return remaining == len ? -1 : len! - remaining!; + } + + int? getStartIndex(int offset) { + if (offset >= _cse!._startByte) { + return _cse!._index; + } + return 0; + } + + _SourceEntry? getEntry(int offset) { + if (offset >= _size!) { + return null; + } + if (offset >= _cse!._startByte && offset <= _cse!._endByte) { + return _cse; + } + final int startAt = getStartIndex(offset)!; + for (int i = startAt; i < _sources.length; i++) { + if (offset >= _sources[i]._startByte && offset <= _sources[i]._endByte) { + _cse = _sources[i]; + return _cse; + } + } + return null; + } +} + +class _SourceEntry { + _SourceEntry(int index, IRandom source, int offset) { + _index = index; + _source = source; + _startByte = offset; + _endByte = offset + source.length! - 1; + } + //Fields + late IRandom _source; + late int _startByte; + late int _endByte; + int? _index; + //Implementation + int offsetN(int absoluteOffset) { + return absoluteOffset - _startByte; + } +} + +class _RandomStream extends PdfStreamReader { + _RandomStream(IRandom source) + : super(List.generate(source.length!, (int i) => 0)) { + _random = source; + } + //Fields + late IRandom _random; + @override + int position = 0; + //Properties + @override + int? get length => _random.length; + + //Implementation + @override + int? read(List buffer, int offset, int length) { + final int? count = _random.getValue(position, buffer, offset, length); + if (count == -1) { + return 0; + } + position += count!; + return count; + } + + @override + int readByte() { + final int c = _random.getValue(position)!; + if (c >= 0) { + ++position; + } + return c; + } +} + +class _RmdSigner implements ISigner { + _RmdSigner(String digest) { + _digest = getDigest(digest); + _output = AccumulatorSink(); + _input = _digest.startChunkedConversion(_output); + _rsaEngine = Pkcs1Encoding(RsaAlgorithm()); + _id = Algorithms(map![digest], DerNull.value); + } + Map? _map; + late ICipherBlock _rsaEngine; + Algorithms? _id; + late dynamic _digest; + late dynamic _output; + dynamic _input; + late bool _isSigning; + //Properties + Map? get map { + if (_map == null) { + _map = {}; + _map![DigestAlgorithms.sha1] = X509Objects.idSha1; + _map![DigestAlgorithms.sha256] = NistObjectIds.sha256; + _map![DigestAlgorithms.sha384] = NistObjectIds.sha384; + _map![DigestAlgorithms.sha512] = NistObjectIds.sha512; + } + return _map; + } + + dynamic getDigest(String digest) { + dynamic result; + if (digest == DigestAlgorithms.sha1) { + result = sha1; + } else if (digest == DigestAlgorithms.sha256) { + result = sha256; + } else if (digest == DigestAlgorithms.sha384) { + result = sha384; + } else if (digest == DigestAlgorithms.sha512) { + result = sha512; + } else { + throw ArgumentError.value(digest, 'digest', 'Invalid digest'); + } + return result; + } + + @override + void initialize(bool isSigning, ICipherParameter? parameters) { + _isSigning = isSigning; + final CipherParameter? k = parameters as CipherParameter?; + if (isSigning && !k!.isPrivate!) { + throw ArgumentError.value('Private key required.'); + } + if (!isSigning && k!.isPrivate!) { + throw ArgumentError.value('Public key required.'); + } + reset(); + _rsaEngine.initialize(isSigning, parameters); + } + + @override + void blockUpdate(List input, int inOff, int length) { + _input.add(input.sublist(inOff, inOff + length)); + } + + @override + List? generateSignature() { + if (!_isSigning) { + throw ArgumentError.value('Invalid entry'); + } + _input.close(); + final List? hash = _output.events.single.bytes as List?; + final List data = derEncode(hash)!; + return _rsaEngine.processBlock(data, 0, data.length); + } + + @override + bool validateSignature(List signature) { + if (_isSigning) { + throw Exception('Invalid entry'); + } + _input.close(); + final List? hash = _output.events.single.bytes as List?; + List sig; + List expected; + try { + sig = _rsaEngine.processBlock(signature, 0, signature.length)!; + expected = derEncode(hash)!; + } catch (e) { + return false; + } + if (sig.length == expected.length) { + for (int i = 0; i < sig.length; i++) { + if (sig[i] != expected[i]) { + return false; + } + } + } else if (sig.length == expected.length - 2) { + final int sigOffset = sig.length - hash!.length - 2; + final int expectedOffset = expected.length - hash.length - 2; + expected[1] -= 2; + expected[3] -= 2; + for (int i = 0; i < hash.length; i++) { + if (sig[sigOffset + i] != expected[expectedOffset + i]) { + return false; + } + } + for (int i = 0; i < sigOffset; i++) { + if (sig[i] != expected[i]) { + return false; + } + } + } else { + return false; + } + return true; + } + + List? derEncode(List? hash) { + if (_id == null) { + return hash; + } + return DigestInformation(_id, hash).getDerEncoded(); + } + + @override + void reset() { + _output = AccumulatorSink(); + _input = _digest.startChunkedConversion(_output); + } +} + +// ignore: avoid_classes_with_only_static_members +/// internal class +class NistObjectIds { + // ignore: public_member_api_docs + static DerObjectID nistAlgorithm = DerObjectID('2.16.840.1.101.3.4'); + // ignore: public_member_api_docs + static DerObjectID hashAlgs = DerObjectID('${nistAlgorithm.id!}.2'); + // ignore: public_member_api_docs + static DerObjectID sha256 = DerObjectID('${hashAlgs.id!}.1'); + // ignore: public_member_api_docs + static DerObjectID sha384 = DerObjectID('${hashAlgs.id!}.2'); + // ignore: public_member_api_docs + static DerObjectID sha512 = DerObjectID('${hashAlgs.id!}.3'); + // ignore: public_member_api_docs + static DerObjectID dsaWithSHA2 = DerObjectID('${nistAlgorithm.id!}.3'); + // ignore: public_member_api_docs + static DerObjectID dsaWithSHA256 = DerObjectID('${dsaWithSHA2.id!}.2'); + // ignore: public_member_api_docs + static DerObjectID tttAlgorithm = DerObjectID('1.3.36.3'); + // ignore: public_member_api_docs + static DerObjectID ripeMD160 = DerObjectID('${tttAlgorithm.id!}.2.1'); + // ignore: public_member_api_docs + static DerObjectID tttRsaSignatureAlgorithm = DerObjectID( + '${tttAlgorithm.id!}.3.1', + ); + // ignore: public_member_api_docs + static DerObjectID rsaSignatureWithRipeMD160 = DerObjectID( + '${tttRsaSignatureAlgorithm.id!}.2', + ); +} + +/// internal type definition +typedef DocumentSavedHandler = + void Function(Object sender, DocumentSavedArgs args); + +/// internal type definition +typedef DocumentSavedHandlerAsync = + Future Function(Object sender, DocumentSavedArgs args); + +/// internal class +class DocumentSavedArgs { + /// internal constructor + DocumentSavedArgs(IPdfWriter writer) { + _writer = writer; + } + + //Fields + IPdfWriter? _writer; + + //Properties + /// internal property + IPdfWriter? get writer => _writer; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/password_utility.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/password_utility.dart index fb821eefc..0f7babf8d 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/password_utility.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/password_utility.dart @@ -1,25 +1,25 @@ -import '../cryptography/cipher_block_chaining_mode.dart'; - -/// internal class -class KeyEntry { - /// internal constructor - KeyEntry(this.key); - - /// internal field - CipherParameter? key; - - //Implementation - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters - bool operator ==(Object obj) { - if (obj is KeyEntry) { - return key == obj.key; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => key.hashCode; -} +import '../cryptography/cipher_block_chaining_mode.dart'; + +/// internal class +class KeyEntry { + /// internal constructor + KeyEntry(this.key); + + /// internal field + CipherParameter? key; + + //Implementation + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes, avoid_renaming_method_parameters + bool operator ==(Object obj) { + if (obj is KeyEntry) { + return key == obj.key; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => key.hashCode; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/pfx_data.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/pfx_data.dart index bbd6aea3d..a0147c04b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/pfx_data.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/pkcs/pfx_data.dart @@ -1,246 +1,246 @@ -import '../asn1/asn1.dart'; -import '../asn1/der.dart'; - -/// internal class -class Algorithms extends Asn1Encode { - /// internal constructor - Algorithms(this.id, [Asn1Encode? parameters]) { - if (parameters != null) { - this.parameters = parameters; - _parametersDefined = true; - } - } - - /// internal constructor - Algorithms.fromAsn1Sequence(Asn1Identifier id, Asn1 asn1) { - _sequence = Asn1Sequence(); - _sequence.objects!.add(id); - _sequence.objects!.add(asn1); - } - - /// internal constructor - Algorithms.fromSequence(Asn1Sequence sequence) { - if (sequence.count < 1 || sequence.count > 2) { - throw ArgumentError.value('Invalid length in sequence'); - } - id = DerObjectID.getID(sequence[0]); - _parametersDefined = sequence.count == 2; - if (_parametersDefined) { - parameters = sequence[1] as Asn1Encode?; - } - } - - /// internal method - static Algorithms? getAlgorithms(dynamic obj) { - if (obj == null || obj is Algorithms) { - return obj as Algorithms?; - } - if (obj is DerObjectID) { - return Algorithms(obj); - } - if (obj is String) { - return Algorithms(DerObjectID(obj)); - } - return Algorithms.fromSequence(Asn1Sequence.getSequence(obj)!); - } - - late Asn1Sequence _sequence; - bool _parametersDefined = false; - - /// internal field - DerObjectID? id; - - /// internal field - Asn1Encode? parameters; - - //Implementation - /// internal method - List? asnEncode() { - return _sequence.asnEncode(); - } - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection([ - id, - ]); - if (_parametersDefined) { - collection.encodableObjects.add(parameters ?? DerNull.value); - } - return DerSequence(collection: collection); - } -} - -/// internal class -class DigestInformation extends Asn1Encode { - /// internal constructor - DigestInformation(Algorithms? algorithms, List? bytes) { - _bytes = bytes; - _algorithms = algorithms; - } - - /// internal constructor - DigestInformation.fromSequence(Asn1Sequence sequence) { - if (sequence.count != 2) { - throw ArgumentError.value('Invalid length in sequence'); - } - _algorithms = Algorithms.getAlgorithms(sequence[0]); - _bytes = Asn1Octet.getOctetStringFromObject(sequence[1])!.getOctets(); - } - - //Fields - Algorithms? _algorithms; - List? _bytes; - - /// internal method - static DigestInformation getDigestInformation(dynamic obj) { - DigestInformation result; - if (obj is DigestInformation) { - result = obj; - } else if (obj is Asn1Sequence) { - result = DigestInformation.fromSequence(obj); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - return result; - } - - @override - Asn1 getAsn1() { - return DerSequence(array: [_algorithms, DerOctet(_bytes!)]); - } -} - -// ignore: avoid_classes_with_only_static_members -/// internal class -class PkcsObjectId { - /// internal field - static const String pkcs1 = '1.2.840.113549.1.1'; - - /// internal field - static const String encryptionAlgorithm = '1.2.840.113549.3'; - - /// internal field - static const String pkcs7 = '1.2.840.113549.1.7'; - - /// internal field - static const String pkcs9 = '1.2.840.113549.1.9'; - - /// internal field - static const String pkcs12 = '1.2.840.113549.1.12'; - - /// internal field - static const String bagTypes = '$pkcs12.10.1'; - - /// internal field - static const String pkcs12PbeIds = '$pkcs12.1'; - - /// internal field - static const String messageDigestAlgorithm = '1.2.840.113549.2'; - - /// internal field - static DerObjectID rsaEncryption = DerObjectID('$pkcs1.1'); - - /// internal field - static DerObjectID md2WithRsaEncryption = DerObjectID('$pkcs1.2'); - - /// internal field - static DerObjectID sha1WithRsaEncryption = DerObjectID('$pkcs1.5'); - - /// internal field - static DerObjectID sha256WithRsaEncryption = DerObjectID('$pkcs1.11'); - - /// internal field - static DerObjectID sha384WithRsaEncryption = DerObjectID('$pkcs1.12'); - - /// internal field - static DerObjectID sha512WithRsaEncryption = DerObjectID('$pkcs1.13'); - - /// internal field - static DerObjectID desEde3Cbc = DerObjectID('$encryptionAlgorithm.7'); - - /// internal field - static DerObjectID rc2Cbc = DerObjectID('$encryptionAlgorithm.2'); - - /// internal field - static DerObjectID data = DerObjectID('$pkcs7.1'); - - /// internal field - static DerObjectID signedData = DerObjectID('$pkcs7.2'); - - /// internal field - static DerObjectID encryptedData = DerObjectID('$pkcs7.6'); - - /// internal field - static DerObjectID pkcs9AtEmailAddress = DerObjectID('$pkcs9.1'); - - /// internal field - static DerObjectID pkcs9AtUnstructuredName = DerObjectID('$pkcs9.2'); - - /// internal field - static DerObjectID pkcs9AtUnstructuredAddress = DerObjectID('$pkcs9.8'); - - /// internal field - static DerObjectID pkcs9AtFriendlyName = DerObjectID('$pkcs9.20'); - - /// internal field - static DerObjectID pkcs9AtLocalKeyID = DerObjectID('$pkcs9.21'); - - /// internal field - static DerObjectID keyBag = DerObjectID('$bagTypes.1'); - - /// internal field - static DerObjectID pkcs8ShroudedKeyBag = DerObjectID('$bagTypes.2'); - - /// internal field - static DerObjectID certBag = DerObjectID('$bagTypes.3'); - - /// internal field - static DerObjectID pbeWithShaAnd128BitRC4 = DerObjectID('$pkcs12PbeIds.1'); - - /// internal field - static DerObjectID pbeWithShaAnd40BitRC4 = DerObjectID('$pkcs12PbeIds.2'); - - /// internal field - static DerObjectID pbeWithShaAnd3KeyTripleDesCbc = DerObjectID( - '$pkcs12PbeIds.3', - ); - - /// internal field - static DerObjectID pbeWithShaAnd2KeyTripleDesCbc = DerObjectID( - '$pkcs12PbeIds.4', - ); - - /// internal field - static DerObjectID pbeWithShaAnd128BitRC2Cbc = DerObjectID('$pkcs12PbeIds.5'); - - /// internal field - static DerObjectID pbewithShaAnd40BitRC2Cbc = DerObjectID('$pkcs12PbeIds.6'); - - /// internal field - static DerObjectID idAlgCms3DesWrap = DerObjectID( - '1.2.840.113549.1.9.16.3.6', - ); - - /// internal field - static DerObjectID idAlgCmsRC2Wrap = DerObjectID('1.2.840.113549.1.9.16.3.7'); - - /// internal field - static DerObjectID md5 = DerObjectID('${messageDigestAlgorithm}5'); -} - -// ignore: avoid_classes_with_only_static_members -/// internal class -class X509Objects { - /// internal field - static const String id = '2.5.4'; - - /// internal field - static DerObjectID telephoneNumberID = DerObjectID('$id.20'); - - /// internal field - static DerObjectID idSha1 = DerObjectID('1.3.14.3.2.26'); - - /// internal field - static DerObjectID idEARsa = DerObjectID('2.5.8.1.1'); -} +import '../asn1/asn1.dart'; +import '../asn1/der.dart'; + +/// internal class +class Algorithms extends Asn1Encode { + /// internal constructor + Algorithms(this.id, [Asn1Encode? parameters]) { + if (parameters != null) { + this.parameters = parameters; + _parametersDefined = true; + } + } + + /// internal constructor + Algorithms.fromAsn1Sequence(Asn1Identifier id, Asn1 asn1) { + _sequence = Asn1Sequence(); + _sequence.objects!.add(id); + _sequence.objects!.add(asn1); + } + + /// internal constructor + Algorithms.fromSequence(Asn1Sequence sequence) { + if (sequence.count < 1 || sequence.count > 2) { + throw ArgumentError.value('Invalid length in sequence'); + } + id = DerObjectID.getID(sequence[0]); + _parametersDefined = sequence.count == 2; + if (_parametersDefined) { + parameters = sequence[1] as Asn1Encode?; + } + } + + /// internal method + static Algorithms? getAlgorithms(dynamic obj) { + if (obj == null || obj is Algorithms) { + return obj as Algorithms?; + } + if (obj is DerObjectID) { + return Algorithms(obj); + } + if (obj is String) { + return Algorithms(DerObjectID(obj)); + } + return Algorithms.fromSequence(Asn1Sequence.getSequence(obj)!); + } + + late Asn1Sequence _sequence; + bool _parametersDefined = false; + + /// internal field + DerObjectID? id; + + /// internal field + Asn1Encode? parameters; + + //Implementation + /// internal method + List? asnEncode() { + return _sequence.asnEncode(); + } + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection([ + id, + ]); + if (_parametersDefined) { + collection.encodableObjects.add(parameters ?? DerNull.value); + } + return DerSequence(collection: collection); + } +} + +/// internal class +class DigestInformation extends Asn1Encode { + /// internal constructor + DigestInformation(Algorithms? algorithms, List? bytes) { + _bytes = bytes; + _algorithms = algorithms; + } + + /// internal constructor + DigestInformation.fromSequence(Asn1Sequence sequence) { + if (sequence.count != 2) { + throw ArgumentError.value('Invalid length in sequence'); + } + _algorithms = Algorithms.getAlgorithms(sequence[0]); + _bytes = Asn1Octet.getOctetStringFromObject(sequence[1])!.getOctets(); + } + + //Fields + Algorithms? _algorithms; + List? _bytes; + + /// internal method + static DigestInformation getDigestInformation(dynamic obj) { + DigestInformation result; + if (obj is DigestInformation) { + result = obj; + } else if (obj is Asn1Sequence) { + result = DigestInformation.fromSequence(obj); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + return result; + } + + @override + Asn1 getAsn1() { + return DerSequence(array: [_algorithms, DerOctet(_bytes!)]); + } +} + +// ignore: avoid_classes_with_only_static_members +/// internal class +class PkcsObjectId { + /// internal field + static const String pkcs1 = '1.2.840.113549.1.1'; + + /// internal field + static const String encryptionAlgorithm = '1.2.840.113549.3'; + + /// internal field + static const String pkcs7 = '1.2.840.113549.1.7'; + + /// internal field + static const String pkcs9 = '1.2.840.113549.1.9'; + + /// internal field + static const String pkcs12 = '1.2.840.113549.1.12'; + + /// internal field + static const String bagTypes = '$pkcs12.10.1'; + + /// internal field + static const String pkcs12PbeIds = '$pkcs12.1'; + + /// internal field + static const String messageDigestAlgorithm = '1.2.840.113549.2'; + + /// internal field + static DerObjectID rsaEncryption = DerObjectID('$pkcs1.1'); + + /// internal field + static DerObjectID md2WithRsaEncryption = DerObjectID('$pkcs1.2'); + + /// internal field + static DerObjectID sha1WithRsaEncryption = DerObjectID('$pkcs1.5'); + + /// internal field + static DerObjectID sha256WithRsaEncryption = DerObjectID('$pkcs1.11'); + + /// internal field + static DerObjectID sha384WithRsaEncryption = DerObjectID('$pkcs1.12'); + + /// internal field + static DerObjectID sha512WithRsaEncryption = DerObjectID('$pkcs1.13'); + + /// internal field + static DerObjectID desEde3Cbc = DerObjectID('$encryptionAlgorithm.7'); + + /// internal field + static DerObjectID rc2Cbc = DerObjectID('$encryptionAlgorithm.2'); + + /// internal field + static DerObjectID data = DerObjectID('$pkcs7.1'); + + /// internal field + static DerObjectID signedData = DerObjectID('$pkcs7.2'); + + /// internal field + static DerObjectID encryptedData = DerObjectID('$pkcs7.6'); + + /// internal field + static DerObjectID pkcs9AtEmailAddress = DerObjectID('$pkcs9.1'); + + /// internal field + static DerObjectID pkcs9AtUnstructuredName = DerObjectID('$pkcs9.2'); + + /// internal field + static DerObjectID pkcs9AtUnstructuredAddress = DerObjectID('$pkcs9.8'); + + /// internal field + static DerObjectID pkcs9AtFriendlyName = DerObjectID('$pkcs9.20'); + + /// internal field + static DerObjectID pkcs9AtLocalKeyID = DerObjectID('$pkcs9.21'); + + /// internal field + static DerObjectID keyBag = DerObjectID('$bagTypes.1'); + + /// internal field + static DerObjectID pkcs8ShroudedKeyBag = DerObjectID('$bagTypes.2'); + + /// internal field + static DerObjectID certBag = DerObjectID('$bagTypes.3'); + + /// internal field + static DerObjectID pbeWithShaAnd128BitRC4 = DerObjectID('$pkcs12PbeIds.1'); + + /// internal field + static DerObjectID pbeWithShaAnd40BitRC4 = DerObjectID('$pkcs12PbeIds.2'); + + /// internal field + static DerObjectID pbeWithShaAnd3KeyTripleDesCbc = DerObjectID( + '$pkcs12PbeIds.3', + ); + + /// internal field + static DerObjectID pbeWithShaAnd2KeyTripleDesCbc = DerObjectID( + '$pkcs12PbeIds.4', + ); + + /// internal field + static DerObjectID pbeWithShaAnd128BitRC2Cbc = DerObjectID('$pkcs12PbeIds.5'); + + /// internal field + static DerObjectID pbewithShaAnd40BitRC2Cbc = DerObjectID('$pkcs12PbeIds.6'); + + /// internal field + static DerObjectID idAlgCms3DesWrap = DerObjectID( + '1.2.840.113549.1.9.16.3.6', + ); + + /// internal field + static DerObjectID idAlgCmsRC2Wrap = DerObjectID('1.2.840.113549.1.9.16.3.7'); + + /// internal field + static DerObjectID md5 = DerObjectID('${messageDigestAlgorithm}5'); +} + +// ignore: avoid_classes_with_only_static_members +/// internal class +class X509Objects { + /// internal field + static const String id = '2.5.4'; + + /// internal field + static DerObjectID telephoneNumberID = DerObjectID('$id.20'); + + /// internal field + static DerObjectID idSha1 = DerObjectID('1.3.14.3.2.26'); + + /// internal field + static DerObjectID idEARsa = DerObjectID('2.5.8.1.1'); +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/time_stamp_server/time_stamp_server.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/time_stamp_server/time_stamp_server.dart index 23ec8b107..96bfc9541 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/time_stamp_server/time_stamp_server.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/time_stamp_server/time_stamp_server.dart @@ -1,116 +1,116 @@ -import 'dart:convert'; - -import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; - -import '../x509/ocsp_utils.dart'; - -/// Represent a timestamp to add in PDF document -/// -/// ```dart -/// //Creates a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Adds a new page -/// PdfPage page = document.pages.add(); -/// //Creates a digital signature and sets signature information -/// PdfSignatureField field = PdfSignatureField(page, 'signature', -/// bounds: Rect.fromLTWH(0, 0, 200, 100), -/// signature: PdfSignature( -/// //Creates a certificate instance from the PFX file with a private key -/// certificate: PdfCertificate( -/// File('D:/PDF.pfx').readAsBytesSync(), 'syncfusion'), -/// contactInfo: 'johndoe@owned.us', -/// locationInfo: 'Honolulu, Hawaii', -/// reason: 'I am author of this document.', -/// //Create a new PDF time stamp server -/// timestampServer: -/// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')))); -/// //Add a signature field to the form -/// document.form.fields.add(field); -/// //Save and dispose the PDF document -/// File('Output.pdf').writeAsBytes(await document.save()); -/// document.dispose(); -/// ``` -class TimestampServer { - /// Initialize a new instance of the [TimestampServer] class with timestamp server url. - /// - /// ```dart - /// //Creates a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Adds a new page - /// PdfPage page = document.pages.add(); - /// //Creates a digital signature and sets signature information - /// PdfSignatureField field = PdfSignatureField(page, 'signature', - /// bounds: Rect.fromLTWH(0, 0, 200, 100), - /// signature: PdfSignature( - /// //Creates a certificate instance from the PFX file with a private key - /// certificate: PdfCertificate( - /// File('D:/PDF.pfx').readAsBytesSync(), 'syncfusion'), - /// contactInfo: 'johndoe@owned.us', - /// locationInfo: 'Honolulu, Hawaii', - /// reason: 'I am author of this document.', - /// //Create a new PDF time stamp server - /// timestampServer: - /// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')))); - /// //Add a signature field to the form - /// document.form.fields.add(field); - /// //Save and dispose the PDF document - /// File('Output.pdf').writeAsBytes(await document.save()); - /// document.dispose(); - /// ``` - TimestampServer(this.uri, {this.userName, this.password, this.timeOut}); - - /// Gets or set the server uri. - Uri uri; - - /// Gets or set the user name. - String? userName; - - /// Gets or set the password. - String? password; - - /// Gets or set the time out duration. - Duration? timeOut; - - /// Gets a value indicating whether the time stamp url is valid. - /// - /// ```dart - /// //Create a new PDF time stamp server - /// TimestampServer server = - /// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')); - /// //Check whether the time stamp server is valid - /// bool isValid = await server.isValid; - /// ``` - Future get isValid => _isValidTimeStamp(); - - // Implementation. - Future _isValidTimeStamp() async { - bool isValid = false; - try { - final dynamic output = AccumulatorSink(); - final dynamic input = sha256.startChunkedConversion(output); - input.add(base64.decode('VABlAHMAdAAgAGQAYQB0AGEA')); //Test unicode data - input.close(); - final List hash = output.events.single.bytes as List; - final List asnEncodedTimestampRequest = TimeStampRequestCreator() - .getAsnEncodedTimestampRequest(hash); - final List? timeStampResponse = await fetchData( - uri, - 'POST', - contentType: 'application/timestamp-query', - userName: userName, - password: password, - data: asnEncodedTimestampRequest, - timeOutDuration: timeOut, - ); - if (timeStampResponse != null && timeStampResponse.length > 2) { - if (timeStampResponse[0] == 0x30 && timeStampResponse[1] == 0x82) { - isValid = true; - } - } - } catch (e) { - isValid = false; - } - return isValid; - } -} +import 'dart:convert'; + +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; + +import '../x509/ocsp_utils.dart'; + +/// Represent a timestamp to add in PDF document +/// +/// ```dart +/// //Creates a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Adds a new page +/// PdfPage page = document.pages.add(); +/// //Creates a digital signature and sets signature information +/// PdfSignatureField field = PdfSignatureField(page, 'signature', +/// bounds: Rect.fromLTWH(0, 0, 200, 100), +/// signature: PdfSignature( +/// //Creates a certificate instance from the PFX file with a private key +/// certificate: PdfCertificate( +/// File('D:/PDF.pfx').readAsBytesSync(), 'syncfusion'), +/// contactInfo: 'johndoe@owned.us', +/// locationInfo: 'Honolulu, Hawaii', +/// reason: 'I am author of this document.', +/// //Create a new PDF time stamp server +/// timestampServer: +/// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')))); +/// //Add a signature field to the form +/// document.form.fields.add(field); +/// //Save and dispose the PDF document +/// File('Output.pdf').writeAsBytes(await document.save()); +/// document.dispose(); +/// ``` +class TimestampServer { + /// Initialize a new instance of the [TimestampServer] class with timestamp server url. + /// + /// ```dart + /// //Creates a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Adds a new page + /// PdfPage page = document.pages.add(); + /// //Creates a digital signature and sets signature information + /// PdfSignatureField field = PdfSignatureField(page, 'signature', + /// bounds: Rect.fromLTWH(0, 0, 200, 100), + /// signature: PdfSignature( + /// //Creates a certificate instance from the PFX file with a private key + /// certificate: PdfCertificate( + /// File('D:/PDF.pfx').readAsBytesSync(), 'syncfusion'), + /// contactInfo: 'johndoe@owned.us', + /// locationInfo: 'Honolulu, Hawaii', + /// reason: 'I am author of this document.', + /// //Create a new PDF time stamp server + /// timestampServer: + /// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')))); + /// //Add a signature field to the form + /// document.form.fields.add(field); + /// //Save and dispose the PDF document + /// File('Output.pdf').writeAsBytes(await document.save()); + /// document.dispose(); + /// ``` + TimestampServer(this.uri, {this.userName, this.password, this.timeOut}); + + /// Gets or set the server uri. + Uri uri; + + /// Gets or set the user name. + String? userName; + + /// Gets or set the password. + String? password; + + /// Gets or set the time out duration. + Duration? timeOut; + + /// Gets a value indicating whether the time stamp url is valid. + /// + /// ```dart + /// //Create a new PDF time stamp server + /// TimestampServer server = + /// TimestampServer(Uri.parse('http://syncfusion.digistamp.com')); + /// //Check whether the time stamp server is valid + /// bool isValid = await server.isValid; + /// ``` + Future get isValid => _isValidTimeStamp(); + + // Implementation. + Future _isValidTimeStamp() async { + bool isValid = false; + try { + final dynamic output = AccumulatorSink(); + final dynamic input = sha256.startChunkedConversion(output); + input.add(base64.decode('VABlAHMAdAAgAGQAYQB0AGEA')); //Test unicode data + input.close(); + final List hash = output.events.single.bytes as List; + final List asnEncodedTimestampRequest = TimeStampRequestCreator() + .getAsnEncodedTimestampRequest(hash); + final List? timeStampResponse = await fetchData( + uri, + 'POST', + contentType: 'application/timestamp-query', + userName: userName, + password: password, + data: asnEncodedTimestampRequest, + timeOutDuration: timeOut, + ); + if (timeStampResponse != null && timeStampResponse.length > 2) { + if (timeStampResponse[0] == 0x30 && timeStampResponse[1] == 0x82) { + isValid = true; + } + } + } catch (e) { + isValid = false; + } + return isValid; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/ocsp_utils.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/ocsp_utils.dart index 282df90cc..8744b857b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/ocsp_utils.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/ocsp_utils.dart @@ -1,867 +1,867 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:math'; - -import 'package:convert/convert.dart'; -import 'package:crypto/crypto.dart'; -import 'package:http/http.dart' as http; - -import '../../../annotations/json_parser.dart'; -import '../../../io/stream_reader.dart'; -import '../asn1/asn1.dart'; -import '../asn1/asn1_stream.dart'; -import '../asn1/der.dart'; -import '../pdf_pkcs_certificate.dart'; -import '../pkcs/pfx_data.dart'; -import 'x509_certificates.dart'; -import 'x509_name.dart'; - -/// internal class -class Ocsp { - /// internal method - Future?> getEncodedOcspResponse( - X509Certificate? checkCertificate, - X509Certificate? rootCertificate, - ) async { - final OcspResponseHelper? helper = await getOcspResponse( - checkCertificate, - rootCertificate, - ); - if (helper != null) { - return helper.getResponseBytes(); - } - return null; - } - - /// internal method - Future getOcspResponse( - X509Certificate? checkCertificate, - X509Certificate? rootCertificate, - ) async { - if (checkCertificate == null || rootCertificate == null) { - return null; - } - final CertificateUtililty utility = CertificateUtililty(); - final String? url = utility.getOcspUrl(checkCertificate); - if (url == null) { - return null; - } - final OcspRequestHelper request = generateOcspRequest( - rootCertificate, - checkCertificate.c!.serialNumber!, - ); - final List? requestBody = request.getEncoded(); - if (requestBody != null) { - final List? data = await fetchData( - url, - 'POST', - data: requestBody, - contentType: 'application/ocsp-request', - timeOutDuration: const Duration(milliseconds: 5000), - ); - if (data != null) { - return OcspResponseHelper(data); - } - } - return null; - } - - /// internal method - OcspRequestHelper generateOcspRequest( - X509Certificate issuerCertificate, - DerInteger serialNumber, - ) { - final CertificateIdentity id = CertificateIdentity( - CertificateIdentity.sha1, - issuerCertificate, - serialNumber, - ); - final OcspRequestCreator requestCreator = OcspRequestCreator(); - requestCreator.addRequest(id); - final Map extensions = - {}; - extensions[OcspConstants.ocspNonce] = X509Extension( - false, - DerOctet(DerOctet(createDocumentId()).getEncoded()!), - ); - requestCreator.requestExtensions = X509Extensions(extensions); - return requestCreator.createRequest(); - } - - /// internal method - List createDocumentId() { - int time = - DateTime.now().microsecondsSinceEpoch + DateTime.now().millisecond; - final int random = 1000000 + Random().nextInt(9999999 - 1000000); - final List b = utf8.encode('$time+$random+${time++}'); - final dynamic output = AccumulatorSink(); - final dynamic input = md5.startChunkedConversion(output); - input.add(b); - input.close(); - final List hash = output.events.single.bytes as List; - return hash; - } -} - -/// Internal class -class RevocationList { - /// Internal method - Future>> getEncoded(X509Certificate certificate) async { - List? urls; - try { - final CertificateUtililty utility = CertificateUtililty(); - urls = utility.getCrlUrls(certificate); - } catch (ex) { - // - } - final List> byteList = >[]; - if (urls != null) { - List? data; - for (final String entry in urls) { - try { - data = await fetchData( - entry, - 'GET', - timeOutDuration: const Duration(milliseconds: 5000), - ); - } catch (e) { - // - } - if (data != null) { - byteList.add(data); - } - } - } - return byteList; - } -} - -/// Internal class -class RevocationPointList extends Asn1Encode { - /// Internal constructor. - RevocationPointList([Asn1Sequence? sequence]) { - if (sequence != null) { - _sequence = sequence; - } - } - - /// Internal field - Asn1Sequence? _sequence; - - /// Internal method - List getDistributionPoints() { - final List distributions = - []; - if (_sequence != null) { - final RevocationDistribution distribution = RevocationDistribution(); - for (int i = 0; i != _sequence!.count; ++i) { - distributions.add(distribution.getCrlDistribution(_sequence![i])!); - } - } - return distributions; - } - - /// Internal method - RevocationPointList getCrlPointList(dynamic obj) { - if (obj is RevocationPointList || obj == null) { - return obj; - } - if (obj is Asn1Sequence) { - return RevocationPointList(obj); - } - throw Exception('Invalid entry in sequence'); - } - - @override - Asn1 getAsn1() { - return _sequence!; - } -} - -/// Internal class -class RevocationDistribution extends Asn1Encode { - /// Internal constructor. - RevocationDistribution([Asn1Sequence? sequence]) { - if (sequence != null) { - for (int i = 0; i != sequence.count; i++) { - final Asn1Tag? tag = Asn1Tag.getTag(sequence[i]); - if (tag != null) { - switch (tag.tagNumber) { - case 0: - final RevocationDistributionType type = - RevocationDistributionType(); - distributionPoint = type.getDistributionType(tag, true); - break; - case 2: - final RevocationName name = RevocationName(); - _issuer = name.getCrlName(tag, false); - break; - } - } - } - } - } - - /// Internal field - RevocationDistributionType? distributionPoint; - RevocationName? _issuer; - - /// Internal method - RevocationDistribution? getCrlDistribution(dynamic obj) { - if (obj == null || obj is RevocationDistribution) { - return obj; - } - if (obj is Asn1Sequence) { - return RevocationDistribution(obj); - } - throw Exception('Invalid entry in CRL distribution point'); - } - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection(); - if (distributionPoint != null) { - collection.add([DerTag(0, distributionPoint)]); - } - if (_issuer != null) { - collection.add([DerTag(2, _issuer, false)]); - } - return DerSequence(collection: collection); - } -} - -/// Internal class -class RevocationDistributionType extends Asn1Encode { - /// Internal constructor. - RevocationDistributionType([Asn1Tag? tag]) { - if (tag != null) { - type = tag.tagNumber; - if (type == fullName) { - final RevocationName crl = RevocationName(); - name = crl.getCrlName(tag, false); - } else { - name = Asn1Set.getAsn1Set(tag, false); - } - } - } - - /// Internal field - Asn1Encode? name; - - /// Internal fields - int? type; - - /// Internal constants - static const int fullName = 0; - - /// Internal method - RevocationDistributionType? getDistributionType( - Asn1Tag tag, - bool isExplicit, - ) { - return getDistributionTypeFromObj(Asn1Tag.getTag(tag, true)); - } - - /// Internal method - RevocationDistributionType? getDistributionTypeFromObj(dynamic obj) { - if (obj == null || obj is RevocationDistributionType) { - return obj; - } - if (obj is Asn1Tag) { - return RevocationDistributionType(obj); - } - throw Exception('Invalid entry in sequence'); - } - - @override - Asn1 getAsn1() { - return DerTag(type, name, false); - } -} - -/// Internal class -class RevocationName extends Asn1Encode { - /// Internal constructor. - RevocationName([Asn1Sequence? sequence]) { - if (sequence != null) { - names = []; - for (int i = 0; i != sequence.count; i++) { - final OcspTag name = OcspTag(); - names!.add(name.getOcspName(sequence[i])!); - } - } - } - - /// Internal field - List? names; - - /// Internal method - RevocationName? getCrlNameFromObj(dynamic obj) { - if (obj == null || obj is RevocationName) { - return obj; - } - if (obj is Asn1Sequence) { - return RevocationName(obj); - } - throw Exception('Invalid entry in sequence'); - } - - /// Internal method - RevocationName? getCrlName(Asn1Tag tag, bool isExplicit) { - return getCrlNameFromObj(Asn1Sequence.getSequence(tag, isExplicit)); - } - - @override - Asn1 getAsn1() { - return DerSequence(array: names); - } -} - -/// Internal class -class OcspTag extends Asn1Encode { - /// Internal constructor. - OcspTag([int? tag, Asn1Encode? encode]) { - if (encode != null) { - _encode = encode; - } - if (tag != null) { - tagNumber = tag; - } - } - - /// Internal fields - Asn1Encode? _encode; - - /// Internal fields - int? tagNumber; - - /// Internal method - OcspTag? getOcspName(dynamic obj) { - if (obj == null || obj is OcspTag) { - return obj; - } - if (obj is Asn1Tag) { - final Asn1Tag tag = obj; - final int? tagNumber = obj.tagNumber; - if (tagNumber != null) { - switch (tagNumber) { - case 0: - return OcspTag(tagNumber, Asn1Sequence.getSequence(tag, false)); - case 1: - return OcspTag( - tagNumber, - DerAsciiString.getAsciiString(tag, false), - ); - case 2: - return OcspTag( - tagNumber, - DerAsciiString.getAsciiString(tag, false), - ); - case 3: - throw Exception('Invalid tag number specified: $tagNumber'); - case 4: - return OcspTag(tagNumber, X509Name.getName(tag, true)); - case 5: - return OcspTag(tagNumber, Asn1Sequence.getSequence(tag, false)); - case 6: - return OcspTag( - tagNumber, - DerAsciiString.getAsciiString(tag, false), - ); - case 7: - return OcspTag(tagNumber, Asn1Octet.getOctetString(tag, false)); - case 8: - return OcspTag(tagNumber, DerObjectID.getID(tag.getObject())); - } - } - } - if (obj is List) { - try { - return getOcspName(Asn1.fromByteArray(obj)); - } catch (e) { - throw Exception('Invalid OCSP name to parse'); - } - } - throw Exception('Invalid entry in sequence'); - } - - @override - Asn1 getAsn1() { - return DerTag(tagNumber, _encode, tagNumber == 4); - } -} - -/// internal class -class CertificateUtililty { - /// internal method - List? getCrlUrls(X509Certificate certificate) { - final List urls = []; - try { - final Asn1? obj = getExtensionValue( - certificate, - X509Extensions.crlDistributionPoints.id!, - ); - if (obj == null) { - return null; - } - final RevocationPointList list = RevocationPointList(); - final RevocationPointList distributionList = list.getCrlPointList(obj); - final List distributionLists = - distributionList.getDistributionPoints(); - for (final RevocationDistribution entry in distributionLists) { - final RevocationDistributionType? distributionPointName = - entry.distributionPoint; - if (distributionPointName != null) { - if (RevocationDistributionType.fullName != - distributionPointName.type) { - continue; - } - if (distributionPointName.name != null && - distributionPointName.name is RevocationName) { - final RevocationName generalNames = - distributionPointName.name! as RevocationName; - final List? names = generalNames.names; - if (names != null) { - for (final OcspTag name in names) { - if (name.tagNumber != 6) { - continue; - } - final DerAsciiString? asciiString = - DerAsciiString.getAsciiString( - name.getAsn1() as Asn1Tag, - false, - ); - if (asciiString != null) { - final String? url = asciiString.getString(); - if (url != null && url.toLowerCase().endsWith('.crl') || - !isNullOrEmpty(url)) { - urls.add(url!); - } - } - } - } - } - } - } - return urls; - } catch (ex) { - return null; - } - } - - /// internal method - String? getOcspUrl(X509Certificate certificate) { - try { - final Asn1? asn1 = getExtensionValue( - certificate, - X509Extensions.authorityInfoAccess.id!, - ); - if (asn1 == null) { - return null; - } - if (asn1 is Asn1Sequence) { - final Asn1Sequence sequence = asn1; - for (int i = 0; i < sequence.count; i++) { - final dynamic asn1Sequence = sequence.objects![i]; - if (asn1Sequence is Asn1Sequence) { - if (asn1Sequence.count != 2) { - continue; - } else { - if (asn1Sequence.objects![0] is DerObjectID && - (asn1Sequence.objects![0]! as DerObjectID).id == - '1.3.6.1.5.5.7.48.1') { - final dynamic obj = asn1Sequence.objects![1]; - if (obj is Asn1) { - final String? accessLocation = getStringFromGeneralName(obj); - if (accessLocation == null) { - return ''; - } else { - return accessLocation; - } - } - } - } - } - } - } - } catch (e) { - return null; - } - return null; - } - - /// internal method - Asn1? getExtensionValue(X509Certificate certificate, String id) { - List? bytes; - final Asn1Octet? extension = certificate.getExtension(DerObjectID(id)); - if (extension != null) { - bytes = extension.getDerEncoded(); - } - if (bytes == null) { - return null; - } - Asn1Stream asn1 = Asn1Stream(PdfStreamReader(bytes)); - final Asn1? octet = asn1.readAsn1(); - if (octet is Asn1Octet) { - asn1 = Asn1Stream(PdfStreamReader(octet.getOctets())); - } - return asn1.readAsn1(); - } - - /// internal method - String? getStringFromGeneralName(Asn1 names) { - if (names is Asn1Tag) { - final Asn1Octet? octet = Asn1Octet.getOctetString(names, false); - if (octet != null) { - final List? bytes = octet.getOctets(); - if (bytes != null) { - return utf8.decode(bytes); - } - } - } - return null; - } -} - -/// internal class -class OcspRequestCreator { - /// Internal constructor - OcspRequestCreator() { - _list = []; - } - - /// Internal field - late List _list; - - /// Internal field - X509Extensions? requestExtensions; - OcspTag? _requestorName; - - /// Internal method - void addRequest(CertificateIdentity id) { - _list.add(RequestCreatorHelper(id, null)); - } - - /// Internal method - OcspRequestHelper createRequest() { - final Asn1EncodeCollection requests = Asn1EncodeCollection(); - for (final dynamic reqObj in _list) { - try { - requests.add([(reqObj as RequestCreatorHelper).toRequest()]); - } catch (e) { - throw Exception('Invalid request creation'); - } - } - final OcspRequestCollection requestList = OcspRequestCollection( - _requestorName, - DerSequence(collection: requests), - requestExtensions!, - ); - return OcspRequestHelper(RevocationListRequest(requestList)); - } -} - -/// Internal class -class OcspRequestHelper extends X509ExtensionBase { - /// Internal constructor - OcspRequestHelper(this._request); - - /// Internal field - final RevocationListRequest _request; - - @override - X509Extensions? getX509Extensions() { - return null; - } - - /// Internal method - List? getEncoded() { - return _request.getEncoded(); - } -} - -/// Internal class -class OcspRequestCollection extends Asn1Encode { - /// Internal constructor - OcspRequestCollection( - this._requestorName, - this._requestList, - this._requestExtensions, - ) { - _version = DerInteger([0]); - versionSet = false; - } - - /// Internal fields - late DerInteger _version; - late final OcspTag? _requestorName; - late final Asn1Sequence _requestList; - late final X509Extensions _requestExtensions; - - /// Internal fields - late bool versionSet; - - ///Internal method - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection(); - if (!(_version == DerInteger([0])) || versionSet) { - collection.add([DerTag(0, _version, true)]); - } - if (_requestorName != null) { - collection.add([DerTag(1, _requestorName, true)]); - } - collection.add([_requestList]); - collection.add([DerTag(2, _requestExtensions, true)]); - return DerSequence(collection: collection); - } -} - -/// Internal class -class RevocationListRequest extends Asn1Encode { - /// Internal constructor - RevocationListRequest(this._requests); - - /// Internal field - late final OcspRequestCollection _requests; - - @override - Asn1 getAsn1() { - return DerSequence( - collection: Asn1EncodeCollection([_requests]), - ); - } -} - -/// Internal class -class OcspResponseHelper { - /// Internal constructor - OcspResponseHelper(List data) { - _response = OcspResponse( - Asn1Stream(PdfStreamReader(data)).readAsn1()! as Asn1Sequence, - ); - } - - /// Internal field - late OcspResponse _response; - - /// Internal method - List? getResponseBytes() { - final RevocationResponseBytes? bytes = _response.responseBytes; - if (bytes == null) { - return null; - } - if (bytes.responseType.id == OcspConstants.ocspBasic.id) { - try { - return bytes.response.getOctets(); - } catch (e) { - throw Exception('Invalid response detected'); - } - } - return null; - } -} - -/// Internal class -class OcspResponse extends Asn1Encode { - /// Internal constructor - OcspResponse(Asn1Sequence sequence) { - if (sequence.count == 2) { - responseBytes = RevocationResponseBytes().getResponseBytes( - sequence[1]! as Asn1Tag, - true, - ); - } - } - - /// Internal field - RevocationResponseBytes? responseBytes; - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection([ - DerCatalogue([0]), - ]); - if (responseBytes != null) { - collection.add([DerTag(0, responseBytes, true)]); - } - return DerSequence(collection: collection); - } -} - -/// Internal class -class RevocationResponseBytes extends Asn1Encode { - /// Internal constructor - RevocationResponseBytes([Asn1Sequence? sequence]) { - if (sequence != null) { - if (sequence.count != 2) { - ArgumentError.value(sequence, 'Invalid length in sequence'); - } - responseType = DerObjectID.getID(sequence[0])!; - response = Asn1Octet.getOctetStringFromObject(sequence[1])!; - } - } - - /// Internal field - late DerObjectID responseType; - - /// Internal field - late Asn1Octet response; - - /// Internal method - RevocationResponseBytes? getResponseBytes(Asn1Tag tag, bool isExplicit) { - return getResponseBytesFromObject( - Asn1Sequence.getSequence(tag, isExplicit), - ); - } - - /// Internal method - RevocationResponseBytes? getResponseBytesFromObject(dynamic obj) { - if (obj == null || obj is RevocationResponseBytes) { - return obj; - } else if (obj is Asn1Sequence) { - return RevocationResponseBytes(obj); - } - ArgumentError.checkNotNull(obj, 'Invalid entry in sequence'); - return null; - } - - @override - Asn1 getAsn1() { - return DerSequence(array: [responseType, response]); - } -} - -/// internal class -class RequestCreatorHelper { - /// internal constructor - RequestCreatorHelper(this._id, this._extensions); - - /// internal field - late final CertificateIdentity _id; - final X509Extensions? _extensions; - - /// internal method - RevocationRequest toRequest() { - return RevocationRequest(_id.id!, _extensions); - } -} - -/// internal class -class RevocationRequest extends Asn1Encode { - /// internal constructor - RevocationRequest(this._certificateID, this._singleRequestExtensions); - - /// internal field - late final CertificateIdentityHelper _certificateID; - final X509Extensions? _singleRequestExtensions; - - @override - Asn1 getAsn1() { - final Asn1EncodeCollection collection = Asn1EncodeCollection([ - _certificateID, - ]); - if (_singleRequestExtensions != null) { - collection.add([DerTag(0, _singleRequestExtensions, true)]); - } - return DerSequence(collection: collection); - } -} - -/// Internal class -class TimeStampRequestCreator extends Asn1 { - /// Internal field - static const String _idSHA256 = '2.16.840.1.101.3.4.2.1'; - - /// Internal method - List getAsnEncodedTimestampRequest(List hash) { - final Asn1Identifier digestAlgOid = Asn1Identifier(_idSHA256); - final Algorithms algID = Algorithms.fromAsn1Sequence( - digestAlgOid, - DerNull.value, - ); - final Asn1Sequence seq = Asn1Sequence(); - seq.objects!.add(algID); - seq.objects!.add(Asn1Octet(hash)); - final Asn1Sequence asn1Sequence = Asn1Sequence(); - asn1Sequence.objects!.add(Asn1Integer(1)); - asn1Sequence.objects!.add(seq); - asn1Sequence.objects!.add(Asn1Integer(100)); - asn1Sequence.objects!.add(Asn1Boolean(true)); - return asn1Sequence.asnEncode()!; - } - - @override - void encode(DerStream derOut) { - throw UnsupportedError('This functionality is not implemented yet.'); - } -} - -// ignore: avoid_classes_with_only_static_members -/// internal class -class OcspConstants { - /// internal field - static DerObjectID ocsp = DerObjectID('1.3.6.1.5.5.7.48.1'); - - /// internal field - static DerObjectID ocspBasic = DerObjectID('1.3.6.1.5.5.7.48.1.1'); - - /// internal field - static DerObjectID ocspNonce = DerObjectID('$ocsp.2'); - - /// internal field - static DerObjectID ocspCrl = DerObjectID('$ocsp.3'); - - /// internal field - static DerObjectID ocspResponse = DerObjectID('$ocsp.4'); - - /// internal field - static DerObjectID ocspNocheck = DerObjectID('$ocsp.5'); - - /// internal field - static DerObjectID ocspArchiveCutoff = DerObjectID('$ocsp.6'); - - /// internal field - static DerObjectID ocspServiceLocator = DerObjectID('$ocsp.7'); -} - -/// Send the data to the server and get the response. -Future?> fetchData( - dynamic uri, - String method, { - String? contentType, - String? userName, - String? password, - List? data, - Duration? timeOutDuration, -}) async { - final http.Client client = http.Client(); - try { - if (uri is String) { - uri = Uri.parse(uri); - } - final http.Request request = http.Request(method, uri as Uri); - if (contentType != null) { - request.headers.addAll({'Content-Type': contentType}); - } - if (password != null && userName != null) { - request.headers.addAll({ - 'Authorization': - 'Basic ${base64Encode(utf8.encode('$userName:$password'))}', - }); - } - if (data != null) { - request.bodyBytes = data; - } - final http.StreamedResponse response = - await ((timeOutDuration != null) - ? client.send(request).timeout(timeOutDuration) - : client.send(request)); - final List responseBytes = await response.stream.toBytes(); - return (response.statusCode == 200) ? responseBytes : null; - } catch (e) { - return null; - } finally { - client.close(); - } -} +import 'dart:async'; +import 'dart:convert'; +import 'dart:math'; + +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart'; +import 'package:http/http.dart' as http; + +import '../../../annotations/json_parser.dart'; +import '../../../io/stream_reader.dart'; +import '../asn1/asn1.dart'; +import '../asn1/asn1_stream.dart'; +import '../asn1/der.dart'; +import '../pdf_pkcs_certificate.dart'; +import '../pkcs/pfx_data.dart'; +import 'x509_certificates.dart'; +import 'x509_name.dart'; + +/// internal class +class Ocsp { + /// internal method + Future?> getEncodedOcspResponse( + X509Certificate? checkCertificate, + X509Certificate? rootCertificate, + ) async { + final OcspResponseHelper? helper = await getOcspResponse( + checkCertificate, + rootCertificate, + ); + if (helper != null) { + return helper.getResponseBytes(); + } + return null; + } + + /// internal method + Future getOcspResponse( + X509Certificate? checkCertificate, + X509Certificate? rootCertificate, + ) async { + if (checkCertificate == null || rootCertificate == null) { + return null; + } + final CertificateUtililty utility = CertificateUtililty(); + final String? url = utility.getOcspUrl(checkCertificate); + if (url == null) { + return null; + } + final OcspRequestHelper request = generateOcspRequest( + rootCertificate, + checkCertificate.c!.serialNumber!, + ); + final List? requestBody = request.getEncoded(); + if (requestBody != null) { + final List? data = await fetchData( + url, + 'POST', + data: requestBody, + contentType: 'application/ocsp-request', + timeOutDuration: const Duration(milliseconds: 5000), + ); + if (data != null) { + return OcspResponseHelper(data); + } + } + return null; + } + + /// internal method + OcspRequestHelper generateOcspRequest( + X509Certificate issuerCertificate, + DerInteger serialNumber, + ) { + final CertificateIdentity id = CertificateIdentity( + CertificateIdentity.sha1, + issuerCertificate, + serialNumber, + ); + final OcspRequestCreator requestCreator = OcspRequestCreator(); + requestCreator.addRequest(id); + final Map extensions = + {}; + extensions[OcspConstants.ocspNonce] = X509Extension( + false, + DerOctet(DerOctet(createDocumentId()).getEncoded()!), + ); + requestCreator.requestExtensions = X509Extensions(extensions); + return requestCreator.createRequest(); + } + + /// internal method + List createDocumentId() { + int time = + DateTime.now().microsecondsSinceEpoch + DateTime.now().millisecond; + final int random = 1000000 + Random().nextInt(9999999 - 1000000); + final List b = utf8.encode('$time+$random+${time++}'); + final dynamic output = AccumulatorSink(); + final dynamic input = md5.startChunkedConversion(output); + input.add(b); + input.close(); + final List hash = output.events.single.bytes as List; + return hash; + } +} + +/// Internal class +class RevocationList { + /// Internal method + Future>> getEncoded(X509Certificate certificate) async { + List? urls; + try { + final CertificateUtililty utility = CertificateUtililty(); + urls = utility.getCrlUrls(certificate); + } catch (ex) { + // + } + final List> byteList = >[]; + if (urls != null) { + List? data; + for (final String entry in urls) { + try { + data = await fetchData( + entry, + 'GET', + timeOutDuration: const Duration(milliseconds: 5000), + ); + } catch (e) { + // + } + if (data != null) { + byteList.add(data); + } + } + } + return byteList; + } +} + +/// Internal class +class RevocationPointList extends Asn1Encode { + /// Internal constructor. + RevocationPointList([Asn1Sequence? sequence]) { + if (sequence != null) { + _sequence = sequence; + } + } + + /// Internal field + Asn1Sequence? _sequence; + + /// Internal method + List getDistributionPoints() { + final List distributions = + []; + if (_sequence != null) { + final RevocationDistribution distribution = RevocationDistribution(); + for (int i = 0; i != _sequence!.count; ++i) { + distributions.add(distribution.getCrlDistribution(_sequence![i])!); + } + } + return distributions; + } + + /// Internal method + RevocationPointList getCrlPointList(dynamic obj) { + if (obj is RevocationPointList || obj == null) { + return obj; + } + if (obj is Asn1Sequence) { + return RevocationPointList(obj); + } + throw Exception('Invalid entry in sequence'); + } + + @override + Asn1 getAsn1() { + return _sequence!; + } +} + +/// Internal class +class RevocationDistribution extends Asn1Encode { + /// Internal constructor. + RevocationDistribution([Asn1Sequence? sequence]) { + if (sequence != null) { + for (int i = 0; i != sequence.count; i++) { + final Asn1Tag? tag = Asn1Tag.getTag(sequence[i]); + if (tag != null) { + switch (tag.tagNumber) { + case 0: + final RevocationDistributionType type = + RevocationDistributionType(); + distributionPoint = type.getDistributionType(tag, true); + break; + case 2: + final RevocationName name = RevocationName(); + _issuer = name.getCrlName(tag, false); + break; + } + } + } + } + } + + /// Internal field + RevocationDistributionType? distributionPoint; + RevocationName? _issuer; + + /// Internal method + RevocationDistribution? getCrlDistribution(dynamic obj) { + if (obj == null || obj is RevocationDistribution) { + return obj; + } + if (obj is Asn1Sequence) { + return RevocationDistribution(obj); + } + throw Exception('Invalid entry in CRL distribution point'); + } + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection(); + if (distributionPoint != null) { + collection.add([DerTag(0, distributionPoint)]); + } + if (_issuer != null) { + collection.add([DerTag(2, _issuer, false)]); + } + return DerSequence(collection: collection); + } +} + +/// Internal class +class RevocationDistributionType extends Asn1Encode { + /// Internal constructor. + RevocationDistributionType([Asn1Tag? tag]) { + if (tag != null) { + type = tag.tagNumber; + if (type == fullName) { + final RevocationName crl = RevocationName(); + name = crl.getCrlName(tag, false); + } else { + name = Asn1Set.getAsn1Set(tag, false); + } + } + } + + /// Internal field + Asn1Encode? name; + + /// Internal fields + int? type; + + /// Internal constants + static const int fullName = 0; + + /// Internal method + RevocationDistributionType? getDistributionType( + Asn1Tag tag, + bool isExplicit, + ) { + return getDistributionTypeFromObj(Asn1Tag.getTag(tag, true)); + } + + /// Internal method + RevocationDistributionType? getDistributionTypeFromObj(dynamic obj) { + if (obj == null || obj is RevocationDistributionType) { + return obj; + } + if (obj is Asn1Tag) { + return RevocationDistributionType(obj); + } + throw Exception('Invalid entry in sequence'); + } + + @override + Asn1 getAsn1() { + return DerTag(type, name, false); + } +} + +/// Internal class +class RevocationName extends Asn1Encode { + /// Internal constructor. + RevocationName([Asn1Sequence? sequence]) { + if (sequence != null) { + names = []; + for (int i = 0; i != sequence.count; i++) { + final OcspTag name = OcspTag(); + names!.add(name.getOcspName(sequence[i])!); + } + } + } + + /// Internal field + List? names; + + /// Internal method + RevocationName? getCrlNameFromObj(dynamic obj) { + if (obj == null || obj is RevocationName) { + return obj; + } + if (obj is Asn1Sequence) { + return RevocationName(obj); + } + throw Exception('Invalid entry in sequence'); + } + + /// Internal method + RevocationName? getCrlName(Asn1Tag tag, bool isExplicit) { + return getCrlNameFromObj(Asn1Sequence.getSequence(tag, isExplicit)); + } + + @override + Asn1 getAsn1() { + return DerSequence(array: names); + } +} + +/// Internal class +class OcspTag extends Asn1Encode { + /// Internal constructor. + OcspTag([int? tag, Asn1Encode? encode]) { + if (encode != null) { + _encode = encode; + } + if (tag != null) { + tagNumber = tag; + } + } + + /// Internal fields + Asn1Encode? _encode; + + /// Internal fields + int? tagNumber; + + /// Internal method + OcspTag? getOcspName(dynamic obj) { + if (obj == null || obj is OcspTag) { + return obj; + } + if (obj is Asn1Tag) { + final Asn1Tag tag = obj; + final int? tagNumber = obj.tagNumber; + if (tagNumber != null) { + switch (tagNumber) { + case 0: + return OcspTag(tagNumber, Asn1Sequence.getSequence(tag, false)); + case 1: + return OcspTag( + tagNumber, + DerAsciiString.getAsciiString(tag, false), + ); + case 2: + return OcspTag( + tagNumber, + DerAsciiString.getAsciiString(tag, false), + ); + case 3: + throw Exception('Invalid tag number specified: $tagNumber'); + case 4: + return OcspTag(tagNumber, X509Name.getName(tag, true)); + case 5: + return OcspTag(tagNumber, Asn1Sequence.getSequence(tag, false)); + case 6: + return OcspTag( + tagNumber, + DerAsciiString.getAsciiString(tag, false), + ); + case 7: + return OcspTag(tagNumber, Asn1Octet.getOctetString(tag, false)); + case 8: + return OcspTag(tagNumber, DerObjectID.getID(tag.getObject())); + } + } + } + if (obj is List) { + try { + return getOcspName(Asn1.fromByteArray(obj)); + } catch (e) { + throw Exception('Invalid OCSP name to parse'); + } + } + throw Exception('Invalid entry in sequence'); + } + + @override + Asn1 getAsn1() { + return DerTag(tagNumber, _encode, tagNumber == 4); + } +} + +/// internal class +class CertificateUtililty { + /// internal method + List? getCrlUrls(X509Certificate certificate) { + final List urls = []; + try { + final Asn1? obj = getExtensionValue( + certificate, + X509Extensions.crlDistributionPoints.id!, + ); + if (obj == null) { + return null; + } + final RevocationPointList list = RevocationPointList(); + final RevocationPointList distributionList = list.getCrlPointList(obj); + final List distributionLists = + distributionList.getDistributionPoints(); + for (final RevocationDistribution entry in distributionLists) { + final RevocationDistributionType? distributionPointName = + entry.distributionPoint; + if (distributionPointName != null) { + if (RevocationDistributionType.fullName != + distributionPointName.type) { + continue; + } + if (distributionPointName.name != null && + distributionPointName.name is RevocationName) { + final RevocationName generalNames = + distributionPointName.name! as RevocationName; + final List? names = generalNames.names; + if (names != null) { + for (final OcspTag name in names) { + if (name.tagNumber != 6) { + continue; + } + final DerAsciiString? asciiString = + DerAsciiString.getAsciiString( + name.getAsn1() as Asn1Tag, + false, + ); + if (asciiString != null) { + final String? url = asciiString.getString(); + if (url != null && url.toLowerCase().endsWith('.crl') || + !isNullOrEmpty(url)) { + urls.add(url!); + } + } + } + } + } + } + } + return urls; + } catch (ex) { + return null; + } + } + + /// internal method + String? getOcspUrl(X509Certificate certificate) { + try { + final Asn1? asn1 = getExtensionValue( + certificate, + X509Extensions.authorityInfoAccess.id!, + ); + if (asn1 == null) { + return null; + } + if (asn1 is Asn1Sequence) { + final Asn1Sequence sequence = asn1; + for (int i = 0; i < sequence.count; i++) { + final dynamic asn1Sequence = sequence.objects![i]; + if (asn1Sequence is Asn1Sequence) { + if (asn1Sequence.count != 2) { + continue; + } else { + if (asn1Sequence.objects![0] is DerObjectID && + (asn1Sequence.objects![0]! as DerObjectID).id == + '1.3.6.1.5.5.7.48.1') { + final dynamic obj = asn1Sequence.objects![1]; + if (obj is Asn1) { + final String? accessLocation = getStringFromGeneralName(obj); + if (accessLocation == null) { + return ''; + } else { + return accessLocation; + } + } + } + } + } + } + } + } catch (e) { + return null; + } + return null; + } + + /// internal method + Asn1? getExtensionValue(X509Certificate certificate, String id) { + List? bytes; + final Asn1Octet? extension = certificate.getExtension(DerObjectID(id)); + if (extension != null) { + bytes = extension.getDerEncoded(); + } + if (bytes == null) { + return null; + } + Asn1Stream asn1 = Asn1Stream(PdfStreamReader(bytes)); + final Asn1? octet = asn1.readAsn1(); + if (octet is Asn1Octet) { + asn1 = Asn1Stream(PdfStreamReader(octet.getOctets())); + } + return asn1.readAsn1(); + } + + /// internal method + String? getStringFromGeneralName(Asn1 names) { + if (names is Asn1Tag) { + final Asn1Octet? octet = Asn1Octet.getOctetString(names, false); + if (octet != null) { + final List? bytes = octet.getOctets(); + if (bytes != null) { + return utf8.decode(bytes); + } + } + } + return null; + } +} + +/// internal class +class OcspRequestCreator { + /// Internal constructor + OcspRequestCreator() { + _list = []; + } + + /// Internal field + late List _list; + + /// Internal field + X509Extensions? requestExtensions; + OcspTag? _requestorName; + + /// Internal method + void addRequest(CertificateIdentity id) { + _list.add(RequestCreatorHelper(id, null)); + } + + /// Internal method + OcspRequestHelper createRequest() { + final Asn1EncodeCollection requests = Asn1EncodeCollection(); + for (final dynamic reqObj in _list) { + try { + requests.add([(reqObj as RequestCreatorHelper).toRequest()]); + } catch (e) { + throw Exception('Invalid request creation'); + } + } + final OcspRequestCollection requestList = OcspRequestCollection( + _requestorName, + DerSequence(collection: requests), + requestExtensions!, + ); + return OcspRequestHelper(RevocationListRequest(requestList)); + } +} + +/// Internal class +class OcspRequestHelper extends X509ExtensionBase { + /// Internal constructor + OcspRequestHelper(this._request); + + /// Internal field + final RevocationListRequest _request; + + @override + X509Extensions? getX509Extensions() { + return null; + } + + /// Internal method + List? getEncoded() { + return _request.getEncoded(); + } +} + +/// Internal class +class OcspRequestCollection extends Asn1Encode { + /// Internal constructor + OcspRequestCollection( + this._requestorName, + this._requestList, + this._requestExtensions, + ) { + _version = DerInteger([0]); + versionSet = false; + } + + /// Internal fields + late DerInteger _version; + late final OcspTag? _requestorName; + late final Asn1Sequence _requestList; + late final X509Extensions _requestExtensions; + + /// Internal fields + late bool versionSet; + + ///Internal method + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection(); + if (!(_version == DerInteger([0])) || versionSet) { + collection.add([DerTag(0, _version, true)]); + } + if (_requestorName != null) { + collection.add([DerTag(1, _requestorName, true)]); + } + collection.add([_requestList]); + collection.add([DerTag(2, _requestExtensions, true)]); + return DerSequence(collection: collection); + } +} + +/// Internal class +class RevocationListRequest extends Asn1Encode { + /// Internal constructor + RevocationListRequest(this._requests); + + /// Internal field + late final OcspRequestCollection _requests; + + @override + Asn1 getAsn1() { + return DerSequence( + collection: Asn1EncodeCollection([_requests]), + ); + } +} + +/// Internal class +class OcspResponseHelper { + /// Internal constructor + OcspResponseHelper(List data) { + _response = OcspResponse( + Asn1Stream(PdfStreamReader(data)).readAsn1()! as Asn1Sequence, + ); + } + + /// Internal field + late OcspResponse _response; + + /// Internal method + List? getResponseBytes() { + final RevocationResponseBytes? bytes = _response.responseBytes; + if (bytes == null) { + return null; + } + if (bytes.responseType.id == OcspConstants.ocspBasic.id) { + try { + return bytes.response.getOctets(); + } catch (e) { + throw Exception('Invalid response detected'); + } + } + return null; + } +} + +/// Internal class +class OcspResponse extends Asn1Encode { + /// Internal constructor + OcspResponse(Asn1Sequence sequence) { + if (sequence.count == 2) { + responseBytes = RevocationResponseBytes().getResponseBytes( + sequence[1]! as Asn1Tag, + true, + ); + } + } + + /// Internal field + RevocationResponseBytes? responseBytes; + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection([ + DerCatalogue([0]), + ]); + if (responseBytes != null) { + collection.add([DerTag(0, responseBytes, true)]); + } + return DerSequence(collection: collection); + } +} + +/// Internal class +class RevocationResponseBytes extends Asn1Encode { + /// Internal constructor + RevocationResponseBytes([Asn1Sequence? sequence]) { + if (sequence != null) { + if (sequence.count != 2) { + ArgumentError.value(sequence, 'Invalid length in sequence'); + } + responseType = DerObjectID.getID(sequence[0])!; + response = Asn1Octet.getOctetStringFromObject(sequence[1])!; + } + } + + /// Internal field + late DerObjectID responseType; + + /// Internal field + late Asn1Octet response; + + /// Internal method + RevocationResponseBytes? getResponseBytes(Asn1Tag tag, bool isExplicit) { + return getResponseBytesFromObject( + Asn1Sequence.getSequence(tag, isExplicit), + ); + } + + /// Internal method + RevocationResponseBytes? getResponseBytesFromObject(dynamic obj) { + if (obj == null || obj is RevocationResponseBytes) { + return obj; + } else if (obj is Asn1Sequence) { + return RevocationResponseBytes(obj); + } + ArgumentError.checkNotNull(obj, 'Invalid entry in sequence'); + return null; + } + + @override + Asn1 getAsn1() { + return DerSequence(array: [responseType, response]); + } +} + +/// internal class +class RequestCreatorHelper { + /// internal constructor + RequestCreatorHelper(this._id, this._extensions); + + /// internal field + late final CertificateIdentity _id; + final X509Extensions? _extensions; + + /// internal method + RevocationRequest toRequest() { + return RevocationRequest(_id.id!, _extensions); + } +} + +/// internal class +class RevocationRequest extends Asn1Encode { + /// internal constructor + RevocationRequest(this._certificateID, this._singleRequestExtensions); + + /// internal field + late final CertificateIdentityHelper _certificateID; + final X509Extensions? _singleRequestExtensions; + + @override + Asn1 getAsn1() { + final Asn1EncodeCollection collection = Asn1EncodeCollection([ + _certificateID, + ]); + if (_singleRequestExtensions != null) { + collection.add([DerTag(0, _singleRequestExtensions, true)]); + } + return DerSequence(collection: collection); + } +} + +/// Internal class +class TimeStampRequestCreator extends Asn1 { + /// Internal field + static const String _idSHA256 = '2.16.840.1.101.3.4.2.1'; + + /// Internal method + List getAsnEncodedTimestampRequest(List hash) { + final Asn1Identifier digestAlgOid = Asn1Identifier(_idSHA256); + final Algorithms algID = Algorithms.fromAsn1Sequence( + digestAlgOid, + DerNull.value, + ); + final Asn1Sequence seq = Asn1Sequence(); + seq.objects!.add(algID); + seq.objects!.add(Asn1Octet(hash)); + final Asn1Sequence asn1Sequence = Asn1Sequence(); + asn1Sequence.objects!.add(Asn1Integer(1)); + asn1Sequence.objects!.add(seq); + asn1Sequence.objects!.add(Asn1Integer(100)); + asn1Sequence.objects!.add(Asn1Boolean(true)); + return asn1Sequence.asnEncode()!; + } + + @override + void encode(DerStream derOut) { + throw UnsupportedError('This functionality is not implemented yet.'); + } +} + +// ignore: avoid_classes_with_only_static_members +/// internal class +class OcspConstants { + /// internal field + static DerObjectID ocsp = DerObjectID('1.3.6.1.5.5.7.48.1'); + + /// internal field + static DerObjectID ocspBasic = DerObjectID('1.3.6.1.5.5.7.48.1.1'); + + /// internal field + static DerObjectID ocspNonce = DerObjectID('$ocsp.2'); + + /// internal field + static DerObjectID ocspCrl = DerObjectID('$ocsp.3'); + + /// internal field + static DerObjectID ocspResponse = DerObjectID('$ocsp.4'); + + /// internal field + static DerObjectID ocspNocheck = DerObjectID('$ocsp.5'); + + /// internal field + static DerObjectID ocspArchiveCutoff = DerObjectID('$ocsp.6'); + + /// internal field + static DerObjectID ocspServiceLocator = DerObjectID('$ocsp.7'); +} + +/// Send the data to the server and get the response. +Future?> fetchData( + dynamic uri, + String method, { + String? contentType, + String? userName, + String? password, + List? data, + Duration? timeOutDuration, +}) async { + final http.Client client = http.Client(); + try { + if (uri is String) { + uri = Uri.parse(uri); + } + final http.Request request = http.Request(method, uri as Uri); + if (contentType != null) { + request.headers.addAll({'Content-Type': contentType}); + } + if (password != null && userName != null) { + request.headers.addAll({ + 'Authorization': + 'Basic ${base64Encode(utf8.encode('$userName:$password'))}', + }); + } + if (data != null) { + request.bodyBytes = data; + } + final http.StreamedResponse response = + await ((timeOutDuration != null) + ? client.send(request).timeout(timeOutDuration) + : client.send(request)); + final List responseBytes = await response.stream.toBytes(); + return (response.statusCode == 200) ? responseBytes : null; + } catch (e) { + return null; + } finally { + client.close(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_certificates.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_certificates.dart index c1b4b647a..0855f9722 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_certificates.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_certificates.dart @@ -1,767 +1,767 @@ -import '../../../io/stream_reader.dart'; -import '../asn1/asn1.dart'; -import '../asn1/asn1_stream.dart'; -import '../asn1/der.dart'; -import '../cryptography/cipher_block_chaining_mode.dart'; -import '../cryptography/ipadding.dart'; -import '../cryptography/signature_utilities.dart'; -import '../pdf_signature_dictionary.dart'; -import '../pkcs/pfx_data.dart'; -import 'x509_name.dart'; -import 'x509_time.dart'; - -/// internal class -class IX509Extension { - /// internal method - Asn1Octet? getExtension(DerObjectID id) => null; -} - -/// internal class -class X509Certificates { - /// internal constructor - X509Certificates(X509Certificate certificate) { - _certificate = certificate; - } - //Fields - X509Certificate? _certificate; - //Properties - /// internal property - X509Certificate? get certificate => _certificate; - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _certificate.hashCode; - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is X509Certificates) { - return _certificate == other._certificate; - } else { - return false; - } - } -} - -/// internal class -abstract class X509ExtensionBase implements IX509Extension { - /// internal method - X509Extensions? getX509Extensions(); - @override - Asn1Octet? getExtension(DerObjectID oid) { - final X509Extensions? exts = getX509Extensions(); - if (exts != null) { - final X509Extension? ext = exts.getExtension(oid); - if (ext != null) { - return ext._value; - } - } - return null; - } -} - -/// internal class -class X509Extension { - /// internal constructor - X509Extension(bool critical, Asn1Octet? value) { - _critical = critical; - _value = value; - } - //Fields - bool? _critical; - Asn1Octet? _value; - //Implementation - /// internal method - static Asn1? convertValueToObject(X509Extension ext) { - return Asn1Stream(PdfStreamReader(ext._value!.getOctets())).readAsn1(); - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - if (other is X509Extension) { - return _value == other._value && _critical == other._critical; - } else { - return false; - } - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _critical! ? _value.hashCode : ~_value.hashCode; -} - -/// internal class -class X509Extensions extends Asn1Encode { - /// internal constructor - X509Extensions( - Map extensions, [ - List? ordering, - ]) { - _extensions = {}; - if (ordering == null) { - final List der = []; - // ignore: avoid_function_literals_in_foreach_calls - extensions.keys.forEach((DerObjectID? col) { - der.add(col); - }); - _ordering = der; - } else { - _ordering = ordering; - } - // ignore: avoid_function_literals_in_foreach_calls - _ordering.forEach((DerObjectID? oid) { - _extensions[oid] = extensions[oid!]; - }); - } - - /// internal method - X509Extensions.fromSequence(Asn1Sequence seq) { - _ordering = []; - _extensions = {}; - for (int i = 0; i < seq.objects!.length; i++) { - final Asn1Encode ae = seq.objects![i] as Asn1Encode; - final Asn1Sequence s = Asn1Sequence.getSequence(ae.getAsn1())!; - if (s.count < 2 || s.count > 3) { - throw ArgumentError.value( - seq, - 'count', - 'Bad sequence size: ${s.count}', - ); - } - final DerObjectID? oid = DerObjectID.getID(s[0]!.getAsn1()); - final bool isCritical = - s.count == 3 && (s[1]!.getAsn1()! as DerBoolean).isTrue; - final Asn1Octet? octets = Asn1Octet.getOctetStringFromObject( - s[s.count - 1]!.getAsn1(), - ); - _extensions[oid] = X509Extension(isCritical, octets); - _ordering.add(oid); - } - } - - /// internal method - static X509Extensions? getInstance(dynamic obj, [bool? explicitly]) { - X509Extensions? result; - if (explicitly == null) { - if (obj == null || obj is X509Extensions) { - result = obj as X509Extensions?; - } else if (obj is Asn1Sequence) { - result = X509Extensions.fromSequence(obj); - } else if (obj is Asn1Tag) { - result = getInstance(obj.getObject()); - } else { - throw ArgumentError.value(obj, 'obj', 'unknown object in factory'); - } - } else { - result = getInstance(Asn1Sequence.getSequence(obj, explicitly)); - } - return result; - } - - //Fields - late Map _extensions; - late List _ordering; - - /// internal field - static DerObjectID authorityKeyIdentifier = DerObjectID('2.5.29.35'); - - /// internal field - static DerObjectID crlDistributionPoints = DerObjectID('2.5.29.31'); - - /// internal field - static DerObjectID authorityInfoAccess = DerObjectID('1.3.6.1.5.5.7.1.1'); - - //Implementation - @override - Asn1 getAsn1() { - final Asn1EncodeCollection vec = Asn1EncodeCollection(); - // ignore: avoid_function_literals_in_foreach_calls - _ordering.forEach((DerObjectID? oid) { - final X509Extension ext = _extensions[oid]!; - final Asn1EncodeCollection v = Asn1EncodeCollection([oid]); - if (ext._critical!) { - v.encodableObjects.add(DerBoolean(true)); - } - v.encodableObjects.add(ext._value); - vec.encodableObjects.add(DerSequence(collection: v)); - }); - return DerSequence(collection: vec); - } - - /// internal method - X509Extension? getExtension(DerObjectID oid) { - return (_extensions.containsKey(oid)) ? _extensions[oid] : null; - } -} - -/// internal class -class X509Certificate extends X509ExtensionBase { - /// internal constructor - X509Certificate(this.c) { - try { - final Asn1Octet? str = getExtension(DerObjectID('2.5.29.15')); - if (str != null) { - final DerBitString bits = - DerBitString.getDetBitString( - Asn1Stream(PdfStreamReader(str.getOctets())).readAsn1(), - )!; - final List bytes = bits.getBytes()!; - final int length = (bytes.length * 8) - bits.extra!; - _keyUsage = List.generate( - (length < 9) ? 9 : length, - (int i) => false, - ); - for (int i = 0; i != length; i++) { - _keyUsage![i] = (bytes[i ~/ 8] & (0x80 >> (i % 8))) != 0; - } - } else { - _keyUsage = null; - } - } catch (e) { - throw ArgumentError.value( - e, - 'ArgumentError', - 'cannot construct KeyUsage', - ); - } - } - //Fields - /// internal field - X509CertificateStructure? c; - List? _keyUsage; - //Implementation - @override - X509Extensions? getX509Extensions() { - return c!.version == 3 ? c!.tbsCertificate!.extensions : null; - } - - /// internal method - CipherParameter getPublicKey() { - return createKey(c!.subjectPublicKeyInfo!); - } - - /// internal method - List? getTbsCertificate() { - return c!.tbsCertificate!.getDerEncoded(); - } - - /// internal method - List? getSignature() { - return c!.signature!.getBytes(); - } - - /// internal method - CipherParameter createKey(PublicKeyInformation keyInfo) { - CipherParameter result; - final Algorithms algID = keyInfo.algorithm!; - final DerObjectID algOid = algID.id!; - if (algOid.id == PkcsObjectId.rsaEncryption.id || - algOid.id == X509Objects.idEARsa.id) { - final RsaPublicKey pubKey = - RsaPublicKey.getPublicKey(keyInfo.getPublicKey())!; - result = RsaKeyParam(false, pubKey.modulus, pubKey.publicExponent); - } else { - throw ArgumentError.value( - keyInfo, - 'keyInfo', - 'algorithm identifier in key not recognised', - ); - } - return result; - } - - /// internal method - void verify(CipherParameter key) { - if (c != null) { - final String sigName = c!.signatureAlgorithm!.id!.id!; - final SignerUtilities util = SignerUtilities(); - final ISigner signature = util.getSigner(sigName); - checkSignature(key, signature); - } - } - - /// internal method - void checkSignature(CipherParameter publicKey, ISigner signature) { - if (!isAlgIDEqual(c!.signatureAlgorithm!, c!.tbsCertificate!.signature!)) { - throw Exception('signature algorithm in TBS cert not same as outer cert'); - } - signature.initialize(false, publicKey); - final List? b = getTbsCertificate(); - if (b != null) { - signature.blockUpdate(b, 0, b.length); - final List? sig = getSignature(); - if (!signature.validateSignature(sig!)) { - throw Exception('Public key presented not for certificate signature'); - } - } - } - - /// internal method - bool isAlgIDEqual(Algorithms id1, Algorithms id2) { - if (!(id1.id == id2.id)) { - return false; - } - final Asn1Encode? p1 = id1.parameters; - final Asn1Encode? p2 = id2.parameters; - if ((p1 == null) == (p2 == null)) { - return p1 == p2; - } - return p1 == null ? p2!.getAsn1() is Asn1Null : p1.getAsn1() is Asn1Null; - } -} - -/// internal class -class X509CertificateStructure extends Asn1Encode { - /// internal constructor - X509CertificateStructure(Asn1Sequence seq) { - _tbsCert = SingnedCertificate.getCertificate(seq[0]); - _sigAlgID = Algorithms.getAlgorithms(seq[1]); - _sig = DerBitString.getDetBitString(seq[2]); - } - //Fields - SingnedCertificate? _tbsCert; - Algorithms? _sigAlgID; - DerBitString? _sig; - //Properties - /// internal property - SingnedCertificate? get tbsCertificate => _tbsCert; - - /// internal property - int get version => _tbsCert!.version; - - /// internal property - DerInteger? get serialNumber => _tbsCert!.serialNumber; - - /// internal property - X509Name? get issuer => _tbsCert!.issuer; - - /// internal property - X509Time? get startDate => _tbsCert!.startDate; - - /// internal property - X509Time? get endDate => _tbsCert!.endDate; - - /// internal property - X509Name? get subject => _tbsCert!.subject; - - /// internal property - PublicKeyInformation? get subjectPublicKeyInfo => - _tbsCert!.subjectPublicKeyInfo; - - /// internal property - Algorithms? get signatureAlgorithm => _sigAlgID; - - /// internal property - DerBitString? get signature => _sig; - //Implementation - /// internal method - static X509CertificateStructure? getInstance(dynamic obj) { - if (obj is X509CertificateStructure) { - return obj; - } - if (obj != null) { - return X509CertificateStructure(Asn1Sequence.getSequence(obj)!); - } - return null; - } - - @override - Asn1 getAsn1() { - return DerSequence(array: [_tbsCert, _sigAlgID, _sig]); - } -} - -/// Internal class -class SingnedCertificate extends Asn1Encode { - /// internal constructor - SingnedCertificate(Asn1Sequence sequence) { - int seqStart = 0; - _sequence = sequence; - if (sequence[0] is DerTag || sequence[0] is Asn1Tag) { - _version = DerInteger.getNumberFromTag(sequence[0]! as Asn1Tag, true); - } else { - seqStart = -1; - _version = DerInteger(bigIntToBytes(BigInt.from(0))); - } - _serialNumber = DerInteger.getNumber(sequence[seqStart + 1]); - _signature = Algorithms.getAlgorithms(sequence[seqStart + 2]); - _issuer = X509Name.getName(sequence[seqStart + 3]); - final Asn1Sequence dates = sequence[seqStart + 4]! as Asn1Sequence; - _startDate = X509Time.getTime(dates[0]); - _endDate = X509Time.getTime(dates[1]); - _subject = X509Name.getName(sequence[seqStart + 5]); - _publicKeyInformation = PublicKeyInformation.getPublicKeyInformation( - sequence[seqStart + 6], - ); - for ( - int extras = sequence.count - (seqStart + 6) - 1; - extras > 0; - extras-- - ) { - final Asn1Tag extra = sequence[seqStart + 6 + extras]! as Asn1Tag; - switch (extra.tagNumber) { - case 1: - _issuerID = DerBitString.getDerBitStringFromTag(extra, false); - break; - case 2: - _subjectID = DerBitString.getDerBitStringFromTag(extra, false); - break; - case 3: - _extensions = X509Extensions.getInstance(extra); - break; - } - } - } - - /// internal method - static SingnedCertificate? getCertificate(dynamic obj) { - if (obj is SingnedCertificate) { - return obj; - } - if (obj != null) { - return SingnedCertificate(Asn1Sequence.getSequence(obj)!); - } - return null; - } - - //Fields - Asn1Sequence? _sequence; - DerInteger? _version; - DerInteger? _serialNumber; - Algorithms? _signature; - X509Name? _issuer; - X509Time? _startDate; - X509Time? _endDate; - X509Name? _subject; - PublicKeyInformation? _publicKeyInformation; - DerBitString? _issuerID; - DerBitString? _subjectID; - X509Extensions? _extensions; - //Properties - /// internal field - int get version => _version!.value.toSigned(32).toInt() + 1; - - /// internal field - DerInteger? get serialNumber => _serialNumber; - - /// internal field - Algorithms? get signature => _signature; - - /// internal field - X509Name? get issuer => _issuer; - - /// internal field - X509Time? get startDate => _startDate; - - /// internal field - X509Time? get endDate => _endDate; - - /// internal field - X509Name? get subject => _subject; - - /// internal field - PublicKeyInformation? get subjectPublicKeyInfo => _publicKeyInformation; - - /// internal field - DerBitString? get issuerUniqueID => _issuerID; - - /// internal field - DerBitString? get subjectUniqueID => _subjectID; - - /// internal field - X509Extensions? get extensions => _extensions; - //Implementation - @override - Asn1? getAsn1() { - return _sequence; - } -} - -/// internal class -class PublicKeyInformation extends Asn1Encode { - /// internal constructor - PublicKeyInformation(Algorithms algorithms, Asn1Encode publicKey) { - _publicKey = DerBitString.fromAsn1(publicKey); - _algorithms = algorithms; - } - - /// internal constructor - PublicKeyInformation.fromSequence(Asn1Sequence sequence) { - if (sequence.count != 2) { - throw ArgumentError.value( - sequence, - 'sequence', - 'Invalid length in sequence', - ); - } - _algorithms = Algorithms.getAlgorithms(sequence[0]); - _publicKey = DerBitString.getDetBitString(sequence[1]); - } - - /// internal method - static PublicKeyInformation? getPublicKeyInformation(dynamic obj) { - if (obj is PublicKeyInformation) { - return obj; - } - if (obj != null) { - return PublicKeyInformation.fromSequence(Asn1Sequence.getSequence(obj)!); - } - return null; - } - - Algorithms? _algorithms; - DerBitString? _publicKey; - - /// internal property - Algorithms? get algorithm => _algorithms; - - /// internal property - DerBitString? get publicKey => _publicKey; - //Implementation - /// internal method - Asn1? getPublicKey() { - return Asn1Stream(PdfStreamReader(_publicKey!.getBytes())).readAsn1(); - } - - @override - Asn1 getAsn1() { - return DerSequence(array: [_algorithms, _publicKey]); - } -} - -/// internal class -class RsaPublicKey extends Asn1Encode { - /// internal constructor - RsaPublicKey(BigInt? modulus, BigInt? publicExponent) { - _modulus = modulus; - _publicExponent = publicExponent; - } - - /// internal constructor - RsaPublicKey.fromSequence(Asn1Sequence sequence) { - _modulus = DerInteger.getNumber(sequence[0])!.positiveValue; - _publicExponent = DerInteger.getNumber(sequence[1])!.positiveValue; - } - BigInt? _modulus; - BigInt? _publicExponent; - - /// internal property - BigInt? get modulus => _modulus; - - /// internal property - BigInt? get publicExponent => _publicExponent; - - /// internal method - static RsaPublicKey? getPublicKey(dynamic obj) { - RsaPublicKey? result; - if (obj == null || obj is RsaPublicKey) { - result = obj as RsaPublicKey?; - } else if (obj is Asn1Sequence) { - result = RsaPublicKey.fromSequence(obj); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - return result; - } - - @override - Asn1 getAsn1() { - return DerSequence( - array: [ - DerInteger.fromNumber(modulus), - DerInteger.fromNumber(publicExponent), - ], - ); - } -} - -/// internal class -class X509CertificateParser { - /// internal constructor - X509CertificateParser(); - //Fields - Asn1Set? _sData; - int? _sDataObjectCount; - PdfStreamReader? _currentStream; - //Implementation - /// internal method - X509Certificate? readCertificate(PdfStreamReader inStream) { - if (_currentStream == null || _currentStream != inStream) { - _currentStream = inStream; - _sData = null; - _sDataObjectCount = 0; - } - if (_sData != null) { - if (_sDataObjectCount != _sData!.objects.length) { - return getCertificate(); - } - _sData = null; - _sDataObjectCount = 0; - return null; - } - final _PushStream pis = _PushStream(inStream); - final int tag = pis.readByte()!; - if (tag < 0) { - return null; - } - pis.unread(tag); - return readDerCertificate(Asn1Stream(pis)); - } - - /// Internal method - List? getCertificateChain(PdfStreamReader inStream) { - if (_currentStream == null || _currentStream != inStream) { - _currentStream = inStream; - _sData = null; - _sDataObjectCount = 0; - } - if (_sData != null) { - if (_sDataObjectCount != _sData!.objects.length) { - return _getCertificateChain(); - } - _sData = null; - _sDataObjectCount = 0; - return null; - } - final _PushStream pis = _PushStream(inStream); - final int tag = pis.readByte()!; - if (tag < 0) { - return null; - } - pis.unread(tag); - return _readDerCertificates(Asn1Stream(pis)); - } - - /// internal method - X509Certificate? getCertificate() { - if (_sData != null) { - while (_sDataObjectCount! < _sData!.objects.length) { - final dynamic obj = _sData![_sDataObjectCount!]; - _sDataObjectCount = _sDataObjectCount! + 1; - if (obj is Asn1Sequence) { - return createX509Certificate( - X509CertificateStructure.getInstance(obj), - ); - } - } - } - return null; - } - - /// internal method - X509Certificate? readDerCertificate(Asn1Stream dIn) { - final dynamic seq = dIn.readAsn1(); - if (seq != null && seq is Asn1Sequence) { - if (seq.count > 1 && seq[0] is DerObjectID) { - if ((seq[0]! as DerObjectID).id == PkcsObjectId.signedData.id) { - if (seq.count >= 2) { - final Asn1Sequence signedSequence = - Asn1Sequence.getSequence(seq[1] as Asn1Tag?, true)!; - bool isContinue = true; - // ignore: avoid_function_literals_in_foreach_calls - signedSequence.objects!.forEach((dynamic o) { - if (isContinue && o is Asn1Tag) { - if (o.tagNumber == 0) { - _sData = Asn1Set.getAsn1Set(o, false); - isContinue = false; - } - } - }); - } - return getCertificate(); - } - } - } - return createX509Certificate(X509CertificateStructure.getInstance(seq)); - } - - List? _getCertificateChain() { - final List certList = []; - if (_sData != null) { - while (_sDataObjectCount! < _sData!.objects.length) { - final dynamic obj = _sData![_sDataObjectCount!]; - _sDataObjectCount = _sDataObjectCount! + 1; - if (obj is Asn1Sequence) { - certList.add( - createX509Certificate(X509CertificateStructure.getInstance(obj)), - ); - } - } - } - return certList.isNotEmpty ? certList : null; - } - - /// internal method - List? _readDerCertificates(Asn1Stream dIn) { - final dynamic seq = dIn.readAsn1(); - if (seq != null && seq is Asn1Sequence) { - if (seq.count > 1 && seq[0] is DerObjectID) { - if ((seq[0]! as DerObjectID).id == PkcsObjectId.signedData.id) { - if (seq.count >= 2) { - final Asn1Sequence signedSequence = - Asn1Sequence.getSequence(seq[1] as Asn1Tag?, true)!; - bool isContinue = true; - // ignore: avoid_function_literals_in_foreach_calls - signedSequence.objects!.forEach((dynamic o) { - if (isContinue && o is Asn1Tag) { - if (o.tagNumber == 0) { - _sData = Asn1Set.getAsn1Set(o, false); - isContinue = false; - } - } - }); - } - return _getCertificateChain(); - } - } - } - return [ - createX509Certificate(X509CertificateStructure.getInstance(seq)), - ]; - } - - /// internal method - X509Certificate createX509Certificate(X509CertificateStructure? c) { - return X509Certificate(c); - } -} - -class _PushStream extends PdfStreamReader { - _PushStream(PdfStreamReader stream) : super(stream.data) { - _stream = stream; - _buffer = -1; - } - //Fields - late PdfStreamReader _stream; - int? _buffer; - @override - int get position => _stream.position; - @override - set position(int value) { - _stream.position = value; - } - - //Implementation - @override - int? readByte() { - if (_buffer != -1) { - final int? temp = _buffer; - _buffer = -1; - return temp; - } - return _stream.readByte(); - } - - @override - int? read(List buffer, int offset, int count) { - if (_buffer != -1) { - final int? temp = _buffer; - _buffer = -1; - return temp; - } - return _stream.read(buffer, offset, count); - } - - void unread(int b) { - _buffer = b & 0xFF; - } -} +import '../../../io/stream_reader.dart'; +import '../asn1/asn1.dart'; +import '../asn1/asn1_stream.dart'; +import '../asn1/der.dart'; +import '../cryptography/cipher_block_chaining_mode.dart'; +import '../cryptography/ipadding.dart'; +import '../cryptography/signature_utilities.dart'; +import '../pdf_signature_dictionary.dart'; +import '../pkcs/pfx_data.dart'; +import 'x509_name.dart'; +import 'x509_time.dart'; + +/// internal class +class IX509Extension { + /// internal method + Asn1Octet? getExtension(DerObjectID id) => null; +} + +/// internal class +class X509Certificates { + /// internal constructor + X509Certificates(X509Certificate certificate) { + _certificate = certificate; + } + //Fields + X509Certificate? _certificate; + //Properties + /// internal property + X509Certificate? get certificate => _certificate; + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _certificate.hashCode; + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is X509Certificates) { + return _certificate == other._certificate; + } else { + return false; + } + } +} + +/// internal class +abstract class X509ExtensionBase implements IX509Extension { + /// internal method + X509Extensions? getX509Extensions(); + @override + Asn1Octet? getExtension(DerObjectID oid) { + final X509Extensions? exts = getX509Extensions(); + if (exts != null) { + final X509Extension? ext = exts.getExtension(oid); + if (ext != null) { + return ext._value; + } + } + return null; + } +} + +/// internal class +class X509Extension { + /// internal constructor + X509Extension(bool critical, Asn1Octet? value) { + _critical = critical; + _value = value; + } + //Fields + bool? _critical; + Asn1Octet? _value; + //Implementation + /// internal method + static Asn1? convertValueToObject(X509Extension ext) { + return Asn1Stream(PdfStreamReader(ext._value!.getOctets())).readAsn1(); + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + if (other is X509Extension) { + return _value == other._value && _critical == other._critical; + } else { + return false; + } + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _critical! ? _value.hashCode : ~_value.hashCode; +} + +/// internal class +class X509Extensions extends Asn1Encode { + /// internal constructor + X509Extensions( + Map extensions, [ + List? ordering, + ]) { + _extensions = {}; + if (ordering == null) { + final List der = []; + // ignore: avoid_function_literals_in_foreach_calls + extensions.keys.forEach((DerObjectID? col) { + der.add(col); + }); + _ordering = der; + } else { + _ordering = ordering; + } + // ignore: avoid_function_literals_in_foreach_calls + _ordering.forEach((DerObjectID? oid) { + _extensions[oid] = extensions[oid!]; + }); + } + + /// internal method + X509Extensions.fromSequence(Asn1Sequence seq) { + _ordering = []; + _extensions = {}; + for (int i = 0; i < seq.objects!.length; i++) { + final Asn1Encode ae = seq.objects![i] as Asn1Encode; + final Asn1Sequence s = Asn1Sequence.getSequence(ae.getAsn1())!; + if (s.count < 2 || s.count > 3) { + throw ArgumentError.value( + seq, + 'count', + 'Bad sequence size: ${s.count}', + ); + } + final DerObjectID? oid = DerObjectID.getID(s[0]!.getAsn1()); + final bool isCritical = + s.count == 3 && (s[1]!.getAsn1()! as DerBoolean).isTrue; + final Asn1Octet? octets = Asn1Octet.getOctetStringFromObject( + s[s.count - 1]!.getAsn1(), + ); + _extensions[oid] = X509Extension(isCritical, octets); + _ordering.add(oid); + } + } + + /// internal method + static X509Extensions? getInstance(dynamic obj, [bool? explicitly]) { + X509Extensions? result; + if (explicitly == null) { + if (obj == null || obj is X509Extensions) { + result = obj as X509Extensions?; + } else if (obj is Asn1Sequence) { + result = X509Extensions.fromSequence(obj); + } else if (obj is Asn1Tag) { + result = getInstance(obj.getObject()); + } else { + throw ArgumentError.value(obj, 'obj', 'unknown object in factory'); + } + } else { + result = getInstance(Asn1Sequence.getSequence(obj, explicitly)); + } + return result; + } + + //Fields + late Map _extensions; + late List _ordering; + + /// internal field + static DerObjectID authorityKeyIdentifier = DerObjectID('2.5.29.35'); + + /// internal field + static DerObjectID crlDistributionPoints = DerObjectID('2.5.29.31'); + + /// internal field + static DerObjectID authorityInfoAccess = DerObjectID('1.3.6.1.5.5.7.1.1'); + + //Implementation + @override + Asn1 getAsn1() { + final Asn1EncodeCollection vec = Asn1EncodeCollection(); + // ignore: avoid_function_literals_in_foreach_calls + _ordering.forEach((DerObjectID? oid) { + final X509Extension ext = _extensions[oid]!; + final Asn1EncodeCollection v = Asn1EncodeCollection([oid]); + if (ext._critical!) { + v.encodableObjects.add(DerBoolean(true)); + } + v.encodableObjects.add(ext._value); + vec.encodableObjects.add(DerSequence(collection: v)); + }); + return DerSequence(collection: vec); + } + + /// internal method + X509Extension? getExtension(DerObjectID oid) { + return (_extensions.containsKey(oid)) ? _extensions[oid] : null; + } +} + +/// internal class +class X509Certificate extends X509ExtensionBase { + /// internal constructor + X509Certificate(this.c) { + try { + final Asn1Octet? str = getExtension(DerObjectID('2.5.29.15')); + if (str != null) { + final DerBitString bits = + DerBitString.getDetBitString( + Asn1Stream(PdfStreamReader(str.getOctets())).readAsn1(), + )!; + final List bytes = bits.getBytes()!; + final int length = (bytes.length * 8) - bits.extra!; + _keyUsage = List.generate( + (length < 9) ? 9 : length, + (int i) => false, + ); + for (int i = 0; i != length; i++) { + _keyUsage![i] = (bytes[i ~/ 8] & (0x80 >> (i % 8))) != 0; + } + } else { + _keyUsage = null; + } + } catch (e) { + throw ArgumentError.value( + e, + 'ArgumentError', + 'cannot construct KeyUsage', + ); + } + } + //Fields + /// internal field + X509CertificateStructure? c; + List? _keyUsage; + //Implementation + @override + X509Extensions? getX509Extensions() { + return c!.version == 3 ? c!.tbsCertificate!.extensions : null; + } + + /// internal method + CipherParameter getPublicKey() { + return createKey(c!.subjectPublicKeyInfo!); + } + + /// internal method + List? getTbsCertificate() { + return c!.tbsCertificate!.getDerEncoded(); + } + + /// internal method + List? getSignature() { + return c!.signature!.getBytes(); + } + + /// internal method + CipherParameter createKey(PublicKeyInformation keyInfo) { + CipherParameter result; + final Algorithms algID = keyInfo.algorithm!; + final DerObjectID algOid = algID.id!; + if (algOid.id == PkcsObjectId.rsaEncryption.id || + algOid.id == X509Objects.idEARsa.id) { + final RsaPublicKey pubKey = + RsaPublicKey.getPublicKey(keyInfo.getPublicKey())!; + result = RsaKeyParam(false, pubKey.modulus, pubKey.publicExponent); + } else { + throw ArgumentError.value( + keyInfo, + 'keyInfo', + 'algorithm identifier in key not recognised', + ); + } + return result; + } + + /// internal method + void verify(CipherParameter key) { + if (c != null) { + final String sigName = c!.signatureAlgorithm!.id!.id!; + final SignerUtilities util = SignerUtilities(); + final ISigner signature = util.getSigner(sigName); + checkSignature(key, signature); + } + } + + /// internal method + void checkSignature(CipherParameter publicKey, ISigner signature) { + if (!isAlgIDEqual(c!.signatureAlgorithm!, c!.tbsCertificate!.signature!)) { + throw Exception('signature algorithm in TBS cert not same as outer cert'); + } + signature.initialize(false, publicKey); + final List? b = getTbsCertificate(); + if (b != null) { + signature.blockUpdate(b, 0, b.length); + final List? sig = getSignature(); + if (!signature.validateSignature(sig!)) { + throw Exception('Public key presented not for certificate signature'); + } + } + } + + /// internal method + bool isAlgIDEqual(Algorithms id1, Algorithms id2) { + if (!(id1.id == id2.id)) { + return false; + } + final Asn1Encode? p1 = id1.parameters; + final Asn1Encode? p2 = id2.parameters; + if ((p1 == null) == (p2 == null)) { + return p1 == p2; + } + return p1 == null ? p2!.getAsn1() is Asn1Null : p1.getAsn1() is Asn1Null; + } +} + +/// internal class +class X509CertificateStructure extends Asn1Encode { + /// internal constructor + X509CertificateStructure(Asn1Sequence seq) { + _tbsCert = SingnedCertificate.getCertificate(seq[0]); + _sigAlgID = Algorithms.getAlgorithms(seq[1]); + _sig = DerBitString.getDetBitString(seq[2]); + } + //Fields + SingnedCertificate? _tbsCert; + Algorithms? _sigAlgID; + DerBitString? _sig; + //Properties + /// internal property + SingnedCertificate? get tbsCertificate => _tbsCert; + + /// internal property + int get version => _tbsCert!.version; + + /// internal property + DerInteger? get serialNumber => _tbsCert!.serialNumber; + + /// internal property + X509Name? get issuer => _tbsCert!.issuer; + + /// internal property + X509Time? get startDate => _tbsCert!.startDate; + + /// internal property + X509Time? get endDate => _tbsCert!.endDate; + + /// internal property + X509Name? get subject => _tbsCert!.subject; + + /// internal property + PublicKeyInformation? get subjectPublicKeyInfo => + _tbsCert!.subjectPublicKeyInfo; + + /// internal property + Algorithms? get signatureAlgorithm => _sigAlgID; + + /// internal property + DerBitString? get signature => _sig; + //Implementation + /// internal method + static X509CertificateStructure? getInstance(dynamic obj) { + if (obj is X509CertificateStructure) { + return obj; + } + if (obj != null) { + return X509CertificateStructure(Asn1Sequence.getSequence(obj)!); + } + return null; + } + + @override + Asn1 getAsn1() { + return DerSequence(array: [_tbsCert, _sigAlgID, _sig]); + } +} + +/// Internal class +class SingnedCertificate extends Asn1Encode { + /// internal constructor + SingnedCertificate(Asn1Sequence sequence) { + int seqStart = 0; + _sequence = sequence; + if (sequence[0] is DerTag || sequence[0] is Asn1Tag) { + _version = DerInteger.getNumberFromTag(sequence[0]! as Asn1Tag, true); + } else { + seqStart = -1; + _version = DerInteger(bigIntToBytes(BigInt.from(0))); + } + _serialNumber = DerInteger.getNumber(sequence[seqStart + 1]); + _signature = Algorithms.getAlgorithms(sequence[seqStart + 2]); + _issuer = X509Name.getName(sequence[seqStart + 3]); + final Asn1Sequence dates = sequence[seqStart + 4]! as Asn1Sequence; + _startDate = X509Time.getTime(dates[0]); + _endDate = X509Time.getTime(dates[1]); + _subject = X509Name.getName(sequence[seqStart + 5]); + _publicKeyInformation = PublicKeyInformation.getPublicKeyInformation( + sequence[seqStart + 6], + ); + for ( + int extras = sequence.count - (seqStart + 6) - 1; + extras > 0; + extras-- + ) { + final Asn1Tag extra = sequence[seqStart + 6 + extras]! as Asn1Tag; + switch (extra.tagNumber) { + case 1: + _issuerID = DerBitString.getDerBitStringFromTag(extra, false); + break; + case 2: + _subjectID = DerBitString.getDerBitStringFromTag(extra, false); + break; + case 3: + _extensions = X509Extensions.getInstance(extra); + break; + } + } + } + + /// internal method + static SingnedCertificate? getCertificate(dynamic obj) { + if (obj is SingnedCertificate) { + return obj; + } + if (obj != null) { + return SingnedCertificate(Asn1Sequence.getSequence(obj)!); + } + return null; + } + + //Fields + Asn1Sequence? _sequence; + DerInteger? _version; + DerInteger? _serialNumber; + Algorithms? _signature; + X509Name? _issuer; + X509Time? _startDate; + X509Time? _endDate; + X509Name? _subject; + PublicKeyInformation? _publicKeyInformation; + DerBitString? _issuerID; + DerBitString? _subjectID; + X509Extensions? _extensions; + //Properties + /// internal field + int get version => _version!.value.toSigned(32).toInt() + 1; + + /// internal field + DerInteger? get serialNumber => _serialNumber; + + /// internal field + Algorithms? get signature => _signature; + + /// internal field + X509Name? get issuer => _issuer; + + /// internal field + X509Time? get startDate => _startDate; + + /// internal field + X509Time? get endDate => _endDate; + + /// internal field + X509Name? get subject => _subject; + + /// internal field + PublicKeyInformation? get subjectPublicKeyInfo => _publicKeyInformation; + + /// internal field + DerBitString? get issuerUniqueID => _issuerID; + + /// internal field + DerBitString? get subjectUniqueID => _subjectID; + + /// internal field + X509Extensions? get extensions => _extensions; + //Implementation + @override + Asn1? getAsn1() { + return _sequence; + } +} + +/// internal class +class PublicKeyInformation extends Asn1Encode { + /// internal constructor + PublicKeyInformation(Algorithms algorithms, Asn1Encode publicKey) { + _publicKey = DerBitString.fromAsn1(publicKey); + _algorithms = algorithms; + } + + /// internal constructor + PublicKeyInformation.fromSequence(Asn1Sequence sequence) { + if (sequence.count != 2) { + throw ArgumentError.value( + sequence, + 'sequence', + 'Invalid length in sequence', + ); + } + _algorithms = Algorithms.getAlgorithms(sequence[0]); + _publicKey = DerBitString.getDetBitString(sequence[1]); + } + + /// internal method + static PublicKeyInformation? getPublicKeyInformation(dynamic obj) { + if (obj is PublicKeyInformation) { + return obj; + } + if (obj != null) { + return PublicKeyInformation.fromSequence(Asn1Sequence.getSequence(obj)!); + } + return null; + } + + Algorithms? _algorithms; + DerBitString? _publicKey; + + /// internal property + Algorithms? get algorithm => _algorithms; + + /// internal property + DerBitString? get publicKey => _publicKey; + //Implementation + /// internal method + Asn1? getPublicKey() { + return Asn1Stream(PdfStreamReader(_publicKey!.getBytes())).readAsn1(); + } + + @override + Asn1 getAsn1() { + return DerSequence(array: [_algorithms, _publicKey]); + } +} + +/// internal class +class RsaPublicKey extends Asn1Encode { + /// internal constructor + RsaPublicKey(BigInt? modulus, BigInt? publicExponent) { + _modulus = modulus; + _publicExponent = publicExponent; + } + + /// internal constructor + RsaPublicKey.fromSequence(Asn1Sequence sequence) { + _modulus = DerInteger.getNumber(sequence[0])!.positiveValue; + _publicExponent = DerInteger.getNumber(sequence[1])!.positiveValue; + } + BigInt? _modulus; + BigInt? _publicExponent; + + /// internal property + BigInt? get modulus => _modulus; + + /// internal property + BigInt? get publicExponent => _publicExponent; + + /// internal method + static RsaPublicKey? getPublicKey(dynamic obj) { + RsaPublicKey? result; + if (obj == null || obj is RsaPublicKey) { + result = obj as RsaPublicKey?; + } else if (obj is Asn1Sequence) { + result = RsaPublicKey.fromSequence(obj); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + return result; + } + + @override + Asn1 getAsn1() { + return DerSequence( + array: [ + DerInteger.fromNumber(modulus), + DerInteger.fromNumber(publicExponent), + ], + ); + } +} + +/// internal class +class X509CertificateParser { + /// internal constructor + X509CertificateParser(); + //Fields + Asn1Set? _sData; + int? _sDataObjectCount; + PdfStreamReader? _currentStream; + //Implementation + /// internal method + X509Certificate? readCertificate(PdfStreamReader inStream) { + if (_currentStream == null || _currentStream != inStream) { + _currentStream = inStream; + _sData = null; + _sDataObjectCount = 0; + } + if (_sData != null) { + if (_sDataObjectCount != _sData!.objects.length) { + return getCertificate(); + } + _sData = null; + _sDataObjectCount = 0; + return null; + } + final _PushStream pis = _PushStream(inStream); + final int tag = pis.readByte()!; + if (tag < 0) { + return null; + } + pis.unread(tag); + return readDerCertificate(Asn1Stream(pis)); + } + + /// Internal method + List? getCertificateChain(PdfStreamReader inStream) { + if (_currentStream == null || _currentStream != inStream) { + _currentStream = inStream; + _sData = null; + _sDataObjectCount = 0; + } + if (_sData != null) { + if (_sDataObjectCount != _sData!.objects.length) { + return _getCertificateChain(); + } + _sData = null; + _sDataObjectCount = 0; + return null; + } + final _PushStream pis = _PushStream(inStream); + final int tag = pis.readByte()!; + if (tag < 0) { + return null; + } + pis.unread(tag); + return _readDerCertificates(Asn1Stream(pis)); + } + + /// internal method + X509Certificate? getCertificate() { + if (_sData != null) { + while (_sDataObjectCount! < _sData!.objects.length) { + final dynamic obj = _sData![_sDataObjectCount!]; + _sDataObjectCount = _sDataObjectCount! + 1; + if (obj is Asn1Sequence) { + return createX509Certificate( + X509CertificateStructure.getInstance(obj), + ); + } + } + } + return null; + } + + /// internal method + X509Certificate? readDerCertificate(Asn1Stream dIn) { + final dynamic seq = dIn.readAsn1(); + if (seq != null && seq is Asn1Sequence) { + if (seq.count > 1 && seq[0] is DerObjectID) { + if ((seq[0]! as DerObjectID).id == PkcsObjectId.signedData.id) { + if (seq.count >= 2) { + final Asn1Sequence signedSequence = + Asn1Sequence.getSequence(seq[1] as Asn1Tag?, true)!; + bool isContinue = true; + // ignore: avoid_function_literals_in_foreach_calls + signedSequence.objects!.forEach((dynamic o) { + if (isContinue && o is Asn1Tag) { + if (o.tagNumber == 0) { + _sData = Asn1Set.getAsn1Set(o, false); + isContinue = false; + } + } + }); + } + return getCertificate(); + } + } + } + return createX509Certificate(X509CertificateStructure.getInstance(seq)); + } + + List? _getCertificateChain() { + final List certList = []; + if (_sData != null) { + while (_sDataObjectCount! < _sData!.objects.length) { + final dynamic obj = _sData![_sDataObjectCount!]; + _sDataObjectCount = _sDataObjectCount! + 1; + if (obj is Asn1Sequence) { + certList.add( + createX509Certificate(X509CertificateStructure.getInstance(obj)), + ); + } + } + } + return certList.isNotEmpty ? certList : null; + } + + /// internal method + List? _readDerCertificates(Asn1Stream dIn) { + final dynamic seq = dIn.readAsn1(); + if (seq != null && seq is Asn1Sequence) { + if (seq.count > 1 && seq[0] is DerObjectID) { + if ((seq[0]! as DerObjectID).id == PkcsObjectId.signedData.id) { + if (seq.count >= 2) { + final Asn1Sequence signedSequence = + Asn1Sequence.getSequence(seq[1] as Asn1Tag?, true)!; + bool isContinue = true; + // ignore: avoid_function_literals_in_foreach_calls + signedSequence.objects!.forEach((dynamic o) { + if (isContinue && o is Asn1Tag) { + if (o.tagNumber == 0) { + _sData = Asn1Set.getAsn1Set(o, false); + isContinue = false; + } + } + }); + } + return _getCertificateChain(); + } + } + } + return [ + createX509Certificate(X509CertificateStructure.getInstance(seq)), + ]; + } + + /// internal method + X509Certificate createX509Certificate(X509CertificateStructure? c) { + return X509Certificate(c); + } +} + +class _PushStream extends PdfStreamReader { + _PushStream(PdfStreamReader stream) : super(stream.data) { + _stream = stream; + _buffer = -1; + } + //Fields + late PdfStreamReader _stream; + int? _buffer; + @override + int get position => _stream.position; + @override + set position(int value) { + _stream.position = value; + } + + //Implementation + @override + int? readByte() { + if (_buffer != -1) { + final int? temp = _buffer; + _buffer = -1; + return temp; + } + return _stream.readByte(); + } + + @override + int? read(List buffer, int offset, int count) { + if (_buffer != -1) { + final int? temp = _buffer; + _buffer = -1; + return temp; + } + return _stream.read(buffer, offset, count); + } + + void unread(int b) { + _buffer = b & 0xFF; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_name.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_name.dart index e7428e74e..d3f6a00a3 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_name.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_name.dart @@ -1,291 +1,291 @@ -import '../asn1/asn1.dart'; -import '../asn1/der.dart'; -import '../pkcs/pfx_data.dart'; - -/// internal class -class X509Name extends Asn1Encode { - /// internal constructor - X509Name(Asn1Sequence sequence) { - _initialize(); - _sequence = sequence; - // ignore: avoid_function_literals_in_foreach_calls - sequence.objects!.forEach((dynamic encode) { - final Asn1Set asn1Set = Asn1Set.getAsn1Set(encode.getAsn1())!; - for (int i = 0; i < asn1Set.objects.length; i++) { - final Asn1Sequence asn1Sequence = - Asn1Sequence.getSequence(asn1Set[i]!.getAsn1())!; - if (asn1Sequence.count != 2) { - throw ArgumentError.value( - sequence, - 'sequence', - 'Invalid length in sequence', - ); - } - _ordering.add(DerObjectID.getID(asn1Sequence[0]!.getAsn1())); - final Asn1? asn1 = asn1Sequence[1]!.getAsn1(); - if (asn1 is IAsn1String) { - String value = (asn1! as IAsn1String).getString()!; - if (value.startsWith('#')) { - value = r'\' + value; - } - _values.add(value); - } - _added.add(i != 0); - } - }); - } - - /// internal field - static DerObjectID c = DerObjectID('2.5.4.6'); - - /// internal field - static DerObjectID o = DerObjectID('2.5.4.10'); - - /// internal field - static DerObjectID ou = DerObjectID('2.5.4.11'); - - /// internal field - static DerObjectID t = DerObjectID('2.5.4.12'); - - /// internal field - static DerObjectID cn = DerObjectID('2.5.4.3'); - - /// internal field - static DerObjectID street = DerObjectID('2.5.4.9'); - - /// internal field - static DerObjectID serialNumber = DerObjectID('2.5.4.5'); - - /// internal field - static DerObjectID l = DerObjectID('2.5.4.7'); - - /// internal field - static DerObjectID st = DerObjectID('2.5.4.8'); - - /// internal field - static DerObjectID surname = DerObjectID('2.5.4.4'); - - /// internal field - static DerObjectID givenName = DerObjectID('2.5.4.42'); - - /// internal field - static DerObjectID initials = DerObjectID('2.5.4.43'); - - /// internal field - static DerObjectID generation = DerObjectID('2.5.4.44'); - - /// internal field - static DerObjectID uniqueIdentifier = DerObjectID('2.5.4.45'); - - /// internal field - static DerObjectID businessCategory = DerObjectID('2.5.4.15'); - - /// internal field - static DerObjectID postalCode = DerObjectID('2.5.4.17'); - - /// internal field - static DerObjectID dnQualifier = DerObjectID('2.5.4.46'); - - /// internal field - static DerObjectID pseudonym = DerObjectID('2.5.4.65'); - - /// internal field - static DerObjectID dateOfBirth = DerObjectID('1.3.6.1.5.5.7.9.1'); - - /// internal field - static DerObjectID placeOfBirth = DerObjectID('1.3.6.1.5.5.7.9.2'); - - /// internal field - static DerObjectID gender = DerObjectID('1.3.6.1.5.5.7.9.3'); - - /// internal field - static DerObjectID countryOfCitizenship = DerObjectID('1.3.6.1.5.5.7.9.4'); - - /// internal field - static DerObjectID countryOfResidence = DerObjectID('1.3.6.1.5.5.7.9.5'); - - /// internal field - static DerObjectID nameAtBirth = DerObjectID('1.3.36.8.3.14'); - - /// internal field - static DerObjectID postalAddress = DerObjectID('2.5.4.16'); - - /// internal field - static DerObjectID telephoneNumber = X509Objects.telephoneNumberID; - - /// internal field - static DerObjectID emailAddress = PkcsObjectId.pkcs9AtEmailAddress; - - /// internal field - static DerObjectID unstructuredName = PkcsObjectId.pkcs9AtUnstructuredName; - - /// internal field - static DerObjectID unstructuredAddress = - PkcsObjectId.pkcs9AtUnstructuredAddress; - - /// internal field - static DerObjectID dc = DerObjectID('0.9.2342.19200300.100.1.25'); - - /// internal field - static DerObjectID uid = DerObjectID('0.9.2342.19200300.100.1.1'); - final List _ordering = []; - final List _values = []; - final List _added = []; - final Map _defaultSymbols = {}; - Asn1Sequence? _sequence; - - /// internal property - static X509Name? getName(dynamic obj, [bool? isExplicit]) { - X509Name? result; - if (obj is Asn1Tag && isExplicit != null) { - result = getName(Asn1Sequence.getSequence(obj, isExplicit)); - } else { - if (obj == null || obj is X509Name) { - result = obj as X509Name?; - } else if (obj != null) { - result = X509Name(Asn1Sequence.getSequence(obj)!); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - } - return result; - } - - void _initialize() { - _defaultSymbols[c] = 'C'; - _defaultSymbols[o] = 'O'; - _defaultSymbols[t] = 'T'; - _defaultSymbols[ou] = 'OU'; - _defaultSymbols[cn] = 'CN'; - _defaultSymbols[l] = 'L'; - _defaultSymbols[st] = 'ST'; - _defaultSymbols[serialNumber] = 'SERIALNUMBER'; - _defaultSymbols[emailAddress] = 'E'; - _defaultSymbols[dc] = 'DC'; - _defaultSymbols[uid] = 'UID'; - _defaultSymbols[street] = 'STREET'; - _defaultSymbols[surname] = 'SURNAME'; - _defaultSymbols[givenName] = 'GIVENNAME'; - _defaultSymbols[initials] = 'INITIALS'; - _defaultSymbols[generation] = 'GENERATION'; - _defaultSymbols[unstructuredAddress] = 'unstructuredAddress'; - _defaultSymbols[unstructuredName] = 'unstructuredName'; - _defaultSymbols[uniqueIdentifier] = 'UniqueIdentifier'; - _defaultSymbols[dnQualifier] = 'DN'; - _defaultSymbols[pseudonym] = 'Pseudonym'; - _defaultSymbols[postalAddress] = 'PostalAddress'; - _defaultSymbols[nameAtBirth] = 'NameAtBirth'; - _defaultSymbols[countryOfCitizenship] = 'CountryOfCitizenship'; - _defaultSymbols[countryOfResidence] = 'CountryOfResidence'; - _defaultSymbols[gender] = 'Gender'; - _defaultSymbols[placeOfBirth] = 'PlaceOfBirth'; - _defaultSymbols[dateOfBirth] = 'DateOfBirth'; - _defaultSymbols[postalCode] = 'PostalCode'; - _defaultSymbols[businessCategory] = 'BusinessCategory'; - _defaultSymbols[telephoneNumber] = 'TelephoneNumber'; - } - - @override - Asn1? getAsn1() { - if (_sequence == null) { - final Asn1EncodeCollection collection1 = Asn1EncodeCollection(); - Asn1EncodeCollection collection2 = Asn1EncodeCollection(); - DerObjectID? lstOid; - for (int i = 0; i != _ordering.length; i++) { - final DerObjectID? oid = _ordering[i] as DerObjectID?; - if (lstOid != null && !(_added[i] as bool)) { - collection1.encodableObjects.add(DerSet(collection: collection2)); - collection2 = Asn1EncodeCollection(); - } - lstOid = oid; - } - collection1.encodableObjects.add(DerSet(collection: collection2)); - _sequence = DerSequence(collection: collection1); - } - return _sequence; - } - - /// internal method - String getString(bool isReverse, Map symbols) { - List components = []; - String result = ''; - for (int i = 0; i < _ordering.length; i++) { - if (_added[i] as bool) { - result = '+'; - result = appendValue( - result, - symbols, - _ordering[i] as DerObjectID?, - _values[i], - ); - } else { - result = ''; - result = appendValue( - result, - symbols, - _ordering[i] as DerObjectID?, - _values[i], - ); - components.add(result); - } - } - if (isReverse) { - components = components.reversed.toList(); - } - String buf = ''; - if (components.isNotEmpty) { - buf += components[0].toString(); - for (int i = 1; i < components.length; ++i) { - buf += ','; - buf += components[i].toString(); - } - } - return buf; - } - - /// internal method - String appendValue( - String builder, - Map symbols, - DerObjectID? id, - String value, - ) { - final String? symbol = symbols[id!]; - if (symbol != null) { - builder += symbol; - } else { - builder += id.id!; - } - builder += '='; - int index = builder.length; - builder += value; - int end = builder.length; - if (value.startsWith(r'\#')) { - index += 2; - } - while (index != end) { - if ((builder[index] == ',') || - (builder[index] == '"') || - (builder[index] == r'\') || - (builder[index] == '+') || - (builder[index] == '=') || - (builder[index] == '<') || - (builder[index] == '>') || - (builder[index] == ';')) { - builder = - builder.substring(0, index) + - r'\' + - builder.substring(index, builder.length); - index++; - end++; - } - index++; - } - return builder; - } - - @override - String toString() { - return getString(false, _defaultSymbols); - } -} +import '../asn1/asn1.dart'; +import '../asn1/der.dart'; +import '../pkcs/pfx_data.dart'; + +/// internal class +class X509Name extends Asn1Encode { + /// internal constructor + X509Name(Asn1Sequence sequence) { + _initialize(); + _sequence = sequence; + // ignore: avoid_function_literals_in_foreach_calls + sequence.objects!.forEach((dynamic encode) { + final Asn1Set asn1Set = Asn1Set.getAsn1Set(encode.getAsn1())!; + for (int i = 0; i < asn1Set.objects.length; i++) { + final Asn1Sequence asn1Sequence = + Asn1Sequence.getSequence(asn1Set[i]!.getAsn1())!; + if (asn1Sequence.count != 2) { + throw ArgumentError.value( + sequence, + 'sequence', + 'Invalid length in sequence', + ); + } + _ordering.add(DerObjectID.getID(asn1Sequence[0]!.getAsn1())); + final Asn1? asn1 = asn1Sequence[1]!.getAsn1(); + if (asn1 is IAsn1String) { + String value = (asn1! as IAsn1String).getString()!; + if (value.startsWith('#')) { + value = r'\' + value; + } + _values.add(value); + } + _added.add(i != 0); + } + }); + } + + /// internal field + static DerObjectID c = DerObjectID('2.5.4.6'); + + /// internal field + static DerObjectID o = DerObjectID('2.5.4.10'); + + /// internal field + static DerObjectID ou = DerObjectID('2.5.4.11'); + + /// internal field + static DerObjectID t = DerObjectID('2.5.4.12'); + + /// internal field + static DerObjectID cn = DerObjectID('2.5.4.3'); + + /// internal field + static DerObjectID street = DerObjectID('2.5.4.9'); + + /// internal field + static DerObjectID serialNumber = DerObjectID('2.5.4.5'); + + /// internal field + static DerObjectID l = DerObjectID('2.5.4.7'); + + /// internal field + static DerObjectID st = DerObjectID('2.5.4.8'); + + /// internal field + static DerObjectID surname = DerObjectID('2.5.4.4'); + + /// internal field + static DerObjectID givenName = DerObjectID('2.5.4.42'); + + /// internal field + static DerObjectID initials = DerObjectID('2.5.4.43'); + + /// internal field + static DerObjectID generation = DerObjectID('2.5.4.44'); + + /// internal field + static DerObjectID uniqueIdentifier = DerObjectID('2.5.4.45'); + + /// internal field + static DerObjectID businessCategory = DerObjectID('2.5.4.15'); + + /// internal field + static DerObjectID postalCode = DerObjectID('2.5.4.17'); + + /// internal field + static DerObjectID dnQualifier = DerObjectID('2.5.4.46'); + + /// internal field + static DerObjectID pseudonym = DerObjectID('2.5.4.65'); + + /// internal field + static DerObjectID dateOfBirth = DerObjectID('1.3.6.1.5.5.7.9.1'); + + /// internal field + static DerObjectID placeOfBirth = DerObjectID('1.3.6.1.5.5.7.9.2'); + + /// internal field + static DerObjectID gender = DerObjectID('1.3.6.1.5.5.7.9.3'); + + /// internal field + static DerObjectID countryOfCitizenship = DerObjectID('1.3.6.1.5.5.7.9.4'); + + /// internal field + static DerObjectID countryOfResidence = DerObjectID('1.3.6.1.5.5.7.9.5'); + + /// internal field + static DerObjectID nameAtBirth = DerObjectID('1.3.36.8.3.14'); + + /// internal field + static DerObjectID postalAddress = DerObjectID('2.5.4.16'); + + /// internal field + static DerObjectID telephoneNumber = X509Objects.telephoneNumberID; + + /// internal field + static DerObjectID emailAddress = PkcsObjectId.pkcs9AtEmailAddress; + + /// internal field + static DerObjectID unstructuredName = PkcsObjectId.pkcs9AtUnstructuredName; + + /// internal field + static DerObjectID unstructuredAddress = + PkcsObjectId.pkcs9AtUnstructuredAddress; + + /// internal field + static DerObjectID dc = DerObjectID('0.9.2342.19200300.100.1.25'); + + /// internal field + static DerObjectID uid = DerObjectID('0.9.2342.19200300.100.1.1'); + final List _ordering = []; + final List _values = []; + final List _added = []; + final Map _defaultSymbols = {}; + Asn1Sequence? _sequence; + + /// internal property + static X509Name? getName(dynamic obj, [bool? isExplicit]) { + X509Name? result; + if (obj is Asn1Tag && isExplicit != null) { + result = getName(Asn1Sequence.getSequence(obj, isExplicit)); + } else { + if (obj == null || obj is X509Name) { + result = obj as X509Name?; + } else if (obj != null) { + result = X509Name(Asn1Sequence.getSequence(obj)!); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + } + return result; + } + + void _initialize() { + _defaultSymbols[c] = 'C'; + _defaultSymbols[o] = 'O'; + _defaultSymbols[t] = 'T'; + _defaultSymbols[ou] = 'OU'; + _defaultSymbols[cn] = 'CN'; + _defaultSymbols[l] = 'L'; + _defaultSymbols[st] = 'ST'; + _defaultSymbols[serialNumber] = 'SERIALNUMBER'; + _defaultSymbols[emailAddress] = 'E'; + _defaultSymbols[dc] = 'DC'; + _defaultSymbols[uid] = 'UID'; + _defaultSymbols[street] = 'STREET'; + _defaultSymbols[surname] = 'SURNAME'; + _defaultSymbols[givenName] = 'GIVENNAME'; + _defaultSymbols[initials] = 'INITIALS'; + _defaultSymbols[generation] = 'GENERATION'; + _defaultSymbols[unstructuredAddress] = 'unstructuredAddress'; + _defaultSymbols[unstructuredName] = 'unstructuredName'; + _defaultSymbols[uniqueIdentifier] = 'UniqueIdentifier'; + _defaultSymbols[dnQualifier] = 'DN'; + _defaultSymbols[pseudonym] = 'Pseudonym'; + _defaultSymbols[postalAddress] = 'PostalAddress'; + _defaultSymbols[nameAtBirth] = 'NameAtBirth'; + _defaultSymbols[countryOfCitizenship] = 'CountryOfCitizenship'; + _defaultSymbols[countryOfResidence] = 'CountryOfResidence'; + _defaultSymbols[gender] = 'Gender'; + _defaultSymbols[placeOfBirth] = 'PlaceOfBirth'; + _defaultSymbols[dateOfBirth] = 'DateOfBirth'; + _defaultSymbols[postalCode] = 'PostalCode'; + _defaultSymbols[businessCategory] = 'BusinessCategory'; + _defaultSymbols[telephoneNumber] = 'TelephoneNumber'; + } + + @override + Asn1? getAsn1() { + if (_sequence == null) { + final Asn1EncodeCollection collection1 = Asn1EncodeCollection(); + Asn1EncodeCollection collection2 = Asn1EncodeCollection(); + DerObjectID? lstOid; + for (int i = 0; i != _ordering.length; i++) { + final DerObjectID? oid = _ordering[i] as DerObjectID?; + if (lstOid != null && !(_added[i] as bool)) { + collection1.encodableObjects.add(DerSet(collection: collection2)); + collection2 = Asn1EncodeCollection(); + } + lstOid = oid; + } + collection1.encodableObjects.add(DerSet(collection: collection2)); + _sequence = DerSequence(collection: collection1); + } + return _sequence; + } + + /// internal method + String getString(bool isReverse, Map symbols) { + List components = []; + String result = ''; + for (int i = 0; i < _ordering.length; i++) { + if (_added[i] as bool) { + result = '+'; + result = appendValue( + result, + symbols, + _ordering[i] as DerObjectID?, + _values[i], + ); + } else { + result = ''; + result = appendValue( + result, + symbols, + _ordering[i] as DerObjectID?, + _values[i], + ); + components.add(result); + } + } + if (isReverse) { + components = components.reversed.toList(); + } + String buf = ''; + if (components.isNotEmpty) { + buf += components[0].toString(); + for (int i = 1; i < components.length; ++i) { + buf += ','; + buf += components[i].toString(); + } + } + return buf; + } + + /// internal method + String appendValue( + String builder, + Map symbols, + DerObjectID? id, + String value, + ) { + final String? symbol = symbols[id!]; + if (symbol != null) { + builder += symbol; + } else { + builder += id.id!; + } + builder += '='; + int index = builder.length; + builder += value; + int end = builder.length; + if (value.startsWith(r'\#')) { + index += 2; + } + while (index != end) { + if ((builder[index] == ',') || + (builder[index] == '"') || + (builder[index] == r'\') || + (builder[index] == '+') || + (builder[index] == '=') || + (builder[index] == '<') || + (builder[index] == '>') || + (builder[index] == ';')) { + builder = + builder.substring(0, index) + + r'\' + + builder.substring(index, builder.length); + index++; + end++; + } + index++; + } + return builder; + } + + @override + String toString() { + return getString(false, _defaultSymbols); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_time.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_time.dart index f31c67b15..178a04737 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_time.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/digital_signature/x509/x509_time.dart @@ -1,59 +1,59 @@ -import '../asn1/asn1.dart'; -import '../asn1/der.dart'; - -/// internal class -class X509Time extends Asn1Encode { - /// internal constructor - X509Time(Asn1 time) { - _time = time; - } - Asn1? _time; - - /// internal method - static X509Time? getTime(dynamic obj) { - X509Time? result; - if (obj == null || obj is X509Time) { - result = obj as X509Time?; - } else if (obj is DerUtcTime) { - result = X509Time(obj); - } else if (obj is GeneralizedTime) { - result = X509Time(obj); - } else { - throw ArgumentError.value(obj, 'obj', 'Invalid entry'); - } - return result; - } - - /// internal method - DateTime? toDateTime() { - DateTime? result; - try { - if (_time is DerUtcTime) { - result = (_time! as DerUtcTime).toAdjustedDateTime; - } else if (_time is GeneralizedTime) { - result = (_time! as GeneralizedTime).toDateTime(); - } else { - result = DateTime.now(); - } - } catch (e) { - throw ArgumentError.value(result, 'DateTime', 'Invalid entry'); - } - return result; - } - - @override - Asn1? getAsn1() { - return _time; - } - - @override - String toString() { - if (_time is DerUtcTime) { - return (_time! as DerUtcTime).adjustedTimeString; - } else if (_time is GeneralizedTime) { - return (_time! as GeneralizedTime).time; - } else { - return ''; - } - } -} +import '../asn1/asn1.dart'; +import '../asn1/der.dart'; + +/// internal class +class X509Time extends Asn1Encode { + /// internal constructor + X509Time(Asn1 time) { + _time = time; + } + Asn1? _time; + + /// internal method + static X509Time? getTime(dynamic obj) { + X509Time? result; + if (obj == null || obj is X509Time) { + result = obj as X509Time?; + } else if (obj is DerUtcTime) { + result = X509Time(obj); + } else if (obj is GeneralizedTime) { + result = X509Time(obj); + } else { + throw ArgumentError.value(obj, 'obj', 'Invalid entry'); + } + return result; + } + + /// internal method + DateTime? toDateTime() { + DateTime? result; + try { + if (_time is DerUtcTime) { + result = (_time! as DerUtcTime).toAdjustedDateTime; + } else if (_time is GeneralizedTime) { + result = (_time! as GeneralizedTime).toDateTime(); + } else { + result = DateTime.now(); + } + } catch (e) { + throw ArgumentError.value(result, 'DateTime', 'Invalid entry'); + } + return result; + } + + @override + Asn1? getAsn1() { + return _time; + } + + @override + String toString() { + if (_time is DerUtcTime) { + return (_time! as DerUtcTime).adjustedTimeString; + } else if (_time is GeneralizedTime) { + return (_time! as GeneralizedTime).time; + } else { + return ''; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/enum.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/enum.dart index 4eb93ad7b..e072aec1b 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/enum.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/enum.dart @@ -1,95 +1,95 @@ -/// Specifies the encryption option. -enum PdfEncryptionOptions { - /// To encrypt all the document contents. - encryptAllContents, - - /// To encrypt all the document contents except metadata. - encryptAllContentsExceptMetadata, - - /// To encrypt atttachment files only. - encryptOnlyAttachments, -} - -/// Specifies the type of encryption algorithm. -enum PdfEncryptionAlgorithm { - /// RC4 encryption algorithm - 40-bit key. - rc4x40Bit, - - /// RC4 encryption algorithm - 128-bit key. - rc4x128Bit, - - /// AES encryption algorithm - 128-bit key. - aesx128Bit, - - /// AES encryption algorithm - 256-bit key. - aesx256Bit, - - /// AES encryption algorithm - 256-bit key with revision 6. - aesx256BitRevision6, -} - -/// Specifies the type of PDF permissions. -enum PdfPermissionsFlags { - /// Default value. - none, - - /// Print the document. - print, - - /// Edit content. - editContent, - - /// Copy content. - copyContent, - - /// Add or modify text annotations, fill in interactive form fields. - editAnnotations, - - /// Fill form fields. (Only for 128 bits key). - fillFields, - - /// Copy accessibility content. - accessibilityCopyContent, - - /// Assemble document permission. (Only for 128 bits key). - assembleDocument, - - /// Full quality print. - fullQualityPrint, -} - -/// Specifies the available permissions on certificated document. -enum PdfCertificationFlags { - /// Restrict any changes to the document. - forbidChanges, - - /// Only allow form fill-in actions on this document. - allowFormFill, - - /// Only allow commenting and form fill-in actions on this document. - allowComments, -} - -/// Specifies the cryptographic standard. -enum CryptographicStandard { - /// Cryptographic Message Syntax - cms, - - /// CMS Advanced Electronic Signatures - cades, -} - -/// Specifies the digestion algorithm. -enum DigestAlgorithm { - /// SHA1 message digest algorithm - sha1, - - /// SHA256 message digest algorithm - sha256, - - /// SHA384 message digest algorithm - sha384, - - /// SHA512 message digest algorithm - sha512, -} +/// Specifies the encryption option. +enum PdfEncryptionOptions { + /// To encrypt all the document contents. + encryptAllContents, + + /// To encrypt all the document contents except metadata. + encryptAllContentsExceptMetadata, + + /// To encrypt atttachment files only. + encryptOnlyAttachments, +} + +/// Specifies the type of encryption algorithm. +enum PdfEncryptionAlgorithm { + /// RC4 encryption algorithm - 40-bit key. + rc4x40Bit, + + /// RC4 encryption algorithm - 128-bit key. + rc4x128Bit, + + /// AES encryption algorithm - 128-bit key. + aesx128Bit, + + /// AES encryption algorithm - 256-bit key. + aesx256Bit, + + /// AES encryption algorithm - 256-bit key with revision 6. + aesx256BitRevision6, +} + +/// Specifies the type of PDF permissions. +enum PdfPermissionsFlags { + /// Default value. + none, + + /// Print the document. + print, + + /// Edit content. + editContent, + + /// Copy content. + copyContent, + + /// Add or modify text annotations, fill in interactive form fields. + editAnnotations, + + /// Fill form fields. (Only for 128 bits key). + fillFields, + + /// Copy accessibility content. + accessibilityCopyContent, + + /// Assemble document permission. (Only for 128 bits key). + assembleDocument, + + /// Full quality print. + fullQualityPrint, +} + +/// Specifies the available permissions on certificated document. +enum PdfCertificationFlags { + /// Restrict any changes to the document. + forbidChanges, + + /// Only allow form fill-in actions on this document. + allowFormFill, + + /// Only allow commenting and form fill-in actions on this document. + allowComments, +} + +/// Specifies the cryptographic standard. +enum CryptographicStandard { + /// Cryptographic Message Syntax + cms, + + /// CMS Advanced Electronic Signatures + cades, +} + +/// Specifies the digestion algorithm. +enum DigestAlgorithm { + /// SHA1 message digest algorithm + sha1, + + /// SHA256 message digest algorithm + sha256, + + /// SHA384 message digest algorithm + sha384, + + /// SHA512 message digest algorithm + sha512, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart index 93a2f0c96..910078621 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_encryptor.dart @@ -1,1981 +1,1757 @@ -import 'dart:convert'; -import 'dart:math'; -import 'dart:typed_data'; - -import 'package:crypto/crypto.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_cross_table.dart'; -import '../primitives/pdf_array.dart'; -import '../primitives/pdf_boolean.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_number.dart'; -import '../primitives/pdf_string.dart'; -import 'digital_signature/cryptography/aes_cipher.dart'; -import 'digital_signature/cryptography/aes_engine.dart'; -import 'digital_signature/cryptography/buffered_block_padding_base.dart'; -import 'digital_signature/cryptography/cipher_block_chaining_mode.dart'; -import 'digital_signature/cryptography/ipadding.dart'; -import 'enum.dart'; - -/// internal class -class PdfEncryptor { - /// internal constructor - PdfEncryptor() { - _initialize(); - } - - //Fields - int? _stringLength; - int? _revisionNumber40Bit; - int? _revisionNumber128Bit; - int? _ownerLoopNum2; - int? _ownerLoopNum; - - /// internal field - List? paddingBytes; - int? _bytesAmount; - int? _permissionSet; - int? _permissionCleared; - int? _permissionRevisionTwoMask; - int? _revisionNumberOut; - int? _versionNumberOut; - int? _permissionValue; - List? _randomBytes; - int? _key40; - int? _key128; - int? _key256; - int? _randomBytesAmount; - int? _newKeyOffset; - - /// internal field - bool? isEncrypt; - - /// internal field - bool? changed; - - /// internal field - bool? hasComputedPasswordValues; - - /// internal field - PdfEncryptionAlgorithm? encryptionAlgorithm; - List? _permissions; - int? _revision; - String? _userPassword; - String? _ownerPassword; - List? _ownerPasswordOut; - List? _userPasswordOut; - List? _encryptionKey; - - /// internal field - int? keyLength; - - /// internal field - List? customArray; - List? _permissionFlagValues; - List? _fileEncryptionKey; - List? _userEncryptionKeyOut; - List? _ownerEncryptionKeyOut; - List? _permissionFlag; - List? _userRandomBytes; - List? _ownerRandomBytes; - - /// internal field - bool? encryptOnlyMetadata; - - /// internal field - bool? encryptAttachmentOnly; - - /// internal field - late PdfEncryptionOptions encryptionOptions; - - //Properties - /// internal property - int? get revisionNumber { - return _revision == 0 - ? (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit - ? (_revisionNumberOut! > 2 - ? _revisionNumberOut - : _revisionNumber40Bit) - : _revisionNumber128Bit) - : _revision; - } - - /// internal property - List? get randomBytes { - if (_randomBytes == null) { - final Random random = Random.secure(); - _randomBytes = List.generate( - _randomBytesAmount!, - (int i) => random.nextInt(256), - ); - } - return _randomBytes; - } - - /// internal property - List get permissions { - return _permissions!; - } - - set permissions(List value) { - changed = true; - _permissions = value; - _permissionValue = - (_getPermissionValue(_permissions!) | _permissionSet!) & - _permissionCleared!; - if (revisionNumber! > 2) { - _permissionValue = _permissionValue! & _permissionRevisionTwoMask!; - } - hasComputedPasswordValues = false; - } - - /// internal property - bool get encrypt { - final List perm = permissions; - final bool bEncrypt = - (!(perm.length == 1 && perm.contains(PdfPermissionsFlags.none))) || - _userPassword!.isNotEmpty || - _ownerPassword!.isNotEmpty; - return isEncrypt! && bEncrypt; - } - - set encrypt(bool value) { - isEncrypt = value; - } - - /// internal property - String get userPassword { - return _userPassword!; - } - - set userPassword(String value) { - if (_userPassword != value) { - changed = true; - _userPassword = value; - hasComputedPasswordValues = false; - } - } - - /// internal property - String get ownerPassword { - if (encryptAttachmentOnly!) { - return ''; - } - return _ownerPassword!; - } - - set ownerPassword(String value) { - if (_ownerPassword != value) { - changed = true; - _ownerPassword = value; - hasComputedPasswordValues = false; - } - } - - /// internal property - bool get encryptOnlyAttachment { - return encryptAttachmentOnly!; - } - - set encryptOnlyAttachment(bool value) { - encryptAttachmentOnly = value; - hasComputedPasswordValues = false; - } - - /// internal property - bool get encryptMetadata { - return encryptOnlyMetadata!; - } - - set encryptMetadata(bool value) { - hasComputedPasswordValues = false; - encryptOnlyMetadata = value; - } - - /// internal property - List? get ownerPasswordOut { - _initializeData(); - return _ownerPasswordOut; - } - - /// internal property - List? get userPasswordOut { - _initializeData(); - return _userPasswordOut; - } - - /// internal property - PdfArray get fileID { - final PdfString str = PdfString.fromBytes(randomBytes); - final PdfArray array = PdfArray(); - array.add(str); - array.add(str); - return array; - } - - //implementation - void _initialize() { - _key40 = 5; - _key128 = 16; - _key256 = 32; - _newKeyOffset = 5; - _userPassword = ''; - _ownerPassword = ''; - _stringLength = 32; - _revisionNumber40Bit = 2; - _revisionNumber128Bit = 3; - _revisionNumberOut = 0; - _versionNumberOut = 0; - _ownerLoopNum2 = 20; - _ownerLoopNum = 50; - _bytesAmount = 256; - _randomBytesAmount = 16; - keyLength = 0; - isEncrypt = true; - _permissionSet = ~0x00f3f; - _permissionCleared = ~0x3; - _permissionRevisionTwoMask = 0xfff; - _revision = 0; - encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x128Bit; - _permissionFlagValues = [ - 0x000000, - 0x000004, - 0x000008, - 0x000010, - 0x000020, - 0x000100, - 0x000200, - 0x000400, - 0x000800, - ]; - permissions = [PdfPermissionsFlags.none]; - encryptionOptions = PdfEncryptionOptions.encryptAllContents; - paddingBytes = [ - 40, - 191, - 78, - 94, - 78, - 117, - 138, - 65, - 100, - 0, - 78, - 86, - 255, - 250, - 1, - 8, - 46, - 46, - 0, - 182, - 208, - 104, - 62, - 128, - 47, - 12, - 169, - 254, - 100, - 83, - 105, - 122, - ]; - customArray = List.filled(_bytesAmount!, 0, growable: true); - changed = false; - hasComputedPasswordValues = false; - encryptOnlyMetadata = true; - encryptAttachmentOnly = false; - } - - void _initializeData() { - if (!hasComputedPasswordValues!) { - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { - _userPasswordOut = _create256BitUserPassword(); - _ownerPasswordOut = _create256BitOwnerPassword(); - _createFileEncryptionKey(); - _userEncryptionKeyOut = _createUserEncryptionKey(); - _ownerEncryptionKeyOut = _createOwnerEncryptionKey(); - _permissionFlag = _createPermissionFlag(); - } else if (encryptionAlgorithm == - PdfEncryptionAlgorithm.aesx256BitRevision6) { - _createFileEncryptionKey(); - _createAcrobatX256BitUserPassword(); - _createAcrobatX256BitOwnerPassword(); - _permissionFlag = _createPermissionFlag(); - } else { - _ownerPasswordOut = _createOwnerPassword(); - _encryptionKey = _createEncryptionKey(userPassword, _ownerPasswordOut!); - _userPasswordOut = _createUserPassword(); - } - hasComputedPasswordValues = true; - } - } - - List _createUserPassword() { - return revisionNumber == 2 - ? _create40BitUserPassword() - : _create128BitUserPassword(); - } - - List _create40BitUserPassword() { - ArgumentError.checkNotNull(_encryptionKey); - return _encryptDataByCustom( - List.from(paddingBytes!), - _encryptionKey, - _encryptionKey!.length, - ); - } - - List _create128BitUserPassword() { - ArgumentError.checkNotNull(_encryptionKey); - final List data = []; - data.addAll(paddingBytes!); - data.addAll(randomBytes!); - final List resultBytes = md5.convert(data).bytes; - final List dataForCustom = List.generate( - _randomBytesAmount!, - (int i) => resultBytes[i], - ); - List dataFromCustom = _encryptDataByCustom( - dataForCustom, - _encryptionKey, - _encryptionKey!.length, - ); - for (int i = 1; i < _ownerLoopNum2!; i++) { - final List currentKey = _getKeyWithOwnerPassword(_encryptionKey!, i); - dataFromCustom = _encryptDataByCustom( - dataFromCustom, - currentKey, - currentKey.length, - ); - } - return _padTrancateString(dataFromCustom); - } - - List _create256BitUserPassword() { - final Random random = Random.secure(); - _userRandomBytes = List.generate( - _randomBytesAmount!, - (int i) => random.nextInt(256), - ); - final List userPasswordBytes = utf8.encode(_userPassword!); - final List hash = []; - hash.addAll(userPasswordBytes); - hash.addAll(List.generate(8, (int i) => _userRandomBytes![i])); - final List userPasswordOut = []; - userPasswordOut.addAll(sha256.convert(hash).bytes); - userPasswordOut.addAll(_userRandomBytes!); - return userPasswordOut; - } - - List _createOwnerPassword() { - final String password = - ownerPassword.isEmpty ? userPassword : ownerPassword; - final List customKey = _getKeyFromOwnerPassword(password); - final List userPasswordBytes = _padTrancateString( - utf8.encode(userPassword), - ); - List dataFromCustom = _encryptDataByCustom( - userPasswordBytes, - customKey, - customKey.length, - ); - if (revisionNumber! > 2) { - for (int i = 1; i < _ownerLoopNum2!; i++) { - final List currentKey = _getKeyWithOwnerPassword(customKey, i); - dataFromCustom = _encryptDataByCustom( - dataFromCustom, - currentKey, - currentKey.length, - ); - } - } - return dataFromCustom; - } - - List _create256BitOwnerPassword() { - final Random random = Random.secure(); - _ownerRandomBytes = List.generate( - _randomBytesAmount!, - (int i) => random.nextInt(256), - ); - final String password = - ownerPassword.isEmpty ? userPassword : ownerPassword; - final List ownerPasswordBytes = utf8.encode(password); - final List hash = []; - hash.addAll(ownerPasswordBytes); - hash.addAll(List.generate(8, (int i) => _ownerRandomBytes![i])); - hash.addAll(_userPasswordOut!); - final List ownerPasswordOut = []; - ownerPasswordOut.addAll(sha256.convert(hash).bytes); - ownerPasswordOut.addAll(_ownerRandomBytes!); - return ownerPasswordOut; - } - - List? _createUserEncryptionKey() { - final List hash = []; - hash.addAll(utf8.encode(userPassword)); - hash.addAll(List.generate(8, (int i) => _userRandomBytes![i + 8])); - final List hashBytes = sha256.convert(hash).bytes; - return AesCipherNoPadding( - true, - KeyParameter(Uint8List.fromList(hashBytes)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); - } - - List? _createOwnerEncryptionKey() { - final String password = - ownerPassword.isEmpty ? userPassword : ownerPassword; - final List hash = []; - hash.addAll(utf8.encode(password)); - hash.addAll(List.generate(8, (int i) => _ownerRandomBytes![i + 8])); - hash.addAll(_userPasswordOut!); - final List hashBytes = sha256.convert(hash).bytes; - return AesCipherNoPadding( - true, - KeyParameter(Uint8List.fromList(hashBytes)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); - } - - List? _createPermissionFlag() { - final List permissionFlagBytes = [ - _permissionValue!.toUnsigned(8), - (_permissionValue! >> 8).toUnsigned(8), - (_permissionValue! >> 16).toUnsigned(8), - (_permissionValue! >> 24).toUnsigned(8), - 255, - 255, - 255, - 255, - // ignore: prefer_if_elements_to_conditional_expressions - encryptMetadata ? 84 : 70, - 97, - 100, - 98, - 98, - 98, - 98, - 98, - ]; - return AesCipherNoPadding( - true, - KeyParameter(Uint8List.fromList(_fileEncryptionKey!)), - ).process(Uint8List.fromList(permissionFlagBytes)); - } - - void _createAcrobatX256BitUserPassword() { - final List userPasswordBytes = utf8.encode(_userPassword!); - final Random random = Random.secure(); - final List userValidationSalt = List.generate( - 8, - (int i) => random.nextInt(256), - ); - final List userKeySalt = List.generate( - 8, - (int i) => random.nextInt(256), - ); - List hash = []; - hash.addAll(userPasswordBytes); - hash.addAll(userValidationSalt); - hash = _acrobatXComputeHash(hash, userPasswordBytes, null); - _userPasswordOut = []; - _userPasswordOut!.addAll(hash); - _userPasswordOut!.addAll(userValidationSalt); - _userPasswordOut!.addAll(userKeySalt); - hash = []; - hash.addAll(userPasswordBytes); - hash.addAll(userKeySalt); - hash = _acrobatXComputeHash(hash, userPasswordBytes, null); - _userEncryptionKeyOut = AesCipherNoPadding( - true, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); - } - - void _createAcrobatX256BitOwnerPassword() { - final String password = - ownerPassword.isEmpty ? userPassword : ownerPassword; - final List ownerPasswordBytes = utf8.encode(password); - final Random random = Random.secure(); - final List ownerValidationSalt = List.generate( - 8, - (int i) => random.nextInt(256), - ); - final List ownerKeySalt = List.generate( - 8, - (int i) => random.nextInt(256), - ); - final List owenrPasswordOut = []; - owenrPasswordOut.addAll(ownerPasswordBytes); - owenrPasswordOut.addAll(ownerValidationSalt); - owenrPasswordOut.addAll(_userPasswordOut!); - _ownerPasswordOut = []; - _ownerPasswordOut!.addAll( - _acrobatXComputeHash( - owenrPasswordOut, - ownerPasswordBytes, - _userPasswordOut, - ), - ); - _ownerPasswordOut!.addAll(ownerValidationSalt); - _ownerPasswordOut!.addAll(ownerKeySalt); - List hash = []; - hash.addAll(ownerPasswordBytes); - hash.addAll(ownerKeySalt); - hash.addAll(_userPasswordOut!); - hash = _acrobatXComputeHash(hash, ownerPasswordBytes, _userPasswordOut); - _ownerEncryptionKeyOut = AesCipherNoPadding( - true, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(_fileEncryptionKey!)); - } - - void _createFileEncryptionKey() { - final Random random = Random.secure(); - _fileEncryptionKey = List.generate(32, (int i) => random.nextInt(256)); - } - - List _encryptDataByCustom( - List data, - List? key, - int keyLength, - ) { - final List buffer = List.filled(data.length, 0, growable: true); - _recreateCustomArray(key, keyLength); - keyLength = data.length; - int tmp1 = 0; - int tmp2 = 0; - for (int i = 0; i < keyLength; i++) { - tmp1 = (tmp1 + 1) % _bytesAmount!; - tmp2 = (tmp2 + customArray![tmp1]) % _bytesAmount!; - final int temp = customArray![tmp1]; - customArray![tmp1] = customArray![tmp2]; - customArray![tmp2] = temp; - final int byteXor = - customArray![(customArray![tmp1] + customArray![tmp2]) % - _bytesAmount!]; - buffer[i] = (data[i] ^ byteXor).toUnsigned(8); - } - return buffer; - } - - void _recreateCustomArray(List? key, int keyLength) { - final List tempArray = List.filled( - _bytesAmount!, - 0, - growable: true, - ); - for (int i = 0; i < _bytesAmount!; i++) { - tempArray[i] = key![i % keyLength]; - customArray![i] = i.toUnsigned(8); - } - int temp = 0; - for (int i = 0; i < _bytesAmount!; i++) { - temp = (temp + customArray![i] + tempArray[i]) % _bytesAmount!; - final int tempByte = customArray![i]; - customArray![i] = customArray![temp]; - customArray![temp] = tempByte; - } - } - - List _getKeyFromOwnerPassword(String password) { - final List passwordBytes = _padTrancateString(utf8.encode(password)); - List currentHash = md5.convert(passwordBytes).bytes; - final int? length = _getKeyLength(); - if (revisionNumber! > 2) { - for (int i = 0; i < _ownerLoopNum!; i++) { - currentHash = - md5 - .convert( - currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]), - ) - .bytes; - } - } - return currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]); - } - - int? _getKeyLength() { - return keyLength != 0 - ? (keyLength! ~/ 8) - : (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit - ? _key40 - : ((encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) - ? _key128 - : _key256)); - } - - List _padTrancateString(List source) { - final List passwordBytes = []; - if (source.isNotEmpty) { - passwordBytes.addAll(source); - } - if (source.length < _stringLength!) { - passwordBytes.addAll( - paddingBytes!.getRange(0, paddingBytes!.length - passwordBytes.length), - ); - } - return List.generate(_stringLength!, (int i) => passwordBytes[i]); - } - - List _getKeyWithOwnerPassword(List originalKey, int index) { - final List result = List.filled( - originalKey.length, - 0, - growable: true, - ); - for (int i = 0; i < originalKey.length; i++) { - result[i] = (originalKey[i] ^ index).toUnsigned(8); - } - return result; - } - - List _createEncryptionKey( - String inputPassword, - List ownerPasswordBytes, - ) { - final List passwordBytes = _padTrancateString( - utf8.encode(inputPassword), - ); - final List encryptionKeyData = []; - encryptionKeyData.addAll(passwordBytes); - encryptionKeyData.addAll(ownerPasswordBytes); - encryptionKeyData.addAll([ - _permissionValue!.toUnsigned(8), - (_permissionValue! >> 8).toUnsigned(8), - (_permissionValue! >> 16).toUnsigned(8), - (_permissionValue! >> 24).toUnsigned(8), - ]); - encryptionKeyData.addAll(randomBytes!); - int? revisionNumber; - if (_revision != 0) { - revisionNumber = this.revisionNumber; - } else { - revisionNumber = getKeyLength() + 2; - } - if (revisionNumber! > 3 && !encryptMetadata) { - encryptionKeyData.add(255); - encryptionKeyData.add(255); - encryptionKeyData.add(255); - encryptionKeyData.add(255); - } - List currentHash = md5.convert(encryptionKeyData).bytes; - final int? length = _getKeyLength(); - if (this.revisionNumber! > 2) { - for (int i = 0; i < _ownerLoopNum!; i++) { - currentHash = - md5 - .convert( - currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]), - ) - .bytes; - } - } - return currentHash.length == length - ? currentHash - : List.generate(length!, (int i) => currentHash[i]); - } - - List _acrobatXComputeHash( - List input, - List password, - List? key, - ) { - List hash = sha256.convert(input).bytes; - List? finalHashKey; - for ( - int i = 0; - i < 64 || (finalHashKey![finalHashKey.length - 1] & 0xFF) > i - 32; - i++ - ) { - final List roundHash = List.filled( - (key != null && key.length >= 48) - ? 64 * (password.length + hash.length + 48) - : 64 * (password.length + hash.length), - 0, - growable: true, - ); - int position = 0; - for (int j = 0; j < 64; j++) { - List.copyRange(roundHash, position, password, 0, password.length); - position += password.length; - List.copyRange(roundHash, position, hash, 0, hash.length); - position += hash.length; - if (key != null && key.length >= 48) { - List.copyRange(roundHash, position, key, 0, 48); - position += 48; - } - } - final List hashFirst = List.generate(16, (int i) => hash[i]); - final List hashSecond = List.generate( - 16, - (int i) => hash[i + 16], - ); - final AesCipher encrypt = AesCipher(true, hashFirst, hashSecond); - finalHashKey = encrypt.update(roundHash, 0, roundHash.length); - final List finalHashKeyFirst = List.generate( - 16, - (int i) => finalHashKey![i], - ); - final BigInt finalKeyBigInteger = _readBigIntFromBytes( - finalHashKeyFirst, - 0, - finalHashKeyFirst.length, - ); - final BigInt divisior = BigInt.parse('3'); - final BigInt algorithmNumber = finalKeyBigInteger % divisior; - final int algorithmIndex = algorithmNumber.toInt(); - if (algorithmIndex == 0) { - hash = sha256.convert(finalHashKey!).bytes; - } else if (algorithmIndex == 1) { - hash = sha384.convert(finalHashKey!).bytes; - } else { - hash = sha512.convert(finalHashKey!).bytes; - } - } - return (hash.length > 32) - ? List.generate(32, (int i) => hash[i]) - : hash; - } - - BigInt _readBigIntFromBytes(List bytes, int start, int end) { - if (end - start <= 4) { - int result = 0; - for (int i = end - 1; i >= start; i--) { - result = result * 256 + bytes[i]; - } - return BigInt.from(result); - } - final int mid = start + ((end - start) >> 1); - return _readBigIntFromBytes(bytes, start, mid) + - _readBigIntFromBytes(bytes, mid, end) * - (BigInt.one << ((mid - start) * 8)); - } - - /// internal method - void readFromDictionary(PdfDictionary dictionary) { - IPdfPrimitive? obj; - if (dictionary.containsKey(PdfDictionaryProperties.filter)) { - obj = PdfCrossTable.dereference( - dictionary[PdfDictionaryProperties.filter], - ); - } - if (obj != null && - obj is PdfName && - obj.name != PdfDictionaryProperties.standard) { - throw ArgumentError.value( - obj, - 'Invalid Format: Unsupported security filter', - ); - } - _permissionValue = dictionary.getInt(PdfDictionaryProperties.p); - _updatePermissions(_permissionValue! & ~_permissionSet!); - _versionNumberOut = dictionary.getInt(PdfDictionaryProperties.v); - _revisionNumberOut = dictionary.getInt(PdfDictionaryProperties.r); - if (_revisionNumberOut != null) { - _revision = _revisionNumberOut; - } - int keySize = dictionary.getInt(PdfDictionaryProperties.v); - if (keySize == 4 && keySize != _revisionNumberOut) { - throw ArgumentError.value( - 'Invalid Format: V and R entries of the Encryption dictionary does not match.', - ); - } - if (keySize == 5) { - _userEncryptionKeyOut = - dictionary.getString(PdfDictionaryProperties.ue)!.data; - _ownerEncryptionKeyOut = - dictionary.getString(PdfDictionaryProperties.oe)!.data; - _permissionFlag = - dictionary.getString(PdfDictionaryProperties.perms)!.data; - } - _userPasswordOut = dictionary.getString(PdfDictionaryProperties.u)!.data; - _ownerPasswordOut = dictionary.getString(PdfDictionaryProperties.o)!.data; - keyLength = - dictionary.containsKey(PdfDictionaryProperties.length) - ? dictionary.getInt(PdfDictionaryProperties.length) - : (keySize == 1 ? 40 : (keySize == 2 ? 128 : 256)); - if (keyLength == 128 && _revisionNumberOut! < 4) { - keySize = 2; - encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x128Bit; - } else if ((keyLength == 128 || keyLength == 256) && - _revisionNumberOut! >= 4) { - final PdfDictionary cryptFilter = - dictionary[PdfDictionaryProperties.cf]! as PdfDictionary; - final PdfDictionary standardCryptFilter = - cryptFilter[PdfDictionaryProperties.stdCF]! as PdfDictionary; - if (standardCryptFilter.containsKey(PdfDictionaryProperties.authEvent)) { - final IPdfPrimitive? authEventPrimitive = - standardCryptFilter[PdfDictionaryProperties.authEvent]; - if (authEventPrimitive is PdfName && - authEventPrimitive.name == PdfDictionaryProperties.efOpen) { - encryptOnlyAttachment = true; - } - } - final String? filterName = - (standardCryptFilter[PdfDictionaryProperties.cfm]! as PdfName).name; - if (keyLength == 128) { - keySize = 2; - encryptionAlgorithm = - filterName != 'V2' - ? PdfEncryptionAlgorithm.aesx128Bit - : PdfEncryptionAlgorithm.rc4x128Bit; - } else { - keySize = 3; - encryptionAlgorithm = PdfEncryptionAlgorithm.aesx256Bit; - } - } else if (keyLength == 40) { - keySize = 1; - encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x40Bit; - } else if (keyLength! <= 128 && - keyLength! > 40 && - keyLength! % 8 == 0 && - _revisionNumberOut! < 4) { - encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x128Bit; - keySize = 2; - } else { - encryptionAlgorithm = PdfEncryptionAlgorithm.aesx256Bit; - keySize = 3; - } - if (_revisionNumberOut == 6) { - encryptionAlgorithm = PdfEncryptionAlgorithm.aesx256BitRevision6; - keySize = 4; - } - if (keyLength != 0 && - keyLength! % 8 != 0 && - (keySize == 1 || keySize == 2 || keySize == 3)) { - throw ArgumentError.value( - 'Invalid format: Invalid/Unsupported security dictionary.', - ); - } - hasComputedPasswordValues = true; - } - - void _updatePermissions(int value) { - _permissions = []; - if (value & 0x000004 > 0) { - _permissions!.add(PdfPermissionsFlags.print); - } - if (value & 0x000008 > 0) { - _permissions!.add(PdfPermissionsFlags.editContent); - } - if (value & 0x000010 > 0) { - _permissions!.add(PdfPermissionsFlags.copyContent); - } - if (value & 0x000020 > 0) { - _permissions!.add(PdfPermissionsFlags.editAnnotations); - } - if (value & 0x000100 > 0) { - _permissions!.add(PdfPermissionsFlags.fillFields); - } - if (value & 0x000200 > 0) { - _permissions!.add(PdfPermissionsFlags.accessibilityCopyContent); - } - if (value & 0x000400 > 0) { - _permissions!.add(PdfPermissionsFlags.assembleDocument); - } - if (value & 0x000800 > 0) { - _permissions!.add(PdfPermissionsFlags.fullQualityPrint); - } - if (permissions.isEmpty) { - _permissions!.add(PdfPermissionsFlags.none); - } - } - - /// internal method - bool checkPassword(String password, PdfString key, bool attachEncryption) { - bool result = false; - final List? fileId = - _randomBytes != null ? List.from(_randomBytes!) : _randomBytes; - _randomBytes = List.from(key.data!); - if (_authenticateOwnerPassword(password)) { - _ownerPassword = password; - result = true; - } else if (_authenticateUserPassword(password)) { - _userPassword = password; - result = true; - } else if (!attachEncryption) { - result = true; - } else { - _encryptionKey = null; - } - if (!result) { - _randomBytes = fileId; - } - return result; - } - - bool _authenticateUserPassword(String password) { - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - return _authenticate256BitUserPassword(password); - } else { - _encryptionKey = _createEncryptionKey(password, _ownerPasswordOut!); - return _compareByteArrays( - _createUserPassword(), - _userPasswordOut, - revisionNumber == 2 ? null : 0x10, - ); - } - } - - bool _authenticateOwnerPassword(String password) { - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - return _authenticate256BitOwnerPassword(password); - } else { - _encryptionKey = _getKeyFromOwnerPassword(password); - List? buff = _ownerPasswordOut; - if (revisionNumber == 2) { - buff = _encryptDataByCustom( - buff!, - _encryptionKey, - _encryptionKey!.length, - ); - } else if (revisionNumber! > 2) { - buff = _ownerPasswordOut; - for (int i = 0; i < _ownerLoopNum2!; ++i) { - final List currKey = _getKeyWithOwnerPassword( - _encryptionKey!, - _ownerLoopNum2! - i - 1, - ); - buff = _encryptDataByCustom(buff!, currKey, currKey.length); - } - } - _encryptionKey = null; - final String userPassword = _convertToPassword(buff!); - if (_authenticateUserPassword(userPassword)) { - _userPassword = userPassword; - _ownerPassword = password; - return true; - } else { - return false; - } - } - } - - String _convertToPassword(List array) { - String result; - int length = array.length; - for (int i = 0; i < length; ++i) { - if (array[i] == paddingBytes![0]) { - if (i < length - 1 && array[i + 1] == paddingBytes![1]) { - length = i; - break; - } - } - } - result = PdfString.byteToString(array, length); - return result; - } - - bool _authenticate256BitUserPassword(String password) { - final List userValidationSalt = List.filled(8, 0, growable: true); - final List userKeySalt = List.filled(8, 0, growable: true); - final List hashProvided = List.filled(32, 0, growable: true); - _userRandomBytes = List.filled(16, 0, growable: true); - List hash; - final List userPassword = utf8.encode(password); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - List.copyRange(hashProvided, 0, _userPasswordOut!, 0, 32); - List.copyRange(userValidationSalt, 0, _userPasswordOut!, 32, 40); - final List combinedUserpassword = List.filled( - userPassword.length + userValidationSalt.length, - 0, - growable: true, - ); - List.copyRange( - combinedUserpassword, - 0, - userPassword, - 0, - userPassword.length, - ); - List.copyRange( - combinedUserpassword, - userPassword.length, - userValidationSalt, - 0, - userValidationSalt.length, - ); - hash = _acrobatXComputeHash(combinedUserpassword, userPassword, null); - _advanceXUserFileEncryptionKey(password); - return _compareByteArrays(hash, hashProvided); - } else { - List.copyRange( - hashProvided, - 0, - _userPasswordOut!, - 0, - hashProvided.length, - ); - List.copyRange(_userRandomBytes!, 0, _userPasswordOut!, 32, 48); - List.copyRange( - userValidationSalt, - 0, - _userRandomBytes!, - 0, - userValidationSalt.length, - ); - List.copyRange( - userKeySalt, - 0, - _userRandomBytes!, - userValidationSalt.length, - userKeySalt.length + userValidationSalt.length, - ); - hash = List.filled( - userPassword.length + userValidationSalt.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, userPassword, 0, userPassword.length); - List.copyRange( - hash, - userPassword.length, - userValidationSalt, - 0, - userValidationSalt.length, - ); - final List hashFound = sha256.convert(hash).bytes; - bool bEqual = false; - if (hashFound.length == hashProvided.length) { - int i = 0; - while ((i < hashFound.length) && (hashFound[i] == hashProvided[i])) { - i += 1; - } - if (i == hashFound.length) { - bEqual = true; - } - } - if (bEqual) { - _findFileEncryptionKey(password); - } - return bEqual; - } - } - - bool _authenticate256BitOwnerPassword(String password) { - final List ownerValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List ownerKeySalt = List.filled(8, 0, growable: true); - final List hashProvided = List.filled(32, 0, growable: true); - _ownerRandomBytes = List.filled(16, 0, growable: true); - List hash; - bool oEqual = false; - final List ownerPassword = utf8.encode(password); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - List.copyRange(hashProvided, 0, _ownerPasswordOut!, 0, 32); - List.copyRange(ownerValidationSalt, 0, _ownerPasswordOut!, 32, 40); - int userKeyLength = 48; - if (_userPasswordOut!.length < 48) { - userKeyLength = _userPasswordOut!.length; - } - final List mixedOwnerPassword = List.filled( - ownerPassword.length + ownerValidationSalt.length + userKeyLength, - 0, - growable: true, - ); - List.copyRange( - mixedOwnerPassword, - 0, - ownerPassword, - 0, - ownerPassword.length, - ); - List.copyRange( - mixedOwnerPassword, - ownerPassword.length, - ownerValidationSalt, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - mixedOwnerPassword, - ownerPassword.length + ownerValidationSalt.length, - _userPasswordOut!, - 0, - userKeyLength, - ); - hash = _acrobatXComputeHash( - mixedOwnerPassword, - ownerPassword, - _userPasswordOut, - ); - _acrobatXOwnerFileEncryptionKey(password); - oEqual = _compareByteArrays(hash, hashProvided); - if (oEqual == true) { - final List? ownerRandom = _fileEncryptionKey; - final String userPassword = password; - _ownerRandomBytes = null; - if (_authenticateUserPassword(userPassword)) { - _userPassword = userPassword; - _ownerPassword = password; - } else { - _fileEncryptionKey = ownerRandom; - } - } else { - _ownerRandomBytes = null; - } - return oEqual; - } else { - final List userPasswordOut = List.filled(48, 0, growable: true); - List.copyRange(userPasswordOut, 0, _userPasswordOut!, 0, 48); - List.copyRange( - hashProvided, - 0, - _ownerPasswordOut!, - 0, - hashProvided.length, - ); - List.copyRange(_ownerRandomBytes!, 0, _ownerPasswordOut!, 32, 48); - List.copyRange( - ownerValidationSalt, - 0, - _ownerRandomBytes!, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - ownerKeySalt, - 0, - _ownerRandomBytes!, - ownerValidationSalt.length, - ownerKeySalt.length, - ); - hash = List.filled( - ownerPassword.length + - ownerValidationSalt.length + - userPasswordOut.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, ownerPassword, 0, ownerPassword.length); - List.copyRange( - hash, - ownerPassword.length, - ownerValidationSalt, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - hash, - ownerPassword.length + ownerValidationSalt.length, - userPasswordOut, - 0, - userPasswordOut.length, - ); - final List hashFound = sha256.convert(hash).bytes; - bool bEqual = false; - if (hashFound.length == hashProvided.length) { - int i = 0; - while ((i < hashFound.length) && (hashFound[i] == hashProvided[i])) { - i += 1; - } - if (i == hashFound.length) { - bEqual = true; - } - } - _findFileEncryptionKey(password); - if (bEqual == true) { - _ownerRandomBytes = null; - final String userPassword = password; - if (_authenticateUserPassword(userPassword)) { - _userPassword = userPassword; - _ownerPassword = password; - } - } else { - _ownerRandomBytes = null; - } - return bEqual; - } - } - - void _findFileEncryptionKey(String password) { - List hash; - late List hashFound; - List? forDecryption; - if (_ownerRandomBytes != null) { - final List ownerValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List ownerKeySalt = List.filled(8, 0, growable: true); - final List ownerPassword = utf8.encode(password); - final List userPasswordOut = List.filled(48, 0, growable: true); - List.copyRange(userPasswordOut, 0, _userPasswordOut!, 0, 48); - List.copyRange(ownerValidationSalt, 0, _ownerRandomBytes!, 0, 8); - List.copyRange(ownerKeySalt, 0, _ownerRandomBytes!, 8, 16); - hash = List.filled( - ownerPassword.length + - ownerValidationSalt.length + - userPasswordOut.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, ownerPassword, 0, ownerPassword.length); - List.copyRange( - hash, - ownerPassword.length, - ownerKeySalt, - 0, - ownerKeySalt.length, - ); - List.copyRange( - hash, - ownerPassword.length + ownerValidationSalt.length, - userPasswordOut, - 0, - userPasswordOut.length, - ); - hashFound = sha256.convert(hash).bytes; - forDecryption = _ownerEncryptionKeyOut; - } else if (_userRandomBytes != null) { - final List userValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List userKeySalt = List.filled(8, 0, growable: true); - final List userPassword = utf8.encode(password); - List.copyRange(userValidationSalt, 0, _userRandomBytes!, 0, 8); - List.copyRange(userKeySalt, 0, _userRandomBytes!, 8, 16); - hash = List.filled( - userPassword.length + userKeySalt.length, - 0, - growable: true, - ); - List.copyRange(hash, 0, userPassword, 0, userPassword.length); - List.copyRange( - hash, - userPassword.length, - userKeySalt, - 0, - userKeySalt.length, - ); - hashFound = sha256.convert(hash).bytes; - forDecryption = _userEncryptionKeyOut; - } - _fileEncryptionKey = AesCipherNoPadding( - false, - KeyParameter(Uint8List.fromList(hashFound)), - ).process(Uint8List.fromList(forDecryption!)); - } - - bool _compareByteArrays(List array1, List? array2, [int? size]) { - bool result = true; - if (size == null) { - if (array2 == null) { - result = array1 == array2; - } else if (array1.length != array2.length) { - result = false; - } else { - for (int i = 0; i < array1.length; ++i) { - if (array1[i] != array2[i]) { - result = false; - break; - } - } - } - } else { - if (array2 == null) { - result = array1 == array2; - } else if (array1.length < size || array2.length < size) { - throw ArgumentError.value( - 'Size of one of the arrays are less then requisted size.', - ); - } else if (array1.length != array2.length) { - result = false; - } else { - for (int i = 0; i < size; ++i) { - if (array1[i] != array2[i]) { - result = false; - break; - } - } - } - } - return result; - } - - void _acrobatXOwnerFileEncryptionKey(String password) { - final List ownerValidationSalt = List.filled( - 8, - 0, - growable: true, - ); - final List ownerPassword = utf8.encode(password); - List.copyRange(ownerValidationSalt, 0, _ownerPasswordOut!, 40, 48); - int userKeyLength = 48; - if (_userPasswordOut!.length < 48) { - userKeyLength = _userPasswordOut!.length; - } - final List combinedPassword = List.filled( - ownerPassword.length + ownerValidationSalt.length + userKeyLength, - 0, - growable: true, - ); - List.copyRange(combinedPassword, 0, ownerPassword, 0, ownerPassword.length); - List.copyRange( - combinedPassword, - ownerPassword.length, - ownerValidationSalt, - 0, - ownerValidationSalt.length, - ); - List.copyRange( - combinedPassword, - ownerPassword.length + ownerValidationSalt.length, - _userPasswordOut!, - 0, - userKeyLength, - ); - final List hash = _acrobatXComputeHash( - combinedPassword, - ownerPassword, - _userPasswordOut, - ); - final List fileEncryptionKey = List.from(_ownerEncryptionKeyOut!); - _fileEncryptionKey = AesCipherNoPadding( - false, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(fileEncryptionKey)); - } - - void _advanceXUserFileEncryptionKey(String password) { - final List userKeySalt = List.filled(8, 0, growable: true); - List.copyRange(userKeySalt, 0, _userPasswordOut!, 40, 48); - final List userpassword = utf8.encode(password); - final List combinedUserPassword = List.filled( - userpassword.length + userKeySalt.length, - 0, - growable: true, - ); - List.copyRange( - combinedUserPassword, - 0, - userpassword, - 0, - userpassword.length, - ); - List.copyRange( - combinedUserPassword, - userpassword.length, - userKeySalt, - 0, - userKeySalt.length, - ); - final List hash = _acrobatXComputeHash( - combinedUserPassword, - userpassword, - null, - ); - final List fileEncryptionKey = List.from(_userEncryptionKeyOut!); - _fileEncryptionKey = AesCipherNoPadding( - false, - KeyParameter(Uint8List.fromList(hash)), - ).process(Uint8List.fromList(fileEncryptionKey)); - } - - /// internal method - PdfDictionary saveToDictionary(PdfDictionary dictionary) { - if (changed!) { - _revisionNumberOut = 0; - _versionNumberOut = 0; - _revision = 0; - keyLength = 0; - } - dictionary[PdfDictionaryProperties.filter] = PdfName( - PdfDictionaryProperties.standard, - ); - dictionary[PdfDictionaryProperties.p] = PdfNumber(_permissionValue!); - dictionary[PdfDictionaryProperties.u] = PdfString.fromBytes( - userPasswordOut, - ); - dictionary[PdfDictionaryProperties.o] = PdfString.fromBytes( - ownerPasswordOut, - ); - if (dictionary.containsKey(PdfDictionaryProperties.length)) { - keyLength = 0; - } - dictionary[PdfDictionaryProperties.length] = PdfNumber( - _getKeyLength()! * 8, - ); - const bool isAes4Dict = false; - if (encryptAttachmentOnly! && - (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit)) { - throw ArgumentError.value( - encryptionAlgorithm, - 'Encrypt only attachment is supported in AES algorithm with 128, 256 and 256Revision6 encryptions only.', - ); - } - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.r] = PdfNumber(_getKeySize() + 3); - dictionary[PdfDictionaryProperties.v] = PdfNumber(_getKeySize() + 3); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.v] = PdfNumber(5); - dictionary[PdfDictionaryProperties.r] = PdfNumber(6); - } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { - dictionary[PdfDictionaryProperties.v] = PdfNumber(5); - dictionary[PdfDictionaryProperties.r] = PdfNumber(5); - } - if (encryptAttachmentOnly!) { - dictionary[PdfDictionaryProperties.stmF] = PdfName( - PdfDictionaryProperties.identity, - ); - dictionary[PdfDictionaryProperties.strF] = PdfName( - PdfDictionaryProperties.identity, - ); - dictionary[PdfDictionaryProperties.eff] = PdfName( - PdfDictionaryProperties.stdCF, - ); - dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( - encryptOnlyMetadata, - ); - } else { - dictionary[PdfDictionaryProperties.stmF] = PdfName( - PdfDictionaryProperties.stdCF, - ); - dictionary[PdfDictionaryProperties.strF] = PdfName( - PdfDictionaryProperties.stdCF, - ); - if (dictionary.containsKey(PdfDictionaryProperties.eff)) { - dictionary.remove(PdfDictionaryProperties.eff); - } - } - if (!encryptOnlyMetadata!) { - if (!dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { - dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( - encryptOnlyMetadata, - ); - } - } else if (!encryptOnlyAttachment) { - if (dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { - dictionary.remove(PdfDictionaryProperties.encryptMetadata); - } - } - dictionary[PdfDictionaryProperties.cf] = _getCryptFilterDictionary(); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.ue] = PdfString.fromBytes( - _userEncryptionKeyOut, - ); - dictionary[PdfDictionaryProperties.oe] = PdfString.fromBytes( - _ownerEncryptionKeyOut, - ); - dictionary[PdfDictionaryProperties.perms] = PdfString.fromBytes( - _permissionFlag, - ); - } - } else { - dictionary[PdfDictionaryProperties.r] = PdfNumber( - (_revisionNumberOut! > 0 && !isAes4Dict) - ? _revisionNumberOut! - : (_getKeySize() + 2), - ); - dictionary[PdfDictionaryProperties.v] = PdfNumber( - (_versionNumberOut! > 0 && !isAes4Dict) - ? _versionNumberOut! - : (_getKeySize() + 1), - ); - } - dictionary.archive = false; - return dictionary; - } - - /// internal method - Future saveToDictionaryAsync(PdfDictionary dictionary) async { - if (changed!) { - _revisionNumberOut = 0; - _versionNumberOut = 0; - _revision = 0; - keyLength = 0; - } - dictionary[PdfDictionaryProperties.filter] = PdfName( - PdfDictionaryProperties.standard, - ); - dictionary[PdfDictionaryProperties.p] = PdfNumber(_permissionValue!); - dictionary[PdfDictionaryProperties.u] = PdfString.fromBytes( - userPasswordOut, - ); - dictionary[PdfDictionaryProperties.o] = PdfString.fromBytes( - ownerPasswordOut, - ); - if (dictionary.containsKey(PdfDictionaryProperties.length)) { - keyLength = 0; - } - dictionary[PdfDictionaryProperties.length] = PdfNumber( - _getKeyLength()! * 8, - ); - const bool isAes4Dict = false; - if (encryptAttachmentOnly! && - (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit)) { - throw ArgumentError.value( - encryptionAlgorithm, - 'Encrypt only attachment is supported in AES algorithm with 128, 256 and 256Revision6 encryptions only.', - ); - } - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.r] = PdfNumber(_getKeySize() + 3); - dictionary[PdfDictionaryProperties.v] = PdfNumber(_getKeySize() + 3); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.v] = PdfNumber(5); - dictionary[PdfDictionaryProperties.r] = PdfNumber(6); - } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { - dictionary[PdfDictionaryProperties.v] = PdfNumber(5); - dictionary[PdfDictionaryProperties.r] = PdfNumber(5); - } - if (encryptAttachmentOnly!) { - dictionary[PdfDictionaryProperties.stmF] = PdfName( - PdfDictionaryProperties.identity, - ); - dictionary[PdfDictionaryProperties.strF] = PdfName( - PdfDictionaryProperties.identity, - ); - dictionary[PdfDictionaryProperties.eff] = PdfName( - PdfDictionaryProperties.stdCF, - ); - dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( - encryptOnlyMetadata, - ); - } else { - dictionary[PdfDictionaryProperties.stmF] = PdfName( - PdfDictionaryProperties.stdCF, - ); - dictionary[PdfDictionaryProperties.strF] = PdfName( - PdfDictionaryProperties.stdCF, - ); - if (dictionary.containsKey(PdfDictionaryProperties.eff)) { - dictionary.remove(PdfDictionaryProperties.eff); - } - } - if (!encryptOnlyMetadata!) { - if (!dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { - dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( - encryptOnlyMetadata, - ); - } - } else if (!encryptOnlyAttachment) { - if (dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { - dictionary.remove(PdfDictionaryProperties.encryptMetadata); - } - } - dictionary[PdfDictionaryProperties.cf] = - await _getCryptFilterDictionaryAsync(); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - dictionary[PdfDictionaryProperties.ue] = PdfString.fromBytes( - _userEncryptionKeyOut, - ); - dictionary[PdfDictionaryProperties.oe] = PdfString.fromBytes( - _ownerEncryptionKeyOut, - ); - dictionary[PdfDictionaryProperties.perms] = PdfString.fromBytes( - _permissionFlag, - ); - } - } else { - dictionary[PdfDictionaryProperties.r] = PdfNumber( - (_revisionNumberOut! > 0 && !isAes4Dict) - ? _revisionNumberOut! - : (_getKeySize() + 2), - ); - dictionary[PdfDictionaryProperties.v] = PdfNumber( - (_versionNumberOut! > 0 && !isAes4Dict) - ? _versionNumberOut! - : (_getKeySize() + 1), - ); - } - dictionary.archive = false; - return dictionary; - } - - PdfDictionary _getCryptFilterDictionary() { - final PdfDictionary standardCryptFilter = PdfDictionary(); - if (!standardCryptFilter.containsKey(PdfDictionaryProperties.cfm)) { - if (encryptAttachmentOnly!) { - standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( - PdfDictionaryProperties.aesv2, - ); - standardCryptFilter[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.cryptFilter, - ); - } else { - standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( - (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == - PdfEncryptionAlgorithm.aesx256BitRevision6) - ? PdfDictionaryProperties.aesv3 - : (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) - ? 'V2' - : PdfDictionaryProperties.aesv2, - ); - } - } - if (!standardCryptFilter.containsKey(PdfDictionaryProperties.authEvent)) { - standardCryptFilter[PdfDictionaryProperties.authEvent] = PdfName( - encryptAttachmentOnly! - ? PdfDictionaryProperties.efOpen - : PdfDictionaryProperties.docOpen, - ); - } - standardCryptFilter[PdfDictionaryProperties.length] = PdfNumber( - (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) - ? _key256! - : ((encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) - ? _key128! - : 128), - ); - final PdfDictionary cryptFilterDictionary = PdfDictionary(); - cryptFilterDictionary[PdfDictionaryProperties.stdCF] = standardCryptFilter; - return cryptFilterDictionary; - } - - Future _getCryptFilterDictionaryAsync() async { - final PdfDictionary standardCryptFilter = PdfDictionary(); - if (!standardCryptFilter.containsKey(PdfDictionaryProperties.cfm)) { - if (encryptAttachmentOnly!) { - standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( - PdfDictionaryProperties.aesv2, - ); - standardCryptFilter[PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.cryptFilter, - ); - } else { - standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( - (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == - PdfEncryptionAlgorithm.aesx256BitRevision6) - ? PdfDictionaryProperties.aesv3 - : (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) - ? 'V2' - : PdfDictionaryProperties.aesv2, - ); - } - } - if (!standardCryptFilter.containsKey(PdfDictionaryProperties.authEvent)) { - standardCryptFilter[PdfDictionaryProperties.authEvent] = PdfName( - encryptAttachmentOnly! - ? PdfDictionaryProperties.efOpen - : PdfDictionaryProperties.docOpen, - ); - } - standardCryptFilter[PdfDictionaryProperties.length] = PdfNumber( - (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) - ? _key256! - : ((encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) - ? _key128! - : 128), - ); - final PdfDictionary cryptFilterDictionary = PdfDictionary(); - cryptFilterDictionary[PdfDictionaryProperties.stdCF] = standardCryptFilter; - return cryptFilterDictionary; - } - - int _getPermissionValue(List permissionFlags) { - int defaultValue = 0; - permissionFlags.toList().forEach((PdfPermissionsFlags flag) { - defaultValue |= _permissionFlagValues![flag.index]; - }); - return defaultValue; - } - - int _getKeySize() { - int result; - switch (encryptionAlgorithm) { - case PdfEncryptionAlgorithm.rc4x40Bit: - result = 0; - break; - case PdfEncryptionAlgorithm.aesx128Bit: - result = 1; - break; - case PdfEncryptionAlgorithm.aesx256Bit: - result = 2; - break; - case PdfEncryptionAlgorithm.aesx256BitRevision6: - result = 3; - break; - // ignore: no_default_cases - default: - result = 1; - break; - } - return result; - } - - /// internal method - List encryptData( - int? currentObjectNumber, - List data, - bool isEncryption, - ) { - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { - return isEncryption - ? _aesEncrypt(data, _fileEncryptionKey!) - : _aesDecrypt(data, _fileEncryptionKey); - } - _initializeData(); - const int genNumber = 0; - int keyLen = 0; - List newKey; - if (_encryptionKey!.length == 5) { - newKey = List.filled( - _encryptionKey!.length + _newKeyOffset!, - 0, - growable: true, - ); - for (int i = 0; i < _encryptionKey!.length; ++i) { - newKey[i] = _encryptionKey![i]; - } - int j = _encryptionKey!.length - 1; - newKey[++j] = currentObjectNumber!.toUnsigned(8); - newKey[++j] = (currentObjectNumber >> 8).toUnsigned(8); - newKey[++j] = (currentObjectNumber >> 16).toUnsigned(8); - newKey[++j] = genNumber.toUnsigned(8); - newKey[++j] = (genNumber >> 8).toUnsigned(8); - keyLen = newKey.length; - newKey = _prepareKeyForEncryption(newKey); - } else { - newKey = List.filled( - _encryptionKey!.length + - ((encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || - encryptionAlgorithm == - PdfEncryptionAlgorithm.aesx256BitRevision6 || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) - ? 9 - : 5), - 0, - growable: true, - ); - List.copyRange(newKey, 0, _encryptionKey!, 0, _encryptionKey!.length); - int j = _encryptionKey!.length - 1; - newKey[++j] = currentObjectNumber!.toUnsigned(8); - newKey[++j] = (currentObjectNumber >> 8).toUnsigned(8); - newKey[++j] = (currentObjectNumber >> 16).toUnsigned(8); - newKey[++j] = genNumber.toUnsigned(8); - newKey[++j] = (genNumber >> 8).toUnsigned(8); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { - newKey[++j] = 0x73.toUnsigned(8); - newKey[++j] = 0x41.toUnsigned(8); - newKey[++j] = 0x6c.toUnsigned(8); - newKey[++j] = 0x54.toUnsigned(8); - } - newKey = md5.convert(newKey).bytes; - keyLen = newKey.length; - } - keyLen = min(keyLen, newKey.length); - if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { - return isEncryption - ? _aesEncrypt(data, encryptOnlyAttachment ? _encryptionKey! : newKey) - : _aesDecrypt(data, encryptOnlyAttachment ? _encryptionKey : newKey); - } - return _encryptDataByCustom(data, newKey, keyLen); - } - - List _aesEncrypt(List data, List key) { - if (key.isEmpty) { - return data; - } - final iv = Uint8List(16); - final Random random = Random.secure(); - for (int i = 0; i < iv.length; i++) { - iv[i] = random.nextInt(256); - } - - final cipher = PaddedCipherMode( - Pkcs7Padding(), - CipherBlockChainingMode(AesEngine()), - ); - - final params = - BlockCipherPaddedParameters( - InvalidParameter(KeyParameter(Uint8List.fromList(key)), iv), - null, - ); - cipher.initialize(true, params); - - try { - final encrypted = cipher.process(Uint8List.fromList(data)); - final results = Uint8List(iv.length + encrypted.length); - results.setRange(0, iv.length, iv); - results.setRange(iv.length, results.length, encrypted); - - return results; - } catch (e) { - return []; - } - } - - List _aesDecrypt(List data, List? key) { - if (key == null || key.isEmpty || data.length < 16) { - return data; - } - - final ivBytes = Uint8List.fromList(data.take(16).toList()); - final encryptedData = Uint8List.fromList(data.skip(16).toList()); - - final cipher = PaddedCipherMode( - Pkcs7Padding(), - CipherBlockChainingMode(AesEngine()), - ); - - final params = - BlockCipherPaddedParameters( - InvalidParameter(KeyParameter(Uint8List.fromList(key)), ivBytes), - null, - ); - - cipher.initialize(false, params); - try { - return cipher.process(encryptedData); - } catch (e) { - return []; - } - } - - /// internal method - int getKeyLength() { - if (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit) { - return 1; - } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || - encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { - return 2; - } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { - return 3; - } else { - return 4; - } - } - - List _prepareKeyForEncryption(List originalKey) { - final int keyLen = originalKey.length; - final List newKey = md5.convert(originalKey).bytes; - if (keyLen > _randomBytesAmount!) { - final int newKeyLength = min( - _getKeyLength()! + _newKeyOffset!, - _randomBytesAmount!, - ); - final List result = List.filled( - newKeyLength, - 0, - growable: true, - ); - List.copyRange(result, 0, newKey, 0, newKeyLength); - return result; - } else { - return newKey; - } - } - - /// internal method - PdfEncryptor clone() { - final PdfEncryptor encryptor = - PdfEncryptor() - .._stringLength = _cloneInt(_stringLength) - .._revisionNumber40Bit = _cloneInt(_revisionNumber40Bit) - .._revisionNumber128Bit = _cloneInt(_revisionNumber128Bit) - .._ownerLoopNum2 = _cloneInt(_ownerLoopNum2) - .._ownerLoopNum = _cloneInt(_ownerLoopNum) - ..paddingBytes = _cloneList(paddingBytes) - .._bytesAmount = _cloneInt(_bytesAmount) - .._permissionSet = _cloneInt(_permissionSet) - .._permissionCleared = _cloneInt(_permissionCleared) - .._permissionRevisionTwoMask = _cloneInt(_permissionRevisionTwoMask) - .._revisionNumberOut = _cloneInt(_revisionNumberOut) - .._versionNumberOut = _cloneInt(_versionNumberOut) - .._permissionValue = _cloneInt(_permissionValue) - .._randomBytes = _cloneList(_randomBytes) - .._key40 = _cloneInt(_key40) - .._key128 = _cloneInt(_key128) - .._key256 = _cloneInt(_key256) - .._randomBytesAmount = _cloneInt(_randomBytesAmount) - .._newKeyOffset = _cloneInt(_newKeyOffset) - ..isEncrypt = _cloneBool(isEncrypt) - ..changed = _cloneBool(changed) - ..hasComputedPasswordValues = _cloneBool(hasComputedPasswordValues) - .._revision = _cloneInt(_revision) - .._ownerPasswordOut = _cloneList(_ownerPasswordOut) - .._userPasswordOut = _cloneList(_userPasswordOut) - .._encryptionKey = _cloneList(_encryptionKey) - ..keyLength = _cloneInt(keyLength) - ..customArray = _cloneList(customArray) - .._permissionFlagValues = _cloneList(_permissionFlagValues) - .._fileEncryptionKey = _cloneList(_fileEncryptionKey) - .._userEncryptionKeyOut = _cloneList(_userEncryptionKeyOut) - .._ownerEncryptionKeyOut = _cloneList(_ownerEncryptionKeyOut) - .._permissionFlag = _cloneList(_permissionFlag) - .._userRandomBytes = _cloneList(_userRandomBytes) - .._ownerRandomBytes = _cloneList(_ownerRandomBytes) - ..encryptOnlyMetadata = _cloneBool(encryptOnlyMetadata) - ..encryptAttachmentOnly = _cloneBool(encryptAttachmentOnly) - ..encryptionAlgorithm = encryptionAlgorithm - .._userPassword = _userPassword - .._ownerPassword = _ownerPassword - ..encryptionOptions = encryptionOptions; - encryptor._permissions = - _permissions != null - ? List.generate( - _permissions!.length, - (int i) => _permissions![i], - ) - : null; - return encryptor; - } - - bool? _cloneBool(bool? value) { - if (value != null) { - if (value) { - return true; - } else { - return false; - } - } else { - return null; - } - } - - int? _cloneInt(int? value) { - if (value != null) { - return value; - } else { - return null; - } - } - - List? _cloneList(List? value) { - if (value != null) { - return List.generate(value.length, (int i) => value[i]); - } else { - return null; - } - } -} +import 'dart:convert'; +import 'dart:math'; +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:crypto/crypto.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_cross_table.dart'; +import '../primitives/pdf_array.dart'; +import '../primitives/pdf_boolean.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_number.dart'; +import '../primitives/pdf_string.dart'; +import 'digital_signature/cryptography/aes_cipher.dart'; +import 'digital_signature/cryptography/aes_engine.dart'; +import 'digital_signature/cryptography/buffered_block_padding_base.dart'; +import 'digital_signature/cryptography/cipher_block_chaining_mode.dart'; +import 'digital_signature/cryptography/ipadding.dart'; +import 'enum.dart'; + +/// internal class +class PdfEncryptor { + /// internal constructor + PdfEncryptor() { + _initialize(); + } + + //Fields + int? _stringLength; + int? _revisionNumber40Bit; + int? _revisionNumber128Bit; + int? _ownerLoopNum2; + int? _ownerLoopNum; + + Uint8List? _paddingBytes; + int? _bytesAmount; + int? _permissionSet; + int? _permissionCleared; + int? _permissionRevisionTwoMask; + int? _revisionNumberOut; + int? _versionNumberOut; + int? _permissionValue; + Uint8List? _randomBytes; + int? _key40; + int? _key128; + int? _key256; + int? _randomBytesAmount; + int? _newKeyOffset; + + /// internal field + bool? isEncrypt; + + /// internal field + bool? changed; + + /// internal field + bool? hasComputedPasswordValues; + + /// internal field + PdfEncryptionAlgorithm? encryptionAlgorithm; + List? _permissions; + int? _revision; + String? _userPassword; + String? _ownerPassword; + Uint8List? _ownerPasswordOut; + Uint8List? _userPasswordOut; + Uint8List? _encryptionKey; + + /// internal field + int? keyLength; + + /// internal field + Uint8List? customArray; + List? _permissionFlagValues; + Uint8List? _fileEncryptionKey; + Uint8List? _userEncryptionKeyOut; + Uint8List? _ownerEncryptionKeyOut; + Uint8List? _permissionFlag; + Uint8List? _userRandomBytes; + Uint8List? _ownerRandomBytes; + + /// internal field + bool? encryptOnlyMetadata; + + /// internal field + bool? encryptAttachmentOnly; + + /// internal field + late PdfEncryptionOptions encryptionOptions; + + //Properties + /// internal property + int? get revisionNumber { + return _revision == 0 + ? (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit + ? (_revisionNumberOut! > 2 + ? _revisionNumberOut + : _revisionNumber40Bit) + : _revisionNumber128Bit) + : _revision; + } + + /// internal property + Uint8List get randomBytes { + if (_randomBytes == null) { + _randomBytes = Uint8List(_randomBytesAmount!); + final Random random = Random.secure(); + for (int i = 0; i < _randomBytesAmount!; i++) { + _randomBytes![i] = random.nextInt(256); + } + } + return _randomBytes!; + } + + /// internal property + List get permissions { + return _permissions!; + } + + set permissions(List value) { + changed = true; + _permissions = value; + _permissionValue = + (_getPermissionValue(_permissions!) | _permissionSet!) & + _permissionCleared!; + if (revisionNumber! > 2) { + _permissionValue = _permissionValue! & _permissionRevisionTwoMask!; + } + hasComputedPasswordValues = false; + } + + /// internal property + bool get encrypt { + final List perm = permissions; + final bool bEncrypt = + (!(perm.length == 1 && perm.contains(PdfPermissionsFlags.none))) || + _userPassword!.isNotEmpty || + _ownerPassword!.isNotEmpty; + return isEncrypt! && bEncrypt; + } + + set encrypt(bool value) { + isEncrypt = value; + } + + /// internal property + String get userPassword { + return _userPassword!; + } + + set userPassword(String value) { + if (_userPassword != value) { + changed = true; + _userPassword = value; + hasComputedPasswordValues = false; + } + } + + /// internal property + String get ownerPassword { + if (encryptAttachmentOnly!) { + return ''; + } + return _ownerPassword!; + } + + set ownerPassword(String value) { + if (_ownerPassword != value) { + changed = true; + _ownerPassword = value; + hasComputedPasswordValues = false; + } + } + + /// internal property + bool get encryptOnlyAttachment { + return encryptAttachmentOnly!; + } + + set encryptOnlyAttachment(bool value) { + encryptAttachmentOnly = value; + hasComputedPasswordValues = false; + } + + /// internal property + bool get encryptMetadata { + return encryptOnlyMetadata!; + } + + set encryptMetadata(bool value) { + hasComputedPasswordValues = false; + encryptOnlyMetadata = value; + } + + /// internal property + Uint8List? get ownerPasswordOut { + _initializeData(); + return _ownerPasswordOut; + } + + /// internal property + Uint8List? get userPasswordOut { + _initializeData(); + return _userPasswordOut; + } + + /// internal property + PdfArray get fileID { + final PdfString str = PdfString.fromBytes(randomBytes); + final PdfArray array = PdfArray(); + array.add(str); + array.add(str); + return array; + } + + //implementation + void _initialize() { + _key40 = 5; + _key128 = 16; + _key256 = 32; + _newKeyOffset = 5; + _userPassword = ''; + _ownerPassword = ''; + _stringLength = 32; + _revisionNumber40Bit = 2; + _revisionNumber128Bit = 3; + _revisionNumberOut = 0; + _versionNumberOut = 0; + _ownerLoopNum2 = 20; + _ownerLoopNum = 50; + _bytesAmount = 256; + _randomBytesAmount = 16; + keyLength = 0; + isEncrypt = true; + _permissionSet = ~0x00f3f; + _permissionCleared = ~0x3; + _permissionRevisionTwoMask = 0xfff; + _revision = 0; + encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x128Bit; + _permissionFlagValues = [ + 0x000000, + 0x000004, + 0x000008, + 0x000010, + 0x000020, + 0x000100, + 0x000200, + 0x000400, + 0x000800, + ]; + permissions = [PdfPermissionsFlags.none]; + encryptionOptions = PdfEncryptionOptions.encryptAllContents; + + _paddingBytes = Uint8List.fromList([ + 40, + 191, + 78, + 94, + 78, + 117, + 138, + 65, + 100, + 0, + 78, + 86, + 255, + 250, + 1, + 8, + 46, + 46, + 0, + 182, + 208, + 104, + 62, + 128, + 47, + 12, + 169, + 254, + 100, + 83, + 105, + 122, + ]); + + customArray = Uint8List(_bytesAmount!); + changed = false; + hasComputedPasswordValues = false; + encryptOnlyMetadata = true; + encryptAttachmentOnly = false; + } + + void _initializeData() { + if (!hasComputedPasswordValues!) { + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { + _userPasswordOut = _create256BitUserPassword(); + _ownerPasswordOut = _create256BitOwnerPassword(); + _createFileEncryptionKey(); + _userEncryptionKeyOut = _createUserEncryptionKey(); + _ownerEncryptionKeyOut = _createOwnerEncryptionKey(); + _permissionFlag = _createPermissionFlag(); + } else if (encryptionAlgorithm == + PdfEncryptionAlgorithm.aesx256BitRevision6) { + _createFileEncryptionKey(); + _createAcrobatX256BitUserPassword(); + _createAcrobatX256BitOwnerPassword(); + _permissionFlag = _createPermissionFlag(); + } else { + _ownerPasswordOut = _createOwnerPassword(); + _encryptionKey = _createEncryptionKey(userPassword, _ownerPasswordOut!); + _userPasswordOut = _createUserPassword(); + } + hasComputedPasswordValues = true; + } + } + + Uint8List _createUserPassword() { + return revisionNumber == 2 + ? _create40BitUserPassword() + : _create128BitUserPassword(); + } + + Uint8List _create40BitUserPassword() { + ArgumentError.checkNotNull(_encryptionKey); + final Uint8List paddingCopy = Uint8List.fromList(_paddingBytes!); + return _encryptDataByCustom( + paddingCopy, + _encryptionKey!, + _encryptionKey!.length, + ); + } + + Uint8List _create128BitUserPassword() { + ArgumentError.checkNotNull(_encryptionKey); + + final BytesBuilder dataBuilder = BytesBuilder(copy: false); + dataBuilder.add(_paddingBytes!); + dataBuilder.add(randomBytes); + + final Uint8List resultBytes = Uint8List.fromList( + md5.convert(dataBuilder.toBytes()).bytes, + ); + final Uint8List dataForCustom = Uint8List.view( + resultBytes.buffer, + 0, + _randomBytesAmount, + ); + + Uint8List dataFromCustom = _encryptDataByCustom( + dataForCustom, + _encryptionKey!, + _encryptionKey!.length, + ); + + for (int i = 1; i < _ownerLoopNum2!; i++) { + final Uint8List currentKey = _getKeyWithOwnerPassword(_encryptionKey!, i); + dataFromCustom = _encryptDataByCustom( + dataFromCustom, + currentKey, + currentKey.length, + ); + } + return _padTrancateString(dataFromCustom); + } + + Uint8List _create256BitUserPassword() { + final Random random = Random.secure(); + _userRandomBytes = Uint8List(_randomBytesAmount!); + for (int i = 0; i < _randomBytesAmount!; i++) { + _userRandomBytes![i] = random.nextInt(256); + } + + final Uint8List userPasswordBytes = Uint8List.fromList( + utf8.encode(_userPassword!), + ); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPasswordBytes); + hashBuilder.add(Uint8List.view(_userRandomBytes!.buffer, 0, 8)); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hashBytes); + resultBuilder.add(_userRandomBytes!); + + return resultBuilder.toBytes(); + } + + Uint8List _createOwnerPassword() { + final String password = + ownerPassword.isEmpty ? userPassword : ownerPassword; + final Uint8List customKey = _getKeyFromOwnerPassword(password); + final Uint8List userPasswordBytes = _padTrancateString( + Uint8List.fromList(utf8.encode(userPassword)), + ); + + Uint8List dataFromCustom = _encryptDataByCustom( + userPasswordBytes, + customKey, + customKey.length, + ); + + if (revisionNumber! > 2) { + for (int i = 1; i < _ownerLoopNum2!; i++) { + final Uint8List currentKey = _getKeyWithOwnerPassword(customKey, i); + dataFromCustom = _encryptDataByCustom( + dataFromCustom, + currentKey, + currentKey.length, + ); + } + } + return dataFromCustom; + } + + Uint8List _create256BitOwnerPassword() { + final Random random = Random.secure(); + _ownerRandomBytes = Uint8List(_randomBytesAmount!); + for (int i = 0; i < _randomBytesAmount!; i++) { + _ownerRandomBytes![i] = random.nextInt(256); + } + + final String password = + ownerPassword.isEmpty ? userPassword : ownerPassword; + final Uint8List ownerPasswordBytes = Uint8List.fromList( + utf8.encode(password), + ); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPasswordBytes); + hashBuilder.add(Uint8List.view(_ownerRandomBytes!.buffer, 0, 8)); + hashBuilder.add(_userPasswordOut!); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hashBytes); + resultBuilder.add(_ownerRandomBytes!); + + return resultBuilder.toBytes(); + } + + Uint8List? _createUserEncryptionKey() { + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(Uint8List.fromList(utf8.encode(userPassword))); + hashBuilder.add(Uint8List.view(_userRandomBytes!.buffer, 8, 8)); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + return AesCipherNoPadding( + true, + KeyParameter(hashBytes), + ).process(_fileEncryptionKey!); + } + + Uint8List? _createOwnerEncryptionKey() { + final String password = + ownerPassword.isEmpty ? userPassword : ownerPassword; + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(Uint8List.fromList(utf8.encode(password))); + hashBuilder.add(Uint8List.view(_ownerRandomBytes!.buffer, 8, 8)); + hashBuilder.add(_userPasswordOut!); + + final Uint8List hashBytes = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + return AesCipherNoPadding( + true, + KeyParameter(hashBytes), + ).process(_fileEncryptionKey!); + } + + Uint8List? _createPermissionFlag() { + final Uint8List permissionFlagBytes = Uint8List.fromList([ + _permissionValue!.toUnsigned(8), + (_permissionValue! >> 8).toUnsigned(8), + (_permissionValue! >> 16).toUnsigned(8), + (_permissionValue! >> 24).toUnsigned(8), + 255, + 255, + 255, + 255, + // ignore: prefer_if_elements_to_conditional_expressions + encryptMetadata ? 84 : 70, + 97, + 100, + 98, + 98, + 98, + 98, + 98, + ]); + + return AesCipherNoPadding( + true, + KeyParameter(_fileEncryptionKey!), + ).process(permissionFlagBytes); + } + + void _createAcrobatX256BitUserPassword() { + final Uint8List userPasswordBytes = Uint8List.fromList( + utf8.encode(_userPassword!), + ); + final Random random = Random.secure(); + final Uint8List userValidationSalt = Uint8List(8); + final Uint8List userKeySalt = Uint8List(8); + + for (int i = 0; i < 8; i++) { + userValidationSalt[i] = random.nextInt(256); + userKeySalt[i] = random.nextInt(256); + } + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPasswordBytes); + hashBuilder.add(userValidationSalt); + + Uint8List hash = _acrobatXComputeHash( + hashBuilder.toBytes(), + userPasswordBytes, + null, + ); + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hash); + resultBuilder.add(userValidationSalt); + resultBuilder.add(userKeySalt); + _userPasswordOut = resultBuilder.toBytes(); + + hashBuilder.clear(); + hashBuilder.add(userPasswordBytes); + hashBuilder.add(userKeySalt); + hash = _acrobatXComputeHash(hashBuilder.toBytes(), userPasswordBytes, null); + + _userEncryptionKeyOut = AesCipherNoPadding( + true, + KeyParameter(hash), + ).process(_fileEncryptionKey!); + } + + void _createAcrobatX256BitOwnerPassword() { + final String password = + ownerPassword.isEmpty ? userPassword : ownerPassword; + final Uint8List ownerPasswordBytes = Uint8List.fromList( + utf8.encode(password), + ); + final Random random = Random.secure(); + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerKeySalt = Uint8List(8); + + for (int i = 0; i < 8; i++) { + ownerValidationSalt[i] = random.nextInt(256); + ownerKeySalt[i] = random.nextInt(256); + } + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPasswordBytes); + hashBuilder.add(ownerValidationSalt); + hashBuilder.add(_userPasswordOut!); + + final Uint8List hash = _acrobatXComputeHash( + hashBuilder.toBytes(), + ownerPasswordBytes, + _userPasswordOut, + ); + + final BytesBuilder resultBuilder = BytesBuilder(copy: false); + resultBuilder.add(hash); + resultBuilder.add(ownerValidationSalt); + resultBuilder.add(ownerKeySalt); + _ownerPasswordOut = resultBuilder.toBytes(); + + hashBuilder.clear(); + hashBuilder.add(ownerPasswordBytes); + hashBuilder.add(ownerKeySalt); + hashBuilder.add(_userPasswordOut!); + + final Uint8List keyHash = _acrobatXComputeHash( + hashBuilder.toBytes(), + ownerPasswordBytes, + _userPasswordOut, + ); + + _ownerEncryptionKeyOut = AesCipherNoPadding( + true, + KeyParameter(keyHash), + ).process(_fileEncryptionKey!); + } + + void _createFileEncryptionKey() { + final Random random = Random.secure(); + _fileEncryptionKey = Uint8List(32); + for (int i = 0; i < 32; i++) { + _fileEncryptionKey![i] = random.nextInt(256); + } + } + + Uint8List _encryptDataByCustom(Uint8List data, Uint8List key, int keyLength) { + final Uint8List buffer = Uint8List(data.length); + _recreateCustomArray(key, keyLength); + + int tmp1 = 0; + int tmp2 = 0; + + for (int i = 0; i < data.length; i++) { + tmp1 = (tmp1 + 1) % _bytesAmount!; + tmp2 = (tmp2 + customArray![tmp1]) % _bytesAmount!; + + final int temp = customArray![tmp1]; + customArray![tmp1] = customArray![tmp2]; + customArray![tmp2] = temp; + + final int byteXor = + customArray![(customArray![tmp1] + customArray![tmp2]) % + _bytesAmount!]; + buffer[i] = (data[i] ^ byteXor) & 0xFF; + } + return buffer; + } + + void _recreateCustomArray(Uint8List key, int keyLength) { + final Uint8List tempArray = Uint8List(_bytesAmount!); + + for (int i = 0; i < _bytesAmount!; i++) { + tempArray[i] = key[i % keyLength]; + customArray![i] = i; + } + + int temp = 0; + for (int i = 0; i < _bytesAmount!; i++) { + temp = (temp + customArray![i] + tempArray[i]) % _bytesAmount!; + final int tempByte = customArray![i]; + customArray![i] = customArray![temp]; + customArray![temp] = tempByte; + } + } + + Uint8List _getKeyFromOwnerPassword(String password) { + final Uint8List passwordBytes = _padTrancateString( + Uint8List.fromList(utf8.encode(password)), + ); + Uint8List currentHash = Uint8List.fromList( + md5.convert(passwordBytes).bytes, + ); + final int length = _getKeyLength()!; + + if (revisionNumber! > 2) { + for (int i = 0; i < _ownerLoopNum!; i++) { + if (currentHash.length != length) { + final Uint8List truncated = Uint8List(length); + truncated.setRange(0, length, currentHash); + currentHash = Uint8List.fromList(md5.convert(truncated).bytes); + } else { + currentHash = Uint8List.fromList(md5.convert(currentHash).bytes); + } + } + } + + if (currentHash.length != length) { + final Uint8List result = Uint8List(length); + result.setRange(0, length, currentHash); + return result; + } + return currentHash; + } + + int? _getKeyLength() { + return keyLength != 0 + ? (keyLength! ~/ 8) + : (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit + ? _key40 + : ((encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) + ? _key128 + : _key256)); + } + + Uint8List _padTrancateString(Uint8List source) { + final Uint8List result = Uint8List(_stringLength!); + + if (source.isNotEmpty) { + final int copyLength = math.min(source.length, _stringLength!); + result.setRange(0, copyLength, source); + + if (copyLength < _stringLength!) { + result.setRange( + copyLength, + _stringLength!, + _paddingBytes!.sublist(0, _stringLength! - copyLength), + ); + } + } else { + result.setRange(0, _stringLength!, _paddingBytes!); + } + + return result; + } + + Uint8List _getKeyWithOwnerPassword(Uint8List originalKey, int index) { + final Uint8List result = Uint8List(originalKey.length); + for (int i = 0; i < originalKey.length; i++) { + result[i] = (originalKey[i] ^ index) & 0xFF; + } + return result; + } + + Uint8List _createEncryptionKey( + String inputPassword, + Uint8List ownerPasswordBytes, + ) { + final Uint8List passwordBytes = _padTrancateString( + Uint8List.fromList(utf8.encode(inputPassword)), + ); + + final BytesBuilder encryptionKeyDataBuilder = BytesBuilder(copy: false); + encryptionKeyDataBuilder.add(passwordBytes); + encryptionKeyDataBuilder.add(ownerPasswordBytes); + + final Uint8List permissionBytes = Uint8List(4); + permissionBytes[0] = _permissionValue!.toUnsigned(8); + permissionBytes[1] = (_permissionValue! >> 8).toUnsigned(8); + permissionBytes[2] = (_permissionValue! >> 16).toUnsigned(8); + permissionBytes[3] = (_permissionValue! >> 24).toUnsigned(8); + encryptionKeyDataBuilder.add(permissionBytes); + encryptionKeyDataBuilder.add(randomBytes); + + int revNum; + if (_revision != 0) { + revNum = revisionNumber!; + } else { + revNum = getKeyLength() + 2; + } + + if (revNum > 3 && !encryptMetadata) { + encryptionKeyDataBuilder.add(Uint8List.fromList([255, 255, 255, 255])); + } + + Uint8List currentHash = Uint8List.fromList( + md5.convert(encryptionKeyDataBuilder.toBytes()).bytes, + ); + final int length = _getKeyLength()!; + + if (revisionNumber! > 2) { + for (int i = 0; i < _ownerLoopNum!; i++) { + if (currentHash.length != length) { + final Uint8List truncated = Uint8List(length); + truncated.setRange(0, length, currentHash); + currentHash = Uint8List.fromList(md5.convert(truncated).bytes); + } else { + currentHash = Uint8List.fromList(md5.convert(currentHash).bytes); + } + } + } + + if (currentHash.length != length) { + final Uint8List result = Uint8List(length); + result.setRange(0, length, currentHash); + return result; + } + return currentHash; + } + + Uint8List _acrobatXComputeHash( + Uint8List input, + Uint8List password, + Uint8List? key, + ) { + Uint8List hash = Uint8List.fromList(sha256.convert(input).bytes); + Uint8List? finalHashKey; + + for ( + int i = 0; + i < 64 || + (finalHashKey != null && + (finalHashKey[finalHashKey.length - 1] & 0xFF) > i - 32); + i++ + ) { + final int roundHashSize = + (key != null && key.length >= 48) + ? 64 * (password.length + hash.length + 48) + : 64 * (password.length + hash.length); + + final Uint8List roundHash = Uint8List(roundHashSize); + int position = 0; + + for (int j = 0; j < 64; j++) { + roundHash.setRange(position, position + password.length, password); + position += password.length; + roundHash.setRange(position, position + hash.length, hash); + position += hash.length; + if (key != null && key.length >= 48) { + roundHash.setRange(position, position + 48, key.sublist(0, 48)); + position += 48; + } + } + + final Uint8List hashFirst = Uint8List.view(hash.buffer, 0, 16); + final Uint8List hashSecond = Uint8List.view(hash.buffer, 16, 16); + final AesCipher encrypt = AesCipher(true, hashFirst, hashSecond); + + final updateResult = encrypt.update(roundHash, 0, roundHash.length); + finalHashKey = + updateResult != null ? Uint8List.fromList(updateResult) : null; + + if (finalHashKey != null) { + final Uint8List finalHashKeyFirst = Uint8List.view( + finalHashKey.buffer, + 0, + 16, + ); + final BigInt finalKeyBigInteger = _readBigIntFromBytes( + finalHashKeyFirst, + 0, + finalHashKeyFirst.length, + ); + final BigInt algorithmNumber = finalKeyBigInteger % BigInt.from(3); + final int algorithmIndex = algorithmNumber.toInt(); + + if (algorithmIndex == 0) { + hash = Uint8List.fromList(sha256.convert(finalHashKey).bytes); + } else if (algorithmIndex == 1) { + hash = Uint8List.fromList(sha384.convert(finalHashKey).bytes); + } else { + hash = Uint8List.fromList(sha512.convert(finalHashKey).bytes); + } + } + } + + return (hash.length > 32) ? Uint8List.view(hash.buffer, 0, 32) : hash; + } + + BigInt _readBigIntFromBytes(Uint8List bytes, int start, int end) { + if (end - start <= 4) { + int result = 0; + for (int i = end - 1; i >= start; i--) { + result = result * 256 + bytes[i]; + } + return BigInt.from(result); + } + final int mid = start + ((end - start) >> 1); + return _readBigIntFromBytes(bytes, start, mid) + + _readBigIntFromBytes(bytes, mid, end) * + (BigInt.one << ((mid - start) * 8)); + } + + bool _compareByteArrays(Uint8List array1, Uint8List? array2, [int? size]) { + if (array2 == null) { + return false; + } + + final int compareLength = size ?? array1.length; + if (array1.length < compareLength || array2.length < compareLength) { + return false; + } + + for (int i = 0; i < compareLength; i++) { + if (array1[i] != array2[i]) { + return false; + } + } + return true; + } + + /// internal method + void readFromDictionary(PdfDictionary dictionary) { + IPdfPrimitive? obj; + if (dictionary.containsKey(PdfDictionaryProperties.filter)) { + obj = PdfCrossTable.dereference( + dictionary[PdfDictionaryProperties.filter], + ); + } + if (obj != null && + obj is PdfName && + obj.name != PdfDictionaryProperties.standard) { + throw ArgumentError.value( + obj, + 'Invalid Format: Unsupported security filter', + ); + } + _permissionValue = dictionary.getInt(PdfDictionaryProperties.p); + _updatePermissions(_permissionValue! & ~_permissionSet!); + _versionNumberOut = dictionary.getInt(PdfDictionaryProperties.v); + _revisionNumberOut = dictionary.getInt(PdfDictionaryProperties.r); + if (_revisionNumberOut != 0) { + _revision = _revisionNumberOut; + } + int keySize = dictionary.getInt(PdfDictionaryProperties.v); + if (keySize == 4 && keySize != _revisionNumberOut) { + throw ArgumentError.value( + 'Invalid Format: V and R entries of the Encryption dictionary does not match.', + ); + } + if (keySize == 5) { + _userEncryptionKeyOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.ue)!.data!, + ); + _ownerEncryptionKeyOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.oe)!.data!, + ); + _permissionFlag = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.perms)!.data!, + ); + } + _userPasswordOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.u)!.data!, + ); + _ownerPasswordOut = Uint8List.fromList( + dictionary.getString(PdfDictionaryProperties.o)!.data!, + ); + keyLength = + dictionary.containsKey(PdfDictionaryProperties.length) + ? dictionary.getInt(PdfDictionaryProperties.length) + : (keySize == 1 ? 40 : (keySize == 2 ? 128 : 256)); + + if (keyLength == 128 && _revisionNumberOut! < 4) { + keySize = 2; + encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x128Bit; + } else if ((keyLength == 128 || keyLength == 256) && + _revisionNumberOut! >= 4) { + final PdfDictionary cryptFilter = + dictionary[PdfDictionaryProperties.cf]! as PdfDictionary; + final PdfDictionary standardCryptFilter = + cryptFilter[PdfDictionaryProperties.stdCF]! as PdfDictionary; + if (standardCryptFilter.containsKey(PdfDictionaryProperties.authEvent)) { + final IPdfPrimitive? authEventPrimitive = + standardCryptFilter[PdfDictionaryProperties.authEvent]; + if (authEventPrimitive is PdfName && + authEventPrimitive.name == PdfDictionaryProperties.efOpen) { + encryptOnlyAttachment = true; + } + } + final String? filterName = + (standardCryptFilter[PdfDictionaryProperties.cfm]! as PdfName).name; + if (keyLength == 128) { + keySize = 2; + encryptionAlgorithm = + filterName != 'V2' + ? PdfEncryptionAlgorithm.aesx128Bit + : PdfEncryptionAlgorithm.rc4x128Bit; + } else { + keySize = 3; + encryptionAlgorithm = PdfEncryptionAlgorithm.aesx256Bit; + } + } else if (keyLength == 40) { + keySize = 1; + encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x40Bit; + } else if (keyLength! <= 128 && + keyLength! > 40 && + keyLength! % 8 == 0 && + _revisionNumberOut! < 4) { + encryptionAlgorithm = PdfEncryptionAlgorithm.rc4x128Bit; + keySize = 2; + } else { + encryptionAlgorithm = PdfEncryptionAlgorithm.aesx256Bit; + keySize = 3; + } + if (_revisionNumberOut == 6) { + encryptionAlgorithm = PdfEncryptionAlgorithm.aesx256BitRevision6; + keySize = 4; + } + if (keyLength != 0 && + keyLength! % 8 != 0 && + (keySize == 1 || keySize == 2 || keySize == 3)) { + throw ArgumentError.value( + 'Invalid format: Invalid/Unsupported security dictionary.', + ); + } + hasComputedPasswordValues = true; + } + + void _updatePermissions(int value) { + _permissions = []; + if (value & 0x000004 > 0) { + _permissions!.add(PdfPermissionsFlags.print); + } + if (value & 0x000008 > 0) { + _permissions!.add(PdfPermissionsFlags.editContent); + } + if (value & 0x000010 > 0) { + _permissions!.add(PdfPermissionsFlags.copyContent); + } + if (value & 0x000020 > 0) { + _permissions!.add(PdfPermissionsFlags.editAnnotations); + } + if (value & 0x000100 > 0) { + _permissions!.add(PdfPermissionsFlags.fillFields); + } + if (value & 0x000200 > 0) { + _permissions!.add(PdfPermissionsFlags.accessibilityCopyContent); + } + if (value & 0x000400 > 0) { + _permissions!.add(PdfPermissionsFlags.assembleDocument); + } + if (value & 0x000800 > 0) { + _permissions!.add(PdfPermissionsFlags.fullQualityPrint); + } + if (_permissions!.isEmpty) { + _permissions!.add(PdfPermissionsFlags.none); + } + } + + /// internal method + bool checkPassword(String password, PdfString key, bool attachEncryption) { + bool result = false; + final Uint8List? fileId = _randomBytes; + _randomBytes = Uint8List.fromList(key.data!); + + if (_authenticateOwnerPassword(password)) { + _ownerPassword = password; + result = true; + } else if (_authenticateUserPassword(password)) { + _userPassword = password; + result = true; + } else if (!attachEncryption) { + result = true; + } else { + _encryptionKey = null; + } + + if (!result) { + _randomBytes = fileId; + } + return result; + } + + bool _authenticateUserPassword(String password) { + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + return _authenticate256BitUserPassword(password); + } else { + _encryptionKey = _createEncryptionKey(password, _ownerPasswordOut!); + return _compareByteArrays( + _createUserPassword(), + _userPasswordOut, + revisionNumber == 2 ? null : 0x10, + ); + } + } + + bool _authenticateOwnerPassword(String password) { + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + return _authenticate256BitOwnerPassword(password); + } else { + _encryptionKey = _getKeyFromOwnerPassword(password); + Uint8List? buff = _ownerPasswordOut; + if (revisionNumber == 2) { + buff = _encryptDataByCustom( + buff!, + _encryptionKey!, + _encryptionKey!.length, + ); + } else if (revisionNumber! > 2) { + buff = _ownerPasswordOut; + for (int i = 0; i < _ownerLoopNum2!; ++i) { + final Uint8List currKey = _getKeyWithOwnerPassword( + _encryptionKey!, + _ownerLoopNum2! - i - 1, + ); + buff = _encryptDataByCustom(buff!, currKey, currKey.length); + } + } + _encryptionKey = null; + final String userPassword = _convertToPassword(buff!); + if (_authenticateUserPassword(userPassword)) { + _userPassword = userPassword; + _ownerPassword = password; + return true; + } else { + return false; + } + } + } + + String _convertToPassword(Uint8List array) { + int length = array.length; + for (int i = 0; i < length; ++i) { + if (array[i] == _paddingBytes![0]) { + if (i < length - 1 && array[i + 1] == _paddingBytes![1]) { + length = i; + break; + } + } + } + return PdfString.byteToString(array, length); + } + + bool _authenticate256BitUserPassword(String password) { + final Uint8List userValidationSalt = Uint8List(8); + final Uint8List userKeySalt = Uint8List(8); + final Uint8List hashProvided = Uint8List(32); + _userRandomBytes = Uint8List(16); + + final Uint8List userPassword = Uint8List.fromList(utf8.encode(password)); + + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + hashProvided.setRange(0, 32, _userPasswordOut!); + userValidationSalt.setRange(0, 8, _userPasswordOut!, 32); + + final BytesBuilder combinedBuilder = BytesBuilder(copy: false); + combinedBuilder.add(userPassword); + combinedBuilder.add(userValidationSalt); + + final Uint8List hash = _acrobatXComputeHash( + combinedBuilder.toBytes(), + userPassword, + null, + ); + _advanceXUserFileEncryptionKey(password); + return _compareByteArrays(hash, hashProvided); + } else { + hashProvided.setRange(0, 32, _userPasswordOut!); + _userRandomBytes!.setRange(0, 16, _userPasswordOut!, 32); + userValidationSalt.setRange(0, 8, _userRandomBytes!); + userKeySalt.setRange(0, 8, _userRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPassword); + hashBuilder.add(userValidationSalt); + + final Uint8List hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + final bool bEqual = _compareByteArrays(hashFound, hashProvided); + + if (bEqual) { + _findFileEncryptionKey(password); + } + return bEqual; + } + } + + bool _authenticate256BitOwnerPassword(String password) { + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerKeySalt = Uint8List(8); + final Uint8List hashProvided = Uint8List(32); + _ownerRandomBytes = Uint8List(16); + + final Uint8List ownerPassword = Uint8List.fromList(utf8.encode(password)); + + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + hashProvided.setRange(0, 32, _ownerPasswordOut!); + ownerValidationSalt.setRange(0, 8, _ownerPasswordOut!, 32); + + final int userKeyLength = math.min(48, _userPasswordOut!.length); + + final BytesBuilder mixedBuilder = BytesBuilder(copy: false); + mixedBuilder.add(ownerPassword); + mixedBuilder.add(ownerValidationSalt); + mixedBuilder.add( + Uint8List.view(_userPasswordOut!.buffer, 0, userKeyLength), + ); + + final Uint8List hash = _acrobatXComputeHash( + mixedBuilder.toBytes(), + ownerPassword, + _userPasswordOut, + ); + + _acrobatXOwnerFileEncryptionKey(password); + final bool oEqual = _compareByteArrays(hash, hashProvided); + + if (oEqual) { + final Uint8List? ownerRandom = _fileEncryptionKey; + final String userPassword = password; + _ownerRandomBytes = null; + if (_authenticateUserPassword(userPassword)) { + _userPassword = userPassword; + _ownerPassword = password; + } else { + _fileEncryptionKey = ownerRandom; + } + } else { + _ownerRandomBytes = null; + } + return oEqual; + } else { + final Uint8List userPasswordOut = Uint8List(48); + userPasswordOut.setRange(0, 48, _userPasswordOut!); + hashProvided.setRange(0, 32, _ownerPasswordOut!); + _ownerRandomBytes!.setRange(0, 16, _ownerPasswordOut!, 32); + ownerValidationSalt.setRange(0, 8, _ownerRandomBytes!); + ownerKeySalt.setRange(0, 8, _ownerRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPassword); + hashBuilder.add(ownerValidationSalt); + hashBuilder.add(userPasswordOut); + + final Uint8List hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + final bool bEqual = _compareByteArrays(hashFound, hashProvided); + + _findFileEncryptionKey(password); + if (bEqual) { + _ownerRandomBytes = null; + final String userPassword = password; + if (_authenticateUserPassword(userPassword)) { + _userPassword = userPassword; + _ownerPassword = password; + } + } else { + _ownerRandomBytes = null; + } + return bEqual; + } + } + + void _findFileEncryptionKey(String password) { + late Uint8List hashFound; + Uint8List? forDecryption; + + if (_ownerRandomBytes != null) { + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerKeySalt = Uint8List(8); + final Uint8List ownerPassword = Uint8List.fromList(utf8.encode(password)); + final Uint8List userPasswordOut = Uint8List(48); + + userPasswordOut.setRange(0, 48, _userPasswordOut!); + ownerValidationSalt.setRange(0, 8, _ownerRandomBytes!); + ownerKeySalt.setRange(0, 8, _ownerRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(ownerPassword); + hashBuilder.add(ownerKeySalt); + hashBuilder.add(userPasswordOut); + + hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + forDecryption = _ownerEncryptionKeyOut; + } else if (_userRandomBytes != null) { + final Uint8List userValidationSalt = Uint8List(8); + final Uint8List userKeySalt = Uint8List(8); + final Uint8List userPassword = Uint8List.fromList(utf8.encode(password)); + + userValidationSalt.setRange(0, 8, _userRandomBytes!); + userKeySalt.setRange(0, 8, _userRandomBytes!, 8); + + final BytesBuilder hashBuilder = BytesBuilder(copy: false); + hashBuilder.add(userPassword); + hashBuilder.add(userKeySalt); + + hashFound = Uint8List.fromList( + sha256.convert(hashBuilder.toBytes()).bytes, + ); + forDecryption = _userEncryptionKeyOut; + } + + _fileEncryptionKey = AesCipherNoPadding( + false, + KeyParameter(hashFound), + ).process(forDecryption!); + } + + void _acrobatXOwnerFileEncryptionKey(String password) { + final Uint8List ownerValidationSalt = Uint8List(8); + final Uint8List ownerPassword = Uint8List.fromList(utf8.encode(password)); + ownerValidationSalt.setRange(0, 8, _ownerPasswordOut!, 40); + + final int userKeyLength = math.min(48, _userPasswordOut!.length); + + final BytesBuilder combinedBuilder = BytesBuilder(copy: false); + combinedBuilder.add(ownerPassword); + combinedBuilder.add(ownerValidationSalt); + combinedBuilder.add( + Uint8List.view(_userPasswordOut!.buffer, 0, userKeyLength), + ); + + final Uint8List hash = _acrobatXComputeHash( + combinedBuilder.toBytes(), + ownerPassword, + _userPasswordOut, + ); + + _fileEncryptionKey = AesCipherNoPadding( + false, + KeyParameter(hash), + ).process(_ownerEncryptionKeyOut!); + } + + void _advanceXUserFileEncryptionKey(String password) { + final Uint8List userKeySalt = Uint8List(8); + userKeySalt.setRange(0, 8, _userPasswordOut!, 40); + final Uint8List userpassword = Uint8List.fromList(utf8.encode(password)); + + final BytesBuilder combinedBuilder = BytesBuilder(copy: false); + combinedBuilder.add(userpassword); + combinedBuilder.add(userKeySalt); + + final Uint8List hash = _acrobatXComputeHash( + combinedBuilder.toBytes(), + userpassword, + null, + ); + + _fileEncryptionKey = AesCipherNoPadding( + false, + KeyParameter(hash), + ).process(_userEncryptionKeyOut!); + } + + /// internal method + PdfDictionary saveToDictionary(PdfDictionary dictionary) { + if (changed!) { + _revisionNumberOut = 0; + _versionNumberOut = 0; + _revision = 0; + keyLength = 0; + } + dictionary[PdfDictionaryProperties.filter] = PdfName( + PdfDictionaryProperties.standard, + ); + dictionary[PdfDictionaryProperties.p] = PdfNumber(_permissionValue!); + dictionary[PdfDictionaryProperties.u] = PdfString.fromBytes( + userPasswordOut, + ); + dictionary[PdfDictionaryProperties.o] = PdfString.fromBytes( + ownerPasswordOut, + ); + + if (dictionary.containsKey(PdfDictionaryProperties.length)) { + keyLength = 0; + } + dictionary[PdfDictionaryProperties.length] = PdfNumber( + _getKeyLength()! * 8, + ); + + const bool isAes4Dict = false; + if (encryptAttachmentOnly! && + (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit)) { + throw ArgumentError.value( + encryptionAlgorithm, + 'Encrypt only attachment is supported in AES algorithm with 128, 256 and 256Revision6 encryptions only.', + ); + } + + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + dictionary[PdfDictionaryProperties.r] = PdfNumber(_getKeySize() + 3); + dictionary[PdfDictionaryProperties.v] = PdfNumber(_getKeySize() + 3); + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + dictionary[PdfDictionaryProperties.v] = PdfNumber(5); + dictionary[PdfDictionaryProperties.r] = PdfNumber(6); + } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { + dictionary[PdfDictionaryProperties.v] = PdfNumber(5); + dictionary[PdfDictionaryProperties.r] = PdfNumber(5); + } + + if (encryptAttachmentOnly!) { + dictionary[PdfDictionaryProperties.stmF] = PdfName( + PdfDictionaryProperties.identity, + ); + dictionary[PdfDictionaryProperties.strF] = PdfName( + PdfDictionaryProperties.identity, + ); + dictionary[PdfDictionaryProperties.eff] = PdfName( + PdfDictionaryProperties.stdCF, + ); + dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( + encryptOnlyMetadata, + ); + } else { + dictionary[PdfDictionaryProperties.stmF] = PdfName( + PdfDictionaryProperties.stdCF, + ); + dictionary[PdfDictionaryProperties.strF] = PdfName( + PdfDictionaryProperties.stdCF, + ); + if (dictionary.containsKey(PdfDictionaryProperties.eff)) { + dictionary.remove(PdfDictionaryProperties.eff); + } + } + + if (!encryptOnlyMetadata!) { + if (!dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { + dictionary[PdfDictionaryProperties.encryptMetadata] = PdfBoolean( + encryptOnlyMetadata, + ); + } + } else if (!encryptOnlyAttachment) { + if (dictionary.containsKey(PdfDictionaryProperties.encryptMetadata)) { + dictionary.remove(PdfDictionaryProperties.encryptMetadata); + } + } + + dictionary[PdfDictionaryProperties.cf] = _getCryptFilterDictionary(); + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + dictionary[PdfDictionaryProperties.ue] = PdfString.fromBytes( + _userEncryptionKeyOut, + ); + dictionary[PdfDictionaryProperties.oe] = PdfString.fromBytes( + _ownerEncryptionKeyOut, + ); + dictionary[PdfDictionaryProperties.perms] = PdfString.fromBytes( + _permissionFlag, + ); + } + } else { + dictionary[PdfDictionaryProperties.r] = PdfNumber( + (_revisionNumberOut! > 0 && !isAes4Dict) + ? _revisionNumberOut! + : (_getKeySize() + 2), + ); + dictionary[PdfDictionaryProperties.v] = PdfNumber( + (_versionNumberOut! > 0 && !isAes4Dict) + ? _versionNumberOut! + : (_getKeySize() + 1), + ); + } + dictionary.archive = false; + return dictionary; + } + + /// internal method + Future saveToDictionaryAsync(PdfDictionary dictionary) async { + return saveToDictionary(dictionary); + } + + PdfDictionary _getCryptFilterDictionary() { + final PdfDictionary standardCryptFilter = PdfDictionary(); + if (!standardCryptFilter.containsKey(PdfDictionaryProperties.cfm)) { + if (encryptAttachmentOnly!) { + standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( + PdfDictionaryProperties.aesv2, + ); + standardCryptFilter[PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.cryptFilter, + ); + } else { + standardCryptFilter[PdfDictionaryProperties.cfm] = PdfName( + (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == + PdfEncryptionAlgorithm.aesx256BitRevision6) + ? PdfDictionaryProperties.aesv3 + : (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit) + ? 'V2' + : PdfDictionaryProperties.aesv2, + ); + } + } + if (!standardCryptFilter.containsKey(PdfDictionaryProperties.authEvent)) { + standardCryptFilter[PdfDictionaryProperties.authEvent] = PdfName( + encryptAttachmentOnly! + ? PdfDictionaryProperties.efOpen + : PdfDictionaryProperties.docOpen, + ); + } + standardCryptFilter[PdfDictionaryProperties.length] = PdfNumber( + (encryptionAlgorithm! == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm! == + PdfEncryptionAlgorithm.aesx256BitRevision6) + ? _key256! + : ((encryptionAlgorithm! == PdfEncryptionAlgorithm.aesx128Bit || + encryptionAlgorithm! == PdfEncryptionAlgorithm.rc4x128Bit) + ? _key128! + : 128), + ); + final PdfDictionary cryptFilterDictionary = PdfDictionary(); + cryptFilterDictionary[PdfDictionaryProperties.stdCF] = standardCryptFilter; + return cryptFilterDictionary; + } + + int _getPermissionValue(List permissionFlags) { + int defaultValue = 0; + for (final PdfPermissionsFlags flag in permissionFlags) { + defaultValue |= _permissionFlagValues![flag.index]; + } + return defaultValue; + } + + int _getKeySize() { + int result; + switch (encryptionAlgorithm) { + case PdfEncryptionAlgorithm.rc4x40Bit: + result = 0; + break; + case PdfEncryptionAlgorithm.aesx128Bit: + result = 1; + break; + case PdfEncryptionAlgorithm.aesx256Bit: + result = 2; + break; + case PdfEncryptionAlgorithm.aesx256BitRevision6: + result = 3; + break; + // ignore: no_default_cases + default: + result = 1; + break; + } + return result; + } + + Uint8List encryptData( + int? currentObjectNumber, + Uint8List data, + bool isEncryption, + ) { + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256BitRevision6) { + return isEncryption + ? _aesEncrypt(data, _fileEncryptionKey!) + : _aesDecrypt(data, _fileEncryptionKey); + } + + _initializeData(); + const int genNumber = 0; + int keyLen; + Uint8List newKey; + + if (_encryptionKey!.length == 5) { + newKey = Uint8List(_encryptionKey!.length + _newKeyOffset!); + newKey.setRange(0, _encryptionKey!.length, _encryptionKey!); + + int j = _encryptionKey!.length - 1; + newKey[++j] = currentObjectNumber!.toUnsigned(8); + newKey[++j] = (currentObjectNumber >> 8).toUnsigned(8); + newKey[++j] = (currentObjectNumber >> 16).toUnsigned(8); + newKey[++j] = genNumber.toUnsigned(8); + newKey[++j] = (genNumber >> 8).toUnsigned(8); + keyLen = newKey.length; + newKey = _prepareKeyForEncryption(newKey); + } else { + final int additionalBytes = + (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit || + encryptionAlgorithm == + PdfEncryptionAlgorithm.aesx256BitRevision6 || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) + ? 9 + : 5; + + newKey = Uint8List(_encryptionKey!.length + additionalBytes); + newKey.setRange(0, _encryptionKey!.length, _encryptionKey!); + + int j = _encryptionKey!.length - 1; + newKey[++j] = currentObjectNumber!.toUnsigned(8); + newKey[++j] = (currentObjectNumber >> 8).toUnsigned(8); + newKey[++j] = (currentObjectNumber >> 16).toUnsigned(8); + newKey[++j] = genNumber.toUnsigned(8); + newKey[++j] = (genNumber >> 8).toUnsigned(8); + + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { + newKey[++j] = 0x73; + newKey[++j] = 0x41; + newKey[++j] = 0x6c; + newKey[++j] = 0x54; + } + + newKey = Uint8List.fromList(md5.convert(newKey).bytes); + keyLen = newKey.length; + } + + keyLen = math.min(keyLen, newKey.length); + if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { + return isEncryption + ? _aesEncrypt(data, encryptAttachmentOnly! ? _encryptionKey! : newKey) + : _aesDecrypt(data, encryptAttachmentOnly! ? _encryptionKey : newKey); + } + return _encryptDataByCustom(data, newKey, keyLen); + } + + Uint8List _aesEncrypt(Uint8List data, Uint8List key) { + if (key.isEmpty) { + return data; + } + + final Uint8List iv = Uint8List(16); + final Random random = Random.secure(); + for (int i = 0; i < iv.length; i++) { + iv[i] = random.nextInt(256); + } + + final cipher = PaddedCipherMode( + Pkcs7Padding(), + CipherBlockChainingMode(AesEngine()), + ); + + final params = + BlockCipherPaddedParameters( + InvalidParameter(KeyParameter(key), iv), + null, + ); + cipher.initialize(true, params); + + try { + final Uint8List encrypted = cipher.process(data); + final Uint8List results = Uint8List(iv.length + encrypted.length); + results.setRange(0, iv.length, iv); + results.setRange(iv.length, results.length, encrypted); + return results; + } catch (e) { + return Uint8List(0); + } + } + + Uint8List _aesDecrypt(Uint8List data, Uint8List? key) { + if (key == null || key.isEmpty || data.length < 16) { + return data; + } + + final Uint8List ivBytes = Uint8List.view(data.buffer, 0, 16); + final Uint8List encryptedData = Uint8List.view(data.buffer, 16); + + final cipher = PaddedCipherMode( + Pkcs7Padding(), + CipherBlockChainingMode(AesEngine()), + ); + + final params = + BlockCipherPaddedParameters( + InvalidParameter(KeyParameter(key), ivBytes), + null, + ); + + cipher.initialize(false, params); + try { + return cipher.process(encryptedData); + } catch (e) { + return Uint8List(0); + } + } + + /// internal method + int getKeyLength() { + if (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x40Bit) { + return 1; + } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.rc4x128Bit || + encryptionAlgorithm == PdfEncryptionAlgorithm.aesx128Bit) { + return 2; + } else if (encryptionAlgorithm == PdfEncryptionAlgorithm.aesx256Bit) { + return 3; + } else { + return 4; + } + } + + Uint8List _prepareKeyForEncryption(Uint8List originalKey) { + final int keyLen = originalKey.length; + final Uint8List newKey = Uint8List.fromList(md5.convert(originalKey).bytes); + + if (keyLen > _randomBytesAmount!) { + final int newKeyLength = math.min( + _getKeyLength()! + _newKeyOffset!, + _randomBytesAmount!, + ); + final Uint8List result = Uint8List(newKeyLength); + result.setRange(0, newKeyLength, newKey); + return result; + } else { + return newKey; + } + } + + PdfEncryptor clone() { + final PdfEncryptor encryptor = + PdfEncryptor() + .._stringLength = _stringLength + .._revisionNumber40Bit = _revisionNumber40Bit + .._revisionNumber128Bit = _revisionNumber128Bit + .._ownerLoopNum2 = _ownerLoopNum2 + .._ownerLoopNum = _ownerLoopNum + .._bytesAmount = _bytesAmount + .._permissionSet = _permissionSet + .._permissionCleared = _permissionCleared + .._permissionRevisionTwoMask = _permissionRevisionTwoMask + .._revisionNumberOut = _revisionNumberOut + .._versionNumberOut = _versionNumberOut + .._permissionValue = _permissionValue + .._key40 = _key40 + .._key128 = _key128 + .._key256 = _key256 + .._randomBytesAmount = _randomBytesAmount + .._newKeyOffset = _newKeyOffset + ..isEncrypt = isEncrypt + ..changed = changed + ..hasComputedPasswordValues = hasComputedPasswordValues + .._revision = _revision + ..keyLength = keyLength + ..encryptOnlyMetadata = encryptOnlyMetadata + ..encryptAttachmentOnly = encryptAttachmentOnly + ..encryptionAlgorithm = encryptionAlgorithm + .._userPassword = _userPassword + .._ownerPassword = _ownerPassword + ..encryptionOptions = encryptionOptions + .._permissionFlagValues = _cloneList(_permissionFlagValues); + + encryptor._paddingBytes = + _paddingBytes != null ? Uint8List.fromList(_paddingBytes!) : null; + encryptor._randomBytes = + _randomBytes != null ? Uint8List.fromList(_randomBytes!) : null; + encryptor._ownerPasswordOut = + _ownerPasswordOut != null + ? Uint8List.fromList(_ownerPasswordOut!) + : null; + encryptor._userPasswordOut = + _userPasswordOut != null ? Uint8List.fromList(_userPasswordOut!) : null; + encryptor._encryptionKey = + _encryptionKey != null ? Uint8List.fromList(_encryptionKey!) : null; + encryptor.customArray = + customArray != null ? Uint8List.fromList(customArray!) : null; + encryptor._fileEncryptionKey = + _fileEncryptionKey != null + ? Uint8List.fromList(_fileEncryptionKey!) + : null; + encryptor._userEncryptionKeyOut = + _userEncryptionKeyOut != null + ? Uint8List.fromList(_userEncryptionKeyOut!) + : null; + encryptor._ownerEncryptionKeyOut = + _ownerEncryptionKeyOut != null + ? Uint8List.fromList(_ownerEncryptionKeyOut!) + : null; + encryptor._permissionFlag = + _permissionFlag != null ? Uint8List.fromList(_permissionFlag!) : null; + encryptor._userRandomBytes = + _userRandomBytes != null ? Uint8List.fromList(_userRandomBytes!) : null; + encryptor._ownerRandomBytes = + _ownerRandomBytes != null + ? Uint8List.fromList(_ownerRandomBytes!) + : null; + + encryptor._permissions = + _permissions != null + ? List.generate( + _permissions!.length, + (int i) => _permissions![i], + ) + : null; + + return encryptor; + } + + List? _cloneList(List? value) { + if (value != null) { + return List.generate(value.length, (int i) => value[i]); + } else { + return null; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_security.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_security.dart index cba5cf2a2..3125a6420 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_security.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/security/pdf_security.dart @@ -1,539 +1,539 @@ -import 'enum.dart'; -import 'pdf_encryptor.dart'; - -/// Represents the security settings of the PDF document. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Document security -/// PdfSecurity security = document.security; -/// //Set security options -/// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; -/// security.userPassword = 'password'; -/// security.ownerPassword = 'syncfusion'; -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfSecurity { - //constructor - /// Initializes a new instance of the [PdfSecurity] class. - PdfSecurity._() { - _helper = PdfSecurityHelper(this); - _initialize(); - } - - //Fields - PdfPermissions? _permissions; - late PdfSecurityHelper _helper; - - /// Gets the type of encryption algorithm used. - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); - /// //Get encryption algorithm - /// PdfEncryptionAlgorithm algorithm = document.security.algorithm; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfEncryptionAlgorithm get algorithm { - return _helper.encryptor.encryptionAlgorithm!; - } - - /// Sets the type of encryption algorithm. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Document security - /// PdfSecurity security = document.security; - /// //Set security options - /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; - /// security.userPassword = 'password'; - /// security.ownerPassword = 'syncfusion'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - set algorithm(PdfEncryptionAlgorithm value) { - _helper.encryptor.encryptionAlgorithm = value; - _helper.encryptor.encrypt = true; - _helper.encryptor.changed = true; - _helper.encryptor.hasComputedPasswordValues = false; - _helper.modifiedSecurity = true; - } - - /// Gets the owner password. - /// - /// If the PDF document is password protected you can use the owner password - /// to open the document and change its permissions. - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); - /// //Get the owner password. - /// String ownerPassword = document.security.ownerPassword; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String get ownerPassword { - return _helper.encryptAttachments ? '' : _helper.encryptor.ownerPassword; - } - - /// Sets the owner password. - /// - /// If the PDF document is password protected you can use the owner password - /// to open the document and change its permissions. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Document security - /// PdfSecurity security = document.security; - /// //Set security options - /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; - /// security.userPassword = 'password'; - /// security.ownerPassword = 'syncfusion'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - set ownerPassword(String value) { - if (_helper.conformance) { - throw ArgumentError( - 'Document encryption is not allowed with Conformance documents.', - ); - } - _helper.encryptor.ownerPassword = value; - _helper.encryptor.encrypt = true; - _helper.modifiedSecurity = true; - } - - /// Gets the user password. - /// - /// User password is required when the PDF document is opened in a viewer. - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); - /// //Get the user password. - /// String userPassword = document.security.userPassword; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String get userPassword { - return _helper.encryptor.userPassword; - } - - /// Sets the user password. - /// - /// User password is required when the PDF document is opened in a viewer. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Document security - /// PdfSecurity security = document.security; - /// //Set security options - /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; - /// security.userPassword = 'password'; - /// security.ownerPassword = 'syncfusion'; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - set userPassword(String value) { - if (_helper.conformance) { - throw ArgumentError( - 'Document encryption is not allowed with Conformance documents.', - ); - } - _helper.encryptor.userPassword = value; - _helper.encryptor.encrypt = true; - _helper.modifiedSecurity = true; - } - - /// Gets the permissions when the document is opened with user password. - /// - /// We can add or remove permissions flags by using add() and remove() method - /// in [PdfPermissions] class. - /// - /// ```dart - /// //Load an exisiting PDF document. - /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); - /// //Get the permissions. - /// PdfPermissions pdfPermissions = document.security.permissions; - /// //Add permissions - /// permissions.add([PdfPermissionsFlags.editContent, PdfPermissionsFlags.copyContent]); - /// //Remove permissions - /// permissions.remove([PdfPermissionsFlags.editContent, PdfPermissionsFlags.copyContent]); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPermissions get permissions { - _permissions ??= PdfPermissions._( - _helper.encryptor, - _helper.encryptor.permissions, - ); - return _permissions!; - } - - /// Gets or sets the type of encryption options used. - /// - /// User password is required when the PDF document is opened in a viewer. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Document security - /// PdfSecurity security = document.security; - /// //Set security options - /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; - /// security.userPassword = 'password'; - /// security.ownerPassword = 'syncfusion'; - /// security.encryptionOptions = PdfEncryptionOptions.encryptAllContents; - /// //Create and add attachment to the PDF document - /// document.attachments.add(PdfAttachment( - /// 'input.txt', File('input.txt').readAsBytesSync(), - /// description: 'Text File', mimeType: 'application/txt')); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfEncryptionOptions get encryptionOptions => - _helper.encryptor.encryptionOptions; - set encryptionOptions(PdfEncryptionOptions value) { - if (_helper.conformance) { - throw ArgumentError( - 'Document encryption is not allowed with Conformance documents.', - ); - } - if (_helper.encryptor.encryptionOptions != value) { - _helper.encryptor.encryptionOptions = value; - _helper.encryptor.encrypt = true; - _helper.encryptor.changed = true; - _helper.modifiedSecurity = true; - _helper.encryptor.hasComputedPasswordValues = false; - if (PdfEncryptionOptions.encryptOnlyAttachments == value) { - _helper.encryptAttachments = true; - _helper.encryptor.encryptMetadata = false; - } else if (PdfEncryptionOptions.encryptAllContentsExceptMetadata == - value) { - _helper.encryptAttachments = false; - _helper.encryptor.encryptMetadata = false; - } else { - _helper.encryptAttachments = false; - _helper.encryptor.encryptMetadata = true; - } - } - } - - //Implementation - void _initialize() { - _helper.encryptAttachmentOnly = false; - _helper.encryptor = PdfEncryptor(); - } -} - -/// [PdfSecurity] helper -class PdfSecurityHelper { - /// internal constructor - PdfSecurityHelper(this.base); - - /// internal field - PdfSecurity base; - - /// internal method - static PdfSecurityHelper getHelper(PdfSecurity base) { - return base._helper; - } - - /// internal field - late PdfEncryptor encryptor; - - /// internal field - late bool encryptAttachmentOnly; - - /// internal property - bool get encryptAttachments { - return encryptAttachmentOnly; - } - - set encryptAttachments(bool value) { - encryptAttachmentOnly = value; - encryptor.encryptOnlyAttachment = value; - encryptor.changed = true; - } - - /// internal field - // ignore: prefer_final_fields - bool conformance = false; - - /// internal field - bool modifiedSecurity = false; - - /// internal method - static PdfSecurity getSecurity() { - return PdfSecurity._(); - } -} - -/// Represents the permissions of the PDF document. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Document security -/// PdfSecurity security = document.security; -/// //Set security options -/// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; -/// security.userPassword = 'password'; -/// security.ownerPassword = 'syncfusion'; -/// //Get PDF permission. -/// PdfPermissions permissions = security.permissions; -/// //Add permissions. -/// permissions.add([PdfPermissionsFlags.print]); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfPermissions { - //constructor - PdfPermissions._( - PdfEncryptor encryptor, - List permissions, - ) { - _encryptor = encryptor; - _permissions = permissions; - } - - //Fields - late PdfEncryptor _encryptor; - late List _permissions; - bool _modifiedPermissions = false; - - //Implementation - /// Get the permissions. - /// - /// ```dart - /// //Load encrypted PDF document with password. - /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); - /// //Document security - /// PdfSecurity security = document.security; - /// //Gets the PDF permission. - /// PdfPermissions permissions = security.permissions; - /// //Gets the permission option at index 0. - /// PdfPermissionsFlags permission = permissions[0]; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPermissionsFlags operator [](int index) => _returnValue(index); - - /// Iterate for each element in permissions and perform action. - /// - /// ```dart - /// //Load encrypted PDF document with password. - /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); - /// //Document security - /// PdfSecurity security = document.security; - /// //Gets the PDF permission. - /// PdfPermissions permissions = security.permissions; - /// List permissions = [ - /// PdfPermissionsFlags.print, - /// PdfPermissionsFlags.editContent, - /// PdfPermissionsFlags.copyContent, - /// PdfPermissionsFlags.editAnnotations, - /// PdfPermissionsFlags.fillFields, - /// PdfPermissionsFlags.accessibilityCopyContent, - /// PdfPermissionsFlags.assembleDocument, - /// PdfPermissionsFlags.fullQualityPrint]; - /// //Check the PDF document encrypted with all permissions options. - /// bool hasAllPermissions = true; - /// permissions.forEach((PdfPermissionsFlags flag) { - /// if (flag != PdfPermissionsFlags.none) { - /// hasAllPermissions &= permissions.contains(flag); - /// } - /// }); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void forEach(void Function(PdfPermissionsFlags element) action) { - final int length = count; - for (int i = 0; i < count; i++) { - action(this[i]); - if (length != count) { - throw ConcurrentModificationError(this); - } - } - } - - /// Get the permissions count. - /// - /// ```dart - /// //Load encrypted PDF document with password. - /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); - /// //Document security - /// PdfSecurity security = document.security; - /// //Gets the PDF permission. - /// PdfPermissions permissions = security.permissions; - /// //Gets the permissions count. - /// int count = permissions.count; - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get count => _permissions.length; - - /// Add the permission. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Document security - /// PdfSecurity security = document.security; - /// //Add permission. - /// security.permissions.add(PdfPermissionsFlags.editContent); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void add(PdfPermissionsFlags permission) { - if (!_permissions.contains(permission)) { - _permissions.add(permission); - _encryptor.permissions = _permissions; - _encryptor.encrypt = true; - _modifiedPermissions = true; - } - } - - /// Add the permissions. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Document security - /// PdfSecurity security = document.security; - /// //Add permissions. - /// security.permissions.addAll([ - /// PdfPermissionsFlags.editContent, - /// PdfPermissionsFlags.copyContent]); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void addAll(List permission) { - bool isChanged = false; - if (permission.isNotEmpty) { - permission.toList().forEach((PdfPermissionsFlags flag) { - if (!_permissions.contains(flag)) { - _permissions.add(flag); - isChanged = true; - _modifiedPermissions = true; - } - }); - } - if (isChanged) { - _encryptor.permissions = _permissions; - _encryptor.encrypt = true; - _modifiedPermissions = true; - } - } - - /// Remove permissions from an existing PDF. - /// - /// ```dart - /// //Load encrypted PDF document with password. - /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); - /// //Document security - /// PdfSecurity security = document.security; - /// //Gets the pdf permission. - /// PdfPermissions permissions = security.permissions; - /// //Remove permission. - /// permissions.remove(PdfPermissionsFlags.editContent); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void remove(PdfPermissionsFlags permission) { - if (_permissions.contains(permission)) { - _permissions.remove(permission); - _encryptor.permissions = _permissions; - _encryptor.encrypt = true; - _modifiedPermissions = true; - } - } - - /// Remove all permissions from an existing PDF and set default. - /// - /// ```dart - /// //Load encrypted PDF document with password. - /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); - /// //Document security - /// PdfSecurity security = document.security; - /// //Gets the pdf permission. - /// PdfPermissions permissions = security.permissions; - /// //Remove all permissions and set default. - /// permissions.clear(); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void clear() { - if (!(_permissions.contains(PdfPermissionsFlags.none) && - _permissions.length == 1)) { - _permissions = [PdfPermissionsFlags.none]; - _encryptor.permissions = _permissions; - _encryptor.encrypt = true; - _modifiedPermissions = true; - } - } - - PdfPermissionsFlags _returnValue(int index) { - if (index < 0 || index >= count) { - throw ArgumentError.value(index, 'Index out of range'); - } - return _permissions[index]; - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfPermissions] helper -class PdfPermissionsHelper { - /// internal method - static PdfEncryptor getEncryptor(PdfPermissions permissions) { - return permissions._encryptor; - } - - /// internal method - static bool isModifiedPermissions(PdfPermissions permissions, [bool? value]) { - if (value != null) { - permissions._modifiedPermissions = value; - } - return permissions._modifiedPermissions; - } -} +import 'enum.dart'; +import 'pdf_encryptor.dart'; + +/// Represents the security settings of the PDF document. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Document security +/// PdfSecurity security = document.security; +/// //Set security options +/// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; +/// security.userPassword = 'password'; +/// security.ownerPassword = 'syncfusion'; +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfSecurity { + //constructor + /// Initializes a new instance of the [PdfSecurity] class. + PdfSecurity._() { + _helper = PdfSecurityHelper(this); + _initialize(); + } + + //Fields + PdfPermissions? _permissions; + late PdfSecurityHelper _helper; + + /// Gets the type of encryption algorithm used. + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); + /// //Get encryption algorithm + /// PdfEncryptionAlgorithm algorithm = document.security.algorithm; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfEncryptionAlgorithm get algorithm { + return _helper.encryptor.encryptionAlgorithm!; + } + + /// Sets the type of encryption algorithm. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Document security + /// PdfSecurity security = document.security; + /// //Set security options + /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; + /// security.userPassword = 'password'; + /// security.ownerPassword = 'syncfusion'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + set algorithm(PdfEncryptionAlgorithm value) { + _helper.encryptor.encryptionAlgorithm = value; + _helper.encryptor.encrypt = true; + _helper.encryptor.changed = true; + _helper.encryptor.hasComputedPasswordValues = false; + _helper.modifiedSecurity = true; + } + + /// Gets the owner password. + /// + /// If the PDF document is password protected you can use the owner password + /// to open the document and change its permissions. + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); + /// //Get the owner password. + /// String ownerPassword = document.security.ownerPassword; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String get ownerPassword { + return _helper.encryptAttachments ? '' : _helper.encryptor.ownerPassword; + } + + /// Sets the owner password. + /// + /// If the PDF document is password protected you can use the owner password + /// to open the document and change its permissions. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Document security + /// PdfSecurity security = document.security; + /// //Set security options + /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; + /// security.userPassword = 'password'; + /// security.ownerPassword = 'syncfusion'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + set ownerPassword(String value) { + if (_helper.conformance) { + throw ArgumentError( + 'Document encryption is not allowed with Conformance documents.', + ); + } + _helper.encryptor.ownerPassword = value; + _helper.encryptor.encrypt = true; + _helper.modifiedSecurity = true; + } + + /// Gets the user password. + /// + /// User password is required when the PDF document is opened in a viewer. + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); + /// //Get the user password. + /// String userPassword = document.security.userPassword; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String get userPassword { + return _helper.encryptor.userPassword; + } + + /// Sets the user password. + /// + /// User password is required when the PDF document is opened in a viewer. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Document security + /// PdfSecurity security = document.security; + /// //Set security options + /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; + /// security.userPassword = 'password'; + /// security.ownerPassword = 'syncfusion'; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + set userPassword(String value) { + if (_helper.conformance) { + throw ArgumentError( + 'Document encryption is not allowed with Conformance documents.', + ); + } + _helper.encryptor.userPassword = value; + _helper.encryptor.encrypt = true; + _helper.modifiedSecurity = true; + } + + /// Gets the permissions when the document is opened with user password. + /// + /// We can add or remove permissions flags by using add() and remove() method + /// in [PdfPermissions] class. + /// + /// ```dart + /// //Load an exisiting PDF document. + /// PdfDocument document = PdfDocument.fromBase64String(pdfData, 'password'); + /// //Get the permissions. + /// PdfPermissions pdfPermissions = document.security.permissions; + /// //Add permissions + /// permissions.add([PdfPermissionsFlags.editContent, PdfPermissionsFlags.copyContent]); + /// //Remove permissions + /// permissions.remove([PdfPermissionsFlags.editContent, PdfPermissionsFlags.copyContent]); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPermissions get permissions { + _permissions ??= PdfPermissions._( + _helper.encryptor, + _helper.encryptor.permissions, + ); + return _permissions!; + } + + /// Gets or sets the type of encryption options used. + /// + /// User password is required when the PDF document is opened in a viewer. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Document security + /// PdfSecurity security = document.security; + /// //Set security options + /// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; + /// security.userPassword = 'password'; + /// security.ownerPassword = 'syncfusion'; + /// security.encryptionOptions = PdfEncryptionOptions.encryptAllContents; + /// //Create and add attachment to the PDF document + /// document.attachments.add(PdfAttachment( + /// 'input.txt', File('input.txt').readAsBytesSync(), + /// description: 'Text File', mimeType: 'application/txt')); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfEncryptionOptions get encryptionOptions => + _helper.encryptor.encryptionOptions; + set encryptionOptions(PdfEncryptionOptions value) { + if (_helper.conformance) { + throw ArgumentError( + 'Document encryption is not allowed with Conformance documents.', + ); + } + if (_helper.encryptor.encryptionOptions != value) { + _helper.encryptor.encryptionOptions = value; + _helper.encryptor.encrypt = true; + _helper.encryptor.changed = true; + _helper.modifiedSecurity = true; + _helper.encryptor.hasComputedPasswordValues = false; + if (PdfEncryptionOptions.encryptOnlyAttachments == value) { + _helper.encryptAttachments = true; + _helper.encryptor.encryptMetadata = false; + } else if (PdfEncryptionOptions.encryptAllContentsExceptMetadata == + value) { + _helper.encryptAttachments = false; + _helper.encryptor.encryptMetadata = false; + } else { + _helper.encryptAttachments = false; + _helper.encryptor.encryptMetadata = true; + } + } + } + + //Implementation + void _initialize() { + _helper.encryptAttachmentOnly = false; + _helper.encryptor = PdfEncryptor(); + } +} + +/// [PdfSecurity] helper +class PdfSecurityHelper { + /// internal constructor + PdfSecurityHelper(this.base); + + /// internal field + PdfSecurity base; + + /// internal method + static PdfSecurityHelper getHelper(PdfSecurity base) { + return base._helper; + } + + /// internal field + late PdfEncryptor encryptor; + + /// internal field + late bool encryptAttachmentOnly; + + /// internal property + bool get encryptAttachments { + return encryptAttachmentOnly; + } + + set encryptAttachments(bool value) { + encryptAttachmentOnly = value; + encryptor.encryptOnlyAttachment = value; + encryptor.changed = true; + } + + /// internal field + // ignore: prefer_final_fields + bool conformance = false; + + /// internal field + bool modifiedSecurity = false; + + /// internal method + static PdfSecurity getSecurity() { + return PdfSecurity._(); + } +} + +/// Represents the permissions of the PDF document. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Document security +/// PdfSecurity security = document.security; +/// //Set security options +/// security.algorithm = PdfEncryptionAlgorithm.rc4x128Bit; +/// security.userPassword = 'password'; +/// security.ownerPassword = 'syncfusion'; +/// //Get PDF permission. +/// PdfPermissions permissions = security.permissions; +/// //Add permissions. +/// permissions.add([PdfPermissionsFlags.print]); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfPermissions { + //constructor + PdfPermissions._( + PdfEncryptor encryptor, + List permissions, + ) { + _encryptor = encryptor; + _permissions = permissions; + } + + //Fields + late PdfEncryptor _encryptor; + late List _permissions; + bool _modifiedPermissions = false; + + //Implementation + /// Get the permissions. + /// + /// ```dart + /// //Load encrypted PDF document with password. + /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); + /// //Document security + /// PdfSecurity security = document.security; + /// //Gets the PDF permission. + /// PdfPermissions permissions = security.permissions; + /// //Gets the permission option at index 0. + /// PdfPermissionsFlags permission = permissions[0]; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPermissionsFlags operator [](int index) => _returnValue(index); + + /// Iterate for each element in permissions and perform action. + /// + /// ```dart + /// //Load encrypted PDF document with password. + /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); + /// //Document security + /// PdfSecurity security = document.security; + /// //Gets the PDF permission. + /// PdfPermissions permissions = security.permissions; + /// List permissions = [ + /// PdfPermissionsFlags.print, + /// PdfPermissionsFlags.editContent, + /// PdfPermissionsFlags.copyContent, + /// PdfPermissionsFlags.editAnnotations, + /// PdfPermissionsFlags.fillFields, + /// PdfPermissionsFlags.accessibilityCopyContent, + /// PdfPermissionsFlags.assembleDocument, + /// PdfPermissionsFlags.fullQualityPrint]; + /// //Check the PDF document encrypted with all permissions options. + /// bool hasAllPermissions = true; + /// permissions.forEach((PdfPermissionsFlags flag) { + /// if (flag != PdfPermissionsFlags.none) { + /// hasAllPermissions &= permissions.contains(flag); + /// } + /// }); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void forEach(void Function(PdfPermissionsFlags element) action) { + final int length = count; + for (int i = 0; i < count; i++) { + action(this[i]); + if (length != count) { + throw ConcurrentModificationError(this); + } + } + } + + /// Get the permissions count. + /// + /// ```dart + /// //Load encrypted PDF document with password. + /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); + /// //Document security + /// PdfSecurity security = document.security; + /// //Gets the PDF permission. + /// PdfPermissions permissions = security.permissions; + /// //Gets the permissions count. + /// int count = permissions.count; + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get count => _permissions.length; + + /// Add the permission. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Document security + /// PdfSecurity security = document.security; + /// //Add permission. + /// security.permissions.add(PdfPermissionsFlags.editContent); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void add(PdfPermissionsFlags permission) { + if (!_permissions.contains(permission)) { + _permissions.add(permission); + _encryptor.permissions = _permissions; + _encryptor.encrypt = true; + _modifiedPermissions = true; + } + } + + /// Add the permissions. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Document security + /// PdfSecurity security = document.security; + /// //Add permissions. + /// security.permissions.addAll([ + /// PdfPermissionsFlags.editContent, + /// PdfPermissionsFlags.copyContent]); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void addAll(List permission) { + bool isChanged = false; + if (permission.isNotEmpty) { + permission.toList().forEach((PdfPermissionsFlags flag) { + if (!_permissions.contains(flag)) { + _permissions.add(flag); + isChanged = true; + _modifiedPermissions = true; + } + }); + } + if (isChanged) { + _encryptor.permissions = _permissions; + _encryptor.encrypt = true; + _modifiedPermissions = true; + } + } + + /// Remove permissions from an existing PDF. + /// + /// ```dart + /// //Load encrypted PDF document with password. + /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); + /// //Document security + /// PdfSecurity security = document.security; + /// //Gets the pdf permission. + /// PdfPermissions permissions = security.permissions; + /// //Remove permission. + /// permissions.remove(PdfPermissionsFlags.editContent); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void remove(PdfPermissionsFlags permission) { + if (_permissions.contains(permission)) { + _permissions.remove(permission); + _encryptor.permissions = _permissions; + _encryptor.encrypt = true; + _modifiedPermissions = true; + } + } + + /// Remove all permissions from an existing PDF and set default. + /// + /// ```dart + /// //Load encrypted PDF document with password. + /// PdfDocument document = PdfDocument(inputBytes: pdfData, password: 'password'); + /// //Document security + /// PdfSecurity security = document.security; + /// //Gets the pdf permission. + /// PdfPermissions permissions = security.permissions; + /// //Remove all permissions and set default. + /// permissions.clear(); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void clear() { + if (!(_permissions.contains(PdfPermissionsFlags.none) && + _permissions.length == 1)) { + _permissions = [PdfPermissionsFlags.none]; + _encryptor.permissions = _permissions; + _encryptor.encrypt = true; + _modifiedPermissions = true; + } + } + + PdfPermissionsFlags _returnValue(int index) { + if (index < 0 || index >= count) { + throw ArgumentError.value(index, 'Index out of range'); + } + return _permissions[index]; + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfPermissions] helper +class PdfPermissionsHelper { + /// internal method + static PdfEncryptor getEncryptor(PdfPermissions permissions) { + return permissions._encryptor; + } + + /// internal method + static bool isModifiedPermissions(PdfPermissions permissions, [bool? value]) { + if (value != null) { + permissions._modifiedPermissions = value; + } + return permissions._modifiedPermissions; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/enums.dart index 4ed00fb69..c7e22c303 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/enums.dart @@ -1,373 +1,373 @@ -///Specifies the alignment type. -enum PdfGridImagePosition { - /// To fit image to the cell based on the cell width and height. - fit, - - /// The image is rendered by center of the cell. - center, - - /// The image is stretched by the percentages required - /// to fit the width and height of the cell. - stretch, - - /// The image is rendered by tile mode. - tile, -} - -/// internal enumerator -enum PdfGridStretchOption { - /// The content is resized to fill the destination dimensions. - /// The aspect ratio is not preserved. - fill, - - /// The content is resized to fit in the destination dimensions, - /// while it preserves its native aspect ratio. - uniform, - - /// The content is resized to fill the destination dimensions, - /// while it preserves its native aspect ratio. - /// If the aspect ratio of the destination rectangle differs from the source, - /// the source content is clipped to fit in the destination dimensions. - uniformToFill, - - /// The content preserves its original size. - none, -} - -/// Describe the possible values of [PdfHorizontalOverflowType]. -/// If a grid is drawn which doesn't fits within a single page, -/// it will be splited to several pages. -enum PdfHorizontalOverflowType { - /// Draws the overflowing grid as next page - nextPage, - - /// Draws the overflowing grid as last page - lastPage, -} - -/// Specifies the values of the border overlap style. -enum PdfBorderOverlapStyle { - /// Cell borders overlap (are drawn using the same coordinates). - overlap, - - /// Cell borders are drawn in the cell's interior. - inside, -} - -/// Specifies PdfGrid built-in table styles. -enum PdfGridBuiltInStyle { - /// Specifies the grid to render Plain Table 1 style. - plainTable1, - - /// Specifies the grid to render Plain Table 2 style. - plainTable2, - - /// Specifies the grid to render Plain Table 3 style. - plainTable3, - - /// Specifies the grid to render Plain Table 4 style. - plainTable4, - - /// Specifies the grid to render Plain Table 5 style. - plainTable5, - - /// Specifies the grid to render Grid Table 1 Light style. - gridTable1Light, - - /// Specifies the grid to render Grid Table 1 Light - Accent 1 style. - gridTable1LightAccent1, - - /// Specifies the grid to render Grid Table 1 Light - Accent 2 style. - gridTable1LightAccent2, - - /// Specifies the grid to render Grid Table 1 Light - Accent 3 style. - gridTable1LightAccent3, - - /// Specifies the grid to render Grid Table 1 Light - Accent 4 style. - gridTable1LightAccent4, - - /// Specifies the grid to render Grid Table 1 Light - Accent 5 style. - gridTable1LightAccent5, - - /// Specifies the grid to render Grid Table 1 Light - Accent 6 style. - gridTable1LightAccent6, - - /// Specifies the grid to render Grid Table 2 style. - gridTable2, - - /// Specifies the grid to render Grid Table 2 - Accent 1 style. - gridTable2Accent1, - - /// Specifies the grid to render Grid Table 2 - Accent 2 style. - gridTable2Accent2, - - /// Specifies the grid to render Grid Table 2 - Accent 3 style. - gridTable2Accent3, - - /// Specifies the grid to render Grid Table 2 - Accent 4 style. - gridTable2Accent4, - - /// Specifies the grid to render Grid Table 2 - Accent 5 style. - gridTable2Accent5, - - /// Specifies the grid to render Grid Table 2 - Accent 6 style. - gridTable2Accent6, - - /// Specifies the grid to render Grid Table 3 style. - gridTable3, - - /// Specifies the grid to render Grid Table 3 - Accent 1 style. - gridTable3Accent1, - - /// Specifies the grid to render Grid Table 3 - Accent 2 style. - gridTable3Accent2, - - /// Specifies the grid to render Grid Table 3 - Accent 3 style. - gridTable3Accent3, - - /// Specifies the grid to render Grid Table 3 - Accent 4 style. - gridTable3Accent4, - - /// Specifies the grid to render Grid Table 3 - Accent 5 style. - gridTable3Accent5, - - /// Specifies the grid to render Grid Table 3 - Accent 6 style. - gridTable3Accent6, - - /// Specifies the grid to render Grid Table 4 style. - gridTable4, - - /// Specifies the grid to render Grid Table 4 - Accent 1 style. - gridTable4Accent1, - - /// Specifies the grid to render Grid Table 4 - Accent 2 style. - gridTable4Accent2, - - /// Specifies the grid to render Grid Table 4 - Accent 3 style. - gridTable4Accent3, - - /// Specifies the grid to render Grid Table 4 - Accent 4 style. - gridTable4Accent4, - - /// Specifies the grid to render Grid Table 4 - Accent 5 style. - gridTable4Accent5, - - /// Specifies the grid to render Grid Table 4 - Accent 6 style. - gridTable4Accent6, - - /// Specifies the grid to render Grid Table 5 Dark style. - gridTable5Dark, - - /// Specifies the grid to render Grid Table 5 Dark - Accent 1 style. - gridTable5DarkAccent1, - - /// Specifies the grid to render Grid Table 5 Dark - Accent 2 style. - gridTable5DarkAccent2, - - /// Specifies the grid to render Grid Table 5 Dark - Accent 3 style. - gridTable5DarkAccent3, - - /// Specifies the grid to render Grid Table 5 Dark - Accent 4 style. - gridTable5DarkAccent4, - - /// Specifies the grid to render Grid Table 5 Dark - Accent 5 style. - gridTable5DarkAccent5, - - /// Specifies the grid to render Grid Table 5 Dark - Accent 6 style. - gridTable5DarkAccent6, - - /// Specifies the grid to render Grid Table 6 Colorful style. - gridTable6Colorful, - - /// Specifies the grid to render Grid Table 6 Colorful - Accent 1 style. - gridTable6ColorfulAccent1, - - /// Specifies the grid to render Grid Table 6 Colorful - Accent 2 style. - gridTable6ColorfulAccent2, - - /// Specifies the grid to render Grid Table 6 Colorful - Accent 3 style. - gridTable6ColorfulAccent3, - - /// Specifies the grid to render Grid Table 6 Colorful - Accent 4 style. - gridTable6ColorfulAccent4, - - /// Specifies the grid to render Grid Table 6 Colorful - Accent 5 style. - gridTable6ColorfulAccent5, - - /// Specifies the grid to render Grid Table 6 Colorful - Accent 6 style. - gridTable6ColorfulAccent6, - - /// Specifies the grid to render Grid Table 7 Colorful style. - gridTable7Colorful, - - /// Specifies the grid to render Grid Table 7 Colorful - Accent 1 style. - gridTable7ColorfulAccent1, - - /// Specifies the grid to render Grid Table 7 Colorful - Accent 2 style. - gridTable7ColorfulAccent2, - - /// Specifies the grid to render Grid Table 7 Colorful - Accent 3 style. - gridTable7ColorfulAccent3, - - /// Specifies the grid to render Grid Table 7 Colorful - Accent 4 style. - gridTable7ColorfulAccent4, - - /// Specifies the grid to render Grid Table 7 Colorful - Accent 5 style. - gridTable7ColorfulAccent5, - - /// Specifies the grid to render Grid Table 7 Colorful - Accent 6 style. - gridTable7ColorfulAccent6, - - /// Specifies the grid to render Light Table 1 Light style. - listTable1Light, - - /// Specifies the grid to render Light Table 1 Light - Accent 1 style. - listTable1LightAccent1, - - /// Specifies the grid to render Light Table 1 Light - Accent 2 style. - listTable1LightAccent2, - - /// Specifies the grid to render Light Table 1 Light - Accent 3 style. - listTable1LightAccent3, - - /// Specifies the grid to render Light Table 1 Light - Accent 4 style. - listTable1LightAccent4, - - /// Specifies the grid to render Light Table 1 Light - Accent 5 style. - listTable1LightAccent5, - - /// Specifies the grid to render Light Table 1 Light - Accent 6 style. - listTable1LightAccent6, - - /// Specifies the grid to render Light Table 2 style. - listTable2, - - /// Specifies the grid to render Light Table 2 - Accent 1 style. - listTable2Accent1, - - /// Specifies the grid to render Light Table 2 - Accent 2 style. - listTable2Accent2, - - /// Specifies the grid to render Light Table 2 - Accent 3 style. - listTable2Accent3, - - /// Specifies the grid to render Light Table 2 - Accent 4 style. - listTable2Accent4, - - /// Specifies the grid to render Light Table 2 - Accent 5 style. - listTable2Accent5, - - /// Specifies the grid to render Light Table 2 - Accent 6 style. - listTable2Accent6, - - /// Specifies the grid to render Light Table 3 style. - listTable3, - - /// Specifies the grid to render Light Table 3 - Accent 1 style. - listTable3Accent1, - - /// Specifies the grid to render Light Table 3 - Accent 2 style. - listTable3Accent2, - - /// Specifies the grid to render Light Table 3 - Accent 3 style. - listTable3Accent3, - - /// Specifies the grid to render Light Table 3 - Accent 4 style. - listTable3Accent4, - - /// Specifies the grid to render Light Table 3 - Accent 5 style. - listTable3Accent5, - - /// Specifies the grid to render Light Table 3 - Accent 6 style. - listTable3Accent6, - - /// Specifies the grid to render Light Table 4 style. - listTable4, - - /// Specifies the grid to render Light Table 4 - Accent 1 style. - listTable4Accent1, - - /// Specifies the grid to render Light Table 4 - Accent 2 style. - listTable4Accent2, - - /// Specifies the grid to render Light Table 4 - Accent 3 style. - listTable4Accent3, - - /// Specifies the grid to render Light Table 4 - Accent 4 style. - listTable4Accent4, - - /// Specifies the grid to render Light Table 4 - Accent 5 style. - listTable4Accent5, - - /// Specifies the grid to render Light Table 4 - Accent 6 style. - listTable4Accent6, - - /// Specifies the grid to render Light Table 5 Dark style. - listTable5Dark, - - /// Specifies the grid to render Light Table 5 Dark - Accent 1 style. - listTable5DarkAccent1, - - /// Specifies the grid to render Light Table 5 Dark - Accent 2 style. - listTable5DarkAccent2, - - /// Specifies the grid to render Light Table 5 Dark - Accent 3 style. - listTable5DarkAccent3, - - /// Specifies the grid to render Light Table 5 Dark - Accent 4 style. - listTable5DarkAccent4, - - /// Specifies the grid to render Light Table 5 Dark - Accent 5 style. - listTable5DarkAccent5, - - /// Specifies the grid to render Light Table 5 Dark - Accent 6 style. - listTable5DarkAccent6, - - /// Specifies the grid to render Light Table 6 Colorful style. - listTable6Colorful, - - /// Specifies the grid to render Light Table 6 Colorful - Accent 1 style. - listTable6ColorfulAccent1, - - /// Specifies the grid to render Light Table 6 Colorful - Accent 2 style. - listTable6ColorfulAccent2, - - /// Specifies the grid to render Light Table 6 Colorful - Accent 3 style. - listTable6ColorfulAccent3, - - /// Specifies the grid to render Light Table 6 Colorful - Accent 4 style. - listTable6ColorfulAccent4, - - /// Specifies the grid to render Light Table 6 Colorful - Accent 5 style. - listTable6ColorfulAccent5, - - /// Specifies the grid to render Light Table 6 Colorful - Accent 6 style. - listTable6ColorfulAccent6, - - /// Specifies the grid to render Light Table 7 Colorful style. - listTable7Colorful, - - /// Specifies the grid to render Light Table 7 Colorful - Accent 1 style. - listTable7ColorfulAccent1, - - /// Specifies the grid to render Light Table 7 Colorful - Accent 2 style. - listTable7ColorfulAccent2, - - /// Specifies the grid to render Light Table 7 Colorful - Accent 3 style. - listTable7ColorfulAccent3, - - /// Specifies the grid to render Light Table 7 Colorful - Accent 4 style. - listTable7ColorfulAccent4, - - /// Specifies the grid to render Light Table 7 Colorful - Accent 5 style. - listTable7ColorfulAccent5, - - /// Specifies the grid to render Light Table 7 Colorful - Accent 6 style. - listTable7ColorfulAccent6, - - /// Specifies the grid to render Table Grid Light style. - tableGridLight, - - /// Specifies the grid to render Table Grid style. - tableGrid, -} +///Specifies the alignment type. +enum PdfGridImagePosition { + /// To fit image to the cell based on the cell width and height. + fit, + + /// The image is rendered by center of the cell. + center, + + /// The image is stretched by the percentages required + /// to fit the width and height of the cell. + stretch, + + /// The image is rendered by tile mode. + tile, +} + +/// internal enumerator +enum PdfGridStretchOption { + /// The content is resized to fill the destination dimensions. + /// The aspect ratio is not preserved. + fill, + + /// The content is resized to fit in the destination dimensions, + /// while it preserves its native aspect ratio. + uniform, + + /// The content is resized to fill the destination dimensions, + /// while it preserves its native aspect ratio. + /// If the aspect ratio of the destination rectangle differs from the source, + /// the source content is clipped to fit in the destination dimensions. + uniformToFill, + + /// The content preserves its original size. + none, +} + +/// Describe the possible values of [PdfHorizontalOverflowType]. +/// If a grid is drawn which doesn't fits within a single page, +/// it will be splited to several pages. +enum PdfHorizontalOverflowType { + /// Draws the overflowing grid as next page + nextPage, + + /// Draws the overflowing grid as last page + lastPage, +} + +/// Specifies the values of the border overlap style. +enum PdfBorderOverlapStyle { + /// Cell borders overlap (are drawn using the same coordinates). + overlap, + + /// Cell borders are drawn in the cell's interior. + inside, +} + +/// Specifies PdfGrid built-in table styles. +enum PdfGridBuiltInStyle { + /// Specifies the grid to render Plain Table 1 style. + plainTable1, + + /// Specifies the grid to render Plain Table 2 style. + plainTable2, + + /// Specifies the grid to render Plain Table 3 style. + plainTable3, + + /// Specifies the grid to render Plain Table 4 style. + plainTable4, + + /// Specifies the grid to render Plain Table 5 style. + plainTable5, + + /// Specifies the grid to render Grid Table 1 Light style. + gridTable1Light, + + /// Specifies the grid to render Grid Table 1 Light - Accent 1 style. + gridTable1LightAccent1, + + /// Specifies the grid to render Grid Table 1 Light - Accent 2 style. + gridTable1LightAccent2, + + /// Specifies the grid to render Grid Table 1 Light - Accent 3 style. + gridTable1LightAccent3, + + /// Specifies the grid to render Grid Table 1 Light - Accent 4 style. + gridTable1LightAccent4, + + /// Specifies the grid to render Grid Table 1 Light - Accent 5 style. + gridTable1LightAccent5, + + /// Specifies the grid to render Grid Table 1 Light - Accent 6 style. + gridTable1LightAccent6, + + /// Specifies the grid to render Grid Table 2 style. + gridTable2, + + /// Specifies the grid to render Grid Table 2 - Accent 1 style. + gridTable2Accent1, + + /// Specifies the grid to render Grid Table 2 - Accent 2 style. + gridTable2Accent2, + + /// Specifies the grid to render Grid Table 2 - Accent 3 style. + gridTable2Accent3, + + /// Specifies the grid to render Grid Table 2 - Accent 4 style. + gridTable2Accent4, + + /// Specifies the grid to render Grid Table 2 - Accent 5 style. + gridTable2Accent5, + + /// Specifies the grid to render Grid Table 2 - Accent 6 style. + gridTable2Accent6, + + /// Specifies the grid to render Grid Table 3 style. + gridTable3, + + /// Specifies the grid to render Grid Table 3 - Accent 1 style. + gridTable3Accent1, + + /// Specifies the grid to render Grid Table 3 - Accent 2 style. + gridTable3Accent2, + + /// Specifies the grid to render Grid Table 3 - Accent 3 style. + gridTable3Accent3, + + /// Specifies the grid to render Grid Table 3 - Accent 4 style. + gridTable3Accent4, + + /// Specifies the grid to render Grid Table 3 - Accent 5 style. + gridTable3Accent5, + + /// Specifies the grid to render Grid Table 3 - Accent 6 style. + gridTable3Accent6, + + /// Specifies the grid to render Grid Table 4 style. + gridTable4, + + /// Specifies the grid to render Grid Table 4 - Accent 1 style. + gridTable4Accent1, + + /// Specifies the grid to render Grid Table 4 - Accent 2 style. + gridTable4Accent2, + + /// Specifies the grid to render Grid Table 4 - Accent 3 style. + gridTable4Accent3, + + /// Specifies the grid to render Grid Table 4 - Accent 4 style. + gridTable4Accent4, + + /// Specifies the grid to render Grid Table 4 - Accent 5 style. + gridTable4Accent5, + + /// Specifies the grid to render Grid Table 4 - Accent 6 style. + gridTable4Accent6, + + /// Specifies the grid to render Grid Table 5 Dark style. + gridTable5Dark, + + /// Specifies the grid to render Grid Table 5 Dark - Accent 1 style. + gridTable5DarkAccent1, + + /// Specifies the grid to render Grid Table 5 Dark - Accent 2 style. + gridTable5DarkAccent2, + + /// Specifies the grid to render Grid Table 5 Dark - Accent 3 style. + gridTable5DarkAccent3, + + /// Specifies the grid to render Grid Table 5 Dark - Accent 4 style. + gridTable5DarkAccent4, + + /// Specifies the grid to render Grid Table 5 Dark - Accent 5 style. + gridTable5DarkAccent5, + + /// Specifies the grid to render Grid Table 5 Dark - Accent 6 style. + gridTable5DarkAccent6, + + /// Specifies the grid to render Grid Table 6 Colorful style. + gridTable6Colorful, + + /// Specifies the grid to render Grid Table 6 Colorful - Accent 1 style. + gridTable6ColorfulAccent1, + + /// Specifies the grid to render Grid Table 6 Colorful - Accent 2 style. + gridTable6ColorfulAccent2, + + /// Specifies the grid to render Grid Table 6 Colorful - Accent 3 style. + gridTable6ColorfulAccent3, + + /// Specifies the grid to render Grid Table 6 Colorful - Accent 4 style. + gridTable6ColorfulAccent4, + + /// Specifies the grid to render Grid Table 6 Colorful - Accent 5 style. + gridTable6ColorfulAccent5, + + /// Specifies the grid to render Grid Table 6 Colorful - Accent 6 style. + gridTable6ColorfulAccent6, + + /// Specifies the grid to render Grid Table 7 Colorful style. + gridTable7Colorful, + + /// Specifies the grid to render Grid Table 7 Colorful - Accent 1 style. + gridTable7ColorfulAccent1, + + /// Specifies the grid to render Grid Table 7 Colorful - Accent 2 style. + gridTable7ColorfulAccent2, + + /// Specifies the grid to render Grid Table 7 Colorful - Accent 3 style. + gridTable7ColorfulAccent3, + + /// Specifies the grid to render Grid Table 7 Colorful - Accent 4 style. + gridTable7ColorfulAccent4, + + /// Specifies the grid to render Grid Table 7 Colorful - Accent 5 style. + gridTable7ColorfulAccent5, + + /// Specifies the grid to render Grid Table 7 Colorful - Accent 6 style. + gridTable7ColorfulAccent6, + + /// Specifies the grid to render Light Table 1 Light style. + listTable1Light, + + /// Specifies the grid to render Light Table 1 Light - Accent 1 style. + listTable1LightAccent1, + + /// Specifies the grid to render Light Table 1 Light - Accent 2 style. + listTable1LightAccent2, + + /// Specifies the grid to render Light Table 1 Light - Accent 3 style. + listTable1LightAccent3, + + /// Specifies the grid to render Light Table 1 Light - Accent 4 style. + listTable1LightAccent4, + + /// Specifies the grid to render Light Table 1 Light - Accent 5 style. + listTable1LightAccent5, + + /// Specifies the grid to render Light Table 1 Light - Accent 6 style. + listTable1LightAccent6, + + /// Specifies the grid to render Light Table 2 style. + listTable2, + + /// Specifies the grid to render Light Table 2 - Accent 1 style. + listTable2Accent1, + + /// Specifies the grid to render Light Table 2 - Accent 2 style. + listTable2Accent2, + + /// Specifies the grid to render Light Table 2 - Accent 3 style. + listTable2Accent3, + + /// Specifies the grid to render Light Table 2 - Accent 4 style. + listTable2Accent4, + + /// Specifies the grid to render Light Table 2 - Accent 5 style. + listTable2Accent5, + + /// Specifies the grid to render Light Table 2 - Accent 6 style. + listTable2Accent6, + + /// Specifies the grid to render Light Table 3 style. + listTable3, + + /// Specifies the grid to render Light Table 3 - Accent 1 style. + listTable3Accent1, + + /// Specifies the grid to render Light Table 3 - Accent 2 style. + listTable3Accent2, + + /// Specifies the grid to render Light Table 3 - Accent 3 style. + listTable3Accent3, + + /// Specifies the grid to render Light Table 3 - Accent 4 style. + listTable3Accent4, + + /// Specifies the grid to render Light Table 3 - Accent 5 style. + listTable3Accent5, + + /// Specifies the grid to render Light Table 3 - Accent 6 style. + listTable3Accent6, + + /// Specifies the grid to render Light Table 4 style. + listTable4, + + /// Specifies the grid to render Light Table 4 - Accent 1 style. + listTable4Accent1, + + /// Specifies the grid to render Light Table 4 - Accent 2 style. + listTable4Accent2, + + /// Specifies the grid to render Light Table 4 - Accent 3 style. + listTable4Accent3, + + /// Specifies the grid to render Light Table 4 - Accent 4 style. + listTable4Accent4, + + /// Specifies the grid to render Light Table 4 - Accent 5 style. + listTable4Accent5, + + /// Specifies the grid to render Light Table 4 - Accent 6 style. + listTable4Accent6, + + /// Specifies the grid to render Light Table 5 Dark style. + listTable5Dark, + + /// Specifies the grid to render Light Table 5 Dark - Accent 1 style. + listTable5DarkAccent1, + + /// Specifies the grid to render Light Table 5 Dark - Accent 2 style. + listTable5DarkAccent2, + + /// Specifies the grid to render Light Table 5 Dark - Accent 3 style. + listTable5DarkAccent3, + + /// Specifies the grid to render Light Table 5 Dark - Accent 4 style. + listTable5DarkAccent4, + + /// Specifies the grid to render Light Table 5 Dark - Accent 5 style. + listTable5DarkAccent5, + + /// Specifies the grid to render Light Table 5 Dark - Accent 6 style. + listTable5DarkAccent6, + + /// Specifies the grid to render Light Table 6 Colorful style. + listTable6Colorful, + + /// Specifies the grid to render Light Table 6 Colorful - Accent 1 style. + listTable6ColorfulAccent1, + + /// Specifies the grid to render Light Table 6 Colorful - Accent 2 style. + listTable6ColorfulAccent2, + + /// Specifies the grid to render Light Table 6 Colorful - Accent 3 style. + listTable6ColorfulAccent3, + + /// Specifies the grid to render Light Table 6 Colorful - Accent 4 style. + listTable6ColorfulAccent4, + + /// Specifies the grid to render Light Table 6 Colorful - Accent 5 style. + listTable6ColorfulAccent5, + + /// Specifies the grid to render Light Table 6 Colorful - Accent 6 style. + listTable6ColorfulAccent6, + + /// Specifies the grid to render Light Table 7 Colorful style. + listTable7Colorful, + + /// Specifies the grid to render Light Table 7 Colorful - Accent 1 style. + listTable7ColorfulAccent1, + + /// Specifies the grid to render Light Table 7 Colorful - Accent 2 style. + listTable7ColorfulAccent2, + + /// Specifies the grid to render Light Table 7 Colorful - Accent 3 style. + listTable7ColorfulAccent3, + + /// Specifies the grid to render Light Table 7 Colorful - Accent 4 style. + listTable7ColorfulAccent4, + + /// Specifies the grid to render Light Table 7 Colorful - Accent 5 style. + listTable7ColorfulAccent5, + + /// Specifies the grid to render Light Table 7 Colorful - Accent 6 style. + listTable7ColorfulAccent6, + + /// Specifies the grid to render Table Grid Light style. + tableGridLight, + + /// Specifies the grid to render Table Grid style. + tableGrid, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/layouting/pdf_grid_layouter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/layouting/pdf_grid_layouter.dart index 4458a229d..607075090 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/layouting/pdf_grid_layouter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/layouting/pdf_grid_layouter.dart @@ -1,1994 +1,1994 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../../drawing/drawing.dart'; -import '../../../graphics/figures/base/element_layouter.dart'; -import '../../../graphics/figures/base/layout_element.dart'; -import '../../../graphics/figures/base/text_layouter.dart'; -import '../../../graphics/figures/enums.dart'; -import '../../../graphics/fonts/pdf_string_format.dart'; -import '../../../graphics/fonts/pdf_string_layout_result.dart'; -import '../../../graphics/images/pdf_image.dart'; -import '../../../graphics/pdf_graphics.dart'; -import '../../../pages/enum.dart'; -import '../../../pages/pdf_page.dart'; -import '../../../pages/pdf_page_collection.dart'; -import '../../../pages/pdf_section.dart'; -import '../../../pdf_document/pdf_document.dart'; -import '../enums.dart'; -import '../pdf_grid.dart'; -import '../pdf_grid_cell.dart'; -import '../pdf_grid_column.dart'; -import '../pdf_grid_row.dart'; -import '../styles/style.dart'; - -/// internal class -class PdfGridLayouter extends ElementLayouter { - /// internal constructor - PdfGridLayouter(PdfGrid super.grid) { - _initialize(); - } - - //Fields - PdfGraphics? _currentGraphics; - PdfPage? _currentPage; - late PdfSize _currentPageBounds; - late PdfRectangle _currentBounds; - late PdfPoint _startLocation; - late double _childHeight; - late PdfHorizontalOverflowType _hType; - List>? _columnRanges; - late int _cellEndIndex; - late int _cellStartIndex; - late double userHeight; - - /// internal field - static int repeatRowIndex = -1; - late List _parentCellIndexList; - late int _currentRowIndex; - late int _currentHeaderRowIndex; - late int _rowBreakPageHeightCellIndex; - - /// internal field - late bool flag; - late bool _isChanged; - late PdfPoint _currentLocation; - bool? _isChildGrid; - late double _newheight; - - //Properties - PdfGrid? get _grid { - return element as PdfGrid?; - } - - //Implementation - void _initialize() { - _rowBreakPageHeightCellIndex = 0; - _newheight = 0; - _hType = PdfHorizontalOverflowType.nextPage; - _currentPageBounds = PdfSize.empty; - _currentRowIndex = 0; - _currentHeaderRowIndex = 0; - _currentLocation = PdfPoint.empty; - _currentBounds = PdfRectangle.empty; - _columnRanges ??= >[]; - _childHeight = 0; - _cellStartIndex = 0; - _cellEndIndex = 0; - _isChanged = false; - flag = true; - _isChildGrid ??= false; - _startLocation = PdfPoint.empty; - } - - /// internal method - void layoutGrid(PdfGraphics graphics, PdfRectangle bounds) { - final PdfLayoutParams param = PdfLayoutParams(); - param.bounds = bounds; - _currentGraphics = graphics; - if (PdfGraphicsHelper.getHelper(_currentGraphics!).layer != null && - PdfGraphicsHelper.getHelper(_currentGraphics!).page != null) { - final int index = PdfSectionHelper.getHelper( - PdfPageHelper.getHelper( - PdfGraphicsHelper.getHelper(_currentGraphics!).page!, - ).section!, - ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); - if (!PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.contains(index)) { - PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(index); - } - } - layoutInternal(param); - } - - PdfLayoutFormat _getFormat(PdfLayoutFormat? format) { - return format != null - ? PdfLayoutFormat.fromFormat(format) - : PdfLayoutFormat(); - } - - void _determineColumnDrawRanges() { - int startColumn = 0; - int endColumn = 0; - double cellWidths = 0; - final double availableWidth = - _currentGraphics!.clientSize.width - _currentBounds.x; - for (int i = 0; i < _grid!.columns.count; i++) { - cellWidths += _grid!.columns[i].width; - if (cellWidths >= availableWidth) { - double subWidths = 0; - for (int j = startColumn; j <= i; j++) { - subWidths += _grid!.columns[j].width; - if (subWidths > availableWidth) { - break; - } - endColumn = j; - } - _columnRanges!.add([startColumn, endColumn]); - startColumn = endColumn + 1; - endColumn = startColumn; - cellWidths = (endColumn <= i) ? _grid!.columns[i].width : 0; - } - } - if (startColumn != _grid!.columns.count) { - _columnRanges!.add([startColumn, _grid!.columns.count - 1]); - } - } - - PdfLayoutResult? _layoutOnPage(PdfLayoutParams param) { - final PdfLayoutFormat format = _getFormat(param.format); - late PdfGridEndPageLayoutArgs endArgs; - PdfLayoutResult? result; - final Map> layoutedPages = >{}; - PdfPage? startPage = param.page; - bool? isParentCell = false; - final List cellBounds = []; - for (int rangeIndex = 0; rangeIndex < _columnRanges!.length; rangeIndex++) { - final List range = _columnRanges![rangeIndex]; - _cellStartIndex = range[0]; - _cellEndIndex = range[1]; - if (_currentPage != null) { - final Map pageLayoutResult = _raiseBeforePageLayout( - _currentPage, - _currentBounds.rect, - _currentRowIndex, - ); - _currentBounds = PdfRectangle.fromRect( - pageLayoutResult['currentBounds'], - ); - _currentRowIndex = pageLayoutResult['currentRow'] as int; - if (pageLayoutResult['cancel'] as bool) { - result = PdfLayoutResultHelper.load( - _currentPage!, - _currentBounds.rect, - ); - break; - } - } - bool drawHeader; - if (PdfGridHelper.getHelper(_grid!).isBuiltinStyle && - PdfGridHelper.getHelper(_grid!).parentCell == null) { - if (PdfGridHelper.getHelper(_grid!).gridBuiltinStyle != - PdfGridBuiltInStyle.tableGrid) { - PdfGridHelper.getHelper(_grid!).applyBuiltinStyles( - PdfGridHelper.getHelper(_grid!).gridBuiltinStyle, - ); - } - } - for (int rowIndex = 0; rowIndex < _grid!.headers.count; rowIndex++) { - _currentHeaderRowIndex = rowIndex; - final PdfGridRow row = _grid!.headers[rowIndex]; - final double headerHeight = _currentBounds.y; - if (startPage != _currentPage) { - for (int k = _cellStartIndex; k <= _cellEndIndex; k++) { - if (PdfGridCellHelper.getHelper(row.cells[k]).isCellMergeContinue) { - PdfGridCellHelper.getHelper(row.cells[k]).isCellMergeContinue = - false; - row.cells[k].value = ''; - } - } - } - final _RowLayoutResult headerResult = _drawRow(row)!; - if (headerHeight == _currentBounds.y) { - drawHeader = true; - repeatRowIndex = PdfGridRowCollectionHelper.indexOf(_grid!.rows, row); - } else { - drawHeader = false; - } - if (!headerResult.isFinish && - startPage != null && - format.layoutType != PdfLayoutType.onePage && - drawHeader) { - _startLocation.x = _currentBounds.x; - _currentPage = _getNextPage(format); - _startLocation.y = _currentBounds.y; - if (PdfRectangle.fromRect(format.paginateBounds) == - PdfRectangle.empty) { - _currentBounds.x = _currentBounds.x + _startLocation.x; - } - _drawRow(row); - } - } - int i = 0; - final int length = _grid!.rows.count; - bool repeatRow; - double? startingHeight = 0; - bool flag = true; - if (isParentCell!) { - _cellEndIndex = - _cellStartIndex = PdfGridHelper.getHelper(_grid!).parentCellIndex; - _parentCellIndexList = []; - _parentCellIndexList.add( - PdfGridHelper.getHelper(_grid!).parentCellIndex, - ); - PdfGridCellHelper.getHelper(PdfGridHelper.getHelper(_grid!).parentCell!) - .present = true; - PdfGrid parentGrid = - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid; - while (PdfGridHelper.getHelper(parentGrid).parentCell != null) { - _parentCellIndexList.add( - PdfGridHelper.getHelper(parentGrid).parentCellIndex, - ); - _cellEndIndex = PdfGridHelper.getHelper(parentGrid).parentCellIndex; - _cellStartIndex = PdfGridHelper.getHelper(parentGrid).parentCellIndex; - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(parentGrid).parentCell!, - ).present = - true; - parentGrid = - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(parentGrid).parentCell!, - ).row!, - ).grid; - if (PdfGridHelper.getHelper(parentGrid).parentCell == null) { - _parentCellIndexList.removeAt(_parentCellIndexList.length - 1); - } - } - PdfSection section = PdfPageHelper.getHelper(_currentPage!).section!; - int index = PdfSectionHelper.getHelper(section).indexOf(_currentPage!); - if ((!PdfGridHelper.getHelper(parentGrid).isDrawn) || - (!PdfGridHelper.getHelper( - parentGrid, - ).listOfNavigatePages.contains(index))) { - section = - PdfPageHelper.getHelper( - PdfGraphicsHelper.getHelper(_currentGraphics!).page!, - ).section!; - index = PdfSectionHelper.getHelper(section).indexOf(_currentPage!); - PdfGridHelper.getHelper(parentGrid).isDrawn = true; - for (int rowIndex = 0; rowIndex < parentGrid.rows.count; rowIndex++) { - final PdfGridRow row = parentGrid.rows[rowIndex]; - final PdfGridCell cell = row.cells[_cellStartIndex]; - cell.value = ''; - final PdfPoint location = PdfPoint( - _currentBounds.x, - _currentBounds.y, - ); - double width = parentGrid.columns[_cellStartIndex].width; - if (width > _currentGraphics!.clientSize.width) { - width = _currentGraphics!.clientSize.width - 2 * location.x; - } - double? height = cell.height; - if (row.height > cell.height) { - height = row.height; - } - PdfGridCellHelper.getHelper(cell).draw( - _currentGraphics, - PdfRectangle(location.x, location.y, width, height), - false, - ); - _currentBounds.y = _currentBounds.y + height; - } - _currentBounds.y = 0; - } - _drawParentGridRow(parentGrid); - _cellStartIndex = range[0]; - _cellEndIndex = range[1]; - } - cellBounds.clear(); - for (int rowIndex = 0; rowIndex < _grid!.rows.count; rowIndex++) { - final PdfGridRow row = _grid!.rows[rowIndex]; - i++; - _currentRowIndex = i - 1; - double? originalHeight = _currentBounds.y; - startPage = _currentPage; - repeatRowIndex = -1; - if (flag && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).isChildGrid!) { - startingHeight = originalHeight; - flag = false; - } - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).isChildGrid! && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell!.rowSpan > - 1 && - (startingHeight! + _childHeight).toInt() < - (_currentBounds.y + row.height).toInt()) { - if (_grid!.rows.count > i) { - final PdfGrid temp = - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell!, - ).row!, - ).grid; - for ( - int tempRowIndex = 0; - tempRowIndex < temp.rows.count; - tempRowIndex++ - ) { - final PdfGridRow tempRow = temp.rows[tempRowIndex]; - if (tempRow.cells[PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCellIndex] == - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell) { - final dynamic grid = - tempRow - .cells[PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCellIndex] - .value; - if (grid is PdfGrid) { - PdfGridRowCollectionHelper.getRows( - grid.rows, - ).removeRange(0, i - 1); - } - } - } - } - break; - } - _RowLayoutResult rowResult = _drawRow(row)!; - cellBounds.add(rowResult.bounds.width); - if (PdfGridRowHelper.getHelper(row).isRowBreaksNextPage) { - double x = 0; - for (int l = 0; l < row.cells.count; l++) { - bool isNestedRowBreak = false; - if (row.height == row.cells[l].height && - row.cells[l].value is PdfGrid) { - final PdfGrid grid = row.cells[l].value as PdfGrid; - for (int m = grid.rows.count; 0 < m; m--) { - if (PdfGridRowHelper.getHelper( - grid.rows[m - 1], - ).rowBreakHeight > - 0) { - isNestedRowBreak = true; - break; - } - if (PdfGridRowHelper.getHelper( - grid.rows[m - 1], - ).isRowBreaksNextPage) { - PdfGridRowHelper.getHelper(row).rowBreakHeight = - PdfGridRowHelper.getHelper( - grid.rows[m - 1], - ).rowBreakHeight; - break; - } - PdfGridRowHelper.getHelper(row).rowBreakHeight = - PdfGridRowHelper.getHelper(row).rowBreakHeight + - grid.rows[m - 1].height; - } - } - if (isNestedRowBreak) { - break; - } - } - for (int j = 0; j < row.cells.count; j++) { - if (row.height > row.cells[j].height) { - row.cells[j].value = ''; - PdfRectangle rect; - PdfPage page = getNextPage(_currentPage!)!; - final PdfSection section = - PdfPageHelper.getHelper(_currentPage!).section!; - final int index = PdfSectionHelper.getHelper( - section, - ).indexOf(page); - for ( - int k = 0; - k < - (PdfSectionHelper.getHelper(section).pageReferences!.count - - 1) - - index; - k++ - ) { - rect = PdfRectangle( - x, - 0, - PdfGridRowHelper.getHelper(row).grid.columns[j].width, - page.getClientSize().height, - ); - repeatRowIndex = -1; - PdfGridCellHelper.getHelper( - row.cells[j], - ).draw(page.graphics, rect, false); - page = getNextPage(page)!; - } - rect = PdfRectangle( - x, - 0, - PdfGridRowHelper.getHelper(row).grid.columns[j].width, - PdfGridRowHelper.getHelper(row).rowBreakHeight, - ); - PdfGridCellHelper.getHelper( - row.cells[j], - ).draw(page.graphics, rect, false); - } - x += PdfGridRowHelper.getHelper(row).grid.columns[j].width; - } - } - if (originalHeight == _currentBounds.y) { - repeatRow = true; - repeatRowIndex = PdfGridRowCollectionHelper.indexOf(_grid!.rows, row); - } else { - repeatRow = false; - repeatRowIndex = -1; - } - while (!rowResult.isFinish && startPage != null) { - final PdfLayoutResult tempResult = _getLayoutResult(); - if (startPage != _currentPage) { - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).isChildGrid! && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell != - null) { - final PdfRectangle bounds = PdfRectangle( - format.paginateBounds.left, - format.paginateBounds.top, - param.bounds!.width, - tempResult.bounds.height, - ); - bounds.x = bounds.x + param.bounds!.x; - bounds.y = - bounds.y + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell!, - ).row!, - ).grid.style.cellPadding.top; - if (bounds.height > _currentPageBounds.height) { - bounds.height = _currentPageBounds.height - bounds.y; - bounds.height = - bounds.height - - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom; - } - for (int c = 0; c < row.cells.count; c++) { - final PdfGridCell cell = row.cells[c]; - double cellWidth = 0.0; - if (cell.columnSpan > 1) { - for (; c < cell.columnSpan; c++) { - cellWidth += - PdfGridRowHelper.getHelper(row).grid.columns[c].width; - } - } else { - cellWidth = max( - cell.width, - PdfGridRowHelper.getHelper(row).grid.columns[c].width, - ); - } - _currentGraphics = PdfGridCellHelper.getHelper( - cell, - ).drawCellBorders( - _currentGraphics!, - PdfRectangle(bounds.x, bounds.y, cellWidth, bounds.height), - ); - bounds.x = bounds.x + cellWidth; - c += cell.columnSpan - 1; - } - } - } - endArgs = _raisePageLayouted(tempResult); - if (endArgs.cancel || repeatRow) { - break; - } - if (repeatRow) { - break; - } else if (_grid!.allowRowBreakingAcrossPages) { - _currentPage = _getNextPage(format); - originalHeight = _currentBounds.y; - final PdfPoint location = PdfPoint( - PdfGridHelper.getHelper(_grid!).defaultBorder.right.width / 2, - PdfGridHelper.getHelper(_grid!).defaultBorder.top.width / 2, - ); - if (PdfRectangle.fromRect(format.paginateBounds) == - PdfRectangle.empty && - _startLocation == location) { - _currentBounds.x = _currentBounds.x + _startLocation.x; - _currentBounds.y = _currentBounds.y + _startLocation.y; - } - if (PdfGridHelper.getHelper(_grid!).isChildGrid! && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell != - null) { - if (PdfGridStyleHelper.getPadding( - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style, - ) != - null) { - if (PdfGridRowHelper.getHelper(row).rowBreakHeight + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.top < - _currentBounds.height) { - _currentBounds.y = - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.top; - } - } - } - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell != - null) { - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell!, - ).row!, - ).isRowBreaksNextPage = - true; - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell!, - ).row!, - ).rowBreakHeight = - PdfGridRowHelper.getHelper(row).rowBreakHeight + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.top + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom; - } - if (PdfGridRowHelper.getHelper(row).noOfPageCount > 1) { - final double temp = - PdfGridRowHelper.getHelper(row).rowBreakHeight; - for ( - int j = 1; - j < PdfGridRowHelper.getHelper(row).noOfPageCount; - j++ - ) { - PdfGridRowHelper.getHelper(row).rowBreakHeight = 0; - row.height = - (PdfGridRowHelper.getHelper(row).noOfPageCount - 1) * - _currentPage!.getClientSize().height; - _drawRow(row); - _currentPage = _getNextPage(format); - startPage = _currentPage; - } - PdfGridRowHelper.getHelper(row).rowBreakHeight = temp; - PdfGridRowHelper.getHelper(row).noOfPageCount = 1; - rowResult = _drawRow(row)!; - } else { - rowResult = _drawRow(row)!; - } - } else if (!_grid!.allowRowBreakingAcrossPages && i < length) { - _currentPage = _getNextPage(format); - break; - } else if (i >= length) { - break; - } - } - if (!rowResult.isFinish && - startPage != null && - format.layoutType != PdfLayoutType.onePage && - repeatRow) { - _startLocation.x = _currentBounds.x; - bool isAddNextPage = false; - if (!PdfGridHelper.getHelper(_grid!).isSingleGrid) { - for (int j = 0; j < _grid!.rows.count; j++) { - bool isWidthGreaterthanParent = false; - for (int k = 0; k < _grid!.rows[j].cells.count; k++) { - if (_grid!.rows[j].cells[k].width > _currentPageBounds.width) { - isWidthGreaterthanParent = true; - } - } - if (isWidthGreaterthanParent && - PdfGridCellHelper.getHelper( - _grid!.rows[j].cells[_rowBreakPageHeightCellIndex], - ).pageCount > - 0) { - isAddNextPage = true; - } - } - } - if (!PdfGridHelper.getHelper(_grid!).isRearranged && isAddNextPage) { - final PdfSection section = - PdfPageHelper.getHelper(_currentPage!).section!; - final PdfPage page = PdfPage(); - PdfSectionHelper.getHelper(section).isNewPageSection = true; - PdfSectionHelper.getHelper(section).add(page); - _currentPage = page; - PdfSectionHelper.getHelper(section).isNewPageSection = false; - _currentGraphics = _currentPage!.graphics; - final Size clientSize = _currentPage!.getClientSize(); - _currentBounds = PdfRectangle( - 0, - 0, - clientSize.width, - clientSize.height, - ); - final int pageindex = PdfSectionHelper.getHelper( - PdfPageHelper.getHelper( - PdfGraphicsHelper.getHelper(_currentGraphics!).page!, - ).section!, - ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); - if (!PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.contains(pageindex)) { - PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.add(pageindex); - } - } else { - if (endArgs.nextPage == null) { - _currentPage = _getNextPage(format); - } else { - _currentPage = endArgs.nextPage; - _currentGraphics = endArgs.nextPage!.graphics; - _currentBounds = PdfRectangle( - 0, - 0, - _currentGraphics!.clientSize.width, - _currentGraphics!.clientSize.height, - ); - } - } - final bool isSameSection = - PdfPageHelper.getHelper(_currentPage!).section == - PdfPageHelper.getHelper(param.page!).section; - _currentBounds.y = - format.paginateBounds.top == 0 - ? PdfGridHelper.getHelper(_grid!).defaultBorder.top.width / 2 - : format.paginateBounds.top; - if (_currentPage != null) { - final Map pageLayoutResult = - _raiseBeforePageLayout( - _currentPage, - _currentBounds.rect, - _currentRowIndex, - ); - _currentBounds = PdfRectangle.fromRect( - pageLayoutResult['currentBounds'], - ); - _currentRowIndex = pageLayoutResult['currentRow'] as int; - if (pageLayoutResult['cancel'] as bool) { - break; - } - } - if ((param.format != null) && - !PdfLayoutFormatHelper.isBoundsSet(param.format!) && - param.bounds != null && - param.bounds!.height > 0 && - !PdfGridHelper.getHelper(_grid!).isChildGrid! && - isSameSection) { - _currentBounds.height = param.bounds!.height; - } - _startLocation.y = _currentBounds.y; - if (PdfRectangle.fromRect(format.paginateBounds) == - PdfRectangle.empty) { - _currentBounds.x = _currentBounds.x + _startLocation.x; - } - if (_currentBounds.x == - PdfGridHelper.getHelper(_grid!).defaultBorder.left.width / 2) { - _currentBounds.y = _currentBounds.y + _startLocation.x; - } - if (_grid!.repeatHeader) { - for ( - int headerIndex = 0; - headerIndex < _grid!.headers.count; - headerIndex++ - ) { - _drawRow(_grid!.headers[headerIndex]); - } - } - _drawRow(row); - if (_currentPage != null && - !layoutedPages.containsKey(_currentPage)) { - layoutedPages[_currentPage] = range; - } - } - if (PdfGridRowHelper.getHelper(row).gridResult != null) { - _currentPage = PdfGridRowHelper.getHelper(row).gridResult!.page; - _currentGraphics = _currentPage!.graphics; - _startLocation = PdfPoint( - PdfGridRowHelper.getHelper(row).gridResult!.bounds.left, - PdfGridRowHelper.getHelper(row).gridResult!.bounds.top, - ); - _currentBounds.y = - PdfGridRowHelper.getHelper(row).gridResult!.bounds.bottom; - if (startPage != _currentPage) { - final PdfSection secion = - PdfPageHelper.getHelper(_currentPage!).section!; - final int startIndex = - PdfSectionHelper.getHelper(secion).indexOf(startPage!) + 1; - final int endIndex = PdfSectionHelper.getHelper( - secion, - ).indexOf(_currentPage!); - for (int page = startIndex; page < endIndex + 1; page++) { - PdfGraphics pageGraphics = - PdfSectionHelper.getHelper( - secion, - ).getPageByIndex(page)!.graphics; - final PdfPoint location = PdfPoint( - format.paginateBounds.left, - format.paginateBounds.top, - ); - if (location == PdfPoint.empty && - _currentBounds.x > location.x && - !PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).isChildGrid! && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell == - null) { - location.x = _currentBounds.x; - } - double height = - page == endIndex - ? (PdfGridRowHelper.getHelper( - row, - ).gridResult!.bounds.height - - param.bounds!.y) - : (_currentBounds.height - location.y); - if (height <= pageGraphics.clientSize.height) { - height += param.bounds!.y; - } - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).isChildGrid! && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).parentCell != - null) { - location.x = location.x + param.bounds!.x; - } - location.y = format.paginateBounds.top; - for (int c = 0; c < row.cells.count; c++) { - final PdfGridCell cell = row.cells[c]; - double cellWidth = 0.0; - if (cell.columnSpan > 1) { - for (; c < cell.columnSpan; c++) { - cellWidth += - PdfGridRowHelper.getHelper(row).grid.columns[c].width; - } - } else { - cellWidth = - PdfGridHelper.getHelper(_grid!).isWidthSet - ? min( - cell.width, - PdfGridRowHelper.getHelper( - row, - ).grid.columns[c].width, - ) - : max( - cell.width, - PdfGridRowHelper.getHelper( - row, - ).grid.columns[c].width, - ); - } - pageGraphics = PdfGridCellHelper.getHelper( - cell, - ).drawCellBorders( - pageGraphics, - PdfRectangle(location.x, location.y, cellWidth, height), - ); - location.x = location.x + cellWidth; - c += cell.columnSpan - 1; - } - } - startPage = _currentPage; - } - } - } - bool isPdfGrid = false; - double maximumCellBoundsWidth = 0; - if (cellBounds.isNotEmpty) { - maximumCellBoundsWidth = cellBounds[0]!; - } - final List> largeNavigatePage = List>.filled( - 1, - List.filled(2, 0), - ); - for (int c = 0; c < _grid!.rows.count; c++) { - if (_cellEndIndex != -1 && - _grid!.rows[c].cells[_cellEndIndex].value is PdfGrid) { - final PdfGrid grid = - _grid!.rows[c].cells[_cellEndIndex].value as PdfGrid; - PdfGridHelper.getHelper(_grid!).rowLayoutBoundswidth = - PdfGridHelper.getHelper(grid).rowLayoutBoundswidth; - isPdfGrid = true; - if (largeNavigatePage[0][0]! < - PdfGridHelper.getHelper(grid).listOfNavigatePages.length) { - largeNavigatePage[0][0] = - PdfGridHelper.getHelper( - grid, - ).listOfNavigatePages.length.toDouble(); - largeNavigatePage[0][1] = cellBounds[c]; - } else if ((largeNavigatePage[0][0] == - PdfGridHelper.getHelper(grid).listOfNavigatePages.length) && - (largeNavigatePage[0][1]! < cellBounds[c]!)) { - largeNavigatePage[0][1] = cellBounds[c]; - } - } - } - if (!isPdfGrid && cellBounds.isNotEmpty) { - for (int c = 0; c < i - 1; c++) { - if (maximumCellBoundsWidth < cellBounds[c]!) { - maximumCellBoundsWidth = cellBounds[c]!; - } - } - PdfGridHelper.getHelper(_grid!).rowLayoutBoundswidth = - maximumCellBoundsWidth; - } else { - PdfGridHelper.getHelper(_grid!).rowLayoutBoundswidth = - largeNavigatePage[0][1]!; - } - if (_columnRanges!.indexOf(range) < _columnRanges!.length - 1 && - startPage != null && - format.layoutType != PdfLayoutType.onePage) { - isParentCell = PdfGridHelper.getHelper(_grid!).isChildGrid; - if (largeNavigatePage[0][0]!.toInt() != 0) { - final PdfSection section = - PdfPageHelper.getHelper(_currentPage!).section!; - final int pageIndex = PdfSectionHelper.getHelper( - section, - ).indexOf(_currentPage!); - if (PdfSectionHelper.getHelper(section).count > - pageIndex + largeNavigatePage[0][0]!.toInt()) { - _currentPage = PdfSectionHelper.getHelper( - section, - ).getPageByIndex(pageIndex + largeNavigatePage[0][0]!.toInt()); - } else { - _currentPage = PdfPage(); - PdfSectionHelper.getHelper(section).isNewPageSection = true; - PdfSectionHelper.getHelper(section).add(_currentPage!); - PdfSectionHelper.getHelper(section).isNewPageSection = false; - } - _currentGraphics = _currentPage!.graphics; - _currentBounds = PdfRectangle( - 0, - 0, - _currentGraphics!.clientSize.width, - _currentGraphics!.clientSize.height, - ); - final int pageindex = PdfSectionHelper.getHelper( - PdfPageHelper.getHelper( - PdfGraphicsHelper.getHelper(_currentGraphics!).page!, - ).section!, - ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); - if (!PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.contains(pageindex)) { - PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(pageindex); - } - } else { - _currentPage = _getNextPage(format); - } - final PdfPoint location = PdfPoint( - PdfGridHelper.getHelper(_grid!).defaultBorder.right.width / 2, - PdfGridHelper.getHelper(_grid!).defaultBorder.top.width / 2, - ); - if (PdfRectangle.fromRect(format.paginateBounds) == - PdfRectangle.empty && - _startLocation == location) { - _currentBounds.x = _currentBounds.x + _startLocation.x; - _currentBounds.y = _currentBounds.y + _startLocation.y; - } - } - } - if (_currentPage != null) { - result = _getLayoutResult(); - if (_grid!.style.allowHorizontalOverflow && - _grid!.style.horizontalOverflowType == - PdfHorizontalOverflowType.nextPage) { - _reArrangeLayoutedPages(layoutedPages); - } - _raisePageLayouted(result); - return result; - } else { - return null; - } - } - - bool _drawParentGridRow(PdfGrid grid) { - bool present = false; - PdfGridHelper.getHelper(grid).isDrawn = true; - double? y = _currentBounds.y; - for (int rowIndex = 0; rowIndex < grid.rows.count; rowIndex++) { - final PdfGridRow row = grid.rows[rowIndex]; - final PdfGridCell cell = row.cells[_cellStartIndex]; - cell.value = ''; - final PdfPoint location = PdfPoint(_currentBounds.x, _currentBounds.y); - double width = grid.columns[_cellStartIndex].width; - if (width > _currentGraphics!.clientSize.width) { - width = _currentGraphics!.clientSize.width - 2 * location.x; - } - final double height = row.height > cell.height ? row.height : cell.height; - if (_isChildGrid!) { - PdfGridCellHelper.getHelper(cell).draw( - _currentGraphics, - PdfRectangle(location.x, location.y, width, height), - false, - ); - } - _currentBounds.y = _currentBounds.y + height; - } - for (int j = 0; j < grid.rows.count; j++) { - if (PdfGridCellHelper.getHelper( - grid.rows[j].cells[_cellStartIndex], - ).present) { - present = true; - if (grid.rows[j].cells[_cellStartIndex].value is PdfGrid) { - final PdfGrid? childGrid = - grid.rows[j].cells[_cellStartIndex].value as PdfGrid?; - PdfGridCellHelper.getHelper(grid.rows[j].cells[_cellStartIndex]) - .present = false; - if (childGrid == _grid) { - if (!_isChildGrid!) { - _currentBounds.y = y!; - } else { - if (j == 0) { - _currentBounds.y = - _currentBounds.y - - PdfGridHelper.getHelper(grid).size.height; - } else { - int k = j; - while (k < grid.rows.count) { - _currentBounds.y = _currentBounds.y - grid.rows[k].height; - k++; - } - } - } - PdfGridHelper.getHelper(childGrid!).isDrawn = true; - grid.rows[j].cells[_cellStartIndex].value = childGrid; - _currentBounds.x = - _currentBounds.x + - grid.style.cellPadding.left + - grid.style.cellPadding.right; - _currentBounds.y = - _currentBounds.y + - grid.style.cellPadding.top + - grid.style.cellPadding.bottom; - _currentBounds.width = _currentBounds.width - 2 * _currentBounds.x; - break; - } else { - _isChildGrid = true; - if (_parentCellIndexList.isNotEmpty) { - _cellStartIndex = - _parentCellIndexList[_parentCellIndexList.length - 1]; - _parentCellIndexList.removeAt(_parentCellIndexList.length - 1); - } - _currentBounds.y = y!; - _currentBounds.x = - _currentBounds.x + - grid.style.cellPadding.left + - grid.style.cellPadding.right; - _currentBounds.y = - _currentBounds.y + - grid.style.cellPadding.top + - grid.style.cellPadding.bottom; - final bool isPresent = _drawParentGridRow(childGrid!); - if (!isPresent) { - _currentBounds.y = - _currentBounds.y - - PdfGridHelper.getHelper(childGrid).size.height; - } - _isChildGrid = false; - break; - } - } else { - y = y! + grid.rows[j].height; - } - } else { - y = y! + grid.rows[j].height; - } - } - return present; - } - - _RowLayoutResult? _drawRow( - PdfGridRow? row, [ - _RowLayoutResult? result, - double? height, - ]) { - if (result == null && height == null) { - _RowLayoutResult result = _RowLayoutResult(); - double rowHeightWithSpan = 0; - bool isHeader = false; - if (PdfGridRowHelper.getHelper(row!).rowSpanExists) { - int currRowIndex = PdfGridRowCollectionHelper.indexOf(_grid!.rows, row); - int maxSpan = PdfGridRowHelper.getHelper(row).maximumRowSpan; - if (currRowIndex == -1) { - currRowIndex = PdfGridHeaderCollectionHelper.getHelper( - _grid!.headers, - ).indexOf(row); - if (currRowIndex != -1) { - isHeader = true; - } - } - for (int i = currRowIndex; i < currRowIndex + maxSpan; i++) { - rowHeightWithSpan += - isHeader ? _grid!.headers[i].height : _grid!.rows[i].height; - } - if ((rowHeightWithSpan > _currentBounds.height || - rowHeightWithSpan + _currentBounds.y > _currentBounds.height) && - !PdfGridRowHelper.getHelper(row).isPageBreakRowSpanApplied) { - rowHeightWithSpan = 0; - PdfGridRowHelper.getHelper(row).isPageBreakRowSpanApplied = true; - for (int cellIndex = 0; cellIndex < row.cells.count; cellIndex++) { - final PdfGridCell cell = row.cells[cellIndex]; - maxSpan = cell.rowSpan; - for (int i = currRowIndex; i < currRowIndex + maxSpan; i++) { - rowHeightWithSpan += - isHeader ? _grid!.headers[i].height : _grid!.rows[i].height; - if ((_currentBounds.y + rowHeightWithSpan) > - _currentPageBounds.height) { - rowHeightWithSpan -= - isHeader ? _grid!.headers[i].height : _grid!.rows[i].height; - for ( - int j = 0; - j < _grid!.rows[currRowIndex].cells.count; - j++ - ) { - final int newSpan = i - currRowIndex; - if (!isHeader && - (_grid!.rows[currRowIndex].cells[j].rowSpan == maxSpan)) { - _grid!.rows[currRowIndex].cells[j].rowSpan = - newSpan == 0 ? 1 : newSpan; - PdfGridRowHelper.getHelper(_grid!.rows[currRowIndex]) - .maximumRowSpan = newSpan == 0 ? 1 : newSpan; - _grid!.rows[i].cells[j].rowSpan = maxSpan - newSpan; - PdfGrid? pdfGrid; - if (_grid!.rows[currRowIndex].cells[j].value is PdfGrid) { - pdfGrid = - _grid!.rows[currRowIndex].cells[j].value as PdfGrid?; - } - _grid!.rows[i].cells[j].stringFormat = - _grid!.rows[currRowIndex].cells[j].stringFormat; - _grid!.rows[i].cells[j].style = - _grid!.rows[currRowIndex].cells[j].style; - _grid!.rows[i].cells[j].style.backgroundImage = null; - _grid!.rows[i].cells[j].columnSpan = - _grid!.rows[currRowIndex].cells[j].columnSpan; - if (pdfGrid is PdfGrid && - _currentBounds.y + - PdfGridHelper.getHelper(pdfGrid).size.height + - _grid!.rows[i].height + - pdfGrid.style.cellPadding.top + - pdfGrid.style.cellPadding.bottom >= - _currentBounds.height) { - _grid!.rows[i].cells[j].value = - _grid!.rows[currRowIndex].cells[j].value; - } else if (pdfGrid is! PdfGrid) { - _grid!.rows[i].cells[j].value = - _grid!.rows[currRowIndex].cells[j].value; - } - if (i > 0) { - PdfGridRowHelper.getHelper(_grid!.rows[i - 1]) - .rowSpanExists = true; - } - PdfGridCellHelper.getHelper(_grid!.rows[i].cells[j]) - .isRowMergeContinue = false; - } else if (isHeader && - (_grid!.headers[currRowIndex].cells[j].rowSpan == - maxSpan)) { - _grid!.headers[currRowIndex].cells[j].rowSpan = - newSpan == 0 ? 1 : newSpan; - _grid!.headers[i].cells[j].rowSpan = maxSpan - newSpan; - _grid!.headers[i].cells[j].stringFormat = - _grid!.headers[currRowIndex].cells[j].stringFormat; - _grid!.headers[i].cells[j].style = - _grid!.headers[currRowIndex].cells[j].style; - _grid!.headers[i].cells[j].columnSpan = - _grid!.headers[currRowIndex].cells[j].columnSpan; - _grid!.headers[i].cells[j].value = - _grid!.headers[currRowIndex].cells[j].value; - PdfGridRowHelper.getHelper(_grid!.headers[i - 1]) - .rowSpanExists = false; - PdfGridCellHelper.getHelper(_grid!.headers[i].cells[j]) - .isRowMergeContinue = false; - } - } - break; - } - } - rowHeightWithSpan = 0; - } - } - } - double? height = - PdfGridRowHelper.getHelper(row).rowBreakHeight > 0.0 - ? PdfGridRowHelper.getHelper(row).rowBreakHeight - : row.height; - if (PdfGridHelper.getHelper(_grid!).isChildGrid! && - PdfGridHelper.getHelper(_grid!).parentCell != null) { - if (height + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.top > - _currentPageBounds.height) { - userHeight = _startLocation.y; - if (_grid!.allowRowBreakingAcrossPages) { - result.isFinish = true; - if (PdfGridHelper.getHelper(_grid!).isChildGrid! && - PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { - _currentBounds.y = - _currentBounds.y + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.top; - _currentBounds.x = _startLocation.x; - } - result.bounds = _currentBounds; - result = _drawRowWithBreak(row, result, height); - } else { - _currentBounds.y = - _currentBounds.y + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.top; - height = - _currentBounds.height - - _currentBounds.y - - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom; - result.isFinish = false; - _drawRow(row, result, height); - } - } else if (_currentBounds.y + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom + - height > - _currentPageBounds.height || - _currentBounds.y + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom + - height > - _currentBounds.height || - _currentBounds.y + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom + - rowHeightWithSpan > - _currentPageBounds.height) { - if (repeatRowIndex > -1 && - repeatRowIndex == PdfGridRowHelper.getHelper(row).index) { - if (_grid!.allowRowBreakingAcrossPages) { - result.isFinish = true; - if (PdfGridHelper.getHelper(_grid!).isChildGrid! && - PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { - _currentBounds.y = - _currentBounds.y + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.top; - - _currentBounds.x = _startLocation.x; - } - result.bounds = _currentBounds; - result = _drawRowWithBreak(row, result, height); - } else { - result.isFinish = false; - _drawRow(row, result, height); - } - } else { - result.isFinish = false; - } - } else { - result.isFinish = true; - if (PdfGridHelper.getHelper(_grid!).isChildGrid! && - PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { - height += - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper(_grid!).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom; - } - _drawRow(row, result, height); - } - } else { - if (height > _currentPageBounds.height) { - if (_grid!.allowRowBreakingAcrossPages) { - result.isFinish = true; - result = _drawRowWithBreak(row, result, height); - } else { - result.isFinish = false; - _drawRow(row, result, height); - } - } else if (_currentBounds.y + height > _currentPageBounds.height || - (_currentBounds.y + height) - userHeight > _currentBounds.height || - _currentBounds.y + rowHeightWithSpan > _currentPageBounds.height) { - if (repeatRowIndex > -1 && - repeatRowIndex == PdfGridRowHelper.getHelper(row).index) { - if (_grid!.allowRowBreakingAcrossPages) { - result.isFinish = true; - result = _drawRowWithBreak(row, result, height); - } else { - result.isFinish = false; - _drawRow(row, result, height); - } - } else { - result.isFinish = false; - } - } else { - result.isFinish = true; - _drawRow(row, result, height); - } - } - return result; - } else { - bool? skipcell = false; - final PdfPoint location = _currentBounds.location; - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).isChildGrid! && - PdfGridRowHelper.getHelper(row).grid.allowRowBreakingAcrossPages && - _startLocation.x != _currentBounds.x && - PdfGridRowHelper.getHelper(row).getWidth() < - _currentPage!.getClientSize().width) { - location.x = _startLocation.x; - } - result!.bounds = PdfRectangle(location.x, location.y, 0, 0); - height = _reCalculateHeight(row, height!); - for (int i = _cellStartIndex; i <= _cellEndIndex; i++) { - final bool cancelSpans = - i > _cellEndIndex + 1 && row.cells[i].columnSpan > 1; - if (!cancelSpans) { - for (int j = 1; j < row.cells[i].columnSpan; j++) { - PdfGridCellHelper.getHelper(row.cells[i + j]).isCellMergeContinue = - true; - } - } - final PdfSize size = PdfSize(_grid!.columns[i].width, height); - if (size.width > _currentGraphics!.clientSize.width) { - size.width = _currentGraphics!.clientSize.width; - } - if (PdfGridHelper.getHelper(_grid!).isChildGrid! && - _grid!.style.allowHorizontalOverflow) { - if (size.width >= _currentGraphics!.clientSize.width) { - size.width = size.width - 2 * _currentBounds.x; - } - } - if (!_checkIfDefaultFormat(_grid!.columns[i].format) && - _checkIfDefaultFormat(row.cells[i].stringFormat)) { - row.cells[i].stringFormat = _grid!.columns[i].format; - } - - PdfGridCellStyle cellstyle = row.cells[i].style; - final Map bclResult = _raiseBeforeCellLayout( - _currentGraphics, - PdfGridRowHelper.getHelper(row).isHeaderRow - ? _currentHeaderRowIndex - : _currentRowIndex, - i, - PdfRectangle(location.x, location.y, size.width, size.height), - (row.cells[i].value is String) ? row.cells[i].value.toString() : '', - cellstyle, - PdfGridRowHelper.getHelper(row).isHeaderRow, - ); - cellstyle = bclResult['style'] as PdfGridCellStyle; - final PdfGridBeginCellLayoutArgs? gridbclArgs = - bclResult['args'] as PdfGridBeginCellLayoutArgs?; - row.cells[i].style = cellstyle; - if (gridbclArgs != null) { - skipcell = gridbclArgs.skip; - } - if (!skipcell!) { - if (row.cells[i].value is PdfGrid) { - final PdfGrid grid = row.cells[i].value as PdfGrid; - PdfGridHelper.getHelper(grid).parentCellIndex = i; - } - final PdfStringLayoutResult? stringResult = - PdfGridCellHelper.getHelper(row.cells[i]).draw( - _currentGraphics, - PdfRectangle(location.x, location.y, size.width, size.height), - cancelSpans, - ); - if (PdfGridRowHelper.getHelper( - row, - ).grid.style.allowHorizontalOverflow && - (row.cells[i].columnSpan > _cellEndIndex || - i + row.cells[i].columnSpan > _cellEndIndex + 1) && - _cellEndIndex < row.cells.count - 1) { - PdfGridRowHelper.getHelper(row).rowOverflowIndex = _cellEndIndex; - } - if (PdfGridRowHelper.getHelper( - row, - ).grid.style.allowHorizontalOverflow && - (PdfGridRowHelper.getHelper(row).rowOverflowIndex >= 0 && - (row.cells[i].columnSpan > _cellEndIndex || - i + row.cells[i].columnSpan > _cellEndIndex + 1)) && - row.cells[i].columnSpan - _cellEndIndex + i - 1 > 0) { - row - .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] - .value = stringResult != null && stringResult.remainder != null - ? stringResult.remainder - : ''; - row - .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] - .stringFormat = row.cells[i].stringFormat; - row - .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] - .style = row.cells[i].style; - row - .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] - .columnSpan = row.cells[i].columnSpan - _cellEndIndex + i - 1; - } - } - - if (!cancelSpans) { - _raiseAfterCellLayout( - _currentGraphics, - _currentRowIndex, - i, - PdfRectangle(location.x, location.y, size.width, size.height), - (row.cells[i].value is String) ? row.cells[i].value.toString() : '', - row.cells[i].style, - PdfGridRowHelper.getHelper(row).isHeaderRow, - ); - } - - if (row.cells[i].value is PdfGrid) { - final PdfGrid grid = row.cells[i].value as PdfGrid; - PdfGridCellHelper.getHelper(row.cells[i]).pageCount = - PdfGridHelper.getHelper(grid).listOfNavigatePages.length; - _rowBreakPageHeightCellIndex = i; - for ( - int k = 0; - k < PdfGridHelper.getHelper(grid).listOfNavigatePages.length; - k++ - ) { - final int pageIndex = - PdfGridHelper.getHelper(grid).listOfNavigatePages[k]; - if (!PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.contains(pageIndex)) { - PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.add(pageIndex); - } - } - if (_grid!.columns[i].width >= _currentGraphics!.clientSize.width) { - location.x = PdfGridHelper.getHelper(grid).rowLayoutBoundswidth; - location.x = location.x + grid.style.cellSpacing; - } else { - location.x = location.x + _grid!.columns[i].width; - } - } else { - location.x = location.x + _grid!.columns[i].width; - } - } - if (!PdfGridRowHelper.getHelper(row).rowMergeComplete || - PdfGridRowHelper.getHelper(row).isRowHeightSet) { - _currentBounds.y = _currentBounds.y + height; - } - result.bounds = PdfRectangle( - result.bounds.x, - result.bounds.y, - location.x, - location.y, - ); - return null; - } - } - - double _reCalculateHeight(PdfGridRow? row, double height) { - double newHeight = 0.0; - for (int i = _cellStartIndex; i <= _cellEndIndex; i++) { - if (PdfGridCellHelper.getHelper(row!.cells[i]).remainingString != null && - PdfGridCellHelper.getHelper( - row.cells[i], - ).remainingString!.isNotEmpty) { - newHeight = max( - newHeight, - PdfGridCellHelper.getHelper(row.cells[i]).measureHeight(), - ); - } - } - return max(height, newHeight); - } - - _RowLayoutResult _drawRowWithBreak( - PdfGridRow row, - _RowLayoutResult result, - double? height, - ) { - final PdfPoint location = _currentBounds.location; - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).isChildGrid! && - PdfGridRowHelper.getHelper(row).grid.allowRowBreakingAcrossPages && - _startLocation.x != _currentBounds.x) { - location.x = _startLocation.x; - } - result.bounds = PdfRectangle(location.x, location.y, 0, 0); - _newheight = - PdfGridRowHelper.getHelper(row).rowBreakHeight > 0 - ? _currentBounds.height < _currentPageBounds.height - ? _currentBounds.height - : _currentPageBounds.height - : 0; - if (PdfGridRowHelper.getHelper(row).grid.style.cellPadding.top + - _currentBounds.y + - PdfGridRowHelper.getHelper(row).grid.style.cellPadding.bottom < - _currentPageBounds.height) { - PdfGridRowHelper.getHelper(row).rowBreakHeight = - _currentBounds.y + height! - _currentPageBounds.height; - } else { - PdfGridRowHelper.getHelper(row).rowBreakHeight = height!; - result.isFinish = false; - return result; - } - for (int cellIndex = 0; cellIndex < row.cells.count; cellIndex++) { - final PdfGridCell cell = row.cells[cellIndex]; - if (PdfGridCellHelper.getHelper(cell).measureHeight() == height) { - PdfGridRowHelper.getHelper(row).rowBreakHeight = - cell.value is PdfGrid - ? 0 - : _currentBounds.y + height - _currentBounds.height < - _currentPageBounds.height - ? _currentBounds.height - : _currentPageBounds.height; - } - } - for (int i = _cellStartIndex; i <= _cellEndIndex; i++) { - final bool cancelSpans = - row.cells[i].columnSpan + i > _cellEndIndex + 1 && - row.cells[i].columnSpan > 1; - if (!cancelSpans) { - for (int j = 1; j < row.cells[i].columnSpan; j++) { - PdfGridCellHelper.getHelper(row.cells[i + j]).isCellMergeContinue = - true; - } - } - PdfSize size = PdfSize( - _grid!.columns[i].width, - _newheight > 0.0 - ? _newheight - : _currentBounds.height < _currentPageBounds.height - ? _currentBounds.height - : _currentPageBounds.height, - ); - if (size.width == 0) { - size = PdfSize(row.cells[i].width, size.height); - } - if (!_checkIfDefaultFormat(_grid!.columns[i].format) && - _checkIfDefaultFormat(row.cells[i].stringFormat)) { - row.cells[i].stringFormat = _grid!.columns[i].format; - } - PdfGridCellStyle cellstyle = row.cells[i].style; - final Map cellLayoutResult = _raiseBeforeCellLayout( - _currentGraphics, - PdfGridRowHelper.getHelper(row).isHeaderRow - ? _currentHeaderRowIndex - : _currentRowIndex, - i, - PdfRectangle(location.x, location.y, size.width, size.height), - row.cells[i].value is String ? row.cells[i].value.toString() : '', - cellstyle, - PdfGridRowHelper.getHelper(row).isHeaderRow, - ); - cellstyle = cellLayoutResult['style'] as PdfGridCellStyle; - final PdfGridBeginCellLayoutArgs? bclArgs = - cellLayoutResult['args'] as PdfGridBeginCellLayoutArgs?; - row.cells[i].style = cellstyle; - final bool skipcell = bclArgs != null && bclArgs.skip; - PdfStringLayoutResult? stringResult; - if (!skipcell) { - stringResult = PdfGridCellHelper.getHelper(row.cells[i]).draw( - _currentGraphics, - PdfRectangle(location.x, location.y, size.width, size.height), - cancelSpans, - ); - } - if (PdfGridRowHelper.getHelper(row).rowBreakHeight > 0.0) { - if (stringResult != null) { - PdfGridCellHelper.getHelper(row.cells[i]).finished = false; - PdfGridCellHelper.getHelper(row.cells[i]).remainingString = - stringResult.remainder ?? ''; - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row).grid, - ).isChildGrid!) { - PdfGridRowHelper.getHelper(row).rowBreakHeight = - height - stringResult.size.height; - } - } else if (row.cells[i].value is PdfImage) { - PdfGridCellHelper.getHelper(row.cells[i]).finished = false; - } - } - result.isFinish = - (!result.isFinish) - ? result.isFinish - : PdfGridCellHelper.getHelper(row.cells[i]).finished; - if (!cancelSpans) { - _raiseAfterCellLayout( - _currentGraphics, - _currentRowIndex, - i, - PdfRectangle(location.x, location.y, size.width, size.height), - (row.cells[i].value is String) ? row.cells[i].value.toString() : '', - row.cells[i].style, - PdfGridRowHelper.getHelper(row).isHeaderRow, - ); - } - if (row.cells[i].value is PdfGrid) { - final PdfGrid grid = row.cells[i].value as PdfGrid; - _rowBreakPageHeightCellIndex = i; - PdfGridCellHelper.getHelper(row.cells[i]).pageCount = - PdfGridHelper.getHelper(grid).listOfNavigatePages.length; - for ( - int i = 0; - i < PdfGridHelper.getHelper(grid).listOfNavigatePages.length; - i++ - ) { - final int pageIndex = - PdfGridHelper.getHelper(grid).listOfNavigatePages[i]; - if (!PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.contains(pageIndex)) { - PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(pageIndex); - } - } - if (_grid!.columns[i].width >= _currentGraphics!.clientSize.width) { - location.x = PdfGridHelper.getHelper(grid).rowLayoutBoundswidth; - location.x = location.x + grid.style.cellSpacing; - } else { - location.x = location.x + _grid!.columns[i].width; - } - } else { - location.x = location.x + _grid!.columns[i].width; - } - } - _currentBounds.y = - _currentBounds.y + (_newheight > 0.0 ? _newheight : height); - result.bounds = PdfRectangle( - result.bounds.x, - result.bounds.y, - location.x, - location.y, - ); - return result; - } - - bool _checkIfDefaultFormat(PdfStringFormat format) { - final PdfStringFormat defaultFormat = PdfStringFormat(); - return format.alignment == defaultFormat.alignment && - format.characterSpacing == defaultFormat.characterSpacing && - format.clipPath == defaultFormat.clipPath && - PdfStringFormatHelper.getHelper(format).firstLineIndent == - PdfStringFormatHelper.getHelper(defaultFormat).firstLineIndent && - PdfStringFormatHelper.getHelper(format).scalingFactor == - PdfStringFormatHelper.getHelper(defaultFormat).scalingFactor && - format.lineAlignment == defaultFormat.lineAlignment && - format.lineLimit == defaultFormat.lineLimit && - format.lineSpacing == defaultFormat.lineSpacing && - format.measureTrailingSpaces == defaultFormat.measureTrailingSpaces && - format.noClip == defaultFormat.noClip && - format.paragraphIndent == defaultFormat.paragraphIndent && - format.textDirection == defaultFormat.textDirection && - format.subSuperscript == defaultFormat.subSuperscript && - format.wordSpacing == defaultFormat.wordSpacing && - format.wordWrap == defaultFormat.wordWrap; - } - - void _reArrangeLayoutedPages(Map> layoutedPages) { - final PdfDocument? document = - PdfPageHelper.getHelper(_currentPage!).document; - final List pages = layoutedPages.keys.toList(); - for (int i = 0; i < pages.length; i++) { - final PdfPage page = pages[i]!; - PdfPageHelper.getHelper(page).section = null; - PdfPageCollectionHelper.getHelper(document!.pages).remove(page); - } - for (int i = 0; i < layoutedPages.length; i++) { - for ( - int j = i; - j < layoutedPages.length; - j += layoutedPages.length ~/ _columnRanges!.length - ) { - final PdfPage page = pages[j]!; - if (document!.pages.indexOf(page) == -1) { - PdfPageCollectionHelper.getHelper(document.pages).addPage(page); - } - } - } - } - - void _reArrangePages(PdfPage page) { - final List pages = []; - final PdfDocument document = PdfPageHelper.getHelper(page).document!; - int pageCount = document.pages.count; - int m = document.pages.indexOf(page); - int n = _columnRanges!.length; - if (pageCount <= _columnRanges!.length) { - for (int i = 0; i < _columnRanges!.length; i++) { - document.pages.add(); - if (document.pages.count > _columnRanges!.length) { - break; - } - } - } - pageCount = document.pages.count; - for (int i = 0; i < pageCount; i++) { - if (m < pageCount && pages.length != pageCount) { - final PdfPage tempPage = document.pages[m]; - if (!pages.contains(tempPage)) { - pages.add(tempPage); - } - } - if (n < pageCount && pages.length != pageCount) { - final PdfPage tempPage = document.pages[n]; - if (!pages.contains(tempPage)) { - pages.add(tempPage); - } - } - if (pages.length == pageCount) { - break; - } - m++; - n++; - } - for (int i = 0; i < pages.length; i++) { - final PdfPage tempPage = pages[i]!; - PdfPageHelper.getHelper(tempPage).section = null; - PdfPageCollectionHelper.getHelper(document.pages).remove(tempPage); - } - for (int i = 0; i < pages.length; i++) { - PdfPageCollectionHelper.getHelper(document.pages).addPage(pages[i]!); - } - } - - PdfPage? _getNextPage(PdfLayoutFormat format) { - final PdfSection section = PdfPageHelper.getHelper(_currentPage!).section!; - PdfPage? nextPage; - final int index = PdfSectionHelper.getHelper( - section, - ).indexOf(_currentPage!); - if (PdfPageHelper.getHelper(_currentPage!).document!.pages.count > 1 && - _hType == PdfHorizontalOverflowType.nextPage && - flag && - _columnRanges!.length > 1) { - PdfGridHelper.getHelper(_grid!).isRearranged = true; - _reArrangePages(_currentPage!); - } - flag = false; - if (index == PdfSectionHelper.getHelper(section).count - 1) { - nextPage = PdfPage(); - PdfSectionHelper.getHelper(section).isNewPageSection = true; - PdfSectionHelper.getHelper(section).add(nextPage); - PdfSectionHelper.getHelper(section).isNewPageSection = false; - } else { - nextPage = PdfSectionHelper.getHelper(section).getPageByIndex(index + 1); - } - _currentGraphics = nextPage!.graphics; - final int pageindex = PdfSectionHelper.getHelper( - PdfPageHelper.getHelper( - PdfGraphicsHelper.getHelper(_currentGraphics!).page!, - ).section!, - ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); - if (!PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.contains(pageindex)) { - PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(pageindex); - } - _currentBounds = PdfRectangle( - 0, - 0, - _currentGraphics!.clientSize.width, - _currentGraphics!.clientSize.height, - ); - if (PdfRectangle.fromRect(format.paginateBounds) != PdfRectangle.empty) { - _currentBounds.x = format.paginateBounds.left; - _currentBounds.y = format.paginateBounds.top; - _currentBounds.height = format.paginateBounds.height; - } - return nextPage; - } - - PdfLayoutResult _getLayoutResult() { - if (PdfGridHelper.getHelper(_grid!).isChildGrid! && - _grid!.allowRowBreakingAcrossPages) { - for (int rowIndex = 0; rowIndex < _grid!.rows.count; rowIndex++) { - final PdfGridRow row = _grid!.rows[rowIndex]; - if (PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { - _startLocation.y = PdfPageHelper.getHelper(_currentPage!).origin.dy; - } - } - } - final Rect bounds = - _isChanged - ? Rect.fromLTWH( - _currentLocation.x, - _currentLocation.y, - _currentBounds.width, - _currentBounds.y - _currentLocation.y, - ) - : Rect.fromLTWH( - _startLocation.x, - _startLocation.y, - _currentBounds.width, - _currentBounds.y - _startLocation.y, - ); - return PdfLayoutResultHelper.load(_currentPage!, bounds); - } - - Map _raiseBeforePageLayout( - PdfPage? currentPage, - Rect currentBounds, - int? currentRow, - ) { - bool cancel = false; - if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout) { - final PdfGridBeginPageLayoutArgs args = - PdfGridBeginPageLayoutArgsHelper.load( - currentBounds, - currentPage!, - currentRow, - ); - PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); - if (PdfRectangle.fromRect(currentBounds) != - PdfRectangle.fromRect(args.bounds)) { - _isChanged = true; - _currentLocation = PdfPoint(args.bounds.left, args.bounds.top); - PdfGridHelper.getHelper(_grid!).measureColumnsWidth( - PdfRectangle( - args.bounds.left, - args.bounds.top, - args.bounds.width + args.bounds.left, - args.bounds.height, - ), - ); - } - cancel = args.cancel; - currentBounds = args.bounds; - currentRow = args.startRowIndex; - } - return { - 'cancel': cancel, - 'currentBounds': currentBounds, - 'currentRow': currentRow, - }; - } - - PdfGridEndPageLayoutArgs _raisePageLayouted(PdfLayoutResult result) { - final PdfGridEndPageLayoutArgs args = PdfGridEndPageLayoutArgsHelper.load( - result, - ); - if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted) { - PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); - } - return args; - } - - Map _raiseBeforeCellLayout( - PdfGraphics? graphics, - int rowIndex, - int cellIndex, - PdfRectangle bounds, - String value, - PdfGridCellStyle? style, - bool isHeaderRow, - ) { - PdfGridBeginCellLayoutArgs? args; - if (PdfGridHelper.getHelper(_grid!).raiseBeginCellLayout) { - args = PdfGridBeginCellLayoutArgsHelper.load( - graphics!, - rowIndex, - cellIndex, - bounds, - value, - style, - isHeaderRow, - ); - PdfGridHelper.getHelper(_grid!).onBeginCellLayout(args); - style = args.style; - } - return {'args': args, 'style': style}; - } - - void _raiseAfterCellLayout( - PdfGraphics? graphics, - int rowIndex, - int cellIndex, - PdfRectangle bounds, - String value, - PdfGridCellStyle? cellstyle, - bool isHeaderRow, - ) { - PdfGridEndCellLayoutArgs args; - if (PdfGridHelper.getHelper(_grid!).raiseEndCellLayout) { - args = PdfGridEndCellLayoutArgsHelper.load( - graphics!, - rowIndex, - cellIndex, - bounds, - value, - cellstyle, - isHeaderRow, - ); - PdfGridHelper.getHelper(_grid!).onEndCellLayout(args); - } - } - - //Override methods - @override - PdfLayoutResult? layoutInternal(PdfLayoutParams param) { - final PdfLayoutFormat format = _getFormat(param.format); - _currentPage = param.page; - if (_currentPage != null) { - final Size size = _currentPage!.getClientSize(); - final double pageHeight = size.height; - final double pageWidth = size.width; - if (pageHeight > pageWidth || - (PdfPageHelper.getHelper(param.page!).orientation == - PdfPageOrientation.landscape && - format.breakType == PdfLayoutBreakType.fitPage)) { - _currentPageBounds = PdfSize.fromSize(size); - } else { - _currentPageBounds = PdfSize.fromSize(_currentPage!.size); - } - } else { - _currentPageBounds = PdfSize.fromSize(_currentGraphics!.clientSize); - } - if (_currentPage != null) { - _currentGraphics = _currentPage!.graphics; - } - if (PdfGraphicsHelper.getHelper(_currentGraphics!).layer != null) { - final int index = - !PdfPageHelper.getHelper( - PdfGraphicsHelper.getHelper(_currentGraphics!).page!, - ).isLoadedPage - ? PdfSectionHelper.getHelper( - PdfPageHelper.getHelper( - PdfGraphicsHelper.getHelper(_currentGraphics!).page!, - ).section!, - ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!) - : PdfGraphicsHelper.getHelper( - _currentGraphics!, - ).page!.defaultLayerIndex; - if (!PdfGridHelper.getHelper( - _grid!, - ).listOfNavigatePages.contains(index)) { - PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(index); - } - } - _currentBounds = PdfRectangle( - param.bounds!.x, - param.bounds!.y, - format.breakType == PdfLayoutBreakType.fitColumnsToPage - ? PdfGridColumnCollectionHelper.getHelper(_grid!.columns).columnWidth - : _currentGraphics!.clientSize.width, - _currentGraphics!.clientSize.height, - ); - if (_grid!.rows.count != 0) { - _currentBounds.width = - (param.bounds!.width > 0) - ? param.bounds!.width - : (_currentBounds.width - - _grid!.rows[0].cells[0].style.borders.left.width / 2); - } else if (_grid!.headers.count != 0) { - _currentBounds.width = - (param.bounds!.width > 0) - ? param.bounds!.width - : (_currentBounds.width - - _grid!.headers[0].cells[0].style.borders.left.width / 2); - } - _startLocation = param.bounds!.location; - if (_grid!.style.allowHorizontalOverflow && - _currentBounds.width > _currentGraphics!.clientSize.width) { - _currentBounds.width = - _currentGraphics!.clientSize.width - _currentBounds.x; - } - if (PdfGridHelper.getHelper(_grid!).isChildGrid!) { - _childHeight = param.bounds!.height; - } - if (param.format != null && - PdfLayoutFormatHelper.isBoundsSet(param.format!)) { - if (param.format!.paginateBounds.height > 0) { - _currentBounds.height = param.format!.paginateBounds.height; - } - } else if (param.bounds!.height > 0 && - !PdfGridHelper.getHelper(_grid!).isChildGrid!) { - _currentBounds.height = param.bounds!.height; - } - if (PdfGridHelper.getHelper(_grid!).isChildGrid!) { - _hType = _grid!.style.horizontalOverflowType; - } - if (!_grid!.style.allowHorizontalOverflow) { - PdfGridHelper.getHelper(_grid!).measureColumnsWidth(_currentBounds); - _columnRanges!.add([0, _grid!.columns.count - 1]); - } else { - PdfGridHelper.getHelper(_grid!).measureColumnsWidth(); - _determineColumnDrawRanges(); - } - if (PdfGridHelper.getHelper(_grid!).hasRowSpan) { - for (int i = 0; i < _grid!.rows.count; i++) { - _grid!.rows[i].height; - if (!PdfGridRowHelper.getHelper(_grid!.rows[i]).isRowHeightSet) { - PdfGridRowHelper.getHelper(_grid!.rows[i]).isRowHeightSet = true; - } else { - PdfGridRowHelper.getHelper(_grid!.rows[i]).isRowSpanRowHeightSet = - true; - } - } - } - userHeight = _startLocation.y; - return _layoutOnPage(param); - } -} - -class _RowLayoutResult { - _RowLayoutResult() { - bounds = PdfRectangle.empty; - isFinish = false; - } - late bool isFinish; - late PdfRectangle bounds; -} +import 'dart:math'; +import 'dart:ui'; + +import '../../../drawing/drawing.dart'; +import '../../../graphics/figures/base/element_layouter.dart'; +import '../../../graphics/figures/base/layout_element.dart'; +import '../../../graphics/figures/base/text_layouter.dart'; +import '../../../graphics/figures/enums.dart'; +import '../../../graphics/fonts/pdf_string_format.dart'; +import '../../../graphics/fonts/pdf_string_layout_result.dart'; +import '../../../graphics/images/pdf_image.dart'; +import '../../../graphics/pdf_graphics.dart'; +import '../../../pages/enum.dart'; +import '../../../pages/pdf_page.dart'; +import '../../../pages/pdf_page_collection.dart'; +import '../../../pages/pdf_section.dart'; +import '../../../pdf_document/pdf_document.dart'; +import '../enums.dart'; +import '../pdf_grid.dart'; +import '../pdf_grid_cell.dart'; +import '../pdf_grid_column.dart'; +import '../pdf_grid_row.dart'; +import '../styles/style.dart'; + +/// internal class +class PdfGridLayouter extends ElementLayouter { + /// internal constructor + PdfGridLayouter(PdfGrid super.grid) { + _initialize(); + } + + //Fields + PdfGraphics? _currentGraphics; + PdfPage? _currentPage; + late PdfSize _currentPageBounds; + late PdfRectangle _currentBounds; + late PdfPoint _startLocation; + late double _childHeight; + late PdfHorizontalOverflowType _hType; + List>? _columnRanges; + late int _cellEndIndex; + late int _cellStartIndex; + late double userHeight; + + /// internal field + static int repeatRowIndex = -1; + late List _parentCellIndexList; + late int _currentRowIndex; + late int _currentHeaderRowIndex; + late int _rowBreakPageHeightCellIndex; + + /// internal field + late bool flag; + late bool _isChanged; + late PdfPoint _currentLocation; + bool? _isChildGrid; + late double _newheight; + + //Properties + PdfGrid? get _grid { + return element as PdfGrid?; + } + + //Implementation + void _initialize() { + _rowBreakPageHeightCellIndex = 0; + _newheight = 0; + _hType = PdfHorizontalOverflowType.nextPage; + _currentPageBounds = PdfSize.empty; + _currentRowIndex = 0; + _currentHeaderRowIndex = 0; + _currentLocation = PdfPoint.empty; + _currentBounds = PdfRectangle.empty; + _columnRanges ??= >[]; + _childHeight = 0; + _cellStartIndex = 0; + _cellEndIndex = 0; + _isChanged = false; + flag = true; + _isChildGrid ??= false; + _startLocation = PdfPoint.empty; + } + + /// internal method + void layoutGrid(PdfGraphics graphics, PdfRectangle bounds) { + final PdfLayoutParams param = PdfLayoutParams(); + param.bounds = bounds; + _currentGraphics = graphics; + if (PdfGraphicsHelper.getHelper(_currentGraphics!).layer != null && + PdfGraphicsHelper.getHelper(_currentGraphics!).page != null) { + final int index = PdfSectionHelper.getHelper( + PdfPageHelper.getHelper( + PdfGraphicsHelper.getHelper(_currentGraphics!).page!, + ).section!, + ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); + if (!PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.contains(index)) { + PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(index); + } + } + layoutInternal(param); + } + + PdfLayoutFormat _getFormat(PdfLayoutFormat? format) { + return format != null + ? PdfLayoutFormat.fromFormat(format) + : PdfLayoutFormat(); + } + + void _determineColumnDrawRanges() { + int startColumn = 0; + int endColumn = 0; + double cellWidths = 0; + final double availableWidth = + _currentGraphics!.clientSize.width - _currentBounds.x; + for (int i = 0; i < _grid!.columns.count; i++) { + cellWidths += _grid!.columns[i].width; + if (cellWidths >= availableWidth) { + double subWidths = 0; + for (int j = startColumn; j <= i; j++) { + subWidths += _grid!.columns[j].width; + if (subWidths > availableWidth) { + break; + } + endColumn = j; + } + _columnRanges!.add([startColumn, endColumn]); + startColumn = endColumn + 1; + endColumn = startColumn; + cellWidths = (endColumn <= i) ? _grid!.columns[i].width : 0; + } + } + if (startColumn != _grid!.columns.count) { + _columnRanges!.add([startColumn, _grid!.columns.count - 1]); + } + } + + PdfLayoutResult? _layoutOnPage(PdfLayoutParams param) { + final PdfLayoutFormat format = _getFormat(param.format); + late PdfGridEndPageLayoutArgs endArgs; + PdfLayoutResult? result; + final Map> layoutedPages = >{}; + PdfPage? startPage = param.page; + bool? isParentCell = false; + final List cellBounds = []; + for (int rangeIndex = 0; rangeIndex < _columnRanges!.length; rangeIndex++) { + final List range = _columnRanges![rangeIndex]; + _cellStartIndex = range[0]; + _cellEndIndex = range[1]; + if (_currentPage != null) { + final Map pageLayoutResult = _raiseBeforePageLayout( + _currentPage, + _currentBounds.rect, + _currentRowIndex, + ); + _currentBounds = PdfRectangle.fromRect( + pageLayoutResult['currentBounds'], + ); + _currentRowIndex = pageLayoutResult['currentRow'] as int; + if (pageLayoutResult['cancel'] as bool) { + result = PdfLayoutResultHelper.load( + _currentPage!, + _currentBounds.rect, + ); + break; + } + } + bool drawHeader; + if (PdfGridHelper.getHelper(_grid!).isBuiltinStyle && + PdfGridHelper.getHelper(_grid!).parentCell == null) { + if (PdfGridHelper.getHelper(_grid!).gridBuiltinStyle != + PdfGridBuiltInStyle.tableGrid) { + PdfGridHelper.getHelper(_grid!).applyBuiltinStyles( + PdfGridHelper.getHelper(_grid!).gridBuiltinStyle, + ); + } + } + for (int rowIndex = 0; rowIndex < _grid!.headers.count; rowIndex++) { + _currentHeaderRowIndex = rowIndex; + final PdfGridRow row = _grid!.headers[rowIndex]; + final double headerHeight = _currentBounds.y; + if (startPage != _currentPage) { + for (int k = _cellStartIndex; k <= _cellEndIndex; k++) { + if (PdfGridCellHelper.getHelper(row.cells[k]).isCellMergeContinue) { + PdfGridCellHelper.getHelper(row.cells[k]).isCellMergeContinue = + false; + row.cells[k].value = ''; + } + } + } + final _RowLayoutResult headerResult = _drawRow(row)!; + if (headerHeight == _currentBounds.y) { + drawHeader = true; + repeatRowIndex = PdfGridRowCollectionHelper.indexOf(_grid!.rows, row); + } else { + drawHeader = false; + } + if (!headerResult.isFinish && + startPage != null && + format.layoutType != PdfLayoutType.onePage && + drawHeader) { + _startLocation.x = _currentBounds.x; + _currentPage = _getNextPage(format); + _startLocation.y = _currentBounds.y; + if (PdfRectangle.fromRect(format.paginateBounds) == + PdfRectangle.empty) { + _currentBounds.x = _currentBounds.x + _startLocation.x; + } + _drawRow(row); + } + } + int i = 0; + final int length = _grid!.rows.count; + bool repeatRow; + double? startingHeight = 0; + bool flag = true; + if (isParentCell!) { + _cellEndIndex = + _cellStartIndex = PdfGridHelper.getHelper(_grid!).parentCellIndex; + _parentCellIndexList = []; + _parentCellIndexList.add( + PdfGridHelper.getHelper(_grid!).parentCellIndex, + ); + PdfGridCellHelper.getHelper(PdfGridHelper.getHelper(_grid!).parentCell!) + .present = true; + PdfGrid parentGrid = + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid; + while (PdfGridHelper.getHelper(parentGrid).parentCell != null) { + _parentCellIndexList.add( + PdfGridHelper.getHelper(parentGrid).parentCellIndex, + ); + _cellEndIndex = PdfGridHelper.getHelper(parentGrid).parentCellIndex; + _cellStartIndex = PdfGridHelper.getHelper(parentGrid).parentCellIndex; + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(parentGrid).parentCell!, + ).present = + true; + parentGrid = + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(parentGrid).parentCell!, + ).row!, + ).grid; + if (PdfGridHelper.getHelper(parentGrid).parentCell == null) { + _parentCellIndexList.removeAt(_parentCellIndexList.length - 1); + } + } + PdfSection section = PdfPageHelper.getHelper(_currentPage!).section!; + int index = PdfSectionHelper.getHelper(section).indexOf(_currentPage!); + if ((!PdfGridHelper.getHelper(parentGrid).isDrawn) || + (!PdfGridHelper.getHelper( + parentGrid, + ).listOfNavigatePages.contains(index))) { + section = + PdfPageHelper.getHelper( + PdfGraphicsHelper.getHelper(_currentGraphics!).page!, + ).section!; + index = PdfSectionHelper.getHelper(section).indexOf(_currentPage!); + PdfGridHelper.getHelper(parentGrid).isDrawn = true; + for (int rowIndex = 0; rowIndex < parentGrid.rows.count; rowIndex++) { + final PdfGridRow row = parentGrid.rows[rowIndex]; + final PdfGridCell cell = row.cells[_cellStartIndex]; + cell.value = ''; + final PdfPoint location = PdfPoint( + _currentBounds.x, + _currentBounds.y, + ); + double width = parentGrid.columns[_cellStartIndex].width; + if (width > _currentGraphics!.clientSize.width) { + width = _currentGraphics!.clientSize.width - 2 * location.x; + } + double? height = cell.height; + if (row.height > cell.height) { + height = row.height; + } + PdfGridCellHelper.getHelper(cell).draw( + _currentGraphics, + PdfRectangle(location.x, location.y, width, height), + false, + ); + _currentBounds.y = _currentBounds.y + height; + } + _currentBounds.y = 0; + } + _drawParentGridRow(parentGrid); + _cellStartIndex = range[0]; + _cellEndIndex = range[1]; + } + cellBounds.clear(); + for (int rowIndex = 0; rowIndex < _grid!.rows.count; rowIndex++) { + final PdfGridRow row = _grid!.rows[rowIndex]; + i++; + _currentRowIndex = i - 1; + double? originalHeight = _currentBounds.y; + startPage = _currentPage; + repeatRowIndex = -1; + if (flag && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).isChildGrid!) { + startingHeight = originalHeight; + flag = false; + } + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).isChildGrid! && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell!.rowSpan > + 1 && + (startingHeight! + _childHeight).toInt() < + (_currentBounds.y + row.height).toInt()) { + if (_grid!.rows.count > i) { + final PdfGrid temp = + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell!, + ).row!, + ).grid; + for ( + int tempRowIndex = 0; + tempRowIndex < temp.rows.count; + tempRowIndex++ + ) { + final PdfGridRow tempRow = temp.rows[tempRowIndex]; + if (tempRow.cells[PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCellIndex] == + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell) { + final dynamic grid = + tempRow + .cells[PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCellIndex] + .value; + if (grid is PdfGrid) { + PdfGridRowCollectionHelper.getRows( + grid.rows, + ).removeRange(0, i - 1); + } + } + } + } + break; + } + _RowLayoutResult rowResult = _drawRow(row)!; + cellBounds.add(rowResult.bounds.width); + if (PdfGridRowHelper.getHelper(row).isRowBreaksNextPage) { + double x = 0; + for (int l = 0; l < row.cells.count; l++) { + bool isNestedRowBreak = false; + if (row.height == row.cells[l].height && + row.cells[l].value is PdfGrid) { + final PdfGrid grid = row.cells[l].value as PdfGrid; + for (int m = grid.rows.count; 0 < m; m--) { + if (PdfGridRowHelper.getHelper( + grid.rows[m - 1], + ).rowBreakHeight > + 0) { + isNestedRowBreak = true; + break; + } + if (PdfGridRowHelper.getHelper( + grid.rows[m - 1], + ).isRowBreaksNextPage) { + PdfGridRowHelper.getHelper(row).rowBreakHeight = + PdfGridRowHelper.getHelper( + grid.rows[m - 1], + ).rowBreakHeight; + break; + } + PdfGridRowHelper.getHelper(row).rowBreakHeight = + PdfGridRowHelper.getHelper(row).rowBreakHeight + + grid.rows[m - 1].height; + } + } + if (isNestedRowBreak) { + break; + } + } + for (int j = 0; j < row.cells.count; j++) { + if (row.height > row.cells[j].height) { + row.cells[j].value = ''; + PdfRectangle rect; + PdfPage page = getNextPage(_currentPage!)!; + final PdfSection section = + PdfPageHelper.getHelper(_currentPage!).section!; + final int index = PdfSectionHelper.getHelper( + section, + ).indexOf(page); + for ( + int k = 0; + k < + (PdfSectionHelper.getHelper(section).pageReferences!.count - + 1) - + index; + k++ + ) { + rect = PdfRectangle( + x, + 0, + PdfGridRowHelper.getHelper(row).grid.columns[j].width, + page.getClientSize().height, + ); + repeatRowIndex = -1; + PdfGridCellHelper.getHelper( + row.cells[j], + ).draw(page.graphics, rect, false); + page = getNextPage(page)!; + } + rect = PdfRectangle( + x, + 0, + PdfGridRowHelper.getHelper(row).grid.columns[j].width, + PdfGridRowHelper.getHelper(row).rowBreakHeight, + ); + PdfGridCellHelper.getHelper( + row.cells[j], + ).draw(page.graphics, rect, false); + } + x += PdfGridRowHelper.getHelper(row).grid.columns[j].width; + } + } + if (originalHeight == _currentBounds.y) { + repeatRow = true; + repeatRowIndex = PdfGridRowCollectionHelper.indexOf(_grid!.rows, row); + } else { + repeatRow = false; + repeatRowIndex = -1; + } + while (!rowResult.isFinish && startPage != null) { + final PdfLayoutResult tempResult = _getLayoutResult(); + if (startPage != _currentPage) { + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).isChildGrid! && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell != + null) { + final PdfRectangle bounds = PdfRectangle( + format.paginateBounds.left, + format.paginateBounds.top, + param.bounds!.width, + tempResult.bounds.height, + ); + bounds.x = bounds.x + param.bounds!.x; + bounds.y = + bounds.y + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell!, + ).row!, + ).grid.style.cellPadding.top; + if (bounds.height > _currentPageBounds.height) { + bounds.height = _currentPageBounds.height - bounds.y; + bounds.height = + bounds.height - + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom; + } + for (int c = 0; c < row.cells.count; c++) { + final PdfGridCell cell = row.cells[c]; + double cellWidth = 0.0; + if (cell.columnSpan > 1) { + for (; c < cell.columnSpan; c++) { + cellWidth += + PdfGridRowHelper.getHelper(row).grid.columns[c].width; + } + } else { + cellWidth = max( + cell.width, + PdfGridRowHelper.getHelper(row).grid.columns[c].width, + ); + } + _currentGraphics = PdfGridCellHelper.getHelper( + cell, + ).drawCellBorders( + _currentGraphics!, + PdfRectangle(bounds.x, bounds.y, cellWidth, bounds.height), + ); + bounds.x = bounds.x + cellWidth; + c += cell.columnSpan - 1; + } + } + } + endArgs = _raisePageLayouted(tempResult); + if (endArgs.cancel || repeatRow) { + break; + } + if (repeatRow) { + break; + } else if (_grid!.allowRowBreakingAcrossPages) { + _currentPage = _getNextPage(format); + originalHeight = _currentBounds.y; + final PdfPoint location = PdfPoint( + PdfGridHelper.getHelper(_grid!).defaultBorder.right.width / 2, + PdfGridHelper.getHelper(_grid!).defaultBorder.top.width / 2, + ); + if (PdfRectangle.fromRect(format.paginateBounds) == + PdfRectangle.empty && + _startLocation == location) { + _currentBounds.x = _currentBounds.x + _startLocation.x; + _currentBounds.y = _currentBounds.y + _startLocation.y; + } + if (PdfGridHelper.getHelper(_grid!).isChildGrid! && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell != + null) { + if (PdfGridStyleHelper.getPadding( + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style, + ) != + null) { + if (PdfGridRowHelper.getHelper(row).rowBreakHeight + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.top < + _currentBounds.height) { + _currentBounds.y = + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.top; + } + } + } + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell != + null) { + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell!, + ).row!, + ).isRowBreaksNextPage = + true; + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell!, + ).row!, + ).rowBreakHeight = + PdfGridRowHelper.getHelper(row).rowBreakHeight + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.top + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom; + } + if (PdfGridRowHelper.getHelper(row).noOfPageCount > 1) { + final double temp = + PdfGridRowHelper.getHelper(row).rowBreakHeight; + for ( + int j = 1; + j < PdfGridRowHelper.getHelper(row).noOfPageCount; + j++ + ) { + PdfGridRowHelper.getHelper(row).rowBreakHeight = 0; + row.height = + (PdfGridRowHelper.getHelper(row).noOfPageCount - 1) * + _currentPage!.getClientSize().height; + _drawRow(row); + _currentPage = _getNextPage(format); + startPage = _currentPage; + } + PdfGridRowHelper.getHelper(row).rowBreakHeight = temp; + PdfGridRowHelper.getHelper(row).noOfPageCount = 1; + rowResult = _drawRow(row)!; + } else { + rowResult = _drawRow(row)!; + } + } else if (!_grid!.allowRowBreakingAcrossPages && i < length) { + _currentPage = _getNextPage(format); + break; + } else if (i >= length) { + break; + } + } + if (!rowResult.isFinish && + startPage != null && + format.layoutType != PdfLayoutType.onePage && + repeatRow) { + _startLocation.x = _currentBounds.x; + bool isAddNextPage = false; + if (!PdfGridHelper.getHelper(_grid!).isSingleGrid) { + for (int j = 0; j < _grid!.rows.count; j++) { + bool isWidthGreaterthanParent = false; + for (int k = 0; k < _grid!.rows[j].cells.count; k++) { + if (_grid!.rows[j].cells[k].width > _currentPageBounds.width) { + isWidthGreaterthanParent = true; + } + } + if (isWidthGreaterthanParent && + PdfGridCellHelper.getHelper( + _grid!.rows[j].cells[_rowBreakPageHeightCellIndex], + ).pageCount > + 0) { + isAddNextPage = true; + } + } + } + if (!PdfGridHelper.getHelper(_grid!).isRearranged && isAddNextPage) { + final PdfSection section = + PdfPageHelper.getHelper(_currentPage!).section!; + final PdfPage page = PdfPage(); + PdfSectionHelper.getHelper(section).isNewPageSection = true; + PdfSectionHelper.getHelper(section).add(page); + _currentPage = page; + PdfSectionHelper.getHelper(section).isNewPageSection = false; + _currentGraphics = _currentPage!.graphics; + final Size clientSize = _currentPage!.getClientSize(); + _currentBounds = PdfRectangle( + 0, + 0, + clientSize.width, + clientSize.height, + ); + final int pageindex = PdfSectionHelper.getHelper( + PdfPageHelper.getHelper( + PdfGraphicsHelper.getHelper(_currentGraphics!).page!, + ).section!, + ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); + if (!PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.contains(pageindex)) { + PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.add(pageindex); + } + } else { + if (endArgs.nextPage == null) { + _currentPage = _getNextPage(format); + } else { + _currentPage = endArgs.nextPage; + _currentGraphics = endArgs.nextPage!.graphics; + _currentBounds = PdfRectangle( + 0, + 0, + _currentGraphics!.clientSize.width, + _currentGraphics!.clientSize.height, + ); + } + } + final bool isSameSection = + PdfPageHelper.getHelper(_currentPage!).section == + PdfPageHelper.getHelper(param.page!).section; + _currentBounds.y = + format.paginateBounds.top == 0 + ? PdfGridHelper.getHelper(_grid!).defaultBorder.top.width / 2 + : format.paginateBounds.top; + if (_currentPage != null) { + final Map pageLayoutResult = + _raiseBeforePageLayout( + _currentPage, + _currentBounds.rect, + _currentRowIndex, + ); + _currentBounds = PdfRectangle.fromRect( + pageLayoutResult['currentBounds'], + ); + _currentRowIndex = pageLayoutResult['currentRow'] as int; + if (pageLayoutResult['cancel'] as bool) { + break; + } + } + if ((param.format != null) && + !PdfLayoutFormatHelper.isBoundsSet(param.format!) && + param.bounds != null && + param.bounds!.height > 0 && + !PdfGridHelper.getHelper(_grid!).isChildGrid! && + isSameSection) { + _currentBounds.height = param.bounds!.height; + } + _startLocation.y = _currentBounds.y; + if (PdfRectangle.fromRect(format.paginateBounds) == + PdfRectangle.empty) { + _currentBounds.x = _currentBounds.x + _startLocation.x; + } + if (_currentBounds.x == + PdfGridHelper.getHelper(_grid!).defaultBorder.left.width / 2) { + _currentBounds.y = _currentBounds.y + _startLocation.x; + } + if (_grid!.repeatHeader) { + for ( + int headerIndex = 0; + headerIndex < _grid!.headers.count; + headerIndex++ + ) { + _drawRow(_grid!.headers[headerIndex]); + } + } + _drawRow(row); + if (_currentPage != null && + !layoutedPages.containsKey(_currentPage)) { + layoutedPages[_currentPage] = range; + } + } + if (PdfGridRowHelper.getHelper(row).gridResult != null) { + _currentPage = PdfGridRowHelper.getHelper(row).gridResult!.page; + _currentGraphics = _currentPage!.graphics; + _startLocation = PdfPoint( + PdfGridRowHelper.getHelper(row).gridResult!.bounds.left, + PdfGridRowHelper.getHelper(row).gridResult!.bounds.top, + ); + _currentBounds.y = + PdfGridRowHelper.getHelper(row).gridResult!.bounds.bottom; + if (startPage != _currentPage) { + final PdfSection secion = + PdfPageHelper.getHelper(_currentPage!).section!; + final int startIndex = + PdfSectionHelper.getHelper(secion).indexOf(startPage!) + 1; + final int endIndex = PdfSectionHelper.getHelper( + secion, + ).indexOf(_currentPage!); + for (int page = startIndex; page < endIndex + 1; page++) { + PdfGraphics pageGraphics = + PdfSectionHelper.getHelper( + secion, + ).getPageByIndex(page)!.graphics; + final PdfPoint location = PdfPoint( + format.paginateBounds.left, + format.paginateBounds.top, + ); + if (location == PdfPoint.empty && + _currentBounds.x > location.x && + !PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).isChildGrid! && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell == + null) { + location.x = _currentBounds.x; + } + double height = + page == endIndex + ? (PdfGridRowHelper.getHelper( + row, + ).gridResult!.bounds.height - + param.bounds!.y) + : (_currentBounds.height - location.y); + if (height <= pageGraphics.clientSize.height) { + height += param.bounds!.y; + } + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).isChildGrid! && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).parentCell != + null) { + location.x = location.x + param.bounds!.x; + } + location.y = format.paginateBounds.top; + for (int c = 0; c < row.cells.count; c++) { + final PdfGridCell cell = row.cells[c]; + double cellWidth = 0.0; + if (cell.columnSpan > 1) { + for (; c < cell.columnSpan; c++) { + cellWidth += + PdfGridRowHelper.getHelper(row).grid.columns[c].width; + } + } else { + cellWidth = + PdfGridHelper.getHelper(_grid!).isWidthSet + ? min( + cell.width, + PdfGridRowHelper.getHelper( + row, + ).grid.columns[c].width, + ) + : max( + cell.width, + PdfGridRowHelper.getHelper( + row, + ).grid.columns[c].width, + ); + } + pageGraphics = PdfGridCellHelper.getHelper( + cell, + ).drawCellBorders( + pageGraphics, + PdfRectangle(location.x, location.y, cellWidth, height), + ); + location.x = location.x + cellWidth; + c += cell.columnSpan - 1; + } + } + startPage = _currentPage; + } + } + } + bool isPdfGrid = false; + double maximumCellBoundsWidth = 0; + if (cellBounds.isNotEmpty) { + maximumCellBoundsWidth = cellBounds[0]!; + } + final List> largeNavigatePage = List>.filled( + 1, + List.filled(2, 0), + ); + for (int c = 0; c < _grid!.rows.count; c++) { + if (_cellEndIndex != -1 && + _grid!.rows[c].cells[_cellEndIndex].value is PdfGrid) { + final PdfGrid grid = + _grid!.rows[c].cells[_cellEndIndex].value as PdfGrid; + PdfGridHelper.getHelper(_grid!).rowLayoutBoundswidth = + PdfGridHelper.getHelper(grid).rowLayoutBoundswidth; + isPdfGrid = true; + if (largeNavigatePage[0][0]! < + PdfGridHelper.getHelper(grid).listOfNavigatePages.length) { + largeNavigatePage[0][0] = + PdfGridHelper.getHelper( + grid, + ).listOfNavigatePages.length.toDouble(); + largeNavigatePage[0][1] = cellBounds[c]; + } else if ((largeNavigatePage[0][0] == + PdfGridHelper.getHelper(grid).listOfNavigatePages.length) && + (largeNavigatePage[0][1]! < cellBounds[c]!)) { + largeNavigatePage[0][1] = cellBounds[c]; + } + } + } + if (!isPdfGrid && cellBounds.isNotEmpty) { + for (int c = 0; c < i - 1; c++) { + if (maximumCellBoundsWidth < cellBounds[c]!) { + maximumCellBoundsWidth = cellBounds[c]!; + } + } + PdfGridHelper.getHelper(_grid!).rowLayoutBoundswidth = + maximumCellBoundsWidth; + } else { + PdfGridHelper.getHelper(_grid!).rowLayoutBoundswidth = + largeNavigatePage[0][1]!; + } + if (_columnRanges!.indexOf(range) < _columnRanges!.length - 1 && + startPage != null && + format.layoutType != PdfLayoutType.onePage) { + isParentCell = PdfGridHelper.getHelper(_grid!).isChildGrid; + if (largeNavigatePage[0][0]!.toInt() != 0) { + final PdfSection section = + PdfPageHelper.getHelper(_currentPage!).section!; + final int pageIndex = PdfSectionHelper.getHelper( + section, + ).indexOf(_currentPage!); + if (PdfSectionHelper.getHelper(section).count > + pageIndex + largeNavigatePage[0][0]!.toInt()) { + _currentPage = PdfSectionHelper.getHelper( + section, + ).getPageByIndex(pageIndex + largeNavigatePage[0][0]!.toInt()); + } else { + _currentPage = PdfPage(); + PdfSectionHelper.getHelper(section).isNewPageSection = true; + PdfSectionHelper.getHelper(section).add(_currentPage!); + PdfSectionHelper.getHelper(section).isNewPageSection = false; + } + _currentGraphics = _currentPage!.graphics; + _currentBounds = PdfRectangle( + 0, + 0, + _currentGraphics!.clientSize.width, + _currentGraphics!.clientSize.height, + ); + final int pageindex = PdfSectionHelper.getHelper( + PdfPageHelper.getHelper( + PdfGraphicsHelper.getHelper(_currentGraphics!).page!, + ).section!, + ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); + if (!PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.contains(pageindex)) { + PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(pageindex); + } + } else { + _currentPage = _getNextPage(format); + } + final PdfPoint location = PdfPoint( + PdfGridHelper.getHelper(_grid!).defaultBorder.right.width / 2, + PdfGridHelper.getHelper(_grid!).defaultBorder.top.width / 2, + ); + if (PdfRectangle.fromRect(format.paginateBounds) == + PdfRectangle.empty && + _startLocation == location) { + _currentBounds.x = _currentBounds.x + _startLocation.x; + _currentBounds.y = _currentBounds.y + _startLocation.y; + } + } + } + if (_currentPage != null) { + result = _getLayoutResult(); + if (_grid!.style.allowHorizontalOverflow && + _grid!.style.horizontalOverflowType == + PdfHorizontalOverflowType.nextPage) { + _reArrangeLayoutedPages(layoutedPages); + } + _raisePageLayouted(result); + return result; + } else { + return null; + } + } + + bool _drawParentGridRow(PdfGrid grid) { + bool present = false; + PdfGridHelper.getHelper(grid).isDrawn = true; + double? y = _currentBounds.y; + for (int rowIndex = 0; rowIndex < grid.rows.count; rowIndex++) { + final PdfGridRow row = grid.rows[rowIndex]; + final PdfGridCell cell = row.cells[_cellStartIndex]; + cell.value = ''; + final PdfPoint location = PdfPoint(_currentBounds.x, _currentBounds.y); + double width = grid.columns[_cellStartIndex].width; + if (width > _currentGraphics!.clientSize.width) { + width = _currentGraphics!.clientSize.width - 2 * location.x; + } + final double height = row.height > cell.height ? row.height : cell.height; + if (_isChildGrid!) { + PdfGridCellHelper.getHelper(cell).draw( + _currentGraphics, + PdfRectangle(location.x, location.y, width, height), + false, + ); + } + _currentBounds.y = _currentBounds.y + height; + } + for (int j = 0; j < grid.rows.count; j++) { + if (PdfGridCellHelper.getHelper( + grid.rows[j].cells[_cellStartIndex], + ).present) { + present = true; + if (grid.rows[j].cells[_cellStartIndex].value is PdfGrid) { + final PdfGrid? childGrid = + grid.rows[j].cells[_cellStartIndex].value as PdfGrid?; + PdfGridCellHelper.getHelper(grid.rows[j].cells[_cellStartIndex]) + .present = false; + if (childGrid == _grid) { + if (!_isChildGrid!) { + _currentBounds.y = y!; + } else { + if (j == 0) { + _currentBounds.y = + _currentBounds.y - + PdfGridHelper.getHelper(grid).size.height; + } else { + int k = j; + while (k < grid.rows.count) { + _currentBounds.y = _currentBounds.y - grid.rows[k].height; + k++; + } + } + } + PdfGridHelper.getHelper(childGrid!).isDrawn = true; + grid.rows[j].cells[_cellStartIndex].value = childGrid; + _currentBounds.x = + _currentBounds.x + + grid.style.cellPadding.left + + grid.style.cellPadding.right; + _currentBounds.y = + _currentBounds.y + + grid.style.cellPadding.top + + grid.style.cellPadding.bottom; + _currentBounds.width = _currentBounds.width - 2 * _currentBounds.x; + break; + } else { + _isChildGrid = true; + if (_parentCellIndexList.isNotEmpty) { + _cellStartIndex = + _parentCellIndexList[_parentCellIndexList.length - 1]; + _parentCellIndexList.removeAt(_parentCellIndexList.length - 1); + } + _currentBounds.y = y!; + _currentBounds.x = + _currentBounds.x + + grid.style.cellPadding.left + + grid.style.cellPadding.right; + _currentBounds.y = + _currentBounds.y + + grid.style.cellPadding.top + + grid.style.cellPadding.bottom; + final bool isPresent = _drawParentGridRow(childGrid!); + if (!isPresent) { + _currentBounds.y = + _currentBounds.y - + PdfGridHelper.getHelper(childGrid).size.height; + } + _isChildGrid = false; + break; + } + } else { + y = y! + grid.rows[j].height; + } + } else { + y = y! + grid.rows[j].height; + } + } + return present; + } + + _RowLayoutResult? _drawRow( + PdfGridRow? row, [ + _RowLayoutResult? result, + double? height, + ]) { + if (result == null && height == null) { + _RowLayoutResult result = _RowLayoutResult(); + double rowHeightWithSpan = 0; + bool isHeader = false; + if (PdfGridRowHelper.getHelper(row!).rowSpanExists) { + int currRowIndex = PdfGridRowCollectionHelper.indexOf(_grid!.rows, row); + int maxSpan = PdfGridRowHelper.getHelper(row).maximumRowSpan; + if (currRowIndex == -1) { + currRowIndex = PdfGridHeaderCollectionHelper.getHelper( + _grid!.headers, + ).indexOf(row); + if (currRowIndex != -1) { + isHeader = true; + } + } + for (int i = currRowIndex; i < currRowIndex + maxSpan; i++) { + rowHeightWithSpan += + isHeader ? _grid!.headers[i].height : _grid!.rows[i].height; + } + if ((rowHeightWithSpan > _currentBounds.height || + rowHeightWithSpan + _currentBounds.y > _currentBounds.height) && + !PdfGridRowHelper.getHelper(row).isPageBreakRowSpanApplied) { + rowHeightWithSpan = 0; + PdfGridRowHelper.getHelper(row).isPageBreakRowSpanApplied = true; + for (int cellIndex = 0; cellIndex < row.cells.count; cellIndex++) { + final PdfGridCell cell = row.cells[cellIndex]; + maxSpan = cell.rowSpan; + for (int i = currRowIndex; i < currRowIndex + maxSpan; i++) { + rowHeightWithSpan += + isHeader ? _grid!.headers[i].height : _grid!.rows[i].height; + if ((_currentBounds.y + rowHeightWithSpan) > + _currentPageBounds.height) { + rowHeightWithSpan -= + isHeader ? _grid!.headers[i].height : _grid!.rows[i].height; + for ( + int j = 0; + j < _grid!.rows[currRowIndex].cells.count; + j++ + ) { + final int newSpan = i - currRowIndex; + if (!isHeader && + (_grid!.rows[currRowIndex].cells[j].rowSpan == maxSpan)) { + _grid!.rows[currRowIndex].cells[j].rowSpan = + newSpan == 0 ? 1 : newSpan; + PdfGridRowHelper.getHelper(_grid!.rows[currRowIndex]) + .maximumRowSpan = newSpan == 0 ? 1 : newSpan; + _grid!.rows[i].cells[j].rowSpan = maxSpan - newSpan; + PdfGrid? pdfGrid; + if (_grid!.rows[currRowIndex].cells[j].value is PdfGrid) { + pdfGrid = + _grid!.rows[currRowIndex].cells[j].value as PdfGrid?; + } + _grid!.rows[i].cells[j].stringFormat = + _grid!.rows[currRowIndex].cells[j].stringFormat; + _grid!.rows[i].cells[j].style = + _grid!.rows[currRowIndex].cells[j].style; + _grid!.rows[i].cells[j].style.backgroundImage = null; + _grid!.rows[i].cells[j].columnSpan = + _grid!.rows[currRowIndex].cells[j].columnSpan; + if (pdfGrid is PdfGrid && + _currentBounds.y + + PdfGridHelper.getHelper(pdfGrid).size.height + + _grid!.rows[i].height + + pdfGrid.style.cellPadding.top + + pdfGrid.style.cellPadding.bottom >= + _currentBounds.height) { + _grid!.rows[i].cells[j].value = + _grid!.rows[currRowIndex].cells[j].value; + } else if (pdfGrid is! PdfGrid) { + _grid!.rows[i].cells[j].value = + _grid!.rows[currRowIndex].cells[j].value; + } + if (i > 0) { + PdfGridRowHelper.getHelper(_grid!.rows[i - 1]) + .rowSpanExists = true; + } + PdfGridCellHelper.getHelper(_grid!.rows[i].cells[j]) + .isRowMergeContinue = false; + } else if (isHeader && + (_grid!.headers[currRowIndex].cells[j].rowSpan == + maxSpan)) { + _grid!.headers[currRowIndex].cells[j].rowSpan = + newSpan == 0 ? 1 : newSpan; + _grid!.headers[i].cells[j].rowSpan = maxSpan - newSpan; + _grid!.headers[i].cells[j].stringFormat = + _grid!.headers[currRowIndex].cells[j].stringFormat; + _grid!.headers[i].cells[j].style = + _grid!.headers[currRowIndex].cells[j].style; + _grid!.headers[i].cells[j].columnSpan = + _grid!.headers[currRowIndex].cells[j].columnSpan; + _grid!.headers[i].cells[j].value = + _grid!.headers[currRowIndex].cells[j].value; + PdfGridRowHelper.getHelper(_grid!.headers[i - 1]) + .rowSpanExists = false; + PdfGridCellHelper.getHelper(_grid!.headers[i].cells[j]) + .isRowMergeContinue = false; + } + } + break; + } + } + rowHeightWithSpan = 0; + } + } + } + double? height = + PdfGridRowHelper.getHelper(row).rowBreakHeight > 0.0 + ? PdfGridRowHelper.getHelper(row).rowBreakHeight + : row.height; + if (PdfGridHelper.getHelper(_grid!).isChildGrid! && + PdfGridHelper.getHelper(_grid!).parentCell != null) { + if (height + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.top > + _currentPageBounds.height) { + userHeight = _startLocation.y; + if (_grid!.allowRowBreakingAcrossPages) { + result.isFinish = true; + if (PdfGridHelper.getHelper(_grid!).isChildGrid! && + PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { + _currentBounds.y = + _currentBounds.y + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.top; + _currentBounds.x = _startLocation.x; + } + result.bounds = _currentBounds; + result = _drawRowWithBreak(row, result, height); + } else { + _currentBounds.y = + _currentBounds.y + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.top; + height = + _currentBounds.height - + _currentBounds.y - + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom; + result.isFinish = false; + _drawRow(row, result, height); + } + } else if (_currentBounds.y + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom + + height > + _currentPageBounds.height || + _currentBounds.y + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom + + height > + _currentBounds.height || + _currentBounds.y + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom + + rowHeightWithSpan > + _currentPageBounds.height) { + if (repeatRowIndex > -1 && + repeatRowIndex == PdfGridRowHelper.getHelper(row).index) { + if (_grid!.allowRowBreakingAcrossPages) { + result.isFinish = true; + if (PdfGridHelper.getHelper(_grid!).isChildGrid! && + PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { + _currentBounds.y = + _currentBounds.y + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.top; + + _currentBounds.x = _startLocation.x; + } + result.bounds = _currentBounds; + result = _drawRowWithBreak(row, result, height); + } else { + result.isFinish = false; + _drawRow(row, result, height); + } + } else { + result.isFinish = false; + } + } else { + result.isFinish = true; + if (PdfGridHelper.getHelper(_grid!).isChildGrid! && + PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { + height += + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper(_grid!).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom; + } + _drawRow(row, result, height); + } + } else { + if (height > _currentPageBounds.height) { + if (_grid!.allowRowBreakingAcrossPages) { + result.isFinish = true; + result = _drawRowWithBreak(row, result, height); + } else { + result.isFinish = false; + _drawRow(row, result, height); + } + } else if (_currentBounds.y + height > _currentPageBounds.height || + (_currentBounds.y + height) - userHeight > _currentBounds.height || + _currentBounds.y + rowHeightWithSpan > _currentPageBounds.height) { + if (repeatRowIndex > -1 && + repeatRowIndex == PdfGridRowHelper.getHelper(row).index) { + if (_grid!.allowRowBreakingAcrossPages) { + result.isFinish = true; + result = _drawRowWithBreak(row, result, height); + } else { + result.isFinish = false; + _drawRow(row, result, height); + } + } else { + result.isFinish = false; + } + } else { + result.isFinish = true; + _drawRow(row, result, height); + } + } + return result; + } else { + bool? skipcell = false; + final PdfPoint location = _currentBounds.location; + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).isChildGrid! && + PdfGridRowHelper.getHelper(row).grid.allowRowBreakingAcrossPages && + _startLocation.x != _currentBounds.x && + PdfGridRowHelper.getHelper(row).getWidth() < + _currentPage!.getClientSize().width) { + location.x = _startLocation.x; + } + result!.bounds = PdfRectangle(location.x, location.y, 0, 0); + height = _reCalculateHeight(row, height!); + for (int i = _cellStartIndex; i <= _cellEndIndex; i++) { + final bool cancelSpans = + i > _cellEndIndex + 1 && row.cells[i].columnSpan > 1; + if (!cancelSpans) { + for (int j = 1; j < row.cells[i].columnSpan; j++) { + PdfGridCellHelper.getHelper(row.cells[i + j]).isCellMergeContinue = + true; + } + } + final PdfSize size = PdfSize(_grid!.columns[i].width, height); + if (size.width > _currentGraphics!.clientSize.width) { + size.width = _currentGraphics!.clientSize.width; + } + if (PdfGridHelper.getHelper(_grid!).isChildGrid! && + _grid!.style.allowHorizontalOverflow) { + if (size.width >= _currentGraphics!.clientSize.width) { + size.width = size.width - 2 * _currentBounds.x; + } + } + if (!_checkIfDefaultFormat(_grid!.columns[i].format) && + _checkIfDefaultFormat(row.cells[i].stringFormat)) { + row.cells[i].stringFormat = _grid!.columns[i].format; + } + + PdfGridCellStyle cellstyle = row.cells[i].style; + final Map bclResult = _raiseBeforeCellLayout( + _currentGraphics, + PdfGridRowHelper.getHelper(row).isHeaderRow + ? _currentHeaderRowIndex + : _currentRowIndex, + i, + PdfRectangle(location.x, location.y, size.width, size.height), + (row.cells[i].value is String) ? row.cells[i].value.toString() : '', + cellstyle, + PdfGridRowHelper.getHelper(row).isHeaderRow, + ); + cellstyle = bclResult['style'] as PdfGridCellStyle; + final PdfGridBeginCellLayoutArgs? gridbclArgs = + bclResult['args'] as PdfGridBeginCellLayoutArgs?; + row.cells[i].style = cellstyle; + if (gridbclArgs != null) { + skipcell = gridbclArgs.skip; + } + if (!skipcell!) { + if (row.cells[i].value is PdfGrid) { + final PdfGrid grid = row.cells[i].value as PdfGrid; + PdfGridHelper.getHelper(grid).parentCellIndex = i; + } + final PdfStringLayoutResult? stringResult = + PdfGridCellHelper.getHelper(row.cells[i]).draw( + _currentGraphics, + PdfRectangle(location.x, location.y, size.width, size.height), + cancelSpans, + ); + if (PdfGridRowHelper.getHelper( + row, + ).grid.style.allowHorizontalOverflow && + (row.cells[i].columnSpan > _cellEndIndex || + i + row.cells[i].columnSpan > _cellEndIndex + 1) && + _cellEndIndex < row.cells.count - 1) { + PdfGridRowHelper.getHelper(row).rowOverflowIndex = _cellEndIndex; + } + if (PdfGridRowHelper.getHelper( + row, + ).grid.style.allowHorizontalOverflow && + (PdfGridRowHelper.getHelper(row).rowOverflowIndex >= 0 && + (row.cells[i].columnSpan > _cellEndIndex || + i + row.cells[i].columnSpan > _cellEndIndex + 1)) && + row.cells[i].columnSpan - _cellEndIndex + i - 1 > 0) { + row + .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] + .value = stringResult != null && stringResult.remainder != null + ? stringResult.remainder + : ''; + row + .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] + .stringFormat = row.cells[i].stringFormat; + row + .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] + .style = row.cells[i].style; + row + .cells[PdfGridRowHelper.getHelper(row).rowOverflowIndex + 1] + .columnSpan = row.cells[i].columnSpan - _cellEndIndex + i - 1; + } + } + + if (!cancelSpans) { + _raiseAfterCellLayout( + _currentGraphics, + _currentRowIndex, + i, + PdfRectangle(location.x, location.y, size.width, size.height), + (row.cells[i].value is String) ? row.cells[i].value.toString() : '', + row.cells[i].style, + PdfGridRowHelper.getHelper(row).isHeaderRow, + ); + } + + if (row.cells[i].value is PdfGrid) { + final PdfGrid grid = row.cells[i].value as PdfGrid; + PdfGridCellHelper.getHelper(row.cells[i]).pageCount = + PdfGridHelper.getHelper(grid).listOfNavigatePages.length; + _rowBreakPageHeightCellIndex = i; + for ( + int k = 0; + k < PdfGridHelper.getHelper(grid).listOfNavigatePages.length; + k++ + ) { + final int pageIndex = + PdfGridHelper.getHelper(grid).listOfNavigatePages[k]; + if (!PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.contains(pageIndex)) { + PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.add(pageIndex); + } + } + if (_grid!.columns[i].width >= _currentGraphics!.clientSize.width) { + location.x = PdfGridHelper.getHelper(grid).rowLayoutBoundswidth; + location.x = location.x + grid.style.cellSpacing; + } else { + location.x = location.x + _grid!.columns[i].width; + } + } else { + location.x = location.x + _grid!.columns[i].width; + } + } + if (!PdfGridRowHelper.getHelper(row).rowMergeComplete || + PdfGridRowHelper.getHelper(row).isRowHeightSet) { + _currentBounds.y = _currentBounds.y + height; + } + result.bounds = PdfRectangle( + result.bounds.x, + result.bounds.y, + location.x, + location.y, + ); + return null; + } + } + + double _reCalculateHeight(PdfGridRow? row, double height) { + double newHeight = 0.0; + for (int i = _cellStartIndex; i <= _cellEndIndex; i++) { + if (PdfGridCellHelper.getHelper(row!.cells[i]).remainingString != null && + PdfGridCellHelper.getHelper( + row.cells[i], + ).remainingString!.isNotEmpty) { + newHeight = max( + newHeight, + PdfGridCellHelper.getHelper(row.cells[i]).measureHeight(), + ); + } + } + return max(height, newHeight); + } + + _RowLayoutResult _drawRowWithBreak( + PdfGridRow row, + _RowLayoutResult result, + double? height, + ) { + final PdfPoint location = _currentBounds.location; + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).isChildGrid! && + PdfGridRowHelper.getHelper(row).grid.allowRowBreakingAcrossPages && + _startLocation.x != _currentBounds.x) { + location.x = _startLocation.x; + } + result.bounds = PdfRectangle(location.x, location.y, 0, 0); + _newheight = + PdfGridRowHelper.getHelper(row).rowBreakHeight > 0 + ? _currentBounds.height < _currentPageBounds.height + ? _currentBounds.height + : _currentPageBounds.height + : 0; + if (PdfGridRowHelper.getHelper(row).grid.style.cellPadding.top + + _currentBounds.y + + PdfGridRowHelper.getHelper(row).grid.style.cellPadding.bottom < + _currentPageBounds.height) { + PdfGridRowHelper.getHelper(row).rowBreakHeight = + _currentBounds.y + height! - _currentPageBounds.height; + } else { + PdfGridRowHelper.getHelper(row).rowBreakHeight = height!; + result.isFinish = false; + return result; + } + for (int cellIndex = 0; cellIndex < row.cells.count; cellIndex++) { + final PdfGridCell cell = row.cells[cellIndex]; + if (PdfGridCellHelper.getHelper(cell).measureHeight() == height) { + PdfGridRowHelper.getHelper(row).rowBreakHeight = + cell.value is PdfGrid + ? 0 + : _currentBounds.y + height - _currentBounds.height < + _currentPageBounds.height + ? _currentBounds.height + : _currentPageBounds.height; + } + } + for (int i = _cellStartIndex; i <= _cellEndIndex; i++) { + final bool cancelSpans = + row.cells[i].columnSpan + i > _cellEndIndex + 1 && + row.cells[i].columnSpan > 1; + if (!cancelSpans) { + for (int j = 1; j < row.cells[i].columnSpan; j++) { + PdfGridCellHelper.getHelper(row.cells[i + j]).isCellMergeContinue = + true; + } + } + PdfSize size = PdfSize( + _grid!.columns[i].width, + _newheight > 0.0 + ? _newheight + : _currentBounds.height < _currentPageBounds.height + ? _currentBounds.height + : _currentPageBounds.height, + ); + if (size.width == 0) { + size = PdfSize(row.cells[i].width, size.height); + } + if (!_checkIfDefaultFormat(_grid!.columns[i].format) && + _checkIfDefaultFormat(row.cells[i].stringFormat)) { + row.cells[i].stringFormat = _grid!.columns[i].format; + } + PdfGridCellStyle cellstyle = row.cells[i].style; + final Map cellLayoutResult = _raiseBeforeCellLayout( + _currentGraphics, + PdfGridRowHelper.getHelper(row).isHeaderRow + ? _currentHeaderRowIndex + : _currentRowIndex, + i, + PdfRectangle(location.x, location.y, size.width, size.height), + row.cells[i].value is String ? row.cells[i].value.toString() : '', + cellstyle, + PdfGridRowHelper.getHelper(row).isHeaderRow, + ); + cellstyle = cellLayoutResult['style'] as PdfGridCellStyle; + final PdfGridBeginCellLayoutArgs? bclArgs = + cellLayoutResult['args'] as PdfGridBeginCellLayoutArgs?; + row.cells[i].style = cellstyle; + final bool skipcell = bclArgs != null && bclArgs.skip; + PdfStringLayoutResult? stringResult; + if (!skipcell) { + stringResult = PdfGridCellHelper.getHelper(row.cells[i]).draw( + _currentGraphics, + PdfRectangle(location.x, location.y, size.width, size.height), + cancelSpans, + ); + } + if (PdfGridRowHelper.getHelper(row).rowBreakHeight > 0.0) { + if (stringResult != null) { + PdfGridCellHelper.getHelper(row.cells[i]).finished = false; + PdfGridCellHelper.getHelper(row.cells[i]).remainingString = + stringResult.remainder ?? ''; + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row).grid, + ).isChildGrid!) { + PdfGridRowHelper.getHelper(row).rowBreakHeight = + height - stringResult.size.height; + } + } else if (row.cells[i].value is PdfImage) { + PdfGridCellHelper.getHelper(row.cells[i]).finished = false; + } + } + result.isFinish = + (!result.isFinish) + ? result.isFinish + : PdfGridCellHelper.getHelper(row.cells[i]).finished; + if (!cancelSpans) { + _raiseAfterCellLayout( + _currentGraphics, + _currentRowIndex, + i, + PdfRectangle(location.x, location.y, size.width, size.height), + (row.cells[i].value is String) ? row.cells[i].value.toString() : '', + row.cells[i].style, + PdfGridRowHelper.getHelper(row).isHeaderRow, + ); + } + if (row.cells[i].value is PdfGrid) { + final PdfGrid grid = row.cells[i].value as PdfGrid; + _rowBreakPageHeightCellIndex = i; + PdfGridCellHelper.getHelper(row.cells[i]).pageCount = + PdfGridHelper.getHelper(grid).listOfNavigatePages.length; + for ( + int i = 0; + i < PdfGridHelper.getHelper(grid).listOfNavigatePages.length; + i++ + ) { + final int pageIndex = + PdfGridHelper.getHelper(grid).listOfNavigatePages[i]; + if (!PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.contains(pageIndex)) { + PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(pageIndex); + } + } + if (_grid!.columns[i].width >= _currentGraphics!.clientSize.width) { + location.x = PdfGridHelper.getHelper(grid).rowLayoutBoundswidth; + location.x = location.x + grid.style.cellSpacing; + } else { + location.x = location.x + _grid!.columns[i].width; + } + } else { + location.x = location.x + _grid!.columns[i].width; + } + } + _currentBounds.y = + _currentBounds.y + (_newheight > 0.0 ? _newheight : height); + result.bounds = PdfRectangle( + result.bounds.x, + result.bounds.y, + location.x, + location.y, + ); + return result; + } + + bool _checkIfDefaultFormat(PdfStringFormat format) { + final PdfStringFormat defaultFormat = PdfStringFormat(); + return format.alignment == defaultFormat.alignment && + format.characterSpacing == defaultFormat.characterSpacing && + format.clipPath == defaultFormat.clipPath && + PdfStringFormatHelper.getHelper(format).firstLineIndent == + PdfStringFormatHelper.getHelper(defaultFormat).firstLineIndent && + PdfStringFormatHelper.getHelper(format).scalingFactor == + PdfStringFormatHelper.getHelper(defaultFormat).scalingFactor && + format.lineAlignment == defaultFormat.lineAlignment && + format.lineLimit == defaultFormat.lineLimit && + format.lineSpacing == defaultFormat.lineSpacing && + format.measureTrailingSpaces == defaultFormat.measureTrailingSpaces && + format.noClip == defaultFormat.noClip && + format.paragraphIndent == defaultFormat.paragraphIndent && + format.textDirection == defaultFormat.textDirection && + format.subSuperscript == defaultFormat.subSuperscript && + format.wordSpacing == defaultFormat.wordSpacing && + format.wordWrap == defaultFormat.wordWrap; + } + + void _reArrangeLayoutedPages(Map> layoutedPages) { + final PdfDocument? document = + PdfPageHelper.getHelper(_currentPage!).document; + final List pages = layoutedPages.keys.toList(); + for (int i = 0; i < pages.length; i++) { + final PdfPage page = pages[i]!; + PdfPageHelper.getHelper(page).section = null; + PdfPageCollectionHelper.getHelper(document!.pages).remove(page); + } + for (int i = 0; i < layoutedPages.length; i++) { + for ( + int j = i; + j < layoutedPages.length; + j += layoutedPages.length ~/ _columnRanges!.length + ) { + final PdfPage page = pages[j]!; + if (document!.pages.indexOf(page) == -1) { + PdfPageCollectionHelper.getHelper(document.pages).addPage(page); + } + } + } + } + + void _reArrangePages(PdfPage page) { + final List pages = []; + final PdfDocument document = PdfPageHelper.getHelper(page).document!; + int pageCount = document.pages.count; + int m = document.pages.indexOf(page); + int n = _columnRanges!.length; + if (pageCount <= _columnRanges!.length) { + for (int i = 0; i < _columnRanges!.length; i++) { + document.pages.add(); + if (document.pages.count > _columnRanges!.length) { + break; + } + } + } + pageCount = document.pages.count; + for (int i = 0; i < pageCount; i++) { + if (m < pageCount && pages.length != pageCount) { + final PdfPage tempPage = document.pages[m]; + if (!pages.contains(tempPage)) { + pages.add(tempPage); + } + } + if (n < pageCount && pages.length != pageCount) { + final PdfPage tempPage = document.pages[n]; + if (!pages.contains(tempPage)) { + pages.add(tempPage); + } + } + if (pages.length == pageCount) { + break; + } + m++; + n++; + } + for (int i = 0; i < pages.length; i++) { + final PdfPage tempPage = pages[i]!; + PdfPageHelper.getHelper(tempPage).section = null; + PdfPageCollectionHelper.getHelper(document.pages).remove(tempPage); + } + for (int i = 0; i < pages.length; i++) { + PdfPageCollectionHelper.getHelper(document.pages).addPage(pages[i]!); + } + } + + PdfPage? _getNextPage(PdfLayoutFormat format) { + final PdfSection section = PdfPageHelper.getHelper(_currentPage!).section!; + PdfPage? nextPage; + final int index = PdfSectionHelper.getHelper( + section, + ).indexOf(_currentPage!); + if (PdfPageHelper.getHelper(_currentPage!).document!.pages.count > 1 && + _hType == PdfHorizontalOverflowType.nextPage && + flag && + _columnRanges!.length > 1) { + PdfGridHelper.getHelper(_grid!).isRearranged = true; + _reArrangePages(_currentPage!); + } + flag = false; + if (index == PdfSectionHelper.getHelper(section).count - 1) { + nextPage = PdfPage(); + PdfSectionHelper.getHelper(section).isNewPageSection = true; + PdfSectionHelper.getHelper(section).add(nextPage); + PdfSectionHelper.getHelper(section).isNewPageSection = false; + } else { + nextPage = PdfSectionHelper.getHelper(section).getPageByIndex(index + 1); + } + _currentGraphics = nextPage!.graphics; + final int pageindex = PdfSectionHelper.getHelper( + PdfPageHelper.getHelper( + PdfGraphicsHelper.getHelper(_currentGraphics!).page!, + ).section!, + ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!); + if (!PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.contains(pageindex)) { + PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(pageindex); + } + _currentBounds = PdfRectangle( + 0, + 0, + _currentGraphics!.clientSize.width, + _currentGraphics!.clientSize.height, + ); + if (PdfRectangle.fromRect(format.paginateBounds) != PdfRectangle.empty) { + _currentBounds.x = format.paginateBounds.left; + _currentBounds.y = format.paginateBounds.top; + _currentBounds.height = format.paginateBounds.height; + } + return nextPage; + } + + PdfLayoutResult _getLayoutResult() { + if (PdfGridHelper.getHelper(_grid!).isChildGrid! && + _grid!.allowRowBreakingAcrossPages) { + for (int rowIndex = 0; rowIndex < _grid!.rows.count; rowIndex++) { + final PdfGridRow row = _grid!.rows[rowIndex]; + if (PdfGridRowHelper.getHelper(row).rowBreakHeight > 0) { + _startLocation.y = PdfPageHelper.getHelper(_currentPage!).origin.dy; + } + } + } + final Rect bounds = + _isChanged + ? Rect.fromLTWH( + _currentLocation.x, + _currentLocation.y, + _currentBounds.width, + _currentBounds.y - _currentLocation.y, + ) + : Rect.fromLTWH( + _startLocation.x, + _startLocation.y, + _currentBounds.width, + _currentBounds.y - _startLocation.y, + ); + return PdfLayoutResultHelper.load(_currentPage!, bounds); + } + + Map _raiseBeforePageLayout( + PdfPage? currentPage, + Rect currentBounds, + int? currentRow, + ) { + bool cancel = false; + if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout) { + final PdfGridBeginPageLayoutArgs args = + PdfGridBeginPageLayoutArgsHelper.load( + currentBounds, + currentPage!, + currentRow, + ); + PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); + if (PdfRectangle.fromRect(currentBounds) != + PdfRectangle.fromRect(args.bounds)) { + _isChanged = true; + _currentLocation = PdfPoint(args.bounds.left, args.bounds.top); + PdfGridHelper.getHelper(_grid!).measureColumnsWidth( + PdfRectangle( + args.bounds.left, + args.bounds.top, + args.bounds.width + args.bounds.left, + args.bounds.height, + ), + ); + } + cancel = args.cancel; + currentBounds = args.bounds; + currentRow = args.startRowIndex; + } + return { + 'cancel': cancel, + 'currentBounds': currentBounds, + 'currentRow': currentRow, + }; + } + + PdfGridEndPageLayoutArgs _raisePageLayouted(PdfLayoutResult result) { + final PdfGridEndPageLayoutArgs args = PdfGridEndPageLayoutArgsHelper.load( + result, + ); + if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted) { + PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); + } + return args; + } + + Map _raiseBeforeCellLayout( + PdfGraphics? graphics, + int rowIndex, + int cellIndex, + PdfRectangle bounds, + String value, + PdfGridCellStyle? style, + bool isHeaderRow, + ) { + PdfGridBeginCellLayoutArgs? args; + if (PdfGridHelper.getHelper(_grid!).raiseBeginCellLayout) { + args = PdfGridBeginCellLayoutArgsHelper.load( + graphics!, + rowIndex, + cellIndex, + bounds, + value, + style, + isHeaderRow, + ); + PdfGridHelper.getHelper(_grid!).onBeginCellLayout(args); + style = args.style; + } + return {'args': args, 'style': style}; + } + + void _raiseAfterCellLayout( + PdfGraphics? graphics, + int rowIndex, + int cellIndex, + PdfRectangle bounds, + String value, + PdfGridCellStyle? cellstyle, + bool isHeaderRow, + ) { + PdfGridEndCellLayoutArgs args; + if (PdfGridHelper.getHelper(_grid!).raiseEndCellLayout) { + args = PdfGridEndCellLayoutArgsHelper.load( + graphics!, + rowIndex, + cellIndex, + bounds, + value, + cellstyle, + isHeaderRow, + ); + PdfGridHelper.getHelper(_grid!).onEndCellLayout(args); + } + } + + //Override methods + @override + PdfLayoutResult? layoutInternal(PdfLayoutParams param) { + final PdfLayoutFormat format = _getFormat(param.format); + _currentPage = param.page; + if (_currentPage != null) { + final Size size = _currentPage!.getClientSize(); + final double pageHeight = size.height; + final double pageWidth = size.width; + if (pageHeight > pageWidth || + (PdfPageHelper.getHelper(param.page!).orientation == + PdfPageOrientation.landscape && + format.breakType == PdfLayoutBreakType.fitPage)) { + _currentPageBounds = PdfSize.fromSize(size); + } else { + _currentPageBounds = PdfSize.fromSize(_currentPage!.size); + } + } else { + _currentPageBounds = PdfSize.fromSize(_currentGraphics!.clientSize); + } + if (_currentPage != null) { + _currentGraphics = _currentPage!.graphics; + } + if (PdfGraphicsHelper.getHelper(_currentGraphics!).layer != null) { + final int index = + !PdfPageHelper.getHelper( + PdfGraphicsHelper.getHelper(_currentGraphics!).page!, + ).isLoadedPage + ? PdfSectionHelper.getHelper( + PdfPageHelper.getHelper( + PdfGraphicsHelper.getHelper(_currentGraphics!).page!, + ).section!, + ).indexOf(PdfGraphicsHelper.getHelper(_currentGraphics!).page!) + : PdfGraphicsHelper.getHelper( + _currentGraphics!, + ).page!.defaultLayerIndex; + if (!PdfGridHelper.getHelper( + _grid!, + ).listOfNavigatePages.contains(index)) { + PdfGridHelper.getHelper(_grid!).listOfNavigatePages.add(index); + } + } + _currentBounds = PdfRectangle( + param.bounds!.x, + param.bounds!.y, + format.breakType == PdfLayoutBreakType.fitColumnsToPage + ? PdfGridColumnCollectionHelper.getHelper(_grid!.columns).columnWidth + : _currentGraphics!.clientSize.width, + _currentGraphics!.clientSize.height, + ); + if (_grid!.rows.count != 0) { + _currentBounds.width = + (param.bounds!.width > 0) + ? param.bounds!.width + : (_currentBounds.width - + _grid!.rows[0].cells[0].style.borders.left.width / 2); + } else if (_grid!.headers.count != 0) { + _currentBounds.width = + (param.bounds!.width > 0) + ? param.bounds!.width + : (_currentBounds.width - + _grid!.headers[0].cells[0].style.borders.left.width / 2); + } + _startLocation = param.bounds!.location; + if (_grid!.style.allowHorizontalOverflow && + _currentBounds.width > _currentGraphics!.clientSize.width) { + _currentBounds.width = + _currentGraphics!.clientSize.width - _currentBounds.x; + } + if (PdfGridHelper.getHelper(_grid!).isChildGrid!) { + _childHeight = param.bounds!.height; + } + if (param.format != null && + PdfLayoutFormatHelper.isBoundsSet(param.format!)) { + if (param.format!.paginateBounds.height > 0) { + _currentBounds.height = param.format!.paginateBounds.height; + } + } else if (param.bounds!.height > 0 && + !PdfGridHelper.getHelper(_grid!).isChildGrid!) { + _currentBounds.height = param.bounds!.height; + } + if (PdfGridHelper.getHelper(_grid!).isChildGrid!) { + _hType = _grid!.style.horizontalOverflowType; + } + if (!_grid!.style.allowHorizontalOverflow) { + PdfGridHelper.getHelper(_grid!).measureColumnsWidth(_currentBounds); + _columnRanges!.add([0, _grid!.columns.count - 1]); + } else { + PdfGridHelper.getHelper(_grid!).measureColumnsWidth(); + _determineColumnDrawRanges(); + } + if (PdfGridHelper.getHelper(_grid!).hasRowSpan) { + for (int i = 0; i < _grid!.rows.count; i++) { + _grid!.rows[i].height; + if (!PdfGridRowHelper.getHelper(_grid!.rows[i]).isRowHeightSet) { + PdfGridRowHelper.getHelper(_grid!.rows[i]).isRowHeightSet = true; + } else { + PdfGridRowHelper.getHelper(_grid!.rows[i]).isRowSpanRowHeightSet = + true; + } + } + } + userHeight = _startLocation.y; + return _layoutOnPage(param); + } +} + +class _RowLayoutResult { + _RowLayoutResult() { + bounds = PdfRectangle.empty; + isFinish = false; + } + late bool isFinish; + late PdfRectangle bounds; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid.dart index b5052d403..d43bdaff4 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid.dart @@ -1,5774 +1,5774 @@ -import 'dart:math'; -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/enums.dart'; -import '../../graphics/figures/base/element_layouter.dart'; -import '../../graphics/figures/base/layout_element.dart'; -import '../../graphics/figures/base/text_layouter.dart'; -import '../../graphics/fonts/enums.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_standard_font.dart'; -import '../../graphics/fonts/pdf_true_type_font.dart'; -import '../../graphics/pdf_color.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../graphics/pdf_pen.dart'; -import '../../pages/pdf_page.dart'; -import 'enums.dart'; -import 'layouting/pdf_grid_layouter.dart'; -import 'pdf_grid_cell.dart'; -import 'pdf_grid_column.dart'; -import 'pdf_grid_row.dart'; -import 'styles/pdf_borders.dart'; -import 'styles/style.dart'; - -/// Represents a flexible grid that consists of columns and rows. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid class -/// PdfGrid grid = PdfGrid(); -/// //Add the columns to the grid -/// grid.columns.add(count: 3); -/// //Add header to the grid -/// grid.headers.add(1); -/// //Add the rows to the grid -/// PdfGridRow header = grid.headers[0]; -/// header.cells[0].value = 'Employee ID'; -/// header.cells[1].value = 'Employee Name'; -/// header.cells[2].value = 'Salary'; -/// //Add rows to grid -/// PdfGridRow row = grid.rows.add(); -/// row.cells[0].value = 'E01'; -/// row.cells[1].value = 'Clay'; -/// row.cells[2].value = '\$10,000'; -/// row = grid.rows.add(); -/// row.cells[0].value = 'E02'; -/// row.cells[1].value = 'Simon'; -/// row.cells[2].value = '\$12,000'; -/// //Set the grid style -/// grid.style = PdfGridStyle( -/// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), -/// backgroundBrush: PdfBrushes.blue, -/// textBrush: PdfBrushes.white, -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); -/// //Draw the grid -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGrid extends PdfLayoutElement { - /// Initializes a new instance of the [PdfGrid] class. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGrid() { - _helper = PdfGridHelper(this); - _initialize(); - } - - //Fields - late PdfGridHelper _helper; - PdfGridColumnCollection? _columns; - PdfGridRowCollection? _rows; - PdfGridStyle? _style; - PdfGridHeaderCollection? _headers; - - /// Gets or sets a value indicating whether to repeat header. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Sets repeatHeader - /// grid.repeatHeader = true; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// for (int i = 0; i < 500; i++) { - /// final PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'Row - $i Cell - 1'; - /// row.cells[1].value = 'Row - $i Cell - 2'; - /// row.cells[2].value = 'Row - $i Cell - 3'; - /// } - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late bool repeatHeader; - - /// Gets or sets a value indicating whether to split or cut rows that overflow a page. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Sets allowRowBreakingAcrossPages - /// grid.allowRowBreakingAcrossPages = true; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(100); - /// //Add the rows to the grid - /// for (int i = 0; i < 100; i++) { - /// final PdfGridRow header = grid.headers[i]; - /// header.cells[0].value = 'Header - $i Cell - 1'; - /// final PdfTextElement element = PdfTextElement(font: PdfStandardFont(PdfFontFamily.timesRoman, 15)); - /// element.text = - /// 'Header - $i Cell - 2 Sample text for pagination. Lorem ipsum dolor sit amet,\r\n consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua'; - /// header.cells[1].value = element; - /// header.cells[2].value = 'Header - $i Cell - 3'; - /// } - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late bool allowRowBreakingAcrossPages; - late PdfRectangle _gridLocation; - bool _headerRow = true; - bool _bandedRow = true; - late bool _bandedColumn; - late bool _totalRow; - late bool _firstColumn; - late bool _lastColumn; - Map? _boldFontCache; - Map? _regularFontCache; - Map? _italicFontCache; - - //Events - /// The event raised on starting cell lay outing. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on starting cell lay outing. - /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridBeginCellLayoutCallback? beginCellLayout; - - /// The event raised on finished cell layout. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on finished cell layout. - /// grid.endCellLayout = (Object sender, PdfGridEndCellLayoutArgs args) { - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridEndCellLayoutCallback? endCellLayout; - - //Properties - /// Gets the column collection of the PdfGrid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Set the grid style - /// grid.style = PdfGridStyle( - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// backgroundBrush: PdfBrushes.blue, - /// textBrush: PdfBrushes.white, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridColumnCollection get columns { - _columns ??= PdfGridColumnCollection(this); - return _columns!; - } - - /// Gets the row collection from the PdfGrid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Set the grid style - /// grid.style = PdfGridStyle( - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// backgroundBrush: PdfBrushes.blue, - /// textBrush: PdfBrushes.white, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridRowCollection get rows { - _rows ??= PdfGridRowCollection(this); - return _rows!; - } - - /// Gets the headers collection from the PdfGrid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Set the grid style - /// grid.style = PdfGridStyle( - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// backgroundBrush: PdfBrushes.blue, - /// textBrush: PdfBrushes.white, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridHeaderCollection get headers { - _headers ??= PdfGridHeaderCollection(this); - return _headers!; - } - - /// Gets the grid style. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Set the grid style - /// grid.style = PdfGridStyle( - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// backgroundBrush: PdfBrushes.blue, - /// textBrush: PdfBrushes.white, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridStyle get style { - _style ??= PdfGridStyle(); - return _style!; - } - - set style(PdfGridStyle value) { - _style = value; - } - - //Implementation - void _initialize() { - _helper.gridSize = PdfSize.empty; - _helper.isComplete = false; - _helper.isDrawn = false; - _helper.isSingleGrid = true; - _helper.isWidthSet = false; - repeatHeader = false; - allowRowBreakingAcrossPages = true; - _gridLocation = PdfRectangle.empty; - _helper.hasColumnSpan = false; - _helper.hasRowSpan = false; - _helper.isChildGrid ??= false; - _helper.isPageWidth = false; - _helper.isRearranged = false; - _helper.initialWidth = 0; - _helper.rowLayoutBoundswidth = 0; - _helper.listOfNavigatePages = []; - _helper.parentCellIndex = 0; - _helper.isBuiltinStyle = false; - _helper.defaultFont = PdfStandardFont(PdfFontFamily.helvetica, 8); - _helper.defaultBorder = PdfBorders(); - } - - /// Draws the [PdfGrid] - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - @override - PdfLayoutResult? draw({ - Rect? bounds, - PdfLayoutFormat? format, - PdfGraphics? graphics, - PdfPage? page, - }) { - final PdfRectangle rectangle = - bounds != null ? PdfRectangle.fromRect(bounds) : PdfRectangle.empty; - _helper.initialWidth = - rectangle.width == 0 - ? page != null - ? page.getClientSize().width - : graphics!.clientSize.width - : rectangle.width; - _helper.isWidthSet = true; - if (page != null) { - final PdfLayoutResult? result = super.draw( - page: page, - bounds: bounds, - format: format, - ); - _helper.isComplete = true; - return result; - } else if (graphics != null) { - _helper.drawInternal(graphics, rectangle); - } - return null; - } - - /// Apply built-in table style to the table - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// PdfGridBuiltInStyleSettings tableStyleOption = - /// PdfGridBuiltInStyleSettings(); - /// tableStyleOption.applyStyleForBandedRows = true; - /// tableStyleOption.applyStyleForHeaderRow = true; - ///Apply built-in table style - /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, - /// settings: tableStyleOption); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void applyBuiltInStyle( - PdfGridBuiltInStyle gridStyle, { - PdfGridBuiltInStyleSettings? settings, - }) { - _intializeBuiltInStyle(gridStyle, settings: settings); - } - - void _intializeBuiltInStyle( - PdfGridBuiltInStyle gridStyle, { - PdfGridBuiltInStyleSettings? settings, - }) { - if (settings != null) { - _headerRow = settings.applyStyleForHeaderRow; - _totalRow = settings.applyStyleForLastRow; - _firstColumn = settings.applyStyleForFirstColumn; - _lastColumn = settings.applyStyleForLastColumn; - _bandedColumn = settings.applyStyleForBandedColumns; - _bandedRow = settings.applyStyleForBandedRows; - } else { - _totalRow = false; - _firstColumn = false; - _lastColumn = false; - _bandedColumn = false; - } - _helper.isBuiltinStyle = true; - _helper.gridBuiltinStyle = gridStyle; - } - - PdfFont? _createBoldFont(PdfFont font) { - _boldFontCache ??= {}; - if (font is PdfStandardFont) { - final PdfStandardFont standardFont = font; - return PdfStandardFont( - standardFont.fontFamily, - font.size, - style: PdfFontStyle.bold, - ); - } else { - if (_boldFontCache!.containsKey(font)) { - return _boldFontCache![font as PdfTrueTypeFont]; - } else { - final PdfTrueTypeFont trueTypeFont = font as PdfTrueTypeFont; - final PdfFont boldStyleFont = PdfTrueTypeFont( - PdfTrueTypeFontHelper.getHelper(trueTypeFont).fontInternal.fontData, - font.size, - style: PdfFontStyle.bold, - ); - _boldFontCache![font] = boldStyleFont as PdfTrueTypeFont; - return boldStyleFont; - } - } - } - - PdfFont? _createRegularFont(PdfFont font) { - _regularFontCache ??= {}; - if (font is PdfStandardFont) { - final PdfStandardFont standardFont = font; - return PdfStandardFont( - standardFont.fontFamily, - font.size, - style: PdfFontStyle.regular, - ); - } else { - if (_regularFontCache!.containsKey(font)) { - return _regularFontCache![font as PdfTrueTypeFont]; - } else { - final PdfTrueTypeFont trueTypeFont = font as PdfTrueTypeFont; - final PdfFont ttfFont = PdfTrueTypeFont( - PdfTrueTypeFontHelper.getHelper(trueTypeFont).fontInternal.fontData, - font.size, - style: PdfFontStyle.regular, - ); - _regularFontCache![font] = ttfFont as PdfTrueTypeFont; - return ttfFont; - } - } - } - - PdfFont? _createItalicFont(PdfFont? font) { - _italicFontCache ??= {}; - if (font is PdfStandardFont) { - final PdfStandardFont standardFont = font; - return PdfStandardFont( - standardFont.fontFamily, - font.size, - style: PdfFontStyle.italic, - ); - } else { - if (_italicFontCache!.containsKey(font)) { - return _italicFontCache![font! as PdfTrueTypeFont]; - } else { - final PdfTrueTypeFont trueTypeFont = font! as PdfTrueTypeFont; - final PdfFont italicStyleFont = PdfTrueTypeFont( - PdfTrueTypeFontHelper.getHelper(trueTypeFont).fontInternal.fontData, - font.size, - style: PdfFontStyle.italic, - ); - _italicFontCache![font as PdfTrueTypeFont] = - italicStyleFont as PdfTrueTypeFont; - return italicStyleFont; - } - } - } - - PdfFont? _changeFontStyle(PdfFont font) { - PdfFont? pdfFont; - if (font.style == PdfFontStyle.regular) { - pdfFont = _createBoldFont(font); - } else if (font.style == PdfFontStyle.bold) { - pdfFont = _createRegularFont(font); - } - return pdfFont; - } - - PdfBrush? _applyBandedColStyle( - bool firstColumn, - PdfColor backColor, - int cellIndex, - ) { - PdfBrush? backBrush; - if (firstColumn) { - if (cellIndex.isEven) { - backBrush = PdfSolidBrush(backColor); - } - } else { - if (cellIndex.isOdd) { - backBrush = PdfSolidBrush(backColor); - } - } - return backBrush; - } - - PdfBrush? _applyBandedRowStyle( - bool headerRow, - PdfColor backColor, - int rowIndex, - ) { - PdfBrush? backBrush; - if (headerRow) { - if (rowIndex.isOdd) { - backBrush = PdfSolidBrush(backColor); - } - } else { - if (rowIndex.isEven) { - backBrush = PdfSolidBrush(backColor); - } - } - return backBrush; - } - - void _applyTableGridLight(PdfColor borderColor) { - final PdfPen borderPen = PdfPen(borderColor); - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - } - } - } - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - } - } - } - - void _applyPlainTable1(PdfColor borderColor, PdfColor backColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfBrush backBrush = PdfSolidBrush(backColor); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = borderPen; - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - } - } else { - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = PdfPen(borderColor); - if (_bandedColumn) { - if (!(_lastColumn && j == row.cells.count)) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - } - } - } - } - } - - void _applyPlainTable2(PdfColor borderColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfPen emptyPen = PdfPen(PdfColor.empty); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.borders.top = borderPen; - if (_bandedColumn) { - cell.style.borders.left = borderPen; - cell.style.borders.right = borderPen; - } - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.bottom = borderPen; - if (_firstColumn && j == 1) { - cell.style.borders.left = emptyPen; - } - if (_lastColumn && j == row.cells.count) { - cell.style.borders.right = emptyPen; - } - } else { - if (_bandedRow) { - cell.style.borders.top = borderPen; - cell.style.borders.bottom = borderPen; - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.left = emptyPen; - } - if (_lastColumn && j == row.cells.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.right = emptyPen; - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - if (i == rows.count) { - cell.style.borders.bottom = borderPen; - } - if (_bandedColumn) { - cell.style.borders.left = borderPen; - cell.style.borders.right = borderPen; - } - if (_bandedRow) { - cell.style.borders.top = borderPen; - cell.style.borders.bottom = borderPen; - } - if (i == rows.count && _totalRow) { - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = borderPen; - if (_bandedColumn) { - cell.style.borders.left = borderPen; - cell.style.borders.right = borderPen; - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.right = emptyPen; - } else if (_bandedColumn) { - cell.style.borders.right = emptyPen; - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.left = emptyPen; - } else if (_bandedColumn) { - cell.style.borders.left = emptyPen; - } - } - } - } - } - - void _applyPlainTable3(PdfColor borderColor, PdfColor backColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfPen whitePen = PdfPen(PdfColor.empty); - final PdfBrush backBrush = PdfSolidBrush(backColor); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - if (i == 1) { - cell.style.borders.bottom = borderPen; - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - } - } else { - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - cell.style.borders.right = borderPen; - } - if (_lastColumn && j == row.cells.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = whitePen; - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - if (_bandedColumn) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - } - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - if (_bandedRow && _bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } - } - if (i == rows.count && _totalRow) { - if (_bandedRow) { - cell.style.borders.all = whitePen; - } - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } - } - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - } - cell.style.borders.right = borderPen; - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - cell.style.backgroundBrush = null; - - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - cell.style.borders.all = whitePen; - } else if (_bandedColumn) { - cell.style.backgroundBrush = null; - } - } - - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } - } - } - - void _applyPlainTable4(PdfColor backColor) { - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen whitePen = PdfPen(PdfColor.empty); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - } - } else { - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.borders.all = whitePen; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - } - } - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.borders.all = whitePen; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - if (cell.value is String) { - final String cellvalue = cell.value as String; - cell.value = cellvalue.toUpperCase(); - } - if (_bandedColumn) { - if (!(_lastColumn && j == row.cells.count)) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - } - } - } - } - } - - void _applyPlainTable5(PdfColor borderColor, PdfColor backColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfPen whitePen = PdfPen(PdfColor.empty); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen backBrushPen = PdfPen(backColor, width: 0.5); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - if (font.style != PdfFontStyle.italic) { - cell.style.font = _createItalicFont(font); - } - if (i == 1) { - cell.style.borders.bottom = borderPen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } else { - cell.style.borders.all = backBrushPen; - } - } - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } else { - cell.style.borders.all = backBrushPen; - } - } - } - if (_firstColumn && j == 1) { - cell.style.borders.all = whitePen; - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - if (font.style != PdfFontStyle.italic) { - cell.style.font = _createItalicFont(font); - } - cell.style.borders.right = borderPen; - } - if (_lastColumn && j == row.cells.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - cell.style.borders.all = whitePen; - cell.style.backgroundBrush = null; - cell.style.borders.left = borderPen; - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - if (_bandedRow && _bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } else { - cell.style.borders.all = backBrushPen; - } - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } else { - cell.style.borders.all = backBrushPen; - } - } - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } else { - cell.style.borders.all = backBrushPen; - } - } - } - if (_totalRow && i == rows.count) { - cell.style.borders.all = PdfPen(PdfColor.empty); - cell.style.backgroundBrush = null; - cell.style.borders.top = borderPen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - if (font.style != PdfFontStyle.italic) { - cell.style.font = _createItalicFont(font); - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - cell.style.borders.all = whitePen; - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - if (font.style != PdfFontStyle.italic) { - cell.style.font = _createItalicFont(font); - } - cell.style.borders.right = borderPen; - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - cell.style.borders.all = whitePen; - cell.style.backgroundBrush = null; - cell.style.borders.left = borderPen; - } - } - - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } - } - } - - void _applyGridTable1Light(PdfColor borderColor, PdfColor headerBottomColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } else { - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (_headerRow && i == 1) { - cell.style.borders.top = PdfPen(headerBottomColor); - } - if (_totalRow) { - if (i == rows.count) { - cell.style.borders.top = PdfPen(headerBottomColor); - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - void _applyGridTable2(PdfColor borderColor, PdfColor backColor) { - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen borderPen = PdfPen(borderColor, width: 0.25); - final PdfPen backColorPen = PdfPen(backColor, width: 0.25); - final PdfPen emptyPen = PdfPen(PdfColor.empty); - final PdfPen headerBorder = PdfPen(borderColor); - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - row.cells[0].style.borders.bottom = headerBorder; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (j == 1) { - cell.style.borders.left = emptyPen; - } else if (j == row.cells.count) { - cell.style.borders.right = emptyPen; - } - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = PdfPen(PdfColor.empty); - if (PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(cell).row!, - ).grid.style.cellSpacing > - 0) { - cell.style.borders.bottom = headerBorder; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (row.cells.count % 2 != 0 && j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - } - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - if (cell.style.backgroundBrush != null) { - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - if (cell.style.backgroundBrush != null) { - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - } - } - - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (j == 1) { - cell.style.borders.left = emptyPen; - } else if (j == row.cells.count) { - cell.style.borders.right = emptyPen; - } - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - cell.style.backgroundBrush ??= _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - } - } else { - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - - if (cell.style.backgroundBrush != null) { - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - } - } - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (row.cells.count % 2 != 0 && j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - } - } - } - if (_totalRow && i == rows.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - cell.style.borders.top = headerBorder; - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.backgroundBrush = null; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush == null) { - cell.style.borders.right = emptyPen; - } - } - } else if (_bandedColumn) { - cell.style.backgroundBrush = null; - } - } - - if (_headerRow && _headers!.count > 0) { - if (i == 1) { - cell.style.borders.top = headerBorder; - } - } - } - } - } - - void _applyGridTable3(PdfColor borderColor, PdfColor backColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen whitePen = PdfPen(PdfColor.empty); - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = whitePen; - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - if (_firstColumn && j == 1) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - } - if (_totalRow && i == rows.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = PdfPen(PdfColor.empty); - cell.style.backgroundBrush = null; - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - if (i == 1 && _headerRow) { - cell.style.borders.top = borderPen; - } - } else { - cell.style.borders.top = borderPen; - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - if (i == 1 && _headerRow) { - cell.style.borders.top = borderPen; - } - } else { - cell.style.borders.top = borderPen; - } - } - } - } - } - - void _applyGridTable4( - PdfColor borderColor, - PdfColor backColor, - PdfColor headerBackColor, - ) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen headerBackColorPen = PdfPen(headerBackColor, width: 0.5); - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = PdfPen(headerBackColor); - cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); - cell.style.backgroundBrush = PdfSolidBrush(headerBackColor); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = PdfPen(borderColor); - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } else if (_bandedColumn) { - cell.style.backgroundBrush = null; - } - } - - if (_headerRow && _headers!.count > 0) { - if (i == 1) { - cell.style.borders.top = headerBackColorPen; - } - } - } - } - } - - void _applyGridTable5Dark( - PdfColor headerBackColor, - PdfColor oddRowBackColor, - PdfColor evenRowBackColor, - ) { - final PdfPen whitePen = PdfPen(PdfColor(255, 255, 255), width: 0.5); - final PdfBrush evenRowBrush = PdfSolidBrush(evenRowBackColor); - final PdfBrush oddRowBrush = PdfSolidBrush(oddRowBackColor); - final PdfBrush headerBrush = PdfSolidBrush(headerBackColor); - final PdfBrush textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - cell.style.backgroundBrush = evenRowBrush; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); - cell.style.backgroundBrush = headerBrush; - cell.style.borders.all = PdfPen(PdfColor.empty, width: 0.5); - if (j == 1) { - cell.style.borders.left = whitePen; - } else if (j == row.cells.count) { - cell.style.borders.right = whitePen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - oddRowBackColor, - j, - ); - - cell.style.backgroundBrush ??= evenRowBrush; - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = oddRowBrush; - } - } - if ((_firstColumn && j == 1) || - (_lastColumn && j == row.cells.count)) { - cell.style.backgroundBrush = headerBrush; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.textBrush = textBrush; - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - cell.style.backgroundBrush = evenRowBrush; - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - oddRowBackColor, - j, - ); - if (cell.style.backgroundBrush == null) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - oddRowBackColor, - i, - ); - - cell.style.backgroundBrush ??= evenRowBrush; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - oddRowBackColor, - j, - ); - - cell.style.backgroundBrush ??= evenRowBrush; - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - oddRowBackColor, - i, - ); - - cell.style.backgroundBrush ??= evenRowBrush; - } - } - if (_totalRow && i == rows.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.textBrush = textBrush; - cell.style.backgroundBrush = PdfSolidBrush(headerBackColor); - cell.style.borders.all = whitePen; - if (j == 1) { - cell.style.borders.left = whitePen; - } else if (j == row.cells.count) { - cell.style.borders.right = whitePen; - } - } - - if ((_firstColumn && j == 1) || (_lastColumn && j == row.cells.count)) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = headerBrush; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.textBrush = textBrush; - } - } - } - } - } - - void _applyGridTable6Colorful( - PdfColor borderColor, - PdfColor backColor, - PdfColor textColor, - ) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen headerBottomPen = PdfPen(borderColor); - final PdfBrush textBrush = PdfSolidBrush(textColor); - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - cell.style.textBrush = textBrush; - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - } - } else { - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - cell.style.textBrush = textBrush; - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - if (_bandedColumn && (!(_lastColumn && j == row.cells.count))) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = PdfPen(borderColor); - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - - if (_headerRow && i == 1) { - cell.style.borders.top = headerBottomPen; - } - } - } - } - - void _applyGridTable7Colorful( - PdfColor borderColor, - PdfColor backColor, - PdfColor textColor, - ) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfBrush textBrush = PdfSolidBrush(textColor); - final PdfPen whitePen = PdfPen(PdfColor.empty, width: 0.5); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.textBrush = textBrush; - cell.style.borders.all = borderPen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = PdfPen(PdfColor(255, 255, 255)); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - } - if (_firstColumn && j == 1) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = borderPen; - cell.style.textBrush = textBrush; - if (_bandedRow && _bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = PdfPen(PdfColor.empty); - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - if (i == 1 && _headerRow) { - cell.style.borders.top = borderPen; - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - } else { - cell.style.borders.top = borderPen; - } - } - - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.all = whitePen; - cell.style.borders.left = borderPen; - if (i == 1 && _headerRow) { - cell.style.borders.top = borderPen; - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - } else { - cell.style.borders.top = borderPen; - } - } - } - } - } - - void _applyListTable1Light(PdfColor borderColor, PdfColor backColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfPen emptyPen = PdfPen(PdfColor.empty); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen backBrushPen = PdfPen(backColor, width: 0.5); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - - if (i == 1) { - cell.style.borders.bottom = PdfPen(borderColor); - } - if (_bandedColumn) { - if (_lastColumn && j == rows.count) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backBrushPen; - } - if (_lastColumn && j == row.cells.count) { - cell.style.borders.all = emptyPen; - cell.style.backgroundBrush = null; - } - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backBrushPen; - } - } - - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - cell.style.borders.all = backBrushPen; - } - } - - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - if (_bandedRow && i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backBrushPen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backBrushPen; - } - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backBrushPen; - } - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } else { - cell.style.borders.top = borderPen; - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (_bandedColumn) { - if (!(_lastColumn && j == row.cells.count)) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backBrushPen; - } - } - - cell.style.borders.top = PdfPen(borderColor); - } - - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } - } - } - - void _applyListTable2(PdfColor borderColor, PdfColor backColor) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen backColorPen = PdfPen(backColor, width: 0.5); - final PdfPen emptyPen = PdfPen(PdfColor.empty, width: 0.5); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.borders.bottom = borderPen; - cell.style.borders.top = borderPen; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - } - if (cell.style.backgroundBrush != null) { - cell.style.borders.right = backColorPen; - cell.style.borders.left = backColorPen; - } - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.right = backColorPen; - cell.style.borders.left = backColorPen; - } - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.borders.left = backColorPen; - cell.style.borders.right = backColorPen; - cell.style.backgroundBrush = backBrush; - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - cell.style.borders.left = emptyPen; - cell.style.borders.right = emptyPen; - if (_bandedRow && i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - if (cell.style.backgroundBrush != null) { - cell.style.borders.left = backColorPen; - cell.style.borders.right = backColorPen; - } - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.borders.bottom = borderPen; - cell.style.borders.top = borderPen; - if (_bandedRow && _bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.right = backColorPen; - cell.style.borders.left = backColorPen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.right = backColorPen; - cell.style.borders.left = backColorPen; - } - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.left = backColorPen; - cell.style.borders.right = backColorPen; - } - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - cell.style.borders.top = borderPen; - cell.style.borders.bottom = borderPen; - - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - - if (_bandedColumn) { - if (!(j == row.cells.count && _lastColumn)) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (cell.style.backgroundBrush != null) { - cell.style.borders.right = backColorPen; - cell.style.borders.left = backColorPen; - } - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.left = emptyPen; - cell.style.borders.right = emptyPen; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.right = backColorPen; - } - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - void _applyListTable3(PdfColor backColor) { - final PdfPen backColorPen = PdfPen(backColor, width: 0.5); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen emptyPen = PdfPen(PdfColor.empty, width: 0.5); - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.borders.top = backColorPen; - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = backColorPen; - cell.style.backgroundBrush = backBrush; - cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); - } else { - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_bandedColumn) { - cell.style.borders.left = backColorPen; - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - if (headers.count == 0 && i == 1) { - cell.style.borders.top = backColorPen; - } - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - if (i == rows.count) { - cell.style.borders.bottom = backColorPen; - } - if (_bandedColumn) { - cell.style.borders.left = backColorPen; - } - if (_bandedRow) { - cell.style.borders.top = backColorPen; - } - if (_totalRow && i == rows.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = PdfPen(backColor); - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - void _applyListTable4( - PdfColor borderColor, - PdfColor headerBackColor, - PdfColor bandRowColor, - ) { - final PdfPen borderColorPen = PdfPen(borderColor, width: 0.5); - final PdfBrush headerBrush = PdfSolidBrush(headerBackColor); - final PdfBrush bandRowBrush = PdfSolidBrush(bandRowColor); - final PdfPen whitePen = PdfPen(PdfColor.empty, width: 0.5); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - cell.style.borders.top = borderColorPen; - if (j == 1) { - cell.style.borders.left = borderColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = borderColorPen; - } - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.all = PdfPen(headerBackColor, width: 0.5); - cell.style.backgroundBrush = headerBrush; - cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - bandRowColor, - j, - ); - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = bandRowBrush; - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - - if (_bandedRow && i % 2 != 0) { - cell.style.backgroundBrush = bandRowBrush; - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = whitePen; - cell.style.borders.top = borderColorPen; - if (j == 1) { - cell.style.borders.left = borderColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = borderColorPen; - } - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - bandRowColor, - j, - ); - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - bandRowColor, - i, - ); - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - bandRowColor, - j, - ); - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - bandRowColor, - i, - ); - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = PdfPen(borderColor); - if (_bandedColumn) { - if (!(_lastColumn && j == rows.count)) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - bandRowColor, - j, - ); - } - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - bandRowColor, - i, - ); - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - - if (i == rows.count) { - cell.style.borders.bottom = borderColorPen; - } - } - } - } - - void _applyListTable5Dark(PdfColor backColor) { - final PdfBrush backColorBrush = PdfSolidBrush(backColor); - final PdfPen whitePen = PdfPen(PdfColor(255, 255, 255), width: 0.5); - final PdfBrush whiteBrush = PdfSolidBrush(PdfColor(255, 255, 255)); - final PdfPen emptyPen = PdfPen(PdfColor.empty); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.textBrush = whiteBrush; - cell.style.backgroundBrush = backColorBrush; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.backgroundBrush = backColorBrush; - cell.style.textBrush = whiteBrush; - cell.style.borders.bottom = PdfPen( - PdfColor(255, 255, 255), - width: 2, - ); - if (_bandedColumn) { - if (j > 1) { - cell.style.borders.left = whitePen; - } - } - } else { - if (_firstColumn) { - if (j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } else if (j == 2) { - cell.style.borders.left = whitePen; - } - } - if (_bandedColumn) { - if (j > 1) { - cell.style.borders.left = whitePen; - } - } - if (_bandedRow) { - cell.style.borders.top = whitePen; - } - if (_lastColumn && j == row.cells.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.left = whitePen; - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.textBrush = whiteBrush; - cell.style.backgroundBrush = backColorBrush; - if (_firstColumn) { - if (!(_totalRow && i == rows.count)) { - if (j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } else if (j == 2) { - cell.style.borders.left = whitePen; - } - } - } - if (_bandedColumn) { - if (j > 1) { - cell.style.borders.left = whitePen; - } - } - if (_bandedRow) { - cell.style.borders.top = whitePen; - } - if (_totalRow && i == rows.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = whitePen; - if (_headerRow) { - if (_firstColumn && j == 1) { - cell.style.borders.top = emptyPen; - } - if (_lastColumn && j == row.cells.count) { - cell.style.borders.top = emptyPen; - } - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.left = whitePen; - } - } - } - } - } - - void _applyListTable6Colorful( - PdfColor borderColor, - PdfColor backColor, - PdfColor textColor, - ) { - final PdfBrush backColorBrush = PdfSolidBrush(backColor); - final PdfPen borderColorPen = PdfPen(borderColor, width: 0.5); - final PdfPen backColorPen = PdfPen(backColor, width: 0.5); - final PdfPen emptyPen = PdfPen(PdfColor.empty, width: 0.5); - final PdfBrush textBrush = PdfSolidBrush(textColor); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.borders.top = borderColorPen; - cell.style.textBrush = textBrush; - if (_headerRow) { - if (_bandedColumn) { - if (!(_lastColumn && j == row.cells.count)) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - } - if (cell.style.backgroundBrush != null) { - cell.style.borders.left = backColorPen; - cell.style.borders.right = backColorPen; - } - } - - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.bottom = borderColorPen; - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - if (i == 1 && _headerRow) { - cell.style.borders.top = borderColorPen; - } - } - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backColorBrush; - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - if (i == 1) { - cell.style.borders.top = borderColorPen; - } - } - } - if (_firstColumn && j == 1) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - cell.style.borders.top = borderColorPen; - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backColorBrush; - } - } - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.left = emptyPen; - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.textBrush = textBrush; - cell.style.borders.all = emptyPen; - if (headers.count == 0 && i == 1) { - cell.style.borders.top = borderColorPen; - } - if (i == rows.count) { - cell.style.borders.bottom = borderColorPen; - } - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - } - if (i == 1 && _headerRow) { - cell.style.borders.top = borderColorPen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.left = backColorPen; - cell.style.borders.right = backColorPen; - if (i == 1 && _headerRow) { - cell.style.borders.top = borderColorPen; - } - } - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (j == 1) { - cell.style.borders.left = backColorPen; - } else if (j == row.cells.count) { - cell.style.borders.right = backColorPen; - } - if (i == 1 && _headerRow) { - cell.style.borders.top = borderColorPen; - } - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - } - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.left = emptyPen; - cell.style.borders.right = emptyPen; - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.right = backColorPen; - } - } - - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - if (i == 1 && _headerRow) { - cell.style.borders.top = borderColorPen; - } - } else if (_bandedColumn) { - cell.style.backgroundBrush = null; - } - } - if (_totalRow && i == rows.count) { - cell.style.backgroundBrush = null; - cell.style.borders.left = emptyPen; - cell.style.borders.right = emptyPen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _changeFontStyle(font); - cell.style.borders.top = PdfPen(borderColor); - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - } - if (cell.style.backgroundBrush != null) { - cell.style.borders.left = backColorPen; - cell.style.borders.right = backColorPen; - } - } - } - } - } - } - - void _applyListTable7Colorful( - PdfColor borderColor, - PdfColor backColor, - PdfColor textColor, - ) { - final PdfPen borderPen = PdfPen(borderColor, width: 0.5); - final PdfPen emptyPen = PdfPen(PdfColor.empty); - final PdfBrush backBrush = PdfSolidBrush(backColor); - final PdfPen backColorPen = PdfPen(backColor, width: 0.5); - final PdfBrush textBrush = PdfSolidBrush(textColor); - - if (headers.count > 0) { - for (int i = 1; i <= headers.count; i++) { - final PdfGridRow row = headers[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.textBrush = textBrush; - if (_headerRow) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - if (font.style != PdfFontStyle.italic) { - cell.style.font = _createItalicFont(font); - } - if (i == 1) { - cell.style.borders.bottom = borderPen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backColorPen; - } - } - if (_bandedRow) { - if (i % 2 != 0) { - cell.style.backgroundBrush = backBrush; - cell.style.borders.all = backColorPen; - } - } - if (_firstColumn && j == 1) { - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - cell.style.borders.right = borderPen; - } - if (_lastColumn && j == row.cells.count) { - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - cell.style.borders.all = emptyPen; - cell.style.borders.left = borderPen; - } - - if (_firstColumn && j == 2) { - cell.style.borders.left = borderPen; - } - } - } - } - } - - for (int i = 1; i <= rows.count; i++) { - final PdfGridRow row = rows[i - 1]; - for (int j = 1; j <= row.cells.count; j++) { - final PdfGridCell cell = row.cells[j - 1]; - cell.style.borders.all = emptyPen; - cell.style.textBrush = textBrush; - - if (_bandedColumn && _bandedRow) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - - cell.style.backgroundBrush ??= _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backColorPen; - } - } else { - if (_bandedColumn) { - cell.style.backgroundBrush = _applyBandedColStyle( - _firstColumn, - backColor, - j, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backColorPen; - } - } - if (_bandedRow) { - cell.style.backgroundBrush = _applyBandedRowStyle( - _headerRow, - backColor, - i, - ); - if (cell.style.backgroundBrush != null) { - cell.style.borders.all = backColorPen; - } - } - } - if (_firstColumn && j == 1) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - cell.style.borders.all = emptyPen; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - cell.style.borders.right = borderPen; - } - } - - if (_firstColumn && j == 2) { - cell.style.borders.all = emptyPen; - cell.style.borders.left = borderPen; - } - - if (_totalRow && i == rows.count) { - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - if (font.style != PdfFontStyle.italic) { - cell.style.font = _createItalicFont(font); - } - cell.style.borders.all = emptyPen; - cell.style.borders.top = borderPen; - cell.style.backgroundBrush = null; - } - if (_lastColumn && j == row.cells.count) { - if (!(_totalRow && i == rows.count)) { - cell.style.backgroundBrush = null; - final PdfFont font = - cell.style.font ?? - row.style.font ?? - PdfGridRowHelper.getHelper(row).grid.style.font ?? - _helper.defaultFont; - cell.style.font = _createItalicFont(font); - cell.style.borders.all = emptyPen; - cell.style.borders.left = borderPen; - } - } - if (_headerRow && i == 1) { - cell.style.borders.top = borderPen; - } - } - } - } -} - -/// [PdfGrid] helper -class PdfGridHelper { - /// internal constructor - PdfGridHelper(this.base); - - /// internal field - PdfGrid base; - - /// internal method - static PdfGridHelper getHelper(PdfGrid base) { - return base._helper; - } - - /// internal method - late PdfBorders defaultBorder; - - /// internal method - late bool isPageWidth; - - /// internal method - bool? isChildGrid; - - /// internal method - late bool hasRowSpan; - - /// internal method - late bool hasColumnSpan; - - /// internal method - late bool isSingleGrid; - - /// internal method - late bool isComplete; - - /// Gets a value indicating whether the start cell layout event should be raised. - bool get raiseBeginCellLayout => base.beginCellLayout != null; - - /// internal method/// Gets a value indicating whether the end cell layout event should be raised. - bool get raiseEndCellLayout => base.endCellLayout != null; - - /// internal method - late bool isBuiltinStyle; - - /// internal method - late bool isRearranged; - - /// internal method - late bool isDrawn; - - /// internal method - late bool isWidthSet; - - /// internal method - late PdfSize gridSize; - - /// internal method - late double rowLayoutBoundswidth; - - /// internal method - late double initialWidth; - - /// internal method - late PdfFont defaultFont; - - /// internal method - PdfLayoutFormat? layoutFormat; - - /// internal method - late int parentCellIndex; - - /// internal method - late List listOfNavigatePages; - - /// internal method - PdfGridBuiltInStyle? gridBuiltinStyle; - - /// internal method - PdfGridCell? parentCell; - - /// internal method - PdfSize get size { - if (gridSize == PdfSize.empty) { - gridSize = _measure(); - } - return gridSize; - } - - /// internal method - PdfSize _measure() { - double height = 0; - final double width = - PdfGridColumnCollectionHelper.getHelper(base.columns).columnWidth; - for (int i = 0; i < base.headers.count; i++) { - height += base.headers[i].height; - } - for (int i = 0; i < base.rows.count; i++) { - height += base.rows[i].height; - } - return PdfSize(width, height); - } - - /// internal method - void setSpan() { - int colSpan, rowSpan = 1; - int currentCellIndex, currentRowIndex = 0; - int maxSpan = 0; - for (int i = 0; i < base.headers.count; i++) { - final PdfGridRow row = base.headers[i]; - maxSpan = 0; - for (int j = 0; j < row.cells.count; j++) { - final PdfGridCell cell = row.cells[j]; - maxSpan = max(maxSpan, cell.rowSpan); - if (!PdfGridCellHelper.getHelper(cell).isCellMergeContinue && - !PdfGridCellHelper.getHelper(cell).isRowMergeContinue && - (cell.columnSpan > 1 || cell.rowSpan > 1)) { - if (cell.columnSpan + j > row.cells.count) { - throw ArgumentError.value( - 'Invalid span specified at row $j column $i', - ); - } - if (cell.rowSpan + i > base.headers.count) { - throw ArgumentError.value( - 'Invalid span specified at row $j column $i', - ); - } - if (cell.columnSpan > 1 && cell.rowSpan > 1) { - colSpan = cell.columnSpan; - rowSpan = cell.rowSpan; - currentCellIndex = j; - currentRowIndex = i; - while (colSpan > 1) { - currentCellIndex++; - PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) - .isCellMergeContinue = true; - PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) - .isRowMergeContinue = true; - row.cells[currentCellIndex].rowSpan = rowSpan; - colSpan--; - } - currentCellIndex = j; - colSpan = cell.columnSpan; - while (rowSpan > 1) { - currentRowIndex++; - PdfGridCellHelper.getHelper( - base.headers[currentRowIndex].cells[j], - ).isRowMergeContinue = - true; - PdfGridCellHelper.getHelper( - base.headers[currentRowIndex].cells[currentCellIndex], - ).isRowMergeContinue = - true; - rowSpan--; - while (colSpan > 1) { - currentCellIndex++; - PdfGridCellHelper.getHelper( - base.headers[currentRowIndex].cells[currentCellIndex], - ).isCellMergeContinue = - true; - PdfGridCellHelper.getHelper( - base.headers[currentRowIndex].cells[currentCellIndex], - ).isRowMergeContinue = - true; - colSpan--; - } - colSpan = cell.columnSpan; - currentCellIndex = j; - } - } else if (cell.columnSpan > 1 && cell.rowSpan == 1) { - colSpan = cell.columnSpan; - currentCellIndex = j; - while (colSpan > 1) { - currentCellIndex++; - PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) - .isCellMergeContinue = true; - colSpan--; - } - } else if (cell.columnSpan == 1 && cell.rowSpan > 1) { - rowSpan = cell.rowSpan; - currentRowIndex = i; - while (rowSpan > 1) { - currentRowIndex++; - PdfGridCellHelper.getHelper( - base.headers[currentRowIndex].cells[j], - ).isRowMergeContinue = - true; - rowSpan--; - } - } - } - } - PdfGridRowHelper.getHelper(row).maximumRowSpan = maxSpan; - } - colSpan = rowSpan = 1; - currentCellIndex = currentRowIndex = 0; - if (hasColumnSpan || hasRowSpan) { - for (int i = 0; i < base.rows.count; i++) { - final PdfGridRow row = base.rows[i]; - maxSpan = 0; - for (int j = 0; j < row.cells.count; j++) { - final PdfGridCell cell = row.cells[j]; - maxSpan = max(maxSpan, cell.rowSpan); - if (!PdfGridCellHelper.getHelper(cell).isCellMergeContinue && - !PdfGridCellHelper.getHelper(cell).isRowMergeContinue && - (cell.columnSpan > 1 || cell.rowSpan > 1)) { - if (cell.columnSpan + j > row.cells.count) { - throw ArgumentError.value( - 'Invalid span specified at row $j column $i', - ); - } - if (cell.rowSpan + i > base.rows.count) { - throw ArgumentError.value( - 'Invalid span specified at row $j column $i', - ); - } - if (cell.columnSpan > 1 && cell.rowSpan > 1) { - colSpan = cell.columnSpan; - rowSpan = cell.rowSpan; - currentCellIndex = j; - currentRowIndex = i; - while (colSpan > 1) { - currentCellIndex++; - PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) - .isCellMergeContinue = true; - PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) - .isRowMergeContinue = true; - colSpan--; - } - currentCellIndex = j; - colSpan = cell.columnSpan; - while (rowSpan > 1) { - currentRowIndex++; - PdfGridCellHelper.getHelper(base.rows[currentRowIndex].cells[j]) - .isRowMergeContinue = true; - PdfGridCellHelper.getHelper( - base.rows[currentRowIndex].cells[currentCellIndex], - ).isRowMergeContinue = - true; - rowSpan--; - while (colSpan > 1) { - currentCellIndex++; - PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper( - base.rows[currentRowIndex], - ).cells![currentCellIndex], - ).isCellMergeContinue = - true; - PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper( - base.rows[currentRowIndex], - ).cells![currentCellIndex], - ).isRowMergeContinue = - true; - colSpan--; - } - colSpan = cell.columnSpan; - currentCellIndex = j; - } - } else if (cell.columnSpan > 1 && cell.rowSpan == 1) { - colSpan = cell.columnSpan; - currentCellIndex = j; - while (colSpan > 1) { - currentCellIndex++; - PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) - .isCellMergeContinue = true; - colSpan--; - } - } else if (cell.columnSpan == 1 && cell.rowSpan > 1) { - rowSpan = cell.rowSpan; - currentRowIndex = i; - while (rowSpan > 1) { - currentRowIndex++; - PdfGridCellHelper.getHelper(base.rows[currentRowIndex].cells[j]) - .isRowMergeContinue = true; - rowSpan--; - } - } - } - } - PdfGridRowHelper.getHelper(row).maximumRowSpan = maxSpan; - } - } - } - - /// internal method - void measureColumnsWidth([PdfRectangle? bounds]) { - if (bounds == null) { - List widths = List.filled(base.columns.count, 0); - double cellWidth = 0; - if (base.headers.count > 0) { - for (int i = 0; i < base.headers[0].cells.count; i++) { - for (int j = 0; j < base.headers.count; j++) { - cellWidth = max( - cellWidth, - initialWidth > 0.0 - ? min(initialWidth, base.headers[j].cells[i].width) - : base.headers[j].cells[i].width, - ); - } - widths[i] = cellWidth; - } - } - cellWidth = 0; - for (int i = 0; i < base.columns.count; i++) { - for (int j = 0; j < base.rows.count; j++) { - final bool isGrid = - base.rows[j].cells[i].value != null && - base.rows[j].cells[i].value is PdfGrid; - if ((base.rows[j].cells[i].columnSpan == 1 && - !PdfGridCellHelper.getHelper( - base.rows[j].cells[i], - ).isCellMergeContinue) || - isGrid) { - if (isGrid && - !PdfGridRowHelper.getHelper( - base.rows[j], - ).grid.style.allowHorizontalOverflow && - initialWidth != 0) { - PdfGridHelper.getHelper(base.rows[j].cells[i].value as PdfGrid) - .initialWidth = initialWidth - - (PdfGridRowHelper.getHelper( - base.rows[j], - ).grid.style.cellPadding.right + - PdfGridRowHelper.getHelper( - base.rows[j], - ).grid.style.cellPadding.left + - base.rows[j].cells[i].style.borders.left.width / 2 + - base._gridLocation.x); - } - cellWidth = max( - widths[i]!, - max( - cellWidth, - initialWidth > 0.0 - ? min(initialWidth, base.rows[j].cells[i].width) - : base.rows[j].cells[i].width, - ), - ); - cellWidth = max(base.columns[i].width, cellWidth); - } - } - if (base.rows.count != 0) { - widths[i] = cellWidth; - } - cellWidth = 0; - } - for (int i = 0; i < base.rows.count; i++) { - for (int j = 0; j < base.columns.count; j++) { - if (base.rows[i].cells[j].columnSpan > 1) { - double totalWidth = widths[j]!; - for (int k = 1; k < base.rows[i].cells[j].columnSpan; k++) { - totalWidth = totalWidth + widths[j + k]!; - } - if (base.rows[i].cells[j].width > totalWidth) { - double extendedWidth = base.rows[i].cells[j].width - totalWidth; - extendedWidth = extendedWidth / base.rows[i].cells[j].columnSpan; - for (int k = j; k < j + base.rows[i].cells[j].columnSpan; k++) { - widths[k] = widths[k]! + extendedWidth; - } - } - } - } - } - if (isChildGrid! && initialWidth != 0) { - widths = PdfGridColumnCollectionHelper.getHelper( - base.columns, - ).getDefaultWidths(initialWidth); - } - for (int i = 0; i < base.columns.count; i++) { - if (base.columns[i].width < 0 || - (base.columns[i].width > 0 && - !PdfGridColumnHelper.getHelper( - base.columns[i], - ).isCustomWidth)) { - PdfGridColumnHelper.getHelper(base.columns[i]).width = widths[i]!; - } - } - } else { - List widths = PdfGridColumnCollectionHelper.getHelper( - base.columns, - ).getDefaultWidths(bounds.width - bounds.x); - for (int i = 0; i < base.columns.count; i++) { - if (base.columns[i].width < 0) { - PdfGridColumnHelper.getHelper(base.columns[i]).width = widths[i]!; - } else if (base.columns[i].width > 0 && - !PdfGridColumnHelper.getHelper(base.columns[i]).isCustomWidth && - widths[i]! > 0 && - isComplete) { - PdfGridColumnHelper.getHelper(base.columns[i]).width = widths[i]!; - } - } - if (parentCell != null && - (!base.style.allowHorizontalOverflow) && - (!PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(parentCell!).row!, - ).grid.style.allowHorizontalOverflow)) { - double padding = 0; - double columnWidth = 0; - int columnCount = base.columns.count; - if (parentCell!.style.cellPadding != null) { - padding += - parentCell!.style.cellPadding!.left + - parentCell!.style.cellPadding!.right; - } else { - padding += - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(parentCell!).row!, - ).grid.style.cellPadding.left + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(parentCell!).row!, - ).grid.style.cellPadding.right; - } - for (int i = 0; i < parentCell!.columnSpan; i++) { - columnWidth += - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(parentCell!).row!, - ).grid.columns[parentCellIndex + i].width; - } - for (int i = 0; i < base.columns.count; i++) { - if (base.columns[i].width > 0 && - PdfGridColumnHelper.getHelper(base.columns[i]).isCustomWidth) { - columnWidth -= base.columns[i].width; - columnCount--; - } - } - if (columnWidth > padding) { - final double childGridColumnWidth = - (columnWidth - padding) / columnCount; - if (parentCell != null && - parentCell!.stringFormat.alignment != PdfTextAlignment.right) { - for (int j = 0; j < base.columns.count; j++) { - if (!PdfGridColumnHelper.getHelper( - base.columns[j], - ).isCustomWidth) { - PdfGridColumnHelper.getHelper(base.columns[j]).width = - childGridColumnWidth; - } - } - } - } - } - if (parentCell != null && - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(parentCell!).row!, - ).getWidth() > - 0) { - if (isChildGrid! && - size.width > - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(parentCell!).row!, - ).getWidth()) { - widths = PdfGridColumnCollectionHelper.getHelper( - base.columns, - ).getDefaultWidths(bounds.width); - for (int i = 0; i < base.columns.count; i++) { - base.columns[i].width = widths[i]!; - } - } - } - } - } - - /// internal method - void onBeginCellLayout(PdfGridBeginCellLayoutArgs args) { - if (raiseBeginCellLayout) { - base.beginCellLayout!(base, args); - } - } - - /// internal method - void onEndCellLayout(PdfGridEndCellLayoutArgs args) { - if (raiseEndCellLayout) { - base.endCellLayout!(base, args); - } - } - - /// internal method - void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { - setSpan(); - final PdfGridLayouter layouter = PdfGridLayouter(base); - layouter.layoutGrid(graphics, bounds); - isComplete = true; - } - - /// internal method - PdfLayoutResult? layout(PdfLayoutParams param) { - if (param.bounds!.width < 0) { - ArgumentError.value('width', 'width', 'out of range'); - } - if (base.rows.count != 0) { - final PdfBorders borders = base.rows[0].cells[0].style.borders; - if (borders.left.width != 1) { - final double x = borders.left.width / 2; - final double y = borders.top.width / 2; - if (param.bounds!.x == defaultBorder.right.width / 2 && - param.bounds!.y == defaultBorder.right.width / 2) { - param.bounds = PdfRectangle(x, y, size.width, size.height); - } - } - } - setSpan(); - layoutFormat = param.format; - base._gridLocation = param.bounds!; - return PdfGridLayouter(base).layoutInternal(param); - } - - /// internal method - void applyBuiltinStyles(PdfGridBuiltInStyle? gridStyle) { - switch (gridStyle) { - case PdfGridBuiltInStyle.tableGrid: - base._applyTableGridLight(PdfColor(0, 0, 0)); - break; - - case PdfGridBuiltInStyle.tableGridLight: - base._applyTableGridLight(PdfColor(191, 191, 191)); - break; - - case PdfGridBuiltInStyle.plainTable1: - base._applyPlainTable1( - PdfColor(191, 191, 191), - PdfColor(242, 242, 242), - ); - break; - - case PdfGridBuiltInStyle.plainTable2: - base._applyPlainTable2(PdfColor(127, 127, 127)); - break; - - case PdfGridBuiltInStyle.plainTable3: - base._applyPlainTable3( - PdfColor(127, 127, 127), - PdfColor(242, 242, 242), - ); - break; - - case PdfGridBuiltInStyle.plainTable4: - base._applyPlainTable4(PdfColor(242, 242, 242)); - break; - - case PdfGridBuiltInStyle.plainTable5: - base._applyPlainTable5( - PdfColor(127, 127, 127), - PdfColor(242, 242, 242), - ); - break; - case PdfGridBuiltInStyle.gridTable1Light: - base._applyGridTable1Light( - PdfColor(153, 153, 153), - PdfColor(102, 102, 102), - ); - break; - - case PdfGridBuiltInStyle.gridTable1LightAccent1: - base._applyGridTable1Light( - PdfColor(189, 214, 238), - PdfColor(156, 194, 229), - ); - break; - - case PdfGridBuiltInStyle.gridTable1LightAccent2: - base._applyGridTable1Light( - PdfColor(247, 202, 172), - PdfColor(244, 176, 131), - ); - break; - - case PdfGridBuiltInStyle.gridTable1LightAccent3: - base._applyGridTable1Light( - PdfColor(219, 219, 219), - PdfColor(201, 201, 201), - ); - break; - - case PdfGridBuiltInStyle.gridTable1LightAccent4: - base._applyGridTable1Light( - PdfColor(255, 229, 153), - PdfColor(255, 217, 102), - ); - break; - - case PdfGridBuiltInStyle.gridTable1LightAccent5: - base._applyGridTable1Light( - PdfColor(180, 198, 231), - PdfColor(142, 170, 219), - ); - break; - - case PdfGridBuiltInStyle.gridTable1LightAccent6: - base._applyGridTable1Light( - PdfColor(192, 224, 179), - PdfColor(168, 208, 141), - ); - break; - - case PdfGridBuiltInStyle.gridTable2: - base._applyGridTable2(PdfColor(102, 102, 102), PdfColor(204, 204, 204)); - break; - - case PdfGridBuiltInStyle.gridTable2Accent1: - base._applyGridTable2(PdfColor(156, 194, 229), PdfColor(222, 234, 246)); - break; - - case PdfGridBuiltInStyle.gridTable2Accent2: - base._applyGridTable2(PdfColor(244, 176, 131), PdfColor(251, 228, 213)); - break; - - case PdfGridBuiltInStyle.gridTable2Accent3: - base._applyGridTable2(PdfColor(201, 201, 201), PdfColor(237, 237, 237)); - break; - - case PdfGridBuiltInStyle.gridTable2Accent4: - base._applyGridTable2(PdfColor(255, 217, 102), PdfColor(255, 242, 204)); - break; - - case PdfGridBuiltInStyle.gridTable2Accent5: - base._applyGridTable2(PdfColor(142, 170, 219), PdfColor(217, 226, 243)); - break; - - case PdfGridBuiltInStyle.gridTable2Accent6: - base._applyGridTable2(PdfColor(168, 208, 141), PdfColor(226, 239, 217)); - break; - - case PdfGridBuiltInStyle.gridTable3: - base._applyGridTable3(PdfColor(102, 102, 102), PdfColor(204, 204, 204)); - break; - - case PdfGridBuiltInStyle.gridTable3Accent1: - base._applyGridTable3(PdfColor(156, 194, 229), PdfColor(222, 234, 246)); - break; - - case PdfGridBuiltInStyle.gridTable3Accent2: - base._applyGridTable3(PdfColor(244, 176, 131), PdfColor(251, 228, 213)); - break; - - case PdfGridBuiltInStyle.gridTable3Accent3: - base._applyGridTable3(PdfColor(201, 201, 201), PdfColor(237, 237, 237)); - break; - - case PdfGridBuiltInStyle.gridTable3Accent4: - base._applyGridTable3(PdfColor(255, 217, 102), PdfColor(255, 242, 204)); - break; - - case PdfGridBuiltInStyle.gridTable3Accent5: - base._applyGridTable3(PdfColor(142, 170, 219), PdfColor(217, 226, 243)); - break; - - case PdfGridBuiltInStyle.gridTable3Accent6: - base._applyGridTable3(PdfColor(168, 208, 141), PdfColor(226, 239, 217)); - break; - - case PdfGridBuiltInStyle.gridTable4: - base._applyGridTable4( - PdfColor(102, 102, 102), - PdfColor(204, 204, 204), - PdfColor(0, 0, 0), - ); - break; - - case PdfGridBuiltInStyle.gridTable4Accent1: - base._applyGridTable4( - PdfColor(156, 194, 229), - PdfColor(222, 234, 246), - PdfColor(91, 155, 213), - ); - break; - - case PdfGridBuiltInStyle.gridTable4Accent2: - base._applyGridTable4( - PdfColor(244, 176, 131), - PdfColor(251, 228, 213), - PdfColor(237, 125, 49), - ); - break; - - case PdfGridBuiltInStyle.gridTable4Accent3: - base._applyGridTable4( - PdfColor(201, 201, 201), - PdfColor(237, 237, 237), - PdfColor(165, 165, 165), - ); - break; - - case PdfGridBuiltInStyle.gridTable4Accent4: - base._applyGridTable4( - PdfColor(255, 217, 102), - PdfColor(255, 242, 204), - PdfColor(255, 192, 0), - ); - break; - - case PdfGridBuiltInStyle.gridTable4Accent5: - base._applyGridTable4( - PdfColor(142, 170, 219), - PdfColor(217, 226, 243), - PdfColor(68, 114, 196), - ); - break; - - case PdfGridBuiltInStyle.gridTable4Accent6: - base._applyGridTable4( - PdfColor(168, 208, 141), - PdfColor(226, 239, 217), - PdfColor(112, 173, 71), - ); - break; - - case PdfGridBuiltInStyle.gridTable5Dark: - base._applyGridTable5Dark( - PdfColor(0, 0, 0), - PdfColor(153, 153, 153), - PdfColor(204, 204, 204), - ); - break; - - case PdfGridBuiltInStyle.gridTable5DarkAccent1: - base._applyGridTable5Dark( - PdfColor(91, 155, 213), - PdfColor(189, 214, 238), - PdfColor(222, 234, 246), - ); - break; - - case PdfGridBuiltInStyle.gridTable5DarkAccent2: - base._applyGridTable5Dark( - PdfColor(237, 125, 49), - PdfColor(247, 202, 172), - PdfColor(251, 228, 213), - ); - break; - - case PdfGridBuiltInStyle.gridTable5DarkAccent3: - base._applyGridTable5Dark( - PdfColor(165, 165, 165), - PdfColor(219, 219, 219), - PdfColor(237, 237, 237), - ); - break; - - case PdfGridBuiltInStyle.gridTable5DarkAccent4: - base._applyGridTable5Dark( - PdfColor(255, 192, 0), - PdfColor(255, 229, 153), - PdfColor(255, 242, 204), - ); - break; - - case PdfGridBuiltInStyle.gridTable5DarkAccent5: - base._applyGridTable5Dark( - PdfColor(68, 114, 196), - PdfColor(180, 198, 231), - PdfColor(217, 226, 243), - ); - break; - - case PdfGridBuiltInStyle.gridTable5DarkAccent6: - base._applyGridTable5Dark( - PdfColor(112, 171, 71), - PdfColor(197, 224, 179), - PdfColor(226, 239, 217), - ); - break; - - case PdfGridBuiltInStyle.gridTable6Colorful: - base._applyGridTable6Colorful( - PdfColor(102, 102, 102), - PdfColor(204, 204, 204), - PdfColor(0, 0, 0), - ); - break; - - case PdfGridBuiltInStyle.gridTable6ColorfulAccent1: - base._applyGridTable6Colorful( - PdfColor(156, 194, 229), - PdfColor(222, 234, 246), - PdfColor(46, 116, 181), - ); - break; - - case PdfGridBuiltInStyle.gridTable6ColorfulAccent2: - base._applyGridTable6Colorful( - PdfColor(244, 176, 131), - PdfColor(251, 228, 213), - PdfColor(196, 89, 17), - ); - break; - - case PdfGridBuiltInStyle.gridTable6ColorfulAccent3: - base._applyGridTable6Colorful( - PdfColor(201, 201, 201), - PdfColor(237, 237, 237), - PdfColor(123, 123, 123), - ); - break; - - case PdfGridBuiltInStyle.gridTable6ColorfulAccent4: - base._applyGridTable6Colorful( - PdfColor(255, 217, 102), - PdfColor(255, 242, 204), - PdfColor(191, 143, 0), - ); - break; - - case PdfGridBuiltInStyle.gridTable6ColorfulAccent5: - base._applyGridTable6Colorful( - PdfColor(142, 170, 219), - PdfColor(217, 226, 243), - PdfColor(47, 84, 150), - ); - break; - - case PdfGridBuiltInStyle.gridTable6ColorfulAccent6: - base._applyGridTable6Colorful( - PdfColor(168, 208, 141), - PdfColor(226, 239, 217), - PdfColor(83, 129, 53), - ); - break; - - case PdfGridBuiltInStyle.gridTable7Colorful: - base._applyGridTable7Colorful( - PdfColor(102, 102, 102), - PdfColor(204, 204, 204), - PdfColor(0, 0, 0), - ); - break; - - case PdfGridBuiltInStyle.gridTable7ColorfulAccent1: - base._applyGridTable7Colorful( - PdfColor(156, 194, 229), - PdfColor(222, 234, 246), - PdfColor(46, 116, 181), - ); - break; - - case PdfGridBuiltInStyle.gridTable7ColorfulAccent2: - base._applyGridTable7Colorful( - PdfColor(244, 176, 131), - PdfColor(251, 228, 213), - PdfColor(196, 89, 17), - ); - break; - - case PdfGridBuiltInStyle.gridTable7ColorfulAccent3: - base._applyGridTable7Colorful( - PdfColor(201, 201, 201), - PdfColor(237, 237, 237), - PdfColor(123, 123, 123), - ); - break; - - case PdfGridBuiltInStyle.gridTable7ColorfulAccent4: - base._applyGridTable7Colorful( - PdfColor(255, 217, 102), - PdfColor(255, 242, 204), - PdfColor(191, 143, 0), - ); - break; - - case PdfGridBuiltInStyle.gridTable7ColorfulAccent5: - base._applyGridTable7Colorful( - PdfColor(142, 170, 219), - PdfColor(217, 226, 243), - PdfColor(47, 84, 150), - ); - break; - - case PdfGridBuiltInStyle.gridTable7ColorfulAccent6: - base._applyGridTable7Colorful( - PdfColor(168, 208, 141), - PdfColor(226, 239, 217), - PdfColor(83, 129, 53), - ); - break; - case PdfGridBuiltInStyle.listTable1Light: - base._applyListTable1Light( - PdfColor(102, 102, 102), - PdfColor(204, 204, 204), - ); - break; - - case PdfGridBuiltInStyle.listTable1LightAccent1: - base._applyListTable1Light( - PdfColor(156, 194, 229), - PdfColor(222, 234, 246), - ); - break; - - case PdfGridBuiltInStyle.listTable1LightAccent2: - base._applyListTable1Light( - PdfColor(244, 176, 131), - PdfColor(251, 228, 213), - ); - break; - - case PdfGridBuiltInStyle.listTable1LightAccent3: - base._applyListTable1Light( - PdfColor(201, 201, 201), - PdfColor(237, 237, 237), - ); - break; - - case PdfGridBuiltInStyle.listTable1LightAccent4: - base._applyListTable1Light( - PdfColor(255, 217, 102), - PdfColor(255, 242, 204), - ); - break; - - case PdfGridBuiltInStyle.listTable1LightAccent5: - base._applyListTable1Light( - PdfColor(142, 170, 219), - PdfColor(217, 226, 243), - ); - break; - - case PdfGridBuiltInStyle.listTable1LightAccent6: - base._applyListTable1Light( - PdfColor(168, 208, 141), - PdfColor(226, 239, 217), - ); - break; - - case PdfGridBuiltInStyle.listTable2: - base._applyListTable2(PdfColor(102, 102, 102), PdfColor(204, 204, 204)); - break; - - case PdfGridBuiltInStyle.listTable2Accent1: - base._applyListTable2(PdfColor(156, 194, 229), PdfColor(222, 234, 246)); - break; - - case PdfGridBuiltInStyle.listTable2Accent2: - base._applyListTable2(PdfColor(244, 176, 131), PdfColor(251, 228, 213)); - break; - - case PdfGridBuiltInStyle.listTable2Accent3: - base._applyListTable2(PdfColor(201, 201, 201), PdfColor(237, 237, 237)); - break; - - case PdfGridBuiltInStyle.listTable2Accent4: - base._applyListTable2(PdfColor(255, 217, 102), PdfColor(255, 242, 204)); - break; - - case PdfGridBuiltInStyle.listTable2Accent5: - base._applyListTable2(PdfColor(142, 170, 219), PdfColor(217, 226, 243)); - break; - - case PdfGridBuiltInStyle.listTable2Accent6: - base._applyListTable2(PdfColor(168, 208, 141), PdfColor(226, 239, 217)); - break; - - case PdfGridBuiltInStyle.listTable3: - base._applyListTable3(PdfColor(0, 0, 0)); - break; - - case PdfGridBuiltInStyle.listTable3Accent1: - base._applyListTable3(PdfColor(91, 155, 213)); - break; - - case PdfGridBuiltInStyle.listTable3Accent2: - base._applyListTable3(PdfColor(237, 125, 49)); - break; - - case PdfGridBuiltInStyle.listTable3Accent3: - base._applyListTable3(PdfColor(165, 165, 165)); - break; - - case PdfGridBuiltInStyle.listTable3Accent4: - base._applyListTable3(PdfColor(255, 192, 0)); - break; - - case PdfGridBuiltInStyle.listTable3Accent5: - base._applyListTable3(PdfColor(68, 114, 196)); - break; - - case PdfGridBuiltInStyle.listTable3Accent6: - base._applyListTable3(PdfColor(112, 171, 71)); - break; - - case PdfGridBuiltInStyle.listTable4: - base._applyListTable4( - PdfColor(102, 102, 102), - PdfColor(0, 0, 0), - PdfColor(204, 204, 204), - ); - break; - - case PdfGridBuiltInStyle.listTable4Accent1: - base._applyListTable4( - PdfColor(156, 194, 229), - PdfColor(91, 155, 213), - PdfColor(222, 234, 246), - ); - break; - - case PdfGridBuiltInStyle.listTable4Accent2: - base._applyListTable4( - PdfColor(244, 176, 131), - PdfColor(237, 125, 49), - PdfColor(251, 228, 213), - ); - break; - - case PdfGridBuiltInStyle.listTable4Accent3: - base._applyListTable4( - PdfColor(201, 201, 201), - PdfColor(165, 165, 165), - PdfColor(237, 237, 237), - ); - break; - - case PdfGridBuiltInStyle.listTable4Accent4: - base._applyListTable4( - PdfColor(255, 217, 102), - PdfColor(255, 192, 0), - PdfColor(255, 242, 204), - ); - break; - - case PdfGridBuiltInStyle.listTable4Accent5: - base._applyListTable4( - PdfColor(142, 170, 219), - PdfColor(68, 114, 196), - PdfColor(217, 226, 243), - ); - break; - - case PdfGridBuiltInStyle.listTable4Accent6: - base._applyListTable4( - PdfColor(168, 208, 141), - PdfColor(112, 173, 71), - PdfColor(226, 239, 217), - ); - break; - - case PdfGridBuiltInStyle.listTable5Dark: - base._applyListTable5Dark(PdfColor(0, 0, 0)); - break; - - case PdfGridBuiltInStyle.listTable5DarkAccent1: - base._applyListTable5Dark(PdfColor(91, 155, 213)); - break; - - case PdfGridBuiltInStyle.listTable5DarkAccent2: - base._applyListTable5Dark(PdfColor(237, 125, 49)); - break; - - case PdfGridBuiltInStyle.listTable5DarkAccent3: - base._applyListTable5Dark(PdfColor(165, 165, 165)); - break; - - case PdfGridBuiltInStyle.listTable5DarkAccent4: - base._applyListTable5Dark(PdfColor(255, 192, 0)); - break; - - case PdfGridBuiltInStyle.listTable5DarkAccent5: - base._applyListTable5Dark(PdfColor(68, 114, 196)); - break; - - case PdfGridBuiltInStyle.listTable5DarkAccent6: - base._applyListTable5Dark(PdfColor(112, 173, 71)); - break; - - case PdfGridBuiltInStyle.listTable6Colorful: - base._applyListTable6Colorful( - PdfColor(102, 102, 102), - PdfColor(204, 204, 204), - PdfColor(0, 0, 0), - ); - break; - - case PdfGridBuiltInStyle.listTable6ColorfulAccent1: - base._applyListTable6Colorful( - PdfColor(91, 155, 213), - PdfColor(222, 234, 246), - PdfColor(46, 116, 181), - ); - break; - - case PdfGridBuiltInStyle.listTable6ColorfulAccent2: - base._applyListTable6Colorful( - PdfColor(237, 125, 49), - PdfColor(251, 228, 213), - PdfColor(196, 89, 17), - ); - break; - - case PdfGridBuiltInStyle.listTable6ColorfulAccent3: - base._applyListTable6Colorful( - PdfColor(165, 165, 165), - PdfColor(237, 237, 237), - PdfColor(123, 123, 123), - ); - break; - - case PdfGridBuiltInStyle.listTable6ColorfulAccent4: - base._applyListTable6Colorful( - PdfColor(255, 192, 0), - PdfColor(255, 242, 204), - PdfColor(191, 143, 0), - ); - break; - - case PdfGridBuiltInStyle.listTable6ColorfulAccent5: - base._applyListTable6Colorful( - PdfColor(68, 114, 196), - PdfColor(217, 226, 243), - PdfColor(47, 84, 150), - ); - break; - - case PdfGridBuiltInStyle.listTable6ColorfulAccent6: - base._applyListTable6Colorful( - PdfColor(112, 173, 71), - PdfColor(226, 239, 217), - PdfColor(83, 129, 53), - ); - break; - - case PdfGridBuiltInStyle.listTable7Colorful: - base._applyListTable7Colorful( - PdfColor(102, 102, 102), - PdfColor(204, 204, 204), - PdfColor(0, 0, 0), - ); - break; - - case PdfGridBuiltInStyle.listTable7ColorfulAccent1: - base._applyListTable7Colorful( - PdfColor(91, 155, 213), - PdfColor(222, 234, 246), - PdfColor(46, 116, 181), - ); - break; - - case PdfGridBuiltInStyle.listTable7ColorfulAccent2: - base._applyListTable7Colorful( - PdfColor(237, 125, 49), - PdfColor(251, 228, 213), - PdfColor(196, 89, 17), - ); - break; - - case PdfGridBuiltInStyle.listTable7ColorfulAccent3: - base._applyListTable7Colorful( - PdfColor(165, 165, 165), - PdfColor(237, 237, 237), - PdfColor(123, 123, 123), - ); - break; - - case PdfGridBuiltInStyle.listTable7ColorfulAccent4: - base._applyListTable7Colorful( - PdfColor(255, 192, 0), - PdfColor(255, 242, 204), - PdfColor(191, 143, 0), - ); - break; - - case PdfGridBuiltInStyle.listTable7ColorfulAccent5: - base._applyListTable7Colorful( - PdfColor(68, 114, 196), - PdfColor(217, 226, 243), - PdfColor(47, 84, 150), - ); - break; - - case PdfGridBuiltInStyle.listTable7ColorfulAccent6: - base._applyListTable7Colorful( - PdfColor(112, 173, 71), - PdfColor(226, 239, 217), - PdfColor(83, 129, 53), - ); - break; - - // ignore: no_default_cases - default: - } - } -} - -/// Delegate for handling StartCellLayoutEvent. -typedef PdfGridBeginCellLayoutCallback = - void Function(Object sender, PdfGridBeginCellLayoutArgs args); - -/// Delegate for handling EndCellLayoutEvent. -typedef PdfGridEndCellLayoutCallback = - void Function(Object sender, PdfGridEndCellLayoutArgs args); - -/// Represents arguments of StartCellLayout Event. -class PdfGridBeginCellLayoutArgs extends GridCellLayoutArgs { - //Constructor - PdfGridBeginCellLayoutArgs._( - PdfGraphics graphics, - int rowIndex, - int cellInder, - PdfRectangle bounds, - String value, - PdfGridCellStyle? style, - bool isHeaderRow, - ) : super._(graphics, rowIndex, cellInder, bounds, value, isHeaderRow) { - if (style != null) { - this.style = style; - } - skip = false; - } - //Fields - /// PDF grid cell style - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// //Apply the cell style to specific row cells - /// row.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridCellStyle? style; - - /// A value that indicates whether the cell is drawn or not in the PDF document. - late bool skip; -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfGridBeginCellLayoutArgs] helper -class PdfGridBeginCellLayoutArgsHelper { - /// internal method - static PdfGridBeginCellLayoutArgs load( - PdfGraphics graphics, - int rowIndex, - int cellInder, - PdfRectangle bounds, - String value, - PdfGridCellStyle? style, - bool isHeaderRow, - ) { - return PdfGridBeginCellLayoutArgs._( - graphics, - rowIndex, - cellInder, - bounds, - value, - style, - isHeaderRow, - ); - } -} - -/// Represents arguments of EndCellLayout Event. -class PdfGridEndCellLayoutArgs extends GridCellLayoutArgs { - //Constructor - PdfGridEndCellLayoutArgs._( - PdfGraphics graphics, - int rowIndex, - int cellInder, - PdfRectangle bounds, - String value, - PdfGridCellStyle? style, - bool isHeaderRow, - ) : super._(graphics, rowIndex, cellInder, bounds, value, isHeaderRow) { - if (style != null) { - this.style = style; - } - } - //Fields - /// PDF grid cell style - PdfGridCellStyle? style; -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfGridEndCellLayoutArgs] helper -class PdfGridEndCellLayoutArgsHelper { - /// internal method - static PdfGridEndCellLayoutArgs load( - PdfGraphics graphics, - int rowIndex, - int cellInder, - PdfRectangle bounds, - String value, - PdfGridCellStyle? style, - bool isHeaderRow, - ) { - return PdfGridEndCellLayoutArgs._( - graphics, - rowIndex, - cellInder, - bounds, - value, - style, - isHeaderRow, - ); - } -} - -/// Represents the abstract class of the [GridCellLayoutArgs]. -abstract class GridCellLayoutArgs { - //Constructors - /// Initializes a new instance of the [StartCellLayoutArgs] class. - GridCellLayoutArgs._( - PdfGraphics graphics, - int rowIndex, - int cellIndex, - PdfRectangle bounds, - String value, - bool isHeaderRow, - ) { - _rowIndex = rowIndex; - _cellIndex = cellIndex; - _value = value; - _bounds = bounds.rect; - _graphics = graphics; - _isHeaderRow = isHeaderRow; - } - - //Fields - late int _rowIndex; - late int _cellIndex; - late String _value; - late Rect _bounds; - late PdfGraphics _graphics; - late bool _isHeaderRow; - - //Properties - /// Gets the index of the row. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on starting cell lay outing. - /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get rowIndex => _rowIndex; - - /// Gets the index of the cell. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on starting cell lay outing. - /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get cellIndex => _cellIndex; - - /// Gets the value. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on starting cell lay outing. - /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String get value => _value; - - /// Gets the bounds of the cell. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on starting cell lay outing. - /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - Rect get bounds => _bounds; - - /// Gets the graphics, on which the cell should be drawn. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on starting cell lay outing. - /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGraphics get graphics => _graphics; - - /// Gets the type of Grid row. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// // Sets the event raised on starting cell lay outing. - /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { - /// if (args.rowIndex == 1 && args.cellIndex == 1) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// if (args.isHeaderRow && args.cellIndex == 0) { - /// args.graphics.drawRectangle( - /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), - /// brush: PdfBrushes.white, - /// bounds: args.bounds); - /// } - /// }; - /// grid.style.cellPadding = PdfPaddings(); - /// grid.style.cellPadding.all = 15; - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool get isHeaderRow => _isHeaderRow; -} - -/// Arguments of BeginPageLayoutEvent. -class PdfGridBeginPageLayoutArgs extends BeginPageLayoutArgs { - //Constructor - PdfGridBeginPageLayoutArgs._(super.bounds, super.page, int? startRow) { - startRowIndex = startRow ?? 0; - } - - //Fields - /// Gets the start row index. - late int startRowIndex; -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfGridBeginPageLayoutArgs] helper -class PdfGridBeginPageLayoutArgsHelper { - /// internal method - static PdfGridBeginPageLayoutArgs load( - Rect bounds, - PdfPage page, - int? startRow, - ) { - return PdfGridBeginPageLayoutArgs._(bounds, page, startRow); - } -} - -/// Arguments of EndPageLayoutEvent. -class PdfGridEndPageLayoutArgs extends EndPageLayoutArgs { - //Constructor - PdfGridEndPageLayoutArgs._(super.result); -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfGridEndPageLayoutArgs] helper -class PdfGridEndPageLayoutArgsHelper { - /// internal method - static PdfGridEndPageLayoutArgs load(PdfLayoutResult result) { - return PdfGridEndPageLayoutArgs._(result); - } -} - -/// Represents the grid built-in style settings. -class PdfGridBuiltInStyleSettings { - // Constructor - /// Represents the grid built-in style settings. - PdfGridBuiltInStyleSettings({ - this.applyStyleForBandedColumns = false, - this.applyStyleForBandedRows = true, - this.applyStyleForFirstColumn = false, - this.applyStyleForHeaderRow = true, - this.applyStyleForLastColumn = false, - this.applyStyleForLastRow = false, - }); - - //Fields - /// Gets or sets a value indicating whether to apply style bands to the columns in a table. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// PdfGridBuiltInStyleSettings tableStyleOption = - /// PdfGridBuiltInStyleSettings(); - /// //Sets applyStyleForBandedColumns - /// tableStyleOption.applyStyleForBandedColumns = true; - ///Apply built-in table style - /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, - /// settings: tableStyleOption); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool applyStyleForBandedColumns; - - /// Gets or sets a value indicating whether to apply style bands to the rows in a table. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// PdfGridBuiltInStyleSettings tableStyleOption = - /// PdfGridBuiltInStyleSettings(); - /// //Sets applyStyleForBandedRows - /// tableStyleOption.applyStyleForBandedRows = true; - ///Apply built-in table style - /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, - /// settings: tableStyleOption); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool applyStyleForBandedRows; - - /// Gets or sets a value indicating whether to apply first-column formatting to the first column of the specified table. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// PdfGridBuiltInStyleSettings tableStyleOption = - /// PdfGridBuiltInStyleSettings(); - /// //Sets applyStyleForFirstColumn - /// tableStyleOption.applyStyleForFirstColumn = true; - ///Apply built-in table style - /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, - /// settings: tableStyleOption); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool applyStyleForFirstColumn; - - /// Gets or sets a value indicating whether to apply heading-row formatting to the first row of the table. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// PdfGridBuiltInStyleSettings tableStyleOption = - /// PdfGridBuiltInStyleSettings(); - /// //Sets applyStyleForHeaderRow - /// tableStyleOption.applyStyleForHeaderRow = true; - ///Apply built-in table style - /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, - /// settings: tableStyleOption); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool applyStyleForHeaderRow; - - /// Gets or sets a value indicating whether to apply first-column formatting to the first column of the specified table. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// PdfGridBuiltInStyleSettings tableStyleOption = - /// PdfGridBuiltInStyleSettings(); - /// //Sets applyStyleForLastColumn - /// tableStyleOption.applyStyleForLastColumn = true; - ///Apply built-in table style - /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, - /// settings: tableStyleOption); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool applyStyleForLastColumn; - - /// Gets or sets a value indicating whether to apply last-row formatting to the last row of the specified table. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid class - /// PdfGrid grid = PdfGrid(); - /// //Add the columns to the grid - /// grid.columns.add(count: 3); - /// //Add header to the grid - /// grid.headers.add(1); - /// //Add the rows to the grid - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row = grid.rows.add(); - /// row.cells[0].value = 'E01'; - /// row.cells[1].value = 'Clay'; - /// row.cells[2].value = '\$10,000'; - /// row = grid.rows.add(); - /// row.cells[0].value = 'E02'; - /// row.cells[1].value = 'Simon'; - /// row.cells[2].value = '\$12,000'; - /// PdfGridBuiltInStyleSettings tableStyleOption = - /// PdfGridBuiltInStyleSettings(); - /// //Sets applyStyleForLastRow - /// tableStyleOption.applyStyleForLastRow = true; - ///Apply built-in table style - /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, - /// settings: tableStyleOption); - /// //Draw the grid - /// grid.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool applyStyleForLastRow; -} +import 'dart:math'; +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/enums.dart'; +import '../../graphics/figures/base/element_layouter.dart'; +import '../../graphics/figures/base/layout_element.dart'; +import '../../graphics/figures/base/text_layouter.dart'; +import '../../graphics/fonts/enums.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_standard_font.dart'; +import '../../graphics/fonts/pdf_true_type_font.dart'; +import '../../graphics/pdf_color.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../graphics/pdf_pen.dart'; +import '../../pages/pdf_page.dart'; +import 'enums.dart'; +import 'layouting/pdf_grid_layouter.dart'; +import 'pdf_grid_cell.dart'; +import 'pdf_grid_column.dart'; +import 'pdf_grid_row.dart'; +import 'styles/pdf_borders.dart'; +import 'styles/style.dart'; + +/// Represents a flexible grid that consists of columns and rows. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid class +/// PdfGrid grid = PdfGrid(); +/// //Add the columns to the grid +/// grid.columns.add(count: 3); +/// //Add header to the grid +/// grid.headers.add(1); +/// //Add the rows to the grid +/// PdfGridRow header = grid.headers[0]; +/// header.cells[0].value = 'Employee ID'; +/// header.cells[1].value = 'Employee Name'; +/// header.cells[2].value = 'Salary'; +/// //Add rows to grid +/// PdfGridRow row = grid.rows.add(); +/// row.cells[0].value = 'E01'; +/// row.cells[1].value = 'Clay'; +/// row.cells[2].value = '\$10,000'; +/// row = grid.rows.add(); +/// row.cells[0].value = 'E02'; +/// row.cells[1].value = 'Simon'; +/// row.cells[2].value = '\$12,000'; +/// //Set the grid style +/// grid.style = PdfGridStyle( +/// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), +/// backgroundBrush: PdfBrushes.blue, +/// textBrush: PdfBrushes.white, +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); +/// //Draw the grid +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGrid extends PdfLayoutElement { + /// Initializes a new instance of the [PdfGrid] class. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGrid() { + _helper = PdfGridHelper(this); + _initialize(); + } + + //Fields + late PdfGridHelper _helper; + PdfGridColumnCollection? _columns; + PdfGridRowCollection? _rows; + PdfGridStyle? _style; + PdfGridHeaderCollection? _headers; + + /// Gets or sets a value indicating whether to repeat header. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Sets repeatHeader + /// grid.repeatHeader = true; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// for (int i = 0; i < 500; i++) { + /// final PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'Row - $i Cell - 1'; + /// row.cells[1].value = 'Row - $i Cell - 2'; + /// row.cells[2].value = 'Row - $i Cell - 3'; + /// } + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late bool repeatHeader; + + /// Gets or sets a value indicating whether to split or cut rows that overflow a page. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Sets allowRowBreakingAcrossPages + /// grid.allowRowBreakingAcrossPages = true; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(100); + /// //Add the rows to the grid + /// for (int i = 0; i < 100; i++) { + /// final PdfGridRow header = grid.headers[i]; + /// header.cells[0].value = 'Header - $i Cell - 1'; + /// final PdfTextElement element = PdfTextElement(font: PdfStandardFont(PdfFontFamily.timesRoman, 15)); + /// element.text = + /// 'Header - $i Cell - 2 Sample text for pagination. Lorem ipsum dolor sit amet,\r\n consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua'; + /// header.cells[1].value = element; + /// header.cells[2].value = 'Header - $i Cell - 3'; + /// } + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late bool allowRowBreakingAcrossPages; + late PdfRectangle _gridLocation; + bool _headerRow = true; + bool _bandedRow = true; + late bool _bandedColumn; + late bool _totalRow; + late bool _firstColumn; + late bool _lastColumn; + Map? _boldFontCache; + Map? _regularFontCache; + Map? _italicFontCache; + + //Events + /// The event raised on starting cell lay outing. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on starting cell lay outing. + /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridBeginCellLayoutCallback? beginCellLayout; + + /// The event raised on finished cell layout. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on finished cell layout. + /// grid.endCellLayout = (Object sender, PdfGridEndCellLayoutArgs args) { + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridEndCellLayoutCallback? endCellLayout; + + //Properties + /// Gets the column collection of the PdfGrid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Set the grid style + /// grid.style = PdfGridStyle( + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// backgroundBrush: PdfBrushes.blue, + /// textBrush: PdfBrushes.white, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridColumnCollection get columns { + _columns ??= PdfGridColumnCollection(this); + return _columns!; + } + + /// Gets the row collection from the PdfGrid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Set the grid style + /// grid.style = PdfGridStyle( + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// backgroundBrush: PdfBrushes.blue, + /// textBrush: PdfBrushes.white, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridRowCollection get rows { + _rows ??= PdfGridRowCollection(this); + return _rows!; + } + + /// Gets the headers collection from the PdfGrid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Set the grid style + /// grid.style = PdfGridStyle( + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// backgroundBrush: PdfBrushes.blue, + /// textBrush: PdfBrushes.white, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridHeaderCollection get headers { + _headers ??= PdfGridHeaderCollection(this); + return _headers!; + } + + /// Gets the grid style. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Set the grid style + /// grid.style = PdfGridStyle( + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// backgroundBrush: PdfBrushes.blue, + /// textBrush: PdfBrushes.white, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 25)); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridStyle get style { + _style ??= PdfGridStyle(); + return _style!; + } + + set style(PdfGridStyle value) { + _style = value; + } + + //Implementation + void _initialize() { + _helper.gridSize = PdfSize.empty; + _helper.isComplete = false; + _helper.isDrawn = false; + _helper.isSingleGrid = true; + _helper.isWidthSet = false; + repeatHeader = false; + allowRowBreakingAcrossPages = true; + _gridLocation = PdfRectangle.empty; + _helper.hasColumnSpan = false; + _helper.hasRowSpan = false; + _helper.isChildGrid ??= false; + _helper.isPageWidth = false; + _helper.isRearranged = false; + _helper.initialWidth = 0; + _helper.rowLayoutBoundswidth = 0; + _helper.listOfNavigatePages = []; + _helper.parentCellIndex = 0; + _helper.isBuiltinStyle = false; + _helper.defaultFont = PdfStandardFont(PdfFontFamily.helvetica, 8); + _helper.defaultBorder = PdfBorders(); + } + + /// Draws the [PdfGrid] + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + @override + PdfLayoutResult? draw({ + Rect? bounds, + PdfLayoutFormat? format, + PdfGraphics? graphics, + PdfPage? page, + }) { + final PdfRectangle rectangle = + bounds != null ? PdfRectangle.fromRect(bounds) : PdfRectangle.empty; + _helper.initialWidth = + rectangle.width == 0 + ? page != null + ? page.getClientSize().width + : graphics!.clientSize.width + : rectangle.width; + _helper.isWidthSet = true; + if (page != null) { + final PdfLayoutResult? result = super.draw( + page: page, + bounds: bounds, + format: format, + ); + _helper.isComplete = true; + return result; + } else if (graphics != null) { + _helper.drawInternal(graphics, rectangle); + } + return null; + } + + /// Apply built-in table style to the table + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// PdfGridBuiltInStyleSettings tableStyleOption = + /// PdfGridBuiltInStyleSettings(); + /// tableStyleOption.applyStyleForBandedRows = true; + /// tableStyleOption.applyStyleForHeaderRow = true; + ///Apply built-in table style + /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, + /// settings: tableStyleOption); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void applyBuiltInStyle( + PdfGridBuiltInStyle gridStyle, { + PdfGridBuiltInStyleSettings? settings, + }) { + _intializeBuiltInStyle(gridStyle, settings: settings); + } + + void _intializeBuiltInStyle( + PdfGridBuiltInStyle gridStyle, { + PdfGridBuiltInStyleSettings? settings, + }) { + if (settings != null) { + _headerRow = settings.applyStyleForHeaderRow; + _totalRow = settings.applyStyleForLastRow; + _firstColumn = settings.applyStyleForFirstColumn; + _lastColumn = settings.applyStyleForLastColumn; + _bandedColumn = settings.applyStyleForBandedColumns; + _bandedRow = settings.applyStyleForBandedRows; + } else { + _totalRow = false; + _firstColumn = false; + _lastColumn = false; + _bandedColumn = false; + } + _helper.isBuiltinStyle = true; + _helper.gridBuiltinStyle = gridStyle; + } + + PdfFont? _createBoldFont(PdfFont font) { + _boldFontCache ??= {}; + if (font is PdfStandardFont) { + final PdfStandardFont standardFont = font; + return PdfStandardFont( + standardFont.fontFamily, + font.size, + style: PdfFontStyle.bold, + ); + } else { + if (_boldFontCache!.containsKey(font)) { + return _boldFontCache![font as PdfTrueTypeFont]; + } else { + final PdfTrueTypeFont trueTypeFont = font as PdfTrueTypeFont; + final PdfFont boldStyleFont = PdfTrueTypeFont( + PdfTrueTypeFontHelper.getHelper(trueTypeFont).fontInternal.fontData, + font.size, + style: PdfFontStyle.bold, + ); + _boldFontCache![font] = boldStyleFont as PdfTrueTypeFont; + return boldStyleFont; + } + } + } + + PdfFont? _createRegularFont(PdfFont font) { + _regularFontCache ??= {}; + if (font is PdfStandardFont) { + final PdfStandardFont standardFont = font; + return PdfStandardFont( + standardFont.fontFamily, + font.size, + style: PdfFontStyle.regular, + ); + } else { + if (_regularFontCache!.containsKey(font)) { + return _regularFontCache![font as PdfTrueTypeFont]; + } else { + final PdfTrueTypeFont trueTypeFont = font as PdfTrueTypeFont; + final PdfFont ttfFont = PdfTrueTypeFont( + PdfTrueTypeFontHelper.getHelper(trueTypeFont).fontInternal.fontData, + font.size, + style: PdfFontStyle.regular, + ); + _regularFontCache![font] = ttfFont as PdfTrueTypeFont; + return ttfFont; + } + } + } + + PdfFont? _createItalicFont(PdfFont? font) { + _italicFontCache ??= {}; + if (font is PdfStandardFont) { + final PdfStandardFont standardFont = font; + return PdfStandardFont( + standardFont.fontFamily, + font.size, + style: PdfFontStyle.italic, + ); + } else { + if (_italicFontCache!.containsKey(font)) { + return _italicFontCache![font! as PdfTrueTypeFont]; + } else { + final PdfTrueTypeFont trueTypeFont = font! as PdfTrueTypeFont; + final PdfFont italicStyleFont = PdfTrueTypeFont( + PdfTrueTypeFontHelper.getHelper(trueTypeFont).fontInternal.fontData, + font.size, + style: PdfFontStyle.italic, + ); + _italicFontCache![font as PdfTrueTypeFont] = + italicStyleFont as PdfTrueTypeFont; + return italicStyleFont; + } + } + } + + PdfFont? _changeFontStyle(PdfFont font) { + PdfFont? pdfFont; + if (font.style == PdfFontStyle.regular) { + pdfFont = _createBoldFont(font); + } else if (font.style == PdfFontStyle.bold) { + pdfFont = _createRegularFont(font); + } + return pdfFont; + } + + PdfBrush? _applyBandedColStyle( + bool firstColumn, + PdfColor backColor, + int cellIndex, + ) { + PdfBrush? backBrush; + if (firstColumn) { + if (cellIndex.isEven) { + backBrush = PdfSolidBrush(backColor); + } + } else { + if (cellIndex.isOdd) { + backBrush = PdfSolidBrush(backColor); + } + } + return backBrush; + } + + PdfBrush? _applyBandedRowStyle( + bool headerRow, + PdfColor backColor, + int rowIndex, + ) { + PdfBrush? backBrush; + if (headerRow) { + if (rowIndex.isOdd) { + backBrush = PdfSolidBrush(backColor); + } + } else { + if (rowIndex.isEven) { + backBrush = PdfSolidBrush(backColor); + } + } + return backBrush; + } + + void _applyTableGridLight(PdfColor borderColor) { + final PdfPen borderPen = PdfPen(borderColor); + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + } + } + } + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + } + } + } + + void _applyPlainTable1(PdfColor borderColor, PdfColor backColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfBrush backBrush = PdfSolidBrush(backColor); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = borderPen; + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + } + } else { + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = PdfPen(borderColor); + if (_bandedColumn) { + if (!(_lastColumn && j == row.cells.count)) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + } + } + } + } + } + + void _applyPlainTable2(PdfColor borderColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfPen emptyPen = PdfPen(PdfColor.empty); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.borders.top = borderPen; + if (_bandedColumn) { + cell.style.borders.left = borderPen; + cell.style.borders.right = borderPen; + } + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.bottom = borderPen; + if (_firstColumn && j == 1) { + cell.style.borders.left = emptyPen; + } + if (_lastColumn && j == row.cells.count) { + cell.style.borders.right = emptyPen; + } + } else { + if (_bandedRow) { + cell.style.borders.top = borderPen; + cell.style.borders.bottom = borderPen; + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.left = emptyPen; + } + if (_lastColumn && j == row.cells.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.right = emptyPen; + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + if (i == rows.count) { + cell.style.borders.bottom = borderPen; + } + if (_bandedColumn) { + cell.style.borders.left = borderPen; + cell.style.borders.right = borderPen; + } + if (_bandedRow) { + cell.style.borders.top = borderPen; + cell.style.borders.bottom = borderPen; + } + if (i == rows.count && _totalRow) { + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = borderPen; + if (_bandedColumn) { + cell.style.borders.left = borderPen; + cell.style.borders.right = borderPen; + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.right = emptyPen; + } else if (_bandedColumn) { + cell.style.borders.right = emptyPen; + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.left = emptyPen; + } else if (_bandedColumn) { + cell.style.borders.left = emptyPen; + } + } + } + } + } + + void _applyPlainTable3(PdfColor borderColor, PdfColor backColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfPen whitePen = PdfPen(PdfColor.empty); + final PdfBrush backBrush = PdfSolidBrush(backColor); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + if (i == 1) { + cell.style.borders.bottom = borderPen; + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + } + } else { + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + cell.style.borders.right = borderPen; + } + if (_lastColumn && j == row.cells.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = whitePen; + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + if (_bandedColumn) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + } + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + if (_bandedRow && _bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } + } + if (i == rows.count && _totalRow) { + if (_bandedRow) { + cell.style.borders.all = whitePen; + } + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } + } + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + } + cell.style.borders.right = borderPen; + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + cell.style.backgroundBrush = null; + + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + cell.style.borders.all = whitePen; + } else if (_bandedColumn) { + cell.style.backgroundBrush = null; + } + } + + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } + } + } + + void _applyPlainTable4(PdfColor backColor) { + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen whitePen = PdfPen(PdfColor.empty); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + } + } else { + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.borders.all = whitePen; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + } + } + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.borders.all = whitePen; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + if (cell.value is String) { + final String cellvalue = cell.value as String; + cell.value = cellvalue.toUpperCase(); + } + if (_bandedColumn) { + if (!(_lastColumn && j == row.cells.count)) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + } + } + } + } + } + + void _applyPlainTable5(PdfColor borderColor, PdfColor backColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfPen whitePen = PdfPen(PdfColor.empty); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen backBrushPen = PdfPen(backColor, width: 0.5); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + if (font.style != PdfFontStyle.italic) { + cell.style.font = _createItalicFont(font); + } + if (i == 1) { + cell.style.borders.bottom = borderPen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } else { + cell.style.borders.all = backBrushPen; + } + } + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } else { + cell.style.borders.all = backBrushPen; + } + } + } + if (_firstColumn && j == 1) { + cell.style.borders.all = whitePen; + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + if (font.style != PdfFontStyle.italic) { + cell.style.font = _createItalicFont(font); + } + cell.style.borders.right = borderPen; + } + if (_lastColumn && j == row.cells.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + cell.style.borders.all = whitePen; + cell.style.backgroundBrush = null; + cell.style.borders.left = borderPen; + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + if (_bandedRow && _bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } else { + cell.style.borders.all = backBrushPen; + } + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } else { + cell.style.borders.all = backBrushPen; + } + } + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } else { + cell.style.borders.all = backBrushPen; + } + } + } + if (_totalRow && i == rows.count) { + cell.style.borders.all = PdfPen(PdfColor.empty); + cell.style.backgroundBrush = null; + cell.style.borders.top = borderPen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + if (font.style != PdfFontStyle.italic) { + cell.style.font = _createItalicFont(font); + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + cell.style.borders.all = whitePen; + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + if (font.style != PdfFontStyle.italic) { + cell.style.font = _createItalicFont(font); + } + cell.style.borders.right = borderPen; + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + cell.style.borders.all = whitePen; + cell.style.backgroundBrush = null; + cell.style.borders.left = borderPen; + } + } + + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } + } + } + + void _applyGridTable1Light(PdfColor borderColor, PdfColor headerBottomColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } else { + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (_headerRow && i == 1) { + cell.style.borders.top = PdfPen(headerBottomColor); + } + if (_totalRow) { + if (i == rows.count) { + cell.style.borders.top = PdfPen(headerBottomColor); + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + void _applyGridTable2(PdfColor borderColor, PdfColor backColor) { + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen borderPen = PdfPen(borderColor, width: 0.25); + final PdfPen backColorPen = PdfPen(backColor, width: 0.25); + final PdfPen emptyPen = PdfPen(PdfColor.empty); + final PdfPen headerBorder = PdfPen(borderColor); + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + row.cells[0].style.borders.bottom = headerBorder; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (j == 1) { + cell.style.borders.left = emptyPen; + } else if (j == row.cells.count) { + cell.style.borders.right = emptyPen; + } + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = PdfPen(PdfColor.empty); + if (PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(cell).row!, + ).grid.style.cellSpacing > + 0) { + cell.style.borders.bottom = headerBorder; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (row.cells.count % 2 != 0 && j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + } + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + if (cell.style.backgroundBrush != null) { + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + if (cell.style.backgroundBrush != null) { + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + } + } + + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (j == 1) { + cell.style.borders.left = emptyPen; + } else if (j == row.cells.count) { + cell.style.borders.right = emptyPen; + } + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + cell.style.backgroundBrush ??= _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + } + } else { + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + + if (cell.style.backgroundBrush != null) { + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + } + } + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (row.cells.count % 2 != 0 && j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + } + } + } + if (_totalRow && i == rows.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + cell.style.borders.top = headerBorder; + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.backgroundBrush = null; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush == null) { + cell.style.borders.right = emptyPen; + } + } + } else if (_bandedColumn) { + cell.style.backgroundBrush = null; + } + } + + if (_headerRow && _headers!.count > 0) { + if (i == 1) { + cell.style.borders.top = headerBorder; + } + } + } + } + } + + void _applyGridTable3(PdfColor borderColor, PdfColor backColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen whitePen = PdfPen(PdfColor.empty); + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = whitePen; + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + if (_firstColumn && j == 1) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + } + if (_totalRow && i == rows.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = PdfPen(PdfColor.empty); + cell.style.backgroundBrush = null; + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + if (i == 1 && _headerRow) { + cell.style.borders.top = borderPen; + } + } else { + cell.style.borders.top = borderPen; + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + if (i == 1 && _headerRow) { + cell.style.borders.top = borderPen; + } + } else { + cell.style.borders.top = borderPen; + } + } + } + } + } + + void _applyGridTable4( + PdfColor borderColor, + PdfColor backColor, + PdfColor headerBackColor, + ) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen headerBackColorPen = PdfPen(headerBackColor, width: 0.5); + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = PdfPen(headerBackColor); + cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); + cell.style.backgroundBrush = PdfSolidBrush(headerBackColor); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = PdfPen(borderColor); + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } else if (_bandedColumn) { + cell.style.backgroundBrush = null; + } + } + + if (_headerRow && _headers!.count > 0) { + if (i == 1) { + cell.style.borders.top = headerBackColorPen; + } + } + } + } + } + + void _applyGridTable5Dark( + PdfColor headerBackColor, + PdfColor oddRowBackColor, + PdfColor evenRowBackColor, + ) { + final PdfPen whitePen = PdfPen(PdfColor(255, 255, 255), width: 0.5); + final PdfBrush evenRowBrush = PdfSolidBrush(evenRowBackColor); + final PdfBrush oddRowBrush = PdfSolidBrush(oddRowBackColor); + final PdfBrush headerBrush = PdfSolidBrush(headerBackColor); + final PdfBrush textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + cell.style.backgroundBrush = evenRowBrush; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); + cell.style.backgroundBrush = headerBrush; + cell.style.borders.all = PdfPen(PdfColor.empty, width: 0.5); + if (j == 1) { + cell.style.borders.left = whitePen; + } else if (j == row.cells.count) { + cell.style.borders.right = whitePen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + oddRowBackColor, + j, + ); + + cell.style.backgroundBrush ??= evenRowBrush; + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = oddRowBrush; + } + } + if ((_firstColumn && j == 1) || + (_lastColumn && j == row.cells.count)) { + cell.style.backgroundBrush = headerBrush; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.textBrush = textBrush; + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + cell.style.backgroundBrush = evenRowBrush; + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + oddRowBackColor, + j, + ); + if (cell.style.backgroundBrush == null) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + oddRowBackColor, + i, + ); + + cell.style.backgroundBrush ??= evenRowBrush; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + oddRowBackColor, + j, + ); + + cell.style.backgroundBrush ??= evenRowBrush; + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + oddRowBackColor, + i, + ); + + cell.style.backgroundBrush ??= evenRowBrush; + } + } + if (_totalRow && i == rows.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.textBrush = textBrush; + cell.style.backgroundBrush = PdfSolidBrush(headerBackColor); + cell.style.borders.all = whitePen; + if (j == 1) { + cell.style.borders.left = whitePen; + } else if (j == row.cells.count) { + cell.style.borders.right = whitePen; + } + } + + if ((_firstColumn && j == 1) || (_lastColumn && j == row.cells.count)) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = headerBrush; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.textBrush = textBrush; + } + } + } + } + } + + void _applyGridTable6Colorful( + PdfColor borderColor, + PdfColor backColor, + PdfColor textColor, + ) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen headerBottomPen = PdfPen(borderColor); + final PdfBrush textBrush = PdfSolidBrush(textColor); + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + cell.style.textBrush = textBrush; + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + } + } else { + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + cell.style.textBrush = textBrush; + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + if (_bandedColumn && (!(_lastColumn && j == row.cells.count))) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = PdfPen(borderColor); + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + + if (_headerRow && i == 1) { + cell.style.borders.top = headerBottomPen; + } + } + } + } + + void _applyGridTable7Colorful( + PdfColor borderColor, + PdfColor backColor, + PdfColor textColor, + ) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfBrush textBrush = PdfSolidBrush(textColor); + final PdfPen whitePen = PdfPen(PdfColor.empty, width: 0.5); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.textBrush = textBrush; + cell.style.borders.all = borderPen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = PdfPen(PdfColor(255, 255, 255)); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + } + if (_firstColumn && j == 1) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = borderPen; + cell.style.textBrush = textBrush; + if (_bandedRow && _bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = PdfPen(PdfColor.empty); + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + if (i == 1 && _headerRow) { + cell.style.borders.top = borderPen; + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + } else { + cell.style.borders.top = borderPen; + } + } + + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.all = whitePen; + cell.style.borders.left = borderPen; + if (i == 1 && _headerRow) { + cell.style.borders.top = borderPen; + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + } else { + cell.style.borders.top = borderPen; + } + } + } + } + } + + void _applyListTable1Light(PdfColor borderColor, PdfColor backColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfPen emptyPen = PdfPen(PdfColor.empty); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen backBrushPen = PdfPen(backColor, width: 0.5); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + + if (i == 1) { + cell.style.borders.bottom = PdfPen(borderColor); + } + if (_bandedColumn) { + if (_lastColumn && j == rows.count) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backBrushPen; + } + if (_lastColumn && j == row.cells.count) { + cell.style.borders.all = emptyPen; + cell.style.backgroundBrush = null; + } + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backBrushPen; + } + } + + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + cell.style.borders.all = backBrushPen; + } + } + + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + if (_bandedRow && i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backBrushPen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backBrushPen; + } + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backBrushPen; + } + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } else { + cell.style.borders.top = borderPen; + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (_bandedColumn) { + if (!(_lastColumn && j == row.cells.count)) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backBrushPen; + } + } + + cell.style.borders.top = PdfPen(borderColor); + } + + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } + } + } + + void _applyListTable2(PdfColor borderColor, PdfColor backColor) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen backColorPen = PdfPen(backColor, width: 0.5); + final PdfPen emptyPen = PdfPen(PdfColor.empty, width: 0.5); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.borders.bottom = borderPen; + cell.style.borders.top = borderPen; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + } + if (cell.style.backgroundBrush != null) { + cell.style.borders.right = backColorPen; + cell.style.borders.left = backColorPen; + } + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.right = backColorPen; + cell.style.borders.left = backColorPen; + } + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.borders.left = backColorPen; + cell.style.borders.right = backColorPen; + cell.style.backgroundBrush = backBrush; + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + cell.style.borders.left = emptyPen; + cell.style.borders.right = emptyPen; + if (_bandedRow && i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + if (cell.style.backgroundBrush != null) { + cell.style.borders.left = backColorPen; + cell.style.borders.right = backColorPen; + } + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.borders.bottom = borderPen; + cell.style.borders.top = borderPen; + if (_bandedRow && _bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.right = backColorPen; + cell.style.borders.left = backColorPen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.right = backColorPen; + cell.style.borders.left = backColorPen; + } + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.left = backColorPen; + cell.style.borders.right = backColorPen; + } + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + cell.style.borders.top = borderPen; + cell.style.borders.bottom = borderPen; + + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + + if (_bandedColumn) { + if (!(j == row.cells.count && _lastColumn)) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (cell.style.backgroundBrush != null) { + cell.style.borders.right = backColorPen; + cell.style.borders.left = backColorPen; + } + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.left = emptyPen; + cell.style.borders.right = emptyPen; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.right = backColorPen; + } + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + void _applyListTable3(PdfColor backColor) { + final PdfPen backColorPen = PdfPen(backColor, width: 0.5); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen emptyPen = PdfPen(PdfColor.empty, width: 0.5); + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.borders.top = backColorPen; + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = backColorPen; + cell.style.backgroundBrush = backBrush; + cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); + } else { + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_bandedColumn) { + cell.style.borders.left = backColorPen; + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + if (headers.count == 0 && i == 1) { + cell.style.borders.top = backColorPen; + } + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + if (i == rows.count) { + cell.style.borders.bottom = backColorPen; + } + if (_bandedColumn) { + cell.style.borders.left = backColorPen; + } + if (_bandedRow) { + cell.style.borders.top = backColorPen; + } + if (_totalRow && i == rows.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = PdfPen(backColor); + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + void _applyListTable4( + PdfColor borderColor, + PdfColor headerBackColor, + PdfColor bandRowColor, + ) { + final PdfPen borderColorPen = PdfPen(borderColor, width: 0.5); + final PdfBrush headerBrush = PdfSolidBrush(headerBackColor); + final PdfBrush bandRowBrush = PdfSolidBrush(bandRowColor); + final PdfPen whitePen = PdfPen(PdfColor.empty, width: 0.5); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + cell.style.borders.top = borderColorPen; + if (j == 1) { + cell.style.borders.left = borderColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = borderColorPen; + } + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.all = PdfPen(headerBackColor, width: 0.5); + cell.style.backgroundBrush = headerBrush; + cell.style.textBrush = PdfSolidBrush(PdfColor(255, 255, 255)); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + bandRowColor, + j, + ); + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = bandRowBrush; + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + + if (_bandedRow && i % 2 != 0) { + cell.style.backgroundBrush = bandRowBrush; + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = whitePen; + cell.style.borders.top = borderColorPen; + if (j == 1) { + cell.style.borders.left = borderColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = borderColorPen; + } + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + bandRowColor, + j, + ); + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + bandRowColor, + i, + ); + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + bandRowColor, + j, + ); + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + bandRowColor, + i, + ); + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = PdfPen(borderColor); + if (_bandedColumn) { + if (!(_lastColumn && j == rows.count)) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + bandRowColor, + j, + ); + } + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + bandRowColor, + i, + ); + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + + if (i == rows.count) { + cell.style.borders.bottom = borderColorPen; + } + } + } + } + + void _applyListTable5Dark(PdfColor backColor) { + final PdfBrush backColorBrush = PdfSolidBrush(backColor); + final PdfPen whitePen = PdfPen(PdfColor(255, 255, 255), width: 0.5); + final PdfBrush whiteBrush = PdfSolidBrush(PdfColor(255, 255, 255)); + final PdfPen emptyPen = PdfPen(PdfColor.empty); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.textBrush = whiteBrush; + cell.style.backgroundBrush = backColorBrush; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.backgroundBrush = backColorBrush; + cell.style.textBrush = whiteBrush; + cell.style.borders.bottom = PdfPen( + PdfColor(255, 255, 255), + width: 2, + ); + if (_bandedColumn) { + if (j > 1) { + cell.style.borders.left = whitePen; + } + } + } else { + if (_firstColumn) { + if (j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } else if (j == 2) { + cell.style.borders.left = whitePen; + } + } + if (_bandedColumn) { + if (j > 1) { + cell.style.borders.left = whitePen; + } + } + if (_bandedRow) { + cell.style.borders.top = whitePen; + } + if (_lastColumn && j == row.cells.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.left = whitePen; + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.textBrush = whiteBrush; + cell.style.backgroundBrush = backColorBrush; + if (_firstColumn) { + if (!(_totalRow && i == rows.count)) { + if (j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } else if (j == 2) { + cell.style.borders.left = whitePen; + } + } + } + if (_bandedColumn) { + if (j > 1) { + cell.style.borders.left = whitePen; + } + } + if (_bandedRow) { + cell.style.borders.top = whitePen; + } + if (_totalRow && i == rows.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = whitePen; + if (_headerRow) { + if (_firstColumn && j == 1) { + cell.style.borders.top = emptyPen; + } + if (_lastColumn && j == row.cells.count) { + cell.style.borders.top = emptyPen; + } + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.left = whitePen; + } + } + } + } + } + + void _applyListTable6Colorful( + PdfColor borderColor, + PdfColor backColor, + PdfColor textColor, + ) { + final PdfBrush backColorBrush = PdfSolidBrush(backColor); + final PdfPen borderColorPen = PdfPen(borderColor, width: 0.5); + final PdfPen backColorPen = PdfPen(backColor, width: 0.5); + final PdfPen emptyPen = PdfPen(PdfColor.empty, width: 0.5); + final PdfBrush textBrush = PdfSolidBrush(textColor); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.borders.top = borderColorPen; + cell.style.textBrush = textBrush; + if (_headerRow) { + if (_bandedColumn) { + if (!(_lastColumn && j == row.cells.count)) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + } + if (cell.style.backgroundBrush != null) { + cell.style.borders.left = backColorPen; + cell.style.borders.right = backColorPen; + } + } + + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.bottom = borderColorPen; + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + if (i == 1 && _headerRow) { + cell.style.borders.top = borderColorPen; + } + } + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backColorBrush; + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + if (i == 1) { + cell.style.borders.top = borderColorPen; + } + } + } + if (_firstColumn && j == 1) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + cell.style.borders.top = borderColorPen; + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backColorBrush; + } + } + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.left = emptyPen; + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.textBrush = textBrush; + cell.style.borders.all = emptyPen; + if (headers.count == 0 && i == 1) { + cell.style.borders.top = borderColorPen; + } + if (i == rows.count) { + cell.style.borders.bottom = borderColorPen; + } + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + } + if (i == 1 && _headerRow) { + cell.style.borders.top = borderColorPen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.left = backColorPen; + cell.style.borders.right = backColorPen; + if (i == 1 && _headerRow) { + cell.style.borders.top = borderColorPen; + } + } + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (j == 1) { + cell.style.borders.left = backColorPen; + } else if (j == row.cells.count) { + cell.style.borders.right = backColorPen; + } + if (i == 1 && _headerRow) { + cell.style.borders.top = borderColorPen; + } + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + } + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.left = emptyPen; + cell.style.borders.right = emptyPen; + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.right = backColorPen; + } + } + + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + if (i == 1 && _headerRow) { + cell.style.borders.top = borderColorPen; + } + } else if (_bandedColumn) { + cell.style.backgroundBrush = null; + } + } + if (_totalRow && i == rows.count) { + cell.style.backgroundBrush = null; + cell.style.borders.left = emptyPen; + cell.style.borders.right = emptyPen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _changeFontStyle(font); + cell.style.borders.top = PdfPen(borderColor); + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + } + if (cell.style.backgroundBrush != null) { + cell.style.borders.left = backColorPen; + cell.style.borders.right = backColorPen; + } + } + } + } + } + } + + void _applyListTable7Colorful( + PdfColor borderColor, + PdfColor backColor, + PdfColor textColor, + ) { + final PdfPen borderPen = PdfPen(borderColor, width: 0.5); + final PdfPen emptyPen = PdfPen(PdfColor.empty); + final PdfBrush backBrush = PdfSolidBrush(backColor); + final PdfPen backColorPen = PdfPen(backColor, width: 0.5); + final PdfBrush textBrush = PdfSolidBrush(textColor); + + if (headers.count > 0) { + for (int i = 1; i <= headers.count; i++) { + final PdfGridRow row = headers[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.textBrush = textBrush; + if (_headerRow) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + if (font.style != PdfFontStyle.italic) { + cell.style.font = _createItalicFont(font); + } + if (i == 1) { + cell.style.borders.bottom = borderPen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backColorPen; + } + } + if (_bandedRow) { + if (i % 2 != 0) { + cell.style.backgroundBrush = backBrush; + cell.style.borders.all = backColorPen; + } + } + if (_firstColumn && j == 1) { + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + cell.style.borders.right = borderPen; + } + if (_lastColumn && j == row.cells.count) { + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + cell.style.borders.all = emptyPen; + cell.style.borders.left = borderPen; + } + + if (_firstColumn && j == 2) { + cell.style.borders.left = borderPen; + } + } + } + } + } + + for (int i = 1; i <= rows.count; i++) { + final PdfGridRow row = rows[i - 1]; + for (int j = 1; j <= row.cells.count; j++) { + final PdfGridCell cell = row.cells[j - 1]; + cell.style.borders.all = emptyPen; + cell.style.textBrush = textBrush; + + if (_bandedColumn && _bandedRow) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + + cell.style.backgroundBrush ??= _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backColorPen; + } + } else { + if (_bandedColumn) { + cell.style.backgroundBrush = _applyBandedColStyle( + _firstColumn, + backColor, + j, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backColorPen; + } + } + if (_bandedRow) { + cell.style.backgroundBrush = _applyBandedRowStyle( + _headerRow, + backColor, + i, + ); + if (cell.style.backgroundBrush != null) { + cell.style.borders.all = backColorPen; + } + } + } + if (_firstColumn && j == 1) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + cell.style.borders.all = emptyPen; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + cell.style.borders.right = borderPen; + } + } + + if (_firstColumn && j == 2) { + cell.style.borders.all = emptyPen; + cell.style.borders.left = borderPen; + } + + if (_totalRow && i == rows.count) { + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + if (font.style != PdfFontStyle.italic) { + cell.style.font = _createItalicFont(font); + } + cell.style.borders.all = emptyPen; + cell.style.borders.top = borderPen; + cell.style.backgroundBrush = null; + } + if (_lastColumn && j == row.cells.count) { + if (!(_totalRow && i == rows.count)) { + cell.style.backgroundBrush = null; + final PdfFont font = + cell.style.font ?? + row.style.font ?? + PdfGridRowHelper.getHelper(row).grid.style.font ?? + _helper.defaultFont; + cell.style.font = _createItalicFont(font); + cell.style.borders.all = emptyPen; + cell.style.borders.left = borderPen; + } + } + if (_headerRow && i == 1) { + cell.style.borders.top = borderPen; + } + } + } + } +} + +/// [PdfGrid] helper +class PdfGridHelper { + /// internal constructor + PdfGridHelper(this.base); + + /// internal field + PdfGrid base; + + /// internal method + static PdfGridHelper getHelper(PdfGrid base) { + return base._helper; + } + + /// internal method + late PdfBorders defaultBorder; + + /// internal method + late bool isPageWidth; + + /// internal method + bool? isChildGrid; + + /// internal method + late bool hasRowSpan; + + /// internal method + late bool hasColumnSpan; + + /// internal method + late bool isSingleGrid; + + /// internal method + late bool isComplete; + + /// Gets a value indicating whether the start cell layout event should be raised. + bool get raiseBeginCellLayout => base.beginCellLayout != null; + + /// internal method/// Gets a value indicating whether the end cell layout event should be raised. + bool get raiseEndCellLayout => base.endCellLayout != null; + + /// internal method + late bool isBuiltinStyle; + + /// internal method + late bool isRearranged; + + /// internal method + late bool isDrawn; + + /// internal method + late bool isWidthSet; + + /// internal method + late PdfSize gridSize; + + /// internal method + late double rowLayoutBoundswidth; + + /// internal method + late double initialWidth; + + /// internal method + late PdfFont defaultFont; + + /// internal method + PdfLayoutFormat? layoutFormat; + + /// internal method + late int parentCellIndex; + + /// internal method + late List listOfNavigatePages; + + /// internal method + PdfGridBuiltInStyle? gridBuiltinStyle; + + /// internal method + PdfGridCell? parentCell; + + /// internal method + PdfSize get size { + if (gridSize == PdfSize.empty) { + gridSize = _measure(); + } + return gridSize; + } + + /// internal method + PdfSize _measure() { + double height = 0; + final double width = + PdfGridColumnCollectionHelper.getHelper(base.columns).columnWidth; + for (int i = 0; i < base.headers.count; i++) { + height += base.headers[i].height; + } + for (int i = 0; i < base.rows.count; i++) { + height += base.rows[i].height; + } + return PdfSize(width, height); + } + + /// internal method + void setSpan() { + int colSpan, rowSpan = 1; + int currentCellIndex, currentRowIndex = 0; + int maxSpan = 0; + for (int i = 0; i < base.headers.count; i++) { + final PdfGridRow row = base.headers[i]; + maxSpan = 0; + for (int j = 0; j < row.cells.count; j++) { + final PdfGridCell cell = row.cells[j]; + maxSpan = max(maxSpan, cell.rowSpan); + if (!PdfGridCellHelper.getHelper(cell).isCellMergeContinue && + !PdfGridCellHelper.getHelper(cell).isRowMergeContinue && + (cell.columnSpan > 1 || cell.rowSpan > 1)) { + if (cell.columnSpan + j > row.cells.count) { + throw ArgumentError.value( + 'Invalid span specified at row $j column $i', + ); + } + if (cell.rowSpan + i > base.headers.count) { + throw ArgumentError.value( + 'Invalid span specified at row $j column $i', + ); + } + if (cell.columnSpan > 1 && cell.rowSpan > 1) { + colSpan = cell.columnSpan; + rowSpan = cell.rowSpan; + currentCellIndex = j; + currentRowIndex = i; + while (colSpan > 1) { + currentCellIndex++; + PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) + .isCellMergeContinue = true; + PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) + .isRowMergeContinue = true; + row.cells[currentCellIndex].rowSpan = rowSpan; + colSpan--; + } + currentCellIndex = j; + colSpan = cell.columnSpan; + while (rowSpan > 1) { + currentRowIndex++; + PdfGridCellHelper.getHelper( + base.headers[currentRowIndex].cells[j], + ).isRowMergeContinue = + true; + PdfGridCellHelper.getHelper( + base.headers[currentRowIndex].cells[currentCellIndex], + ).isRowMergeContinue = + true; + rowSpan--; + while (colSpan > 1) { + currentCellIndex++; + PdfGridCellHelper.getHelper( + base.headers[currentRowIndex].cells[currentCellIndex], + ).isCellMergeContinue = + true; + PdfGridCellHelper.getHelper( + base.headers[currentRowIndex].cells[currentCellIndex], + ).isRowMergeContinue = + true; + colSpan--; + } + colSpan = cell.columnSpan; + currentCellIndex = j; + } + } else if (cell.columnSpan > 1 && cell.rowSpan == 1) { + colSpan = cell.columnSpan; + currentCellIndex = j; + while (colSpan > 1) { + currentCellIndex++; + PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) + .isCellMergeContinue = true; + colSpan--; + } + } else if (cell.columnSpan == 1 && cell.rowSpan > 1) { + rowSpan = cell.rowSpan; + currentRowIndex = i; + while (rowSpan > 1) { + currentRowIndex++; + PdfGridCellHelper.getHelper( + base.headers[currentRowIndex].cells[j], + ).isRowMergeContinue = + true; + rowSpan--; + } + } + } + } + PdfGridRowHelper.getHelper(row).maximumRowSpan = maxSpan; + } + colSpan = rowSpan = 1; + currentCellIndex = currentRowIndex = 0; + if (hasColumnSpan || hasRowSpan) { + for (int i = 0; i < base.rows.count; i++) { + final PdfGridRow row = base.rows[i]; + maxSpan = 0; + for (int j = 0; j < row.cells.count; j++) { + final PdfGridCell cell = row.cells[j]; + maxSpan = max(maxSpan, cell.rowSpan); + if (!PdfGridCellHelper.getHelper(cell).isCellMergeContinue && + !PdfGridCellHelper.getHelper(cell).isRowMergeContinue && + (cell.columnSpan > 1 || cell.rowSpan > 1)) { + if (cell.columnSpan + j > row.cells.count) { + throw ArgumentError.value( + 'Invalid span specified at row $j column $i', + ); + } + if (cell.rowSpan + i > base.rows.count) { + throw ArgumentError.value( + 'Invalid span specified at row $j column $i', + ); + } + if (cell.columnSpan > 1 && cell.rowSpan > 1) { + colSpan = cell.columnSpan; + rowSpan = cell.rowSpan; + currentCellIndex = j; + currentRowIndex = i; + while (colSpan > 1) { + currentCellIndex++; + PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) + .isCellMergeContinue = true; + PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) + .isRowMergeContinue = true; + colSpan--; + } + currentCellIndex = j; + colSpan = cell.columnSpan; + while (rowSpan > 1) { + currentRowIndex++; + PdfGridCellHelper.getHelper(base.rows[currentRowIndex].cells[j]) + .isRowMergeContinue = true; + PdfGridCellHelper.getHelper( + base.rows[currentRowIndex].cells[currentCellIndex], + ).isRowMergeContinue = + true; + rowSpan--; + while (colSpan > 1) { + currentCellIndex++; + PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper( + base.rows[currentRowIndex], + ).cells![currentCellIndex], + ).isCellMergeContinue = + true; + PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper( + base.rows[currentRowIndex], + ).cells![currentCellIndex], + ).isRowMergeContinue = + true; + colSpan--; + } + colSpan = cell.columnSpan; + currentCellIndex = j; + } + } else if (cell.columnSpan > 1 && cell.rowSpan == 1) { + colSpan = cell.columnSpan; + currentCellIndex = j; + while (colSpan > 1) { + currentCellIndex++; + PdfGridCellHelper.getHelper(row.cells[currentCellIndex]) + .isCellMergeContinue = true; + colSpan--; + } + } else if (cell.columnSpan == 1 && cell.rowSpan > 1) { + rowSpan = cell.rowSpan; + currentRowIndex = i; + while (rowSpan > 1) { + currentRowIndex++; + PdfGridCellHelper.getHelper(base.rows[currentRowIndex].cells[j]) + .isRowMergeContinue = true; + rowSpan--; + } + } + } + } + PdfGridRowHelper.getHelper(row).maximumRowSpan = maxSpan; + } + } + } + + /// internal method + void measureColumnsWidth([PdfRectangle? bounds]) { + if (bounds == null) { + List widths = List.filled(base.columns.count, 0); + double cellWidth = 0; + if (base.headers.count > 0) { + for (int i = 0; i < base.headers[0].cells.count; i++) { + for (int j = 0; j < base.headers.count; j++) { + cellWidth = max( + cellWidth, + initialWidth > 0.0 + ? min(initialWidth, base.headers[j].cells[i].width) + : base.headers[j].cells[i].width, + ); + } + widths[i] = cellWidth; + } + } + cellWidth = 0; + for (int i = 0; i < base.columns.count; i++) { + for (int j = 0; j < base.rows.count; j++) { + final bool isGrid = + base.rows[j].cells[i].value != null && + base.rows[j].cells[i].value is PdfGrid; + if ((base.rows[j].cells[i].columnSpan == 1 && + !PdfGridCellHelper.getHelper( + base.rows[j].cells[i], + ).isCellMergeContinue) || + isGrid) { + if (isGrid && + !PdfGridRowHelper.getHelper( + base.rows[j], + ).grid.style.allowHorizontalOverflow && + initialWidth != 0) { + PdfGridHelper.getHelper(base.rows[j].cells[i].value as PdfGrid) + .initialWidth = initialWidth - + (PdfGridRowHelper.getHelper( + base.rows[j], + ).grid.style.cellPadding.right + + PdfGridRowHelper.getHelper( + base.rows[j], + ).grid.style.cellPadding.left + + base.rows[j].cells[i].style.borders.left.width / 2 + + base._gridLocation.x); + } + cellWidth = max( + widths[i]!, + max( + cellWidth, + initialWidth > 0.0 + ? min(initialWidth, base.rows[j].cells[i].width) + : base.rows[j].cells[i].width, + ), + ); + cellWidth = max(base.columns[i].width, cellWidth); + } + } + if (base.rows.count != 0) { + widths[i] = cellWidth; + } + cellWidth = 0; + } + for (int i = 0; i < base.rows.count; i++) { + for (int j = 0; j < base.columns.count; j++) { + if (base.rows[i].cells[j].columnSpan > 1) { + double totalWidth = widths[j]!; + for (int k = 1; k < base.rows[i].cells[j].columnSpan; k++) { + totalWidth = totalWidth + widths[j + k]!; + } + if (base.rows[i].cells[j].width > totalWidth) { + double extendedWidth = base.rows[i].cells[j].width - totalWidth; + extendedWidth = extendedWidth / base.rows[i].cells[j].columnSpan; + for (int k = j; k < j + base.rows[i].cells[j].columnSpan; k++) { + widths[k] = widths[k]! + extendedWidth; + } + } + } + } + } + if (isChildGrid! && initialWidth != 0) { + widths = PdfGridColumnCollectionHelper.getHelper( + base.columns, + ).getDefaultWidths(initialWidth); + } + for (int i = 0; i < base.columns.count; i++) { + if (base.columns[i].width < 0 || + (base.columns[i].width > 0 && + !PdfGridColumnHelper.getHelper( + base.columns[i], + ).isCustomWidth)) { + PdfGridColumnHelper.getHelper(base.columns[i]).width = widths[i]!; + } + } + } else { + List widths = PdfGridColumnCollectionHelper.getHelper( + base.columns, + ).getDefaultWidths(bounds.width - bounds.x); + for (int i = 0; i < base.columns.count; i++) { + if (base.columns[i].width < 0) { + PdfGridColumnHelper.getHelper(base.columns[i]).width = widths[i]!; + } else if (base.columns[i].width > 0 && + !PdfGridColumnHelper.getHelper(base.columns[i]).isCustomWidth && + widths[i]! > 0 && + isComplete) { + PdfGridColumnHelper.getHelper(base.columns[i]).width = widths[i]!; + } + } + if (parentCell != null && + (!base.style.allowHorizontalOverflow) && + (!PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(parentCell!).row!, + ).grid.style.allowHorizontalOverflow)) { + double padding = 0; + double columnWidth = 0; + int columnCount = base.columns.count; + if (parentCell!.style.cellPadding != null) { + padding += + parentCell!.style.cellPadding!.left + + parentCell!.style.cellPadding!.right; + } else { + padding += + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(parentCell!).row!, + ).grid.style.cellPadding.left + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(parentCell!).row!, + ).grid.style.cellPadding.right; + } + for (int i = 0; i < parentCell!.columnSpan; i++) { + columnWidth += + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(parentCell!).row!, + ).grid.columns[parentCellIndex + i].width; + } + for (int i = 0; i < base.columns.count; i++) { + if (base.columns[i].width > 0 && + PdfGridColumnHelper.getHelper(base.columns[i]).isCustomWidth) { + columnWidth -= base.columns[i].width; + columnCount--; + } + } + if (columnWidth > padding) { + final double childGridColumnWidth = + (columnWidth - padding) / columnCount; + if (parentCell != null && + parentCell!.stringFormat.alignment != PdfTextAlignment.right) { + for (int j = 0; j < base.columns.count; j++) { + if (!PdfGridColumnHelper.getHelper( + base.columns[j], + ).isCustomWidth) { + PdfGridColumnHelper.getHelper(base.columns[j]).width = + childGridColumnWidth; + } + } + } + } + } + if (parentCell != null && + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(parentCell!).row!, + ).getWidth() > + 0) { + if (isChildGrid! && + size.width > + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(parentCell!).row!, + ).getWidth()) { + widths = PdfGridColumnCollectionHelper.getHelper( + base.columns, + ).getDefaultWidths(bounds.width); + for (int i = 0; i < base.columns.count; i++) { + base.columns[i].width = widths[i]!; + } + } + } + } + } + + /// internal method + void onBeginCellLayout(PdfGridBeginCellLayoutArgs args) { + if (raiseBeginCellLayout) { + base.beginCellLayout!(base, args); + } + } + + /// internal method + void onEndCellLayout(PdfGridEndCellLayoutArgs args) { + if (raiseEndCellLayout) { + base.endCellLayout!(base, args); + } + } + + /// internal method + void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { + setSpan(); + final PdfGridLayouter layouter = PdfGridLayouter(base); + layouter.layoutGrid(graphics, bounds); + isComplete = true; + } + + /// internal method + PdfLayoutResult? layout(PdfLayoutParams param) { + if (param.bounds!.width < 0) { + ArgumentError.value('width', 'width', 'out of range'); + } + if (base.rows.count != 0) { + final PdfBorders borders = base.rows[0].cells[0].style.borders; + if (borders.left.width != 1) { + final double x = borders.left.width / 2; + final double y = borders.top.width / 2; + if (param.bounds!.x == defaultBorder.right.width / 2 && + param.bounds!.y == defaultBorder.right.width / 2) { + param.bounds = PdfRectangle(x, y, size.width, size.height); + } + } + } + setSpan(); + layoutFormat = param.format; + base._gridLocation = param.bounds!; + return PdfGridLayouter(base).layoutInternal(param); + } + + /// internal method + void applyBuiltinStyles(PdfGridBuiltInStyle? gridStyle) { + switch (gridStyle) { + case PdfGridBuiltInStyle.tableGrid: + base._applyTableGridLight(PdfColor(0, 0, 0)); + break; + + case PdfGridBuiltInStyle.tableGridLight: + base._applyTableGridLight(PdfColor(191, 191, 191)); + break; + + case PdfGridBuiltInStyle.plainTable1: + base._applyPlainTable1( + PdfColor(191, 191, 191), + PdfColor(242, 242, 242), + ); + break; + + case PdfGridBuiltInStyle.plainTable2: + base._applyPlainTable2(PdfColor(127, 127, 127)); + break; + + case PdfGridBuiltInStyle.plainTable3: + base._applyPlainTable3( + PdfColor(127, 127, 127), + PdfColor(242, 242, 242), + ); + break; + + case PdfGridBuiltInStyle.plainTable4: + base._applyPlainTable4(PdfColor(242, 242, 242)); + break; + + case PdfGridBuiltInStyle.plainTable5: + base._applyPlainTable5( + PdfColor(127, 127, 127), + PdfColor(242, 242, 242), + ); + break; + case PdfGridBuiltInStyle.gridTable1Light: + base._applyGridTable1Light( + PdfColor(153, 153, 153), + PdfColor(102, 102, 102), + ); + break; + + case PdfGridBuiltInStyle.gridTable1LightAccent1: + base._applyGridTable1Light( + PdfColor(189, 214, 238), + PdfColor(156, 194, 229), + ); + break; + + case PdfGridBuiltInStyle.gridTable1LightAccent2: + base._applyGridTable1Light( + PdfColor(247, 202, 172), + PdfColor(244, 176, 131), + ); + break; + + case PdfGridBuiltInStyle.gridTable1LightAccent3: + base._applyGridTable1Light( + PdfColor(219, 219, 219), + PdfColor(201, 201, 201), + ); + break; + + case PdfGridBuiltInStyle.gridTable1LightAccent4: + base._applyGridTable1Light( + PdfColor(255, 229, 153), + PdfColor(255, 217, 102), + ); + break; + + case PdfGridBuiltInStyle.gridTable1LightAccent5: + base._applyGridTable1Light( + PdfColor(180, 198, 231), + PdfColor(142, 170, 219), + ); + break; + + case PdfGridBuiltInStyle.gridTable1LightAccent6: + base._applyGridTable1Light( + PdfColor(192, 224, 179), + PdfColor(168, 208, 141), + ); + break; + + case PdfGridBuiltInStyle.gridTable2: + base._applyGridTable2(PdfColor(102, 102, 102), PdfColor(204, 204, 204)); + break; + + case PdfGridBuiltInStyle.gridTable2Accent1: + base._applyGridTable2(PdfColor(156, 194, 229), PdfColor(222, 234, 246)); + break; + + case PdfGridBuiltInStyle.gridTable2Accent2: + base._applyGridTable2(PdfColor(244, 176, 131), PdfColor(251, 228, 213)); + break; + + case PdfGridBuiltInStyle.gridTable2Accent3: + base._applyGridTable2(PdfColor(201, 201, 201), PdfColor(237, 237, 237)); + break; + + case PdfGridBuiltInStyle.gridTable2Accent4: + base._applyGridTable2(PdfColor(255, 217, 102), PdfColor(255, 242, 204)); + break; + + case PdfGridBuiltInStyle.gridTable2Accent5: + base._applyGridTable2(PdfColor(142, 170, 219), PdfColor(217, 226, 243)); + break; + + case PdfGridBuiltInStyle.gridTable2Accent6: + base._applyGridTable2(PdfColor(168, 208, 141), PdfColor(226, 239, 217)); + break; + + case PdfGridBuiltInStyle.gridTable3: + base._applyGridTable3(PdfColor(102, 102, 102), PdfColor(204, 204, 204)); + break; + + case PdfGridBuiltInStyle.gridTable3Accent1: + base._applyGridTable3(PdfColor(156, 194, 229), PdfColor(222, 234, 246)); + break; + + case PdfGridBuiltInStyle.gridTable3Accent2: + base._applyGridTable3(PdfColor(244, 176, 131), PdfColor(251, 228, 213)); + break; + + case PdfGridBuiltInStyle.gridTable3Accent3: + base._applyGridTable3(PdfColor(201, 201, 201), PdfColor(237, 237, 237)); + break; + + case PdfGridBuiltInStyle.gridTable3Accent4: + base._applyGridTable3(PdfColor(255, 217, 102), PdfColor(255, 242, 204)); + break; + + case PdfGridBuiltInStyle.gridTable3Accent5: + base._applyGridTable3(PdfColor(142, 170, 219), PdfColor(217, 226, 243)); + break; + + case PdfGridBuiltInStyle.gridTable3Accent6: + base._applyGridTable3(PdfColor(168, 208, 141), PdfColor(226, 239, 217)); + break; + + case PdfGridBuiltInStyle.gridTable4: + base._applyGridTable4( + PdfColor(102, 102, 102), + PdfColor(204, 204, 204), + PdfColor(0, 0, 0), + ); + break; + + case PdfGridBuiltInStyle.gridTable4Accent1: + base._applyGridTable4( + PdfColor(156, 194, 229), + PdfColor(222, 234, 246), + PdfColor(91, 155, 213), + ); + break; + + case PdfGridBuiltInStyle.gridTable4Accent2: + base._applyGridTable4( + PdfColor(244, 176, 131), + PdfColor(251, 228, 213), + PdfColor(237, 125, 49), + ); + break; + + case PdfGridBuiltInStyle.gridTable4Accent3: + base._applyGridTable4( + PdfColor(201, 201, 201), + PdfColor(237, 237, 237), + PdfColor(165, 165, 165), + ); + break; + + case PdfGridBuiltInStyle.gridTable4Accent4: + base._applyGridTable4( + PdfColor(255, 217, 102), + PdfColor(255, 242, 204), + PdfColor(255, 192, 0), + ); + break; + + case PdfGridBuiltInStyle.gridTable4Accent5: + base._applyGridTable4( + PdfColor(142, 170, 219), + PdfColor(217, 226, 243), + PdfColor(68, 114, 196), + ); + break; + + case PdfGridBuiltInStyle.gridTable4Accent6: + base._applyGridTable4( + PdfColor(168, 208, 141), + PdfColor(226, 239, 217), + PdfColor(112, 173, 71), + ); + break; + + case PdfGridBuiltInStyle.gridTable5Dark: + base._applyGridTable5Dark( + PdfColor(0, 0, 0), + PdfColor(153, 153, 153), + PdfColor(204, 204, 204), + ); + break; + + case PdfGridBuiltInStyle.gridTable5DarkAccent1: + base._applyGridTable5Dark( + PdfColor(91, 155, 213), + PdfColor(189, 214, 238), + PdfColor(222, 234, 246), + ); + break; + + case PdfGridBuiltInStyle.gridTable5DarkAccent2: + base._applyGridTable5Dark( + PdfColor(237, 125, 49), + PdfColor(247, 202, 172), + PdfColor(251, 228, 213), + ); + break; + + case PdfGridBuiltInStyle.gridTable5DarkAccent3: + base._applyGridTable5Dark( + PdfColor(165, 165, 165), + PdfColor(219, 219, 219), + PdfColor(237, 237, 237), + ); + break; + + case PdfGridBuiltInStyle.gridTable5DarkAccent4: + base._applyGridTable5Dark( + PdfColor(255, 192, 0), + PdfColor(255, 229, 153), + PdfColor(255, 242, 204), + ); + break; + + case PdfGridBuiltInStyle.gridTable5DarkAccent5: + base._applyGridTable5Dark( + PdfColor(68, 114, 196), + PdfColor(180, 198, 231), + PdfColor(217, 226, 243), + ); + break; + + case PdfGridBuiltInStyle.gridTable5DarkAccent6: + base._applyGridTable5Dark( + PdfColor(112, 171, 71), + PdfColor(197, 224, 179), + PdfColor(226, 239, 217), + ); + break; + + case PdfGridBuiltInStyle.gridTable6Colorful: + base._applyGridTable6Colorful( + PdfColor(102, 102, 102), + PdfColor(204, 204, 204), + PdfColor(0, 0, 0), + ); + break; + + case PdfGridBuiltInStyle.gridTable6ColorfulAccent1: + base._applyGridTable6Colorful( + PdfColor(156, 194, 229), + PdfColor(222, 234, 246), + PdfColor(46, 116, 181), + ); + break; + + case PdfGridBuiltInStyle.gridTable6ColorfulAccent2: + base._applyGridTable6Colorful( + PdfColor(244, 176, 131), + PdfColor(251, 228, 213), + PdfColor(196, 89, 17), + ); + break; + + case PdfGridBuiltInStyle.gridTable6ColorfulAccent3: + base._applyGridTable6Colorful( + PdfColor(201, 201, 201), + PdfColor(237, 237, 237), + PdfColor(123, 123, 123), + ); + break; + + case PdfGridBuiltInStyle.gridTable6ColorfulAccent4: + base._applyGridTable6Colorful( + PdfColor(255, 217, 102), + PdfColor(255, 242, 204), + PdfColor(191, 143, 0), + ); + break; + + case PdfGridBuiltInStyle.gridTable6ColorfulAccent5: + base._applyGridTable6Colorful( + PdfColor(142, 170, 219), + PdfColor(217, 226, 243), + PdfColor(47, 84, 150), + ); + break; + + case PdfGridBuiltInStyle.gridTable6ColorfulAccent6: + base._applyGridTable6Colorful( + PdfColor(168, 208, 141), + PdfColor(226, 239, 217), + PdfColor(83, 129, 53), + ); + break; + + case PdfGridBuiltInStyle.gridTable7Colorful: + base._applyGridTable7Colorful( + PdfColor(102, 102, 102), + PdfColor(204, 204, 204), + PdfColor(0, 0, 0), + ); + break; + + case PdfGridBuiltInStyle.gridTable7ColorfulAccent1: + base._applyGridTable7Colorful( + PdfColor(156, 194, 229), + PdfColor(222, 234, 246), + PdfColor(46, 116, 181), + ); + break; + + case PdfGridBuiltInStyle.gridTable7ColorfulAccent2: + base._applyGridTable7Colorful( + PdfColor(244, 176, 131), + PdfColor(251, 228, 213), + PdfColor(196, 89, 17), + ); + break; + + case PdfGridBuiltInStyle.gridTable7ColorfulAccent3: + base._applyGridTable7Colorful( + PdfColor(201, 201, 201), + PdfColor(237, 237, 237), + PdfColor(123, 123, 123), + ); + break; + + case PdfGridBuiltInStyle.gridTable7ColorfulAccent4: + base._applyGridTable7Colorful( + PdfColor(255, 217, 102), + PdfColor(255, 242, 204), + PdfColor(191, 143, 0), + ); + break; + + case PdfGridBuiltInStyle.gridTable7ColorfulAccent5: + base._applyGridTable7Colorful( + PdfColor(142, 170, 219), + PdfColor(217, 226, 243), + PdfColor(47, 84, 150), + ); + break; + + case PdfGridBuiltInStyle.gridTable7ColorfulAccent6: + base._applyGridTable7Colorful( + PdfColor(168, 208, 141), + PdfColor(226, 239, 217), + PdfColor(83, 129, 53), + ); + break; + case PdfGridBuiltInStyle.listTable1Light: + base._applyListTable1Light( + PdfColor(102, 102, 102), + PdfColor(204, 204, 204), + ); + break; + + case PdfGridBuiltInStyle.listTable1LightAccent1: + base._applyListTable1Light( + PdfColor(156, 194, 229), + PdfColor(222, 234, 246), + ); + break; + + case PdfGridBuiltInStyle.listTable1LightAccent2: + base._applyListTable1Light( + PdfColor(244, 176, 131), + PdfColor(251, 228, 213), + ); + break; + + case PdfGridBuiltInStyle.listTable1LightAccent3: + base._applyListTable1Light( + PdfColor(201, 201, 201), + PdfColor(237, 237, 237), + ); + break; + + case PdfGridBuiltInStyle.listTable1LightAccent4: + base._applyListTable1Light( + PdfColor(255, 217, 102), + PdfColor(255, 242, 204), + ); + break; + + case PdfGridBuiltInStyle.listTable1LightAccent5: + base._applyListTable1Light( + PdfColor(142, 170, 219), + PdfColor(217, 226, 243), + ); + break; + + case PdfGridBuiltInStyle.listTable1LightAccent6: + base._applyListTable1Light( + PdfColor(168, 208, 141), + PdfColor(226, 239, 217), + ); + break; + + case PdfGridBuiltInStyle.listTable2: + base._applyListTable2(PdfColor(102, 102, 102), PdfColor(204, 204, 204)); + break; + + case PdfGridBuiltInStyle.listTable2Accent1: + base._applyListTable2(PdfColor(156, 194, 229), PdfColor(222, 234, 246)); + break; + + case PdfGridBuiltInStyle.listTable2Accent2: + base._applyListTable2(PdfColor(244, 176, 131), PdfColor(251, 228, 213)); + break; + + case PdfGridBuiltInStyle.listTable2Accent3: + base._applyListTable2(PdfColor(201, 201, 201), PdfColor(237, 237, 237)); + break; + + case PdfGridBuiltInStyle.listTable2Accent4: + base._applyListTable2(PdfColor(255, 217, 102), PdfColor(255, 242, 204)); + break; + + case PdfGridBuiltInStyle.listTable2Accent5: + base._applyListTable2(PdfColor(142, 170, 219), PdfColor(217, 226, 243)); + break; + + case PdfGridBuiltInStyle.listTable2Accent6: + base._applyListTable2(PdfColor(168, 208, 141), PdfColor(226, 239, 217)); + break; + + case PdfGridBuiltInStyle.listTable3: + base._applyListTable3(PdfColor(0, 0, 0)); + break; + + case PdfGridBuiltInStyle.listTable3Accent1: + base._applyListTable3(PdfColor(91, 155, 213)); + break; + + case PdfGridBuiltInStyle.listTable3Accent2: + base._applyListTable3(PdfColor(237, 125, 49)); + break; + + case PdfGridBuiltInStyle.listTable3Accent3: + base._applyListTable3(PdfColor(165, 165, 165)); + break; + + case PdfGridBuiltInStyle.listTable3Accent4: + base._applyListTable3(PdfColor(255, 192, 0)); + break; + + case PdfGridBuiltInStyle.listTable3Accent5: + base._applyListTable3(PdfColor(68, 114, 196)); + break; + + case PdfGridBuiltInStyle.listTable3Accent6: + base._applyListTable3(PdfColor(112, 171, 71)); + break; + + case PdfGridBuiltInStyle.listTable4: + base._applyListTable4( + PdfColor(102, 102, 102), + PdfColor(0, 0, 0), + PdfColor(204, 204, 204), + ); + break; + + case PdfGridBuiltInStyle.listTable4Accent1: + base._applyListTable4( + PdfColor(156, 194, 229), + PdfColor(91, 155, 213), + PdfColor(222, 234, 246), + ); + break; + + case PdfGridBuiltInStyle.listTable4Accent2: + base._applyListTable4( + PdfColor(244, 176, 131), + PdfColor(237, 125, 49), + PdfColor(251, 228, 213), + ); + break; + + case PdfGridBuiltInStyle.listTable4Accent3: + base._applyListTable4( + PdfColor(201, 201, 201), + PdfColor(165, 165, 165), + PdfColor(237, 237, 237), + ); + break; + + case PdfGridBuiltInStyle.listTable4Accent4: + base._applyListTable4( + PdfColor(255, 217, 102), + PdfColor(255, 192, 0), + PdfColor(255, 242, 204), + ); + break; + + case PdfGridBuiltInStyle.listTable4Accent5: + base._applyListTable4( + PdfColor(142, 170, 219), + PdfColor(68, 114, 196), + PdfColor(217, 226, 243), + ); + break; + + case PdfGridBuiltInStyle.listTable4Accent6: + base._applyListTable4( + PdfColor(168, 208, 141), + PdfColor(112, 173, 71), + PdfColor(226, 239, 217), + ); + break; + + case PdfGridBuiltInStyle.listTable5Dark: + base._applyListTable5Dark(PdfColor(0, 0, 0)); + break; + + case PdfGridBuiltInStyle.listTable5DarkAccent1: + base._applyListTable5Dark(PdfColor(91, 155, 213)); + break; + + case PdfGridBuiltInStyle.listTable5DarkAccent2: + base._applyListTable5Dark(PdfColor(237, 125, 49)); + break; + + case PdfGridBuiltInStyle.listTable5DarkAccent3: + base._applyListTable5Dark(PdfColor(165, 165, 165)); + break; + + case PdfGridBuiltInStyle.listTable5DarkAccent4: + base._applyListTable5Dark(PdfColor(255, 192, 0)); + break; + + case PdfGridBuiltInStyle.listTable5DarkAccent5: + base._applyListTable5Dark(PdfColor(68, 114, 196)); + break; + + case PdfGridBuiltInStyle.listTable5DarkAccent6: + base._applyListTable5Dark(PdfColor(112, 173, 71)); + break; + + case PdfGridBuiltInStyle.listTable6Colorful: + base._applyListTable6Colorful( + PdfColor(102, 102, 102), + PdfColor(204, 204, 204), + PdfColor(0, 0, 0), + ); + break; + + case PdfGridBuiltInStyle.listTable6ColorfulAccent1: + base._applyListTable6Colorful( + PdfColor(91, 155, 213), + PdfColor(222, 234, 246), + PdfColor(46, 116, 181), + ); + break; + + case PdfGridBuiltInStyle.listTable6ColorfulAccent2: + base._applyListTable6Colorful( + PdfColor(237, 125, 49), + PdfColor(251, 228, 213), + PdfColor(196, 89, 17), + ); + break; + + case PdfGridBuiltInStyle.listTable6ColorfulAccent3: + base._applyListTable6Colorful( + PdfColor(165, 165, 165), + PdfColor(237, 237, 237), + PdfColor(123, 123, 123), + ); + break; + + case PdfGridBuiltInStyle.listTable6ColorfulAccent4: + base._applyListTable6Colorful( + PdfColor(255, 192, 0), + PdfColor(255, 242, 204), + PdfColor(191, 143, 0), + ); + break; + + case PdfGridBuiltInStyle.listTable6ColorfulAccent5: + base._applyListTable6Colorful( + PdfColor(68, 114, 196), + PdfColor(217, 226, 243), + PdfColor(47, 84, 150), + ); + break; + + case PdfGridBuiltInStyle.listTable6ColorfulAccent6: + base._applyListTable6Colorful( + PdfColor(112, 173, 71), + PdfColor(226, 239, 217), + PdfColor(83, 129, 53), + ); + break; + + case PdfGridBuiltInStyle.listTable7Colorful: + base._applyListTable7Colorful( + PdfColor(102, 102, 102), + PdfColor(204, 204, 204), + PdfColor(0, 0, 0), + ); + break; + + case PdfGridBuiltInStyle.listTable7ColorfulAccent1: + base._applyListTable7Colorful( + PdfColor(91, 155, 213), + PdfColor(222, 234, 246), + PdfColor(46, 116, 181), + ); + break; + + case PdfGridBuiltInStyle.listTable7ColorfulAccent2: + base._applyListTable7Colorful( + PdfColor(237, 125, 49), + PdfColor(251, 228, 213), + PdfColor(196, 89, 17), + ); + break; + + case PdfGridBuiltInStyle.listTable7ColorfulAccent3: + base._applyListTable7Colorful( + PdfColor(165, 165, 165), + PdfColor(237, 237, 237), + PdfColor(123, 123, 123), + ); + break; + + case PdfGridBuiltInStyle.listTable7ColorfulAccent4: + base._applyListTable7Colorful( + PdfColor(255, 192, 0), + PdfColor(255, 242, 204), + PdfColor(191, 143, 0), + ); + break; + + case PdfGridBuiltInStyle.listTable7ColorfulAccent5: + base._applyListTable7Colorful( + PdfColor(68, 114, 196), + PdfColor(217, 226, 243), + PdfColor(47, 84, 150), + ); + break; + + case PdfGridBuiltInStyle.listTable7ColorfulAccent6: + base._applyListTable7Colorful( + PdfColor(112, 173, 71), + PdfColor(226, 239, 217), + PdfColor(83, 129, 53), + ); + break; + + // ignore: no_default_cases + default: + } + } +} + +/// Delegate for handling StartCellLayoutEvent. +typedef PdfGridBeginCellLayoutCallback = + void Function(Object sender, PdfGridBeginCellLayoutArgs args); + +/// Delegate for handling EndCellLayoutEvent. +typedef PdfGridEndCellLayoutCallback = + void Function(Object sender, PdfGridEndCellLayoutArgs args); + +/// Represents arguments of StartCellLayout Event. +class PdfGridBeginCellLayoutArgs extends GridCellLayoutArgs { + //Constructor + PdfGridBeginCellLayoutArgs._( + PdfGraphics graphics, + int rowIndex, + int cellInder, + PdfRectangle bounds, + String value, + PdfGridCellStyle? style, + bool isHeaderRow, + ) : super._(graphics, rowIndex, cellInder, bounds, value, isHeaderRow) { + if (style != null) { + this.style = style; + } + skip = false; + } + //Fields + /// PDF grid cell style + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// //Apply the cell style to specific row cells + /// row.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridCellStyle? style; + + /// A value that indicates whether the cell is drawn or not in the PDF document. + late bool skip; +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfGridBeginCellLayoutArgs] helper +class PdfGridBeginCellLayoutArgsHelper { + /// internal method + static PdfGridBeginCellLayoutArgs load( + PdfGraphics graphics, + int rowIndex, + int cellInder, + PdfRectangle bounds, + String value, + PdfGridCellStyle? style, + bool isHeaderRow, + ) { + return PdfGridBeginCellLayoutArgs._( + graphics, + rowIndex, + cellInder, + bounds, + value, + style, + isHeaderRow, + ); + } +} + +/// Represents arguments of EndCellLayout Event. +class PdfGridEndCellLayoutArgs extends GridCellLayoutArgs { + //Constructor + PdfGridEndCellLayoutArgs._( + PdfGraphics graphics, + int rowIndex, + int cellInder, + PdfRectangle bounds, + String value, + PdfGridCellStyle? style, + bool isHeaderRow, + ) : super._(graphics, rowIndex, cellInder, bounds, value, isHeaderRow) { + if (style != null) { + this.style = style; + } + } + //Fields + /// PDF grid cell style + PdfGridCellStyle? style; +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfGridEndCellLayoutArgs] helper +class PdfGridEndCellLayoutArgsHelper { + /// internal method + static PdfGridEndCellLayoutArgs load( + PdfGraphics graphics, + int rowIndex, + int cellInder, + PdfRectangle bounds, + String value, + PdfGridCellStyle? style, + bool isHeaderRow, + ) { + return PdfGridEndCellLayoutArgs._( + graphics, + rowIndex, + cellInder, + bounds, + value, + style, + isHeaderRow, + ); + } +} + +/// Represents the abstract class of the [GridCellLayoutArgs]. +abstract class GridCellLayoutArgs { + //Constructors + /// Initializes a new instance of the [StartCellLayoutArgs] class. + GridCellLayoutArgs._( + PdfGraphics graphics, + int rowIndex, + int cellIndex, + PdfRectangle bounds, + String value, + bool isHeaderRow, + ) { + _rowIndex = rowIndex; + _cellIndex = cellIndex; + _value = value; + _bounds = bounds.rect; + _graphics = graphics; + _isHeaderRow = isHeaderRow; + } + + //Fields + late int _rowIndex; + late int _cellIndex; + late String _value; + late Rect _bounds; + late PdfGraphics _graphics; + late bool _isHeaderRow; + + //Properties + /// Gets the index of the row. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on starting cell lay outing. + /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get rowIndex => _rowIndex; + + /// Gets the index of the cell. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on starting cell lay outing. + /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get cellIndex => _cellIndex; + + /// Gets the value. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on starting cell lay outing. + /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String get value => _value; + + /// Gets the bounds of the cell. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on starting cell lay outing. + /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + Rect get bounds => _bounds; + + /// Gets the graphics, on which the cell should be drawn. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on starting cell lay outing. + /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGraphics get graphics => _graphics; + + /// Gets the type of Grid row. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// // Sets the event raised on starting cell lay outing. + /// grid.beginCellLayout = (Object sender, PdfGridBeginCellLayoutArgs args) { + /// if (args.rowIndex == 1 && args.cellIndex == 1) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// if (args.isHeaderRow && args.cellIndex == 0) { + /// args.graphics.drawRectangle( + /// pen: PdfPen(PdfColor(250, 100, 0), width: 2), + /// brush: PdfBrushes.white, + /// bounds: args.bounds); + /// } + /// }; + /// grid.style.cellPadding = PdfPaddings(); + /// grid.style.cellPadding.all = 15; + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool get isHeaderRow => _isHeaderRow; +} + +/// Arguments of BeginPageLayoutEvent. +class PdfGridBeginPageLayoutArgs extends BeginPageLayoutArgs { + //Constructor + PdfGridBeginPageLayoutArgs._(super.bounds, super.page, int? startRow) { + startRowIndex = startRow ?? 0; + } + + //Fields + /// Gets the start row index. + late int startRowIndex; +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfGridBeginPageLayoutArgs] helper +class PdfGridBeginPageLayoutArgsHelper { + /// internal method + static PdfGridBeginPageLayoutArgs load( + Rect bounds, + PdfPage page, + int? startRow, + ) { + return PdfGridBeginPageLayoutArgs._(bounds, page, startRow); + } +} + +/// Arguments of EndPageLayoutEvent. +class PdfGridEndPageLayoutArgs extends EndPageLayoutArgs { + //Constructor + PdfGridEndPageLayoutArgs._(super.result); +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfGridEndPageLayoutArgs] helper +class PdfGridEndPageLayoutArgsHelper { + /// internal method + static PdfGridEndPageLayoutArgs load(PdfLayoutResult result) { + return PdfGridEndPageLayoutArgs._(result); + } +} + +/// Represents the grid built-in style settings. +class PdfGridBuiltInStyleSettings { + // Constructor + /// Represents the grid built-in style settings. + PdfGridBuiltInStyleSettings({ + this.applyStyleForBandedColumns = false, + this.applyStyleForBandedRows = true, + this.applyStyleForFirstColumn = false, + this.applyStyleForHeaderRow = true, + this.applyStyleForLastColumn = false, + this.applyStyleForLastRow = false, + }); + + //Fields + /// Gets or sets a value indicating whether to apply style bands to the columns in a table. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// PdfGridBuiltInStyleSettings tableStyleOption = + /// PdfGridBuiltInStyleSettings(); + /// //Sets applyStyleForBandedColumns + /// tableStyleOption.applyStyleForBandedColumns = true; + ///Apply built-in table style + /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, + /// settings: tableStyleOption); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool applyStyleForBandedColumns; + + /// Gets or sets a value indicating whether to apply style bands to the rows in a table. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// PdfGridBuiltInStyleSettings tableStyleOption = + /// PdfGridBuiltInStyleSettings(); + /// //Sets applyStyleForBandedRows + /// tableStyleOption.applyStyleForBandedRows = true; + ///Apply built-in table style + /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, + /// settings: tableStyleOption); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool applyStyleForBandedRows; + + /// Gets or sets a value indicating whether to apply first-column formatting to the first column of the specified table. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// PdfGridBuiltInStyleSettings tableStyleOption = + /// PdfGridBuiltInStyleSettings(); + /// //Sets applyStyleForFirstColumn + /// tableStyleOption.applyStyleForFirstColumn = true; + ///Apply built-in table style + /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, + /// settings: tableStyleOption); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool applyStyleForFirstColumn; + + /// Gets or sets a value indicating whether to apply heading-row formatting to the first row of the table. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// PdfGridBuiltInStyleSettings tableStyleOption = + /// PdfGridBuiltInStyleSettings(); + /// //Sets applyStyleForHeaderRow + /// tableStyleOption.applyStyleForHeaderRow = true; + ///Apply built-in table style + /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, + /// settings: tableStyleOption); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool applyStyleForHeaderRow; + + /// Gets or sets a value indicating whether to apply first-column formatting to the first column of the specified table. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// PdfGridBuiltInStyleSettings tableStyleOption = + /// PdfGridBuiltInStyleSettings(); + /// //Sets applyStyleForLastColumn + /// tableStyleOption.applyStyleForLastColumn = true; + ///Apply built-in table style + /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, + /// settings: tableStyleOption); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool applyStyleForLastColumn; + + /// Gets or sets a value indicating whether to apply last-row formatting to the last row of the specified table. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid class + /// PdfGrid grid = PdfGrid(); + /// //Add the columns to the grid + /// grid.columns.add(count: 3); + /// //Add header to the grid + /// grid.headers.add(1); + /// //Add the rows to the grid + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row = grid.rows.add(); + /// row.cells[0].value = 'E01'; + /// row.cells[1].value = 'Clay'; + /// row.cells[2].value = '\$10,000'; + /// row = grid.rows.add(); + /// row.cells[0].value = 'E02'; + /// row.cells[1].value = 'Simon'; + /// row.cells[2].value = '\$12,000'; + /// PdfGridBuiltInStyleSettings tableStyleOption = + /// PdfGridBuiltInStyleSettings(); + /// //Sets applyStyleForLastRow + /// tableStyleOption.applyStyleForLastRow = true; + ///Apply built-in table style + /// grid.applyBuiltInStyle(PdfGridBuiltInStyle.listTable6ColorfulAccent1, + /// settings: tableStyleOption); + /// //Draw the grid + /// grid.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool applyStyleForLastRow; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_cell.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_cell.dart index cfeccca84..cce4a5be8 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_cell.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_cell.dart @@ -1,2141 +1,2141 @@ -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/brushes/pdf_brush.dart'; -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/enums.dart'; -import '../../graphics/figures/base/element_layouter.dart'; -import '../../graphics/figures/base/text_layouter.dart'; -import '../../graphics/figures/enums.dart'; -import '../../graphics/figures/pdf_template.dart'; -import '../../graphics/figures/pdf_text_element.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_string_format.dart'; -import '../../graphics/fonts/pdf_string_layout_result.dart'; -import '../../graphics/fonts/pdf_string_layouter.dart'; -import '../../graphics/images/pdf_image.dart'; -import '../../graphics/pdf_color.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../graphics/pdf_pen.dart'; -import '../../pages/pdf_page.dart'; -import 'enums.dart'; -import 'layouting/pdf_grid_layouter.dart'; -import 'pdf_grid.dart'; -import 'pdf_grid_row.dart'; -import 'styles/pdf_borders.dart'; -import 'styles/style.dart'; - -/// Represents the schema of a cell in a [PdfGrid]. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid -/// PdfGrid grid = PdfGrid(); -/// //Add columns to grid -/// grid.columns.add(count: 3); -/// //Add headers to grid -/// PdfGridRow header = grid.headers.add(1)[0]; -/// header.cells[0].value = 'Employee ID'; -/// header.cells[1].value = 'Employee Name'; -/// header.cells[2].value = 'Salary'; -/// //Add rows to grid -/// PdfGridRow row1 = grid.rows.add(); -/// row1.cells[0].value = 'E01'; -/// row1.cells[1].value = 'Clay'; -/// //Apply the cell style to specific row cells -/// row1.cells[0].style = PdfGridCellStyle( -/// backgroundBrush: PdfBrushes.lightYellow, -/// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), -/// textBrush: PdfBrushes.white, -/// textPen: PdfPens.orange, -/// ); -/// PdfGridCell gridCell = PdfGridCell( -/// row: row1, -/// format: PdfStringFormat( -/// alignment: PdfTextAlignment.center, -/// lineAlignment: PdfVerticalAlignment.bottom, -/// wordSpacing: 10)); -/// gridCell.value = '\$10,000'; -/// row1.cells[2].value = gridCell.value; -/// row1.cells[2].stringFormat = gridCell.stringFormat; -/// PdfGridRow row2 = grid.rows.add(); -/// row2.cells[0].value = 'E02'; -/// row2.cells[1].value = 'Simon'; -/// row2.cells[2].value = '\$12,000'; -/// //Draw the grid in PDF document page -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGridCell { - /// Initializes a new instance of the [PdfGridCell] class. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// //Apply the cell style to specific row cells - /// row1.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// PdfGridCell gridCell = PdfGridCell( - /// row: row1, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10)); - /// gridCell.value = '\$10,000'; - /// row1.cells[2].value = gridCell.value; - /// row1.cells[2].stringFormat = gridCell.stringFormat; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridCell({ - PdfGridCellStyle? style, - PdfStringFormat? format, - PdfGridRow? row, - int? rowSpan, - int? columnSpan, - }) { - _helper = PdfGridCellHelper(this); - _initialize(style, format, row, rowSpan, columnSpan); - } - - //Fields - late PdfGridCellHelper _helper; - late double _width; - late double _height; - late double _outerCellWidth; - late int _rowSpan; - late int _columnSpan; - dynamic _value; - PdfStringFormat? _format; - PdfGridCell? _parent; - late double _tempRowSpanRemainingHeight; - late PdfGridImagePosition _imagePosition; - late PdfGridStretchOption _pdfGridStretchOption; - PdfGridCellStyle? _style; - late double _maxValue; - - //Properties - /// Gets the width of the [PdfGrid] cell. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add the styles to specific cell - /// header.cells[0].style.stringFormat = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10); - /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; - /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; - /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10000'; - /// //Sets the rowSpan - /// row1.cells[1].rowSpan = 1; - /// //Sets the colSpan - /// row1.cells[1].columnSpan = 2; - /// //Apply the cell style to specific row cells - /// row1.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Gets the width of the PDF grid cell - /// double width = row2.cells[2].width; - /// //Gets the height of the PDF grid cell - /// double height = row2.cells[2].height; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get width { - if (_width == -1 || - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(_helper.row!).grid, - ).isComplete) { - _width = _measureWidth(); - } - return double.parse(_width.toStringAsFixed(4)); - } - - /// Gets the height of the [PdfGrid] cell. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add the styles to specific cell - /// header.cells[0].style.stringFormat = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10); - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10000'; - /// //Sets the rowSpan - /// row1.cells[1].rowSpan = 1; - /// //Sets the colSpan - /// row1.cells[1].columnSpan = 2; - /// //Apply the cell style to specific row cells - /// row1.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Gets the width of the PDF grid cell - /// double width = row2.cells[2].width; - /// //Gets the height of the PDF grid cell - /// double height = row2.cells[2].height; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get height { - if (_height == -1) { - _height = _helper.measureHeight(); - } - return _height; - } - - /// Gets or sets a value that indicates the total number of rows that cell spans - /// within a [PdfGrid]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10000'; - /// //Sets the rowSpan - /// row1.cells[1].rowSpan = 1; - /// //Sets the colSpan - /// row1.cells[1].columnSpan = 2; - /// //Apply the cell style to specific row cells - /// row1.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Gets the width of the PDF grid cell - /// double width = row2.cells[2].width; - /// //Gets the height of the PDF grid cell - /// double height = row2.cells[2].height; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get rowSpan => _rowSpan; - set rowSpan(int value) { - if (value < 1) { - throw ArgumentError.value( - 'value', - 'row span', - 'Invalid span specified, must be greater than or equal to 1', - ); - } - if (value > 1) { - _rowSpan = value; - PdfGridRowHelper.getHelper(_helper.row!).rowSpanExists = true; - PdfGridHelper.getHelper(PdfGridRowHelper.getHelper(_helper.row!).grid) - .hasRowSpan = true; - } - } - - /// Gets or sets a value that indicates the total number of columns that cell spans - /// within a [PdfGrid]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add the styles to specific cell - /// header.cells[0].style.stringFormat = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10); - /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; - /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; - /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10000'; - /// //Sets the rowSpan - /// row1.cells[1].rowSpan = 1; - /// //Sets the colSpan - /// row1.cells[1].columnSpan = 2; - /// //Apply the cell style to specific row cells - /// row1.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Gets the width of the PDF grid cell - /// double width = row2.cells[2].width; - /// //Gets the height of the PDF grid cell - /// double height = row2.cells[2].height; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get columnSpan => _columnSpan; - set columnSpan(int value) { - if (value < 1) { - throw ArgumentError.value( - 'value', - 'column span', - 'Invalid span specified, must be greater than or equal to 1', - ); - } - if (value > 1) { - _columnSpan = value; - PdfGridHelper.getHelper(PdfGridRowHelper.getHelper(_helper.row!).grid) - .hasColumnSpan = true; - } - } - - /// Gets or sets the cell style. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add the styles to specific cell - /// header.cells[0].style.stringFormat = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10); - /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; - /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; - /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// //Apply the cell style to specific row cells - /// row1.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// PdfGridCell gridCell = PdfGridCell( - /// row: row1, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10)); - /// gridCell.value = '\$10,000'; - /// row1.cells[2].value = gridCell.value; - /// row1.cells[2].stringFormat = gridCell.stringFormat; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Add the style to specific cell - /// row2.cells[2].style.borders = PdfBorders( - /// left: PdfPen(PdfColor(240, 0, 0), width: 2), - /// top: PdfPen(PdfColor(0, 240, 0), width: 3), - /// bottom: PdfPen(PdfColor(0, 0, 240), width: 4), - /// right: PdfPen(PdfColor(240, 100, 240), width: 5)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridCellStyle get style { - _style ??= PdfGridCellStyle(); - return _style!; - } - - set style(PdfGridCellStyle value) { - _style = value; - } - - /// Gets or sets the value of the cell. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// //Apply the cell style to specific row cells - /// PdfGridCell gridCell = PdfGridCell( - /// row: row1, - /// format: PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10)); - /// gridCell.value = '\$10,000'; - /// row1.cells[2].value = gridCell.value; - /// row1.cells[2].stringFormat = gridCell.stringFormat; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - dynamic get value => _value; - set value(dynamic value) { - _value = value; - _setValue(value); - } - - /// Gets or sets the string format. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add the styles to specific cell - /// header.cells[0].style.stringFormat = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom, - /// wordSpacing: 10); - /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; - /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; - /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// //Apply the cell style to specific row cells - /// row1.cells[0].style = PdfGridCellStyle( - /// backgroundBrush: PdfBrushes.lightYellow, - /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), - /// textBrush: PdfBrushes.white, - /// textPen: PdfPens.orange, - /// ); - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfStringFormat get stringFormat { - _format ??= PdfStringFormat(); - return _format!; - } - - set stringFormat(PdfStringFormat value) { - _format = value; - } - - /// Gets or sets the image alignment type of the [PdfGridCell] image. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// PdfGridCell cell1 = row1.cells[0]; - /// //Sets the image alignment type of the PdfGridCell image - /// cell1.imagePosition = PdfGridImagePosition.center; - /// cell1.style.backgroundImage = PdfBitmap(imageData); - /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridImagePosition get imagePosition => _imagePosition; - set imagePosition(PdfGridImagePosition value) { - if (_imagePosition != value) { - _imagePosition = value; - } - } - - //Implementation - void _initialize( - PdfGridCellStyle? style, - PdfStringFormat? format, - PdfGridRow? row, - int? rowSpan, - int? columnSpan, - ) { - if (row != null) { - _helper.row = row; - } - if (style != null) { - _style = style; - } - if (format != null) { - stringFormat = format; - } - if (rowSpan != null && rowSpan > 1) { - this.rowSpan = rowSpan; - } else { - _rowSpan = 1; - } - if (columnSpan != null && columnSpan > 1) { - this.columnSpan = columnSpan; - } else { - _columnSpan = 1; - } - _width = -1; - _height = -1; - _helper.finished = true; - _helper.pageCount = 0; - _helper.present = false; - _outerCellWidth = -1; - _helper.rowSpanRemainingHeight = 0; - _imagePosition = PdfGridImagePosition.stretch; - _pdfGridStretchOption = PdfGridStretchOption.none; - _helper.isCellMergeContinue = false; - _helper.isRowMergeContinue = false; - _tempRowSpanRemainingHeight = 0; - _maxValue = 3.40282347E+38; - } - - void _setValue(dynamic value) { - if (value == null) { - throw ArgumentError.value(value, 'value', 'value cannot be null'); - } - if (_value is PdfGrid) { - PdfGridHelper.getHelper(PdfGridRowHelper.getHelper(_helper.row!).grid) - .isSingleGrid = false; - PdfGridHelper.getHelper(_value as PdfGrid).parentCell = this; - PdfGridHelper.getHelper(_value as PdfGrid).isChildGrid = true; - for (int i = 0; i < _value.rows.count; i++) { - final PdfGridRow row = _value.rows[i] as PdfGridRow; - for (int j = 0; j < row.cells.count; j++) { - final PdfGridCell cell = row.cells[j]; - cell._parent = this; - } - } - } - } - - PdfFont? _getTextFont() { - return style.font ?? - _helper.row!.style.font ?? - PdfGridRowHelper.getHelper(_helper.row!).grid.style.font ?? - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(_helper.row!).grid, - ).defaultFont; - } - - PdfBrush? _getTextBrush() { - return style.textBrush ?? - _helper.row!.style.textBrush ?? - PdfGridRowHelper.getHelper(_helper.row!).grid.style.textBrush ?? - PdfBrushes.black; - } - - PdfPen? _getTextPen() { - return style.textPen ?? - _helper.row!.style.textPen ?? - PdfGridRowHelper.getHelper(_helper.row!).grid.style.textPen; - } - - PdfBrush? _getBackgroundBrush() { - return style.backgroundBrush ?? - _helper.row!.style.backgroundBrush ?? - PdfGridRowHelper.getHelper(_helper.row!).grid.style.backgroundBrush; - } - - double _measureWidth() { - double? width = 0; - final PdfStringLayouter layouter = PdfStringLayouter(); - if (value is String) { - double? defaultWidth = _maxValue; - if (_parent != null) { - defaultWidth = _getColumnWidth(); - } - final PdfStringLayoutResult result = layouter.layout( - value, - _getTextFont()!, - stringFormat, - width: defaultWidth, - height: _maxValue, - ); - width += result.size.width; - width += (style.borders.left.width + style.borders.right.width) * 2; - } else if (value is PdfGrid) { - width = PdfGridHelper.getHelper(value).gridSize.width; - } else if (value is PdfTextElement) { - double? defaultWidth = _maxValue; - if (_parent != null) { - defaultWidth = _getColumnWidth(); - } - final PdfTextElement element = value as PdfTextElement; - String? temp = element.text; - if (!_helper.finished) { - temp = - (_helper.remainingString != null && - _helper.remainingString!.isNotEmpty) - ? _helper.remainingString - : value as String; - } - final PdfStringLayoutResult result = layouter.layout( - temp!, - element.font, - element.stringFormat ?? stringFormat, - width: defaultWidth, - height: _maxValue, - ); - width += result.size.width; - width += (style.borders.left.width + style.borders.right.width) * 2; - } - return width + - PdfGridRowHelper.getHelper(_helper.row!).grid.style.cellSpacing + - (style.cellPadding != null - ? (style.cellPadding!.left + style.cellPadding!.right) - : (PdfGridRowHelper.getHelper( - _helper.row!, - ).grid.style.cellPadding.left + - PdfGridRowHelper.getHelper( - _helper.row!, - ).grid.style.cellPadding.right)); - } - - double _getColumnWidth() { - double defaultWidth = - PdfGridCellHelper.getHelper(_parent!)._calculateWidth()! / - PdfGridRowHelper.getHelper(_helper.row!).grid.columns.count; - if (defaultWidth <= 0) { - defaultWidth = _maxValue; - } - return defaultWidth; - } -} - -/// [PdfGridCell] helper -class PdfGridCellHelper { - /// internal constructor - PdfGridCellHelper(this.base); - - /// internal field - PdfGridCell base; - - /// internal method - static PdfGridCellHelper getHelper(PdfGridCell base) { - return base._helper; - } - - /// internal field - PdfGridRow? row; - - /// internal field - late bool finished; - - /// internal field - String? remainingString; - - /// internal field - bool present = false; - - /// internal field - late bool isCellMergeContinue; - - /// internal method - late bool isRowMergeContinue; - - /// internal method - late double rowSpanRemainingHeight; - - /// internal method - late int pageCount; - - /// internal method - double measureHeight() { - final double width = - _calculateWidth()! - - (base.style.cellPadding == null - ? (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.right + - PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.left) - : (base.style.cellPadding!.right + - base.style.cellPadding!.left + - base.style.borders.left.width + - base.style.borders.right.width)); - base._outerCellWidth = width; - double height = 0; - final PdfStringLayouter layouter = PdfStringLayouter(); - if (base.value is PdfTextElement) { - final PdfTextElement element = base.value as PdfTextElement; - String? temp = element.text; - if (!finished) { - temp = - (remainingString != null && remainingString!.isNotEmpty) - ? remainingString - : base.value as String; - } - final PdfStringLayoutResult result = layouter.layout( - temp!, - element.font, - element.stringFormat ?? base.stringFormat, - width: width, - height: base._maxValue, - ); - height += - result.size.height + - ((base.style.borders.top.width + base.style.borders.bottom.width) * - 2); - } else if (base.value is String || remainingString is String) { - String? currentValue = base.value as String; - if (!finished) { - currentValue = - (remainingString != null && remainingString!.isNotEmpty) - ? remainingString - : base.value as String; - } - final PdfStringLayoutResult result = layouter.layout( - currentValue!, - base._getTextFont()!, - base.stringFormat, - width: width, - height: base._maxValue, - ); - height += - result.size.height + - ((base.style.borders.top.width + base.style.borders.bottom.width) * - 2); - } else if (base.value is PdfGrid) { - height = PdfGridHelper.getHelper(base.value as PdfGrid).size.height; - } else if (base.value is PdfImage) { - final PdfImage img = base._value as PdfImage; - height = img.height / (96 / 72); - } - height += - base.style.cellPadding == null - ? (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.top + - PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.bottom) - : (base.style.cellPadding!.top + base.style.cellPadding!.bottom); - height += PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; - return height; - } - - double? _calculateWidth() { - final int cellIndex = row!.cells.indexOf(base); - final int columnSpan = base.columnSpan; - double width = 0; - for (int i = 0; i < columnSpan; i++) { - width += - PdfGridRowHelper.getHelper(row!).grid.columns[cellIndex + i].width; - } - if (base._parent != null && - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(base._parent!).row!, - ).getWidth() > - 0 && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).isChildGrid! && - (PdfGridRowHelper.getHelper(row!).getWidth() > - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(base._parent!).row!, - ).getWidth())) { - width = 0; - for (int j = 0; j < base._parent!.columnSpan; j++) { - width += - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(base._parent!).row!, - ).grid.columns[j].width; - } - width = width / row!.cells.count; - } else if (base._parent != null && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).isChildGrid! && - width == -1) { - width = _findGridColumnWidth(base._parent!); - width = width / row!.cells.count; - } - return width; - } - - double _findGridColumnWidth(PdfGridCell pdfGridCell) { - double width = -1; - if (pdfGridCell._parent != null && pdfGridCell._outerCellWidth == -1) { - width = _findGridColumnWidth(pdfGridCell._parent!); - width = width / PdfGridCellHelper.getHelper(pdfGridCell).row!.cells.count; - } else if (pdfGridCell._parent == null && pdfGridCell._outerCellWidth > 0) { - width = pdfGridCell._outerCellWidth; - } - return width; - } - - /// internal method - PdfGraphics drawCellBorders(PdfGraphics graphics, PdfRectangle bounds) { - final PdfBorders borders = base.style.borders; - if (PdfGridRowHelper.getHelper(row!).grid.style.borderOverlapStyle == - PdfBorderOverlapStyle.inside) { - bounds.x = bounds.x + borders.left.width; - bounds.y = bounds.y + borders.top.width; - bounds.width = bounds.width - borders.right.width; - bounds.height = bounds.height - borders.bottom.width; - } - PdfPen? pen = base.style.borders.left; - if (PdfBordersHelper.isAll(base.style.borders)) { - _setTransparency(graphics, pen); - graphics.drawRectangle(pen: pen, bounds: bounds.rect); - } else { - Offset p1 = Offset(bounds.x, bounds.y + bounds.height); - Offset p2 = Offset(bounds.x, bounds.y); - if (base._style!.borders.left.dashStyle == PdfDashStyle.solid && - !PdfPenHelper.getHelper(pen).isImmutable) { - pen.lineCap = PdfLineCap.square; - } - _setTransparency(graphics, pen); - graphics.drawLine(pen, p1, p2); - graphics.restore(); - - p1 = Offset(bounds.x + bounds.width, bounds.y); - p2 = Offset(bounds.x + bounds.width, bounds.y + bounds.height); - pen = base._style!.borders.right; - if (bounds.x + bounds.width > graphics.clientSize.width - pen.width / 2) { - p1 = Offset(graphics.clientSize.width - pen.width / 2, bounds.y); - p2 = Offset( - graphics.clientSize.width - pen.width / 2, - bounds.y + bounds.height, - ); - } - if (base._style!.borders.right.dashStyle == PdfDashStyle.solid && - !PdfPenHelper.getHelper(pen).isImmutable) { - pen.lineCap = PdfLineCap.square; - } - _setTransparency(graphics, pen); - graphics.drawLine(pen, p1, p2); - graphics.restore(); - p1 = Offset(bounds.x, bounds.y); - p2 = Offset(bounds.x + bounds.width, bounds.y); - pen = base._style!.borders.top; - if (base._style!.borders.top.dashStyle == PdfDashStyle.solid && - !PdfPenHelper.getHelper(pen).isImmutable) { - pen.lineCap = PdfLineCap.square; - } - _setTransparency(graphics, pen); - graphics.drawLine(pen, p1, p2); - graphics.restore(); - p1 = Offset(bounds.x + bounds.width, bounds.y + bounds.height); - p2 = Offset(bounds.x, bounds.y + bounds.height); - pen = base._style!.borders.bottom; - if (bounds.y + bounds.height > - graphics.clientSize.height - pen.width / 2) { - p1 = Offset( - bounds.x + bounds.width, - graphics.clientSize.height - pen.width / 2, - ); - p2 = Offset(bounds.x, graphics.clientSize.height - pen.width / 2); - } - if (base._style!.borders.bottom.dashStyle == PdfDashStyle.solid && - !PdfPenHelper.getHelper(pen).isImmutable) { - pen.lineCap = PdfLineCap.square; - } - _setTransparency(graphics, pen); - graphics.drawLine(pen, p1, p2); - } - graphics.restore(); - return graphics; - } - - void _setTransparency(PdfGraphics graphics, PdfPen pen) { - graphics.save(); - graphics.setTransparency(PdfColorHelper.getHelper(pen.color).alpha / 255); - } - - /// internal method - PdfStringLayoutResult? draw( - PdfGraphics? graphics, - PdfRectangle bounds, - bool cancelSubsequentSpans, - ) { - bool isrowbreak = false; - if (!PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).isSingleGrid) { - if ((remainingString != null) || (PdfGridLayouter.repeatRowIndex != -1)) { - _drawParentCells(graphics!, bounds, true); - } else if (PdfGridRowHelper.getHelper(row!).grid.rows.count > 1) { - for ( - int i = 0; - i < PdfGridRowHelper.getHelper(row!).grid.rows.count; - i++ - ) { - if (row == PdfGridRowHelper.getHelper(row!).grid.rows[i]) { - if (PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[i], - ).rowBreakHeight > - 0) { - isrowbreak = true; - } - if ((i > 0) && isrowbreak) { - _drawParentCells(graphics!, bounds, false); - } - } - } - } - } - PdfStringLayoutResult? result; - if (cancelSubsequentSpans) { - final int currentCellIndex = row!.cells.indexOf(base); - for ( - int i = currentCellIndex + 1; - i <= currentCellIndex + base._columnSpan; - i++ - ) { - PdfGridCellHelper.getHelper(row!.cells[i]).isCellMergeContinue = false; - PdfGridCellHelper.getHelper(row!.cells[i]).isRowMergeContinue = false; - } - base._columnSpan = 1; - } - if (isCellMergeContinue || isRowMergeContinue) { - if (isCellMergeContinue && - PdfGridRowHelper.getHelper(row!).grid.style.allowHorizontalOverflow) { - if ((PdfGridRowHelper.getHelper(row!).rowOverflowIndex > 0 && - (row!.cells.indexOf(base) != - PdfGridRowHelper.getHelper(row!).rowOverflowIndex + 1)) || - (PdfGridRowHelper.getHelper(row!).rowOverflowIndex == 0 && - isCellMergeContinue)) { - return result; - } - } else { - return result; - } - } - bounds = _adjustOuterLayoutArea(bounds, graphics); - graphics = _drawCellBackground(graphics, bounds); - final PdfPen? textPen = base._getTextPen(); - final PdfBrush? textBrush = base._getTextBrush(); - final PdfFont? font = base._getTextFont(); - final PdfStringFormat strFormat = - base.style.stringFormat ?? base.stringFormat; - PdfRectangle innerLayoutArea = bounds.clone(); - if (innerLayoutArea.height >= graphics!.clientSize.height) { - if (PdfGridRowHelper.getHelper(row!).grid.allowRowBreakingAcrossPages) { - innerLayoutArea.height = innerLayoutArea.height - innerLayoutArea.y; - bounds.height = bounds.height - bounds.y; - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).isChildGrid!) { - innerLayoutArea.height = - innerLayoutArea.height - - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom; - } - } else { - innerLayoutArea.height = graphics.clientSize.height; - bounds.height = graphics.clientSize.height; - } - } - innerLayoutArea = _adjustContentLayoutArea(innerLayoutArea); - if (base.value is PdfGrid) { - graphics.save(); - graphics.setClip(bounds: innerLayoutArea.rect, mode: PdfFillMode.winding); - final PdfGrid childGrid = base.value as PdfGrid; - PdfGridHelper.getHelper(childGrid).isChildGrid = true; - PdfGridHelper.getHelper(childGrid).parentCell = base; - PdfGridHelper.getHelper(childGrid).listOfNavigatePages = []; - PdfGridLayouter layouter = PdfGridLayouter(childGrid); - PdfLayoutFormat? format = PdfLayoutFormat(); - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).layoutFormat != - null) { - format = - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).layoutFormat; - } else { - format.layoutType = PdfLayoutType.paginate; - } - if (PdfGraphicsHelper.getHelper(graphics).layer != null) { - final PdfLayoutParams param = PdfLayoutParams(); - param.page = PdfGraphicsHelper.getHelper(graphics).page; - param.bounds = innerLayoutArea; - param.format = format; - PdfGridHelper.getHelper(childGrid).setSpan(); - final PdfLayoutResult? childGridResult = layouter.layout(param); - base.value = childGrid; - if (childGridResult != null && param.page != childGridResult.page) { - PdfGridRowHelper.getHelper(row!).gridResult = childGridResult; - bounds.height = graphics.clientSize.height - bounds.y; - } - } else { - PdfGridHelper.getHelper(childGrid).setSpan(); - layouter = PdfGridLayouter(base.value as PdfGrid); - layouter.layoutGrid(graphics, innerLayoutArea); - } - graphics.restore(); - } else if (base.value is PdfTextElement) { - final PdfTextElement textelement = base.value as PdfTextElement; - final PdfPage? page = PdfGraphicsHelper.getHelper(graphics).page; - PdfTextElementHelper.getHelper(textelement).isPdfTextElement = true; - final String textElementString = textelement.text; - PdfTextLayoutResult? textlayoutresult; - if (finished) { - textlayoutresult = - textelement.draw(page: page, bounds: innerLayoutArea.rect) - as PdfTextLayoutResult?; - } else { - textelement.text = remainingString!; - textlayoutresult = - textelement.draw(page: page, bounds: innerLayoutArea.rect) - as PdfTextLayoutResult?; - } - if (textlayoutresult!.remainder != null && - textlayoutresult.remainder!.isNotEmpty) { - remainingString = textlayoutresult.remainder; - finished = false; - } else { - remainingString = null; - finished = true; - } - textelement.text = textElementString; - } else if (base.value is String || remainingString is String) { - String? temp; - PdfRectangle layoutRectangle; - if (innerLayoutArea.height < font!.height) { - layoutRectangle = PdfRectangle( - innerLayoutArea.x, - innerLayoutArea.y, - innerLayoutArea.width, - font.height, - ); - } else { - layoutRectangle = innerLayoutArea; - } - if (innerLayoutArea.height < font.height && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).isChildGrid! && - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).parentCell != - null) { - final double height = - layoutRectangle.height - - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom - - PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.bottom; - if (height > 0 && height < font.height) { - layoutRectangle.height = height; - } else if (height + - PdfGridRowHelper.getHelper( - row!, - ).grid.style.cellPadding.bottom > - 0 && - height + - PdfGridRowHelper.getHelper( - row!, - ).grid.style.cellPadding.bottom < - font.height) { - layoutRectangle.height = - height + - PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.bottom; - } else if (bounds.height < font.height) { - layoutRectangle.height = bounds.height; - } else if (bounds.height - - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom < - font.height) { - layoutRectangle.height = - bounds.height - - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom; - } - } - if (base.style.cellPadding != null && - base.style.cellPadding!.bottom == 0 && - base.style.cellPadding!.left == 0 && - base.style.cellPadding!.right == 0 && - base.style.cellPadding!.top == 0) { - layoutRectangle.width = - layoutRectangle.width - - base.style.borders.left.width + - base.style.borders.right.width; - } - if (finished) { - temp = - remainingString != null && remainingString!.isEmpty - ? remainingString - : base.value as String; - graphics.drawString( - temp!, - font, - pen: textPen, - brush: textBrush, - bounds: layoutRectangle.rect, - format: strFormat, - ); - } else { - graphics.drawString( - remainingString!, - font, - pen: textPen, - brush: textBrush, - bounds: layoutRectangle.rect, - format: strFormat, - ); - } - result = PdfGraphicsHelper.getHelper(graphics).stringLayoutResult; - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).isChildGrid! && - PdfGridRowHelper.getHelper(row!).rowBreakHeight > 0 && - result != null) { - bounds.height = - bounds.height - - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).parentCell!, - ).row!, - ).grid.style.cellPadding.bottom; - } - } else if (base._value is PdfImage) { - if (base.style.cellPadding != null && - base.style.cellPadding != - PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { - final PdfPaddings padding = base.style.cellPadding!; - bounds = PdfRectangle( - bounds.x + padding.left, - bounds.y + padding.top, - bounds.width - (padding.left + padding.right), - bounds.height - (padding.top + padding.bottom), - ); - } else if (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding != - PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { - final PdfPaddings padding = - PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; - bounds = PdfRectangle( - bounds.x + padding.left, - bounds.y + padding.top, - bounds.width - (padding.left + padding.right), - bounds.height - (padding.top + padding.bottom), - ); - } - final PdfImage img = base.value as PdfImage; - double? imgWidth = img.width.toDouble(); - double? imgHeight = img.height.toDouble(); - double spaceX = 0; - double spaceY = 0; - if (base._pdfGridStretchOption == PdfGridStretchOption.uniform || - base._pdfGridStretchOption == PdfGridStretchOption.uniformToFill) { - double ratio = 1; - if (imgWidth > bounds.width) { - ratio = imgWidth / bounds.width; - imgWidth = bounds.width; - imgHeight = imgHeight / ratio; - } - if (imgHeight > bounds.height) { - ratio = imgHeight / bounds.height; - imgHeight = bounds.height; - imgWidth = imgWidth / ratio; - } - if (imgWidth < bounds.width && imgHeight < bounds.height) { - spaceX = bounds.width - imgWidth; - spaceY = bounds.height - imgHeight; - if (spaceX < spaceY) { - ratio = imgWidth / bounds.width; - imgWidth = bounds.width; - imgHeight = imgHeight / ratio; - } else { - ratio = imgHeight / bounds.height; - imgHeight = bounds.height; - imgWidth = imgWidth / ratio; - } - } - } - if (base._pdfGridStretchOption == PdfGridStretchOption.fill || - base._pdfGridStretchOption == PdfGridStretchOption.none) { - imgWidth = bounds.width; - imgHeight = bounds.height; - } - if (base._pdfGridStretchOption == PdfGridStretchOption.uniformToFill) { - double ratio = 1; - if (imgWidth == bounds.width && imgHeight < bounds.height) { - ratio = imgHeight / bounds.height; - imgHeight = bounds.height; - imgWidth = imgWidth / ratio; - } - if (imgHeight == bounds.height && imgWidth < bounds.width) { - ratio = imgWidth / bounds.width; - imgWidth = bounds.width; - imgHeight = imgHeight / ratio; - } - final PdfPage graphicsPage = - PdfGraphicsHelper.getHelper(graphics).page!; - final PdfGraphicsState st = graphicsPage.graphics.save(); - graphicsPage.graphics.setClip( - bounds: bounds.rect, - mode: PdfFillMode.winding, - ); - graphicsPage.graphics.drawImage( - img, - Rect.fromLTWH(bounds.x, bounds.y, imgWidth, imgHeight), - ); - graphicsPage.graphics.restore(st); - } else { - graphics = _setImagePosition( - graphics, - img, - PdfRectangle(bounds.x, bounds.y, imgWidth, imgHeight), - ); - } - graphics!.save(); - } - graphics = drawCellBorders(graphics, bounds); - return result; - } - - void _drawParentCells(PdfGraphics graphics, PdfRectangle bounds, bool b) { - final PdfPoint location = PdfPoint( - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).defaultBorder.right.width / - 2, - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).defaultBorder.top.width / - 2, - ); - if ((bounds.height < graphics.clientSize.height) && (b == true)) { - bounds.height = bounds.height + bounds.y - location.y; - } - final PdfRectangle rect = PdfRectangle( - location.x, - location.y, - bounds.width, - bounds.height, - ); - if (b == false) { - rect.y = bounds.y; - rect.height = bounds.height; - } - PdfGridCell? c = base; - if (base._parent != null) { - if ((PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(c).row!, - ).grid.rows.count == - 1) && - (PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(c).row!, - ).grid.rows[0].cells.count == - 1)) { - PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(c).row!, - ).grid.rows[0].cells[0], - ).present = - true; - } else { - for ( - int rowIndex = 0; - rowIndex < - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(c).row!, - ).grid.rows.count; - rowIndex++ - ) { - final PdfGridRow r = - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(c).row!, - ).grid.rows[rowIndex]; - if (r == PdfGridCellHelper.getHelper(c).row) { - for (int cellIndex = 0; cellIndex < row!.cells.count; cellIndex++) { - final PdfGridCell cell = row!.cells[cellIndex]; - if (cell == c) { - PdfGridCellHelper.getHelper(cell).present = true; - break; - } - } - } - } - } - while (c!._parent != null) { - c = c._parent; - PdfGridCellHelper.getHelper(c!).present = true; - rect.x = - rect.x + - PdfGridRowHelper.getHelper( - PdfGridCellHelper.getHelper(c).row!, - ).grid.style.cellPadding.left; - } - } - if (bounds.x >= rect.x) { - rect.x = rect.x - bounds.x; - if (rect.x < 0) { - rect.x = bounds.x; - } - } - PdfGrid pdfGrid = - PdfGridRowHelper.getHelper(PdfGridCellHelper.getHelper(c).row!).grid; - for (int i = 0; i < pdfGrid.rows.count; i++) { - for (int j = 0; j < pdfGrid.rows[i].cells.count; j++) { - if (PdfGridCellHelper.getHelper(pdfGrid.rows[i].cells[j]).present == - true) { - int cellcount = 0; - if (pdfGrid.rows[i].style.backgroundBrush != null) { - base.style.backgroundBrush = pdfGrid.rows[i].style.backgroundBrush; - double cellwidth = 0; - if (j > 0) { - for (int n = 0; n < j; n++) { - cellwidth += pdfGrid.columns[n].width; - } - } - rect.width = - PdfGridRowHelper.getHelper(pdfGrid.rows[i]).getWidth() - - cellwidth; - final PdfGrid? grid = pdfGrid.rows[i].cells[j].value as PdfGrid?; - if (grid != null) { - for (int l = 0; l < grid.rows.count; l++) { - for (int m = 0; m < grid.rows[l].cells.count; m++) { - if ((PdfGridCellHelper.getHelper( - grid.rows[l].cells[m], - ).present) && - m > 0) { - rect.width = grid.rows[l].cells[m].width; - cellcount = m; - } - } - } - } - graphics = _drawCellBackground(graphics, rect)!; - } - PdfGridCellHelper.getHelper(pdfGrid.rows[i].cells[j]).present = false; - if (pdfGrid.rows[i].cells[j].style.backgroundBrush != null) { - base.style.backgroundBrush = - pdfGrid.rows[i].cells[j].style.backgroundBrush; - if (cellcount == 0) { - rect.width = pdfGrid.columns[j].width; - } - graphics = _drawCellBackground(graphics, rect)!; - } - if (pdfGrid.rows[i].cells[j].value is PdfGrid) { - if (!PdfGridRowHelper.getHelper(pdfGrid.rows[i]).isrowFinish) { - if (cellcount == 0) { - rect.x = rect.x + pdfGrid.style.cellPadding.left; - } - } - pdfGrid = pdfGrid.rows[i].cells[j].value as PdfGrid; - if (pdfGrid.style.backgroundBrush != null) { - base.style.backgroundBrush = pdfGrid.style.backgroundBrush; - if (cellcount == 0) { - if (j < pdfGrid.columns.count) { - rect.width = pdfGrid.columns[j].width; - } - } - graphics = _drawCellBackground(graphics, rect)!; - } - i = -1; - break; - } - } - } - } - if (bounds.height < graphics.clientSize.height) { - bounds.height = bounds.height - bounds.y - location.y; - } - } - - PdfGraphics? _drawCellBackground(PdfGraphics? graphics, PdfRectangle bounds) { - final PdfBrush? backgroundBrush = base._getBackgroundBrush(); - if (backgroundBrush != null) { - graphics!.save(); - graphics.drawRectangle(brush: backgroundBrush, bounds: bounds.rect); - graphics.restore(); - } - if (base.style.backgroundImage != null) { - final PdfImage? image = base.style.backgroundImage; - if (base.style.cellPadding != null && - base.style.cellPadding != - PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { - final PdfPaddings padding = base.style.cellPadding!; - bounds = PdfRectangle( - bounds.x + padding.left, - bounds.y + padding.top, - bounds.width - (padding.left + padding.right), - bounds.height - (padding.top + padding.bottom), - ); - } else if (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding != - PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { - final PdfPaddings padding = - PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; - bounds = PdfRectangle( - bounds.x + padding.left, - bounds.y + padding.top, - bounds.width - (padding.left + padding.right), - bounds.height - (padding.top + padding.bottom), - ); - } - return _setImagePosition(graphics, image, bounds); - } - return graphics; - } - - PdfRectangle _adjustContentLayoutArea(PdfRectangle bounds) { - PdfPaddings? padding = base.style.cellPadding; - if (base.value is PdfGrid) { - final PdfSize size = PdfGridHelper.getHelper(base.value).gridSize; - if (padding == null) { - padding = PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; - bounds.width = bounds.width - (padding.right + padding.left); - bounds.height = bounds.height - (padding.bottom + padding.top); - if (base.stringFormat.alignment == PdfTextAlignment.center) { - bounds.x = - bounds.x + padding.left + ((bounds.width - size.width) / 2); - bounds.y = - bounds.y + padding.top + ((bounds.height - size.height) / 2); - } else if (base.stringFormat.alignment == PdfTextAlignment.left) { - bounds.x = bounds.x + padding.left; - bounds.y = bounds.y + padding.top; - } else if (base.stringFormat.alignment == PdfTextAlignment.right) { - bounds.x = bounds.x + padding.left + (bounds.width - size.width); - bounds.y = bounds.y + padding.top; - bounds.width = size.width; - } - } else { - bounds.width = bounds.width - (padding.right + padding.left); - bounds.height = bounds.height - (padding.bottom + padding.top); - - if (base.stringFormat.alignment == PdfTextAlignment.center) { - bounds.x = - bounds.x + padding.left + ((bounds.width - size.width) / 2); - bounds.y = - bounds.y + padding.top + ((bounds.height - size.height) / 2); - } else if (base.stringFormat.alignment == PdfTextAlignment.left) { - bounds.x = bounds.x + padding.left; - bounds.y = bounds.y + padding.top; - } else if (base.stringFormat.alignment == PdfTextAlignment.right) { - bounds.x = bounds.x + padding.left + (bounds.width - size.width); - bounds.y = bounds.y + padding.top; - bounds.width = size.width; - } - } - } else { - if (padding == null) { - padding = PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; - bounds.x = bounds.x + padding.left; - bounds.y = bounds.y + padding.top; - bounds.width = bounds.width - (padding.right + padding.left); - bounds.height = bounds.height - (padding.bottom + padding.top); - } else { - bounds.x = bounds.x + padding.left; - bounds.y = bounds.y + padding.top; - bounds.width = bounds.width - (padding.right + padding.left); - bounds.height = bounds.height - (padding.bottom + padding.top); - } - } - return bounds; - } - - PdfRectangle _adjustOuterLayoutArea(PdfRectangle bounds, PdfGraphics? g) { - bool isHeader = false; - final double cellSpacing = - PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; - if (cellSpacing > 0) { - bounds = PdfRectangle( - bounds.x + cellSpacing, - bounds.y + cellSpacing, - bounds.width - cellSpacing, - bounds.height - cellSpacing, - ); - } - final int currentColIndex = row!.cells.indexOf(base); - if (base.columnSpan > 1 || - (PdfGridRowHelper.getHelper(row!).rowOverflowIndex > 0 && - (currentColIndex == - PdfGridRowHelper.getHelper(row!).rowOverflowIndex + 1) && - isCellMergeContinue)) { - int span = base.columnSpan; - if (span == 1 && isCellMergeContinue) { - for ( - int j = currentColIndex + 1; - j < PdfGridRowHelper.getHelper(row!).grid.columns.count; - j++ - ) { - if (PdfGridCellHelper.getHelper(row!.cells[j]).isCellMergeContinue) { - span++; - } else { - break; - } - } - } - double totalWidth = 0; - for (int i = currentColIndex; i < currentColIndex + span; i++) { - if (PdfGridRowHelper.getHelper( - row!, - ).grid.style.allowHorizontalOverflow) { - double width; - final double compWidth = - PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).size.width < - g!.clientSize.width - ? PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).size.width - : g.clientSize.width; - if (PdfGridHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid, - ).size.width > - g.clientSize.width) { - width = - bounds.x + - totalWidth + - PdfGridRowHelper.getHelper(row!).grid.columns[i].width; - } else { - width = - totalWidth + - PdfGridRowHelper.getHelper(row!).grid.columns[i].width; - } - if (width > compWidth) { - break; - } - } - totalWidth += PdfGridRowHelper.getHelper(row!).grid.columns[i].width; - } - totalWidth -= PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; - bounds.width = totalWidth; - } - if (base.rowSpan > 1 || PdfGridRowHelper.getHelper(row!).rowSpanExists) { - int span = base.rowSpan; - int currentRowIndex = PdfGridRowCollectionHelper.indexOf( - PdfGridRowHelper.getHelper(row!).grid.rows, - row, - ); - if (currentRowIndex == -1) { - currentRowIndex = PdfGridHeaderCollectionHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.headers, - ).indexOf(row!); - if (currentRowIndex != -1) { - isHeader = true; - } - } - if (span == 1 && isCellMergeContinue) { - for ( - int j = currentRowIndex + 1; - j < PdfGridRowHelper.getHelper(row!).grid.rows.count; - j++ - ) { - if (isHeader - ? PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper( - row!, - ).grid.headers[j].cells[currentColIndex], - ).isCellMergeContinue - : PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper( - row!, - ).grid.rows[j].cells[currentColIndex], - ).isCellMergeContinue) { - span++; - } else { - break; - } - } - } - double totalHeight = 0; - double max = 0; - if (isHeader) { - for (int i = currentRowIndex; i < currentRowIndex + span; i++) { - totalHeight += - PdfGridRowHelper.getHelper(row!).grid.headers[i].height; - } - totalHeight -= PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; - bounds.height = totalHeight; - } else { - for (int i = currentRowIndex; i < currentRowIndex + span; i++) { - if (!PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[i], - ).isRowSpanRowHeightSet) { - PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[i], - ).isRowHeightSet = - false; - } - totalHeight += - isHeader - ? PdfGridRowHelper.getHelper(row!).grid.headers[i].height - : PdfGridRowHelper.getHelper(row!).grid.rows[i].height; - final PdfGridRow gridRow = - PdfGridRowHelper.getHelper(row!).grid.rows[i]; - final int rowIndex = PdfGridRowCollectionHelper.indexOf( - PdfGridRowHelper.getHelper(row!).grid.rows, - gridRow, - ); - if (base.rowSpan > 1) { - for ( - int cellIndex = 0; - cellIndex < gridRow.cells.count; - cellIndex++ - ) { - final PdfGridCell cell = gridRow.cells[cellIndex]; - if (cell.rowSpan > 1) { - double tempHeight = 0; - for (int j = i; j < i + cell.rowSpan; j++) { - if (!PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[j], - ).isRowSpanRowHeightSet) { - PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[j], - ).isRowHeightSet = - false; - } - tempHeight += - PdfGridRowHelper.getHelper(row!).grid.rows[j].height; - if (!PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[j], - ).isRowSpanRowHeightSet) { - PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[j], - ).isRowHeightSet = - true; - } - } - if (cell.height > tempHeight) { - if (max < (cell.height - tempHeight)) { - max = cell.height - tempHeight; - if (base._tempRowSpanRemainingHeight != 0 && - max > base._tempRowSpanRemainingHeight) { - max += base._tempRowSpanRemainingHeight; - } - final int index = gridRow.cells.indexOf(cell); - PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper(row!) - .grid - .rows[(rowIndex + cell.rowSpan) - 1] - .cells[index], - ).rowSpanRemainingHeight = - max; - base._tempRowSpanRemainingHeight = - PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper(row!) - .grid - .rows[(rowIndex + cell.rowSpan) - 1] - .cells[index], - ).rowSpanRemainingHeight; - } - } - } - } - } - if (!PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[i], - ).isRowSpanRowHeightSet) { - PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper(row!).grid.rows[i], - ).isRowHeightSet = - true; - } - } - final int cellIndex = row!.cells.indexOf(base); - totalHeight -= PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; - if (row!.cells[cellIndex].height > totalHeight && - (!PdfGridRowHelper.getHelper( - PdfGridRowHelper.getHelper( - row!, - ).grid.rows[(currentRowIndex + span) - 1], - ).isRowHeightSet)) { - PdfGridCellHelper.getHelper( - PdfGridRowHelper.getHelper( - row!, - ).grid.rows[(currentRowIndex + span) - 1].cells[cellIndex], - ).rowSpanRemainingHeight = - row!.cells[cellIndex].height - totalHeight; - totalHeight = row!.cells[cellIndex].height; - bounds.height = totalHeight; - } else { - bounds.height = totalHeight; - } - if (!PdfGridRowHelper.getHelper(row!).rowMergeComplete) { - bounds.height = totalHeight; - } - } - } - return bounds; - } - - PdfGraphics? _setImagePosition( - PdfGraphics? graphics, - PdfImage? image, - PdfRectangle bounds, - ) { - if (base._imagePosition == PdfGridImagePosition.stretch) { - graphics!.drawImage(image!, bounds.rect); - } else if (base._imagePosition == PdfGridImagePosition.center) { - double gridCentreX; - double gridCentreY; - gridCentreX = bounds.x + (bounds.width / 4); - gridCentreY = bounds.y + (bounds.height / 4); - graphics!.drawImage( - image!, - Rect.fromLTWH( - gridCentreX, - gridCentreY, - bounds.width / 2, - bounds.height / 2, - ), - ); - } else if (base._imagePosition == PdfGridImagePosition.fit) { - final double imageWidth = image!.physicalDimension.width; - final double imageHeight = image.physicalDimension.height; - double? x; - double? y; - if (imageHeight > imageWidth) { - y = bounds.y; - x = bounds.x + bounds.width / 4; - graphics!.drawImage( - image, - Rect.fromLTWH(x, y, bounds.width / 2, bounds.height), - ); - } else { - x = bounds.x; - y = bounds.y + (bounds.height / 4); - graphics!.drawImage( - image, - Rect.fromLTWH(x, y, bounds.width, bounds.height / 2), - ); - } - } else if (base._imagePosition == PdfGridImagePosition.tile) { - final double cellLeft = bounds.x; - final double cellTop = bounds.y; - final double pWidth = _physicalDimension(image, true); - final double pHeight = _physicalDimension(image, false); - double? x = cellLeft; - double y = cellTop; - for (; y < bounds.bottom;) { - for (x = cellLeft; x! < bounds.right;) { - if (x + pWidth > bounds.right && y + pHeight > bounds.bottom) { - final PdfTemplate template = PdfTemplate( - bounds.right - x, - bounds.bottom - y, - ); - template.graphics!.drawImage(image!, Rect.zero); - graphics!.drawPdfTemplate(template, Offset(x, y)); - } else if (x + pWidth > bounds.right) { - final PdfTemplate template = PdfTemplate(bounds.right - x, pHeight); - template.graphics!.drawImage(image!, Rect.zero); - graphics!.drawPdfTemplate(template, Offset(x, y)); - } else if (y + pHeight > bounds.bottom) { - final PdfTemplate template = PdfTemplate(pWidth, bounds.bottom - y); - template.graphics!.drawImage(image!, Rect.zero); - graphics!.drawPdfTemplate(template, Offset(x, y)); - } else { - graphics!.drawImage(image!, Rect.fromLTWH(x, y, 0, 0)); - } - x += pWidth; - } - y += pHeight; - } - } - return graphics; - } - - //if horizontal/vertical resolution is not set, resolution set as default 96. - double _physicalDimension(PdfImage? image, bool isHorizontal) { - if (isHorizontal) { - return image!.width / - ((image.horizontalResolution > 0 ? image.horizontalResolution : 96) / - 72); - } else { - return image!.height / - ((image.verticalResolution > 0 ? image.verticalResolution : 96) / 72); - } - } -} - -/// Provides access to an ordered, strongly typed collection of -/// [PdfGridCell] objects. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid -/// PdfGrid grid = PdfGrid(); -/// //Add columns to grid -/// grid.columns.add(count: 3); -/// //Add headers to grid -/// PdfGridRow header = grid.headers.add(1)[0]; -/// header.cells[0].value = 'Employee ID'; -/// header.cells[1].value = 'Employee Name'; -/// header.cells[2].value = 'Salary'; -/// //Add rows to grid -/// PdfGridRow row1 = grid.rows.add(); -/// //Gets the cell collection from the row -/// PdfGridCellCollection cellCollection = row1.cells; -/// //Gets the specific cell from the row collection -/// PdfGridCell cell1 = cellCollection[0]; -/// cell1.value = 'E01'; -/// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); -/// cellCollection[1].value = 'Clay'; -/// cellCollection[2].value = '\$10000'; -/// PdfGridRow row2 = grid.rows.add(); -/// row2.cells[0].value = 'E02'; -/// row2.cells[1].value = 'Simon'; -/// row2.cells[2].value = '\$12,000'; -/// //Draw the grid in PDF document page -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGridCellCollection { - //Constructors - /// Initializes a new instance of the [PdfGridCellCollection] class - /// with the row. - PdfGridCellCollection._(PdfGridRow row) { - _helper = PdfGridCellCollectionHelper(this); - _helper.row = row; - _helper._cells = []; - } - - //Fields - late PdfGridCellCollectionHelper _helper; - - //Properties - /// Gets the cells count. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// //Gets the cell collection from the row - /// PdfGridCellCollection cellCollection = row1.cells; - /// //Gets the specific cell from the row collection - /// PdfGridCell cell1 = cellCollection[0]; - /// cell1.value = 'E01'; - /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); - /// cellCollection[1].value = 'Clay'; - /// cellCollection[2].value = '\$10000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Gets the cells count - /// int cellsCount = cellCollection.count; - /// //Gets the index of particular cell - /// int index = cellCollection.indexOf(cell1); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get count => _helper._cells.length; - - /// Gets the [PdfGridCell] at the specified index. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// //Gets the cell collection from the row - /// PdfGridCellCollection cellCollection = row1.cells; - /// //Gets the specific cell from the row collection - /// PdfGridCell cell1 = cellCollection[0]; - /// cell1.value = 'E01'; - /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); - /// cellCollection[1].value = 'Clay'; - /// cellCollection[2].value = '\$10000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Gets the cells count - /// int cellsCount = cellCollection.count; - /// //Gets the index of particular cell - /// int index = cellCollection.indexOf(cell1); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridCell operator [](int index) => _returnValue(index); - - //Public methods - /// Returns the index of a particular cell in the collection. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// PdfGridRow header = grid.headers.add(1)[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// //Gets the cell collection from the row - /// PdfGridCellCollection cellCollection = row1.cells; - /// //Gets the specific cell from the row collection - /// PdfGridCell cell1 = cellCollection[0]; - /// cell1.value = 'E01'; - /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); - /// cellCollection[1].value = 'Clay'; - /// cellCollection[2].value = '\$10000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Gets the cells count - /// int cellsCount = cellCollection.count; - /// //Gets the index of particular cell - /// int index = cellCollection.indexOf(cell1); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int indexOf(PdfGridCell cell) { - return _helper._cells.indexOf(cell); - } - - //Implementation - PdfGridCell _returnValue(int index) { - if (index < 0 || index >= _helper._cells.length) { - // ignore: deprecated_member_use - throw IndexError(index, _helper._cells); - } - return _helper._cells[index]; - } -} - -/// [PdfGridCellCollection] helper -class PdfGridCellCollectionHelper { - /// internal constructor - PdfGridCellCollectionHelper(this.base); - - /// internal field - PdfGridCellCollection base; - - /// internal field - late PdfGridRow row; - late List _cells; - - /// internal method - static PdfGridCellCollectionHelper getHelper(PdfGridCellCollection base) { - return base._helper; - } - - /// internal method - static PdfGridCellCollection load(PdfGridRow row) { - return PdfGridCellCollection._(row); - } - - /// internal method - void add(PdfGridCell cell) { - // cell.style ??= _row!.style as PdfGridCellStyle; - PdfGridCellHelper.getHelper(cell).row = row; - _cells.add(cell); - } -} +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/brushes/pdf_brush.dart'; +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/enums.dart'; +import '../../graphics/figures/base/element_layouter.dart'; +import '../../graphics/figures/base/text_layouter.dart'; +import '../../graphics/figures/enums.dart'; +import '../../graphics/figures/pdf_template.dart'; +import '../../graphics/figures/pdf_text_element.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_string_format.dart'; +import '../../graphics/fonts/pdf_string_layout_result.dart'; +import '../../graphics/fonts/pdf_string_layouter.dart'; +import '../../graphics/images/pdf_image.dart'; +import '../../graphics/pdf_color.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../graphics/pdf_pen.dart'; +import '../../pages/pdf_page.dart'; +import 'enums.dart'; +import 'layouting/pdf_grid_layouter.dart'; +import 'pdf_grid.dart'; +import 'pdf_grid_row.dart'; +import 'styles/pdf_borders.dart'; +import 'styles/style.dart'; + +/// Represents the schema of a cell in a [PdfGrid]. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid +/// PdfGrid grid = PdfGrid(); +/// //Add columns to grid +/// grid.columns.add(count: 3); +/// //Add headers to grid +/// PdfGridRow header = grid.headers.add(1)[0]; +/// header.cells[0].value = 'Employee ID'; +/// header.cells[1].value = 'Employee Name'; +/// header.cells[2].value = 'Salary'; +/// //Add rows to grid +/// PdfGridRow row1 = grid.rows.add(); +/// row1.cells[0].value = 'E01'; +/// row1.cells[1].value = 'Clay'; +/// //Apply the cell style to specific row cells +/// row1.cells[0].style = PdfGridCellStyle( +/// backgroundBrush: PdfBrushes.lightYellow, +/// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), +/// textBrush: PdfBrushes.white, +/// textPen: PdfPens.orange, +/// ); +/// PdfGridCell gridCell = PdfGridCell( +/// row: row1, +/// format: PdfStringFormat( +/// alignment: PdfTextAlignment.center, +/// lineAlignment: PdfVerticalAlignment.bottom, +/// wordSpacing: 10)); +/// gridCell.value = '\$10,000'; +/// row1.cells[2].value = gridCell.value; +/// row1.cells[2].stringFormat = gridCell.stringFormat; +/// PdfGridRow row2 = grid.rows.add(); +/// row2.cells[0].value = 'E02'; +/// row2.cells[1].value = 'Simon'; +/// row2.cells[2].value = '\$12,000'; +/// //Draw the grid in PDF document page +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGridCell { + /// Initializes a new instance of the [PdfGridCell] class. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// //Apply the cell style to specific row cells + /// row1.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// PdfGridCell gridCell = PdfGridCell( + /// row: row1, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10)); + /// gridCell.value = '\$10,000'; + /// row1.cells[2].value = gridCell.value; + /// row1.cells[2].stringFormat = gridCell.stringFormat; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridCell({ + PdfGridCellStyle? style, + PdfStringFormat? format, + PdfGridRow? row, + int? rowSpan, + int? columnSpan, + }) { + _helper = PdfGridCellHelper(this); + _initialize(style, format, row, rowSpan, columnSpan); + } + + //Fields + late PdfGridCellHelper _helper; + late double _width; + late double _height; + late double _outerCellWidth; + late int _rowSpan; + late int _columnSpan; + dynamic _value; + PdfStringFormat? _format; + PdfGridCell? _parent; + late double _tempRowSpanRemainingHeight; + late PdfGridImagePosition _imagePosition; + late PdfGridStretchOption _pdfGridStretchOption; + PdfGridCellStyle? _style; + late double _maxValue; + + //Properties + /// Gets the width of the [PdfGrid] cell. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add the styles to specific cell + /// header.cells[0].style.stringFormat = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10); + /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; + /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; + /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10000'; + /// //Sets the rowSpan + /// row1.cells[1].rowSpan = 1; + /// //Sets the colSpan + /// row1.cells[1].columnSpan = 2; + /// //Apply the cell style to specific row cells + /// row1.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Gets the width of the PDF grid cell + /// double width = row2.cells[2].width; + /// //Gets the height of the PDF grid cell + /// double height = row2.cells[2].height; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get width { + if (_width == -1 || + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(_helper.row!).grid, + ).isComplete) { + _width = _measureWidth(); + } + return double.parse(_width.toStringAsFixed(4)); + } + + /// Gets the height of the [PdfGrid] cell. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add the styles to specific cell + /// header.cells[0].style.stringFormat = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10); + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10000'; + /// //Sets the rowSpan + /// row1.cells[1].rowSpan = 1; + /// //Sets the colSpan + /// row1.cells[1].columnSpan = 2; + /// //Apply the cell style to specific row cells + /// row1.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Gets the width of the PDF grid cell + /// double width = row2.cells[2].width; + /// //Gets the height of the PDF grid cell + /// double height = row2.cells[2].height; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get height { + if (_height == -1) { + _height = _helper.measureHeight(); + } + return _height; + } + + /// Gets or sets a value that indicates the total number of rows that cell spans + /// within a [PdfGrid]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10000'; + /// //Sets the rowSpan + /// row1.cells[1].rowSpan = 1; + /// //Sets the colSpan + /// row1.cells[1].columnSpan = 2; + /// //Apply the cell style to specific row cells + /// row1.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Gets the width of the PDF grid cell + /// double width = row2.cells[2].width; + /// //Gets the height of the PDF grid cell + /// double height = row2.cells[2].height; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get rowSpan => _rowSpan; + set rowSpan(int value) { + if (value < 1) { + throw ArgumentError.value( + 'value', + 'row span', + 'Invalid span specified, must be greater than or equal to 1', + ); + } + if (value > 1) { + _rowSpan = value; + PdfGridRowHelper.getHelper(_helper.row!).rowSpanExists = true; + PdfGridHelper.getHelper(PdfGridRowHelper.getHelper(_helper.row!).grid) + .hasRowSpan = true; + } + } + + /// Gets or sets a value that indicates the total number of columns that cell spans + /// within a [PdfGrid]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add the styles to specific cell + /// header.cells[0].style.stringFormat = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10); + /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; + /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; + /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10000'; + /// //Sets the rowSpan + /// row1.cells[1].rowSpan = 1; + /// //Sets the colSpan + /// row1.cells[1].columnSpan = 2; + /// //Apply the cell style to specific row cells + /// row1.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Gets the width of the PDF grid cell + /// double width = row2.cells[2].width; + /// //Gets the height of the PDF grid cell + /// double height = row2.cells[2].height; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get columnSpan => _columnSpan; + set columnSpan(int value) { + if (value < 1) { + throw ArgumentError.value( + 'value', + 'column span', + 'Invalid span specified, must be greater than or equal to 1', + ); + } + if (value > 1) { + _columnSpan = value; + PdfGridHelper.getHelper(PdfGridRowHelper.getHelper(_helper.row!).grid) + .hasColumnSpan = true; + } + } + + /// Gets or sets the cell style. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add the styles to specific cell + /// header.cells[0].style.stringFormat = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10); + /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; + /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; + /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// //Apply the cell style to specific row cells + /// row1.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// PdfGridCell gridCell = PdfGridCell( + /// row: row1, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10)); + /// gridCell.value = '\$10,000'; + /// row1.cells[2].value = gridCell.value; + /// row1.cells[2].stringFormat = gridCell.stringFormat; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Add the style to specific cell + /// row2.cells[2].style.borders = PdfBorders( + /// left: PdfPen(PdfColor(240, 0, 0), width: 2), + /// top: PdfPen(PdfColor(0, 240, 0), width: 3), + /// bottom: PdfPen(PdfColor(0, 0, 240), width: 4), + /// right: PdfPen(PdfColor(240, 100, 240), width: 5)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridCellStyle get style { + _style ??= PdfGridCellStyle(); + return _style!; + } + + set style(PdfGridCellStyle value) { + _style = value; + } + + /// Gets or sets the value of the cell. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// //Apply the cell style to specific row cells + /// PdfGridCell gridCell = PdfGridCell( + /// row: row1, + /// format: PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10)); + /// gridCell.value = '\$10,000'; + /// row1.cells[2].value = gridCell.value; + /// row1.cells[2].stringFormat = gridCell.stringFormat; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + dynamic get value => _value; + set value(dynamic value) { + _value = value; + _setValue(value); + } + + /// Gets or sets the string format. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add the styles to specific cell + /// header.cells[0].style.stringFormat = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom, + /// wordSpacing: 10); + /// header.cells[1].style.textPen = PdfPens.mediumVioletRed; + /// header.cells[2].style.backgroundBrush = PdfBrushes.yellow; + /// header.cells[2].style.textBrush = PdfBrushes.darkOrange; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// //Apply the cell style to specific row cells + /// row1.cells[0].style = PdfGridCellStyle( + /// backgroundBrush: PdfBrushes.lightYellow, + /// cellPadding: PdfPaddings(left: 2, right: 3, top: 4, bottom: 5), + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 17), + /// textBrush: PdfBrushes.white, + /// textPen: PdfPens.orange, + /// ); + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfStringFormat get stringFormat { + _format ??= PdfStringFormat(); + return _format!; + } + + set stringFormat(PdfStringFormat value) { + _format = value; + } + + /// Gets or sets the image alignment type of the [PdfGridCell] image. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// PdfGridCell cell1 = row1.cells[0]; + /// //Sets the image alignment type of the PdfGridCell image + /// cell1.imagePosition = PdfGridImagePosition.center; + /// cell1.style.backgroundImage = PdfBitmap(imageData); + /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridImagePosition get imagePosition => _imagePosition; + set imagePosition(PdfGridImagePosition value) { + if (_imagePosition != value) { + _imagePosition = value; + } + } + + //Implementation + void _initialize( + PdfGridCellStyle? style, + PdfStringFormat? format, + PdfGridRow? row, + int? rowSpan, + int? columnSpan, + ) { + if (row != null) { + _helper.row = row; + } + if (style != null) { + _style = style; + } + if (format != null) { + stringFormat = format; + } + if (rowSpan != null && rowSpan > 1) { + this.rowSpan = rowSpan; + } else { + _rowSpan = 1; + } + if (columnSpan != null && columnSpan > 1) { + this.columnSpan = columnSpan; + } else { + _columnSpan = 1; + } + _width = -1; + _height = -1; + _helper.finished = true; + _helper.pageCount = 0; + _helper.present = false; + _outerCellWidth = -1; + _helper.rowSpanRemainingHeight = 0; + _imagePosition = PdfGridImagePosition.stretch; + _pdfGridStretchOption = PdfGridStretchOption.none; + _helper.isCellMergeContinue = false; + _helper.isRowMergeContinue = false; + _tempRowSpanRemainingHeight = 0; + _maxValue = 3.40282347E+38; + } + + void _setValue(dynamic value) { + if (value == null) { + throw ArgumentError.value(value, 'value', 'value cannot be null'); + } + if (_value is PdfGrid) { + PdfGridHelper.getHelper(PdfGridRowHelper.getHelper(_helper.row!).grid) + .isSingleGrid = false; + PdfGridHelper.getHelper(_value as PdfGrid).parentCell = this; + PdfGridHelper.getHelper(_value as PdfGrid).isChildGrid = true; + for (int i = 0; i < _value.rows.count; i++) { + final PdfGridRow row = _value.rows[i] as PdfGridRow; + for (int j = 0; j < row.cells.count; j++) { + final PdfGridCell cell = row.cells[j]; + cell._parent = this; + } + } + } + } + + PdfFont? _getTextFont() { + return style.font ?? + _helper.row!.style.font ?? + PdfGridRowHelper.getHelper(_helper.row!).grid.style.font ?? + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(_helper.row!).grid, + ).defaultFont; + } + + PdfBrush? _getTextBrush() { + return style.textBrush ?? + _helper.row!.style.textBrush ?? + PdfGridRowHelper.getHelper(_helper.row!).grid.style.textBrush ?? + PdfBrushes.black; + } + + PdfPen? _getTextPen() { + return style.textPen ?? + _helper.row!.style.textPen ?? + PdfGridRowHelper.getHelper(_helper.row!).grid.style.textPen; + } + + PdfBrush? _getBackgroundBrush() { + return style.backgroundBrush ?? + _helper.row!.style.backgroundBrush ?? + PdfGridRowHelper.getHelper(_helper.row!).grid.style.backgroundBrush; + } + + double _measureWidth() { + double? width = 0; + final PdfStringLayouter layouter = PdfStringLayouter(); + if (value is String) { + double? defaultWidth = _maxValue; + if (_parent != null) { + defaultWidth = _getColumnWidth(); + } + final PdfStringLayoutResult result = layouter.layout( + value, + _getTextFont()!, + stringFormat, + width: defaultWidth, + height: _maxValue, + ); + width += result.size.width; + width += (style.borders.left.width + style.borders.right.width) * 2; + } else if (value is PdfGrid) { + width = PdfGridHelper.getHelper(value).gridSize.width; + } else if (value is PdfTextElement) { + double? defaultWidth = _maxValue; + if (_parent != null) { + defaultWidth = _getColumnWidth(); + } + final PdfTextElement element = value as PdfTextElement; + String? temp = element.text; + if (!_helper.finished) { + temp = + (_helper.remainingString != null && + _helper.remainingString!.isNotEmpty) + ? _helper.remainingString + : value as String; + } + final PdfStringLayoutResult result = layouter.layout( + temp!, + element.font, + element.stringFormat ?? stringFormat, + width: defaultWidth, + height: _maxValue, + ); + width += result.size.width; + width += (style.borders.left.width + style.borders.right.width) * 2; + } + return width + + PdfGridRowHelper.getHelper(_helper.row!).grid.style.cellSpacing + + (style.cellPadding != null + ? (style.cellPadding!.left + style.cellPadding!.right) + : (PdfGridRowHelper.getHelper( + _helper.row!, + ).grid.style.cellPadding.left + + PdfGridRowHelper.getHelper( + _helper.row!, + ).grid.style.cellPadding.right)); + } + + double _getColumnWidth() { + double defaultWidth = + PdfGridCellHelper.getHelper(_parent!)._calculateWidth()! / + PdfGridRowHelper.getHelper(_helper.row!).grid.columns.count; + if (defaultWidth <= 0) { + defaultWidth = _maxValue; + } + return defaultWidth; + } +} + +/// [PdfGridCell] helper +class PdfGridCellHelper { + /// internal constructor + PdfGridCellHelper(this.base); + + /// internal field + PdfGridCell base; + + /// internal method + static PdfGridCellHelper getHelper(PdfGridCell base) { + return base._helper; + } + + /// internal field + PdfGridRow? row; + + /// internal field + late bool finished; + + /// internal field + String? remainingString; + + /// internal field + bool present = false; + + /// internal field + late bool isCellMergeContinue; + + /// internal method + late bool isRowMergeContinue; + + /// internal method + late double rowSpanRemainingHeight; + + /// internal method + late int pageCount; + + /// internal method + double measureHeight() { + final double width = + _calculateWidth()! - + (base.style.cellPadding == null + ? (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.right + + PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.left) + : (base.style.cellPadding!.right + + base.style.cellPadding!.left + + base.style.borders.left.width + + base.style.borders.right.width)); + base._outerCellWidth = width; + double height = 0; + final PdfStringLayouter layouter = PdfStringLayouter(); + if (base.value is PdfTextElement) { + final PdfTextElement element = base.value as PdfTextElement; + String? temp = element.text; + if (!finished) { + temp = + (remainingString != null && remainingString!.isNotEmpty) + ? remainingString + : base.value as String; + } + final PdfStringLayoutResult result = layouter.layout( + temp!, + element.font, + element.stringFormat ?? base.stringFormat, + width: width, + height: base._maxValue, + ); + height += + result.size.height + + ((base.style.borders.top.width + base.style.borders.bottom.width) * + 2); + } else if (base.value is String || remainingString is String) { + String? currentValue = base.value as String; + if (!finished) { + currentValue = + (remainingString != null && remainingString!.isNotEmpty) + ? remainingString + : base.value as String; + } + final PdfStringLayoutResult result = layouter.layout( + currentValue!, + base._getTextFont()!, + base.stringFormat, + width: width, + height: base._maxValue, + ); + height += + result.size.height + + ((base.style.borders.top.width + base.style.borders.bottom.width) * + 2); + } else if (base.value is PdfGrid) { + height = PdfGridHelper.getHelper(base.value as PdfGrid).size.height; + } else if (base.value is PdfImage) { + final PdfImage img = base._value as PdfImage; + height = img.height / (96 / 72); + } + height += + base.style.cellPadding == null + ? (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.top + + PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.bottom) + : (base.style.cellPadding!.top + base.style.cellPadding!.bottom); + height += PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; + return height; + } + + double? _calculateWidth() { + final int cellIndex = row!.cells.indexOf(base); + final int columnSpan = base.columnSpan; + double width = 0; + for (int i = 0; i < columnSpan; i++) { + width += + PdfGridRowHelper.getHelper(row!).grid.columns[cellIndex + i].width; + } + if (base._parent != null && + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(base._parent!).row!, + ).getWidth() > + 0 && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).isChildGrid! && + (PdfGridRowHelper.getHelper(row!).getWidth() > + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(base._parent!).row!, + ).getWidth())) { + width = 0; + for (int j = 0; j < base._parent!.columnSpan; j++) { + width += + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(base._parent!).row!, + ).grid.columns[j].width; + } + width = width / row!.cells.count; + } else if (base._parent != null && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).isChildGrid! && + width == -1) { + width = _findGridColumnWidth(base._parent!); + width = width / row!.cells.count; + } + return width; + } + + double _findGridColumnWidth(PdfGridCell pdfGridCell) { + double width = -1; + if (pdfGridCell._parent != null && pdfGridCell._outerCellWidth == -1) { + width = _findGridColumnWidth(pdfGridCell._parent!); + width = width / PdfGridCellHelper.getHelper(pdfGridCell).row!.cells.count; + } else if (pdfGridCell._parent == null && pdfGridCell._outerCellWidth > 0) { + width = pdfGridCell._outerCellWidth; + } + return width; + } + + /// internal method + PdfGraphics drawCellBorders(PdfGraphics graphics, PdfRectangle bounds) { + final PdfBorders borders = base.style.borders; + if (PdfGridRowHelper.getHelper(row!).grid.style.borderOverlapStyle == + PdfBorderOverlapStyle.inside) { + bounds.x = bounds.x + borders.left.width; + bounds.y = bounds.y + borders.top.width; + bounds.width = bounds.width - borders.right.width; + bounds.height = bounds.height - borders.bottom.width; + } + PdfPen? pen = base.style.borders.left; + if (PdfBordersHelper.isAll(base.style.borders)) { + _setTransparency(graphics, pen); + graphics.drawRectangle(pen: pen, bounds: bounds.rect); + } else { + Offset p1 = Offset(bounds.x, bounds.y + bounds.height); + Offset p2 = Offset(bounds.x, bounds.y); + if (base._style!.borders.left.dashStyle == PdfDashStyle.solid && + !PdfPenHelper.getHelper(pen).isImmutable) { + pen.lineCap = PdfLineCap.square; + } + _setTransparency(graphics, pen); + graphics.drawLine(pen, p1, p2); + graphics.restore(); + + p1 = Offset(bounds.x + bounds.width, bounds.y); + p2 = Offset(bounds.x + bounds.width, bounds.y + bounds.height); + pen = base._style!.borders.right; + if (bounds.x + bounds.width > graphics.clientSize.width - pen.width / 2) { + p1 = Offset(graphics.clientSize.width - pen.width / 2, bounds.y); + p2 = Offset( + graphics.clientSize.width - pen.width / 2, + bounds.y + bounds.height, + ); + } + if (base._style!.borders.right.dashStyle == PdfDashStyle.solid && + !PdfPenHelper.getHelper(pen).isImmutable) { + pen.lineCap = PdfLineCap.square; + } + _setTransparency(graphics, pen); + graphics.drawLine(pen, p1, p2); + graphics.restore(); + p1 = Offset(bounds.x, bounds.y); + p2 = Offset(bounds.x + bounds.width, bounds.y); + pen = base._style!.borders.top; + if (base._style!.borders.top.dashStyle == PdfDashStyle.solid && + !PdfPenHelper.getHelper(pen).isImmutable) { + pen.lineCap = PdfLineCap.square; + } + _setTransparency(graphics, pen); + graphics.drawLine(pen, p1, p2); + graphics.restore(); + p1 = Offset(bounds.x + bounds.width, bounds.y + bounds.height); + p2 = Offset(bounds.x, bounds.y + bounds.height); + pen = base._style!.borders.bottom; + if (bounds.y + bounds.height > + graphics.clientSize.height - pen.width / 2) { + p1 = Offset( + bounds.x + bounds.width, + graphics.clientSize.height - pen.width / 2, + ); + p2 = Offset(bounds.x, graphics.clientSize.height - pen.width / 2); + } + if (base._style!.borders.bottom.dashStyle == PdfDashStyle.solid && + !PdfPenHelper.getHelper(pen).isImmutable) { + pen.lineCap = PdfLineCap.square; + } + _setTransparency(graphics, pen); + graphics.drawLine(pen, p1, p2); + } + graphics.restore(); + return graphics; + } + + void _setTransparency(PdfGraphics graphics, PdfPen pen) { + graphics.save(); + graphics.setTransparency(PdfColorHelper.getHelper(pen.color).alpha / 255); + } + + /// internal method + PdfStringLayoutResult? draw( + PdfGraphics? graphics, + PdfRectangle bounds, + bool cancelSubsequentSpans, + ) { + bool isrowbreak = false; + if (!PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).isSingleGrid) { + if ((remainingString != null) || (PdfGridLayouter.repeatRowIndex != -1)) { + _drawParentCells(graphics!, bounds, true); + } else if (PdfGridRowHelper.getHelper(row!).grid.rows.count > 1) { + for ( + int i = 0; + i < PdfGridRowHelper.getHelper(row!).grid.rows.count; + i++ + ) { + if (row == PdfGridRowHelper.getHelper(row!).grid.rows[i]) { + if (PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[i], + ).rowBreakHeight > + 0) { + isrowbreak = true; + } + if ((i > 0) && isrowbreak) { + _drawParentCells(graphics!, bounds, false); + } + } + } + } + } + PdfStringLayoutResult? result; + if (cancelSubsequentSpans) { + final int currentCellIndex = row!.cells.indexOf(base); + for ( + int i = currentCellIndex + 1; + i <= currentCellIndex + base._columnSpan; + i++ + ) { + PdfGridCellHelper.getHelper(row!.cells[i]).isCellMergeContinue = false; + PdfGridCellHelper.getHelper(row!.cells[i]).isRowMergeContinue = false; + } + base._columnSpan = 1; + } + if (isCellMergeContinue || isRowMergeContinue) { + if (isCellMergeContinue && + PdfGridRowHelper.getHelper(row!).grid.style.allowHorizontalOverflow) { + if ((PdfGridRowHelper.getHelper(row!).rowOverflowIndex > 0 && + (row!.cells.indexOf(base) != + PdfGridRowHelper.getHelper(row!).rowOverflowIndex + 1)) || + (PdfGridRowHelper.getHelper(row!).rowOverflowIndex == 0 && + isCellMergeContinue)) { + return result; + } + } else { + return result; + } + } + bounds = _adjustOuterLayoutArea(bounds, graphics); + graphics = _drawCellBackground(graphics, bounds); + final PdfPen? textPen = base._getTextPen(); + final PdfBrush? textBrush = base._getTextBrush(); + final PdfFont? font = base._getTextFont(); + final PdfStringFormat strFormat = + base.style.stringFormat ?? base.stringFormat; + PdfRectangle innerLayoutArea = bounds.clone(); + if (innerLayoutArea.height >= graphics!.clientSize.height) { + if (PdfGridRowHelper.getHelper(row!).grid.allowRowBreakingAcrossPages) { + innerLayoutArea.height = innerLayoutArea.height - innerLayoutArea.y; + bounds.height = bounds.height - bounds.y; + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).isChildGrid!) { + innerLayoutArea.height = + innerLayoutArea.height - + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom; + } + } else { + innerLayoutArea.height = graphics.clientSize.height; + bounds.height = graphics.clientSize.height; + } + } + innerLayoutArea = _adjustContentLayoutArea(innerLayoutArea); + if (base.value is PdfGrid) { + graphics.save(); + graphics.setClip(bounds: innerLayoutArea.rect, mode: PdfFillMode.winding); + final PdfGrid childGrid = base.value as PdfGrid; + PdfGridHelper.getHelper(childGrid).isChildGrid = true; + PdfGridHelper.getHelper(childGrid).parentCell = base; + PdfGridHelper.getHelper(childGrid).listOfNavigatePages = []; + PdfGridLayouter layouter = PdfGridLayouter(childGrid); + PdfLayoutFormat? format = PdfLayoutFormat(); + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).layoutFormat != + null) { + format = + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).layoutFormat; + } else { + format.layoutType = PdfLayoutType.paginate; + } + if (PdfGraphicsHelper.getHelper(graphics).layer != null) { + final PdfLayoutParams param = PdfLayoutParams(); + param.page = PdfGraphicsHelper.getHelper(graphics).page; + param.bounds = innerLayoutArea; + param.format = format; + PdfGridHelper.getHelper(childGrid).setSpan(); + final PdfLayoutResult? childGridResult = layouter.layout(param); + base.value = childGrid; + if (childGridResult != null && param.page != childGridResult.page) { + PdfGridRowHelper.getHelper(row!).gridResult = childGridResult; + bounds.height = graphics.clientSize.height - bounds.y; + } + } else { + PdfGridHelper.getHelper(childGrid).setSpan(); + layouter = PdfGridLayouter(base.value as PdfGrid); + layouter.layoutGrid(graphics, innerLayoutArea); + } + graphics.restore(); + } else if (base.value is PdfTextElement) { + final PdfTextElement textelement = base.value as PdfTextElement; + final PdfPage? page = PdfGraphicsHelper.getHelper(graphics).page; + PdfTextElementHelper.getHelper(textelement).isPdfTextElement = true; + final String textElementString = textelement.text; + PdfTextLayoutResult? textlayoutresult; + if (finished) { + textlayoutresult = + textelement.draw(page: page, bounds: innerLayoutArea.rect) + as PdfTextLayoutResult?; + } else { + textelement.text = remainingString!; + textlayoutresult = + textelement.draw(page: page, bounds: innerLayoutArea.rect) + as PdfTextLayoutResult?; + } + if (textlayoutresult!.remainder != null && + textlayoutresult.remainder!.isNotEmpty) { + remainingString = textlayoutresult.remainder; + finished = false; + } else { + remainingString = null; + finished = true; + } + textelement.text = textElementString; + } else if (base.value is String || remainingString is String) { + String? temp; + PdfRectangle layoutRectangle; + if (innerLayoutArea.height < font!.height) { + layoutRectangle = PdfRectangle( + innerLayoutArea.x, + innerLayoutArea.y, + innerLayoutArea.width, + font.height, + ); + } else { + layoutRectangle = innerLayoutArea; + } + if (innerLayoutArea.height < font.height && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).isChildGrid! && + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).parentCell != + null) { + final double height = + layoutRectangle.height - + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom - + PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.bottom; + if (height > 0 && height < font.height) { + layoutRectangle.height = height; + } else if (height + + PdfGridRowHelper.getHelper( + row!, + ).grid.style.cellPadding.bottom > + 0 && + height + + PdfGridRowHelper.getHelper( + row!, + ).grid.style.cellPadding.bottom < + font.height) { + layoutRectangle.height = + height + + PdfGridRowHelper.getHelper(row!).grid.style.cellPadding.bottom; + } else if (bounds.height < font.height) { + layoutRectangle.height = bounds.height; + } else if (bounds.height - + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom < + font.height) { + layoutRectangle.height = + bounds.height - + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom; + } + } + if (base.style.cellPadding != null && + base.style.cellPadding!.bottom == 0 && + base.style.cellPadding!.left == 0 && + base.style.cellPadding!.right == 0 && + base.style.cellPadding!.top == 0) { + layoutRectangle.width = + layoutRectangle.width - + base.style.borders.left.width + + base.style.borders.right.width; + } + if (finished) { + temp = + remainingString != null && remainingString!.isEmpty + ? remainingString + : base.value as String; + graphics.drawString( + temp!, + font, + pen: textPen, + brush: textBrush, + bounds: layoutRectangle.rect, + format: strFormat, + ); + } else { + graphics.drawString( + remainingString!, + font, + pen: textPen, + brush: textBrush, + bounds: layoutRectangle.rect, + format: strFormat, + ); + } + result = PdfGraphicsHelper.getHelper(graphics).stringLayoutResult; + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).isChildGrid! && + PdfGridRowHelper.getHelper(row!).rowBreakHeight > 0 && + result != null) { + bounds.height = + bounds.height - + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).parentCell!, + ).row!, + ).grid.style.cellPadding.bottom; + } + } else if (base._value is PdfImage) { + if (base.style.cellPadding != null && + base.style.cellPadding != + PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { + final PdfPaddings padding = base.style.cellPadding!; + bounds = PdfRectangle( + bounds.x + padding.left, + bounds.y + padding.top, + bounds.width - (padding.left + padding.right), + bounds.height - (padding.top + padding.bottom), + ); + } else if (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding != + PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { + final PdfPaddings padding = + PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; + bounds = PdfRectangle( + bounds.x + padding.left, + bounds.y + padding.top, + bounds.width - (padding.left + padding.right), + bounds.height - (padding.top + padding.bottom), + ); + } + final PdfImage img = base.value as PdfImage; + double? imgWidth = img.width.toDouble(); + double? imgHeight = img.height.toDouble(); + double spaceX = 0; + double spaceY = 0; + if (base._pdfGridStretchOption == PdfGridStretchOption.uniform || + base._pdfGridStretchOption == PdfGridStretchOption.uniformToFill) { + double ratio = 1; + if (imgWidth > bounds.width) { + ratio = imgWidth / bounds.width; + imgWidth = bounds.width; + imgHeight = imgHeight / ratio; + } + if (imgHeight > bounds.height) { + ratio = imgHeight / bounds.height; + imgHeight = bounds.height; + imgWidth = imgWidth / ratio; + } + if (imgWidth < bounds.width && imgHeight < bounds.height) { + spaceX = bounds.width - imgWidth; + spaceY = bounds.height - imgHeight; + if (spaceX < spaceY) { + ratio = imgWidth / bounds.width; + imgWidth = bounds.width; + imgHeight = imgHeight / ratio; + } else { + ratio = imgHeight / bounds.height; + imgHeight = bounds.height; + imgWidth = imgWidth / ratio; + } + } + } + if (base._pdfGridStretchOption == PdfGridStretchOption.fill || + base._pdfGridStretchOption == PdfGridStretchOption.none) { + imgWidth = bounds.width; + imgHeight = bounds.height; + } + if (base._pdfGridStretchOption == PdfGridStretchOption.uniformToFill) { + double ratio = 1; + if (imgWidth == bounds.width && imgHeight < bounds.height) { + ratio = imgHeight / bounds.height; + imgHeight = bounds.height; + imgWidth = imgWidth / ratio; + } + if (imgHeight == bounds.height && imgWidth < bounds.width) { + ratio = imgWidth / bounds.width; + imgWidth = bounds.width; + imgHeight = imgHeight / ratio; + } + final PdfPage graphicsPage = + PdfGraphicsHelper.getHelper(graphics).page!; + final PdfGraphicsState st = graphicsPage.graphics.save(); + graphicsPage.graphics.setClip( + bounds: bounds.rect, + mode: PdfFillMode.winding, + ); + graphicsPage.graphics.drawImage( + img, + Rect.fromLTWH(bounds.x, bounds.y, imgWidth, imgHeight), + ); + graphicsPage.graphics.restore(st); + } else { + graphics = _setImagePosition( + graphics, + img, + PdfRectangle(bounds.x, bounds.y, imgWidth, imgHeight), + ); + } + graphics!.save(); + } + graphics = drawCellBorders(graphics, bounds); + return result; + } + + void _drawParentCells(PdfGraphics graphics, PdfRectangle bounds, bool b) { + final PdfPoint location = PdfPoint( + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).defaultBorder.right.width / + 2, + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).defaultBorder.top.width / + 2, + ); + if ((bounds.height < graphics.clientSize.height) && (b == true)) { + bounds.height = bounds.height + bounds.y - location.y; + } + final PdfRectangle rect = PdfRectangle( + location.x, + location.y, + bounds.width, + bounds.height, + ); + if (b == false) { + rect.y = bounds.y; + rect.height = bounds.height; + } + PdfGridCell? c = base; + if (base._parent != null) { + if ((PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(c).row!, + ).grid.rows.count == + 1) && + (PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(c).row!, + ).grid.rows[0].cells.count == + 1)) { + PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(c).row!, + ).grid.rows[0].cells[0], + ).present = + true; + } else { + for ( + int rowIndex = 0; + rowIndex < + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(c).row!, + ).grid.rows.count; + rowIndex++ + ) { + final PdfGridRow r = + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(c).row!, + ).grid.rows[rowIndex]; + if (r == PdfGridCellHelper.getHelper(c).row) { + for (int cellIndex = 0; cellIndex < row!.cells.count; cellIndex++) { + final PdfGridCell cell = row!.cells[cellIndex]; + if (cell == c) { + PdfGridCellHelper.getHelper(cell).present = true; + break; + } + } + } + } + } + while (c!._parent != null) { + c = c._parent; + PdfGridCellHelper.getHelper(c!).present = true; + rect.x = + rect.x + + PdfGridRowHelper.getHelper( + PdfGridCellHelper.getHelper(c).row!, + ).grid.style.cellPadding.left; + } + } + if (bounds.x >= rect.x) { + rect.x = rect.x - bounds.x; + if (rect.x < 0) { + rect.x = bounds.x; + } + } + PdfGrid pdfGrid = + PdfGridRowHelper.getHelper(PdfGridCellHelper.getHelper(c).row!).grid; + for (int i = 0; i < pdfGrid.rows.count; i++) { + for (int j = 0; j < pdfGrid.rows[i].cells.count; j++) { + if (PdfGridCellHelper.getHelper(pdfGrid.rows[i].cells[j]).present == + true) { + int cellcount = 0; + if (pdfGrid.rows[i].style.backgroundBrush != null) { + base.style.backgroundBrush = pdfGrid.rows[i].style.backgroundBrush; + double cellwidth = 0; + if (j > 0) { + for (int n = 0; n < j; n++) { + cellwidth += pdfGrid.columns[n].width; + } + } + rect.width = + PdfGridRowHelper.getHelper(pdfGrid.rows[i]).getWidth() - + cellwidth; + final PdfGrid? grid = pdfGrid.rows[i].cells[j].value as PdfGrid?; + if (grid != null) { + for (int l = 0; l < grid.rows.count; l++) { + for (int m = 0; m < grid.rows[l].cells.count; m++) { + if ((PdfGridCellHelper.getHelper( + grid.rows[l].cells[m], + ).present) && + m > 0) { + rect.width = grid.rows[l].cells[m].width; + cellcount = m; + } + } + } + } + graphics = _drawCellBackground(graphics, rect)!; + } + PdfGridCellHelper.getHelper(pdfGrid.rows[i].cells[j]).present = false; + if (pdfGrid.rows[i].cells[j].style.backgroundBrush != null) { + base.style.backgroundBrush = + pdfGrid.rows[i].cells[j].style.backgroundBrush; + if (cellcount == 0) { + rect.width = pdfGrid.columns[j].width; + } + graphics = _drawCellBackground(graphics, rect)!; + } + if (pdfGrid.rows[i].cells[j].value is PdfGrid) { + if (!PdfGridRowHelper.getHelper(pdfGrid.rows[i]).isrowFinish) { + if (cellcount == 0) { + rect.x = rect.x + pdfGrid.style.cellPadding.left; + } + } + pdfGrid = pdfGrid.rows[i].cells[j].value as PdfGrid; + if (pdfGrid.style.backgroundBrush != null) { + base.style.backgroundBrush = pdfGrid.style.backgroundBrush; + if (cellcount == 0) { + if (j < pdfGrid.columns.count) { + rect.width = pdfGrid.columns[j].width; + } + } + graphics = _drawCellBackground(graphics, rect)!; + } + i = -1; + break; + } + } + } + } + if (bounds.height < graphics.clientSize.height) { + bounds.height = bounds.height - bounds.y - location.y; + } + } + + PdfGraphics? _drawCellBackground(PdfGraphics? graphics, PdfRectangle bounds) { + final PdfBrush? backgroundBrush = base._getBackgroundBrush(); + if (backgroundBrush != null) { + graphics!.save(); + graphics.drawRectangle(brush: backgroundBrush, bounds: bounds.rect); + graphics.restore(); + } + if (base.style.backgroundImage != null) { + final PdfImage? image = base.style.backgroundImage; + if (base.style.cellPadding != null && + base.style.cellPadding != + PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { + final PdfPaddings padding = base.style.cellPadding!; + bounds = PdfRectangle( + bounds.x + padding.left, + bounds.y + padding.top, + bounds.width - (padding.left + padding.right), + bounds.height - (padding.top + padding.bottom), + ); + } else if (PdfGridRowHelper.getHelper(row!).grid.style.cellPadding != + PdfPaddings(left: 0, right: 0, top: 0, bottom: 0)) { + final PdfPaddings padding = + PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; + bounds = PdfRectangle( + bounds.x + padding.left, + bounds.y + padding.top, + bounds.width - (padding.left + padding.right), + bounds.height - (padding.top + padding.bottom), + ); + } + return _setImagePosition(graphics, image, bounds); + } + return graphics; + } + + PdfRectangle _adjustContentLayoutArea(PdfRectangle bounds) { + PdfPaddings? padding = base.style.cellPadding; + if (base.value is PdfGrid) { + final PdfSize size = PdfGridHelper.getHelper(base.value).gridSize; + if (padding == null) { + padding = PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; + bounds.width = bounds.width - (padding.right + padding.left); + bounds.height = bounds.height - (padding.bottom + padding.top); + if (base.stringFormat.alignment == PdfTextAlignment.center) { + bounds.x = + bounds.x + padding.left + ((bounds.width - size.width) / 2); + bounds.y = + bounds.y + padding.top + ((bounds.height - size.height) / 2); + } else if (base.stringFormat.alignment == PdfTextAlignment.left) { + bounds.x = bounds.x + padding.left; + bounds.y = bounds.y + padding.top; + } else if (base.stringFormat.alignment == PdfTextAlignment.right) { + bounds.x = bounds.x + padding.left + (bounds.width - size.width); + bounds.y = bounds.y + padding.top; + bounds.width = size.width; + } + } else { + bounds.width = bounds.width - (padding.right + padding.left); + bounds.height = bounds.height - (padding.bottom + padding.top); + + if (base.stringFormat.alignment == PdfTextAlignment.center) { + bounds.x = + bounds.x + padding.left + ((bounds.width - size.width) / 2); + bounds.y = + bounds.y + padding.top + ((bounds.height - size.height) / 2); + } else if (base.stringFormat.alignment == PdfTextAlignment.left) { + bounds.x = bounds.x + padding.left; + bounds.y = bounds.y + padding.top; + } else if (base.stringFormat.alignment == PdfTextAlignment.right) { + bounds.x = bounds.x + padding.left + (bounds.width - size.width); + bounds.y = bounds.y + padding.top; + bounds.width = size.width; + } + } + } else { + if (padding == null) { + padding = PdfGridRowHelper.getHelper(row!).grid.style.cellPadding; + bounds.x = bounds.x + padding.left; + bounds.y = bounds.y + padding.top; + bounds.width = bounds.width - (padding.right + padding.left); + bounds.height = bounds.height - (padding.bottom + padding.top); + } else { + bounds.x = bounds.x + padding.left; + bounds.y = bounds.y + padding.top; + bounds.width = bounds.width - (padding.right + padding.left); + bounds.height = bounds.height - (padding.bottom + padding.top); + } + } + return bounds; + } + + PdfRectangle _adjustOuterLayoutArea(PdfRectangle bounds, PdfGraphics? g) { + bool isHeader = false; + final double cellSpacing = + PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; + if (cellSpacing > 0) { + bounds = PdfRectangle( + bounds.x + cellSpacing, + bounds.y + cellSpacing, + bounds.width - cellSpacing, + bounds.height - cellSpacing, + ); + } + final int currentColIndex = row!.cells.indexOf(base); + if (base.columnSpan > 1 || + (PdfGridRowHelper.getHelper(row!).rowOverflowIndex > 0 && + (currentColIndex == + PdfGridRowHelper.getHelper(row!).rowOverflowIndex + 1) && + isCellMergeContinue)) { + int span = base.columnSpan; + if (span == 1 && isCellMergeContinue) { + for ( + int j = currentColIndex + 1; + j < PdfGridRowHelper.getHelper(row!).grid.columns.count; + j++ + ) { + if (PdfGridCellHelper.getHelper(row!.cells[j]).isCellMergeContinue) { + span++; + } else { + break; + } + } + } + double totalWidth = 0; + for (int i = currentColIndex; i < currentColIndex + span; i++) { + if (PdfGridRowHelper.getHelper( + row!, + ).grid.style.allowHorizontalOverflow) { + double width; + final double compWidth = + PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).size.width < + g!.clientSize.width + ? PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).size.width + : g.clientSize.width; + if (PdfGridHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid, + ).size.width > + g.clientSize.width) { + width = + bounds.x + + totalWidth + + PdfGridRowHelper.getHelper(row!).grid.columns[i].width; + } else { + width = + totalWidth + + PdfGridRowHelper.getHelper(row!).grid.columns[i].width; + } + if (width > compWidth) { + break; + } + } + totalWidth += PdfGridRowHelper.getHelper(row!).grid.columns[i].width; + } + totalWidth -= PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; + bounds.width = totalWidth; + } + if (base.rowSpan > 1 || PdfGridRowHelper.getHelper(row!).rowSpanExists) { + int span = base.rowSpan; + int currentRowIndex = PdfGridRowCollectionHelper.indexOf( + PdfGridRowHelper.getHelper(row!).grid.rows, + row, + ); + if (currentRowIndex == -1) { + currentRowIndex = PdfGridHeaderCollectionHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.headers, + ).indexOf(row!); + if (currentRowIndex != -1) { + isHeader = true; + } + } + if (span == 1 && isCellMergeContinue) { + for ( + int j = currentRowIndex + 1; + j < PdfGridRowHelper.getHelper(row!).grid.rows.count; + j++ + ) { + if (isHeader + ? PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper( + row!, + ).grid.headers[j].cells[currentColIndex], + ).isCellMergeContinue + : PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper( + row!, + ).grid.rows[j].cells[currentColIndex], + ).isCellMergeContinue) { + span++; + } else { + break; + } + } + } + double totalHeight = 0; + double max = 0; + if (isHeader) { + for (int i = currentRowIndex; i < currentRowIndex + span; i++) { + totalHeight += + PdfGridRowHelper.getHelper(row!).grid.headers[i].height; + } + totalHeight -= PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; + bounds.height = totalHeight; + } else { + for (int i = currentRowIndex; i < currentRowIndex + span; i++) { + if (!PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[i], + ).isRowSpanRowHeightSet) { + PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[i], + ).isRowHeightSet = + false; + } + totalHeight += + isHeader + ? PdfGridRowHelper.getHelper(row!).grid.headers[i].height + : PdfGridRowHelper.getHelper(row!).grid.rows[i].height; + final PdfGridRow gridRow = + PdfGridRowHelper.getHelper(row!).grid.rows[i]; + final int rowIndex = PdfGridRowCollectionHelper.indexOf( + PdfGridRowHelper.getHelper(row!).grid.rows, + gridRow, + ); + if (base.rowSpan > 1) { + for ( + int cellIndex = 0; + cellIndex < gridRow.cells.count; + cellIndex++ + ) { + final PdfGridCell cell = gridRow.cells[cellIndex]; + if (cell.rowSpan > 1) { + double tempHeight = 0; + for (int j = i; j < i + cell.rowSpan; j++) { + if (!PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[j], + ).isRowSpanRowHeightSet) { + PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[j], + ).isRowHeightSet = + false; + } + tempHeight += + PdfGridRowHelper.getHelper(row!).grid.rows[j].height; + if (!PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[j], + ).isRowSpanRowHeightSet) { + PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[j], + ).isRowHeightSet = + true; + } + } + if (cell.height > tempHeight) { + if (max < (cell.height - tempHeight)) { + max = cell.height - tempHeight; + if (base._tempRowSpanRemainingHeight != 0 && + max > base._tempRowSpanRemainingHeight) { + max += base._tempRowSpanRemainingHeight; + } + final int index = gridRow.cells.indexOf(cell); + PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper(row!) + .grid + .rows[(rowIndex + cell.rowSpan) - 1] + .cells[index], + ).rowSpanRemainingHeight = + max; + base._tempRowSpanRemainingHeight = + PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper(row!) + .grid + .rows[(rowIndex + cell.rowSpan) - 1] + .cells[index], + ).rowSpanRemainingHeight; + } + } + } + } + } + if (!PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[i], + ).isRowSpanRowHeightSet) { + PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper(row!).grid.rows[i], + ).isRowHeightSet = + true; + } + } + final int cellIndex = row!.cells.indexOf(base); + totalHeight -= PdfGridRowHelper.getHelper(row!).grid.style.cellSpacing; + if (row!.cells[cellIndex].height > totalHeight && + (!PdfGridRowHelper.getHelper( + PdfGridRowHelper.getHelper( + row!, + ).grid.rows[(currentRowIndex + span) - 1], + ).isRowHeightSet)) { + PdfGridCellHelper.getHelper( + PdfGridRowHelper.getHelper( + row!, + ).grid.rows[(currentRowIndex + span) - 1].cells[cellIndex], + ).rowSpanRemainingHeight = + row!.cells[cellIndex].height - totalHeight; + totalHeight = row!.cells[cellIndex].height; + bounds.height = totalHeight; + } else { + bounds.height = totalHeight; + } + if (!PdfGridRowHelper.getHelper(row!).rowMergeComplete) { + bounds.height = totalHeight; + } + } + } + return bounds; + } + + PdfGraphics? _setImagePosition( + PdfGraphics? graphics, + PdfImage? image, + PdfRectangle bounds, + ) { + if (base._imagePosition == PdfGridImagePosition.stretch) { + graphics!.drawImage(image!, bounds.rect); + } else if (base._imagePosition == PdfGridImagePosition.center) { + double gridCentreX; + double gridCentreY; + gridCentreX = bounds.x + (bounds.width / 4); + gridCentreY = bounds.y + (bounds.height / 4); + graphics!.drawImage( + image!, + Rect.fromLTWH( + gridCentreX, + gridCentreY, + bounds.width / 2, + bounds.height / 2, + ), + ); + } else if (base._imagePosition == PdfGridImagePosition.fit) { + final double imageWidth = image!.physicalDimension.width; + final double imageHeight = image.physicalDimension.height; + double? x; + double? y; + if (imageHeight > imageWidth) { + y = bounds.y; + x = bounds.x + bounds.width / 4; + graphics!.drawImage( + image, + Rect.fromLTWH(x, y, bounds.width / 2, bounds.height), + ); + } else { + x = bounds.x; + y = bounds.y + (bounds.height / 4); + graphics!.drawImage( + image, + Rect.fromLTWH(x, y, bounds.width, bounds.height / 2), + ); + } + } else if (base._imagePosition == PdfGridImagePosition.tile) { + final double cellLeft = bounds.x; + final double cellTop = bounds.y; + final double pWidth = _physicalDimension(image, true); + final double pHeight = _physicalDimension(image, false); + double? x = cellLeft; + double y = cellTop; + for (; y < bounds.bottom;) { + for (x = cellLeft; x! < bounds.right;) { + if (x + pWidth > bounds.right && y + pHeight > bounds.bottom) { + final PdfTemplate template = PdfTemplate( + bounds.right - x, + bounds.bottom - y, + ); + template.graphics!.drawImage(image!, Rect.zero); + graphics!.drawPdfTemplate(template, Offset(x, y)); + } else if (x + pWidth > bounds.right) { + final PdfTemplate template = PdfTemplate(bounds.right - x, pHeight); + template.graphics!.drawImage(image!, Rect.zero); + graphics!.drawPdfTemplate(template, Offset(x, y)); + } else if (y + pHeight > bounds.bottom) { + final PdfTemplate template = PdfTemplate(pWidth, bounds.bottom - y); + template.graphics!.drawImage(image!, Rect.zero); + graphics!.drawPdfTemplate(template, Offset(x, y)); + } else { + graphics!.drawImage(image!, Rect.fromLTWH(x, y, 0, 0)); + } + x += pWidth; + } + y += pHeight; + } + } + return graphics; + } + + //if horizontal/vertical resolution is not set, resolution set as default 96. + double _physicalDimension(PdfImage? image, bool isHorizontal) { + if (isHorizontal) { + return image!.width / + ((image.horizontalResolution > 0 ? image.horizontalResolution : 96) / + 72); + } else { + return image!.height / + ((image.verticalResolution > 0 ? image.verticalResolution : 96) / 72); + } + } +} + +/// Provides access to an ordered, strongly typed collection of +/// [PdfGridCell] objects. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid +/// PdfGrid grid = PdfGrid(); +/// //Add columns to grid +/// grid.columns.add(count: 3); +/// //Add headers to grid +/// PdfGridRow header = grid.headers.add(1)[0]; +/// header.cells[0].value = 'Employee ID'; +/// header.cells[1].value = 'Employee Name'; +/// header.cells[2].value = 'Salary'; +/// //Add rows to grid +/// PdfGridRow row1 = grid.rows.add(); +/// //Gets the cell collection from the row +/// PdfGridCellCollection cellCollection = row1.cells; +/// //Gets the specific cell from the row collection +/// PdfGridCell cell1 = cellCollection[0]; +/// cell1.value = 'E01'; +/// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); +/// cellCollection[1].value = 'Clay'; +/// cellCollection[2].value = '\$10000'; +/// PdfGridRow row2 = grid.rows.add(); +/// row2.cells[0].value = 'E02'; +/// row2.cells[1].value = 'Simon'; +/// row2.cells[2].value = '\$12,000'; +/// //Draw the grid in PDF document page +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGridCellCollection { + //Constructors + /// Initializes a new instance of the [PdfGridCellCollection] class + /// with the row. + PdfGridCellCollection._(PdfGridRow row) { + _helper = PdfGridCellCollectionHelper(this); + _helper.row = row; + _helper._cells = []; + } + + //Fields + late PdfGridCellCollectionHelper _helper; + + //Properties + /// Gets the cells count. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// //Gets the cell collection from the row + /// PdfGridCellCollection cellCollection = row1.cells; + /// //Gets the specific cell from the row collection + /// PdfGridCell cell1 = cellCollection[0]; + /// cell1.value = 'E01'; + /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); + /// cellCollection[1].value = 'Clay'; + /// cellCollection[2].value = '\$10000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Gets the cells count + /// int cellsCount = cellCollection.count; + /// //Gets the index of particular cell + /// int index = cellCollection.indexOf(cell1); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get count => _helper._cells.length; + + /// Gets the [PdfGridCell] at the specified index. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// //Gets the cell collection from the row + /// PdfGridCellCollection cellCollection = row1.cells; + /// //Gets the specific cell from the row collection + /// PdfGridCell cell1 = cellCollection[0]; + /// cell1.value = 'E01'; + /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); + /// cellCollection[1].value = 'Clay'; + /// cellCollection[2].value = '\$10000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Gets the cells count + /// int cellsCount = cellCollection.count; + /// //Gets the index of particular cell + /// int index = cellCollection.indexOf(cell1); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridCell operator [](int index) => _returnValue(index); + + //Public methods + /// Returns the index of a particular cell in the collection. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// PdfGridRow header = grid.headers.add(1)[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// //Gets the cell collection from the row + /// PdfGridCellCollection cellCollection = row1.cells; + /// //Gets the specific cell from the row collection + /// PdfGridCell cell1 = cellCollection[0]; + /// cell1.value = 'E01'; + /// cell1.style.cellPadding = PdfPaddings(left: 0, right: 0, top: 10, bottom: 10); + /// cellCollection[1].value = 'Clay'; + /// cellCollection[2].value = '\$10000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Gets the cells count + /// int cellsCount = cellCollection.count; + /// //Gets the index of particular cell + /// int index = cellCollection.indexOf(cell1); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int indexOf(PdfGridCell cell) { + return _helper._cells.indexOf(cell); + } + + //Implementation + PdfGridCell _returnValue(int index) { + if (index < 0 || index >= _helper._cells.length) { + // ignore: deprecated_member_use + throw IndexError(index, _helper._cells); + } + return _helper._cells[index]; + } +} + +/// [PdfGridCellCollection] helper +class PdfGridCellCollectionHelper { + /// internal constructor + PdfGridCellCollectionHelper(this.base); + + /// internal field + PdfGridCellCollection base; + + /// internal field + late PdfGridRow row; + late List _cells; + + /// internal method + static PdfGridCellCollectionHelper getHelper(PdfGridCellCollection base) { + return base._helper; + } + + /// internal method + static PdfGridCellCollection load(PdfGridRow row) { + return PdfGridCellCollection._(row); + } + + /// internal method + void add(PdfGridCell cell) { + // cell.style ??= _row!.style as PdfGridCellStyle; + PdfGridCellHelper.getHelper(cell).row = row; + _cells.add(cell); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_column.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_column.dart index 4fc729d1c..72d70fad2 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_column.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_column.dart @@ -1,539 +1,539 @@ -import '../../graphics/fonts/pdf_string_format.dart'; -import 'pdf_grid.dart'; -import 'pdf_grid_cell.dart'; -import 'pdf_grid_row.dart'; - -/// Represents the schema of a column in a [PdfGrid]. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid -/// PdfGrid grid = PdfGrid(); -/// //Create column to the PDF grid -/// PdfGridColumn column = PdfGridColumn(grid); -/// //Add columns to grid -/// grid.columns.add(column: column); -/// grid.columns.add(count: 2); -/// //Add headers to grid -/// grid.headers.add(1); -/// PdfGridRow header = grid.headers[0]; -/// header.cells[0].value = 'Employee ID'; -/// header.cells[1].value = 'Employee Name'; -/// header.cells[2].value = 'Salary'; -/// //Add rows to grid -/// PdfGridRow row1 = grid.rows.add(); -/// row1.cells[0].value = 'E01'; -/// row1.cells[1].value = 'Clay'; -/// row1.cells[2].value = '\$10,000'; -/// PdfGridRow row2 = grid.rows.add(); -/// row2.cells[0].value = 'E02'; -/// row2.cells[1].value = 'Simon'; -/// row2.cells[2].value = '\$12,000'; -/// //Set the width -/// grid.columns[1].width = 50; -/// //Draw the grid in PDF document page -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGridColumn { - //Constructors - /// Initializes a new instance of the [PdfGridColumn] class - /// with the parent grid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Create column to the PDF grid - /// PdfGridColumn column = PdfGridColumn(grid); - /// //Add columns to grid - /// grid.columns.add(column: column); - /// grid.columns.add(count: 2); - /// //Add headers to grid - /// grid.headers.add(1); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the width - /// grid.columns[1].width = 50; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridColumn(PdfGrid grid) { - _helper = PdfGridColumnHelper(this); - _grid = grid; - _helper.width = -1; - _helper.isCustomWidth = false; - } - - //Fields - late PdfGridColumnHelper _helper; - late PdfGrid _grid; - PdfStringFormat? _format; - - //Properties - /// Gets the width of the [PdfGridColumn]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Create column to the PDF grid - /// PdfGridColumn column = PdfGridColumn(grid); - /// //Add columns to grid - /// grid.columns.add(column: column); - /// grid.columns.add(count: 2); - /// //Add headers to grid - /// grid.headers.add(1); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the width - /// grid.columns[1].width = 50; - /// //Set the column text format - /// grid.columns[0].format = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get width => _helper.width; - set width(double value) { - _helper.isCustomWidth = true; - _helper.width = value; - } - - /// Gets the information about the text formatting. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Create column to the PDF grid - /// PdfGridColumn column = PdfGridColumn(grid); - /// //Add columns to grid - /// grid.columns.add(column: column); - /// grid.columns.add(count: 2); - /// //Add headers to grid - /// grid.headers.add(1); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the width - /// grid.columns[1].width = 50; - /// //Set the column text format - /// grid.columns[0].format = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfStringFormat get format => _format ??= PdfStringFormat(); - set format(PdfStringFormat value) { - _format = value; - } - - /// Gets the parent [PdfGrid]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Create column to the PDF grid - /// PdfGridColumn column = PdfGridColumn(grid); - /// //Add columns to grid - /// grid.columns.add(column: column); - /// grid.columns.add(count: 2); - /// //Add headers to grid - /// grid.headers.add(1); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the width - /// grid.columns[1].width = 50; - /// //Set the column text format - /// grid.columns[0].format = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGrid get grid => _grid; -} - -/// [PdfGridColumn] helper -class PdfGridColumnHelper { - /// internal constructor - PdfGridColumnHelper(this.base); - - /// internal field - PdfGridColumn base; - - /// internal method - static PdfGridColumnHelper getHelper(PdfGridColumn base) { - return base._helper; - } - - /// internal field - late bool isCustomWidth; - - /// internal field - late double width; -} - -/// Provides access to an ordered, strongly typed collection of [PdfGridColumn] -/// objects. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid -/// PdfGrid grid = PdfGrid(); -/// //Create column to the PDF grid -/// PdfGridColumn column = PdfGridColumn(grid); -/// //Gets column form the PDF grid -/// PdfGridColumnCollection columns = grid.columns; -/// //Add columns to grid -/// columns.add(column: column); -/// columns.add(count: 2); -/// //Add headers to grid -/// grid.headers.add(1); -/// PdfGridRow header = grid.headers[0]; -/// header.cells[0].value = 'Employee ID'; -/// header.cells[1].value = 'Employee Name'; -/// header.cells[2].value = 'Salary'; -/// //Add rows to grid -/// PdfGridRow row1 = grid.rows.add(); -/// row1.cells[0].value = 'E01'; -/// row1.cells[1].value = 'Clay'; -/// row1.cells[2].value = '\$10,000'; -/// PdfGridRow row2 = grid.rows.add(); -/// row2.cells[0].value = 'E02'; -/// row2.cells[1].value = 'Simon'; -/// row2.cells[2].value = '\$12,000'; -/// //Set the width -/// grid.columns[1].width = 50; -/// //Set the column text format -/// grid.columns[0].format = PdfStringFormat( -/// alignment: PdfTextAlignment.center, -/// lineAlignment: PdfVerticalAlignment.bottom); -/// //Draw the grid in PDF document page -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGridColumnCollection { - /// Initializes a new instance of the [PdfGridColumnCollection] class - /// with the parent grid. - PdfGridColumnCollection(PdfGrid grid) { - _helper = PdfGridColumnCollectionHelper(this); - _helper._grid = grid; - _helper._columns = []; - _helper._columnsWidth = -1; - } - - //Fields - late PdfGridColumnCollectionHelper _helper; - - //Properties - /// Gets the number of columns in the [PdfGrid]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Create column to the PDF grid - /// PdfGridColumn column = PdfGridColumn(grid); - /// //Gets column form the PDF grid - /// PdfGridColumnCollection columns = grid.columns; - /// //Add columns to grid - /// columns.add(column: column); - /// columns.add(count: 2); - /// //Gets column count - /// int columnCount = columns.count; - /// //Add headers to grid - /// grid.headers.add(1); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the width - /// grid.columns[1].width = 50; - /// //Set the column text format - /// grid.columns[0].format = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get count => _helper._columns.length; - - /// Gets the [PdfGridColumn] at the specified index. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Create column to the PDF grid - /// PdfGridColumn column = PdfGridColumn(grid); - /// //Gets column form the PDF grid - /// PdfGridColumnCollection columns = grid.columns; - /// //Add columns to grid - /// columns.add(column: column); - /// columns.add(count: 2); - /// //Add headers to grid - /// grid.headers.add(1); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the width - /// grid.columns[1].width = 50; - /// //Set the column text format - /// grid.columns[0].format = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridColumn operator [](int index) => _returnValue(index); - - //Public methods - - /// Adds the column into the collection. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Create column to the PDF grid - /// PdfGridColumn column = PdfGridColumn(grid); - /// //Gets column form the PDF grid - /// PdfGridColumnCollection columns = grid.columns; - /// //Add columns to grid - /// columns.add(column: column); - /// columns.add(count: 2); - /// //Add headers to grid - /// grid.headers.add(1); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the width - /// grid.columns[1].width = 50; - /// //Set the column text format - /// grid.columns[0].format = PdfStringFormat( - /// alignment: PdfTextAlignment.center, - /// lineAlignment: PdfVerticalAlignment.bottom); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void add({int? count, PdfGridColumn? column}) { - if (count == null && column == null) { - final PdfGridColumn column = PdfGridColumn(_helper._grid); - _helper._columns.add(column); - } else { - if (count != null) { - for (int i = 0; i < count; i++) { - _helper._columns.add(PdfGridColumn(_helper._grid)); - for (int i = 0; i < _helper._grid.rows.count; i++) { - final PdfGridRow row = _helper._grid.rows[i]; - final PdfGridCell cell = PdfGridCell(); - cell.value = ''; - PdfGridCellCollectionHelper.getHelper(row.cells).add(cell); - } - } - } - if (column != null) { - _helper._columns.add(column); - } - } - } - - //Implementation - PdfGridColumn _returnValue(int index) { - if (index < 0 || index >= _helper._columns.length) { - // ignore: deprecated_member_use - throw IndexError(index, _helper._columns); - } - return _helper._columns[index]; - } -} - -/// [PdfGridColumnCollection] helper -class PdfGridColumnCollectionHelper { - /// internal constructor - PdfGridColumnCollectionHelper(this.base); - - /// internal field - PdfGridColumnCollection base; - late double _columnsWidth; - late PdfGrid _grid; - late List _columns; - - /// internal method - static PdfGridColumnCollectionHelper getHelper(PdfGridColumnCollection base) { - return base._helper; - } - - /// internal method - double get columnWidth { - if (_columnsWidth == -1) { - _columnsWidth = _measureColumnsWidth(); - } - if (PdfGridHelper.getHelper(_grid).initialWidth != 0 && - _columnsWidth != PdfGridHelper.getHelper(_grid).initialWidth && - !_grid.style.allowHorizontalOverflow) { - _columnsWidth = PdfGridHelper.getHelper(_grid).initialWidth; - PdfGridHelper.getHelper(_grid).isPageWidth = true; - } - return _columnsWidth; - } - - double _measureColumnsWidth() { - double totalWidth = 0; - PdfGridHelper.getHelper(_grid).measureColumnsWidth(); - for (int i = 0; i < _columns.length; i++) { - totalWidth += _columns[i].width; - } - return totalWidth; - } - - /// internal method - - List getDefaultWidths(double? totalWidth) { - final List widths = List.filled(base.count, 0); - int subFactor = base.count; - for (int i = 0; i < base.count; i++) { - if (PdfGridHelper.getHelper(_grid).isPageWidth && - totalWidth! >= 0 && - !PdfGridColumnHelper.getHelper(_columns[i]).isCustomWidth) { - _columns[i].width = -1; - } else { - widths[i] = _columns[i].width; - if (_columns[i].width > 0 && - PdfGridColumnHelper.getHelper(_columns[i]).isCustomWidth) { - totalWidth = totalWidth! - _columns[i].width; - subFactor--; - } else { - widths[i] = -1; - } - } - } - for (int i = 0; i < base.count; i++) { - final double width = totalWidth! / subFactor; - if (widths[i]! <= 0) { - widths[i] = width; - } - } - return widths; - } -} +import '../../graphics/fonts/pdf_string_format.dart'; +import 'pdf_grid.dart'; +import 'pdf_grid_cell.dart'; +import 'pdf_grid_row.dart'; + +/// Represents the schema of a column in a [PdfGrid]. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid +/// PdfGrid grid = PdfGrid(); +/// //Create column to the PDF grid +/// PdfGridColumn column = PdfGridColumn(grid); +/// //Add columns to grid +/// grid.columns.add(column: column); +/// grid.columns.add(count: 2); +/// //Add headers to grid +/// grid.headers.add(1); +/// PdfGridRow header = grid.headers[0]; +/// header.cells[0].value = 'Employee ID'; +/// header.cells[1].value = 'Employee Name'; +/// header.cells[2].value = 'Salary'; +/// //Add rows to grid +/// PdfGridRow row1 = grid.rows.add(); +/// row1.cells[0].value = 'E01'; +/// row1.cells[1].value = 'Clay'; +/// row1.cells[2].value = '\$10,000'; +/// PdfGridRow row2 = grid.rows.add(); +/// row2.cells[0].value = 'E02'; +/// row2.cells[1].value = 'Simon'; +/// row2.cells[2].value = '\$12,000'; +/// //Set the width +/// grid.columns[1].width = 50; +/// //Draw the grid in PDF document page +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGridColumn { + //Constructors + /// Initializes a new instance of the [PdfGridColumn] class + /// with the parent grid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Create column to the PDF grid + /// PdfGridColumn column = PdfGridColumn(grid); + /// //Add columns to grid + /// grid.columns.add(column: column); + /// grid.columns.add(count: 2); + /// //Add headers to grid + /// grid.headers.add(1); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the width + /// grid.columns[1].width = 50; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridColumn(PdfGrid grid) { + _helper = PdfGridColumnHelper(this); + _grid = grid; + _helper.width = -1; + _helper.isCustomWidth = false; + } + + //Fields + late PdfGridColumnHelper _helper; + late PdfGrid _grid; + PdfStringFormat? _format; + + //Properties + /// Gets the width of the [PdfGridColumn]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Create column to the PDF grid + /// PdfGridColumn column = PdfGridColumn(grid); + /// //Add columns to grid + /// grid.columns.add(column: column); + /// grid.columns.add(count: 2); + /// //Add headers to grid + /// grid.headers.add(1); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the width + /// grid.columns[1].width = 50; + /// //Set the column text format + /// grid.columns[0].format = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get width => _helper.width; + set width(double value) { + _helper.isCustomWidth = true; + _helper.width = value; + } + + /// Gets the information about the text formatting. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Create column to the PDF grid + /// PdfGridColumn column = PdfGridColumn(grid); + /// //Add columns to grid + /// grid.columns.add(column: column); + /// grid.columns.add(count: 2); + /// //Add headers to grid + /// grid.headers.add(1); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the width + /// grid.columns[1].width = 50; + /// //Set the column text format + /// grid.columns[0].format = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfStringFormat get format => _format ??= PdfStringFormat(); + set format(PdfStringFormat value) { + _format = value; + } + + /// Gets the parent [PdfGrid]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Create column to the PDF grid + /// PdfGridColumn column = PdfGridColumn(grid); + /// //Add columns to grid + /// grid.columns.add(column: column); + /// grid.columns.add(count: 2); + /// //Add headers to grid + /// grid.headers.add(1); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the width + /// grid.columns[1].width = 50; + /// //Set the column text format + /// grid.columns[0].format = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGrid get grid => _grid; +} + +/// [PdfGridColumn] helper +class PdfGridColumnHelper { + /// internal constructor + PdfGridColumnHelper(this.base); + + /// internal field + PdfGridColumn base; + + /// internal method + static PdfGridColumnHelper getHelper(PdfGridColumn base) { + return base._helper; + } + + /// internal field + late bool isCustomWidth; + + /// internal field + late double width; +} + +/// Provides access to an ordered, strongly typed collection of [PdfGridColumn] +/// objects. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid +/// PdfGrid grid = PdfGrid(); +/// //Create column to the PDF grid +/// PdfGridColumn column = PdfGridColumn(grid); +/// //Gets column form the PDF grid +/// PdfGridColumnCollection columns = grid.columns; +/// //Add columns to grid +/// columns.add(column: column); +/// columns.add(count: 2); +/// //Add headers to grid +/// grid.headers.add(1); +/// PdfGridRow header = grid.headers[0]; +/// header.cells[0].value = 'Employee ID'; +/// header.cells[1].value = 'Employee Name'; +/// header.cells[2].value = 'Salary'; +/// //Add rows to grid +/// PdfGridRow row1 = grid.rows.add(); +/// row1.cells[0].value = 'E01'; +/// row1.cells[1].value = 'Clay'; +/// row1.cells[2].value = '\$10,000'; +/// PdfGridRow row2 = grid.rows.add(); +/// row2.cells[0].value = 'E02'; +/// row2.cells[1].value = 'Simon'; +/// row2.cells[2].value = '\$12,000'; +/// //Set the width +/// grid.columns[1].width = 50; +/// //Set the column text format +/// grid.columns[0].format = PdfStringFormat( +/// alignment: PdfTextAlignment.center, +/// lineAlignment: PdfVerticalAlignment.bottom); +/// //Draw the grid in PDF document page +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGridColumnCollection { + /// Initializes a new instance of the [PdfGridColumnCollection] class + /// with the parent grid. + PdfGridColumnCollection(PdfGrid grid) { + _helper = PdfGridColumnCollectionHelper(this); + _helper._grid = grid; + _helper._columns = []; + _helper._columnsWidth = -1; + } + + //Fields + late PdfGridColumnCollectionHelper _helper; + + //Properties + /// Gets the number of columns in the [PdfGrid]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Create column to the PDF grid + /// PdfGridColumn column = PdfGridColumn(grid); + /// //Gets column form the PDF grid + /// PdfGridColumnCollection columns = grid.columns; + /// //Add columns to grid + /// columns.add(column: column); + /// columns.add(count: 2); + /// //Gets column count + /// int columnCount = columns.count; + /// //Add headers to grid + /// grid.headers.add(1); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the width + /// grid.columns[1].width = 50; + /// //Set the column text format + /// grid.columns[0].format = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get count => _helper._columns.length; + + /// Gets the [PdfGridColumn] at the specified index. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Create column to the PDF grid + /// PdfGridColumn column = PdfGridColumn(grid); + /// //Gets column form the PDF grid + /// PdfGridColumnCollection columns = grid.columns; + /// //Add columns to grid + /// columns.add(column: column); + /// columns.add(count: 2); + /// //Add headers to grid + /// grid.headers.add(1); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the width + /// grid.columns[1].width = 50; + /// //Set the column text format + /// grid.columns[0].format = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridColumn operator [](int index) => _returnValue(index); + + //Public methods + + /// Adds the column into the collection. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Create column to the PDF grid + /// PdfGridColumn column = PdfGridColumn(grid); + /// //Gets column form the PDF grid + /// PdfGridColumnCollection columns = grid.columns; + /// //Add columns to grid + /// columns.add(column: column); + /// columns.add(count: 2); + /// //Add headers to grid + /// grid.headers.add(1); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the width + /// grid.columns[1].width = 50; + /// //Set the column text format + /// grid.columns[0].format = PdfStringFormat( + /// alignment: PdfTextAlignment.center, + /// lineAlignment: PdfVerticalAlignment.bottom); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void add({int? count, PdfGridColumn? column}) { + if (count == null && column == null) { + final PdfGridColumn column = PdfGridColumn(_helper._grid); + _helper._columns.add(column); + } else { + if (count != null) { + for (int i = 0; i < count; i++) { + _helper._columns.add(PdfGridColumn(_helper._grid)); + for (int i = 0; i < _helper._grid.rows.count; i++) { + final PdfGridRow row = _helper._grid.rows[i]; + final PdfGridCell cell = PdfGridCell(); + cell.value = ''; + PdfGridCellCollectionHelper.getHelper(row.cells).add(cell); + } + } + } + if (column != null) { + _helper._columns.add(column); + } + } + } + + //Implementation + PdfGridColumn _returnValue(int index) { + if (index < 0 || index >= _helper._columns.length) { + // ignore: deprecated_member_use + throw IndexError(index, _helper._columns); + } + return _helper._columns[index]; + } +} + +/// [PdfGridColumnCollection] helper +class PdfGridColumnCollectionHelper { + /// internal constructor + PdfGridColumnCollectionHelper(this.base); + + /// internal field + PdfGridColumnCollection base; + late double _columnsWidth; + late PdfGrid _grid; + late List _columns; + + /// internal method + static PdfGridColumnCollectionHelper getHelper(PdfGridColumnCollection base) { + return base._helper; + } + + /// internal method + double get columnWidth { + if (_columnsWidth == -1) { + _columnsWidth = _measureColumnsWidth(); + } + if (PdfGridHelper.getHelper(_grid).initialWidth != 0 && + _columnsWidth != PdfGridHelper.getHelper(_grid).initialWidth && + !_grid.style.allowHorizontalOverflow) { + _columnsWidth = PdfGridHelper.getHelper(_grid).initialWidth; + PdfGridHelper.getHelper(_grid).isPageWidth = true; + } + return _columnsWidth; + } + + double _measureColumnsWidth() { + double totalWidth = 0; + PdfGridHelper.getHelper(_grid).measureColumnsWidth(); + for (int i = 0; i < _columns.length; i++) { + totalWidth += _columns[i].width; + } + return totalWidth; + } + + /// internal method + + List getDefaultWidths(double? totalWidth) { + final List widths = List.filled(base.count, 0); + int subFactor = base.count; + for (int i = 0; i < base.count; i++) { + if (PdfGridHelper.getHelper(_grid).isPageWidth && + totalWidth! >= 0 && + !PdfGridColumnHelper.getHelper(_columns[i]).isCustomWidth) { + _columns[i].width = -1; + } else { + widths[i] = _columns[i].width; + if (_columns[i].width > 0 && + PdfGridColumnHelper.getHelper(_columns[i]).isCustomWidth) { + totalWidth = totalWidth! - _columns[i].width; + subFactor--; + } else { + widths[i] = -1; + } + } + } + for (int i = 0; i < base.count; i++) { + final double width = totalWidth! / subFactor; + if (widths[i]! <= 0) { + widths[i] = width; + } + } + return widths; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_row.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_row.dart index de03b4e42..b95f218b0 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_row.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/pdf_grid_row.dart @@ -1,1131 +1,1131 @@ -import 'dart:math'; - -import '../../graphics/figures/base/text_layouter.dart'; -import 'pdf_grid.dart'; -import 'pdf_grid_cell.dart'; -import 'styles/style.dart'; - -/// Provides customization of the settings for the particular row. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid -/// PdfGrid grid = PdfGrid(); -/// //Add columns to grid -/// grid.columns.add(count: 3); -/// //Add headers to grid -/// grid.headers.add(2); -/// PdfGridRow header = grid.headers[0]; -/// header.cells[0].value = 'Employee ID'; -/// header.cells[1].value = 'Employee Name'; -/// header.cells[2].value = 'Salary'; -/// //Add rows to grid -/// PdfGridRow row1 = grid.rows.add(); -/// row1.cells[0].value = 'E01'; -/// row1.cells[1].value = 'Clay'; -/// row1.cells[2].value = '\$10,000'; -/// PdfGridRow row2 = grid.rows.add(); -/// row2.cells[0].value = 'E02'; -/// row2.cells[1].value = 'Simon'; -/// row2.cells[2].value = '\$12,000'; -/// //Set the row span -/// row1.cells[1].rowSpan = 2; -/// //Set the row height -/// row2.height = 20; -/// //Set the row style -/// row1.style = PdfGridRowStyle( -/// backgroundBrush: PdfBrushes.dimGray, -/// textPen: PdfPens.lightGoldenrodYellow, -/// textBrush: PdfBrushes.darkOrange, -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); -/// //Draw the grid in PDF document page -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGridRow { - /// Initializes a new instance of the [PdfGridRow] class with the parent grid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// row1.style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridRow(PdfGrid grid, {PdfGridRowStyle? style, double? height}) { - _helper = PdfGridRowHelper(this); - _initialize(grid, style, height); - } - - //Fields - late PdfGridRowHelper _helper; - PdfGridRowStyle? _style; - late double _height; - late double _width; - - //Properties - /// Gets the cells from the selected row. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridCellCollection get cells { - _helper.cells ??= PdfGridCellCollectionHelper.load(this); - return _helper.cells!; - } - - /// Gets or sets the row style. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// row1.style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Create the PDF grid row style. Assign to second row - /// PdfGridRowStyle rowStyle = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, - /// textPen: PdfPens.indianRed, - /// textBrush: PdfBrushes.lightYellow, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// row2.style = rowStyle; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridRowStyle get style { - _style ??= PdfGridRowStyle(); - return _style!; - } - - set style(PdfGridRowStyle? value) { - _style = value; - } - - /// Gets or sets the height of the row. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// row1.style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double get height { - if (!_helper.isRowHeightSet) { - _height = _measureHeight(); - } - return _height; - } - - set height(double value) { - _helper.isRowHeightSet = true; - _height = value; - } - - //Implementation - void _initialize(PdfGrid grid, PdfGridRowStyle? style, double? height) { - if (style != null) { - _style = style; - } - _helper.grid = grid; - if (height != null) { - this.height = height; - } else { - _height = -1; - } - _width = -1; - _helper.rowSpanExists = false; - _helper.rowBreakHeight = 0; - _helper.rowOverflowIndex = 0; - _helper.isRowBreaksNextPage = false; - _helper.isrowFinish = false; - _helper.rowMergeComplete = true; - _helper.noOfPageCount = 0; - _helper.isRowHeightSet = false; - _helper.maximumRowSpan = 0; - _helper.isPageBreakRowSpanApplied = false; - _helper.isRowSpanRowHeightSet = false; - _helper.isHeaderRow = false; - } - - double _measureHeight() { - double rowSpanRemainingHeight = 0; - bool isHeader = false; - double rowHeight = cells[0].rowSpan > 1 ? 0 : cells[0].height; - double maxHeight = 0; - if (PdfGridHeaderCollectionHelper.getHelper( - _helper.grid.headers, - ).indexOf(this) != - -1) { - isHeader = true; - } - for (int i = 0; i < _helper.cells!.count; i++) { - final PdfGridCell cell = _helper.cells![i]; - if (PdfGridCellHelper.getHelper(cell).rowSpanRemainingHeight > - rowSpanRemainingHeight) { - rowSpanRemainingHeight = - PdfGridCellHelper.getHelper(cell).rowSpanRemainingHeight; - } - if (PdfGridCellHelper.getHelper(cell).isRowMergeContinue) { - continue; - } - if (!PdfGridCellHelper.getHelper(cell).isRowMergeContinue) { - _helper.rowMergeComplete = false; - } - if (cell.rowSpan > 1) { - if (maxHeight < cell.height) { - maxHeight = cell.height; - } - continue; - } - rowHeight = max(rowHeight, cell.height); - } - if (rowHeight == 0) { - rowHeight = maxHeight; - } else if (rowSpanRemainingHeight > 0) { - rowHeight = rowHeight + rowSpanRemainingHeight; - } - if (isHeader && maxHeight != 0 && rowHeight != 0 && rowHeight < maxHeight) { - rowHeight = maxHeight; - } - return rowHeight; - } -} - -/// [PdfGridRow] helper -class PdfGridRowHelper { - /// internal constructor - PdfGridRowHelper(this.base); - - /// internal field - PdfGridRow base; - - /// internal method - static PdfGridRowHelper getHelper(PdfGridRow base) { - return base._helper; - } - - /// internal method - double getWidth() { - if (base._width == -1) { - base._width = _measureWidth(); - } - return base._width; - } - - double _measureWidth() { - double width = 0; - for (int i = 0; i < grid.columns.count; i++) { - width += grid.columns[i].width; - } - return width; - } - - /// internal field - late PdfGrid grid; - - /// internal field - PdfGridCellCollection? cells; - - /// internal method - late bool rowSpanExists; - - /// internal method - late bool isHeaderRow; - - /// internal method - late bool isRowSpanRowHeightSet; - - /// internal method - late bool isPageBreakRowSpanApplied; - - /// internal method - late bool isRowHeightSet; - - /// internal method - late bool rowMergeComplete; - - /// internal method - late bool isrowFinish; - - /// internal method - late bool isRowBreaksNextPage; - - /// internal method - late int maximumRowSpan; - - /// internal method - late int noOfPageCount; - - /// internal method - PdfLayoutResult? gridResult; - - /// internal method - late int rowOverflowIndex; - - /// internal method - late double rowBreakHeight; - - /// internal method - int get index => grid.rows._indexOf(base); -} - -/// Provides access to an ordered, strongly typed collection of -/// [PdfGridRow] objects. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid -/// PdfGrid grid = PdfGrid(); -/// //Add columns to grid -/// grid.columns.add(count: 3); -/// //Add headers to grid -/// grid.headers.add(2); -/// PdfGridRow header = grid.headers[0]; -/// header.cells[0].value = 'Employee ID'; -/// header.cells[1].value = 'Employee Name'; -/// header.cells[2].value = 'Salary'; -/// //Add rows to grid -/// grid.rows.add(); -/// grid.rows.add(); -/// //Gets the row collection -/// PdfGridRowCollection rowCollection = grid.rows; -/// PdfGridRow row1 = rowCollection[0]; -/// row1.cells[0].value = 'E01'; -/// row1.cells[1].value = 'Clay'; -/// row1.cells[2].value = '\$10,000'; -/// PdfGridRow row2 = rowCollection[1]; -/// row2.cells[0].value = 'E02'; -/// row2.cells[1].value = 'Simon'; -/// row2.cells[2].value = '\$12,000'; -/// //Set the row span -/// row1.cells[1].rowSpan = 2; -/// //Set the row height -/// row2.height = 20; -/// //Set the row style -/// rowCollection[0].style = PdfGridRowStyle( -/// backgroundBrush: PdfBrushes.dimGray, -/// textPen: PdfPens.lightGoldenrodYellow, -/// textBrush: PdfBrushes.darkOrange, -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); -/// //Draw the grid in PDF document page -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGridRowCollection { - /// Initializes a new instance of the [PdfGridRowCollection] class - /// with the parent grid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// grid.rows.add(); - /// grid.rows.add(); - /// //Gets the row collection - /// PdfGridRowCollection rowCollection = grid.rows; - /// PdfGridRow row1 = rowCollection[0]; - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = rowCollection[1]; - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// rowCollection[0].style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridRowCollection(PdfGrid grid) { - _grid = grid; - _rows = []; - } - - //Fields - late PdfGrid _grid; - late List _rows; - - //Properties - /// Gets the rows count. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// grid.rows.add(); - /// grid.rows.add(); - /// //Gets the row count - /// int rowCount = grid.rows.count; - /// //Gets the row collection - /// PdfGridRowCollection rowCollection = grid.rows; - /// PdfGridRow row1 = rowCollection[0]; - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = rowCollection[1]; - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// rowCollection[0].style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get count => _rows.length; - - /// Gets the [PdfGridRow] at the specified index. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// grid.rows.add(); - /// grid.rows.add(); - /// //Gets the row collection - /// PdfGridRowCollection rowCollection = grid.rows; - /// PdfGridRow row1 = rowCollection[0]; - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = rowCollection[1]; - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// rowCollection[0].style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridRow operator [](int index) => _returnValue(index); - - //Public methods - /// Add a row to the grid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// grid.rows.add(); - /// grid.rows.add(); - /// //Gets the row collection - /// PdfGridRowCollection rowCollection = grid.rows; - /// PdfGridRow row1 = rowCollection[0]; - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = rowCollection[1]; - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the row span - /// row1.cells[1].rowSpan = 2; - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// rowCollection[0].style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridRow add([PdfGridRow? row]) { - if (row == null) { - final PdfGridRow row = PdfGridRow(_grid); - add(row); - return row; - } else { - row.style.font = _grid.style.font; - row.style.backgroundBrush = _grid.style.backgroundBrush; - row.style.textPen = _grid.style.textPen; - row.style.textBrush = _grid.style.textBrush; - if (row.cells.count == 0) { - for (int i = 0; i < _grid.columns.count; i++) { - PdfGridCellCollectionHelper.getHelper(row.cells).add(PdfGridCell()); - } - } - _rows.add(row); - return row; - } - } - - /// Sets the row span and column span to a cell. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the rows span - /// grid.rows.setSpan(0, 1, 2, 1); - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// row1.style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void setSpan(int rowIndex, int cellIndex, int rowSpan, int columnSpan) { - if (rowIndex > _grid.rows.count) { - ArgumentError.value(rowIndex, 'rowIndex', 'Index out of range'); - } - if (cellIndex > _grid.columns.count) { - ArgumentError.value(cellIndex, 'cellIndex', 'Index out of range'); - } - final PdfGridCell cell = _grid.rows[rowIndex].cells[cellIndex]; - cell.rowSpan = rowSpan; - cell.columnSpan = columnSpan; - } - - /// Applies the style to all the rows in the grid. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Add headers to grid - /// grid.headers.add(2); - /// PdfGridRow header = grid.headers[0]; - /// header.cells[0].value = 'Employee ID'; - /// header.cells[1].value = 'Employee Name'; - /// header.cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Set the rows span - /// grid.rows.setSpan(0, 1, 2, 1); - /// //Set the row height - /// row2.height = 20; - /// //Set the row style - /// row1.style = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.dimGray, - /// textPen: PdfPens.lightGoldenrodYellow, - /// textBrush: PdfBrushes.darkOrange, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// //Create the PDF grid row style. Assign to whole rows - /// PdfGridRowStyle rowStyle = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, - /// textPen: PdfPens.indianRed, - /// textBrush: PdfBrushes.lightYellow, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// grid.rows.applyStyle(rowStyle); - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void applyStyle(PdfGridStyleBase style) { - if (style is PdfGridCellStyle) { - for (int i = 0; i < _grid.rows.count; i++) { - final PdfGridRow row = _grid.rows[i]; - for (int j = 0; j < row.cells.count; j++) { - row.cells[j].style = style; - } - } - } else if (style is PdfGridRowStyle) { - for (int i = 0; i < _grid.rows.count; i++) { - _grid.rows[i].style = style; - } - } else if (style is PdfGridStyle) { - _grid.style = style; - } - } - - //Implementation - PdfGridRow _returnValue(int index) { - if (index < 0 || index >= _rows.length) { - // ignore: deprecated_member_use - throw IndexError(index, _rows); - } - return _rows[index]; - } - - int _indexOf(PdfGridRow? row) { - return _rows.indexOf(row!); - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfGridRowCollection] helper -class PdfGridRowCollectionHelper { - /// internal method - static PdfGrid getGrid(PdfGridRowCollection collection) { - return collection._grid; - } - - /// internal method - static void setGrid(PdfGridRowCollection collection, PdfGrid value) { - collection._grid = value; - } - - /// internal method - static List getRows(PdfGridRowCollection collection) { - return collection._rows; - } - - /// internal method - static void setRows(PdfGridRowCollection collection, List value) { - collection._rows = value; - } - - /// internal method - static int indexOf(PdfGridRowCollection collection, PdfGridRow? row) { - return collection._indexOf(row); - } -} - -/// Provides customization of the settings for the header. -/// ```dart -/// //Create a new PDF document -/// PdfDocument document = PdfDocument(); -/// //Create a PdfGrid -/// PdfGrid grid = PdfGrid(); -/// //Add columns to grid -/// grid.columns.add(count: 3); -/// //Add headers to grid -/// grid.headers.add(2); -/// PdfGridHeaderCollection headers = grid.headers; -/// headers[0].cells[0].value = 'Employee ID'; -/// headers[0].cells[1].value = 'Employee Name'; -/// headers[0].cells[2].value = 'Salary'; -/// //Add rows to grid -/// PdfGridRow row1 = grid.rows.add(); -/// row1.cells[0].value = 'E01'; -/// row1.cells[1].value = 'Clay'; -/// row1.cells[2].value = '\$10,000'; -/// PdfGridRow row2 = grid.rows.add(); -/// row2.cells[0].value = 'E02'; -/// row2.cells[1].value = 'Simon'; -/// row2.cells[2].value = '\$12,000'; -/// //Set the rows span -/// grid.rows.setSpan(0, 1, 2, 1); -/// //Draw the grid in PDF document page -/// grid.draw( -/// page: document.pages.add(), bounds: Rect.zero); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfGridHeaderCollection { - /// Initializes a new instance of the [PdfGridHeaderCollection] class - /// with the parent grid. - PdfGridHeaderCollection(PdfGrid grid) { - _helper = PdfGridHeaderCollectionHelper(this); - _helper.grid = grid; - _rows = []; - } - - //Fields - late PdfGridHeaderCollectionHelper _helper; - late List _rows; - - //Properties - /// Gets the number of header in the [PdfGrid]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Gets the headers collection from the grid - /// PdfGridHeaderCollection headers = grid.headers; - /// //Add headers to grid - /// headers.add(1); - /// Gets a header row from the headers collection - /// headers[0].cells[0].value = 'Employee ID'; - /// headers[0].cells[1].value = 'Employee Name'; - /// headers[0].cells[2].value = 'Salary'; - /// Gets the headers count - /// int headerCount = headers.count; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get count => _rows.length; - - /// Gets a [PdfGridRow] object that represents the header row in a - /// [PdfGridHeaderCollection] control. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Gets the headers collection from the grid - /// PdfGridHeaderCollection headers = grid.headers; - /// //Add headers to grid - /// headers.add(1); - /// Gets a header row from the headers collection - /// headers[0].cells[0].value = 'Employee ID'; - /// headers[0].cells[1].value = 'Employee Name'; - /// headers[0].cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfGridRow operator [](int index) => _returnValue(index); - - //Public methods - /// [PdfGrid] enables you to quickly and easily add rows - /// to the header at run time. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Gets the headers collection from the grid - /// PdfGridHeaderCollection headers = grid.headers; - /// //Add headers to grid - /// headers.add(1); - /// headers[0].cells[0].value = 'Employee ID'; - /// headers[0].cells[1].value = 'Employee Name'; - /// headers[0].cells[2].value = 'Salary'; - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - List add(int count) { - return _addRows(count); - } - - /// Enables you to set the appearance of the header row in a [PdfGrid]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Gets the headers collection from the grid - /// PdfGridHeaderCollection headers = grid.headers; - /// //Add headers to grid - /// headers.add(1); - /// headers[0].cells[0].value = 'Employee ID'; - /// headers[0].cells[1].value = 'Employee Name'; - /// headers[0].cells[2].value = 'Salary'; - /// //Create the header row style. Assign to whole headers - /// PdfGridRowStyle headerStyle = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, - /// textPen: PdfPens.indianRed, - /// textBrush: PdfBrushes.lightYellow, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// headers.applyStyle(headerStyle); - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void applyStyle(PdfGridStyleBase style) { - if (style is PdfGridCellStyle) { - for (int i = 0; i < _rows.length; i++) { - final PdfGridRow row = _rows[i]; - for (int j = 0; j < row.cells.count; j++) { - row.cells[j].style = style; - } - } - } else if (style is PdfGridRowStyle) { - for (int i = 0; i < _rows.length; i++) { - _rows[i].style = style; - } - } - } - - /// Removes all the header information in the [PdfGrid]. - /// ```dart - /// //Create a new PDF document - /// PdfDocument document = PdfDocument(); - /// //Create a PdfGrid - /// PdfGrid grid = PdfGrid(); - /// //Add columns to grid - /// grid.columns.add(count: 3); - /// //Gets the headers collection from the grid - /// PdfGridHeaderCollection headers = grid.headers; - /// //Add headers to grid - /// headers.add(1); - /// headers[0].cells[0].value = 'Employee ID'; - /// headers[0].cells[1].value = 'Employee Name'; - /// headers[0].cells[2].value = 'Salary'; - /// //Create the header row style. Assign to whole headers - /// PdfGridRowStyle headerStyle = PdfGridRowStyle( - /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, - /// textPen: PdfPens.indianRed, - /// textBrush: PdfBrushes.lightYellow, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); - /// headers.applyStyle(headerStyle); - /// //Clear the headers - /// headers.clear(); - /// //Add rows to grid - /// PdfGridRow row1 = grid.rows.add(); - /// row1.cells[0].value = 'E01'; - /// row1.cells[1].value = 'Clay'; - /// row1.cells[2].value = '\$10,000'; - /// PdfGridRow row2 = grid.rows.add(); - /// row2.cells[0].value = 'E02'; - /// row2.cells[1].value = 'Simon'; - /// row2.cells[2].value = '\$12,000'; - /// //Draw the grid in PDF document page - /// grid.draw( - /// page: document.pages.add(), bounds: Rect.zero); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void clear() { - _rows.clear(); - } - - //Implementation - PdfGridRow _returnValue(int index) { - if (index < 0 || index >= count) { - // ignore: deprecated_member_use - throw IndexError(index, _rows); - } - return _rows[index]; - } - - void _add(PdfGridRow row) { - PdfGridRowHelper.getHelper(row).isHeaderRow = true; - _rows.add(row); - } - - List _addRows(int count) { - PdfGridRow row; - for (int i = 0; i < count; i++) { - row = PdfGridRow(_helper.grid); - for (int j = 0; j < _helper.grid.columns.count; j++) { - PdfGridCellCollectionHelper.getHelper(row.cells).add(PdfGridCell()); - } - _add(row); - } - return _rows.toList(); - } -} - -/// [PdfGridHeaderCollection] helper -class PdfGridHeaderCollectionHelper { - /// internal constructor - PdfGridHeaderCollectionHelper(this.base); - - /// internal field - PdfGridHeaderCollection base; - - /// internal method - static PdfGridHeaderCollectionHelper getHelper(PdfGridHeaderCollection base) { - return base._helper; - } - - /// internal method - late PdfGrid grid; - - /// internal method - int indexOf(PdfGridRow row) { - return base._rows.indexOf(row); - } -} +import 'dart:math'; + +import '../../graphics/figures/base/text_layouter.dart'; +import 'pdf_grid.dart'; +import 'pdf_grid_cell.dart'; +import 'styles/style.dart'; + +/// Provides customization of the settings for the particular row. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid +/// PdfGrid grid = PdfGrid(); +/// //Add columns to grid +/// grid.columns.add(count: 3); +/// //Add headers to grid +/// grid.headers.add(2); +/// PdfGridRow header = grid.headers[0]; +/// header.cells[0].value = 'Employee ID'; +/// header.cells[1].value = 'Employee Name'; +/// header.cells[2].value = 'Salary'; +/// //Add rows to grid +/// PdfGridRow row1 = grid.rows.add(); +/// row1.cells[0].value = 'E01'; +/// row1.cells[1].value = 'Clay'; +/// row1.cells[2].value = '\$10,000'; +/// PdfGridRow row2 = grid.rows.add(); +/// row2.cells[0].value = 'E02'; +/// row2.cells[1].value = 'Simon'; +/// row2.cells[2].value = '\$12,000'; +/// //Set the row span +/// row1.cells[1].rowSpan = 2; +/// //Set the row height +/// row2.height = 20; +/// //Set the row style +/// row1.style = PdfGridRowStyle( +/// backgroundBrush: PdfBrushes.dimGray, +/// textPen: PdfPens.lightGoldenrodYellow, +/// textBrush: PdfBrushes.darkOrange, +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); +/// //Draw the grid in PDF document page +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGridRow { + /// Initializes a new instance of the [PdfGridRow] class with the parent grid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// row1.style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridRow(PdfGrid grid, {PdfGridRowStyle? style, double? height}) { + _helper = PdfGridRowHelper(this); + _initialize(grid, style, height); + } + + //Fields + late PdfGridRowHelper _helper; + PdfGridRowStyle? _style; + late double _height; + late double _width; + + //Properties + /// Gets the cells from the selected row. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridCellCollection get cells { + _helper.cells ??= PdfGridCellCollectionHelper.load(this); + return _helper.cells!; + } + + /// Gets or sets the row style. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// row1.style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Create the PDF grid row style. Assign to second row + /// PdfGridRowStyle rowStyle = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, + /// textPen: PdfPens.indianRed, + /// textBrush: PdfBrushes.lightYellow, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// row2.style = rowStyle; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridRowStyle get style { + _style ??= PdfGridRowStyle(); + return _style!; + } + + set style(PdfGridRowStyle? value) { + _style = value; + } + + /// Gets or sets the height of the row. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// row1.style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double get height { + if (!_helper.isRowHeightSet) { + _height = _measureHeight(); + } + return _height; + } + + set height(double value) { + _helper.isRowHeightSet = true; + _height = value; + } + + //Implementation + void _initialize(PdfGrid grid, PdfGridRowStyle? style, double? height) { + if (style != null) { + _style = style; + } + _helper.grid = grid; + if (height != null) { + this.height = height; + } else { + _height = -1; + } + _width = -1; + _helper.rowSpanExists = false; + _helper.rowBreakHeight = 0; + _helper.rowOverflowIndex = 0; + _helper.isRowBreaksNextPage = false; + _helper.isrowFinish = false; + _helper.rowMergeComplete = true; + _helper.noOfPageCount = 0; + _helper.isRowHeightSet = false; + _helper.maximumRowSpan = 0; + _helper.isPageBreakRowSpanApplied = false; + _helper.isRowSpanRowHeightSet = false; + _helper.isHeaderRow = false; + } + + double _measureHeight() { + double rowSpanRemainingHeight = 0; + bool isHeader = false; + double rowHeight = cells[0].rowSpan > 1 ? 0 : cells[0].height; + double maxHeight = 0; + if (PdfGridHeaderCollectionHelper.getHelper( + _helper.grid.headers, + ).indexOf(this) != + -1) { + isHeader = true; + } + for (int i = 0; i < _helper.cells!.count; i++) { + final PdfGridCell cell = _helper.cells![i]; + if (PdfGridCellHelper.getHelper(cell).rowSpanRemainingHeight > + rowSpanRemainingHeight) { + rowSpanRemainingHeight = + PdfGridCellHelper.getHelper(cell).rowSpanRemainingHeight; + } + if (PdfGridCellHelper.getHelper(cell).isRowMergeContinue) { + continue; + } + if (!PdfGridCellHelper.getHelper(cell).isRowMergeContinue) { + _helper.rowMergeComplete = false; + } + if (cell.rowSpan > 1) { + if (maxHeight < cell.height) { + maxHeight = cell.height; + } + continue; + } + rowHeight = max(rowHeight, cell.height); + } + if (rowHeight == 0) { + rowHeight = maxHeight; + } else if (rowSpanRemainingHeight > 0) { + rowHeight = rowHeight + rowSpanRemainingHeight; + } + if (isHeader && maxHeight != 0 && rowHeight != 0 && rowHeight < maxHeight) { + rowHeight = maxHeight; + } + return rowHeight; + } +} + +/// [PdfGridRow] helper +class PdfGridRowHelper { + /// internal constructor + PdfGridRowHelper(this.base); + + /// internal field + PdfGridRow base; + + /// internal method + static PdfGridRowHelper getHelper(PdfGridRow base) { + return base._helper; + } + + /// internal method + double getWidth() { + if (base._width == -1) { + base._width = _measureWidth(); + } + return base._width; + } + + double _measureWidth() { + double width = 0; + for (int i = 0; i < grid.columns.count; i++) { + width += grid.columns[i].width; + } + return width; + } + + /// internal field + late PdfGrid grid; + + /// internal field + PdfGridCellCollection? cells; + + /// internal method + late bool rowSpanExists; + + /// internal method + late bool isHeaderRow; + + /// internal method + late bool isRowSpanRowHeightSet; + + /// internal method + late bool isPageBreakRowSpanApplied; + + /// internal method + late bool isRowHeightSet; + + /// internal method + late bool rowMergeComplete; + + /// internal method + late bool isrowFinish; + + /// internal method + late bool isRowBreaksNextPage; + + /// internal method + late int maximumRowSpan; + + /// internal method + late int noOfPageCount; + + /// internal method + PdfLayoutResult? gridResult; + + /// internal method + late int rowOverflowIndex; + + /// internal method + late double rowBreakHeight; + + /// internal method + int get index => grid.rows._indexOf(base); +} + +/// Provides access to an ordered, strongly typed collection of +/// [PdfGridRow] objects. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid +/// PdfGrid grid = PdfGrid(); +/// //Add columns to grid +/// grid.columns.add(count: 3); +/// //Add headers to grid +/// grid.headers.add(2); +/// PdfGridRow header = grid.headers[0]; +/// header.cells[0].value = 'Employee ID'; +/// header.cells[1].value = 'Employee Name'; +/// header.cells[2].value = 'Salary'; +/// //Add rows to grid +/// grid.rows.add(); +/// grid.rows.add(); +/// //Gets the row collection +/// PdfGridRowCollection rowCollection = grid.rows; +/// PdfGridRow row1 = rowCollection[0]; +/// row1.cells[0].value = 'E01'; +/// row1.cells[1].value = 'Clay'; +/// row1.cells[2].value = '\$10,000'; +/// PdfGridRow row2 = rowCollection[1]; +/// row2.cells[0].value = 'E02'; +/// row2.cells[1].value = 'Simon'; +/// row2.cells[2].value = '\$12,000'; +/// //Set the row span +/// row1.cells[1].rowSpan = 2; +/// //Set the row height +/// row2.height = 20; +/// //Set the row style +/// rowCollection[0].style = PdfGridRowStyle( +/// backgroundBrush: PdfBrushes.dimGray, +/// textPen: PdfPens.lightGoldenrodYellow, +/// textBrush: PdfBrushes.darkOrange, +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); +/// //Draw the grid in PDF document page +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGridRowCollection { + /// Initializes a new instance of the [PdfGridRowCollection] class + /// with the parent grid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// grid.rows.add(); + /// grid.rows.add(); + /// //Gets the row collection + /// PdfGridRowCollection rowCollection = grid.rows; + /// PdfGridRow row1 = rowCollection[0]; + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = rowCollection[1]; + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// rowCollection[0].style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridRowCollection(PdfGrid grid) { + _grid = grid; + _rows = []; + } + + //Fields + late PdfGrid _grid; + late List _rows; + + //Properties + /// Gets the rows count. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// grid.rows.add(); + /// grid.rows.add(); + /// //Gets the row count + /// int rowCount = grid.rows.count; + /// //Gets the row collection + /// PdfGridRowCollection rowCollection = grid.rows; + /// PdfGridRow row1 = rowCollection[0]; + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = rowCollection[1]; + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// rowCollection[0].style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get count => _rows.length; + + /// Gets the [PdfGridRow] at the specified index. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// grid.rows.add(); + /// grid.rows.add(); + /// //Gets the row collection + /// PdfGridRowCollection rowCollection = grid.rows; + /// PdfGridRow row1 = rowCollection[0]; + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = rowCollection[1]; + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// rowCollection[0].style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridRow operator [](int index) => _returnValue(index); + + //Public methods + /// Add a row to the grid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// grid.rows.add(); + /// grid.rows.add(); + /// //Gets the row collection + /// PdfGridRowCollection rowCollection = grid.rows; + /// PdfGridRow row1 = rowCollection[0]; + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = rowCollection[1]; + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the row span + /// row1.cells[1].rowSpan = 2; + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// rowCollection[0].style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridRow add([PdfGridRow? row]) { + if (row == null) { + final PdfGridRow row = PdfGridRow(_grid); + add(row); + return row; + } else { + row.style.font = _grid.style.font; + row.style.backgroundBrush = _grid.style.backgroundBrush; + row.style.textPen = _grid.style.textPen; + row.style.textBrush = _grid.style.textBrush; + if (row.cells.count == 0) { + for (int i = 0; i < _grid.columns.count; i++) { + PdfGridCellCollectionHelper.getHelper(row.cells).add(PdfGridCell()); + } + } + _rows.add(row); + return row; + } + } + + /// Sets the row span and column span to a cell. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the rows span + /// grid.rows.setSpan(0, 1, 2, 1); + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// row1.style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void setSpan(int rowIndex, int cellIndex, int rowSpan, int columnSpan) { + if (rowIndex > _grid.rows.count) { + ArgumentError.value(rowIndex, 'rowIndex', 'Index out of range'); + } + if (cellIndex > _grid.columns.count) { + ArgumentError.value(cellIndex, 'cellIndex', 'Index out of range'); + } + final PdfGridCell cell = _grid.rows[rowIndex].cells[cellIndex]; + cell.rowSpan = rowSpan; + cell.columnSpan = columnSpan; + } + + /// Applies the style to all the rows in the grid. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Add headers to grid + /// grid.headers.add(2); + /// PdfGridRow header = grid.headers[0]; + /// header.cells[0].value = 'Employee ID'; + /// header.cells[1].value = 'Employee Name'; + /// header.cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Set the rows span + /// grid.rows.setSpan(0, 1, 2, 1); + /// //Set the row height + /// row2.height = 20; + /// //Set the row style + /// row1.style = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.dimGray, + /// textPen: PdfPens.lightGoldenrodYellow, + /// textBrush: PdfBrushes.darkOrange, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// //Create the PDF grid row style. Assign to whole rows + /// PdfGridRowStyle rowStyle = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, + /// textPen: PdfPens.indianRed, + /// textBrush: PdfBrushes.lightYellow, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// grid.rows.applyStyle(rowStyle); + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void applyStyle(PdfGridStyleBase style) { + if (style is PdfGridCellStyle) { + for (int i = 0; i < _grid.rows.count; i++) { + final PdfGridRow row = _grid.rows[i]; + for (int j = 0; j < row.cells.count; j++) { + row.cells[j].style = style; + } + } + } else if (style is PdfGridRowStyle) { + for (int i = 0; i < _grid.rows.count; i++) { + _grid.rows[i].style = style; + } + } else if (style is PdfGridStyle) { + _grid.style = style; + } + } + + //Implementation + PdfGridRow _returnValue(int index) { + if (index < 0 || index >= _rows.length) { + // ignore: deprecated_member_use + throw IndexError(index, _rows); + } + return _rows[index]; + } + + int _indexOf(PdfGridRow? row) { + return _rows.indexOf(row!); + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfGridRowCollection] helper +class PdfGridRowCollectionHelper { + /// internal method + static PdfGrid getGrid(PdfGridRowCollection collection) { + return collection._grid; + } + + /// internal method + static void setGrid(PdfGridRowCollection collection, PdfGrid value) { + collection._grid = value; + } + + /// internal method + static List getRows(PdfGridRowCollection collection) { + return collection._rows; + } + + /// internal method + static void setRows(PdfGridRowCollection collection, List value) { + collection._rows = value; + } + + /// internal method + static int indexOf(PdfGridRowCollection collection, PdfGridRow? row) { + return collection._indexOf(row); + } +} + +/// Provides customization of the settings for the header. +/// ```dart +/// //Create a new PDF document +/// PdfDocument document = PdfDocument(); +/// //Create a PdfGrid +/// PdfGrid grid = PdfGrid(); +/// //Add columns to grid +/// grid.columns.add(count: 3); +/// //Add headers to grid +/// grid.headers.add(2); +/// PdfGridHeaderCollection headers = grid.headers; +/// headers[0].cells[0].value = 'Employee ID'; +/// headers[0].cells[1].value = 'Employee Name'; +/// headers[0].cells[2].value = 'Salary'; +/// //Add rows to grid +/// PdfGridRow row1 = grid.rows.add(); +/// row1.cells[0].value = 'E01'; +/// row1.cells[1].value = 'Clay'; +/// row1.cells[2].value = '\$10,000'; +/// PdfGridRow row2 = grid.rows.add(); +/// row2.cells[0].value = 'E02'; +/// row2.cells[1].value = 'Simon'; +/// row2.cells[2].value = '\$12,000'; +/// //Set the rows span +/// grid.rows.setSpan(0, 1, 2, 1); +/// //Draw the grid in PDF document page +/// grid.draw( +/// page: document.pages.add(), bounds: Rect.zero); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfGridHeaderCollection { + /// Initializes a new instance of the [PdfGridHeaderCollection] class + /// with the parent grid. + PdfGridHeaderCollection(PdfGrid grid) { + _helper = PdfGridHeaderCollectionHelper(this); + _helper.grid = grid; + _rows = []; + } + + //Fields + late PdfGridHeaderCollectionHelper _helper; + late List _rows; + + //Properties + /// Gets the number of header in the [PdfGrid]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Gets the headers collection from the grid + /// PdfGridHeaderCollection headers = grid.headers; + /// //Add headers to grid + /// headers.add(1); + /// Gets a header row from the headers collection + /// headers[0].cells[0].value = 'Employee ID'; + /// headers[0].cells[1].value = 'Employee Name'; + /// headers[0].cells[2].value = 'Salary'; + /// Gets the headers count + /// int headerCount = headers.count; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get count => _rows.length; + + /// Gets a [PdfGridRow] object that represents the header row in a + /// [PdfGridHeaderCollection] control. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Gets the headers collection from the grid + /// PdfGridHeaderCollection headers = grid.headers; + /// //Add headers to grid + /// headers.add(1); + /// Gets a header row from the headers collection + /// headers[0].cells[0].value = 'Employee ID'; + /// headers[0].cells[1].value = 'Employee Name'; + /// headers[0].cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfGridRow operator [](int index) => _returnValue(index); + + //Public methods + /// [PdfGrid] enables you to quickly and easily add rows + /// to the header at run time. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Gets the headers collection from the grid + /// PdfGridHeaderCollection headers = grid.headers; + /// //Add headers to grid + /// headers.add(1); + /// headers[0].cells[0].value = 'Employee ID'; + /// headers[0].cells[1].value = 'Employee Name'; + /// headers[0].cells[2].value = 'Salary'; + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + List add(int count) { + return _addRows(count); + } + + /// Enables you to set the appearance of the header row in a [PdfGrid]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Gets the headers collection from the grid + /// PdfGridHeaderCollection headers = grid.headers; + /// //Add headers to grid + /// headers.add(1); + /// headers[0].cells[0].value = 'Employee ID'; + /// headers[0].cells[1].value = 'Employee Name'; + /// headers[0].cells[2].value = 'Salary'; + /// //Create the header row style. Assign to whole headers + /// PdfGridRowStyle headerStyle = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, + /// textPen: PdfPens.indianRed, + /// textBrush: PdfBrushes.lightYellow, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// headers.applyStyle(headerStyle); + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void applyStyle(PdfGridStyleBase style) { + if (style is PdfGridCellStyle) { + for (int i = 0; i < _rows.length; i++) { + final PdfGridRow row = _rows[i]; + for (int j = 0; j < row.cells.count; j++) { + row.cells[j].style = style; + } + } + } else if (style is PdfGridRowStyle) { + for (int i = 0; i < _rows.length; i++) { + _rows[i].style = style; + } + } + } + + /// Removes all the header information in the [PdfGrid]. + /// ```dart + /// //Create a new PDF document + /// PdfDocument document = PdfDocument(); + /// //Create a PdfGrid + /// PdfGrid grid = PdfGrid(); + /// //Add columns to grid + /// grid.columns.add(count: 3); + /// //Gets the headers collection from the grid + /// PdfGridHeaderCollection headers = grid.headers; + /// //Add headers to grid + /// headers.add(1); + /// headers[0].cells[0].value = 'Employee ID'; + /// headers[0].cells[1].value = 'Employee Name'; + /// headers[0].cells[2].value = 'Salary'; + /// //Create the header row style. Assign to whole headers + /// PdfGridRowStyle headerStyle = PdfGridRowStyle( + /// backgroundBrush: PdfBrushes.lightGoldenrodYellow, + /// textPen: PdfPens.indianRed, + /// textBrush: PdfBrushes.lightYellow, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 12)); + /// headers.applyStyle(headerStyle); + /// //Clear the headers + /// headers.clear(); + /// //Add rows to grid + /// PdfGridRow row1 = grid.rows.add(); + /// row1.cells[0].value = 'E01'; + /// row1.cells[1].value = 'Clay'; + /// row1.cells[2].value = '\$10,000'; + /// PdfGridRow row2 = grid.rows.add(); + /// row2.cells[0].value = 'E02'; + /// row2.cells[1].value = 'Simon'; + /// row2.cells[2].value = '\$12,000'; + /// //Draw the grid in PDF document page + /// grid.draw( + /// page: document.pages.add(), bounds: Rect.zero); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void clear() { + _rows.clear(); + } + + //Implementation + PdfGridRow _returnValue(int index) { + if (index < 0 || index >= count) { + // ignore: deprecated_member_use + throw IndexError(index, _rows); + } + return _rows[index]; + } + + void _add(PdfGridRow row) { + PdfGridRowHelper.getHelper(row).isHeaderRow = true; + _rows.add(row); + } + + List _addRows(int count) { + PdfGridRow row; + for (int i = 0; i < count; i++) { + row = PdfGridRow(_helper.grid); + for (int j = 0; j < _helper.grid.columns.count; j++) { + PdfGridCellCollectionHelper.getHelper(row.cells).add(PdfGridCell()); + } + _add(row); + } + return _rows.toList(); + } +} + +/// [PdfGridHeaderCollection] helper +class PdfGridHeaderCollectionHelper { + /// internal constructor + PdfGridHeaderCollectionHelper(this.base); + + /// internal field + PdfGridHeaderCollection base; + + /// internal method + static PdfGridHeaderCollectionHelper getHelper(PdfGridHeaderCollection base) { + return base._helper; + } + + /// internal method + late PdfGrid grid; + + /// internal method + int indexOf(PdfGridRow row) { + return base._rows.indexOf(row); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/pdf_borders.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/pdf_borders.dart index 802ef6ed7..4fbf6d8c5 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/pdf_borders.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/pdf_borders.dart @@ -1,189 +1,189 @@ -import '../../../graphics/enums.dart'; -import '../../../graphics/pdf_color.dart'; -import '../../../graphics/pdf_pen.dart'; - -/// The class used represents the cell border of the PDF grid -class PdfBorders { - //Constructor - /// Initialize a new instance of the [PdfBorders] class. - PdfBorders({PdfPen? left, PdfPen? right, PdfPen? top, PdfPen? bottom}) { - if (left == null) { - final PdfPen defaultBorderPenLeft = PdfPen(PdfColor(0, 0, 0)); - defaultBorderPenLeft.dashStyle = PdfDashStyle.solid; - this.left = defaultBorderPenLeft; - } else { - this.left = left; - } - if (right == null) { - final PdfPen defaultBorderPenRight = PdfPen(PdfColor(0, 0, 0)); - defaultBorderPenRight.dashStyle = PdfDashStyle.solid; - this.right = defaultBorderPenRight; - } else { - this.right = right; - } - if (top == null) { - final PdfPen defaultBorderPenTop = PdfPen(PdfColor(0, 0, 0)); - defaultBorderPenTop.dashStyle = PdfDashStyle.solid; - this.top = defaultBorderPenTop; - } else { - this.top = top; - } - if (bottom == null) { - final PdfPen defaultBorderPenBottom = PdfPen(PdfColor(0, 0, 0)); - defaultBorderPenBottom.dashStyle = PdfDashStyle.solid; - this.bottom = defaultBorderPenBottom; - } else { - this.bottom = bottom; - } - } - - /// Gets the default border. - static PdfBorders get defaultBorder { - _defaultBorder ??= PdfBorders(); - return _defaultBorder!; - } - - //Fields - static PdfBorders? _defaultBorder; - - /// Gets or sets the pen for the left line of border. - late PdfPen left; - - /// Gets or sets the pen for the right line of border. - late PdfPen right; - - /// Gets or sets the pen for the bottom line of border. - late PdfPen bottom; - - /// Gets or sets the pen for the top line of border. - late PdfPen top; - - //Properties - /// Sets all. - // ignore: avoid_setters_without_getters - set all(PdfPen pen) { - left = right = bottom = top = pen; - } - - bool get _isAll => left == right && right == bottom && bottom == top; -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfBorders] helper -class PdfBordersHelper { - /// internal method - static bool isAll(PdfBorders borders) { - return borders._isAll; - } -} - -/// The class used represents the cell padding of the PDF grid -class PdfPaddings { - //Constructors - /// Initializes a new instance of the [PdfPaddings] class. - PdfPaddings({double? left, double? right, double? top, double? bottom}) { - _initialize(left, right, top, bottom); - } - - //Fields - late double _left; - late double _right; - late double _bottom; - late double _top; - - //Properties - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - bool operator ==(Object other) { - return other is PdfPaddings && - left == other.left && - right == other.right && - top == other.top && - bottom == other.bottom; - } - - @override - // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => _left.hashCode; - - /// Sets space value to all sides of a cell Left,Right,Top,Bottom. - // ignore: avoid_setters_without_getters - set all(double value) { - if (value < 0) { - ArgumentError.value( - value, - 'all', - 'value should greater than or equal to zero', - ); - } - _left = _right = _bottom = _top = value; - } - - /// Gets the left space of padding. - double get left => _left; - - /// Sets the left space of padding. - set left(double value) { - if (value < 0) { - ArgumentError.value( - value, - 'left', - 'value should greater than or equal to zero', - ); - } - _left = value; - } - - /// Gets the right space of padding. - double get right => _right; - - /// Sets the right space of padding. - set right(double value) { - if (value < 0) { - ArgumentError.value( - value, - 'right', - 'value should greater than or equal to zero', - ); - } - _right = value; - } - - /// Gets the top space of padding. - double get top => _top; - - /// Sets the top space of padding. - set top(double value) { - if (value < 0) { - ArgumentError.value( - value, - 'top', - 'value should greater than or equal to zero', - ); - } - _top = value; - } - - /// Gets the bottom space of padding. - double get bottom => _bottom; - - /// Sets the bottom space of padding. - set bottom(double value) { - if (value < 0) { - ArgumentError.value( - value, - 'bottom', - 'value should greater than or equal to zero', - ); - } - _bottom = value; - } - - //Implementation - void _initialize(double? left, double? right, double? top, double? bottom) { - this.left = left ?? 0.5; - this.right = right ?? 0.5; - this.top = top ?? 0.5; - this.bottom = bottom ?? 0.5; - } -} +import '../../../graphics/enums.dart'; +import '../../../graphics/pdf_color.dart'; +import '../../../graphics/pdf_pen.dart'; + +/// The class used represents the cell border of the PDF grid +class PdfBorders { + //Constructor + /// Initialize a new instance of the [PdfBorders] class. + PdfBorders({PdfPen? left, PdfPen? right, PdfPen? top, PdfPen? bottom}) { + if (left == null) { + final PdfPen defaultBorderPenLeft = PdfPen(PdfColor(0, 0, 0)); + defaultBorderPenLeft.dashStyle = PdfDashStyle.solid; + this.left = defaultBorderPenLeft; + } else { + this.left = left; + } + if (right == null) { + final PdfPen defaultBorderPenRight = PdfPen(PdfColor(0, 0, 0)); + defaultBorderPenRight.dashStyle = PdfDashStyle.solid; + this.right = defaultBorderPenRight; + } else { + this.right = right; + } + if (top == null) { + final PdfPen defaultBorderPenTop = PdfPen(PdfColor(0, 0, 0)); + defaultBorderPenTop.dashStyle = PdfDashStyle.solid; + this.top = defaultBorderPenTop; + } else { + this.top = top; + } + if (bottom == null) { + final PdfPen defaultBorderPenBottom = PdfPen(PdfColor(0, 0, 0)); + defaultBorderPenBottom.dashStyle = PdfDashStyle.solid; + this.bottom = defaultBorderPenBottom; + } else { + this.bottom = bottom; + } + } + + /// Gets the default border. + static PdfBorders get defaultBorder { + _defaultBorder ??= PdfBorders(); + return _defaultBorder!; + } + + //Fields + static PdfBorders? _defaultBorder; + + /// Gets or sets the pen for the left line of border. + late PdfPen left; + + /// Gets or sets the pen for the right line of border. + late PdfPen right; + + /// Gets or sets the pen for the bottom line of border. + late PdfPen bottom; + + /// Gets or sets the pen for the top line of border. + late PdfPen top; + + //Properties + /// Sets all. + // ignore: avoid_setters_without_getters + set all(PdfPen pen) { + left = right = bottom = top = pen; + } + + bool get _isAll => left == right && right == bottom && bottom == top; +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfBorders] helper +class PdfBordersHelper { + /// internal method + static bool isAll(PdfBorders borders) { + return borders._isAll; + } +} + +/// The class used represents the cell padding of the PDF grid +class PdfPaddings { + //Constructors + /// Initializes a new instance of the [PdfPaddings] class. + PdfPaddings({double? left, double? right, double? top, double? bottom}) { + _initialize(left, right, top, bottom); + } + + //Fields + late double _left; + late double _right; + late double _bottom; + late double _top; + + //Properties + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + bool operator ==(Object other) { + return other is PdfPaddings && + left == other.left && + right == other.right && + top == other.top && + bottom == other.bottom; + } + + @override + // ignore: avoid_equals_and_hash_code_on_mutable_classes + int get hashCode => _left.hashCode; + + /// Sets space value to all sides of a cell Left,Right,Top,Bottom. + // ignore: avoid_setters_without_getters + set all(double value) { + if (value < 0) { + ArgumentError.value( + value, + 'all', + 'value should greater than or equal to zero', + ); + } + _left = _right = _bottom = _top = value; + } + + /// Gets the left space of padding. + double get left => _left; + + /// Sets the left space of padding. + set left(double value) { + if (value < 0) { + ArgumentError.value( + value, + 'left', + 'value should greater than or equal to zero', + ); + } + _left = value; + } + + /// Gets the right space of padding. + double get right => _right; + + /// Sets the right space of padding. + set right(double value) { + if (value < 0) { + ArgumentError.value( + value, + 'right', + 'value should greater than or equal to zero', + ); + } + _right = value; + } + + /// Gets the top space of padding. + double get top => _top; + + /// Sets the top space of padding. + set top(double value) { + if (value < 0) { + ArgumentError.value( + value, + 'top', + 'value should greater than or equal to zero', + ); + } + _top = value; + } + + /// Gets the bottom space of padding. + double get bottom => _bottom; + + /// Sets the bottom space of padding. + set bottom(double value) { + if (value < 0) { + ArgumentError.value( + value, + 'bottom', + 'value should greater than or equal to zero', + ); + } + _bottom = value; + } + + //Implementation + void _initialize(double? left, double? right, double? top, double? bottom) { + this.left = left ?? 0.5; + this.right = right ?? 0.5; + this.top = top ?? 0.5; + this.bottom = bottom ?? 0.5; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/style.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/style.dart index 557d3d295..2fe8fdaee 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/style.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/grid/styles/style.dart @@ -1,208 +1,208 @@ -import '../../../graphics/brushes/pdf_solid_brush.dart'; -import '../../../graphics/fonts/pdf_font.dart'; -import '../../../graphics/fonts/pdf_string_format.dart'; -import '../../../graphics/images/pdf_image.dart'; -import '../../../graphics/pdf_pen.dart'; -import '../enums.dart'; -import '../styles/pdf_borders.dart'; - -/// Base class for the grid style -abstract class PdfGridStyleBase { - /// Gets or sets the background brush. - PdfBrush? backgroundBrush; - - /// Gets or sets the text brush. - PdfBrush? textBrush; - - /// Gets or sets the text pen. - PdfPen? textPen; - - /// Gets or sets the font. - PdfFont? font; - PdfPaddings? _gridCellPadding; -} - -/// Provides customization of the appearance for the [PdfGridRow]. -class PdfGridRowStyle extends PdfGridStyleBase { - /// Initializes a new instance of the [PdfGridRowStyle] class. - PdfGridRowStyle({ - PdfBrush? backgroundBrush, - PdfBrush? textBrush, - PdfPen? textPen, - PdfFont? font, - }) { - _initializeRowStyle(backgroundBrush, textBrush, textPen, font); - } - - //Implementation - void _initializeRowStyle( - PdfBrush? backgroundBrush, - PdfBrush? textBrush, - PdfPen? textPen, - PdfFont? font, - ) { - super.backgroundBrush = backgroundBrush; - super.textBrush = textBrush; - super.textPen = textPen; - super.font = font; - } -} - -/// Provides customization of the appearance for the [PdfGridCell]. -class PdfGridCellStyle extends PdfGridRowStyle { - /// Initializes a new instance of the [PdfGridCellStyle] class. - PdfGridCellStyle({ - PdfBorders? borders, - PdfStringFormat? format, - PdfImage? backgroundImage, - PdfPaddings? cellPadding, - super.backgroundBrush, - super.textBrush, - super.textPen, - super.font, - }) { - _initializeCellStyle(borders, format, backgroundImage, cellPadding); - } - - //Fields - /// Gets or sets the border of the [PdfGridCell]. - late PdfBorders borders; - - /// Gets the string format of the [PdfGridCell]. - PdfStringFormat? stringFormat; - PdfPaddings? _cellPadding; - - /// Gets or sets the background image in the [PdfGridCell]. - PdfImage? backgroundImage; - - //Properties - /// Gets the cell padding. - PdfPaddings? get cellPadding { - _cellPadding ??= _gridCellPadding; - return _cellPadding; - } - - /// Sets the cell padding. - set cellPadding(PdfPaddings? value) { - _cellPadding = value; - } - - //Implementation - void _initializeCellStyle( - PdfBorders? borders, - PdfStringFormat? format, - PdfImage? backgroundImage, - PdfPaddings? cellPadding, - ) { - this.borders = borders ?? PdfBorders(); - stringFormat = format; - this.backgroundImage = backgroundImage; - if (cellPadding != null) { - this.cellPadding = cellPadding; - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfGridCellStyle] helper -class PdfGridCellStyleHelper { - /// internal method - static PdfPaddings? getPadding(PdfGridCellStyle style) { - return style._cellPadding; - } - - /// internal method - static void setPadding(PdfGridCellStyle style, PdfPaddings? padding) { - style._cellPadding = padding; - } -} - -/// Provides customization of the appearance for the [PdfGrid]. -class PdfGridStyle extends PdfGridStyleBase { - //Constructor - /// Initializes a new instance of the [PdfGridStyle] class. - PdfGridStyle({ - double? cellSpacing, - PdfPaddings? cellPadding, - PdfBorderOverlapStyle? borderOverlapStyle, - PdfBrush? backgroundBrush, - PdfBrush? textBrush, - PdfPen? textPen, - PdfFont? font, - }) { - _initializeStyle( - cellSpacing, - cellPadding, - borderOverlapStyle, - backgroundBrush, - textBrush, - textPen, - font, - ); - } - //Fields - /// Gets or sets the cell spacing of the [PdfGrid]. - late double cellSpacing; - PdfPaddings? _cellPadding; - - /// Gets or sets the border overlap style of the [PdfGrid]. - late PdfBorderOverlapStyle borderOverlapStyle; - - /// Gets or sets a value indicating whether to allow horizontal overflow. - late bool allowHorizontalOverflow; - - /// Gets or sets the type of the horizontal overflow of the [PdfGrid]. - late PdfHorizontalOverflowType horizontalOverflowType; - - //Properties - /// Gets the cell padding. - PdfPaddings get cellPadding { - _cellPadding ??= PdfPaddings(); - _gridCellPadding = _cellPadding; - return _cellPadding!; - } - - /// Sets the cell padding. - set cellPadding(PdfPaddings value) { - _cellPadding = value; - _gridCellPadding = _cellPadding; - } - - //Implementation - void _initializeStyle( - double? cellSpacing, - PdfPaddings? cellPadding, - PdfBorderOverlapStyle? borderOverlapStyle, - PdfBrush? backgroundBrush, - PdfBrush? textBrush, - PdfPen? textPen, - PdfFont? font, - ) { - super.backgroundBrush = backgroundBrush; - super.textBrush = textBrush; - super.textPen = textPen; - super.font = font; - this.borderOverlapStyle = - borderOverlapStyle ?? PdfBorderOverlapStyle.overlap; - allowHorizontalOverflow = false; - horizontalOverflowType = PdfHorizontalOverflowType.lastPage; - this.cellSpacing = cellSpacing ?? 0; - if (cellPadding != null) { - this.cellPadding = cellPadding; - } - } -} - -// ignore: avoid_classes_with_only_static_members -/// [PdfGridStyle] helper -class PdfGridStyleHelper { - /// internal method - static PdfPaddings? getPadding(PdfGridStyle style) { - return style._cellPadding; - } - - /// internal method - static void setPadding(PdfGridStyle style, PdfPaddings? padding) { - style._cellPadding = padding; - } -} +import '../../../graphics/brushes/pdf_solid_brush.dart'; +import '../../../graphics/fonts/pdf_font.dart'; +import '../../../graphics/fonts/pdf_string_format.dart'; +import '../../../graphics/images/pdf_image.dart'; +import '../../../graphics/pdf_pen.dart'; +import '../enums.dart'; +import '../styles/pdf_borders.dart'; + +/// Base class for the grid style +abstract class PdfGridStyleBase { + /// Gets or sets the background brush. + PdfBrush? backgroundBrush; + + /// Gets or sets the text brush. + PdfBrush? textBrush; + + /// Gets or sets the text pen. + PdfPen? textPen; + + /// Gets or sets the font. + PdfFont? font; + PdfPaddings? _gridCellPadding; +} + +/// Provides customization of the appearance for the [PdfGridRow]. +class PdfGridRowStyle extends PdfGridStyleBase { + /// Initializes a new instance of the [PdfGridRowStyle] class. + PdfGridRowStyle({ + PdfBrush? backgroundBrush, + PdfBrush? textBrush, + PdfPen? textPen, + PdfFont? font, + }) { + _initializeRowStyle(backgroundBrush, textBrush, textPen, font); + } + + //Implementation + void _initializeRowStyle( + PdfBrush? backgroundBrush, + PdfBrush? textBrush, + PdfPen? textPen, + PdfFont? font, + ) { + super.backgroundBrush = backgroundBrush; + super.textBrush = textBrush; + super.textPen = textPen; + super.font = font; + } +} + +/// Provides customization of the appearance for the [PdfGridCell]. +class PdfGridCellStyle extends PdfGridRowStyle { + /// Initializes a new instance of the [PdfGridCellStyle] class. + PdfGridCellStyle({ + PdfBorders? borders, + PdfStringFormat? format, + PdfImage? backgroundImage, + PdfPaddings? cellPadding, + super.backgroundBrush, + super.textBrush, + super.textPen, + super.font, + }) { + _initializeCellStyle(borders, format, backgroundImage, cellPadding); + } + + //Fields + /// Gets or sets the border of the [PdfGridCell]. + late PdfBorders borders; + + /// Gets the string format of the [PdfGridCell]. + PdfStringFormat? stringFormat; + PdfPaddings? _cellPadding; + + /// Gets or sets the background image in the [PdfGridCell]. + PdfImage? backgroundImage; + + //Properties + /// Gets the cell padding. + PdfPaddings? get cellPadding { + _cellPadding ??= _gridCellPadding; + return _cellPadding; + } + + /// Sets the cell padding. + set cellPadding(PdfPaddings? value) { + _cellPadding = value; + } + + //Implementation + void _initializeCellStyle( + PdfBorders? borders, + PdfStringFormat? format, + PdfImage? backgroundImage, + PdfPaddings? cellPadding, + ) { + this.borders = borders ?? PdfBorders(); + stringFormat = format; + this.backgroundImage = backgroundImage; + if (cellPadding != null) { + this.cellPadding = cellPadding; + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfGridCellStyle] helper +class PdfGridCellStyleHelper { + /// internal method + static PdfPaddings? getPadding(PdfGridCellStyle style) { + return style._cellPadding; + } + + /// internal method + static void setPadding(PdfGridCellStyle style, PdfPaddings? padding) { + style._cellPadding = padding; + } +} + +/// Provides customization of the appearance for the [PdfGrid]. +class PdfGridStyle extends PdfGridStyleBase { + //Constructor + /// Initializes a new instance of the [PdfGridStyle] class. + PdfGridStyle({ + double? cellSpacing, + PdfPaddings? cellPadding, + PdfBorderOverlapStyle? borderOverlapStyle, + PdfBrush? backgroundBrush, + PdfBrush? textBrush, + PdfPen? textPen, + PdfFont? font, + }) { + _initializeStyle( + cellSpacing, + cellPadding, + borderOverlapStyle, + backgroundBrush, + textBrush, + textPen, + font, + ); + } + //Fields + /// Gets or sets the cell spacing of the [PdfGrid]. + late double cellSpacing; + PdfPaddings? _cellPadding; + + /// Gets or sets the border overlap style of the [PdfGrid]. + late PdfBorderOverlapStyle borderOverlapStyle; + + /// Gets or sets a value indicating whether to allow horizontal overflow. + late bool allowHorizontalOverflow; + + /// Gets or sets the type of the horizontal overflow of the [PdfGrid]. + late PdfHorizontalOverflowType horizontalOverflowType; + + //Properties + /// Gets the cell padding. + PdfPaddings get cellPadding { + _cellPadding ??= PdfPaddings(); + _gridCellPadding = _cellPadding; + return _cellPadding!; + } + + /// Sets the cell padding. + set cellPadding(PdfPaddings value) { + _cellPadding = value; + _gridCellPadding = _cellPadding; + } + + //Implementation + void _initializeStyle( + double? cellSpacing, + PdfPaddings? cellPadding, + PdfBorderOverlapStyle? borderOverlapStyle, + PdfBrush? backgroundBrush, + PdfBrush? textBrush, + PdfPen? textPen, + PdfFont? font, + ) { + super.backgroundBrush = backgroundBrush; + super.textBrush = textBrush; + super.textPen = textPen; + super.font = font; + this.borderOverlapStyle = + borderOverlapStyle ?? PdfBorderOverlapStyle.overlap; + allowHorizontalOverflow = false; + horizontalOverflowType = PdfHorizontalOverflowType.lastPage; + this.cellSpacing = cellSpacing ?? 0; + if (cellPadding != null) { + this.cellPadding = cellPadding; + } + } +} + +// ignore: avoid_classes_with_only_static_members +/// [PdfGridStyle] helper +class PdfGridStyleHelper { + /// internal method + static PdfPaddings? getPadding(PdfGridStyle style) { + return style._cellPadding; + } + + /// internal method + static void setPadding(PdfGridStyle style, PdfPaddings? padding) { + style._cellPadding = padding; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/enums.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/enums.dart index 2ce2dbaee..86a1a2f1e 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/enums.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/enums.dart @@ -1,70 +1,70 @@ -/// Represents marker alignment. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new ordered list. -/// PdfOrderedList( -/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) -/// ..alignment = PdfListMarkerAlignment.right) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -enum PdfListMarkerAlignment { - /// Left alignment for marker. - left, - - /// Right alignment for marker. - right, -} - -/// Specifies the marker style. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new unordered list. -/// PdfUnorderedList( -/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -enum PdfUnorderedMarkerStyle { - /// Marker have no style. - none, - - /// Marker is like a disk. - disk, - - /// Marker is like a square. - square, - - /// Marker is like a Asterisk. - asterisk, - - /// Marker is like a circle. - circle, - - /// Marker is custom string. - customString, - - /// Marker is custom image. - customImage, - - /// Marker is custom template. - customTemplate, -} +/// Represents marker alignment. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new ordered list. +/// PdfOrderedList( +/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) +/// ..alignment = PdfListMarkerAlignment.right) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +enum PdfListMarkerAlignment { + /// Left alignment for marker. + left, + + /// Right alignment for marker. + right, +} + +/// Specifies the marker style. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new unordered list. +/// PdfUnorderedList( +/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +enum PdfUnorderedMarkerStyle { + /// Marker have no style. + none, + + /// Marker is like a disk. + disk, + + /// Marker is like a square. + square, + + /// Marker is like a Asterisk. + asterisk, + + /// Marker is like a circle. + circle, + + /// Marker is custom string. + customString, + + /// Marker is custom image. + customImage, + + /// Marker is custom template. + customTemplate, +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_marker.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_marker.dart index b1a5aaa69..2ee9d7139 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_marker.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_marker.dart @@ -1,157 +1,157 @@ -import '../../../graphics/brushes/pdf_solid_brush.dart'; -import '../../../graphics/fonts/pdf_font.dart'; -import '../../../graphics/fonts/pdf_string_format.dart'; -import '../../../graphics/pdf_pen.dart'; -import 'enums.dart'; - -/// Represents base class for markers. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new ordered list. -/// PdfOrderedList( -/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic)) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -abstract class PdfMarker { - //Fields - /// Marker font. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfFont? font; - - /// Marker brush. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) - /// ..brush = PdfBrushes.red) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBrush? brush; - - /// Marker pen. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) - /// //Set the marker pen. - /// ..pen = PdfPens.red) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPen? pen; - - /// The string format of the marker. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) - /// //Set the marker format. - /// ..stringFormat = PdfStringFormat(alignment: PdfTextAlignment.left)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfStringFormat? stringFormat; - - /// Marker alignment. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) - /// //Set the marker alignment. - /// ..alignment = PdfListMarkerAlignment.right) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfListMarkerAlignment alignment = PdfListMarkerAlignment.left; - - //Properties - /// Indicates is alignment right. - bool get _rightToLeft => alignment == PdfListMarkerAlignment.right; - - late PdfMarkerHelper _helper; -} - -/// [PdfMarker] helper -class PdfMarkerHelper { - /// internal constructor - PdfMarkerHelper(this.marker) { - marker._helper = this; - } - - /// internal field - late PdfMarker marker; - - /// internal method - static PdfMarkerHelper getHelper(PdfMarker marker) { - return marker._helper; - } - - /// internal property - bool get rightToLeft => marker._rightToLeft; -} +import '../../../graphics/brushes/pdf_solid_brush.dart'; +import '../../../graphics/fonts/pdf_font.dart'; +import '../../../graphics/fonts/pdf_string_format.dart'; +import '../../../graphics/pdf_pen.dart'; +import 'enums.dart'; + +/// Represents base class for markers. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new ordered list. +/// PdfOrderedList( +/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic)) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +abstract class PdfMarker { + //Fields + /// Marker font. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfFont? font; + + /// Marker brush. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) + /// ..brush = PdfBrushes.red) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBrush? brush; + + /// Marker pen. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) + /// //Set the marker pen. + /// ..pen = PdfPens.red) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPen? pen; + + /// The string format of the marker. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) + /// //Set the marker format. + /// ..stringFormat = PdfStringFormat(alignment: PdfTextAlignment.left)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfStringFormat? stringFormat; + + /// Marker alignment. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) + /// //Set the marker alignment. + /// ..alignment = PdfListMarkerAlignment.right) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfListMarkerAlignment alignment = PdfListMarkerAlignment.left; + + //Properties + /// Indicates is alignment right. + bool get _rightToLeft => alignment == PdfListMarkerAlignment.right; + + late PdfMarkerHelper _helper; +} + +/// [PdfMarker] helper +class PdfMarkerHelper { + /// internal constructor + PdfMarkerHelper(this.marker) { + marker._helper = this; + } + + /// internal field + late PdfMarker marker; + + /// internal method + static PdfMarkerHelper getHelper(PdfMarker marker) { + return marker._helper; + } + + /// internal property + bool get rightToLeft => marker._rightToLeft; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_ordered_marker.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_ordered_marker.dart index 5d1285711..d73c223b5 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_ordered_marker.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_ordered_marker.dart @@ -1,203 +1,203 @@ -import '../../../graphics/fonts/pdf_font.dart'; -import '../../../pages/enum.dart'; -import '../../../pdf_document/automatic_fields/pdf_automatic_field.dart'; -import 'pdf_marker.dart'; - -/// Represents marker for ordered list. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new ordered list. -/// PdfOrderedList( -/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// marker: //Create a new ordered marker. -/// PdfOrderedMarker(style: PdfNumberStyle.numeric)) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfOrderedMarker extends PdfMarker { - //Constructor - /// Initializes a new instance of the [PdfOrderedMarker] class. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: //Create a new ordered marker. - /// PdfOrderedMarker(style: PdfNumberStyle.numeric)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfOrderedMarker({ - this.style = PdfNumberStyle.none, - PdfFont? font, - String suffix = '', - String delimiter = '', - }) { - _helper = PdfOrderedMarkerHelper(this); - _delimiter = delimiter; - _suffix = suffix; - this.font = font; - } - - //Fields - /// Holds numbering style. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: //Create a new ordered marker. - /// PdfOrderedMarker(style: PdfNumberStyle.numeric)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfNumberStyle style = PdfNumberStyle.none; - - /// Delimiter for numbers. - String? _delimiter; - - /// Finalizer for numbers. - String? _suffix; - late PdfOrderedMarkerHelper _helper; - - //Properties - /// Gets or sets start number for ordered list. Default value is 1. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) - /// //Set the start number. - /// ..startNumber = 2) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int get startNumber => _helper._startNumber; - set startNumber(int value) { - if (value <= 0) { - throw ArgumentError('Start number should be greater than 0'); - } - _helper._startNumber = value; - } - - /// Gets or sets the delimiter. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..items[0].subList = PdfOrderedList( - /// items: PdfListItemCollection(['PDF', 'DocIO']), - /// marker: PdfOrderedMarker( - /// style: PdfNumberStyle.numeric, delimiter: ',', suffix: ')')) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String get delimiter { - if (_delimiter == '' || _delimiter == null) { - return '.'; - } - return _delimiter!; - } - - set delimiter(String value) => _delimiter = value; - - /// Gets or sets the suffix of the marker. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..items[0].subList = PdfOrderedList( - /// items: PdfListItemCollection(['PDF', 'DocIO']), - /// marker: PdfOrderedMarker( - /// style: PdfNumberStyle.numeric, delimiter: ',', suffix: ')')) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String get suffix { - if (_suffix == null || _suffix == '') { - return '.'; - } - return _suffix!; - } - - set suffix(String value) => _suffix = value; -} - -/// [PdfOrderedMarker] helper -class PdfOrderedMarkerHelper extends PdfMarkerHelper { - /// internal constructor - PdfOrderedMarkerHelper(this.base) : super(base); - - /// internal field - PdfOrderedMarker base; - - /// internal method - static PdfOrderedMarkerHelper getHelper(PdfOrderedMarker base) { - return base._helper; - } - - /// Current index of item. - late int currentIndex; - - /// Start number for ordered list. - int _startNumber = 1; - - /// Gets the marker number. - String getNumber() { - return PdfAutomaticFieldHelper.convert( - _startNumber + currentIndex, - base.style, - ); - } -} +import '../../../graphics/fonts/pdf_font.dart'; +import '../../../pages/enum.dart'; +import '../../../pdf_document/automatic_fields/pdf_automatic_field.dart'; +import 'pdf_marker.dart'; + +/// Represents marker for ordered list. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new ordered list. +/// PdfOrderedList( +/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// marker: //Create a new ordered marker. +/// PdfOrderedMarker(style: PdfNumberStyle.numeric)) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfOrderedMarker extends PdfMarker { + //Constructor + /// Initializes a new instance of the [PdfOrderedMarker] class. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: //Create a new ordered marker. + /// PdfOrderedMarker(style: PdfNumberStyle.numeric)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfOrderedMarker({ + this.style = PdfNumberStyle.none, + PdfFont? font, + String suffix = '', + String delimiter = '', + }) { + _helper = PdfOrderedMarkerHelper(this); + _delimiter = delimiter; + _suffix = suffix; + this.font = font; + } + + //Fields + /// Holds numbering style. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: //Create a new ordered marker. + /// PdfOrderedMarker(style: PdfNumberStyle.numeric)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfNumberStyle style = PdfNumberStyle.none; + + /// Delimiter for numbers. + String? _delimiter; + + /// Finalizer for numbers. + String? _suffix; + late PdfOrderedMarkerHelper _helper; + + //Properties + /// Gets or sets start number for ordered list. Default value is 1. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric) + /// //Set the start number. + /// ..startNumber = 2) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int get startNumber => _helper._startNumber; + set startNumber(int value) { + if (value <= 0) { + throw ArgumentError('Start number should be greater than 0'); + } + _helper._startNumber = value; + } + + /// Gets or sets the delimiter. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..items[0].subList = PdfOrderedList( + /// items: PdfListItemCollection(['PDF', 'DocIO']), + /// marker: PdfOrderedMarker( + /// style: PdfNumberStyle.numeric, delimiter: ',', suffix: ')')) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String get delimiter { + if (_delimiter == '' || _delimiter == null) { + return '.'; + } + return _delimiter!; + } + + set delimiter(String value) => _delimiter = value; + + /// Gets or sets the suffix of the marker. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..items[0].subList = PdfOrderedList( + /// items: PdfListItemCollection(['PDF', 'DocIO']), + /// marker: PdfOrderedMarker( + /// style: PdfNumberStyle.numeric, delimiter: ',', suffix: ')')) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String get suffix { + if (_suffix == null || _suffix == '') { + return '.'; + } + return _suffix!; + } + + set suffix(String value) => _suffix = value; +} + +/// [PdfOrderedMarker] helper +class PdfOrderedMarkerHelper extends PdfMarkerHelper { + /// internal constructor + PdfOrderedMarkerHelper(this.base) : super(base); + + /// internal field + PdfOrderedMarker base; + + /// internal method + static PdfOrderedMarkerHelper getHelper(PdfOrderedMarker base) { + return base._helper; + } + + /// Current index of item. + late int currentIndex; + + /// Start number for ordered list. + int _startNumber = 1; + + /// Gets the marker number. + String getNumber() { + return PdfAutomaticFieldHelper.convert( + _startNumber + currentIndex, + base.style, + ); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_unordered_marker.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_unordered_marker.dart index 0d257a0d2..6b9860161 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_unordered_marker.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/bullets/pdf_unordered_marker.dart @@ -1,252 +1,252 @@ -import 'dart:ui'; - -import '../../../drawing/drawing.dart'; -import '../../../graphics/brushes/pdf_solid_brush.dart'; -import '../../../graphics/figures/pdf_template.dart'; -import '../../../graphics/fonts/pdf_font.dart'; -import '../../../graphics/pdf_graphics.dart'; -import '../../../graphics/pdf_pen.dart'; -import '../bullets/enums.dart'; -import '../pdf_list.dart'; -import 'pdf_marker.dart'; - -/// Represents bullet for the list. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new unordered list. -/// PdfUnorderedList uList = PdfUnorderedList( -/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// marker: //Create an unordered marker. -/// PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfUnorderedMarker extends PdfMarker { - //Constructor - /// Initializes a new instance of the [PdfUnorderedMarker] class - /// with Pdf unordered marker style. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new unordered list. - /// PdfUnorderedList uList = PdfUnorderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: //Create an unordered marker. - /// PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfUnorderedMarker({ - this.style = PdfUnorderedMarkerStyle.none, - PdfFont? font, - String? text, - PdfTemplate? template, - }) { - _helper = PdfUnorderedMarkerHelper(this); - if (font != null) { - this.font = font; - } - if (text != null) { - this.text = text; - style = PdfUnorderedMarkerStyle.customString; - } else if (template != null) { - _template = template; - style = PdfUnorderedMarkerStyle.customTemplate; - } - } - - //Fields - /// Gets and sets the marker style. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new unordered list. - /// PdfUnorderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfUnorderedMarkerStyle style = PdfUnorderedMarkerStyle.none; - - /// Holds the marker text. - String? _text; - - // /// Holds the marker image. - // PdfImage _image; - - /// Marker temlapte. - PdfTemplate? _template; - late PdfUnorderedMarkerHelper _helper; - - //Properties - /// Gets or sets template of the marker. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new unordered list. - /// PdfUnorderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfUnorderedMarker(template: (PdfTemplate(100, 100) - /// ..graphics!.drawRectangle( - /// brush: PdfBrushes.red, - /// bounds: const Rect.fromLTWH(0, 0, 100, 100))))) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfTemplate? get template => _template; - set template(PdfTemplate? value) { - if (value != null) { - _template = value; - style = PdfUnorderedMarkerStyle.customTemplate; - } - } - - /// Gets marker text. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new unordered list. - /// PdfUnorderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfUnorderedMarker(text: 'Text')) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String? get text => _text; - set text(String? value) { - if (value != null) { - _text = value; - style = PdfUnorderedMarkerStyle.customString; - } - } -} - -/// [PdfUnorderedMarker] helper -class PdfUnorderedMarkerHelper extends PdfMarkerHelper { - /// internal constructor - PdfUnorderedMarkerHelper(this.base) : super(base); - - /// internal field - PdfUnorderedMarker base; - - /// internal method - static PdfUnorderedMarkerHelper getHelper(PdfUnorderedMarker base) { - return base._helper; - } - - /// Marker size. - PdfSize? size; - - /// Font used when draws styled marker - late PdfFont unicodeFont; - - /// Draws the specified graphics. - void draw( - PdfGraphics? graphics, - Offset point, - PdfBrush? brush, - PdfPen? pen, [ - PdfList? curList, - ]) { - final PdfTemplate templete = PdfTemplate(size!.width, size!.height); - Offset offset = Offset(point.dx, point.dy); - switch (base.style) { - case PdfUnorderedMarkerStyle.customTemplate: - templete.graphics!.drawPdfTemplate( - base._template!, - Offset.zero, - size!.size, - ); - offset = Offset( - point.dx, - point.dy + - ((curList!.font!.height > base.font!.height - ? curList.font!.height - : base.font!.height) / - 2) - - (size!.height / 2), - ); - break; - case PdfUnorderedMarkerStyle.customImage: - // templete.graphics.drawImage( - // _image, 1, 1, _size.width - 2, _size.height - 2); - break; - // ignore: no_default_cases - default: - final PdfPoint location = PdfPoint.empty; - if (pen != null) { - location.x = location.x + pen.width; - location.y = location.y + pen.width; - } - templete.graphics!.drawString( - getStyledText(), - unicodeFont, - pen: pen, - brush: brush, - bounds: Rect.fromLTWH(location.x, location.y, 0, 0), - ); - break; - } - graphics!.drawPdfTemplate(templete, offset); - } - - /// Gets the styled text. - String getStyledText() { - String text = ''; - switch (base.style) { - case PdfUnorderedMarkerStyle.disk: - text = '\x6C'; - break; - case PdfUnorderedMarkerStyle.square: - text = '\x6E'; - break; - case PdfUnorderedMarkerStyle.asterisk: - text = '\x5D'; - break; - case PdfUnorderedMarkerStyle.circle: - text = '\x6D'; - break; - // ignore: no_default_cases - default: - break; - } - return text; - } -} +import 'dart:ui'; + +import '../../../drawing/drawing.dart'; +import '../../../graphics/brushes/pdf_solid_brush.dart'; +import '../../../graphics/figures/pdf_template.dart'; +import '../../../graphics/fonts/pdf_font.dart'; +import '../../../graphics/pdf_graphics.dart'; +import '../../../graphics/pdf_pen.dart'; +import '../bullets/enums.dart'; +import '../pdf_list.dart'; +import 'pdf_marker.dart'; + +/// Represents bullet for the list. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new unordered list. +/// PdfUnorderedList uList = PdfUnorderedList( +/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// marker: //Create an unordered marker. +/// PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfUnorderedMarker extends PdfMarker { + //Constructor + /// Initializes a new instance of the [PdfUnorderedMarker] class + /// with Pdf unordered marker style. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new unordered list. + /// PdfUnorderedList uList = PdfUnorderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: //Create an unordered marker. + /// PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfUnorderedMarker({ + this.style = PdfUnorderedMarkerStyle.none, + PdfFont? font, + String? text, + PdfTemplate? template, + }) { + _helper = PdfUnorderedMarkerHelper(this); + if (font != null) { + this.font = font; + } + if (text != null) { + this.text = text; + style = PdfUnorderedMarkerStyle.customString; + } else if (template != null) { + _template = template; + style = PdfUnorderedMarkerStyle.customTemplate; + } + } + + //Fields + /// Gets and sets the marker style. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new unordered list. + /// PdfUnorderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfUnorderedMarkerStyle style = PdfUnorderedMarkerStyle.none; + + /// Holds the marker text. + String? _text; + + // /// Holds the marker image. + // PdfImage _image; + + /// Marker temlapte. + PdfTemplate? _template; + late PdfUnorderedMarkerHelper _helper; + + //Properties + /// Gets or sets template of the marker. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new unordered list. + /// PdfUnorderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfUnorderedMarker(template: (PdfTemplate(100, 100) + /// ..graphics!.drawRectangle( + /// brush: PdfBrushes.red, + /// bounds: const Rect.fromLTWH(0, 0, 100, 100))))) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfTemplate? get template => _template; + set template(PdfTemplate? value) { + if (value != null) { + _template = value; + style = PdfUnorderedMarkerStyle.customTemplate; + } + } + + /// Gets marker text. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new unordered list. + /// PdfUnorderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfUnorderedMarker(text: 'Text')) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String? get text => _text; + set text(String? value) { + if (value != null) { + _text = value; + style = PdfUnorderedMarkerStyle.customString; + } + } +} + +/// [PdfUnorderedMarker] helper +class PdfUnorderedMarkerHelper extends PdfMarkerHelper { + /// internal constructor + PdfUnorderedMarkerHelper(this.base) : super(base); + + /// internal field + PdfUnorderedMarker base; + + /// internal method + static PdfUnorderedMarkerHelper getHelper(PdfUnorderedMarker base) { + return base._helper; + } + + /// Marker size. + PdfSize? size; + + /// Font used when draws styled marker + late PdfFont unicodeFont; + + /// Draws the specified graphics. + void draw( + PdfGraphics? graphics, + Offset point, + PdfBrush? brush, + PdfPen? pen, [ + PdfList? curList, + ]) { + final PdfTemplate templete = PdfTemplate(size!.width, size!.height); + Offset offset = Offset(point.dx, point.dy); + switch (base.style) { + case PdfUnorderedMarkerStyle.customTemplate: + templete.graphics!.drawPdfTemplate( + base._template!, + Offset.zero, + size!.size, + ); + offset = Offset( + point.dx, + point.dy + + ((curList!.font!.height > base.font!.height + ? curList.font!.height + : base.font!.height) / + 2) - + (size!.height / 2), + ); + break; + case PdfUnorderedMarkerStyle.customImage: + // templete.graphics.drawImage( + // _image, 1, 1, _size.width - 2, _size.height - 2); + break; + // ignore: no_default_cases + default: + final PdfPoint location = PdfPoint.empty; + if (pen != null) { + location.x = location.x + pen.width; + location.y = location.y + pen.width; + } + templete.graphics!.drawString( + getStyledText(), + unicodeFont, + pen: pen, + brush: brush, + bounds: Rect.fromLTWH(location.x, location.y, 0, 0), + ); + break; + } + graphics!.drawPdfTemplate(templete, offset); + } + + /// Gets the styled text. + String getStyledText() { + String text = ''; + switch (base.style) { + case PdfUnorderedMarkerStyle.disk: + text = '\x6C'; + break; + case PdfUnorderedMarkerStyle.square: + text = '\x6E'; + break; + case PdfUnorderedMarkerStyle.asterisk: + text = '\x5D'; + break; + case PdfUnorderedMarkerStyle.circle: + text = '\x6D'; + break; + // ignore: no_default_cases + default: + break; + } + return text; + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list.dart index 7a783e870..1577ab6e6 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list.dart @@ -1,618 +1,618 @@ -import '../../drawing/drawing.dart'; -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/figures/base/element_layouter.dart'; -import '../../graphics/figures/base/layout_element.dart'; -import '../../graphics/figures/base/text_layouter.dart'; -import '../../graphics/figures/enums.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_string_format.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../graphics/pdf_pen.dart'; -import '../../pages/pdf_page.dart'; -import 'pdf_list_item.dart'; -import 'pdf_list_item_collection.dart'; -import 'pdf_list_layouter.dart'; - -/// Represents base class for lists. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new ordered list. -/// PdfOrderedList( -/// text: 'PDF\nXlsIO\nDocIO\nPPT', -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// format: PdfStringFormat(lineSpacing: 20), -/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), -/// style: PdfNumberStyle.numeric, -/// indent: 15, -/// textIndent: 10) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -abstract class PdfList extends PdfLayoutElement { - //Fields - /// Tabulation for items. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late double indent; - - /// Indent between marker and text. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late double textIndent; - - /// The pen for the list. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..pen = PdfPens.red - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPen? pen; - - /// The brush for the list. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..brush = PdfBrushes.red - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBrush? brush; - - /// The string format for the list. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfStringFormat? stringFormat; - - //Properties - /// Gets items of the list. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// indent: 10, - /// textIndent: 10, - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10, - /// style: PdfFontStyle.italic)) - /// ..items.add(PdfListItem(text: 'PDF')) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfListItemCollection get items { - _helper.items ??= PdfListItemCollection(); - return _helper.items!; - } - - /// Gets or sets the list font. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfFont? get font => _helper.font; - set font(PdfFont? value) { - if (value != null) { - _helper.font = value; - } - } - - //Events - /// Event that rises when item begin layout. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20)) - /// //Begin item layout event. - /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { - /// args.item.text += '_Beginsave'; - /// } - /// //End item layout event. - /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { - /// args.page.graphics.drawRectangle( - /// brush: PdfBrushes.red, - /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); - /// } - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - BeginItemLayoutCallback? beginItemLayout; - - /// Event that rises when item end layout. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20)) - /// //Begin item layout event. - /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { - /// args.item.text += '_Beginsave'; - /// } - /// //End item layout event. - /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { - /// args.page.graphics.drawRectangle( - /// brush: PdfBrushes.red, - /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); - /// } - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - EndItemLayoutCallback? endItemLayout; - - late PdfListHelper _helper; -} - -/// [PdfList] helper -class PdfListHelper { - /// internal construtor - PdfListHelper(this.list) { - list._helper = this; - } - - /// Creates an item collection. - static PdfListItemCollection createItems(String text) { - return PdfListItemCollection(text.split('\n')); - } - - /// internal field - PdfListItemCollection? items; - - /// internal field - PdfFont? font; - - /// internal field - late PdfList list; - - /// internal method - static PdfListHelper getHelper(PdfList list) { - return list._helper; - } - - /// Layouts on the specified Page. - PdfLayoutResult? layout(PdfLayoutParams param) { - final PdfListLayouter layouter = PdfListLayouter(list); - return layouter.layout(param); - } - - /// Draws list on the Graphics. - void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { - final PdfLayoutParams param = PdfLayoutParams(); - param.bounds = bounds; - param.format = PdfLayoutFormat(); - param.format!.layoutType = PdfLayoutType.onePage; - final PdfListLayouter layouter = PdfListLayouter(list); - layouter.graphics = graphics; - layouter.layoutInternal(param); - } - - /// Rise the BeginItemLayout event. - void onBeginItemLayout(BeginItemLayoutArgs args) { - if (list.beginItemLayout != null) { - list.beginItemLayout!(list, args); - } - } - - /// Rise the EndItemLayout event. - void onEndItemLayout(EndItemLayoutArgs args) { - if (list.endItemLayout != null) { - list.endItemLayout!(list, args); - } - } -} - -/// Represents begin layout event arguments. -/// -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new list. -/// PdfOrderedList( -/// text: 'PDF\nXlsIO\nDocIO\nPPT', -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// format: PdfStringFormat(lineSpacing: 20)) -/// //Begin item layout event. -/// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { -/// args.item.text += '_Beginsave'; -/// } -/// //End item layout event. -/// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { -/// args.page.graphics.drawRectangle( -/// brush: PdfBrushes.red, -/// bounds: const Rect.fromLTWH(400, 400, 100, 100)); -/// } -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class BeginItemLayoutArgs { - /// Initializes a new instance of the [BeginItemLayoutArgs] class. - BeginItemLayoutArgs._internal(this._item, this._page); - - //Fields - //Item that layout. - final PdfListItem _item; - - //The page in which item start layout. - final PdfPage _page; - - //Properties - /// Gets the item. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20)) - /// //Begin item layout event. - /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { - /// args.item.text += '_Beginsave'; - /// } - /// //End item layout event. - /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { - /// args.page.graphics.drawRectangle( - /// brush: PdfBrushes.red, - /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); - /// } - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfListItem get item => _item; - - /// Gets the page. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20)) - /// //Begin item layout event. - /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { - /// args.item.text += '_Beginsave'; - /// PdfPage page = args.page; - /// } - /// //End item layout event. - /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { - /// args.page.graphics.drawRectangle( - /// brush: PdfBrushes.red, - /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); - /// } - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPage get page => _page; -} - -// ignore: avoid_classes_with_only_static_members -/// [BeginItemLayoutArgs] helper -class BeginItemLayoutArgsHelper { - /// internal method - static BeginItemLayoutArgs internal(PdfListItem item, PdfPage page) { - return BeginItemLayoutArgs._internal(item, page); - } -} - -/// Represents end layout event arguments. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new list. -/// PdfOrderedList oList = PdfOrderedList( -/// text: 'PDF\nXlsIO\nDocIO\nPPT', -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// format: PdfStringFormat(lineSpacing: 20)); -/// oList.beginItemLayout = (Object sender, BeginItemLayoutArgs args) { -/// args.item.text += '_Beginsave'; -/// }; -/// //End item layout event. -/// oList.endItemLayout = (Object sender, EndItemLayoutArgs args) { -/// args.page.graphics.drawRectangle( -/// brush: PdfBrushes.red, bounds: const Rect.fromLTWH(400, 400, 100, 100)); -/// }; -/// oList.draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class EndItemLayoutArgs { - /// Initializes a new instance of the [EndItemLayoutArgs] class. - EndItemLayoutArgs._internal(this._item, this._page); - - //Fields - //Item that layouted. - final PdfListItem _item; - - //The page in which item ended layout. - final PdfPage _page; - - //Properties - /// Gets the item. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20)) - /// //Begin item layout event. - /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { - /// args.item.text += '_Beginsave'; - /// } - /// //End item layout event. - /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { - /// args.page.graphics.drawRectangle( - /// brush: PdfBrushes.red, - /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); - /// PdfListItem item = args.item; - /// } - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfListItem get item => _item; - - /// Gets the page. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20)) - /// //Begin item layout event. - /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { - /// args.item.text += '_Beginsave'; - /// } - /// //End item layout event. - /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { - /// args.page.graphics.drawRectangle( - /// brush: PdfBrushes.red, - /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); - /// } - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPage get page => _page; -} - -// ignore: avoid_classes_with_only_static_members -/// [EndItemLayoutArgs] helper -class EndItemLayoutArgsHelper { - /// internal method - static EndItemLayoutArgs internal(PdfListItem item, PdfPage page) { - return EndItemLayoutArgs._internal(item, page); - } -} - -/// typedef for handling BeginItemLayoutEvent. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new list. -/// PdfOrderedList( -/// text: 'PDF\nXlsIO\nDocIO\nPPT', -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// format: PdfStringFormat(lineSpacing: 20)) -/// //Begin item layout event. -/// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { -/// args.item.text += '_Beginsave'; -/// } -/// //End item layout event. -/// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { -/// args.page.graphics.drawRectangle( -/// brush: PdfBrushes.red, -/// bounds: const Rect.fromLTWH(400, 400, 100, 100)); -/// } -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -typedef BeginItemLayoutCallback = - void Function(Object sender, BeginItemLayoutArgs args); - -/// typedef for handling EndItemLayoutEvent. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new list. -/// PdfOrderedList( -/// text: 'PDF\nXlsIO\nDocIO\nPPT', -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// format: PdfStringFormat(lineSpacing: 20)) -/// //Begin item layout event. -/// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { -/// args.item.text += '_Beginsave'; -/// } -/// //End item layout event. -/// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { -/// args.page.graphics.drawRectangle( -/// brush: PdfBrushes.red, -/// bounds: const Rect.fromLTWH(400, 400, 100, 100)); -/// } -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -typedef EndItemLayoutCallback = - void Function(Object sender, EndItemLayoutArgs args); +import '../../drawing/drawing.dart'; +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/figures/base/element_layouter.dart'; +import '../../graphics/figures/base/layout_element.dart'; +import '../../graphics/figures/base/text_layouter.dart'; +import '../../graphics/figures/enums.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_string_format.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../graphics/pdf_pen.dart'; +import '../../pages/pdf_page.dart'; +import 'pdf_list_item.dart'; +import 'pdf_list_item_collection.dart'; +import 'pdf_list_layouter.dart'; + +/// Represents base class for lists. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new ordered list. +/// PdfOrderedList( +/// text: 'PDF\nXlsIO\nDocIO\nPPT', +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// format: PdfStringFormat(lineSpacing: 20), +/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), +/// style: PdfNumberStyle.numeric, +/// indent: 15, +/// textIndent: 10) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +abstract class PdfList extends PdfLayoutElement { + //Fields + /// Tabulation for items. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late double indent; + + /// Indent between marker and text. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late double textIndent; + + /// The pen for the list. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..pen = PdfPens.red + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPen? pen; + + /// The brush for the list. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..brush = PdfBrushes.red + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBrush? brush; + + /// The string format for the list. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfStringFormat? stringFormat; + + //Properties + /// Gets items of the list. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// indent: 10, + /// textIndent: 10, + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10, + /// style: PdfFontStyle.italic)) + /// ..items.add(PdfListItem(text: 'PDF')) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfListItemCollection get items { + _helper.items ??= PdfListItemCollection(); + return _helper.items!; + } + + /// Gets or sets the list font. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfFont? get font => _helper.font; + set font(PdfFont? value) { + if (value != null) { + _helper.font = value; + } + } + + //Events + /// Event that rises when item begin layout. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20)) + /// //Begin item layout event. + /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { + /// args.item.text += '_Beginsave'; + /// } + /// //End item layout event. + /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { + /// args.page.graphics.drawRectangle( + /// brush: PdfBrushes.red, + /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); + /// } + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + BeginItemLayoutCallback? beginItemLayout; + + /// Event that rises when item end layout. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20)) + /// //Begin item layout event. + /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { + /// args.item.text += '_Beginsave'; + /// } + /// //End item layout event. + /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { + /// args.page.graphics.drawRectangle( + /// brush: PdfBrushes.red, + /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); + /// } + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + EndItemLayoutCallback? endItemLayout; + + late PdfListHelper _helper; +} + +/// [PdfList] helper +class PdfListHelper { + /// internal construtor + PdfListHelper(this.list) { + list._helper = this; + } + + /// Creates an item collection. + static PdfListItemCollection createItems(String text) { + return PdfListItemCollection(text.split('\n')); + } + + /// internal field + PdfListItemCollection? items; + + /// internal field + PdfFont? font; + + /// internal field + late PdfList list; + + /// internal method + static PdfListHelper getHelper(PdfList list) { + return list._helper; + } + + /// Layouts on the specified Page. + PdfLayoutResult? layout(PdfLayoutParams param) { + final PdfListLayouter layouter = PdfListLayouter(list); + return layouter.layout(param); + } + + /// Draws list on the Graphics. + void drawInternal(PdfGraphics graphics, PdfRectangle bounds) { + final PdfLayoutParams param = PdfLayoutParams(); + param.bounds = bounds; + param.format = PdfLayoutFormat(); + param.format!.layoutType = PdfLayoutType.onePage; + final PdfListLayouter layouter = PdfListLayouter(list); + layouter.graphics = graphics; + layouter.layoutInternal(param); + } + + /// Rise the BeginItemLayout event. + void onBeginItemLayout(BeginItemLayoutArgs args) { + if (list.beginItemLayout != null) { + list.beginItemLayout!(list, args); + } + } + + /// Rise the EndItemLayout event. + void onEndItemLayout(EndItemLayoutArgs args) { + if (list.endItemLayout != null) { + list.endItemLayout!(list, args); + } + } +} + +/// Represents begin layout event arguments. +/// +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new list. +/// PdfOrderedList( +/// text: 'PDF\nXlsIO\nDocIO\nPPT', +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// format: PdfStringFormat(lineSpacing: 20)) +/// //Begin item layout event. +/// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { +/// args.item.text += '_Beginsave'; +/// } +/// //End item layout event. +/// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { +/// args.page.graphics.drawRectangle( +/// brush: PdfBrushes.red, +/// bounds: const Rect.fromLTWH(400, 400, 100, 100)); +/// } +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class BeginItemLayoutArgs { + /// Initializes a new instance of the [BeginItemLayoutArgs] class. + BeginItemLayoutArgs._internal(this._item, this._page); + + //Fields + //Item that layout. + final PdfListItem _item; + + //The page in which item start layout. + final PdfPage _page; + + //Properties + /// Gets the item. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20)) + /// //Begin item layout event. + /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { + /// args.item.text += '_Beginsave'; + /// } + /// //End item layout event. + /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { + /// args.page.graphics.drawRectangle( + /// brush: PdfBrushes.red, + /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); + /// } + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfListItem get item => _item; + + /// Gets the page. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20)) + /// //Begin item layout event. + /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { + /// args.item.text += '_Beginsave'; + /// PdfPage page = args.page; + /// } + /// //End item layout event. + /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { + /// args.page.graphics.drawRectangle( + /// brush: PdfBrushes.red, + /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); + /// } + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPage get page => _page; +} + +// ignore: avoid_classes_with_only_static_members +/// [BeginItemLayoutArgs] helper +class BeginItemLayoutArgsHelper { + /// internal method + static BeginItemLayoutArgs internal(PdfListItem item, PdfPage page) { + return BeginItemLayoutArgs._internal(item, page); + } +} + +/// Represents end layout event arguments. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new list. +/// PdfOrderedList oList = PdfOrderedList( +/// text: 'PDF\nXlsIO\nDocIO\nPPT', +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// format: PdfStringFormat(lineSpacing: 20)); +/// oList.beginItemLayout = (Object sender, BeginItemLayoutArgs args) { +/// args.item.text += '_Beginsave'; +/// }; +/// //End item layout event. +/// oList.endItemLayout = (Object sender, EndItemLayoutArgs args) { +/// args.page.graphics.drawRectangle( +/// brush: PdfBrushes.red, bounds: const Rect.fromLTWH(400, 400, 100, 100)); +/// }; +/// oList.draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class EndItemLayoutArgs { + /// Initializes a new instance of the [EndItemLayoutArgs] class. + EndItemLayoutArgs._internal(this._item, this._page); + + //Fields + //Item that layouted. + final PdfListItem _item; + + //The page in which item ended layout. + final PdfPage _page; + + //Properties + /// Gets the item. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20)) + /// //Begin item layout event. + /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { + /// args.item.text += '_Beginsave'; + /// } + /// //End item layout event. + /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { + /// args.page.graphics.drawRectangle( + /// brush: PdfBrushes.red, + /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); + /// PdfListItem item = args.item; + /// } + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfListItem get item => _item; + + /// Gets the page. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20)) + /// //Begin item layout event. + /// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { + /// args.item.text += '_Beginsave'; + /// } + /// //End item layout event. + /// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { + /// args.page.graphics.drawRectangle( + /// brush: PdfBrushes.red, + /// bounds: const Rect.fromLTWH(400, 400, 100, 100)); + /// } + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPage get page => _page; +} + +// ignore: avoid_classes_with_only_static_members +/// [EndItemLayoutArgs] helper +class EndItemLayoutArgsHelper { + /// internal method + static EndItemLayoutArgs internal(PdfListItem item, PdfPage page) { + return EndItemLayoutArgs._internal(item, page); + } +} + +/// typedef for handling BeginItemLayoutEvent. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new list. +/// PdfOrderedList( +/// text: 'PDF\nXlsIO\nDocIO\nPPT', +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// format: PdfStringFormat(lineSpacing: 20)) +/// //Begin item layout event. +/// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { +/// args.item.text += '_Beginsave'; +/// } +/// //End item layout event. +/// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { +/// args.page.graphics.drawRectangle( +/// brush: PdfBrushes.red, +/// bounds: const Rect.fromLTWH(400, 400, 100, 100)); +/// } +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +typedef BeginItemLayoutCallback = + void Function(Object sender, BeginItemLayoutArgs args); + +/// typedef for handling EndItemLayoutEvent. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new list. +/// PdfOrderedList( +/// text: 'PDF\nXlsIO\nDocIO\nPPT', +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// format: PdfStringFormat(lineSpacing: 20)) +/// //Begin item layout event. +/// ..beginItemLayout = (Object sender, BeginItemLayoutArgs args) { +/// args.item.text += '_Beginsave'; +/// } +/// //End item layout event. +/// ..endItemLayout = (Object sender, EndItemLayoutArgs args) { +/// args.page.graphics.drawRectangle( +/// brush: PdfBrushes.red, +/// bounds: const Rect.fromLTWH(400, 400, 100, 100)); +/// } +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +typedef EndItemLayoutCallback = + void Function(Object sender, EndItemLayoutArgs args); diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item.dart index 5d45eeddb..916394d60 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item.dart @@ -1,202 +1,202 @@ -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_string_format.dart'; -import '../../graphics/pdf_pen.dart'; -import 'pdf_list.dart'; - -/// Represents list item of the list. -/// -/// ```dart -/// //Create a new instance of PdfDocument class. -/// PdfDocument document = PdfDocument(); -/// //Create a new list. -/// PdfOrderedList( -/// font: PdfStandardFont(PdfFontFamily.timesRoman, 10, -/// style: PdfFontStyle.italic)) -/// ..items.add( -/// //Create list item. -/// PdfListItem(text: 'PDF')) -/// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfListItem { - //Constructor - /// Initializes a new instance of the [PdfListItem] class. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList( - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10, - /// style: PdfFontStyle.italic)) - /// ..items.add( - /// //Create list item. - /// PdfListItem(text: 'PDF')) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfListItem({ - this.text = '', - this.font, - PdfStringFormat? format, - this.pen, - this.brush, - this.subList, - }) { - stringFormat = format; - } - - //Fields - /// Holds item font. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList() - /// ..items.add(PdfListItem( - /// text: 'PDF', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), - /// format: PdfStringFormat(alignment: PdfTextAlignment.left), - /// pen: PdfPens.green, - /// brush: PdfBrushes.red)) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfFont? font; - - /// Holds text format. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList() - /// ..items.add(PdfListItem( - /// text: 'PDF', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), - /// format: PdfStringFormat(alignment: PdfTextAlignment.left), - /// pen: PdfPens.green, - /// brush: PdfBrushes.red)) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfStringFormat? stringFormat; - - /// Holds pen. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList() - /// ..items.add(PdfListItem( - /// text: 'PDF', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), - /// format: PdfStringFormat(alignment: PdfTextAlignment.left), - /// pen: PdfPens.green, - /// brush: PdfBrushes.red)) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfPen? pen; - - /// Holds brush. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList() - /// ..items.add(PdfListItem( - /// text: 'PDF', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), - /// format: PdfStringFormat(alignment: PdfTextAlignment.left), - /// pen: PdfPens.green, - /// brush: PdfBrushes.red)) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfBrush? brush; - - /// Adds the Sub list. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList() - /// ..items.add(PdfListItem(text: 'Essential tools') - /// //Add sub list. - /// ..subList = PdfOrderedList(items: PdfListItemCollection(['PDF']))) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfList? subList; - - /// Text indent for current item. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList() - /// ..items.add(PdfListItem( - /// text: 'PDF', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), - /// format: PdfStringFormat(alignment: PdfTextAlignment.left), - /// pen: PdfPens.green, - /// brush: PdfBrushes.red) - /// ..textIndent = 10) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - double textIndent = 0; - - //Properties - /// Gets or sets item text. - /// - /// ```dart - /// //Create a new instance of PdfDocument class. - /// PdfDocument document = PdfDocument(); - /// //Create a new list. - /// PdfOrderedList() - /// ..items.add(PdfListItem( - /// text: 'PDF', - /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), - /// format: PdfStringFormat(alignment: PdfTextAlignment.left), - /// pen: PdfPens.green, - /// brush: PdfBrushes.red)) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - String text = ''; -} +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_string_format.dart'; +import '../../graphics/pdf_pen.dart'; +import 'pdf_list.dart'; + +/// Represents list item of the list. +/// +/// ```dart +/// //Create a new instance of PdfDocument class. +/// PdfDocument document = PdfDocument(); +/// //Create a new list. +/// PdfOrderedList( +/// font: PdfStandardFont(PdfFontFamily.timesRoman, 10, +/// style: PdfFontStyle.italic)) +/// ..items.add( +/// //Create list item. +/// PdfListItem(text: 'PDF')) +/// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfListItem { + //Constructor + /// Initializes a new instance of the [PdfListItem] class. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList( + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10, + /// style: PdfFontStyle.italic)) + /// ..items.add( + /// //Create list item. + /// PdfListItem(text: 'PDF')) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfListItem({ + this.text = '', + this.font, + PdfStringFormat? format, + this.pen, + this.brush, + this.subList, + }) { + stringFormat = format; + } + + //Fields + /// Holds item font. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList() + /// ..items.add(PdfListItem( + /// text: 'PDF', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), + /// format: PdfStringFormat(alignment: PdfTextAlignment.left), + /// pen: PdfPens.green, + /// brush: PdfBrushes.red)) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfFont? font; + + /// Holds text format. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList() + /// ..items.add(PdfListItem( + /// text: 'PDF', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), + /// format: PdfStringFormat(alignment: PdfTextAlignment.left), + /// pen: PdfPens.green, + /// brush: PdfBrushes.red)) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfStringFormat? stringFormat; + + /// Holds pen. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList() + /// ..items.add(PdfListItem( + /// text: 'PDF', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), + /// format: PdfStringFormat(alignment: PdfTextAlignment.left), + /// pen: PdfPens.green, + /// brush: PdfBrushes.red)) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfPen? pen; + + /// Holds brush. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList() + /// ..items.add(PdfListItem( + /// text: 'PDF', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), + /// format: PdfStringFormat(alignment: PdfTextAlignment.left), + /// pen: PdfPens.green, + /// brush: PdfBrushes.red)) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfBrush? brush; + + /// Adds the Sub list. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList() + /// ..items.add(PdfListItem(text: 'Essential tools') + /// //Add sub list. + /// ..subList = PdfOrderedList(items: PdfListItemCollection(['PDF']))) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfList? subList; + + /// Text indent for current item. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList() + /// ..items.add(PdfListItem( + /// text: 'PDF', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), + /// format: PdfStringFormat(alignment: PdfTextAlignment.left), + /// pen: PdfPens.green, + /// brush: PdfBrushes.red) + /// ..textIndent = 10) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + double textIndent = 0; + + //Properties + /// Gets or sets item text. + /// + /// ```dart + /// //Create a new instance of PdfDocument class. + /// PdfDocument document = PdfDocument(); + /// //Create a new list. + /// PdfOrderedList() + /// ..items.add(PdfListItem( + /// text: 'PDF', + /// font: PdfStandardFont(PdfFontFamily.timesRoman, 10), + /// format: PdfStringFormat(alignment: PdfTextAlignment.left), + /// pen: PdfPens.green, + /// brush: PdfBrushes.red)) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(10, 10, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + String text = ''; +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item_collection.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item_collection.dart index 2fb09c8f2..3ed8537a2 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item_collection.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_item_collection.dart @@ -1,314 +1,314 @@ -import '../../general/pdf_collection.dart'; -import 'pdf_list_item.dart'; - -/// Represents collection of list items. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new ordered list. -/// PdfOrderedList( -/// //Create a new list item collection. -/// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// format: PdfStringFormat(lineSpacing: 20), -/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), -/// style: PdfNumberStyle.numeric, -/// indent: 15, -/// textIndent: 10) -/// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfListItemCollection extends PdfObjectCollection { - //Constructor - /// Initializes a new instance of the [PdfListItemCollection] class. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// //Create a new list item collection. - /// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfListItemCollection([List? items]) { - _helper = PdfListItemCollectionHelper(this, items); - } - - //Fields - late PdfListItemCollectionHelper _helper; - - //Properties - /// Gets the [PdfListItem] from collection at the specified index. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..items[0].subList = - /// PdfOrderedList(items: PdfListItemCollection(['PDF', 'DocIO'])) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfListItem operator [](int index) => _helper.getValue(index); - - //Public methods - /// Adds the specified item. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection() - /// //Add items to list item collection - /// ..add(PdfListItem(text: 'PDF')) - /// ..add(PdfListItem(text: 'DocIO')), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int add(PdfListItem item, [double? itemIndent]) { - return _helper.add(item, itemIndent); - } - - /// Inserts item at the specified index. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection() - /// ..add(PdfListItem(text: 'PDF')) - /// //insert items to list item collection - /// ..insert(0, PdfListItem(text: 'DocIO')), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void insert(int index, PdfListItem item, [double? itemIndent]) { - _helper.insert(index, item, itemIndent); - } - - /// Removes the specified item from the list. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfList list = PdfOrderedList( - /// items: PdfListItemCollection() - /// ..add(PdfListItem(text: 'PDF')) - /// ..add(PdfListItem(text: 'DocIO')), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)); - /// //Remove a specific item - /// list - /// ..items.remove(list.items[0]) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void remove(PdfListItem item) { - _helper.remove(item); - } - - /// Removes the item at the specified index from the list. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection() - /// ..add(PdfListItem(text: 'PDF')) - /// ..insert(0, PdfListItem(text: 'DocIO')) - /// //Remove item at specific index. - /// ..removeAt(1), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void removeAt(int index) { - _helper.removeAt(index); - } - - /// Determines the index of a specific item in the list. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a list item. - /// PdfListItem item = PdfListItem(text: 'PDF'); - /// //Create a new ordered list. - /// PdfOrderedList oList = PdfOrderedList( - /// items: PdfListItemCollection() - /// ..add(item) - /// ..add(PdfListItem(text: 'DocIO')), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)); - /// //Get the index of specific item. - /// int index = oList.items.indexOf(item); - /// //Draw the list to the page. - /// oList.draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - int indexOf(PdfListItem item) { - return _helper.indexOf(item); - } - - /// Clears collection - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection() - /// ..add(PdfListItem(text: 'PDF')) - /// ..add(PdfListItem(text: 'DocIO')) - /// //Clears the all items in the collection. - /// ..clear() - /// ..add(PdfListItem(text: 'DocIO')), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - void clear() { - _helper.clear(); - } -} - -/// [PdfListItemCollection] helper -class PdfListItemCollectionHelper extends PdfObjectCollectionHelper { - /// internal constructor - PdfListItemCollectionHelper(this.base, List? items) : super(base) { - if (items != null) { - for (int i = 0; i < items.length; i++) { - _add(items[i]); - } - } - } - - /// internal field - PdfListItemCollection base; - - /// internal method - PdfListItem _add(String text) { - final PdfListItem item = PdfListItem(text: text); - list.add(item); - return item; - } - - /// internal method - PdfListItem getValue(int index) { - if (index < 0 || index >= base.count) { - throw RangeError( - "The index should be less than item's count or more or equal to 0", - ); - } - return list[index] as PdfListItem; - } - - /// internal method - int add(PdfListItem item, double? itemIndent) { - if (itemIndent != null) { - item.textIndent = itemIndent; - } - list.add(item); - return list.length - 1; - } - - /// internal method - void insert(int index, PdfListItem item, double? itemIndent) { - if (index < 0 || index >= base.count) { - throw ArgumentError( - "The index should be less than item's count or more or equal to 0, $index", - ); - } - if (itemIndent != null) { - item.textIndent = itemIndent; - } - list.insert(index, item); - } - - /// internal method - void remove(PdfListItem item) { - if (!list.contains(item)) { - throw ArgumentError("The list doesn't contain this item, $item"); - } - list.remove(item); - } - - /// internal method - void removeAt(int index) { - if (index < 0 || index >= base.count) { - throw ArgumentError( - "The index should be less than item's count or more or equal to 0, $index", - ); - } - list.removeAt(index); - } - - /// Determines the index of a specific item in the list. - int indexOf(PdfListItem item) { - return list.indexOf(item); - } - - /// Clears collection - void clear() { - list.clear(); - } -} +import '../../general/pdf_collection.dart'; +import 'pdf_list_item.dart'; + +/// Represents collection of list items. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new ordered list. +/// PdfOrderedList( +/// //Create a new list item collection. +/// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// format: PdfStringFormat(lineSpacing: 20), +/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), +/// style: PdfNumberStyle.numeric, +/// indent: 15, +/// textIndent: 10) +/// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfListItemCollection extends PdfObjectCollection { + //Constructor + /// Initializes a new instance of the [PdfListItemCollection] class. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// //Create a new list item collection. + /// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..draw(page: document.pages.add(), bounds: Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfListItemCollection([List? items]) { + _helper = PdfListItemCollectionHelper(this, items); + } + + //Fields + late PdfListItemCollectionHelper _helper; + + //Properties + /// Gets the [PdfListItem] from collection at the specified index. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..items[0].subList = + /// PdfOrderedList(items: PdfListItemCollection(['PDF', 'DocIO'])) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfListItem operator [](int index) => _helper.getValue(index); + + //Public methods + /// Adds the specified item. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection() + /// //Add items to list item collection + /// ..add(PdfListItem(text: 'PDF')) + /// ..add(PdfListItem(text: 'DocIO')), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int add(PdfListItem item, [double? itemIndent]) { + return _helper.add(item, itemIndent); + } + + /// Inserts item at the specified index. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection() + /// ..add(PdfListItem(text: 'PDF')) + /// //insert items to list item collection + /// ..insert(0, PdfListItem(text: 'DocIO')), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void insert(int index, PdfListItem item, [double? itemIndent]) { + _helper.insert(index, item, itemIndent); + } + + /// Removes the specified item from the list. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfList list = PdfOrderedList( + /// items: PdfListItemCollection() + /// ..add(PdfListItem(text: 'PDF')) + /// ..add(PdfListItem(text: 'DocIO')), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)); + /// //Remove a specific item + /// list + /// ..items.remove(list.items[0]) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void remove(PdfListItem item) { + _helper.remove(item); + } + + /// Removes the item at the specified index from the list. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection() + /// ..add(PdfListItem(text: 'PDF')) + /// ..insert(0, PdfListItem(text: 'DocIO')) + /// //Remove item at specific index. + /// ..removeAt(1), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void removeAt(int index) { + _helper.removeAt(index); + } + + /// Determines the index of a specific item in the list. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a list item. + /// PdfListItem item = PdfListItem(text: 'PDF'); + /// //Create a new ordered list. + /// PdfOrderedList oList = PdfOrderedList( + /// items: PdfListItemCollection() + /// ..add(item) + /// ..add(PdfListItem(text: 'DocIO')), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)); + /// //Get the index of specific item. + /// int index = oList.items.indexOf(item); + /// //Draw the list to the page. + /// oList.draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + int indexOf(PdfListItem item) { + return _helper.indexOf(item); + } + + /// Clears collection + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection() + /// ..add(PdfListItem(text: 'PDF')) + /// ..add(PdfListItem(text: 'DocIO')) + /// //Clears the all items in the collection. + /// ..clear() + /// ..add(PdfListItem(text: 'DocIO')), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + void clear() { + _helper.clear(); + } +} + +/// [PdfListItemCollection] helper +class PdfListItemCollectionHelper extends PdfObjectCollectionHelper { + /// internal constructor + PdfListItemCollectionHelper(this.base, List? items) : super(base) { + if (items != null) { + for (int i = 0; i < items.length; i++) { + _add(items[i]); + } + } + } + + /// internal field + PdfListItemCollection base; + + /// internal method + PdfListItem _add(String text) { + final PdfListItem item = PdfListItem(text: text); + list.add(item); + return item; + } + + /// internal method + PdfListItem getValue(int index) { + if (index < 0 || index >= base.count) { + throw RangeError( + "The index should be less than item's count or more or equal to 0", + ); + } + return list[index] as PdfListItem; + } + + /// internal method + int add(PdfListItem item, double? itemIndent) { + if (itemIndent != null) { + item.textIndent = itemIndent; + } + list.add(item); + return list.length - 1; + } + + /// internal method + void insert(int index, PdfListItem item, double? itemIndent) { + if (index < 0 || index >= base.count) { + throw ArgumentError( + "The index should be less than item's count or more or equal to 0, $index", + ); + } + if (itemIndent != null) { + item.textIndent = itemIndent; + } + list.insert(index, item); + } + + /// internal method + void remove(PdfListItem item) { + if (!list.contains(item)) { + throw ArgumentError("The list doesn't contain this item, $item"); + } + list.remove(item); + } + + /// internal method + void removeAt(int index) { + if (index < 0 || index >= base.count) { + throw ArgumentError( + "The index should be less than item's count or more or equal to 0, $index", + ); + } + list.removeAt(index); + } + + /// Determines the index of a specific item in the list. + int indexOf(PdfListItem item) { + return list.indexOf(item); + } + + /// Clears collection + void clear() { + list.clear(); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_layouter.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_layouter.dart index 9523f06a4..f98b48da1 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_layouter.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_list_layouter.dart @@ -1,1091 +1,1091 @@ -import 'dart:ui'; - -import '../../drawing/drawing.dart'; -import '../../graphics/brushes/pdf_brush.dart'; -import '../../graphics/brushes/pdf_solid_brush.dart'; -import '../../graphics/enums.dart'; -import '../../graphics/figures/base/element_layouter.dart'; -import '../../graphics/figures/base/layout_element.dart'; -import '../../graphics/figures/base/text_layouter.dart'; -import '../../graphics/figures/enums.dart'; -import '../../graphics/fonts/enums.dart'; -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_standard_font.dart'; -import '../../graphics/fonts/pdf_string_format.dart'; -import '../../graphics/fonts/pdf_string_layout_result.dart'; -import '../../graphics/fonts/pdf_string_layouter.dart'; -import '../../graphics/pdf_graphics.dart'; -import '../../graphics/pdf_pen.dart'; -import '../../pages/enum.dart'; -import '../../pages/pdf_page.dart'; -import 'bullets/enums.dart'; -import 'bullets/pdf_marker.dart'; -import 'bullets/pdf_ordered_marker.dart'; -import 'bullets/pdf_unordered_marker.dart'; -import 'pdf_list.dart'; -import 'pdf_list_item.dart'; -import 'pdf_ordered_list.dart'; -import 'pdf_unordered_list.dart'; - -/// Layouts list. -class PdfListLayouter extends ElementLayouter { - /// Initializes a new instance of the [PdfListLayouter] class. - PdfListLayouter(PdfList super.element); - - /// Current graphics for lay outing. - PdfGraphics? graphics; - - /// Indicates end of lay outing. - bool finish = false; - - /// List that layouts at the moment. - PdfList? curList; - - /// List that contains ListInfo. - List info = []; - - /// Index of item that lay outing. - int index = 0; - - /// The indent of current list. - double? indent; - - /// Height in which it stop lay outing. - double? resultHeight; - - /// Lay outing bounds. - late PdfRectangle bounds; - - /// Current page for layout. - PdfPage? currentPage; - - /// PdfSize for item lay outing. - PdfSize size = PdfSize.empty; - - /// If true it use paginate bounds if it is set. - bool usePaginateBounds = true; - - /// Current brush for lay outing. - PdfBrush? currentBrush; - - /// Current pen for layout. - PdfPen? currentPen; - - /// Current font for layout. - PdfFont? currentFont; - - /// Current string format. - PdfStringFormat? currentFormat; - - /// Marker maximum width. - num? markerMaxWidth; - @override - PdfList? get element => super.element as PdfList?; - - @override - PdfLayoutResult? layoutInternal(PdfLayoutParams param) { - currentPage = param.page; - bounds = param.bounds!.clone(); - if (param.bounds!.height == 0 && - param.bounds!.width == 0 && - currentPage != null) { - bounds.width = currentPage!.getClientSize().width; - bounds.height = currentPage!.getClientSize().height; - bounds.width = bounds.width - bounds.x; - bounds.height = bounds.height - bounds.y; - } - - if (currentPage != null) { - graphics = currentPage!.graphics; - } - - _PageLayoutResult pageResult = _PageLayoutResult(); - pageResult.broken = false; - pageResult.y = bounds.y; - curList = element; - indent = element!.indent; - - _setCurrentParameters(element); - - if (element!.brush == null) { - currentBrush = PdfBrushes.black; - } - - if (element!.font == null) { - currentFont = PdfStandardFont(PdfFontFamily.helvetica, 8); - curList!.font = currentFont; - } - - if (curList is PdfOrderedList) { - markerMaxWidth = _getMarkerMaxWidth(curList! as PdfOrderedList, info); - } - - final bool useOnePage = param.format!.layoutType == PdfLayoutType.onePage; - - while (!finish) { - bool cancel = _beforePageLayout(bounds.rect, currentPage, curList!); - pageResult.y = bounds.y; - ListEndPageLayoutArgs? endArgs; - if (!cancel) { - pageResult = _layoutOnPage(pageResult)!; - endArgs = _afterPageLayouted(bounds.rect, currentPage, curList!); - cancel = endArgs != null && endArgs.cancel; - } - if (useOnePage || cancel) { - break; - } - if (currentPage != null && !finish) { - if ((endArgs != null) && (endArgs.nextPage != null)) { - currentPage = endArgs.nextPage; - } else { - currentPage = getNextPage(currentPage!); - } - graphics = currentPage!.graphics; - if (param.bounds!.width == 0 && param.bounds!.height == 0) { - bounds.width = currentPage!.getClientSize().width; - bounds.height = currentPage!.getClientSize().height; - bounds.width = bounds.width - bounds.x; - bounds.height = bounds.height - bounds.y; - } - if ((param.format != null) && - PdfLayoutFormatHelper.isBoundsSet(param.format!) && - usePaginateBounds) { - bounds = PdfRectangle.fromRect(param.format!.paginateBounds); - } - } - } - info.clear(); - final Rect finalBounds = Rect.fromLTWH( - bounds.x, - pageResult.y!, - bounds.width, - resultHeight ?? 0, - ); - if (currentPage != null) { - final PdfLayoutResult result = PdfLayoutResultHelper.load( - currentPage!, - finalBounds, - ); - return result; - } else { - return null; - } - } - - /// Layouts the on the page. - _PageLayoutResult? _layoutOnPage(_PageLayoutResult? pageResult) { - double? height = 0; - double resultantHeight = 0; - double? y = bounds.y; - final double x = bounds.x; - size = PdfSize(bounds.size.width, bounds.size.height); - size.width = size.width - indent!; - - while (true) { - for (; index < curList!.items.count; ++index) { - final PdfListItem item = curList!.items[index]; - - if (currentPage != null && !pageResult!.broken) { - _beforeItemLayout(item, currentPage!); - } - final Map returnedValue = _drawItem( - pageResult!, - x, - curList!, - index, - indent!, - info, - item, - height!, - y!, - ); - pageResult = returnedValue['pageResult'] as _PageLayoutResult?; - height = returnedValue['height'] as double?; - y = returnedValue['y'] as double?; - resultantHeight += height!; - if (pageResult!.broken) { - return pageResult; - } - - if (currentPage != null) { - _afterItemLayouted(item, currentPage!); - } - pageResult.markerWrote = false; - - if (item.subList != null && item.subList!.items.count > 0) { - if (curList is PdfOrderedList) { - final PdfOrderedList oList = curList! as PdfOrderedList; - PdfOrderedMarkerHelper.getHelper(oList.marker).currentIndex = index; - final ListInfo listInfo = ListInfo( - curList, - index, - PdfOrderedMarkerHelper.getHelper(oList.marker).getNumber(), - ); - listInfo.brush = currentBrush; - listInfo.font = currentFont; - listInfo.format = currentFormat; - listInfo.pen = currentPen; - listInfo.markerWidth = markerMaxWidth as double?; - info.add(listInfo); - } else { - final ListInfo listInfo = ListInfo(curList, index); - listInfo.brush = currentBrush; - listInfo.font = currentFont; - listInfo.format = currentFormat; - listInfo.pen = currentPen; - info.add(listInfo); - } - curList = item.subList; - if (curList is PdfOrderedList) { - markerMaxWidth = _getMarkerMaxWidth( - curList! as PdfOrderedList, - info, - ); - } - index = -1; - indent = indent! + curList!.indent; - size.width = size.width - curList!.indent; - _setCurrentParameters(item); - _setCurrentParameters(curList); - } - } - if (info.isEmpty) { - resultHeight = resultantHeight; - finish = true; - break; - } - final ListInfo listInfo = info.last; - info.remove(listInfo); - index = listInfo.index + 1; - indent = indent! - curList!.indent; - size.width = size.width + curList!.indent; - markerMaxWidth = listInfo.markerWidth; - currentBrush = listInfo.brush; - currentPen = listInfo.pen; - currentFont = listInfo.font; - currentFormat = listInfo.format; - curList = listInfo.list; - } - return pageResult; - } - - /// Draws the item. - Map _drawItem( - _PageLayoutResult pageResult, - double x, - PdfList curList, - int index, - double indent, - List listInfo, - PdfListItem item, - double height, - double y, - ) { - final PdfStringLayouter layouter = PdfStringLayouter(); - PdfStringLayoutResult? markerResult; - PdfStringLayoutResult? result; - - bool wroteMaker = false; - final double textIndent = curList.textIndent; - - final double posY = height + y; - double posX = indent + x; - - double? itemHeight = 0; - double? markerHeight = 0; - PdfSize itemSize = PdfSize(size.width, size.height); - - String? text = item.text; - String? markerText; - - PdfBrush? itemBrush = currentBrush; - - if (item.brush != null) { - itemBrush = item.brush; - } - - PdfPen? itemPen = currentPen; - - if (item.pen != null) { - itemPen = item.pen; - } - - PdfFont? itemFont = currentFont; - - if (item.font != null) { - itemFont = item.font; - } - - PdfStringFormat? itemFormat = currentFormat; - - if (item.stringFormat != null) { - itemFormat = item.stringFormat; - } - - if (((size.width <= 0) || (size.width < itemFont!.size)) && - currentPage != null) { - throw Exception('There is not enough space to layout list.'); - } - size.height = size.height - height; - - PdfMarker marker; - - if (curList is PdfUnorderedList) { - marker = curList.marker; - } else { - marker = (curList as PdfOrderedList).marker; - } - - if (pageResult.broken) { - text = pageResult.itemText; - markerText = pageResult.markerText; - } - - bool canDrawMarker = true; - - if (markerText != null && - ((marker is PdfUnorderedMarker) && - (marker.style == PdfUnorderedMarkerStyle.customString))) { - markerResult = layouter.layout( - markerText, - _getMarkerFont(marker, item)!, - _getMarkerFormat(marker, item), - width: size.width, - height: size.height, - ); - posX += markerResult.size.width; - pageResult.markerWidth = markerResult.size.width; - markerHeight = markerResult.size.height; - canDrawMarker = true; - } else { - markerResult = _createMarkerResult(index, curList, info, item); - - if (markerResult != null) { - if (curList is PdfOrderedList) { - posX += markerMaxWidth!; - pageResult.markerWidth = markerMaxWidth as double?; - } else { - posX += markerResult.size.width; - pageResult.markerWidth = markerResult.size.width; - } - markerHeight = markerResult.size.height; - - if (currentPage != null) { - canDrawMarker = markerHeight < size.height; - } - - if (markerResult.isEmpty) { - canDrawMarker = false; - } - } else { - posX += - PdfUnorderedMarkerHelper.getHelper( - marker as PdfUnorderedMarker, - ).size!.width; - pageResult.markerWidth = - PdfUnorderedMarkerHelper.getHelper(marker).size!.width; - markerHeight = PdfUnorderedMarkerHelper.getHelper(marker).size!.height; - - if (currentPage != null) { - canDrawMarker = markerHeight < size.height; - } - } - } - - if (markerText == null || markerText == '') { - canDrawMarker = true; - } - - if ((text != null) && canDrawMarker) { - itemSize = PdfSize(size.width, size.height); - itemSize.width = itemSize.width - pageResult.markerWidth!; - - if (item.textIndent == 0) { - itemSize.width = itemSize.width - textIndent; - } else { - itemSize.width = itemSize.width - item.textIndent; - } - - if (((itemSize.width <= 0) || (itemSize.width < itemFont!.size)) && - currentPage != null) { - throw Exception( - 'There is not enough space to layout the item text. Marker is too long or there is no enough space to draw it.', - ); - } - - double itemX = posX; - - if (!PdfMarkerHelper.getHelper(marker).rightToLeft) { - if (item.textIndent == 0) { - itemX += textIndent; - } else { - itemX += item.textIndent; - } - } else { - itemX -= pageResult.markerWidth!; - - if (itemFormat != null && - (itemFormat.alignment == PdfTextAlignment.right || - itemFormat.alignment == PdfTextAlignment.center)) { - itemX -= indent; - } - } - - if (currentPage == null) { - if (itemFormat != null) { - itemFormat.alignment = PdfTextAlignment.left; - } - } - - result = layouter.layout( - text, - itemFont!, - itemFormat, - width: itemSize.width, - height: itemSize.height, - ); - final PdfRectangle rect = PdfRectangle( - itemX, - posY, - itemSize.width, - itemSize.height, - ); - PdfGraphicsHelper.getHelper(graphics!).drawStringLayoutResult( - result, - itemFont, - itemPen, - itemBrush, - rect, - itemFormat, - ); - y = posY; - itemHeight = result.size.height; - } - height = (itemHeight < markerHeight) ? markerHeight : itemHeight; - final bool isRemainder = - (result!.remainder == null) || (result.remainder == ''); - if (!isRemainder || - (markerResult != null) && !isRemainder || - !canDrawMarker) { - y = 0; - height = 0; - pageResult.itemText = result.remainder; - if (result.remainder == item.text) { - canDrawMarker = false; - } - if (markerResult != null) { - pageResult.markerText = markerResult.remainder; - } else { - pageResult.markerText = null; - } - pageResult.broken = true; - pageResult.y = 0; - bounds.y = 0; - } else { - pageResult.broken = false; - } - - pageResult.markerX = posX; - if (itemFormat != null) { - switch (itemFormat.alignment) { - case PdfTextAlignment.right: - pageResult.markerX = posX + itemSize.width - result.size.width; - break; - case PdfTextAlignment.center: - pageResult.markerX = - posX + (itemSize.width / 2) - (result.size.width / 2); - break; - case PdfTextAlignment.left: - case PdfTextAlignment.justify: - break; - } - } - - if (PdfMarkerHelper.getHelper(marker).rightToLeft) { - pageResult.markerX += result.size.width; - - if (item.textIndent == 0) { - pageResult.markerX += textIndent; - } else { - pageResult.markerX += item.textIndent; - } - - if (itemFormat != null && - (itemFormat.alignment == PdfTextAlignment.right || - itemFormat.alignment == PdfTextAlignment.center)) { - pageResult.markerX -= indent; - } - } - - if ((marker is PdfUnorderedMarker) && - marker.style == PdfUnorderedMarkerStyle.customString) { - if (markerResult != null) { - wroteMaker = _drawMarker( - curList, - item, - markerResult, - posY, - pageResult.markerX, - ); - pageResult.markerWrote = true; - pageResult.markerWidth = markerResult.size.width; - } - } else { - if (canDrawMarker && !pageResult.markerWrote) { - wroteMaker = _drawMarker( - curList, - item, - markerResult, - posY, - pageResult.markerX, - ); - pageResult.markerWrote = wroteMaker; - - if (curList is PdfOrderedList) { - pageResult.markerWidth = markerResult!.size.width; - } else { - pageResult.markerWidth = - PdfUnorderedMarkerHelper.getHelper( - marker as PdfUnorderedMarker, - ).size!.width; - } - } - } - return { - 'pageResult': pageResult, - 'height': height, - 'y': y, - }; - } - - /// Sets the current parameters. - void _setCurrentParameters(dynamic value) { - if (value.brush != null) { - currentBrush = value.brush as PdfBrush?; - } - if (value.pen != null) { - currentPen = value.pen as PdfPen?; - } - if (value.font != null) { - currentFont = value.font as PdfFont?; - } - if (value.stringFormat != null) { - currentFormat = value.stringFormat as PdfStringFormat?; - } - } - - /// Gets the width of the marker max. - double? _getMarkerMaxWidth(PdfOrderedList list, List info) { - double? width = -1; - - for (int i = 0; i < list.items.count; i++) { - final PdfStringLayoutResult result = _createOrderedMarkerResult( - list, - list.items[i], - i + list.marker.startNumber, - info, - true, - ); - - if (width! < result.size.width) { - width = result.size.width; - } - } - return width; - } - - /// Creates the ordered marker result. - PdfStringLayoutResult _createOrderedMarkerResult( - PdfList list, - PdfListItem? item, - int index, - List info, - bool findMaxWidth, - ) { - PdfOrderedList orderedList = list as PdfOrderedList; - PdfOrderedMarker marker = orderedList.marker; - PdfOrderedMarkerHelper.getHelper(marker).currentIndex = index; - - String text = ''; - - if (orderedList.marker.style != PdfNumberStyle.none) { - text = - PdfOrderedMarkerHelper.getHelper(orderedList.marker).getNumber() + - orderedList.marker.suffix; - } - if (orderedList.markerHierarchy) { - final List listInfos = info; - for (int i = listInfos.length - 1; i >= 0; i--) { - final ListInfo listInfo = listInfos[i]; - if (listInfo.list is PdfUnorderedList) { - break; - } - orderedList = listInfo.list! as PdfOrderedList; - if (orderedList.marker.style == PdfNumberStyle.none) { - break; - } - marker = orderedList.marker; - text = listInfo.number + marker.delimiter + text; - if (!orderedList.markerHierarchy) { - break; - } - } - } - final PdfStringLayouter layouter = PdfStringLayouter(); - orderedList = list; - marker = orderedList.marker; - final PdfFont markerFont = _getMarkerFont(marker, item)!; - PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); - final PdfSize markerSize = PdfSize(size.width, size.height); - if (!findMaxWidth) { - markerSize.width = markerMaxWidth! as double; - markerFormat = _setMarkerStringFormat(marker, markerFormat); - } - final PdfStringLayoutResult result = layouter.layout( - text, - markerFont, - markerFormat, - width: markerSize.width, - height: markerSize.height, - ); - return result; - } - - /// Gets the markers font. - PdfFont? _getMarkerFont(PdfMarker marker, PdfListItem? item) { - PdfFont? markerFont = marker.font; - if (marker.font == null) { - markerFont = item!.font; - if (item.font == null) { - markerFont = currentFont; - } - } - marker.font = markerFont; - return markerFont; - } - - /// Gets the marker format. - PdfStringFormat? _getMarkerFormat(PdfMarker marker, PdfListItem? item) { - PdfStringFormat? markerFormat = marker.stringFormat; - if (marker.stringFormat == null) { - markerFormat = item!.stringFormat; - if (item.stringFormat == null) { - markerFormat = currentFormat; - } - } - return markerFormat; - } - - /// Sets the marker alingment. - PdfStringFormat _setMarkerStringFormat( - PdfOrderedMarker marker, - PdfStringFormat? markerFormat, - ) { - markerFormat = - markerFormat == null - ? PdfStringFormat() - : _markerFormatClone(markerFormat); - if (marker.stringFormat == null) { - markerFormat.alignment = PdfTextAlignment.right; - if (PdfMarkerHelper.getHelper(marker).rightToLeft) { - markerFormat.alignment = PdfTextAlignment.left; - } - } - if (currentPage == null) { - markerFormat.alignment = PdfTextAlignment.left; - } - return markerFormat; - } - - PdfStringFormat _markerFormatClone(PdfStringFormat format) { - final PdfStringFormat markerFormat = PdfStringFormat( - alignment: format.alignment, - lineAlignment: format.lineAlignment, - ); - markerFormat.lineSpacing = format.lineSpacing; - markerFormat.characterSpacing = format.characterSpacing; - markerFormat.clipPath = format.clipPath; - markerFormat.lineLimit = format.lineLimit; - markerFormat.measureTrailingSpaces = format.measureTrailingSpaces; - markerFormat.noClip = format.noClip; - markerFormat.paragraphIndent = format.paragraphIndent; - markerFormat.subSuperscript = format.subSuperscript; - markerFormat.textDirection = format.textDirection; - markerFormat.wordSpacing = format.wordSpacing; - markerFormat.wordWrap = format.wordWrap; - PdfStringFormatHelper.getHelper(markerFormat).firstLineIndent = - PdfStringFormatHelper.getHelper(format).firstLineIndent; - return markerFormat; - } - - /// Before the page layout. - bool _beforePageLayout( - Rect currentBounds, - PdfPage? currentPage, - PdfList list, - ) { - bool cancel = false; - if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout && - currentPage != null) { - final ListBeginPageLayoutArgs args = ListBeginPageLayoutArgs._( - currentBounds, - currentPage, - list, - ); - - PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); - cancel = args.cancel; - bounds = PdfRectangle.fromRect(args.bounds); - usePaginateBounds = false; - } - return cancel; - } - - /// After the page layouted. - ListEndPageLayoutArgs? _afterPageLayouted( - Rect bounds, - PdfPage? currentPage, - PdfList list, - ) { - ListEndPageLayoutArgs? args; - if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted && - currentPage != null) { - final PdfLayoutResult result = PdfLayoutResultHelper.load( - currentPage, - bounds, - ); - args = ListEndPageLayoutArgs._internal(result, list); - PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); - } - return args; - } - - /// Before the item layout. - void _beforeItemLayout(PdfListItem item, PdfPage page) { - final BeginItemLayoutArgs args = BeginItemLayoutArgsHelper.internal( - item, - page, - ); - PdfListHelper.getHelper(element!).onBeginItemLayout(args); - } - - /// Afters the item layouted. - void _afterItemLayouted(PdfListItem item, PdfPage page) { - final EndItemLayoutArgs args = EndItemLayoutArgsHelper.internal(item, page); - PdfListHelper.getHelper(element!).onEndItemLayout(args); - } - - /// Draws the marker. - bool _drawMarker( - PdfList curList, - PdfListItem item, - PdfStringLayoutResult? markerResult, - double posY, - double posX, - ) { - if (curList is PdfOrderedList) { - if (markerResult != null) { - if (curList.font != null && - curList.font!.size > markerResult.size.height) { - posY += (curList.font!.size / 2) - (markerResult.size.height / 2); - markerResult.size.height = markerResult.size.height + posY; - } - } - _drawOrderedMarker(curList, markerResult!, item, posX, posY); - } else if (curList is PdfUnorderedList) { - if (curList.marker.font != null && markerResult != null) { - final PdfFont font = - curList.font != null && - curList.font!.size > curList.marker.font!.size - ? curList.font! - : curList.marker.font!; - if (font.size > markerResult.size.height) { - posY += (font.height / 2) - (markerResult.size.height / 2); - markerResult.size.height = markerResult.size.height + posY; - } - } - _drawUnorderedMarker(curList, markerResult, item, posX, posY); - } - return true; - } - - /// Draws the ordered marker. - PdfStringLayoutResult _drawOrderedMarker( - PdfList curList, - PdfStringLayoutResult markerResult, - PdfListItem item, - double posX, - double posY, - ) { - final PdfOrderedList oList = curList as PdfOrderedList; - final PdfOrderedMarker marker = oList.marker; - final PdfFont markerFont = _getMarkerFont(marker, item)!; - PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); - final PdfPen? markerPen = _getMarkerPen(marker, item); - final PdfBrush? markerBrush = _getMarkerBrush(marker, item); - final PdfRectangle rect = PdfRectangle( - posX - markerMaxWidth!, - posY, - markerResult.size.width, - markerResult.size.height, - ); - rect.width = markerMaxWidth! as double; - markerFormat = _setMarkerStringFormat(marker, markerFormat); - PdfGraphicsHelper.getHelper(graphics!).drawStringLayoutResult( - markerResult, - markerFont, - markerPen, - markerBrush, - rect, - markerFormat, - ); - return markerResult; - } - - /// Draws the unordered marker. - PdfStringLayoutResult? _drawUnorderedMarker( - PdfList curList, - PdfStringLayoutResult? markerResult, - PdfListItem item, - double posX, - double posY, - ) { - final PdfUnorderedList uList = curList as PdfUnorderedList; - final PdfUnorderedMarker marker = uList.marker; - final PdfFont? markerFont = _getMarkerFont(marker, item); - final PdfPen? markerPen = _getMarkerPen(marker, item); - final PdfBrush? markerBrush = _getMarkerBrush(marker, item); - final PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); - if (markerResult != null) { - final PdfPoint location = PdfPoint(posX - markerResult.size.width, posY); - PdfUnorderedMarkerHelper.getHelper(marker).size = markerResult.size; - if (marker.style == PdfUnorderedMarkerStyle.customString) { - final PdfRectangle rect = PdfRectangle( - location.x, - location.y, - markerResult.size.width, - markerResult.size.height, - ); - PdfGraphicsHelper.getHelper(graphics!).drawStringLayoutResult( - markerResult, - markerFont!, - markerPen, - markerBrush, - rect, - markerFormat, - ); - } else { - PdfUnorderedMarkerHelper.getHelper(marker).unicodeFont = - PdfStandardFont(PdfFontFamily.zapfDingbats, markerFont!.size); - PdfUnorderedMarkerHelper.getHelper( - marker, - ).draw(graphics, location.offset, markerBrush, markerPen); - } - } else { - PdfUnorderedMarkerHelper.getHelper(marker).size = PdfSize( - markerFont!.size, - markerFont.size, - ); - final PdfPoint location = PdfPoint(posX - markerFont.size, posY); - PdfUnorderedMarkerHelper.getHelper( - marker, - ).draw(graphics, location.offset, markerBrush, markerPen, curList); - } - return null; - } - - /// Gets the marker pen. - PdfPen? _getMarkerPen(PdfMarker marker, PdfListItem item) { - PdfPen? markerPen = marker.pen; - if (marker.pen == null) { - markerPen = item.pen; - if (item.pen == null) { - markerPen = currentPen; - } - } - return markerPen; - } - - /// Gets the marker brush. - PdfBrush? _getMarkerBrush(PdfMarker marker, PdfListItem item) { - PdfBrush? markerBrush = marker.brush; - if (marker.brush == null) { - markerBrush = item.brush; - if (item.brush == null) { - markerBrush = currentBrush; - } - } - return markerBrush; - } - - /// Creates the marker result. - PdfStringLayoutResult? _createMarkerResult( - int index, - PdfList curList, - List listInfo, - PdfListItem item, - ) { - PdfStringLayoutResult? markerResult; - if (curList is PdfOrderedList) { - markerResult = _createOrderedMarkerResult( - curList, - item, - index, - info, - false, - ); - } else { - final PdfSize markerSize = PdfSize.empty; - markerResult = _createUnorderedMarkerResult(curList, item, markerSize); - } - return markerResult; - } - - /// Creates the unordered marker result. - PdfStringLayoutResult? _createUnorderedMarkerResult( - PdfList curList, - PdfListItem item, - PdfSize markerSize, - ) { - final PdfUnorderedMarker marker = (curList as PdfUnorderedList).marker; - PdfStringLayoutResult? result; - final PdfFont? markerFont = _getMarkerFont(marker, item); - final PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); - final PdfStringLayouter layouter = PdfStringLayouter(); - switch (marker.style) { - case PdfUnorderedMarkerStyle.customImage: - // markerSize = PdfSize(markerFont.size, markerFont.size); - // marker._size = markerSize; - break; - case PdfUnorderedMarkerStyle.customTemplate: - markerSize = PdfSize(markerFont!.size, markerFont.size); - PdfUnorderedMarkerHelper.getHelper(marker).size = markerSize; - break; - case PdfUnorderedMarkerStyle.customString: - result = layouter.layout( - marker.text!, - markerFont!, - markerFormat, - width: size.width, - height: size.height, - ); - break; - // ignore: no_default_cases - default: - final PdfStandardFont uFont = PdfStandardFont( - PdfFontFamily.zapfDingbats, - markerFont!.size, - ); - result = layouter.layout( - PdfUnorderedMarkerHelper.getHelper(marker).getStyledText(), - uFont, - null, - width: size.width, - height: size.height, - ); - PdfUnorderedMarkerHelper.getHelper(marker).size = result.size; - if (marker.pen != null) { - result.size = PdfSize( - result.size.width + 2 * marker.pen!.width, - result.size.height + 2 * marker.pen!.width, - ); - } - break; - } - return result; - } -} - -/// Represents Page Layout result. -class _PageLayoutResult { - /// If true item finished layout on page. - bool broken = false; - - /// Y-ordinate of broken item of marker. - double? y = 0; - - /// Text of item that was not draw. - String? itemText; - - /// Text of marker that was not draw. - String? markerText; - - /// If true marker start draw. - bool markerWrote = false; - - /// Width of marker. - double? markerWidth = 0; - - /// X-coordinate of marker. - double markerX = 0; -} - -/// Represents information about list. -class ListInfo { - /// Initializes a new instance of the [ListInfo] class. - ListInfo(this.list, this.index, [this.number = '']); - - /// Index of list. - int index; - - /// Represents list. - PdfList? list; - - /// The number of item at specified index. - String number; - - /// Lists brush. - PdfBrush? brush; - - /// Lists pen. - PdfPen? pen; - - /// Lists font. - PdfFont? font; - - /// Lists format. - PdfStringFormat? format; - - /// Marker width; - double? markerWidth; -} - -/// Represents begin page layout event arguments. -class ListBeginPageLayoutArgs extends BeginPageLayoutArgs { - /// Initializes a new instance of the [ListBeginPageLayoutArgs] class. - ListBeginPageLayoutArgs._(super.bounds, super.page, this.list); - - /// Gets the ended layout - late PdfList list; -} - -// ignore: avoid_classes_with_only_static_members -/// [ListBeginPageLayoutArgs] helper -class ListBeginPageLayoutArgsHelper { - /// internal method - static ListBeginPageLayoutArgs internal( - Rect bounds, - PdfPage page, - PdfList list, - ) { - return ListBeginPageLayoutArgs._(bounds, page, list); - } -} - -/// Represents begin page layout event arguments. -class ListEndPageLayoutArgs extends EndPageLayoutArgs { - /// Initializes a new instance of the [ListEndPageLayoutArgs] class. - ListEndPageLayoutArgs._internal(super.result, this.list); - - /// Gets the ended layout - PdfList list; -} - -// ignore: avoid_classes_with_only_static_members -/// [ListEndPageLayoutArgs] helper -class ListEndPageLayoutArgsHelper { - /// internal method - static ListEndPageLayoutArgs internal(PdfLayoutResult result, PdfList list) { - return ListEndPageLayoutArgs._internal(result, list); - } -} +import 'dart:ui'; + +import '../../drawing/drawing.dart'; +import '../../graphics/brushes/pdf_brush.dart'; +import '../../graphics/brushes/pdf_solid_brush.dart'; +import '../../graphics/enums.dart'; +import '../../graphics/figures/base/element_layouter.dart'; +import '../../graphics/figures/base/layout_element.dart'; +import '../../graphics/figures/base/text_layouter.dart'; +import '../../graphics/figures/enums.dart'; +import '../../graphics/fonts/enums.dart'; +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_standard_font.dart'; +import '../../graphics/fonts/pdf_string_format.dart'; +import '../../graphics/fonts/pdf_string_layout_result.dart'; +import '../../graphics/fonts/pdf_string_layouter.dart'; +import '../../graphics/pdf_graphics.dart'; +import '../../graphics/pdf_pen.dart'; +import '../../pages/enum.dart'; +import '../../pages/pdf_page.dart'; +import 'bullets/enums.dart'; +import 'bullets/pdf_marker.dart'; +import 'bullets/pdf_ordered_marker.dart'; +import 'bullets/pdf_unordered_marker.dart'; +import 'pdf_list.dart'; +import 'pdf_list_item.dart'; +import 'pdf_ordered_list.dart'; +import 'pdf_unordered_list.dart'; + +/// Layouts list. +class PdfListLayouter extends ElementLayouter { + /// Initializes a new instance of the [PdfListLayouter] class. + PdfListLayouter(PdfList super.element); + + /// Current graphics for lay outing. + PdfGraphics? graphics; + + /// Indicates end of lay outing. + bool finish = false; + + /// List that layouts at the moment. + PdfList? curList; + + /// List that contains ListInfo. + List info = []; + + /// Index of item that lay outing. + int index = 0; + + /// The indent of current list. + double? indent; + + /// Height in which it stop lay outing. + double? resultHeight; + + /// Lay outing bounds. + late PdfRectangle bounds; + + /// Current page for layout. + PdfPage? currentPage; + + /// PdfSize for item lay outing. + PdfSize size = PdfSize.empty; + + /// If true it use paginate bounds if it is set. + bool usePaginateBounds = true; + + /// Current brush for lay outing. + PdfBrush? currentBrush; + + /// Current pen for layout. + PdfPen? currentPen; + + /// Current font for layout. + PdfFont? currentFont; + + /// Current string format. + PdfStringFormat? currentFormat; + + /// Marker maximum width. + num? markerMaxWidth; + @override + PdfList? get element => super.element as PdfList?; + + @override + PdfLayoutResult? layoutInternal(PdfLayoutParams param) { + currentPage = param.page; + bounds = param.bounds!.clone(); + if (param.bounds!.height == 0 && + param.bounds!.width == 0 && + currentPage != null) { + bounds.width = currentPage!.getClientSize().width; + bounds.height = currentPage!.getClientSize().height; + bounds.width = bounds.width - bounds.x; + bounds.height = bounds.height - bounds.y; + } + + if (currentPage != null) { + graphics = currentPage!.graphics; + } + + _PageLayoutResult pageResult = _PageLayoutResult(); + pageResult.broken = false; + pageResult.y = bounds.y; + curList = element; + indent = element!.indent; + + _setCurrentParameters(element); + + if (element!.brush == null) { + currentBrush = PdfBrushes.black; + } + + if (element!.font == null) { + currentFont = PdfStandardFont(PdfFontFamily.helvetica, 8); + curList!.font = currentFont; + } + + if (curList is PdfOrderedList) { + markerMaxWidth = _getMarkerMaxWidth(curList! as PdfOrderedList, info); + } + + final bool useOnePage = param.format!.layoutType == PdfLayoutType.onePage; + + while (!finish) { + bool cancel = _beforePageLayout(bounds.rect, currentPage, curList!); + pageResult.y = bounds.y; + ListEndPageLayoutArgs? endArgs; + if (!cancel) { + pageResult = _layoutOnPage(pageResult)!; + endArgs = _afterPageLayouted(bounds.rect, currentPage, curList!); + cancel = endArgs != null && endArgs.cancel; + } + if (useOnePage || cancel) { + break; + } + if (currentPage != null && !finish) { + if ((endArgs != null) && (endArgs.nextPage != null)) { + currentPage = endArgs.nextPage; + } else { + currentPage = getNextPage(currentPage!); + } + graphics = currentPage!.graphics; + if (param.bounds!.width == 0 && param.bounds!.height == 0) { + bounds.width = currentPage!.getClientSize().width; + bounds.height = currentPage!.getClientSize().height; + bounds.width = bounds.width - bounds.x; + bounds.height = bounds.height - bounds.y; + } + if ((param.format != null) && + PdfLayoutFormatHelper.isBoundsSet(param.format!) && + usePaginateBounds) { + bounds = PdfRectangle.fromRect(param.format!.paginateBounds); + } + } + } + info.clear(); + final Rect finalBounds = Rect.fromLTWH( + bounds.x, + pageResult.y!, + bounds.width, + resultHeight ?? 0, + ); + if (currentPage != null) { + final PdfLayoutResult result = PdfLayoutResultHelper.load( + currentPage!, + finalBounds, + ); + return result; + } else { + return null; + } + } + + /// Layouts the on the page. + _PageLayoutResult? _layoutOnPage(_PageLayoutResult? pageResult) { + double? height = 0; + double resultantHeight = 0; + double? y = bounds.y; + final double x = bounds.x; + size = PdfSize(bounds.size.width, bounds.size.height); + size.width = size.width - indent!; + + while (true) { + for (; index < curList!.items.count; ++index) { + final PdfListItem item = curList!.items[index]; + + if (currentPage != null && !pageResult!.broken) { + _beforeItemLayout(item, currentPage!); + } + final Map returnedValue = _drawItem( + pageResult!, + x, + curList!, + index, + indent!, + info, + item, + height!, + y!, + ); + pageResult = returnedValue['pageResult'] as _PageLayoutResult?; + height = returnedValue['height'] as double?; + y = returnedValue['y'] as double?; + resultantHeight += height!; + if (pageResult!.broken) { + return pageResult; + } + + if (currentPage != null) { + _afterItemLayouted(item, currentPage!); + } + pageResult.markerWrote = false; + + if (item.subList != null && item.subList!.items.count > 0) { + if (curList is PdfOrderedList) { + final PdfOrderedList oList = curList! as PdfOrderedList; + PdfOrderedMarkerHelper.getHelper(oList.marker).currentIndex = index; + final ListInfo listInfo = ListInfo( + curList, + index, + PdfOrderedMarkerHelper.getHelper(oList.marker).getNumber(), + ); + listInfo.brush = currentBrush; + listInfo.font = currentFont; + listInfo.format = currentFormat; + listInfo.pen = currentPen; + listInfo.markerWidth = markerMaxWidth as double?; + info.add(listInfo); + } else { + final ListInfo listInfo = ListInfo(curList, index); + listInfo.brush = currentBrush; + listInfo.font = currentFont; + listInfo.format = currentFormat; + listInfo.pen = currentPen; + info.add(listInfo); + } + curList = item.subList; + if (curList is PdfOrderedList) { + markerMaxWidth = _getMarkerMaxWidth( + curList! as PdfOrderedList, + info, + ); + } + index = -1; + indent = indent! + curList!.indent; + size.width = size.width - curList!.indent; + _setCurrentParameters(item); + _setCurrentParameters(curList); + } + } + if (info.isEmpty) { + resultHeight = resultantHeight; + finish = true; + break; + } + final ListInfo listInfo = info.last; + info.remove(listInfo); + index = listInfo.index + 1; + indent = indent! - curList!.indent; + size.width = size.width + curList!.indent; + markerMaxWidth = listInfo.markerWidth; + currentBrush = listInfo.brush; + currentPen = listInfo.pen; + currentFont = listInfo.font; + currentFormat = listInfo.format; + curList = listInfo.list; + } + return pageResult; + } + + /// Draws the item. + Map _drawItem( + _PageLayoutResult pageResult, + double x, + PdfList curList, + int index, + double indent, + List listInfo, + PdfListItem item, + double height, + double y, + ) { + final PdfStringLayouter layouter = PdfStringLayouter(); + PdfStringLayoutResult? markerResult; + PdfStringLayoutResult? result; + + bool wroteMaker = false; + final double textIndent = curList.textIndent; + + final double posY = height + y; + double posX = indent + x; + + double? itemHeight = 0; + double? markerHeight = 0; + PdfSize itemSize = PdfSize(size.width, size.height); + + String? text = item.text; + String? markerText; + + PdfBrush? itemBrush = currentBrush; + + if (item.brush != null) { + itemBrush = item.brush; + } + + PdfPen? itemPen = currentPen; + + if (item.pen != null) { + itemPen = item.pen; + } + + PdfFont? itemFont = currentFont; + + if (item.font != null) { + itemFont = item.font; + } + + PdfStringFormat? itemFormat = currentFormat; + + if (item.stringFormat != null) { + itemFormat = item.stringFormat; + } + + if (((size.width <= 0) || (size.width < itemFont!.size)) && + currentPage != null) { + throw Exception('There is not enough space to layout list.'); + } + size.height = size.height - height; + + PdfMarker marker; + + if (curList is PdfUnorderedList) { + marker = curList.marker; + } else { + marker = (curList as PdfOrderedList).marker; + } + + if (pageResult.broken) { + text = pageResult.itemText; + markerText = pageResult.markerText; + } + + bool canDrawMarker = true; + + if (markerText != null && + ((marker is PdfUnorderedMarker) && + (marker.style == PdfUnorderedMarkerStyle.customString))) { + markerResult = layouter.layout( + markerText, + _getMarkerFont(marker, item)!, + _getMarkerFormat(marker, item), + width: size.width, + height: size.height, + ); + posX += markerResult.size.width; + pageResult.markerWidth = markerResult.size.width; + markerHeight = markerResult.size.height; + canDrawMarker = true; + } else { + markerResult = _createMarkerResult(index, curList, info, item); + + if (markerResult != null) { + if (curList is PdfOrderedList) { + posX += markerMaxWidth!; + pageResult.markerWidth = markerMaxWidth as double?; + } else { + posX += markerResult.size.width; + pageResult.markerWidth = markerResult.size.width; + } + markerHeight = markerResult.size.height; + + if (currentPage != null) { + canDrawMarker = markerHeight < size.height; + } + + if (markerResult.isEmpty) { + canDrawMarker = false; + } + } else { + posX += + PdfUnorderedMarkerHelper.getHelper( + marker as PdfUnorderedMarker, + ).size!.width; + pageResult.markerWidth = + PdfUnorderedMarkerHelper.getHelper(marker).size!.width; + markerHeight = PdfUnorderedMarkerHelper.getHelper(marker).size!.height; + + if (currentPage != null) { + canDrawMarker = markerHeight < size.height; + } + } + } + + if (markerText == null || markerText == '') { + canDrawMarker = true; + } + + if ((text != null) && canDrawMarker) { + itemSize = PdfSize(size.width, size.height); + itemSize.width = itemSize.width - pageResult.markerWidth!; + + if (item.textIndent == 0) { + itemSize.width = itemSize.width - textIndent; + } else { + itemSize.width = itemSize.width - item.textIndent; + } + + if (((itemSize.width <= 0) || (itemSize.width < itemFont!.size)) && + currentPage != null) { + throw Exception( + 'There is not enough space to layout the item text. Marker is too long or there is no enough space to draw it.', + ); + } + + double itemX = posX; + + if (!PdfMarkerHelper.getHelper(marker).rightToLeft) { + if (item.textIndent == 0) { + itemX += textIndent; + } else { + itemX += item.textIndent; + } + } else { + itemX -= pageResult.markerWidth!; + + if (itemFormat != null && + (itemFormat.alignment == PdfTextAlignment.right || + itemFormat.alignment == PdfTextAlignment.center)) { + itemX -= indent; + } + } + + if (currentPage == null) { + if (itemFormat != null) { + itemFormat.alignment = PdfTextAlignment.left; + } + } + + result = layouter.layout( + text, + itemFont!, + itemFormat, + width: itemSize.width, + height: itemSize.height, + ); + final PdfRectangle rect = PdfRectangle( + itemX, + posY, + itemSize.width, + itemSize.height, + ); + PdfGraphicsHelper.getHelper(graphics!).drawStringLayoutResult( + result, + itemFont, + itemPen, + itemBrush, + rect, + itemFormat, + ); + y = posY; + itemHeight = result.size.height; + } + height = (itemHeight < markerHeight) ? markerHeight : itemHeight; + final bool isRemainder = + (result!.remainder == null) || (result.remainder == ''); + if (!isRemainder || + (markerResult != null) && !isRemainder || + !canDrawMarker) { + y = 0; + height = 0; + pageResult.itemText = result.remainder; + if (result.remainder == item.text) { + canDrawMarker = false; + } + if (markerResult != null) { + pageResult.markerText = markerResult.remainder; + } else { + pageResult.markerText = null; + } + pageResult.broken = true; + pageResult.y = 0; + bounds.y = 0; + } else { + pageResult.broken = false; + } + + pageResult.markerX = posX; + if (itemFormat != null) { + switch (itemFormat.alignment) { + case PdfTextAlignment.right: + pageResult.markerX = posX + itemSize.width - result.size.width; + break; + case PdfTextAlignment.center: + pageResult.markerX = + posX + (itemSize.width / 2) - (result.size.width / 2); + break; + case PdfTextAlignment.left: + case PdfTextAlignment.justify: + break; + } + } + + if (PdfMarkerHelper.getHelper(marker).rightToLeft) { + pageResult.markerX += result.size.width; + + if (item.textIndent == 0) { + pageResult.markerX += textIndent; + } else { + pageResult.markerX += item.textIndent; + } + + if (itemFormat != null && + (itemFormat.alignment == PdfTextAlignment.right || + itemFormat.alignment == PdfTextAlignment.center)) { + pageResult.markerX -= indent; + } + } + + if ((marker is PdfUnorderedMarker) && + marker.style == PdfUnorderedMarkerStyle.customString) { + if (markerResult != null) { + wroteMaker = _drawMarker( + curList, + item, + markerResult, + posY, + pageResult.markerX, + ); + pageResult.markerWrote = true; + pageResult.markerWidth = markerResult.size.width; + } + } else { + if (canDrawMarker && !pageResult.markerWrote) { + wroteMaker = _drawMarker( + curList, + item, + markerResult, + posY, + pageResult.markerX, + ); + pageResult.markerWrote = wroteMaker; + + if (curList is PdfOrderedList) { + pageResult.markerWidth = markerResult!.size.width; + } else { + pageResult.markerWidth = + PdfUnorderedMarkerHelper.getHelper( + marker as PdfUnorderedMarker, + ).size!.width; + } + } + } + return { + 'pageResult': pageResult, + 'height': height, + 'y': y, + }; + } + + /// Sets the current parameters. + void _setCurrentParameters(dynamic value) { + if (value.brush != null) { + currentBrush = value.brush as PdfBrush?; + } + if (value.pen != null) { + currentPen = value.pen as PdfPen?; + } + if (value.font != null) { + currentFont = value.font as PdfFont?; + } + if (value.stringFormat != null) { + currentFormat = value.stringFormat as PdfStringFormat?; + } + } + + /// Gets the width of the marker max. + double? _getMarkerMaxWidth(PdfOrderedList list, List info) { + double? width = -1; + + for (int i = 0; i < list.items.count; i++) { + final PdfStringLayoutResult result = _createOrderedMarkerResult( + list, + list.items[i], + i + list.marker.startNumber, + info, + true, + ); + + if (width! < result.size.width) { + width = result.size.width; + } + } + return width; + } + + /// Creates the ordered marker result. + PdfStringLayoutResult _createOrderedMarkerResult( + PdfList list, + PdfListItem? item, + int index, + List info, + bool findMaxWidth, + ) { + PdfOrderedList orderedList = list as PdfOrderedList; + PdfOrderedMarker marker = orderedList.marker; + PdfOrderedMarkerHelper.getHelper(marker).currentIndex = index; + + String text = ''; + + if (orderedList.marker.style != PdfNumberStyle.none) { + text = + PdfOrderedMarkerHelper.getHelper(orderedList.marker).getNumber() + + orderedList.marker.suffix; + } + if (orderedList.markerHierarchy) { + final List listInfos = info; + for (int i = listInfos.length - 1; i >= 0; i--) { + final ListInfo listInfo = listInfos[i]; + if (listInfo.list is PdfUnorderedList) { + break; + } + orderedList = listInfo.list! as PdfOrderedList; + if (orderedList.marker.style == PdfNumberStyle.none) { + break; + } + marker = orderedList.marker; + text = listInfo.number + marker.delimiter + text; + if (!orderedList.markerHierarchy) { + break; + } + } + } + final PdfStringLayouter layouter = PdfStringLayouter(); + orderedList = list; + marker = orderedList.marker; + final PdfFont markerFont = _getMarkerFont(marker, item)!; + PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); + final PdfSize markerSize = PdfSize(size.width, size.height); + if (!findMaxWidth) { + markerSize.width = markerMaxWidth! as double; + markerFormat = _setMarkerStringFormat(marker, markerFormat); + } + final PdfStringLayoutResult result = layouter.layout( + text, + markerFont, + markerFormat, + width: markerSize.width, + height: markerSize.height, + ); + return result; + } + + /// Gets the markers font. + PdfFont? _getMarkerFont(PdfMarker marker, PdfListItem? item) { + PdfFont? markerFont = marker.font; + if (marker.font == null) { + markerFont = item!.font; + if (item.font == null) { + markerFont = currentFont; + } + } + marker.font = markerFont; + return markerFont; + } + + /// Gets the marker format. + PdfStringFormat? _getMarkerFormat(PdfMarker marker, PdfListItem? item) { + PdfStringFormat? markerFormat = marker.stringFormat; + if (marker.stringFormat == null) { + markerFormat = item!.stringFormat; + if (item.stringFormat == null) { + markerFormat = currentFormat; + } + } + return markerFormat; + } + + /// Sets the marker alingment. + PdfStringFormat _setMarkerStringFormat( + PdfOrderedMarker marker, + PdfStringFormat? markerFormat, + ) { + markerFormat = + markerFormat == null + ? PdfStringFormat() + : _markerFormatClone(markerFormat); + if (marker.stringFormat == null) { + markerFormat.alignment = PdfTextAlignment.right; + if (PdfMarkerHelper.getHelper(marker).rightToLeft) { + markerFormat.alignment = PdfTextAlignment.left; + } + } + if (currentPage == null) { + markerFormat.alignment = PdfTextAlignment.left; + } + return markerFormat; + } + + PdfStringFormat _markerFormatClone(PdfStringFormat format) { + final PdfStringFormat markerFormat = PdfStringFormat( + alignment: format.alignment, + lineAlignment: format.lineAlignment, + ); + markerFormat.lineSpacing = format.lineSpacing; + markerFormat.characterSpacing = format.characterSpacing; + markerFormat.clipPath = format.clipPath; + markerFormat.lineLimit = format.lineLimit; + markerFormat.measureTrailingSpaces = format.measureTrailingSpaces; + markerFormat.noClip = format.noClip; + markerFormat.paragraphIndent = format.paragraphIndent; + markerFormat.subSuperscript = format.subSuperscript; + markerFormat.textDirection = format.textDirection; + markerFormat.wordSpacing = format.wordSpacing; + markerFormat.wordWrap = format.wordWrap; + PdfStringFormatHelper.getHelper(markerFormat).firstLineIndent = + PdfStringFormatHelper.getHelper(format).firstLineIndent; + return markerFormat; + } + + /// Before the page layout. + bool _beforePageLayout( + Rect currentBounds, + PdfPage? currentPage, + PdfList list, + ) { + bool cancel = false; + if (PdfLayoutElementHelper.getHelper(element!).raiseBeginPageLayout && + currentPage != null) { + final ListBeginPageLayoutArgs args = ListBeginPageLayoutArgs._( + currentBounds, + currentPage, + list, + ); + + PdfLayoutElementHelper.getHelper(element!).onBeginPageLayout(args); + cancel = args.cancel; + bounds = PdfRectangle.fromRect(args.bounds); + usePaginateBounds = false; + } + return cancel; + } + + /// After the page layouted. + ListEndPageLayoutArgs? _afterPageLayouted( + Rect bounds, + PdfPage? currentPage, + PdfList list, + ) { + ListEndPageLayoutArgs? args; + if (PdfLayoutElementHelper.getHelper(element!).raisePageLayouted && + currentPage != null) { + final PdfLayoutResult result = PdfLayoutResultHelper.load( + currentPage, + bounds, + ); + args = ListEndPageLayoutArgs._internal(result, list); + PdfLayoutElementHelper.getHelper(element!).onEndPageLayout(args); + } + return args; + } + + /// Before the item layout. + void _beforeItemLayout(PdfListItem item, PdfPage page) { + final BeginItemLayoutArgs args = BeginItemLayoutArgsHelper.internal( + item, + page, + ); + PdfListHelper.getHelper(element!).onBeginItemLayout(args); + } + + /// Afters the item layouted. + void _afterItemLayouted(PdfListItem item, PdfPage page) { + final EndItemLayoutArgs args = EndItemLayoutArgsHelper.internal(item, page); + PdfListHelper.getHelper(element!).onEndItemLayout(args); + } + + /// Draws the marker. + bool _drawMarker( + PdfList curList, + PdfListItem item, + PdfStringLayoutResult? markerResult, + double posY, + double posX, + ) { + if (curList is PdfOrderedList) { + if (markerResult != null) { + if (curList.font != null && + curList.font!.size > markerResult.size.height) { + posY += (curList.font!.size / 2) - (markerResult.size.height / 2); + markerResult.size.height = markerResult.size.height + posY; + } + } + _drawOrderedMarker(curList, markerResult!, item, posX, posY); + } else if (curList is PdfUnorderedList) { + if (curList.marker.font != null && markerResult != null) { + final PdfFont font = + curList.font != null && + curList.font!.size > curList.marker.font!.size + ? curList.font! + : curList.marker.font!; + if (font.size > markerResult.size.height) { + posY += (font.height / 2) - (markerResult.size.height / 2); + markerResult.size.height = markerResult.size.height + posY; + } + } + _drawUnorderedMarker(curList, markerResult, item, posX, posY); + } + return true; + } + + /// Draws the ordered marker. + PdfStringLayoutResult _drawOrderedMarker( + PdfList curList, + PdfStringLayoutResult markerResult, + PdfListItem item, + double posX, + double posY, + ) { + final PdfOrderedList oList = curList as PdfOrderedList; + final PdfOrderedMarker marker = oList.marker; + final PdfFont markerFont = _getMarkerFont(marker, item)!; + PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); + final PdfPen? markerPen = _getMarkerPen(marker, item); + final PdfBrush? markerBrush = _getMarkerBrush(marker, item); + final PdfRectangle rect = PdfRectangle( + posX - markerMaxWidth!, + posY, + markerResult.size.width, + markerResult.size.height, + ); + rect.width = markerMaxWidth! as double; + markerFormat = _setMarkerStringFormat(marker, markerFormat); + PdfGraphicsHelper.getHelper(graphics!).drawStringLayoutResult( + markerResult, + markerFont, + markerPen, + markerBrush, + rect, + markerFormat, + ); + return markerResult; + } + + /// Draws the unordered marker. + PdfStringLayoutResult? _drawUnorderedMarker( + PdfList curList, + PdfStringLayoutResult? markerResult, + PdfListItem item, + double posX, + double posY, + ) { + final PdfUnorderedList uList = curList as PdfUnorderedList; + final PdfUnorderedMarker marker = uList.marker; + final PdfFont? markerFont = _getMarkerFont(marker, item); + final PdfPen? markerPen = _getMarkerPen(marker, item); + final PdfBrush? markerBrush = _getMarkerBrush(marker, item); + final PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); + if (markerResult != null) { + final PdfPoint location = PdfPoint(posX - markerResult.size.width, posY); + PdfUnorderedMarkerHelper.getHelper(marker).size = markerResult.size; + if (marker.style == PdfUnorderedMarkerStyle.customString) { + final PdfRectangle rect = PdfRectangle( + location.x, + location.y, + markerResult.size.width, + markerResult.size.height, + ); + PdfGraphicsHelper.getHelper(graphics!).drawStringLayoutResult( + markerResult, + markerFont!, + markerPen, + markerBrush, + rect, + markerFormat, + ); + } else { + PdfUnorderedMarkerHelper.getHelper(marker).unicodeFont = + PdfStandardFont(PdfFontFamily.zapfDingbats, markerFont!.size); + PdfUnorderedMarkerHelper.getHelper( + marker, + ).draw(graphics, location.offset, markerBrush, markerPen); + } + } else { + PdfUnorderedMarkerHelper.getHelper(marker).size = PdfSize( + markerFont!.size, + markerFont.size, + ); + final PdfPoint location = PdfPoint(posX - markerFont.size, posY); + PdfUnorderedMarkerHelper.getHelper( + marker, + ).draw(graphics, location.offset, markerBrush, markerPen, curList); + } + return null; + } + + /// Gets the marker pen. + PdfPen? _getMarkerPen(PdfMarker marker, PdfListItem item) { + PdfPen? markerPen = marker.pen; + if (marker.pen == null) { + markerPen = item.pen; + if (item.pen == null) { + markerPen = currentPen; + } + } + return markerPen; + } + + /// Gets the marker brush. + PdfBrush? _getMarkerBrush(PdfMarker marker, PdfListItem item) { + PdfBrush? markerBrush = marker.brush; + if (marker.brush == null) { + markerBrush = item.brush; + if (item.brush == null) { + markerBrush = currentBrush; + } + } + return markerBrush; + } + + /// Creates the marker result. + PdfStringLayoutResult? _createMarkerResult( + int index, + PdfList curList, + List listInfo, + PdfListItem item, + ) { + PdfStringLayoutResult? markerResult; + if (curList is PdfOrderedList) { + markerResult = _createOrderedMarkerResult( + curList, + item, + index, + info, + false, + ); + } else { + final PdfSize markerSize = PdfSize.empty; + markerResult = _createUnorderedMarkerResult(curList, item, markerSize); + } + return markerResult; + } + + /// Creates the unordered marker result. + PdfStringLayoutResult? _createUnorderedMarkerResult( + PdfList curList, + PdfListItem item, + PdfSize markerSize, + ) { + final PdfUnorderedMarker marker = (curList as PdfUnorderedList).marker; + PdfStringLayoutResult? result; + final PdfFont? markerFont = _getMarkerFont(marker, item); + final PdfStringFormat? markerFormat = _getMarkerFormat(marker, item); + final PdfStringLayouter layouter = PdfStringLayouter(); + switch (marker.style) { + case PdfUnorderedMarkerStyle.customImage: + // markerSize = PdfSize(markerFont.size, markerFont.size); + // marker._size = markerSize; + break; + case PdfUnorderedMarkerStyle.customTemplate: + markerSize = PdfSize(markerFont!.size, markerFont.size); + PdfUnorderedMarkerHelper.getHelper(marker).size = markerSize; + break; + case PdfUnorderedMarkerStyle.customString: + result = layouter.layout( + marker.text!, + markerFont!, + markerFormat, + width: size.width, + height: size.height, + ); + break; + // ignore: no_default_cases + default: + final PdfStandardFont uFont = PdfStandardFont( + PdfFontFamily.zapfDingbats, + markerFont!.size, + ); + result = layouter.layout( + PdfUnorderedMarkerHelper.getHelper(marker).getStyledText(), + uFont, + null, + width: size.width, + height: size.height, + ); + PdfUnorderedMarkerHelper.getHelper(marker).size = result.size; + if (marker.pen != null) { + result.size = PdfSize( + result.size.width + 2 * marker.pen!.width, + result.size.height + 2 * marker.pen!.width, + ); + } + break; + } + return result; + } +} + +/// Represents Page Layout result. +class _PageLayoutResult { + /// If true item finished layout on page. + bool broken = false; + + /// Y-ordinate of broken item of marker. + double? y = 0; + + /// Text of item that was not draw. + String? itemText; + + /// Text of marker that was not draw. + String? markerText; + + /// If true marker start draw. + bool markerWrote = false; + + /// Width of marker. + double? markerWidth = 0; + + /// X-coordinate of marker. + double markerX = 0; +} + +/// Represents information about list. +class ListInfo { + /// Initializes a new instance of the [ListInfo] class. + ListInfo(this.list, this.index, [this.number = '']); + + /// Index of list. + int index; + + /// Represents list. + PdfList? list; + + /// The number of item at specified index. + String number; + + /// Lists brush. + PdfBrush? brush; + + /// Lists pen. + PdfPen? pen; + + /// Lists font. + PdfFont? font; + + /// Lists format. + PdfStringFormat? format; + + /// Marker width; + double? markerWidth; +} + +/// Represents begin page layout event arguments. +class ListBeginPageLayoutArgs extends BeginPageLayoutArgs { + /// Initializes a new instance of the [ListBeginPageLayoutArgs] class. + ListBeginPageLayoutArgs._(super.bounds, super.page, this.list); + + /// Gets the ended layout + late PdfList list; +} + +// ignore: avoid_classes_with_only_static_members +/// [ListBeginPageLayoutArgs] helper +class ListBeginPageLayoutArgsHelper { + /// internal method + static ListBeginPageLayoutArgs internal( + Rect bounds, + PdfPage page, + PdfList list, + ) { + return ListBeginPageLayoutArgs._(bounds, page, list); + } +} + +/// Represents begin page layout event arguments. +class ListEndPageLayoutArgs extends EndPageLayoutArgs { + /// Initializes a new instance of the [ListEndPageLayoutArgs] class. + ListEndPageLayoutArgs._internal(super.result, this.list); + + /// Gets the ended layout + PdfList list; +} + +// ignore: avoid_classes_with_only_static_members +/// [ListEndPageLayoutArgs] helper +class ListEndPageLayoutArgsHelper { + /// internal method + static ListEndPageLayoutArgs internal(PdfLayoutResult result, PdfList list) { + return ListEndPageLayoutArgs._internal(result, list); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_ordered_list.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_ordered_list.dart index 4cecb78fb..58bcfbfb7 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_ordered_list.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_ordered_list.dart @@ -1,134 +1,134 @@ -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_string_format.dart'; -import '../../pages/enum.dart'; -import 'bullets/pdf_ordered_marker.dart'; -import 'pdf_list.dart'; -import 'pdf_list_item_collection.dart'; - -/// Represents the ordered list. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new ordered list. -/// PdfOrderedList( -/// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// format: PdfStringFormat(lineSpacing: 20), -/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), -/// style: PdfNumberStyle.numeric, -/// indent: 15, -/// textIndent: 10) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfOrderedList extends PdfList { - //Constructor - /// Initialize a new instance of the [PdfOrderedList] class. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfOrderedList({ - PdfOrderedMarker? marker, - PdfListItemCollection? items, - String? text, - PdfFont? font, - PdfNumberStyle style = PdfNumberStyle.numeric, - PdfStringFormat? format, - this.markerHierarchy = false, - double indent = 10, - double textIndent = 5, - }) : super() { - final PdfListHelper helper = PdfListHelper(this); - this.marker = marker ?? _createMarker(style); - stringFormat = format; - super.indent = indent; - super.textIndent = textIndent; - if (font != null) { - helper.font = font; - } - if (items != null) { - helper.items = items; - } else if (text != null) { - helper.items = PdfListHelper.createItems(text); - } - } - - /// True if user want to use numbering hierarchy, otherwise false. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic)) - /// .items[0] - /// .subList = - /// PdfOrderedList( - /// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']) - /// markerHierarchy: true) - /// ..draw( - /// page: document.pages.add(), - /// bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - bool markerHierarchy; - - /// Gets or sets marker of the list items. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new ordered list. - /// PdfOrderedList( - /// text: 'PDF\nXlsIO\nDocIO\nPPT', - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// format: PdfStringFormat(lineSpacing: 20), - /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), - /// style: PdfNumberStyle.numeric, - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late PdfOrderedMarker marker; - - //Static methods. - //Creates the marker. - static PdfOrderedMarker _createMarker(PdfNumberStyle style) { - return PdfOrderedMarker(style: style); - } -} +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_string_format.dart'; +import '../../pages/enum.dart'; +import 'bullets/pdf_ordered_marker.dart'; +import 'pdf_list.dart'; +import 'pdf_list_item_collection.dart'; + +/// Represents the ordered list. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new ordered list. +/// PdfOrderedList( +/// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// format: PdfStringFormat(lineSpacing: 20), +/// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), +/// style: PdfNumberStyle.numeric, +/// indent: 15, +/// textIndent: 10) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfOrderedList extends PdfList { + //Constructor + /// Initialize a new instance of the [PdfOrderedList] class. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfOrderedList({ + PdfOrderedMarker? marker, + PdfListItemCollection? items, + String? text, + PdfFont? font, + PdfNumberStyle style = PdfNumberStyle.numeric, + PdfStringFormat? format, + this.markerHierarchy = false, + double indent = 10, + double textIndent = 5, + }) : super() { + final PdfListHelper helper = PdfListHelper(this); + this.marker = marker ?? _createMarker(style); + stringFormat = format; + super.indent = indent; + super.textIndent = textIndent; + if (font != null) { + helper.font = font; + } + if (items != null) { + helper.items = items; + } else if (text != null) { + helper.items = PdfListHelper.createItems(text); + } + } + + /// True if user want to use numbering hierarchy, otherwise false. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic)) + /// .items[0] + /// .subList = + /// PdfOrderedList( + /// items: PdfListItemCollection(['PDF', 'XlsIO', 'DocIO', 'PPT']) + /// markerHierarchy: true) + /// ..draw( + /// page: document.pages.add(), + /// bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + bool markerHierarchy; + + /// Gets or sets marker of the list items. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new ordered list. + /// PdfOrderedList( + /// text: 'PDF\nXlsIO\nDocIO\nPPT', + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// format: PdfStringFormat(lineSpacing: 20), + /// marker: PdfOrderedMarker(style: PdfNumberStyle.numeric), + /// style: PdfNumberStyle.numeric, + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late PdfOrderedMarker marker; + + //Static methods. + //Creates the marker. + static PdfOrderedMarker _createMarker(PdfNumberStyle style) { + return PdfOrderedMarker(style: style); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_unordered_list.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_unordered_list.dart index 10643424e..e46e8eb49 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_unordered_list.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/structured_elements/lists/pdf_unordered_list.dart @@ -1,106 +1,106 @@ -import '../../graphics/fonts/pdf_font.dart'; -import '../../graphics/fonts/pdf_string_format.dart'; -import 'bullets/enums.dart'; -import 'bullets/pdf_unordered_marker.dart'; -import 'pdf_list.dart'; -import 'pdf_list_item_collection.dart'; - -/// Represents the ordered list. -/// -/// ```dart -/// //Create a new PDF document. -/// PdfDocument document = PdfDocument(); -/// //Create a new unordered list. -/// PdfUnorderedList( -/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), -/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, -/// style: PdfFontStyle.italic), -/// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk), -/// format: PdfStringFormat(lineSpacing: 20), -/// indent: 15, -/// textIndent: 10) -/// ..draw( -/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); -/// //Save the document. -/// List bytes = await document.save(); -/// //Dispose the document. -/// document.dispose(); -/// ``` -class PdfUnorderedList extends PdfList { - //Constructor - /// Initializes a new instance of the [PdfUnorderedList] class. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new unordered list. - /// PdfUnorderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk), - /// format: PdfStringFormat(lineSpacing: 20), - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - PdfUnorderedList({ - PdfUnorderedMarker? marker, - PdfListItemCollection? items, - String? text, - PdfFont? font, - PdfUnorderedMarkerStyle style = PdfUnorderedMarkerStyle.disk, - PdfStringFormat? format, - double indent = 10, - double textIndent = 5, - }) : super() { - final PdfListHelper helper = PdfListHelper(this); - this.marker = marker ?? _createMarker(style); - stringFormat = format; - super.indent = indent; - super.textIndent = textIndent; - if (font != null) { - helper.font = font; - } - if (items != null) { - helper.items = items; - } else if (text != null) { - helper.items = PdfListHelper.createItems(text); - } - } - - //Properties - /// Gets or gets the marker. - /// - /// ```dart - /// //Create a new PDF document. - /// PdfDocument document = PdfDocument(); - /// //Create a new unordered list. - /// PdfUnorderedList( - /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), - /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, - /// style: PdfFontStyle.italic), - /// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk), - /// format: PdfStringFormat(lineSpacing: 20), - /// indent: 15, - /// textIndent: 10) - /// ..draw( - /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); - /// //Save the document. - /// List bytes = await document.save(); - /// //Dispose the document. - /// document.dispose(); - /// ``` - late PdfUnorderedMarker marker; - - //Static methods - //Creates the marker. - static PdfUnorderedMarker _createMarker(PdfUnorderedMarkerStyle style) { - return PdfUnorderedMarker(style: style); - } -} +import '../../graphics/fonts/pdf_font.dart'; +import '../../graphics/fonts/pdf_string_format.dart'; +import 'bullets/enums.dart'; +import 'bullets/pdf_unordered_marker.dart'; +import 'pdf_list.dart'; +import 'pdf_list_item_collection.dart'; + +/// Represents the ordered list. +/// +/// ```dart +/// //Create a new PDF document. +/// PdfDocument document = PdfDocument(); +/// //Create a new unordered list. +/// PdfUnorderedList( +/// items: PdfListItemCollection(['Essential tools', 'Essential grid']), +/// font: PdfStandardFont(PdfFontFamily.helvetica, 16, +/// style: PdfFontStyle.italic), +/// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk), +/// format: PdfStringFormat(lineSpacing: 20), +/// indent: 15, +/// textIndent: 10) +/// ..draw( +/// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); +/// //Save the document. +/// List bytes = await document.save(); +/// //Dispose the document. +/// document.dispose(); +/// ``` +class PdfUnorderedList extends PdfList { + //Constructor + /// Initializes a new instance of the [PdfUnorderedList] class. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new unordered list. + /// PdfUnorderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk), + /// format: PdfStringFormat(lineSpacing: 20), + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + PdfUnorderedList({ + PdfUnorderedMarker? marker, + PdfListItemCollection? items, + String? text, + PdfFont? font, + PdfUnorderedMarkerStyle style = PdfUnorderedMarkerStyle.disk, + PdfStringFormat? format, + double indent = 10, + double textIndent = 5, + }) : super() { + final PdfListHelper helper = PdfListHelper(this); + this.marker = marker ?? _createMarker(style); + stringFormat = format; + super.indent = indent; + super.textIndent = textIndent; + if (font != null) { + helper.font = font; + } + if (items != null) { + helper.items = items; + } else if (text != null) { + helper.items = PdfListHelper.createItems(text); + } + } + + //Properties + /// Gets or gets the marker. + /// + /// ```dart + /// //Create a new PDF document. + /// PdfDocument document = PdfDocument(); + /// //Create a new unordered list. + /// PdfUnorderedList( + /// items: PdfListItemCollection(['Essential tools', 'Essential grid']), + /// font: PdfStandardFont(PdfFontFamily.helvetica, 16, + /// style: PdfFontStyle.italic), + /// marker: PdfUnorderedMarker(style: PdfUnorderedMarkerStyle.disk), + /// format: PdfStringFormat(lineSpacing: 20), + /// indent: 15, + /// textIndent: 10) + /// ..draw( + /// page: document.pages.add(), bounds: const Rect.fromLTWH(20, 20, 0, 0)); + /// //Save the document. + /// List bytes = await document.save(); + /// //Dispose the document. + /// document.dispose(); + /// ``` + late PdfUnorderedMarker marker; + + //Static methods + //Creates the marker. + static PdfUnorderedMarker _createMarker(PdfUnorderedMarkerStyle style) { + return PdfUnorderedMarker(style: style); + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/xmp/xmp_metadata.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/xmp/xmp_metadata.dart index 9eda7fc0e..e809d2cba 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/xmp/xmp_metadata.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/implementation/xmp/xmp_metadata.dart @@ -1,427 +1,427 @@ -import 'package:xml/xml.dart'; - -import '../../interfaces/pdf_interface.dart'; -import '../io/pdf_constants.dart'; -import '../io/pdf_stream_writer.dart'; -import '../pdf_document/enums.dart'; -import '../pdf_document/pdf_document_information.dart'; -import '../primitives/pdf_dictionary.dart'; -import '../primitives/pdf_name.dart'; -import '../primitives/pdf_stream.dart'; - -/// Represents XMP metadata of the document. -class XmpMetadata implements IPdfWrapper { - //Constructor - /// Initializes a new instance of the [XmpMetadata] class. - XmpMetadata(PdfDocumentInformation? documentInfo) { - _initialize(documentInfo); - } - - /// Initializes a new instance of the [XmpMetadata] class. - XmpMetadata.fromXmlDocument(XmlDocument xmp) { - _stream = PdfStream(); - _stream!.beginSave = beginSave; - _stream!.endSave = endSave; - load(xmp); - } - - //Fields - PdfStream? _stream; - XmlDocument? _xmlData; - PdfDocumentInformation? _documentInfo; - Map _namespaceCollection = {}; - final String _rdfUri = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; - final String _xap = 'http://ns.adobe.com/xap/1.0/'; - final String _dublinSchema = 'http://purl.org/dc/elements/1.1/'; - - //Properties - /// Gets XMP data in XML format. - XmlDocument? get xmlData => _xmlData; - - //Gets RDF element of the packet. - XmlElement? get _rdf { - XmlElement? node; - for (final XmlNode element in _xmlData!.descendants) { - if (element is XmlElement && element.name.local == 'RDF') { - node = element; - break; - } - } - final String elmName = _xmlData!.rootElement.name.toString(); - if (node == null) { - for (final XmlNode element in _xmlData!.descendants) { - if (element is XmlElement && element.name.local == elmName) { - node = element; - break; - } - } - if (node == null) { - throw ArgumentError.value(node, 'node', 'node cannot be null'); - } - } - return node; - } - - //Gets xmpmeta element of the packet. - XmlElement? get _xmpmeta { - XmlElement? node; - int count = 0; - for (final XmlNode element in _xmlData!.descendants) { - if (element is XmlElement && element.name.local == 'xmpmeta') { - node = element; - count++; - if (count > 1) { - throw ArgumentError( - 'More than one element satisfies the specified condition', - ); - } - } - } - if (node == null) { - throw ArgumentError.value(node, 'node', 'node cannot be null'); - } - return node; - } - - //Public methods. - /// Loads XMP from the XML. - void load(XmlDocument xmp) { - _reset(); - _xmlData = xmp; - _importNamespaces(_xmlData!); - } - - /// Adds schema to the XMP in XML format. - void add(XmlElement schema) { - // Import namespaces. - _addNamespace(schema.name.prefix!, schema.name.namespaceUri ?? ''); - // Append schema. - _rdf!.children.add(schema); - } - - //Implementations - void _initialize(PdfDocumentInformation? info) { - _xmlData = XmlDocument(); - _stream = PdfStream(); - _documentInfo = info; - _initializeStream(); - _createStartPacket(); - _createXmpmeta(); - _createRdf(_documentInfo!); - _createEndPacket(); - } - - //Initialize stream. - void _initializeStream() { - _stream!.beginSave = beginSave; - _stream!.endSave = endSave; - _stream![PdfDictionaryProperties.type] = PdfName( - PdfDictionaryProperties.metadata, - ); - _stream![PdfDictionaryProperties.subtype] = PdfName( - PdfDictionaryProperties.xml, - ); - _stream!.compress = false; - } - - /// internal method - //Raises before stream saves. - void beginSave(Object sender, SavePdfPrimitiveArgs? ars) { - //Save Xml to the stream. - final PdfStreamWriter streamWriter = PdfStreamWriter(_stream); - streamWriter.write(_xmlData!.toXmlString(pretty: true)); - } - - /// internal method - //Raises after stream saves. - void endSave(Object sender, SavePdfPrimitiveArgs? ars) { - //Reset stream data - _stream!.clearStream(); - } - - //Creates packet element. - void _createStartPacket() { - const String startPacket = 'begin="\uFEFF" id="W5M0MpCehiHzreSzNTczkc9d"'; - _xmlData!.children.add(XmlProcessing('xpacket', startPacket)); - } - - //Creates packet element. - void _createEndPacket() { - const String endPacket = 'end="r"'; - _xmlData!.children.add(XmlProcessing('xpacket', endPacket)); - } - - //Creates xmpmeta element. - void _createXmpmeta() { - final XmlElement element = _createElement('x', 'xmpmeta', 'adobe:ns:meta/'); - _xmlData!.children.add(element); - } - - //Creates Resource Description Framework element. - void _createRdf(PdfDocumentInformation info) { - final XmlElement rdf = _createElement('rdf', 'RDF', _rdfUri); - _addNamespace('rdf', _rdfUri); - if (!_isNullOrEmpty(info.producer) || !_isNullOrEmpty(info.keywords)) { - final String? pdfNamespace = _addNamespace( - 'pdf', - 'http://ns.adobe.com/pdf/1.3/', - ); - final XmlElement rdfDescription = _createElement( - 'rdf', - 'Description', - _rdfUri, - ); - rdfDescription.setAttribute('rdf:about', ' '); - if (!_isNullOrEmpty(info.producer)) { - rdfDescription.children.add( - XmlElement( - XmlName('Producer', 'pdf'), - [ - XmlAttribute(XmlName('pdf', 'xmlns'), pdfNamespace!), - ], - [XmlText(info.producer)], - ), - ); - } - if (!_isNullOrEmpty(info.keywords)) { - rdfDescription.children.add( - XmlElement( - XmlName('Keywords', 'pdf'), - [ - XmlAttribute(XmlName('pdf', 'xmlns'), pdfNamespace!), - ], - [XmlText(info.keywords)], - ), - ); - } - rdf.children.add(rdfDescription); - } - if (!_isNullOrEmpty(info.creator)) { - final XmlElement xmpDescription = _createElement( - 'rdf', - 'Description', - _rdfUri, - ); - xmpDescription.setAttribute('rdf:about', ' '); - final String? xmpNamespace = _addNamespace('xmp', _xap); - xmpDescription.setAttribute('xmlns:xmp', xmpNamespace); - if (!_isNullOrEmpty(info.creator)) { - xmpDescription.children.add( - XmlElement(XmlName('CreatorTool', 'xmp'), [], [ - XmlText(info.creator), - ]), - ); - } - final String createDate = _getDateTime( - PdfDocumentInformationHelper.getHelper(info).creationDate, - ); - xmpDescription.children.add( - XmlElement(XmlName('CreateDate', 'xmp'), [], [ - XmlText(createDate), - ]), - ); - if (!PdfDocumentInformationHelper.getHelper(info).isRemoveModifyDate) { - final String modificationDate = _getDateTime( - PdfDocumentInformationHelper.getHelper(info).modificationDate, - ); - xmpDescription.children.add( - XmlElement(XmlName('ModifyDate', 'xmp'), [], [ - XmlText(modificationDate), - ]), - ); - } - rdf.children.add(xmpDescription); - } - //Dublin Core Schema - final String? dublinNamespace = _addNamespace('dc', _dublinSchema); - final XmlElement dublinDescription = _createElement( - 'rdf', - 'Description', - _rdfUri, - ); - dublinDescription.setAttribute('rdf:about', ' '); - dublinDescription.setAttribute('xmlns:dc', dublinNamespace); - dublinDescription.children.add( - XmlElement(XmlName('format', 'dc'), [], [ - XmlText('application/pdf'), - ]), - ); - _createDublinCoreContainer( - dublinDescription, - 'title', - info.title, - true, - 'Alt', - ); - _createDublinCoreContainer( - dublinDescription, - 'description', - info.subject, - true, - 'Alt', - ); - _createDublinCoreContainer( - dublinDescription, - 'subject', - info.keywords, - false, - 'Bag', - ); - _createDublinCoreContainer( - dublinDescription, - 'creator', - info.author, - false, - 'Seq', - ); - rdf.children.add(dublinDescription); - if (PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == - PdfConformanceLevel.a1b || - PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == - PdfConformanceLevel.a2b || - PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == - PdfConformanceLevel.a3b) { - final String? pdfaid = _addNamespace( - 'pdfaid', - 'http://www.aiim.org/pdfa/ns/id/', - ); - final XmlElement pdfA = _createElement('rdf', 'Description', _rdfUri); - pdfA.setAttribute('rdf:about', ' '); - if (PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == - PdfConformanceLevel.a1b) { - pdfA.setAttribute('pdfaid:part', '1'); - } else if (PdfDocumentInformationHelper.getHelper( - _documentInfo!, - ).conformance == - PdfConformanceLevel.a2b) { - pdfA.setAttribute('pdfaid:part', '2'); - } else { - pdfA.setAttribute('pdfaid:part', '3'); - } - pdfA.setAttribute('pdfaid:conformance', 'B'); - pdfA.setAttribute('xmlns:pdfaid', pdfaid); - rdf.children.add(pdfA); - } else { - _addNamespace('pdfaid', _rdfUri); - } - _xmpmeta!.children.add(rdf); - } - - bool _isNullOrEmpty(String? text) { - return text == null || text == ''; - } - - XmlElement _createElement( - String prefix, - String localName, - String namespaceURI, - ) { - XmlElement element; - if (!_namespaceCollection.containsKey(prefix) && - prefix != 'xml' && - prefix != 'xmlns') { - element = XmlElement( - XmlName(localName, prefix), - [XmlAttribute(XmlName(prefix, 'xmlns'), namespaceURI)], - [], - false, - ); - } else { - element = XmlElement( - XmlName(localName, prefix == 'xap' ? 'xmp' : prefix), - ); - } - _addNamespace(prefix, namespaceURI); - return element; - } - - String? _addNamespace(String prefix, String namespaceURI) { - String? result = namespaceURI; - if (!_namespaceCollection.containsKey(prefix) && - prefix != 'xml' && - prefix != 'xmlns') { - _namespaceCollection[prefix] = namespaceURI; - } else { - result = _namespaceCollection[prefix]; - } - return result; - } - - String _getDateTime(DateTime dateTime) { - final int regionMinutes = dateTime.timeZoneOffset.inMinutes ~/ 11; - String offsetMinutes = regionMinutes.toString(); - if (regionMinutes >= 0 && regionMinutes <= 9) { - offsetMinutes = '0$offsetMinutes'; - } - final int regionHours = dateTime.timeZoneOffset.inHours; - String offsetHours = regionHours.toString(); - if (regionHours >= 0 && regionHours <= 9) { - offsetHours = '0$offsetHours'; - } - final String date = - '${dateTime.toIso8601String().substring(0, 22)}+$offsetHours:$offsetMinutes'; - return date; - } - - //Creates a Dublin core containers. - void _createDublinCoreContainer( - XmlElement dublinDesc, - String containerName, - String? value, - bool defaultLang, - String element, - ) { - if (!_isNullOrEmpty(value)) { - final XmlElement title = _createElement( - 'dc', - containerName, - _dublinSchema, - ); - _addNamespace('rdf', _rdfUri); - final XmlElement alt = _createElement('rdf', element, _rdfUri); - XmlElement li = _createElement('rdf', 'li', _rdfUri); - if (containerName == 'Subject') { - final List values = value!.split(','); - for (int i = 0; i < values.length; i++) { - if (i > 0) { - li = _createElement('rdf', 'li', _rdfUri); - } - li.innerText = values[i]; - alt.children.add(li); - } - } else { - li.innerText = value!; - alt.children.add(li); - } - title.children.add(alt); - dublinDesc.children.add(title); - if (defaultLang) { - li.setAttribute('xml:lang', 'x-default'); - } - } - } - - //Resets current xmp metadata. - void _reset() { - _xmlData = null; - _namespaceCollection = {}; - } - - void _importNamespaces(XmlDocument xml) { - for (final XmlNode element in xml.descendants) { - if (element is XmlElement) { - if (!_namespaceCollection.containsKey(element.name.prefix)) { - _namespaceCollection[element.name.prefix] = element.name.namespaceUri; - } - } - } - } - - /// internal property - IPdfPrimitive? get element => _stream; - set element(IPdfPrimitive? value) { - if (value != null && value is PdfStream) { - _stream = value; - } - } -} +import 'package:xml/xml.dart'; + +import '../../interfaces/pdf_interface.dart'; +import '../io/pdf_constants.dart'; +import '../io/pdf_stream_writer.dart'; +import '../pdf_document/enums.dart'; +import '../pdf_document/pdf_document_information.dart'; +import '../primitives/pdf_dictionary.dart'; +import '../primitives/pdf_name.dart'; +import '../primitives/pdf_stream.dart'; + +/// Represents XMP metadata of the document. +class XmpMetadata implements IPdfWrapper { + //Constructor + /// Initializes a new instance of the [XmpMetadata] class. + XmpMetadata(PdfDocumentInformation? documentInfo) { + _initialize(documentInfo); + } + + /// Initializes a new instance of the [XmpMetadata] class. + XmpMetadata.fromXmlDocument(XmlDocument xmp) { + _stream = PdfStream(); + _stream!.beginSave = beginSave; + _stream!.endSave = endSave; + load(xmp); + } + + //Fields + PdfStream? _stream; + XmlDocument? _xmlData; + PdfDocumentInformation? _documentInfo; + Map _namespaceCollection = {}; + final String _rdfUri = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; + final String _xap = 'http://ns.adobe.com/xap/1.0/'; + final String _dublinSchema = 'http://purl.org/dc/elements/1.1/'; + + //Properties + /// Gets XMP data in XML format. + XmlDocument? get xmlData => _xmlData; + + //Gets RDF element of the packet. + XmlElement? get _rdf { + XmlElement? node; + for (final XmlNode element in _xmlData!.descendants) { + if (element is XmlElement && element.name.local == 'RDF') { + node = element; + break; + } + } + final String elmName = _xmlData!.rootElement.name.toString(); + if (node == null) { + for (final XmlNode element in _xmlData!.descendants) { + if (element is XmlElement && element.name.local == elmName) { + node = element; + break; + } + } + if (node == null) { + throw ArgumentError.value(node, 'node', 'node cannot be null'); + } + } + return node; + } + + //Gets xmpmeta element of the packet. + XmlElement? get _xmpmeta { + XmlElement? node; + int count = 0; + for (final XmlNode element in _xmlData!.descendants) { + if (element is XmlElement && element.name.local == 'xmpmeta') { + node = element; + count++; + if (count > 1) { + throw ArgumentError( + 'More than one element satisfies the specified condition', + ); + } + } + } + if (node == null) { + throw ArgumentError.value(node, 'node', 'node cannot be null'); + } + return node; + } + + //Public methods. + /// Loads XMP from the XML. + void load(XmlDocument xmp) { + _reset(); + _xmlData = xmp; + _importNamespaces(_xmlData!); + } + + /// Adds schema to the XMP in XML format. + void add(XmlElement schema) { + // Import namespaces. + _addNamespace(schema.name.prefix!, schema.name.namespaceUri ?? ''); + // Append schema. + _rdf!.children.add(schema); + } + + //Implementations + void _initialize(PdfDocumentInformation? info) { + _xmlData = XmlDocument(); + _stream = PdfStream(); + _documentInfo = info; + _initializeStream(); + _createStartPacket(); + _createXmpmeta(); + _createRdf(_documentInfo!); + _createEndPacket(); + } + + //Initialize stream. + void _initializeStream() { + _stream!.beginSave = beginSave; + _stream!.endSave = endSave; + _stream![PdfDictionaryProperties.type] = PdfName( + PdfDictionaryProperties.metadata, + ); + _stream![PdfDictionaryProperties.subtype] = PdfName( + PdfDictionaryProperties.xml, + ); + _stream!.compress = false; + } + + /// internal method + //Raises before stream saves. + void beginSave(Object sender, SavePdfPrimitiveArgs? ars) { + //Save Xml to the stream. + final PdfStreamWriter streamWriter = PdfStreamWriter(_stream); + streamWriter.write(_xmlData!.toXmlString(pretty: true)); + } + + /// internal method + //Raises after stream saves. + void endSave(Object sender, SavePdfPrimitiveArgs? ars) { + //Reset stream data + _stream!.clearStream(); + } + + //Creates packet element. + void _createStartPacket() { + const String startPacket = 'begin="\uFEFF" id="W5M0MpCehiHzreSzNTczkc9d"'; + _xmlData!.children.add(XmlProcessing('xpacket', startPacket)); + } + + //Creates packet element. + void _createEndPacket() { + const String endPacket = 'end="r"'; + _xmlData!.children.add(XmlProcessing('xpacket', endPacket)); + } + + //Creates xmpmeta element. + void _createXmpmeta() { + final XmlElement element = _createElement('x', 'xmpmeta', 'adobe:ns:meta/'); + _xmlData!.children.add(element); + } + + //Creates Resource Description Framework element. + void _createRdf(PdfDocumentInformation info) { + final XmlElement rdf = _createElement('rdf', 'RDF', _rdfUri); + _addNamespace('rdf', _rdfUri); + if (!_isNullOrEmpty(info.producer) || !_isNullOrEmpty(info.keywords)) { + final String? pdfNamespace = _addNamespace( + 'pdf', + 'http://ns.adobe.com/pdf/1.3/', + ); + final XmlElement rdfDescription = _createElement( + 'rdf', + 'Description', + _rdfUri, + ); + rdfDescription.setAttribute('rdf:about', ' '); + if (!_isNullOrEmpty(info.producer)) { + rdfDescription.children.add( + XmlElement( + XmlName('Producer', 'pdf'), + [ + XmlAttribute(XmlName('pdf', 'xmlns'), pdfNamespace!), + ], + [XmlText(info.producer)], + ), + ); + } + if (!_isNullOrEmpty(info.keywords)) { + rdfDescription.children.add( + XmlElement( + XmlName('Keywords', 'pdf'), + [ + XmlAttribute(XmlName('pdf', 'xmlns'), pdfNamespace!), + ], + [XmlText(info.keywords)], + ), + ); + } + rdf.children.add(rdfDescription); + } + if (!_isNullOrEmpty(info.creator)) { + final XmlElement xmpDescription = _createElement( + 'rdf', + 'Description', + _rdfUri, + ); + xmpDescription.setAttribute('rdf:about', ' '); + final String? xmpNamespace = _addNamespace('xmp', _xap); + xmpDescription.setAttribute('xmlns:xmp', xmpNamespace); + if (!_isNullOrEmpty(info.creator)) { + xmpDescription.children.add( + XmlElement(XmlName('CreatorTool', 'xmp'), [], [ + XmlText(info.creator), + ]), + ); + } + final String createDate = _getDateTime( + PdfDocumentInformationHelper.getHelper(info).creationDate, + ); + xmpDescription.children.add( + XmlElement(XmlName('CreateDate', 'xmp'), [], [ + XmlText(createDate), + ]), + ); + if (!PdfDocumentInformationHelper.getHelper(info).isRemoveModifyDate) { + final String modificationDate = _getDateTime( + PdfDocumentInformationHelper.getHelper(info).modificationDate, + ); + xmpDescription.children.add( + XmlElement(XmlName('ModifyDate', 'xmp'), [], [ + XmlText(modificationDate), + ]), + ); + } + rdf.children.add(xmpDescription); + } + //Dublin Core Schema + final String? dublinNamespace = _addNamespace('dc', _dublinSchema); + final XmlElement dublinDescription = _createElement( + 'rdf', + 'Description', + _rdfUri, + ); + dublinDescription.setAttribute('rdf:about', ' '); + dublinDescription.setAttribute('xmlns:dc', dublinNamespace); + dublinDescription.children.add( + XmlElement(XmlName('format', 'dc'), [], [ + XmlText('application/pdf'), + ]), + ); + _createDublinCoreContainer( + dublinDescription, + 'title', + info.title, + true, + 'Alt', + ); + _createDublinCoreContainer( + dublinDescription, + 'description', + info.subject, + true, + 'Alt', + ); + _createDublinCoreContainer( + dublinDescription, + 'subject', + info.keywords, + false, + 'Bag', + ); + _createDublinCoreContainer( + dublinDescription, + 'creator', + info.author, + false, + 'Seq', + ); + rdf.children.add(dublinDescription); + if (PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == + PdfConformanceLevel.a1b || + PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == + PdfConformanceLevel.a2b || + PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == + PdfConformanceLevel.a3b) { + final String? pdfaid = _addNamespace( + 'pdfaid', + 'http://www.aiim.org/pdfa/ns/id/', + ); + final XmlElement pdfA = _createElement('rdf', 'Description', _rdfUri); + pdfA.setAttribute('rdf:about', ' '); + if (PdfDocumentInformationHelper.getHelper(_documentInfo!).conformance == + PdfConformanceLevel.a1b) { + pdfA.setAttribute('pdfaid:part', '1'); + } else if (PdfDocumentInformationHelper.getHelper( + _documentInfo!, + ).conformance == + PdfConformanceLevel.a2b) { + pdfA.setAttribute('pdfaid:part', '2'); + } else { + pdfA.setAttribute('pdfaid:part', '3'); + } + pdfA.setAttribute('pdfaid:conformance', 'B'); + pdfA.setAttribute('xmlns:pdfaid', pdfaid); + rdf.children.add(pdfA); + } else { + _addNamespace('pdfaid', _rdfUri); + } + _xmpmeta!.children.add(rdf); + } + + bool _isNullOrEmpty(String? text) { + return text == null || text == ''; + } + + XmlElement _createElement( + String prefix, + String localName, + String namespaceURI, + ) { + XmlElement element; + if (!_namespaceCollection.containsKey(prefix) && + prefix != 'xml' && + prefix != 'xmlns') { + element = XmlElement( + XmlName(localName, prefix), + [XmlAttribute(XmlName(prefix, 'xmlns'), namespaceURI)], + [], + false, + ); + } else { + element = XmlElement( + XmlName(localName, prefix == 'xap' ? 'xmp' : prefix), + ); + } + _addNamespace(prefix, namespaceURI); + return element; + } + + String? _addNamespace(String prefix, String namespaceURI) { + String? result = namespaceURI; + if (!_namespaceCollection.containsKey(prefix) && + prefix != 'xml' && + prefix != 'xmlns') { + _namespaceCollection[prefix] = namespaceURI; + } else { + result = _namespaceCollection[prefix]; + } + return result; + } + + String _getDateTime(DateTime dateTime) { + final int regionMinutes = dateTime.timeZoneOffset.inMinutes ~/ 11; + String offsetMinutes = regionMinutes.toString(); + if (regionMinutes >= 0 && regionMinutes <= 9) { + offsetMinutes = '0$offsetMinutes'; + } + final int regionHours = dateTime.timeZoneOffset.inHours; + String offsetHours = regionHours.toString(); + if (regionHours >= 0 && regionHours <= 9) { + offsetHours = '0$offsetHours'; + } + final String date = + '${dateTime.toIso8601String().substring(0, 22)}+$offsetHours:$offsetMinutes'; + return date; + } + + //Creates a Dublin core containers. + void _createDublinCoreContainer( + XmlElement dublinDesc, + String containerName, + String? value, + bool defaultLang, + String element, + ) { + if (!_isNullOrEmpty(value)) { + final XmlElement title = _createElement( + 'dc', + containerName, + _dublinSchema, + ); + _addNamespace('rdf', _rdfUri); + final XmlElement alt = _createElement('rdf', element, _rdfUri); + XmlElement li = _createElement('rdf', 'li', _rdfUri); + if (containerName == 'Subject') { + final List values = value!.split(','); + for (int i = 0; i < values.length; i++) { + if (i > 0) { + li = _createElement('rdf', 'li', _rdfUri); + } + li.innerText = values[i]; + alt.children.add(li); + } + } else { + li.innerText = value!; + alt.children.add(li); + } + title.children.add(alt); + dublinDesc.children.add(title); + if (defaultLang) { + li.setAttribute('xml:lang', 'x-default'); + } + } + } + + //Resets current xmp metadata. + void _reset() { + _xmlData = null; + _namespaceCollection = {}; + } + + void _importNamespaces(XmlDocument xml) { + for (final XmlNode element in xml.descendants) { + if (element is XmlElement) { + if (!_namespaceCollection.containsKey(element.name.prefix)) { + _namespaceCollection[element.name.prefix] = element.name.namespaceUri; + } + } + } + } + + /// internal property + IPdfPrimitive? get element => _stream; + set element(IPdfPrimitive? value) { + if (value != null && value is PdfStream) { + _stream = value; + } + } +} diff --git a/packages/syncfusion_flutter_pdf/lib/src/pdf/interfaces/pdf_interface.dart b/packages/syncfusion_flutter_pdf/lib/src/pdf/interfaces/pdf_interface.dart index 2c5330dd0..180417c1f 100644 --- a/packages/syncfusion_flutter_pdf/lib/src/pdf/interfaces/pdf_interface.dart +++ b/packages/syncfusion_flutter_pdf/lib/src/pdf/interfaces/pdf_interface.dart @@ -1,322 +1,322 @@ -import '../implementation/actions/pdf_action.dart'; -import '../implementation/actions/pdf_annotation_action.dart'; -import '../implementation/actions/pdf_field_actions.dart'; -import '../implementation/annotations/appearance/pdf_appearance_state.dart'; -import '../implementation/annotations/appearance/pdf_extended_appearance.dart'; -import '../implementation/annotations/pdf_action_annotation.dart'; -import '../implementation/annotations/pdf_annotation.dart'; -import '../implementation/annotations/pdf_annotation_border.dart'; -import '../implementation/annotations/pdf_annotation_collection.dart'; -import '../implementation/annotations/pdf_appearance.dart'; -import '../implementation/annotations/pdf_document_link_annotation.dart'; -import '../implementation/annotations/pdf_ellipse_annotation.dart'; -import '../implementation/annotations/pdf_line_annotation.dart'; -import '../implementation/annotations/pdf_polygon_annotation.dart'; -import '../implementation/annotations/pdf_rectangle_annotation.dart'; -import '../implementation/annotations/pdf_text_web_link.dart'; -import '../implementation/annotations/pdf_uri_annotation.dart'; -import '../implementation/annotations/widget_annotation.dart'; -import '../implementation/annotations/widget_appearance.dart'; -import '../implementation/color_space/pdf_icc_color_profile.dart'; -import '../implementation/forms/pdf_check_box_field.dart'; -import '../implementation/forms/pdf_field.dart'; -import '../implementation/forms/pdf_form.dart'; -import '../implementation/forms/pdf_form_field_collection.dart'; -import '../implementation/forms/pdf_list_field_item.dart'; -import '../implementation/forms/pdf_list_field_item_collection.dart'; -import '../implementation/forms/pdf_radio_button_item_collection.dart'; -import '../implementation/general/embedded_file.dart'; -import '../implementation/general/file_specification_base.dart'; -import '../implementation/general/pdf_destination.dart'; -import '../implementation/general/pdf_named_destination.dart'; -import '../implementation/general/pdf_named_destination_collection.dart'; -import '../implementation/graphics/figures/pdf_template.dart'; -import '../implementation/graphics/fonts/pdf_cjk_standard_font.dart'; -import '../implementation/graphics/fonts/pdf_standard_font.dart'; -import '../implementation/graphics/fonts/pdf_true_type_font.dart'; -import '../implementation/graphics/images/pdf_image.dart'; -import '../implementation/graphics/pdf_transparency.dart'; -import '../implementation/io/enums.dart'; -import '../implementation/io/pdf_cross_table.dart'; -import '../implementation/pages/pdf_layer.dart'; -import '../implementation/pages/pdf_page.dart'; -import '../implementation/pages/pdf_page_layer.dart'; -import '../implementation/pages/pdf_section.dart'; -import '../implementation/pages/pdf_section_collection.dart'; -import '../implementation/pdf_document/attachments/pdf_attachment_collection.dart'; -import '../implementation/pdf_document/outlines/pdf_outline.dart'; -import '../implementation/pdf_document/pdf_catalog_names.dart'; -import '../implementation/pdf_document/pdf_document.dart'; -import '../implementation/pdf_document/pdf_document_information.dart'; -import '../implementation/security/digital_signature/pdf_signature_dictionary.dart'; -import '../implementation/xmp/xmp_metadata.dart'; - -/// internal interface -class IPdfChangable { - /// internal field - bool? changed; - - /// internal field - void freezeChanges(Object freezer) {} -} - -/// Defines the basic interace of the various Primitive. -class IPdfPrimitive { - /// Specfies the status of the IPdfPrmitive. - /// Status is registered if it has a reference or else none. - PdfObjectStatus? status; - - /// Indicates whether this primitive is saving or not - bool? isSaving; - - /// Index value of the specified object - int? objectCollectionIndex; - - /// Stores the cloned object for future use. - IPdfPrimitive? clonedObject; - - /// Position of the object. - int? position; - - /// Saves the object using the specified writer. - void save(IPdfWriter? writer) {} - - /// internal method - void dispose() {} - - /// internal method - IPdfPrimitive? cloneObject(PdfCrossTable crossTable) => null; -} - -/// Defines the basic interface of the various Wrapper. -class IPdfWrapper { - /// Get the primitive element. - IPdfPrimitive? _element; - - /// internal method - static IPdfPrimitive? getElement(IPdfWrapper wrapper) { - IPdfPrimitive? element; - if (wrapper is PdfAction) { - element = PdfActionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfAnnotationActions) { - element = PdfAnnotationActionsHelper.getHelper(wrapper).element; - } else if (wrapper is PdfFieldActions) { - element = PdfFieldActionsHelper.getHelper(wrapper).element; - } else if (wrapper is PdfTextWebLink) { - element = PdfTextWebLinkHelper.getHelper(wrapper).element; - } else if (wrapper is PdfEllipseAnnotation) { - element = PdfEllipseAnnotationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfLineAnnotation) { - element = PdfLineAnnotationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfPolygonAnnotation) { - element = PdfPolygonAnnotationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfRectangleAnnotation) { - element = PdfRectangleAnnotationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfDocumentLinkAnnotation) { - element = PdfDocumentLinkAnnotationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfActionAnnotation) { - element = PdfActionAnnotationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfUriAnnotation) { - element = PdfUriAnnotationHelper.getHelper(wrapper).element; - } else if (wrapper is WidgetAnnotation || wrapper is PdfAnnotation) { - element = PdfAnnotationHelper.getHelper(wrapper as PdfAnnotation).element; - } else if (wrapper is PdfAnnotationBorder) { - element = PdfAnnotationBorderHelper.getHelper(wrapper).element; - } else if (wrapper is PdfAnnotationCollection) { - element = PdfAnnotationCollectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfAppearance) { - element = PdfAppearanceHelper.getHelper(wrapper).element; - } else if (wrapper is PdfRadioButtonListItem) { - element = getElement(PdfFieldHelper.getHelper(wrapper).widget!); - } else if (wrapper is PdfField) { - element = PdfFieldHelper.getHelper(wrapper).element; - } else if (wrapper is PdfFormFieldCollection) { - element = PdfFormFieldCollectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfForm) { - element = PdfFormHelper.getHelper(wrapper).element; - } else if (wrapper is PdfListFieldItemCollection) { - element = PdfListFieldItemCollectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfListFieldItem) { - element = PdfListFieldItemHelper.getHelper(wrapper).element; - } else if (wrapper is PdfRadioButtonItemCollection) { - element = PdfRadioButtonItemCollectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfFileSpecificationBase) { - element = PdfFileSpecificationBaseHelper.getHelper(wrapper).element; - } else if (wrapper is PdfDestination) { - element = PdfDestinationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfNamedDestinationCollection) { - element = PdfNamedDestinationCollectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfNamedDestination) { - element = PdfNamedDestinationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfTemplate) { - element = PdfTemplateHelper.getHelper(wrapper).element; - } else if (wrapper is PdfStandardFont) { - element = PdfStandardFontHelper.getHelper(wrapper).element; - } else if (wrapper is PdfCjkStandardFont) { - element = PdfCjkStandardFontHelper.getHelper(wrapper).element; - } else if (wrapper is PdfTrueTypeFont) { - element = PdfTrueTypeFontHelper.getHelper(wrapper).element; - } else if (wrapper is PdfImage) { - element = PdfImageHelper.getElement(wrapper); - } else if (wrapper is PdfLayer) { - element = PdfLayerHelper.getHelper(wrapper).element; - } else if (wrapper is PdfPageLayer) { - element = PdfPageLayerHelper.getHelper(wrapper).element; - } else if (wrapper is PdfPage) { - element = PdfPageHelper.getHelper(wrapper).element; - } else if (wrapper is PdfSectionCollection) { - element = PdfSectionCollectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfSection) { - element = PdfSectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfDocumentInformation) { - element = PdfDocumentInformationHelper.getHelper(wrapper).element; - } else if (wrapper is PdfAttachmentCollection) { - element = PdfAttachmentCollectionHelper.getHelper(wrapper).element; - } else if (wrapper is PdfBookmarkBase) { - element = PdfBookmarkBaseHelper.getHelper(wrapper).element; - } else if (wrapper is WidgetAppearance) { - element = wrapper.element; - } else if (wrapper is PdfAppearanceState) { - element = wrapper.element; - } else if (wrapper is PdfExtendedAppearance) { - element = wrapper.element; - } else if (wrapper is PdfICCColorProfile) { - element = wrapper.element; - } else if (wrapper is EmbeddedFile) { - element = wrapper.element; - } else if (wrapper is EmbeddedFileParams) { - element = wrapper.element; - } else if (wrapper is PdfTransparency) { - element = wrapper.element; - } else if (wrapper is PdfCatalogNames) { - element = wrapper.element; - } else if (wrapper is PdfSignatureDictionary) { - element = wrapper.element; - } else if (wrapper is XmpMetadata) { - element = wrapper.element; - } else { - element = wrapper._element; - } - return element; - } - - /// internal method - static void setElement(IPdfWrapper wrapper, IPdfPrimitive? element) { - if (wrapper is PdfAction) { - PdfActionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfAnnotationActions) { - PdfAnnotationActionsHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfFieldActions) { - PdfFieldActionsHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfTextWebLink) { - PdfTextWebLinkHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfEllipseAnnotation) { - PdfEllipseAnnotationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfLineAnnotation) { - PdfLineAnnotationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfPolygonAnnotation) { - PdfPolygonAnnotationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfRectangleAnnotation) { - PdfRectangleAnnotationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfDocumentLinkAnnotation) { - PdfDocumentLinkAnnotationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfActionAnnotation) { - PdfActionAnnotationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfUriAnnotation) { - PdfUriAnnotationHelper.getHelper(wrapper).element = element; - } else if (wrapper is WidgetAnnotation || wrapper is PdfAnnotation) { - PdfAnnotationHelper.getHelper(wrapper as PdfAnnotation).element = element; - } else if (wrapper is PdfAnnotationBorder) { - PdfAnnotationBorderHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfAnnotationCollection) { - PdfAnnotationCollectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfAppearance) { - PdfAppearanceHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfField) { - PdfFieldHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfFormFieldCollection) { - PdfFormFieldCollectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfForm) { - PdfFormHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfListFieldItemCollection) { - PdfListFieldItemCollectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfListFieldItem) { - PdfListFieldItemHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfRadioButtonItemCollection) { - PdfRadioButtonItemCollectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfFileSpecificationBase) { - PdfFileSpecificationBaseHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfDestination) { - PdfDestinationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfNamedDestinationCollection) { - PdfNamedDestinationCollectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfNamedDestination) { - PdfNamedDestinationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfTemplate) { - PdfTemplateHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfStandardFont) { - PdfStandardFontHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfCjkStandardFont) { - PdfCjkStandardFontHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfTrueTypeFont) { - PdfTrueTypeFontHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfImage) { - PdfImageHelper.setElement(wrapper, element); - } else if (wrapper is PdfLayer) { - PdfLayerHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfPageLayer) { - PdfPageLayerHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfPage) { - PdfPageHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfSectionCollection) { - PdfSectionCollectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfSection) { - PdfSectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfDocumentInformation) { - PdfDocumentInformationHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfAttachmentCollection) { - PdfAttachmentCollectionHelper.getHelper(wrapper).element = element; - } else if (wrapper is PdfBookmarkBase) { - PdfBookmarkBaseHelper.getHelper(wrapper).element = element; - } else if (wrapper is WidgetAppearance) { - wrapper.element = element; - } else if (wrapper is PdfAppearanceState) { - wrapper.element = element; - } else if (wrapper is PdfExtendedAppearance) { - wrapper.element = element; - } else if (wrapper is PdfICCColorProfile) { - wrapper.element = element; - } else if (wrapper is EmbeddedFile) { - wrapper.element = element; - } else if (wrapper is EmbeddedFileParams) { - wrapper.element = element; - } else if (wrapper is PdfTransparency) { - wrapper.element = element; - } else if (wrapper is PdfCatalogNames) { - wrapper.element = element; - } else if (wrapper is PdfSignatureDictionary) { - wrapper.element = element; - } else if (wrapper is XmpMetadata) { - wrapper.element = element; - } else { - wrapper._element = element; - } - } -} - -/// internal interface -class IPdfWriter { - /// internal field - //ignore:unused_field - int? position; - - /// internal field - //ignore:unused_field - int? length; - - /// internal field - PdfDocument? document; - - /// internal method - void write(dynamic pdfObject) {} -} +import '../implementation/actions/pdf_action.dart'; +import '../implementation/actions/pdf_annotation_action.dart'; +import '../implementation/actions/pdf_field_actions.dart'; +import '../implementation/annotations/appearance/pdf_appearance_state.dart'; +import '../implementation/annotations/appearance/pdf_extended_appearance.dart'; +import '../implementation/annotations/pdf_action_annotation.dart'; +import '../implementation/annotations/pdf_annotation.dart'; +import '../implementation/annotations/pdf_annotation_border.dart'; +import '../implementation/annotations/pdf_annotation_collection.dart'; +import '../implementation/annotations/pdf_appearance.dart'; +import '../implementation/annotations/pdf_document_link_annotation.dart'; +import '../implementation/annotations/pdf_ellipse_annotation.dart'; +import '../implementation/annotations/pdf_line_annotation.dart'; +import '../implementation/annotations/pdf_polygon_annotation.dart'; +import '../implementation/annotations/pdf_rectangle_annotation.dart'; +import '../implementation/annotations/pdf_text_web_link.dart'; +import '../implementation/annotations/pdf_uri_annotation.dart'; +import '../implementation/annotations/widget_annotation.dart'; +import '../implementation/annotations/widget_appearance.dart'; +import '../implementation/color_space/pdf_icc_color_profile.dart'; +import '../implementation/forms/pdf_check_box_field.dart'; +import '../implementation/forms/pdf_field.dart'; +import '../implementation/forms/pdf_form.dart'; +import '../implementation/forms/pdf_form_field_collection.dart'; +import '../implementation/forms/pdf_list_field_item.dart'; +import '../implementation/forms/pdf_list_field_item_collection.dart'; +import '../implementation/forms/pdf_radio_button_item_collection.dart'; +import '../implementation/general/embedded_file.dart'; +import '../implementation/general/file_specification_base.dart'; +import '../implementation/general/pdf_destination.dart'; +import '../implementation/general/pdf_named_destination.dart'; +import '../implementation/general/pdf_named_destination_collection.dart'; +import '../implementation/graphics/figures/pdf_template.dart'; +import '../implementation/graphics/fonts/pdf_cjk_standard_font.dart'; +import '../implementation/graphics/fonts/pdf_standard_font.dart'; +import '../implementation/graphics/fonts/pdf_true_type_font.dart'; +import '../implementation/graphics/images/pdf_image.dart'; +import '../implementation/graphics/pdf_transparency.dart'; +import '../implementation/io/enums.dart'; +import '../implementation/io/pdf_cross_table.dart'; +import '../implementation/pages/pdf_layer.dart'; +import '../implementation/pages/pdf_page.dart'; +import '../implementation/pages/pdf_page_layer.dart'; +import '../implementation/pages/pdf_section.dart'; +import '../implementation/pages/pdf_section_collection.dart'; +import '../implementation/pdf_document/attachments/pdf_attachment_collection.dart'; +import '../implementation/pdf_document/outlines/pdf_outline.dart'; +import '../implementation/pdf_document/pdf_catalog_names.dart'; +import '../implementation/pdf_document/pdf_document.dart'; +import '../implementation/pdf_document/pdf_document_information.dart'; +import '../implementation/security/digital_signature/pdf_signature_dictionary.dart'; +import '../implementation/xmp/xmp_metadata.dart'; + +/// internal interface +class IPdfChangable { + /// internal field + bool? changed; + + /// internal field + void freezeChanges(Object freezer) {} +} + +/// Defines the basic interace of the various Primitive. +class IPdfPrimitive { + /// Specfies the status of the IPdfPrmitive. + /// Status is registered if it has a reference or else none. + PdfObjectStatus? status; + + /// Indicates whether this primitive is saving or not + bool? isSaving; + + /// Index value of the specified object + int? objectCollectionIndex; + + /// Stores the cloned object for future use. + IPdfPrimitive? clonedObject; + + /// Position of the object. + int? position; + + /// Saves the object using the specified writer. + void save(IPdfWriter? writer) {} + + /// internal method + void dispose() {} + + /// internal method + IPdfPrimitive? cloneObject(PdfCrossTable crossTable) => null; +} + +/// Defines the basic interface of the various Wrapper. +class IPdfWrapper { + /// Get the primitive element. + IPdfPrimitive? _element; + + /// internal method + static IPdfPrimitive? getElement(IPdfWrapper wrapper) { + IPdfPrimitive? element; + if (wrapper is PdfAction) { + element = PdfActionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfAnnotationActions) { + element = PdfAnnotationActionsHelper.getHelper(wrapper).element; + } else if (wrapper is PdfFieldActions) { + element = PdfFieldActionsHelper.getHelper(wrapper).element; + } else if (wrapper is PdfTextWebLink) { + element = PdfTextWebLinkHelper.getHelper(wrapper).element; + } else if (wrapper is PdfEllipseAnnotation) { + element = PdfEllipseAnnotationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfLineAnnotation) { + element = PdfLineAnnotationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfPolygonAnnotation) { + element = PdfPolygonAnnotationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfRectangleAnnotation) { + element = PdfRectangleAnnotationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfDocumentLinkAnnotation) { + element = PdfDocumentLinkAnnotationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfActionAnnotation) { + element = PdfActionAnnotationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfUriAnnotation) { + element = PdfUriAnnotationHelper.getHelper(wrapper).element; + } else if (wrapper is WidgetAnnotation || wrapper is PdfAnnotation) { + element = PdfAnnotationHelper.getHelper(wrapper as PdfAnnotation).element; + } else if (wrapper is PdfAnnotationBorder) { + element = PdfAnnotationBorderHelper.getHelper(wrapper).element; + } else if (wrapper is PdfAnnotationCollection) { + element = PdfAnnotationCollectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfAppearance) { + element = PdfAppearanceHelper.getHelper(wrapper).element; + } else if (wrapper is PdfRadioButtonListItem) { + element = getElement(PdfFieldHelper.getHelper(wrapper).widget!); + } else if (wrapper is PdfField) { + element = PdfFieldHelper.getHelper(wrapper).element; + } else if (wrapper is PdfFormFieldCollection) { + element = PdfFormFieldCollectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfForm) { + element = PdfFormHelper.getHelper(wrapper).element; + } else if (wrapper is PdfListFieldItemCollection) { + element = PdfListFieldItemCollectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfListFieldItem) { + element = PdfListFieldItemHelper.getHelper(wrapper).element; + } else if (wrapper is PdfRadioButtonItemCollection) { + element = PdfRadioButtonItemCollectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfFileSpecificationBase) { + element = PdfFileSpecificationBaseHelper.getHelper(wrapper).element; + } else if (wrapper is PdfDestination) { + element = PdfDestinationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfNamedDestinationCollection) { + element = PdfNamedDestinationCollectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfNamedDestination) { + element = PdfNamedDestinationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfTemplate) { + element = PdfTemplateHelper.getHelper(wrapper).element; + } else if (wrapper is PdfStandardFont) { + element = PdfStandardFontHelper.getHelper(wrapper).element; + } else if (wrapper is PdfCjkStandardFont) { + element = PdfCjkStandardFontHelper.getHelper(wrapper).element; + } else if (wrapper is PdfTrueTypeFont) { + element = PdfTrueTypeFontHelper.getHelper(wrapper).element; + } else if (wrapper is PdfImage) { + element = PdfImageHelper.getElement(wrapper); + } else if (wrapper is PdfLayer) { + element = PdfLayerHelper.getHelper(wrapper).element; + } else if (wrapper is PdfPageLayer) { + element = PdfPageLayerHelper.getHelper(wrapper).element; + } else if (wrapper is PdfPage) { + element = PdfPageHelper.getHelper(wrapper).element; + } else if (wrapper is PdfSectionCollection) { + element = PdfSectionCollectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfSection) { + element = PdfSectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfDocumentInformation) { + element = PdfDocumentInformationHelper.getHelper(wrapper).element; + } else if (wrapper is PdfAttachmentCollection) { + element = PdfAttachmentCollectionHelper.getHelper(wrapper).element; + } else if (wrapper is PdfBookmarkBase) { + element = PdfBookmarkBaseHelper.getHelper(wrapper).element; + } else if (wrapper is WidgetAppearance) { + element = wrapper.element; + } else if (wrapper is PdfAppearanceState) { + element = wrapper.element; + } else if (wrapper is PdfExtendedAppearance) { + element = wrapper.element; + } else if (wrapper is PdfICCColorProfile) { + element = wrapper.element; + } else if (wrapper is EmbeddedFile) { + element = wrapper.element; + } else if (wrapper is EmbeddedFileParams) { + element = wrapper.element; + } else if (wrapper is PdfTransparency) { + element = wrapper.element; + } else if (wrapper is PdfCatalogNames) { + element = wrapper.element; + } else if (wrapper is PdfSignatureDictionary) { + element = wrapper.element; + } else if (wrapper is XmpMetadata) { + element = wrapper.element; + } else { + element = wrapper._element; + } + return element; + } + + /// internal method + static void setElement(IPdfWrapper wrapper, IPdfPrimitive? element) { + if (wrapper is PdfAction) { + PdfActionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfAnnotationActions) { + PdfAnnotationActionsHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfFieldActions) { + PdfFieldActionsHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfTextWebLink) { + PdfTextWebLinkHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfEllipseAnnotation) { + PdfEllipseAnnotationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfLineAnnotation) { + PdfLineAnnotationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfPolygonAnnotation) { + PdfPolygonAnnotationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfRectangleAnnotation) { + PdfRectangleAnnotationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfDocumentLinkAnnotation) { + PdfDocumentLinkAnnotationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfActionAnnotation) { + PdfActionAnnotationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfUriAnnotation) { + PdfUriAnnotationHelper.getHelper(wrapper).element = element; + } else if (wrapper is WidgetAnnotation || wrapper is PdfAnnotation) { + PdfAnnotationHelper.getHelper(wrapper as PdfAnnotation).element = element; + } else if (wrapper is PdfAnnotationBorder) { + PdfAnnotationBorderHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfAnnotationCollection) { + PdfAnnotationCollectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfAppearance) { + PdfAppearanceHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfField) { + PdfFieldHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfFormFieldCollection) { + PdfFormFieldCollectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfForm) { + PdfFormHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfListFieldItemCollection) { + PdfListFieldItemCollectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfListFieldItem) { + PdfListFieldItemHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfRadioButtonItemCollection) { + PdfRadioButtonItemCollectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfFileSpecificationBase) { + PdfFileSpecificationBaseHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfDestination) { + PdfDestinationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfNamedDestinationCollection) { + PdfNamedDestinationCollectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfNamedDestination) { + PdfNamedDestinationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfTemplate) { + PdfTemplateHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfStandardFont) { + PdfStandardFontHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfCjkStandardFont) { + PdfCjkStandardFontHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfTrueTypeFont) { + PdfTrueTypeFontHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfImage) { + PdfImageHelper.setElement(wrapper, element); + } else if (wrapper is PdfLayer) { + PdfLayerHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfPageLayer) { + PdfPageLayerHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfPage) { + PdfPageHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfSectionCollection) { + PdfSectionCollectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfSection) { + PdfSectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfDocumentInformation) { + PdfDocumentInformationHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfAttachmentCollection) { + PdfAttachmentCollectionHelper.getHelper(wrapper).element = element; + } else if (wrapper is PdfBookmarkBase) { + PdfBookmarkBaseHelper.getHelper(wrapper).element = element; + } else if (wrapper is WidgetAppearance) { + wrapper.element = element; + } else if (wrapper is PdfAppearanceState) { + wrapper.element = element; + } else if (wrapper is PdfExtendedAppearance) { + wrapper.element = element; + } else if (wrapper is PdfICCColorProfile) { + wrapper.element = element; + } else if (wrapper is EmbeddedFile) { + wrapper.element = element; + } else if (wrapper is EmbeddedFileParams) { + wrapper.element = element; + } else if (wrapper is PdfTransparency) { + wrapper.element = element; + } else if (wrapper is PdfCatalogNames) { + wrapper.element = element; + } else if (wrapper is PdfSignatureDictionary) { + wrapper.element = element; + } else if (wrapper is XmpMetadata) { + wrapper.element = element; + } else { + wrapper._element = element; + } + } +} + +/// internal interface +class IPdfWriter { + /// internal field + //ignore:unused_field + int? position; + + /// internal field + //ignore:unused_field + int? length; + + /// internal field + PdfDocument? document; + + /// internal method + void write(dynamic pdfObject) {} +} diff --git a/packages/syncfusion_flutter_pdf/pubspec.lock b/packages/syncfusion_flutter_pdf/pubspec.lock new file mode 100644 index 000000000..9f1b45bc0 --- /dev/null +++ b/packages/syncfusion_flutter_pdf/pubspec.lock @@ -0,0 +1,184 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: "direct main" + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + crypto: + dependency: "direct main" + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" + url: "https://pub.dev" + source: hosted + version: "0.20.2" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "1a97266a94f7350d30ae522c0af07890c70b8e62c71e8e3920d1db4d23c057d1" + url: "https://pub.dev" + source: hosted + version: "7.0.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + syncfusion_flutter_core: + dependency: "direct main" + description: + name: syncfusion_flutter_core + sha256: e68a7e214659faf0df483c760d295ab58e376a639285d2a9f7d1e43351efcbb3 + url: "https://pub.dev" + source: hosted + version: "31.2.16" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b + url: "https://pub.dev" + source: hosted + version: "2.2.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xml: + dependency: "direct main" + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" +sdks: + dart: ">=3.8.0 <4.0.0" + flutter: ">=3.35.1" diff --git a/packages/syncfusion_flutter_pdf/pubspec.yaml b/packages/syncfusion_flutter_pdf/pubspec.yaml index 827da5db3..9e0b88cc5 100644 --- a/packages/syncfusion_flutter_pdf/pubspec.yaml +++ b/packages/syncfusion_flutter_pdf/pubspec.yaml @@ -1,22 +1,23 @@ -name: syncfusion_flutter_pdf -description: The Flutter PDF is a library written natively in Dart for creating, reading, editing, and securing PDF files in Android, iOS, and web platforms. -version: 30.1.37 -homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_pdf - -environment: - sdk: ^3.7.0-0 - -dependencies: - flutter: - sdk: flutter - intl: '>=0.18.0 <0.21.0' - xml: ">=6.5.0 <7.0.0" - syncfusion_flutter_core: - path: ../syncfusion_flutter_core - - - crypto: ">=3.0.0 <4.0.0" - convert: ">=3.0.0 <4.0.0" - http: ^1.2.1 - - +name: syncfusion_flutter_pdf +description: The Flutter PDF is a library written natively in Dart for creating, reading, editing, and securing PDF files in Android, iOS, and web platforms. +version: 31.2.16 +homepage: https://github.com/syncfusion/flutter-widgets/tree/master/packages/syncfusion_flutter_pdf + +environment: + sdk: ^3.7.0 + flutter: '>=3.35.1' + +dependencies: + flutter: + sdk: flutter + intl: '>=0.18.0 <0.21.0' + xml: ">=6.5.0 <7.0.0" + crypto: ">=3.0.0 <4.0.0" + convert: ">=3.0.0 <4.0.0" + http: ^1.2.1 + syncfusion_flutter_core: ^31.2.16 + + + + +