├── .editorconfig
├── .gitattributes
├── .github
├── CODEOWNERS
├── dependabot.yml
└── workflows
│ ├── cla.yml
│ ├── dotnet.yml
│ └── stale.yml
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
├── tasks.json
└── updateNuget.sh
├── LICENSE
├── OpenXmlToHtml.sln
├── OpenXmlToHtml
├── ExportImageHandler.cs
├── IOpenXmlToHtml.cs
├── NugetIcon.png
├── OpenXmlToHtml.cs
├── OpenXmlToHtml.csproj
├── OpenXmlToHtml.snk
├── PageBreakHandler.cs
├── SymbolHandler.cs
├── TextSymbolToUnicodeHandler.cs
├── Tooling
│ └── Linux.cs
├── WebSafeFontsHandler.cs
└── docs
│ └── nugetReadme.md
├── OpenXmlToHtmlCli
├── OpenXmlToHtmlCli.csproj
├── Program.cs
└── Properties
│ └── launchSettings.json
├── OpenXmlToHtmlOpenApi
├── .config
│ └── dotnet-tools.json
├── Azure
│ └── LinuxSpecificContainerSetup.cs
├── Controllers
│ └── OpenXmlConverterController.cs
├── OpenXmlToHtmlOpenApi.csproj
├── OpenXmlToHtmlOpenApi
│ └── OpenXmlToHtmlOpenApi.xml
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Startup.cs
├── appsettings.Development.json
└── appsettings.json
├── OpenXmlToHtmlOpenApiTests
├── .editorconfig
├── AzureTests.cs
├── OpenXmlConverterControllerIntegrativeTests.cs
├── OpenXmlToHtmlOpenApiTests.csproj
├── TestInput
│ └── BasicTextFormated.docx
└── WebApplicationFactory.cs
├── OpenXmlToHtmlTests
├── .editorconfig
├── BreakHandlerAdapterTests.cs
├── ExpectedTestOutcome
│ ├── BasicTextFormated.docx.png
│ ├── EmptyDocument.docx.png
│ ├── Font.docx.png
│ ├── Font.docx.png.diff.linux.png
│ ├── Font.docx.png.diff.win.png
│ ├── Images.docx.png
│ ├── Images.docx.png.diff.linux.png
│ ├── SymbolRibbon.docx.png
│ ├── Symbols.docx.png
│ ├── Wingdings.docx.png
│ └── WingdingsSymbols.docx.png
├── ExportImageHandlerTests.cs
├── OpenXmlToHtmlIntegrationTests.cs
├── OpenXmlToHtmlTests.csproj
├── SymbolHandlerTests.cs
├── TestInfrastructure
│ └── DocumentAsserter.cs
├── TestInput
│ ├── BasicTextFormated.docx
│ ├── EmptyDocument.docx
│ ├── Font.docx
│ ├── Images.docx
│ ├── SymbolRibbon.docx
│ ├── Symbols.docx
│ ├── TestInput.png
│ ├── TwoPages.docx
│ ├── Wingdings.docx
│ └── WingdingsSymbols.pdf
├── TextSymbolToUnicodeHandlerTests.cs
└── WebSafeFontsHandlerTests.cs
├── README.md
├── cla.md
├── signatures
└── version1
│ └── cla.json
└── testenvironments.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories
2 | root = true
3 |
4 | [*.sh]
5 | end_of_line = lf
6 |
7 | # C# files
8 | [*.cs]
9 |
10 | #### Core EditorConfig Options ####
11 |
12 | # Indentation and spacing
13 | indent_size = 4
14 | indent_style = space
15 | tab_width = 4
16 |
17 | # New line preferences
18 | end_of_line = crlf
19 | insert_final_newline = false
20 |
21 | #### .NET Coding Conventions ####
22 |
23 | # Organize usings
24 | dotnet_separate_import_directive_groups = false
25 | dotnet_sort_system_directives_first = false
26 |
27 | # this. and Me. preferences
28 | dotnet_style_qualification_for_event = false:silent
29 | dotnet_style_qualification_for_field = false:silent
30 | dotnet_style_qualification_for_method = false:silent
31 | dotnet_style_qualification_for_property = false:silent
32 |
33 | # Language keywords vs BCL types preferences
34 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent
35 | dotnet_style_predefined_type_for_member_access = true:silent
36 |
37 | # Parentheses preferences
38 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
39 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
40 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
41 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
42 |
43 | # Modifier preferences
44 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
45 |
46 | # Expression-level preferences
47 | dotnet_style_coalesce_expression = true:suggestion
48 | dotnet_style_collection_initializer = true:suggestion
49 | dotnet_style_explicit_tuple_names = true:suggestion
50 | dotnet_style_null_propagation = true:suggestion
51 | dotnet_style_object_initializer = true:suggestion
52 | dotnet_style_prefer_auto_properties = true:silent
53 | dotnet_style_prefer_compound_assignment = true:suggestion
54 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent
55 | dotnet_style_prefer_conditional_expression_over_return = true:silent
56 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
57 | dotnet_style_prefer_inferred_tuple_names = true:suggestion
58 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
59 | dotnet_style_prefer_simplified_interpolation = true:suggestion
60 |
61 | # Field preferences
62 | dotnet_style_readonly_field = true:suggestion
63 |
64 | # Parameter preferences
65 | dotnet_code_quality_unused_parameters = all:suggestion
66 |
67 | #### C# Coding Conventions ####
68 |
69 | # var preferences
70 | csharp_style_var_elsewhere = true:silent
71 | csharp_style_var_for_built_in_types = true:silent
72 | csharp_style_var_when_type_is_apparent = true:silent
73 |
74 | # Expression-bodied members
75 | csharp_style_expression_bodied_accessors = true:silent
76 | csharp_style_expression_bodied_constructors = false:silent
77 | csharp_style_expression_bodied_indexers = true:silent
78 | csharp_style_expression_bodied_lambdas = true:silent
79 | csharp_style_expression_bodied_local_functions = false:silent
80 | csharp_style_expression_bodied_methods = false:silent
81 | csharp_style_expression_bodied_operators = false:silent
82 | csharp_style_expression_bodied_properties = true:silent
83 |
84 | # Pattern matching preferences
85 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
86 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
87 | csharp_style_prefer_switch_expression = true:suggestion
88 |
89 | # Null-checking preferences
90 | csharp_style_conditional_delegate_call = true:suggestion
91 |
92 | # Modifier preferences
93 | csharp_prefer_static_local_function = true:suggestion
94 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
95 |
96 | # Code-block preferences
97 | csharp_prefer_braces = true:warning
98 | csharp_prefer_simple_using_statement = true:suggestion
99 |
100 | # Expression-level preferences
101 | csharp_prefer_simple_default_expression = true:suggestion
102 | csharp_style_deconstructed_variable_declaration = true:suggestion
103 | csharp_style_inlined_variable_declaration = true:suggestion
104 | csharp_style_pattern_local_over_anonymous_function = true:suggestion
105 | csharp_style_prefer_index_operator = true:suggestion
106 | csharp_style_prefer_range_operator = true:suggestion
107 | csharp_style_throw_expression = true:suggestion
108 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion
109 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent
110 |
111 | # 'using' directive preferences
112 | csharp_using_directive_placement = outside_namespace:silent
113 |
114 | #### C# Formatting Rules ####
115 |
116 | # New line preferences
117 | csharp_new_line_before_catch = true
118 | csharp_new_line_before_else = true
119 | csharp_new_line_before_finally = true
120 | csharp_new_line_before_members_in_anonymous_types = true
121 | csharp_new_line_before_members_in_object_initializers = true
122 | csharp_new_line_before_open_brace = all
123 | csharp_new_line_between_query_expression_clauses = true
124 |
125 | # Indentation preferences
126 | csharp_indent_block_contents = true
127 | csharp_indent_braces = false
128 | csharp_indent_case_contents = true
129 | csharp_indent_case_contents_when_block = true
130 | csharp_indent_labels = one_less_than_current
131 | csharp_indent_switch_labels = true
132 |
133 | # Space preferences
134 | csharp_space_after_cast = false
135 | csharp_space_after_colon_in_inheritance_clause = true
136 | csharp_space_after_comma = true
137 | csharp_space_after_dot = false
138 | csharp_space_after_keywords_in_control_flow_statements = true
139 | csharp_space_after_semicolon_in_for_statement = true
140 | csharp_space_around_binary_operators = before_and_after
141 | csharp_space_around_declaration_statements = false
142 | csharp_space_before_colon_in_inheritance_clause = true
143 | csharp_space_before_comma = false
144 | csharp_space_before_dot = false
145 | csharp_space_before_open_square_brackets = false
146 | csharp_space_before_semicolon_in_for_statement = false
147 | csharp_space_between_empty_square_brackets = false
148 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
149 | csharp_space_between_method_call_name_and_opening_parenthesis = false
150 | csharp_space_between_method_call_parameter_list_parentheses = false
151 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
152 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
153 | csharp_space_between_method_declaration_parameter_list_parentheses = false
154 | csharp_space_between_parentheses = false
155 | csharp_space_between_square_brackets = false
156 |
157 | # Wrapping preferences
158 | csharp_preserve_single_line_blocks = true
159 | csharp_preserve_single_line_statements = true
160 |
161 | #### Naming styles ####
162 |
163 | # Naming rules
164 |
165 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
166 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
167 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
168 |
169 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
170 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types
171 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
172 |
173 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
174 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
175 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
176 |
177 | # Symbol specifications
178 |
179 | dotnet_naming_symbols.interface.applicable_kinds = interface
180 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
181 | dotnet_naming_symbols.interface.required_modifiers =
182 |
183 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
184 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
185 | dotnet_naming_symbols.types.required_modifiers =
186 |
187 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
188 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
189 | dotnet_naming_symbols.non_field_members.required_modifiers =
190 |
191 | # Naming styles
192 |
193 | dotnet_naming_style.pascal_case.required_prefix =
194 | dotnet_naming_style.pascal_case.required_suffix =
195 | dotnet_naming_style.pascal_case.word_separator =
196 | dotnet_naming_style.pascal_case.capitalization = pascal_case
197 |
198 | dotnet_naming_style.begins_with_i.required_prefix = I
199 | dotnet_naming_style.begins_with_i.required_suffix =
200 | dotnet_naming_style.begins_with_i.word_separator =
201 | dotnet_naming_style.begins_with_i.capitalization = pascal_case
202 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Lines starting with '#' are comments.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # More details are here: https://help.github.com/articles/about-codeowners/
5 |
6 | # The '*' pattern is global owners.
7 |
8 | # Order is important. The last matching pattern has the most precedence.
9 | # The folders are ordered as follows:
10 |
11 | # In each subsection folders are ordered first by depth, then alphabetically.
12 | # This should make it easy to add new rules without breaking existing ones.
13 |
14 | # Global rule:
15 | * @stesee
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "docker"
4 | directory: "/"
5 | schedule:
6 | interval: weekly
7 | rebase-strategy: auto
8 |
9 | - package-ecosystem: "github-actions"
10 | directory: "/"
11 | schedule:
12 | interval: weekly
13 | rebase-strategy: auto
14 |
15 | - package-ecosystem: "npm"
16 | directory: "/"
17 | schedule:
18 | interval: weekly
19 | rebase-strategy: auto
20 |
21 | - package-ecosystem: "nuget"
22 | directory: "/"
23 | schedule:
24 | interval: "daily"
25 | ignore:
26 | - dependency-name: "nunit"
27 | - dependency-name: "coverlet.collector"
28 | - dependency-name: "SonarAnalyzer.CSharp"
29 | - dependency-name: "AngleSharp"
30 | - dependency-name: "Microsoft.NET.Test.Sdk"
31 | - dependency-name: "Microsoft.AspNetCore.Mvc.Testing"
32 | - dependency-name: "Moq"
33 | - dependency-name: "xunit"
34 | - dependency-name: "xunit.runner.visualstudio"
35 | - dependency-name: "MSTest.TestAdapter"
36 | - dependency-name: "MSTest.TestFramework"
37 | - dependency-name: "Microsoft.AspNetCore.Identity.UI"
38 | - dependency-name: "Microsoft.VisualStudio.Web.CodeGeneration.Design"
39 | - dependency-name: "Codeuctivity.ImageSharpCompare"
40 |
--------------------------------------------------------------------------------
/.github/workflows/cla.yml:
--------------------------------------------------------------------------------
1 | name: "CLA Assistant"
2 | on:
3 | issue_comment:
4 | types: [created]
5 | pull_request_target:
6 | types: [opened,closed,synchronize]
7 |
8 | jobs:
9 | CLAssistant:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: "CLA Assistant"
13 | if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
14 | uses: cla-assistant/github-action@v2.6.1
15 | env:
16 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
17 | # the below token should have repo scope and must be manually added by you in the repository's secret
18 | PERSONAL_ACCESS_TOKEN : ${{ secrets.PERSONAL_ACCESS_TOKEN }}
19 | with:
20 | path-to-signatures: 'signatures/version1/cla.json'
21 | path-to-document: 'https://github.com/Codeuctivity/OpenXmlToHtml/blob/main/cla.md' # e.g. a CLA or a DCO document
22 | # branch should not be protected
23 | branch: 'cla'
24 | allowlist: dependabot[bot],stesee
25 |
26 | #below are the optional inputs - If the optional inputs are not given, then default values will be taken
27 | #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
28 | #remote-repository-name: enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository)
29 | #create-file-commit-message: 'For example: Creating file for storing CLA Signatures'
30 | #signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo'
31 | #custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
32 | #custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
33 | #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
34 | #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
35 | #use-dco-flag: true - If you are using DCO instead of CLA
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | name: .NET build and test
2 | env:
3 | CURRENT_VERSION: 2.0.${{ github.run_number }}
4 | LAST_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
5 |
6 | on:
7 | push:
8 | pull_request:
9 |
10 | jobs:
11 | build:
12 | runs-on: ${{ matrix.os }}
13 | strategy:
14 | matrix:
15 | os: [ubuntu-latest, windows-latest]
16 | steps:
17 | - uses: actions/checkout@v4
18 | - name: Setup .NET
19 | uses: actions/setup-dotnet@v4
20 | with:
21 | dotnet-version: 8.0.x
22 | - name: Restore dependencies
23 | run: dotnet restore
24 | - name: Build
25 | run: dotnet build --configuration Release --no-restore
26 | - name: Test
27 | run: dotnet test --no-build --verbosity normal --configuration Release
28 | - name: Publish Unit Test Results
29 | uses: actions/upload-artifact@v4
30 | if: failure()
31 | with:
32 | name: TestResult
33 | path: "TestResult/**/*"
34 |
35 | deployRelease:
36 | if: ${{ github.ref == 'refs/heads/release' }}
37 | runs-on: windows-latest
38 | needs: build
39 | steps:
40 | - uses: actions/checkout@v4
41 | - name: Setup .NET
42 | uses: actions/setup-dotnet@v4
43 | with:
44 | dotnet-version: 8.0.x
45 | - name: Restore dependencies
46 | run: dotnet restore
47 | - name: Build
48 | run: |
49 | dotnet build --configuration Release --no-restore
50 | dotnet publish ./OpenXmlToHtmlOpenApi -c Release /p:WebPublishMethod=Package
51 | dotnet publish ./OpenXmlToHtmlCli -c Release
52 | - name: Zip
53 | uses: thedoctor0/zip-release@main
54 | with:
55 | path: .\OpenXmlToHtmlCli\bin\Release\net8.0\win-x64\publish
56 | type: 'zip'
57 | filename: 'OpenXmlToHtmlCli.zip'
58 | - name: NugetPush
59 | env:
60 | NUGET_TOKEN_EXISTS: ${{ secrets.NUGET_TOKEN }}
61 | if: env.NUGET_TOKEN_EXISTS != ''
62 | run: |
63 | dotnet nuget push .\OpenXmlToHtml\bin\Release\*.nupkg --skip-duplicate --api-key ${{secrets.NUGET_TOKEN}} --source https://api.nuget.org/v3/index.json
64 | - name: Github Prelease
65 | shell: bash
66 | env:
67 | GITHUB_TOKEN: ${{ github.TOKEN }}
68 | if: env.GITHUB_TOKEN != ''
69 | run: |
70 | gh release create ${{env.CURRENT_VERSION}} ./OpenXmlToHtmlOpenApi/bin/Release/net8.0/OpenXmlToHtmlOpenApi.zip ./OpenXmlToHtmlCli.zip ./OpenXmlToHtml/bin/Release/*.*nupkg --generate-notes
71 |
72 |
73 | deployTest:
74 | if: ${{ github.ref == 'refs/heads/main' }}
75 | runs-on: windows-latest
76 | needs: build
77 | steps:
78 | - uses: actions/checkout@v4
79 | - name: Setup .NET
80 | uses: actions/setup-dotnet@v4
81 | with:
82 | dotnet-version: 8.0.x
83 | - name: Restore dependencies
84 | run: dotnet restore
85 | - name: Build
86 | run: |
87 | dotnet build --configuration Release --no-restore
88 | dotnet publish ./OpenXmlToHtmlOpenApi -c Release /p:WebPublishMethod=Package
89 | dotnet publish ./OpenXmlToHtmlCli -c Release
90 | - name: Zip
91 | uses: thedoctor0/zip-release@main
92 | with:
93 | path: .\OpenXmlToHtmlCli\bin\Release\net8.0\win-x64\publish
94 | type: 'zip'
95 | filename: 'OpenXmlToHtmlCli.zip'
96 | - name: NugetPush
97 | env:
98 | NUGET_TOKEN_EXISTS: ${{ secrets.NUGET_TEST_TOKEN }}
99 | if: env.NUGET_TOKEN_EXISTS != ''
100 | run: |
101 | dotnet nuget push .\OpenXmlToHtml\bin\Release\*.nupkg --skip-duplicate --api-key ${{secrets.NUGET_TEST_TOKEN}} --source https://apiint.nugettest.org/v3/index.json
102 | - name: Github Prelease
103 | shell: bash
104 | env:
105 | GITHUB_TOKEN: ${{ github.TOKEN }}
106 | if: env.GITHUB_TOKEN != ''
107 | run: |
108 | gh release create ${{env.CURRENT_VERSION}} ./OpenXmlToHtmlOpenApi/bin/Release/net8.0/OpenXmlToHtmlOpenApi.zip ./OpenXmlToHtmlCli.zip ./OpenXmlToHtml/bin/Release/*.*nupkg --prerelease --generate-notes
109 |
110 | deployAzure:
111 | if: ${{ github.ref == 'refs/heads/release' || github.ref == 'refs/heads/AzureAppPublishUsingGithubActions'}}
112 | runs-on: ubuntu-latest
113 | needs: build
114 | steps:
115 | - uses: actions/checkout@v4
116 | - name: Setup .NET
117 | uses: actions/setup-dotnet@v4
118 | with:
119 | dotnet-version: 8.0.x
120 | - name: Restore dependencies
121 | run: dotnet restore
122 | - name: Build
123 | run: dotnet build --configuration Release --no-restore
124 | - name: Publish
125 | run: dotnet publish ./OpenXmlToHtmlOpenApi/OpenXmlToHtmlOpenApi.csproj --configuration Release -o ./Publish
126 | - uses: azure/webapps-deploy@v3
127 | with:
128 | publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
129 | package: './Publish'
130 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | # This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
2 | #
3 | # You can adjust the behavior by modifying this file.
4 | # For more information, see:
5 | # https://github.com/actions/stale
6 | name: Mark stale issues and pull requests
7 |
8 | on:
9 | schedule:
10 | - cron: '44 1 * * *'
11 |
12 | jobs:
13 | stale:
14 |
15 | runs-on: ubuntu-latest
16 | permissions:
17 | issues: write
18 | pull-requests: write
19 |
20 | steps:
21 | - uses: actions/stale@v9
22 | with:
23 | repo-token: ${{ secrets.GITHUB_TOKEN }}
24 | stale-issue-message: 'Stale issue message'
25 | stale-pr-message: 'Stale pull request message'
26 | stale-issue-label: 'no-issue-activity'
27 | stale-pr-label: 'no-pr-activity'
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # JustCode is a .NET coding add-in
131 | .JustCode
132 |
133 | # TeamCity is a build add-in
134 | _TeamCity*
135 |
136 | # DotCover is a Code Coverage Tool
137 | *.dotCover
138 |
139 | # AxoCover is a Code Coverage Tool
140 | .axoCover/*
141 | !.axoCover/settings.json
142 |
143 | # Visual Studio code coverage results
144 | *.coverage
145 | *.coveragexml
146 |
147 | # NCrunch
148 | _NCrunch_*
149 | .*crunch*.local.xml
150 | nCrunchTemp_*
151 |
152 | # MightyMoose
153 | *.mm.*
154 | AutoTest.Net/
155 |
156 | # Web workbench (sass)
157 | .sass-cache/
158 |
159 | # Installshield output folder
160 | [Ee]xpress/
161 |
162 | # DocProject is a documentation generator add-in
163 | DocProject/buildhelp/
164 | DocProject/Help/*.HxT
165 | DocProject/Help/*.HxC
166 | DocProject/Help/*.hhc
167 | DocProject/Help/*.hhk
168 | DocProject/Help/*.hhp
169 | DocProject/Help/Html2
170 | DocProject/Help/html
171 |
172 | # Click-Once directory
173 | publish/
174 |
175 | # Publish Web Output
176 | *.[Pp]ublish.xml
177 | *.azurePubxml
178 | # Note: Comment the next line if you want to checkin your web deploy settings,
179 | # but database connection strings (with potential passwords) will be unencrypted
180 | *.pubxml
181 | *.publishproj
182 |
183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
184 | # checkin your Azure Web App publish settings, but sensitive information contained
185 | # in these scripts will be unencrypted
186 | PublishScripts/
187 |
188 | # NuGet Packages
189 | *.nupkg
190 | # NuGet Symbol Packages
191 | *.snupkg
192 | # The packages folder can be ignored because of Package Restore
193 | **/[Pp]ackages/*
194 | # except build/, which is used as an MSBuild target.
195 | !**/[Pp]ackages/build/
196 | # Uncomment if necessary however generally it will be regenerated when needed
197 | #!**/[Pp]ackages/repositories.config
198 | # NuGet v3's project.json files produces more ignorable files
199 | *.nuget.props
200 | *.nuget.targets
201 |
202 | # Microsoft Azure Build Output
203 | csx/
204 | *.build.csdef
205 |
206 | # Microsoft Azure Emulator
207 | ecf/
208 | rcf/
209 |
210 | # Windows Store app package directories and files
211 | AppPackages/
212 | BundleArtifacts/
213 | Package.StoreAssociation.xml
214 | _pkginfo.txt
215 | *.appx
216 | *.appxbundle
217 | *.appxupload
218 |
219 | # Visual Studio cache files
220 | # files ending in .cache can be ignored
221 | *.[Cc]ache
222 | # but keep track of directories ending in .cache
223 | !?*.[Cc]ache/
224 |
225 | # Others
226 | ClientBin/
227 | ~$*
228 | *~
229 | *.dbmdl
230 | *.dbproj.schemaview
231 | *.jfm
232 | *.pfx
233 | *.publishsettings
234 | orleans.codegen.cs
235 |
236 | # Including strong name files can present a security risk
237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
238 | #*.snk
239 |
240 | # Since there are multiple workflows, uncomment next line to ignore bower_components
241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
242 | #bower_components/
243 |
244 | # RIA/Silverlight projects
245 | Generated_Code/
246 |
247 | # Backup & report files from converting an old project file
248 | # to a newer Visual Studio version. Backup files are not needed,
249 | # because we have git ;-)
250 | _UpgradeReport_Files/
251 | Backup*/
252 | UpgradeLog*.XML
253 | UpgradeLog*.htm
254 | ServiceFabricBackup/
255 | *.rptproj.bak
256 |
257 | # SQL Server files
258 | *.mdf
259 | *.ldf
260 | *.ndf
261 |
262 | # Business Intelligence projects
263 | *.rdl.data
264 | *.bim.layout
265 | *.bim_*.settings
266 | *.rptproj.rsuser
267 | *- [Bb]ackup.rdl
268 | *- [Bb]ackup ([0-9]).rdl
269 | *- [Bb]ackup ([0-9][0-9]).rdl
270 |
271 | # Microsoft Fakes
272 | FakesAssemblies/
273 |
274 | # GhostDoc plugin setting file
275 | *.GhostDoc.xml
276 |
277 | # Node.js Tools for Visual Studio
278 | .ntvs_analysis.dat
279 | node_modules/
280 |
281 | # Visual Studio 6 build log
282 | *.plg
283 |
284 | # Visual Studio 6 workspace options file
285 | *.opt
286 |
287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
288 | *.vbw
289 |
290 | # Visual Studio LightSwitch build output
291 | **/*.HTMLClient/GeneratedArtifacts
292 | **/*.DesktopClient/GeneratedArtifacts
293 | **/*.DesktopClient/ModelManifest.xml
294 | **/*.Server/GeneratedArtifacts
295 | **/*.Server/ModelManifest.xml
296 | _Pvt_Extensions
297 |
298 | # Paket dependency manager
299 | .paket/paket.exe
300 | paket-files/
301 |
302 | # FAKE - F# Make
303 | .fake/
304 |
305 | # CodeRush personal settings
306 | .cr/personal
307 |
308 | # Python Tools for Visual Studio (PTVS)
309 | __pycache__/
310 | *.pyc
311 |
312 | # Cake - Uncomment if you are using it
313 | # tools/**
314 | # !tools/packages.config
315 |
316 | # Tabs Studio
317 | *.tss
318 |
319 | # Telerik's JustMock configuration file
320 | *.jmconfig
321 |
322 | # BizTalk build output
323 | *.btp.cs
324 | *.btm.cs
325 | *.odx.cs
326 | *.xsd.cs
327 |
328 | # OpenCover UI analysis results
329 | OpenCover/
330 |
331 | # Azure Stream Analytics local run output
332 | ASALocalRun/
333 |
334 | # MSBuild Binary and Structured Log
335 | *.binlog
336 |
337 | # NVidia Nsight GPU debugger configuration file
338 | *.nvuser
339 |
340 | # MFractors (Xamarin productivity tool) working folder
341 | .mfractor/
342 |
343 | # Local History for Visual Studio
344 | .localhistory/
345 |
346 | # BeatPulse healthcheck temp database
347 | healthchecksdb
348 |
349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
350 | MigrationBackup/
351 |
352 | # Ionide (cross platform F# VS Code tools) working folder
353 | .ionide/
354 | OpenXmlToHtmlOpenApi/.local-chromium
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-dotnettools.csharp"
4 | ]
5 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to find out which attributes exist for C# debugging
3 | // Use hover for the description of the existing attributes
4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "OpenXmlToHtmlOpenApi",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | "program": "${workspaceFolder}/bin/Debug/net5/OpenXmlToHtmlOpenApi.dll",
13 | "args": [],
14 | "cwd": "${workspaceFolder}",
15 | "stopAtEntry": false,
16 | "serverReadyAction": {
17 | "action": "openExternally",
18 | "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
19 | },
20 | "env": {
21 | "ASPNETCORE_ENVIRONMENT": "Development"
22 | },
23 | "sourceFileMap": {
24 | "/Views": "${workspaceFolder}/Views"
25 | }
26 | },
27 | {
28 | "name": ".NET Core Attach",
29 | "type": "coreclr",
30 | "request": "attach",
31 | "processId": "${command:pickProcess}"
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "Codacy",
4 | "Codeuctivity",
5 | "Nuget",
6 | "Nunit",
7 | "Rasterized",
8 | "Rgba",
9 | "nupkg",
10 | "snupkg"
11 | ],
12 | "editor.formatOnSave": true
13 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/OpenXmlToHtmlTests/OpenXmlToHtmlTests.csproj",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | },
16 | {
17 | "label": "publish",
18 | "command": "dotnet",
19 | "type": "process",
20 | "args": [
21 | "publish",
22 | "${workspaceFolder}/OpenXmlToHtmlTests/OpenXmlToHtmlTests.csproj",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "problemMatcher": "$msCompile"
27 | },
28 | {
29 | "label": "watch",
30 | "command": "dotnet",
31 | "type": "process",
32 | "args": [
33 | "watch",
34 | "run",
35 | "${workspaceFolder}/OpenXmlToHtmlTests/OpenXmlToHtmlTests.csproj",
36 | "/property:GenerateFullPaths=true",
37 | "/consoleloggerparameters:NoSummary"
38 | ],
39 | "problemMatcher": "$msCompile"
40 | },
41 | {
42 | "label": "update nuget",
43 | "command": "${workspaceFolder}/.vscode/updateNuget.sh",
44 | "args": [],
45 | "group": "build",
46 | "presentation": {
47 | "reveal": "always"
48 | },
49 | "problemMatcher": "$msCompile"
50 | }
51 | ]
52 | }
53 |
--------------------------------------------------------------------------------
/.vscode/updateNuget.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | regex='PackageReference Include="([^"]*)" Version="([^"]*)"'
3 | find . -name "*.*proj" | while read proj; do
4 | while read line; do
5 | if [[ $line =~ $regex ]]; then
6 | name="${BASH_REMATCH[1]}"
7 | version="${BASH_REMATCH[2]}"
8 | if [[ $version != *-* ]]; then
9 | dotnet add "$proj" package "$name"
10 | fi
11 | fi
12 | done <"$proj"
13 | done
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/OpenXmlToHtml.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32526.322
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlToHtml", "OpenXmlToHtml\OpenXmlToHtml.csproj", "{D3FE5D0D-4ED4-41D4-B3EF-116F5140B1CB}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FC3F4498-FA14-48A8-AA41-8D9095A0844F}"
9 | ProjectSection(SolutionItems) = preProject
10 | .editorconfig = .editorconfig
11 | cla.md = cla.md
12 | .github\workflows\cla.yml = .github\workflows\cla.yml
13 | .github\dependabot.yml = .github\dependabot.yml
14 | .github\workflows\dotnet.yml = .github\workflows\dotnet.yml
15 | README.md = README.md
16 | .github\workflows\stale.yml = .github\workflows\stale.yml
17 | EndProjectSection
18 | EndProject
19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlToHtmlTests", "OpenXmlToHtmlTests\OpenXmlToHtmlTests.csproj", "{A1A7AF98-904A-4B85-B9FF-3DC985DEA382}"
20 | EndProject
21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlToHtmlCli", "OpenXmlToHtmlCli\OpenXmlToHtmlCli.csproj", "{BE60CFAD-B5B5-40AE-B459-8AB75886E717}"
22 | EndProject
23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlToHtmlOpenApi", "OpenXmlToHtmlOpenApi\OpenXmlToHtmlOpenApi.csproj", "{292B4D3E-0821-4907-A875-52DF1BE21DE9}"
24 | EndProject
25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenXmlToHtmlOpenApiTests", "OpenXmlToHtmlOpenApiTests\OpenXmlToHtmlOpenApiTests.csproj", "{B07C63A5-87D2-4620-BD60-04073AED6AC0}"
26 | EndProject
27 | Global
28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
29 | Debug|Any CPU = Debug|Any CPU
30 | Release|Any CPU = Release|Any CPU
31 | EndGlobalSection
32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
33 | {D3FE5D0D-4ED4-41D4-B3EF-116F5140B1CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
34 | {D3FE5D0D-4ED4-41D4-B3EF-116F5140B1CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
35 | {D3FE5D0D-4ED4-41D4-B3EF-116F5140B1CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {D3FE5D0D-4ED4-41D4-B3EF-116F5140B1CB}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {A1A7AF98-904A-4B85-B9FF-3DC985DEA382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {A1A7AF98-904A-4B85-B9FF-3DC985DEA382}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {A1A7AF98-904A-4B85-B9FF-3DC985DEA382}.Release|Any CPU.ActiveCfg = Release|Any CPU
40 | {A1A7AF98-904A-4B85-B9FF-3DC985DEA382}.Release|Any CPU.Build.0 = Release|Any CPU
41 | {BE60CFAD-B5B5-40AE-B459-8AB75886E717}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
42 | {BE60CFAD-B5B5-40AE-B459-8AB75886E717}.Debug|Any CPU.Build.0 = Debug|Any CPU
43 | {BE60CFAD-B5B5-40AE-B459-8AB75886E717}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {BE60CFAD-B5B5-40AE-B459-8AB75886E717}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {292B4D3E-0821-4907-A875-52DF1BE21DE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
46 | {292B4D3E-0821-4907-A875-52DF1BE21DE9}.Debug|Any CPU.Build.0 = Debug|Any CPU
47 | {292B4D3E-0821-4907-A875-52DF1BE21DE9}.Release|Any CPU.ActiveCfg = Release|Any CPU
48 | {292B4D3E-0821-4907-A875-52DF1BE21DE9}.Release|Any CPU.Build.0 = Release|Any CPU
49 | {B07C63A5-87D2-4620-BD60-04073AED6AC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50 | {B07C63A5-87D2-4620-BD60-04073AED6AC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
51 | {B07C63A5-87D2-4620-BD60-04073AED6AC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
52 | {B07C63A5-87D2-4620-BD60-04073AED6AC0}.Release|Any CPU.Build.0 = Release|Any CPU
53 | EndGlobalSection
54 | GlobalSection(SolutionProperties) = preSolution
55 | HideSolutionNode = FALSE
56 | EndGlobalSection
57 | GlobalSection(ExtensibilityGlobals) = postSolution
58 | SolutionGuid = {A194188E-5DA7-498B-A165-1250B4A43640}
59 | EndGlobalSection
60 | EndGlobal
61 |
--------------------------------------------------------------------------------
/OpenXmlToHtml/ExportImageHandler.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools;
2 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Xml.Linq;
7 |
8 | namespace Codeuctivity.OpenXmlToHtml
9 | {
10 | ///
11 | /// Exports every image of an Open XML
12 | ///
13 | public class ExportImageHandler : IImageHandler
14 | {
15 | ///
16 | /// Images of Open XML
17 | ///
18 | public IDictionary Images { get; }
19 |
20 | ///
21 | /// Transforms OpenXml Images to HTML embeddable images
22 | ///
23 | ///
24 | public ExportImageHandler(IDictionary images)
25 | {
26 | Images = images;
27 | }
28 |
29 | ///
30 | /// Transforms images to Content-ID based embedded value
31 | ///
32 | ///
33 | ///
34 | public XElement TransformImage(ImageInfo imageInfo)
35 | {
36 | var cid = Guid.NewGuid().ToString();
37 | using var memoryStream = new MemoryStream();
38 | imageInfo.Image.CopyTo(memoryStream);
39 |
40 | Images.Add(cid, memoryStream.ToArray());
41 |
42 | var cidReference = $"cid: {cid}";
43 |
44 | return new XElement(Xhtml.img, new XAttribute(NoNamespace.src, cidReference), imageInfo.ImgStyleAttribute, imageInfo?.AltText != null ? new XAttribute(NoNamespace.alt, imageInfo.AltText) : null);
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/IOpenXmlToHtml.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Threading.Tasks;
3 |
4 | namespace Codeuctivity.OpenXmlToHtml
5 | {
6 | ///
7 | /// Converts DOCX to HTML
8 | ///
9 | public interface IOpenXmlToHtml
10 | {
11 | ///
12 | /// Converts DOCX to HTML
13 | ///
14 | ///
15 | ///
16 | /// selfContainedHtmlFilePath
17 | Task ConvertToHtmlAsync(string sourceOpenXmlFilePath, string destinationHtmlFilePath);
18 |
19 | ///
20 | /// Converts DOCX to HTML
21 | ///
22 | ///
23 | ///
24 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
25 | /// selfContainedHtmlFilePath
26 | Task ConvertToHtmlAsync(string sourceOpenXmlFilePath, string destinationHtmlFilePath, bool useWebSafeFonts);
27 |
28 | ///
29 | /// Converts DOCX to HTML
30 | ///
31 | ///
32 | /// selfContainedHtml
33 | Task ConvertToHtmlAsync(Stream sourceOpenXml);
34 |
35 | ///
36 | /// Converts DOCX to HTML
37 | ///
38 | ///
39 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
40 | /// selfContainedHtml
41 | Task ConvertToHtmlAsync(Stream sourceOpenXml, bool useWebSafeFonts);
42 |
43 | ///
44 | /// Converts DOCX to HTML
45 | ///
46 | ///
47 | ///
48 | /// selfContainedHtml
49 | Task ConvertToHtmlAsync(Stream sourceOpenXml, string fallbackPageTitle);
50 |
51 | ///
52 | /// Converts DOCX to HTML
53 | ///
54 | ///
55 | ///
56 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
57 | /// selfContainedHtml
58 | Task ConvertToHtmlAsync(Stream sourceOpenXml, string fallbackPageTitle, bool useWebSafeFonts);
59 | }
60 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/NugetIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtml/NugetIcon.png
--------------------------------------------------------------------------------
/OpenXmlToHtml/OpenXmlToHtml.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools;
2 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
3 | using DocumentFormat.OpenXml.Packaging;
4 |
5 | using System;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Threading.Tasks;
10 | using System.Xml.Linq;
11 |
12 | namespace Codeuctivity.OpenXmlToHtml
13 | {
14 | ///
15 | /// Converts DOCX to HTML
16 | ///
17 | public class OpenXmlToHtml : IOpenXmlToHtml
18 | {
19 | ///
20 | /// Converts DOCX to HTML
21 | ///
22 | ///
23 | ///
24 | /// selfContainedHtmlFilePath
25 | public Task ConvertToHtmlAsync(string sourceOpenXmlFilePath, string destinationHtmlFilePath)
26 | {
27 | return ConvertToHtmlAsync(sourceOpenXmlFilePath, destinationHtmlFilePath, false);
28 | }
29 |
30 | ///
31 | /// Converts DOCX to HTML
32 | ///
33 | ///
34 | ///
35 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
36 | /// selfContainedHtmlFilePath
37 | public async Task ConvertToHtmlAsync(string sourceOpenXmlFilePath, string destinationHtmlFilePath, bool useWebSafeFonts)
38 | {
39 | if (!File.Exists(sourceOpenXmlFilePath))
40 | {
41 | throw new FileNotFoundException(sourceOpenXmlFilePath);
42 | }
43 |
44 | using var sourceIpenXml = new FileStream(sourceOpenXmlFilePath, FileMode.Open, FileAccess.Read);
45 | using var html = await ConvertToHtmlAsync(sourceIpenXml, sourceOpenXmlFilePath, useWebSafeFonts).ConfigureAwait(false);
46 | using var destinationHtmlFile = new FileStream(destinationHtmlFilePath, FileMode.CreateNew, FileAccess.Write);
47 | await html.CopyToAsync(destinationHtmlFile).ConfigureAwait(false);
48 | }
49 |
50 | ///
51 | /// Converts DOCX to HTML
52 | ///
53 | ///
54 | /// selfContainedHtml
55 | public Task ConvertToHtmlAsync(Stream sourceOpenXml)
56 | {
57 | return ConvertToHtmlAsync(sourceOpenXml, false);
58 | }
59 |
60 | ///
61 | /// Converts DOCX to HTML
62 | ///
63 | ///
64 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
65 | /// selfContainedHtml
66 | public Task ConvertToHtmlAsync(Stream sourceOpenXml, bool useWebSafeFonts)
67 | {
68 | return ConvertToHtmlAsync(sourceOpenXml, string.Empty, useWebSafeFonts);
69 | }
70 |
71 | ///
72 | /// Converts DOCX to HTML
73 | ///
74 | ///
75 | ///
76 | /// selfContainedHtml
77 | public Task ConvertToHtmlAsync(Stream sourceOpenXml, string fallbackPageTitle)
78 | {
79 | return ConvertToHtmlAsync(sourceOpenXml, fallbackPageTitle, false);
80 | }
81 |
82 | ///
83 | /// Converts DOCX to HTML
84 | ///
85 | ///
86 | ///
87 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
88 | /// selfContainedHtml
89 | public Task ConvertToHtmlAsync(Stream sourceOpenXml, string fallbackPageTitle, bool useWebSafeFonts)
90 | {
91 | if (sourceOpenXml == null)
92 | {
93 | throw new ArgumentNullException(nameof(sourceOpenXml));
94 | }
95 |
96 | return ConvertToHtmlInternalAsync(sourceOpenXml, fallbackPageTitle, new ImageHandler(), useWebSafeFonts);
97 | }
98 |
99 | ///
100 | /// Converts DOCX to HTML
101 | ///
102 | ///
103 | ///
104 | ///
105 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
106 | /// selfContainedHtml
107 | public static Task ConvertToHtmlAsync(Stream sourceOpenXml, string fallbackPageTitle, IDictionary images, bool useWebSafeFonts)
108 | {
109 | if (sourceOpenXml == null)
110 | {
111 | throw new ArgumentNullException(nameof(sourceOpenXml));
112 | }
113 |
114 | return ConvertToHtmlInternalAsync(sourceOpenXml, fallbackPageTitle, new ExportImageHandler(images), useWebSafeFonts);
115 | }
116 |
117 | private static async Task ConvertToHtmlInternalAsync(Stream sourceOpenXml, string fallbackPageTitle, IImageHandler imageHandler, bool useWebSafeFonts)
118 | {
119 | using var memoryStream = new MemoryStream();
120 | await sourceOpenXml.CopyToAsync(memoryStream).ConfigureAwait(false);
121 | sourceOpenXml = memoryStream;
122 |
123 | using var wordProcessingDocument = WordprocessingDocument.Open(sourceOpenXml, true);
124 | var coreFilePropertiesPart = wordProcessingDocument.CoreFilePropertiesPart;
125 | var computedPageTitle = coreFilePropertiesPart?.GetXDocument().Descendants(DC.title).FirstOrDefault();
126 | var pageTitle = string.IsNullOrEmpty(computedPageTitle?.Value) ? fallbackPageTitle : computedPageTitle!.Value;
127 |
128 | var htmlElement = WmlToHtmlConverter.ConvertToHtml(wordProcessingDocument, CreateHtmlConverterSettings(pageTitle, imageHandler, useWebSafeFonts ? new WebSafeFontsHandler() : new FontHandler()));
129 | var html = new XDocument(new XDocumentType("html", "-//W3C//DTD XHTML 1.1//EN", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd", null), htmlElement);
130 | var memoryStreamHtml = new MemoryStream();
131 | html.Save(memoryStreamHtml, SaveOptions.DisableFormatting);
132 | memoryStreamHtml.Position = 0;
133 | return memoryStreamHtml;
134 | }
135 |
136 | private static WmlToHtmlConverterSettings CreateHtmlConverterSettings(string pageTitle, IImageHandler imageHandler, IFontHandler fontHandler)
137 | {
138 | var settings = new WmlToHtmlConverterSettings(pageTitle, imageHandler, new TextSymbolToUnicodeHandler(), new SymbolHandler(), new PageBreakHandler(new BreakHandler()), fontHandler, true, string.Empty, "@page { size: A4 } body { margin: 1cm auto; max-width: 20cm; padding: 0; }", "Codeuctivity-");
139 |
140 | return settings;
141 | }
142 | }
143 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/OpenXmlToHtml.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | true
5 | true
6 | https://github.com/Codeuctivity/OpenXmlToHtml
7 | openxml docx html
8 | Stefan Seeland
9 | Codeuctivity
10 | $(CURRENT_VERSION)
11 | 0.0.1
12 | $(Version)
13 | $(Version)
14 | $(Version)-prerelease
15 | $(LAST_COMMIT_MESSAGE)
16 | NugetIcon.png
17 | https://github.com/Codeuctivity/OpenXmlToHtml
18 | Converts docx to html without the need to setup any dependency
19 | Apache-2.0
20 | true
21 | OpenXmlToHtml.snk
22 | true
23 | true
24 | snupkg
25 | true
26 | true
27 | 9.0
28 | enable
29 | Codeuctivity.OpenXmlToHtml
30 | nugetReadme.md
31 | OpenXmlToHtml
32 | Codeuctivity.OpenXmlToHtml
33 | Codeuctivity.OpenXmlToHtml
34 | true
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | all
47 | runtime; build; native; contentfiles; analyzers; buildtransitive
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/OpenXmlToHtml/OpenXmlToHtml.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtml/OpenXmlToHtml.snk
--------------------------------------------------------------------------------
/OpenXmlToHtml/PageBreakHandler.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools;
2 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
3 | using System.Collections.Generic;
4 | using System.Xml.Linq;
5 |
6 | namespace Codeuctivity.OpenXmlToHtml
7 | {
8 | ///
9 | ///
10 | ///
11 | public class PageBreakHandler : IBreakHandler
12 | {
13 | ///
14 | /// DefaultBreakHandler is used if TransformBreak is not applied to a page break
15 | ///
16 | public IBreakHandler DefaultBreakHandler { get; }
17 |
18 | ///
19 | ///
20 | ///
21 | ///
22 | public PageBreakHandler(IBreakHandler defaultBreakHandler)
23 | {
24 | DefaultBreakHandler = defaultBreakHandler;
25 | }
26 |
27 | ///
28 | /// Default handler that transforms breaks into some HTML specific equivalent
29 | ///
30 | ///
31 | ///
32 | public IEnumerable TransformBreak(XElement element)
33 | {
34 | if (element.Attribute(W.type)?.Value == "page")
35 | {
36 | var pageBreakDiv = new XElement(Xhtml.div);
37 | pageBreakDiv.Add(new XAttribute(H.Style, "break-before: page;"));
38 | return new XNode[] { pageBreakDiv };
39 | }
40 |
41 | return DefaultBreakHandler.TransformBreak(element);
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/SymbolHandler.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools;
2 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
3 | using System.Collections.Generic;
4 | using System.Xml.Linq;
5 |
6 | namespace Codeuctivity.OpenXmlToHtml
7 | {
8 | ///
9 | /// Handler that transforms every symbol into some HTML encoded font specific char
10 | ///
11 | public class SymbolHandler : ISymbolHandler
12 | {
13 | private OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter.SymbolHandler DefaultSymbolHandler { get; set; }
14 |
15 | ///
16 | /// Dictionary codes from symbol char to Unicode
17 | ///
18 | public static Dictionary SymbolCharDictonary => new Dictionary
19 | {
20 | {"F020"," "},
21 | {"F021","!"},
22 | {"F022","∀"},
23 | {"F023","#"},
24 | {"F024","∃"},
25 | {"F025","%"},
26 | {"F026","&"},
27 | {"F027","∋"},
28 | {"F028","("},
29 | {"F029",")"},
30 | {"F02A","*"},
31 | {"F02B","+"},
32 | {"F02C",","},
33 | {"F02D","-"},
34 | {"F02E","."},
35 | {"F02F","/"},
36 | {"F030","0"},
37 | {"F031","1"},
38 | {"F032","2"},
39 | {"F033","3"},
40 | {"F034","4"},
41 | {"F035","5"},
42 | {"F036","6"},
43 | {"F037","7"},
44 | {"F038","8"},
45 | {"F039","9"},
46 | {"F03A",":"},
47 | {"F03B",";"},
48 | {"F03C","<"},
49 | {"F03D","="},
50 | {"F03E",">"},
51 | {"F03F","?"},
52 | {"F040","≅"},
53 | {"F041","A"},
54 | {"F042","B"},
55 | {"F043","X"},
56 | {"F044","Δ"},
57 | {"F045","E"},
58 | {"F046","Φ"},
59 | {"F047","Γ"},
60 | {"F048","H"},
61 | {"F049","I"},
62 | {"F04A","ϑ"},
63 | {"F04B","K"},
64 | {"F04C","∧"},
65 | {"F04D","M"},
66 | {"F04E","N"},
67 | {"F04F","O"},
68 | {"F050","Π"},
69 | {"F051","Θ"},
70 | {"F052","P"},
71 | {"F053","∑"},
72 | {"F054","T"},
73 | {"F055","Y"},
74 | {"F056","Z"},
75 | {"F057","Ω"},
76 | {"F058","Ξ"},
77 | {"F059","Ψ"},
78 | {"F05A","Z"},
79 | {"F05B","["},
80 | {"F05C","∴"},
81 | {"F05D","]"},
82 | {"F05E","⊥"},
83 | {"F05F","_"},
84 | // Not sure, but I think that overline has a context specific effect on the following char
85 | {"F060","\u0305"},
86 | {"F061","α"},
87 | {"F062","β"},
88 | {"F063","χ"},
89 | {"F064","δ"},
90 | {"F065","ε"},
91 | {"F066","ϕ"},
92 | {"F067","γ"},
93 | {"F068","η"},
94 | {"F069","ι"},
95 | {"F06A","φ"},
96 | {"F06B","κ"},
97 | {"F06C","λ"},
98 | {"F06D","μ"},
99 | {"F06E","ν"},
100 | {"F06F","ο"},
101 | {"F070","π"},
102 | {"F071","θ"},
103 | {"F072","ρ"},
104 | {"F073","σ"},
105 | {"F074","τ"},
106 | {"F075","υ"},
107 | {"F076","ϖ"},
108 | {"F077","ω"},
109 | {"F078","ξ"},
110 | {"F079","ψ"},
111 | {"F07A","ζ"},
112 | {"F07B","{"},
113 | {"F07C","|"},
114 | {"F07D","}"},
115 | {"F07E","∼"},
116 | {"F07F","□"},
117 | {"F080","□"},
118 | {"F081","□"},
119 | {"F082","□"},
120 | {"F083","□"},
121 | {"F084","□"},
122 | {"F085","□"},
123 | {"F086","□"},
124 | {"F087","□"},
125 | {"F088","□"},
126 | {"F089","□"},
127 | {"F08A","□"},
128 | {"F08B","□"},
129 | {"F08C","□"},
130 | {"F08D","□"},
131 | {"F08E","□"},
132 | {"F08F","□"},
133 | {"F090","□"},
134 | {"F091","□"},
135 | {"F092","□"},
136 | {"F093","□"},
137 | {"F094","□"},
138 | {"F095","□"},
139 | {"F096","□"},
140 | {"F097","□"},
141 | {"F098","□"},
142 | {"F099","□"},
143 | {"F09A","□"},
144 | {"F09B","□"},
145 | {"F09C","□"},
146 | {"F09D","□"},
147 | {"F09E","□"},
148 | {"F09F","□"},
149 | {"F0A0","□"},
150 | {"F0A1","ϒ"},
151 | {"F0A2","′"},
152 | {"F0A3","≤"},
153 | {"F0A4","∞"},
154 | {"F0A5","⁄"},
155 | {"F0A6","ƒ"},
156 | {"F0A7","♣"},
157 | {"F0A8","♦"},
158 | {"F0A9","♥"},
159 | {"F0AA","♠"},
160 | {"F0AB","↔"},
161 | {"F0AC","←"},
162 | {"F0AD","↑"},
163 | {"F0AE","→"},
164 | {"F0AF","↓"},
165 | {"F0B0","°"},
166 | {"F0B1","±"},
167 | {"F0B2","″"},
168 | {"F0B3","≥"},
169 | {"F0B4","×"},
170 | {"F0B5","∝"},
171 | {"F0B6","∂"},
172 | {"F0B7","•"},
173 | {"F0B8","÷"},
174 | {"F0B9","≠"},
175 | {"F0BA","≡"},
176 | {"F0BB","≈"},
177 | {"F0BC","…"},
178 | {"F0BD","⏐"},
179 | {"F0BE","⎯"},
180 | {"F0BF","↵"},
181 | {"F0C0","ℵ"},
182 | {"F0C1","ℑ"},
183 | {"F0C2","ℜ"},
184 | {"F0C3","℘"},
185 | {"F0C4","⊗"},
186 | {"F0C5","⊕"},
187 | {"F0C6","∅"},
188 | {"F0C7","∩"},
189 | {"F0C8","∪"},
190 | {"F0C9","⊃"},
191 | {"F0CA","⊇"},
192 | {"F0CB","⊄"},
193 | {"F0CC","⊂"},
194 | {"F0CD","⊆"},
195 | {"F0CE","∈"},
196 | {"F0CF","∉"},
197 | {"F0D0","∠"},
198 | {"F0D1","∇"},
199 | {"F0D2","®️"},
200 | {"F0D3","©️"},
201 | {"F0D4","™️"},
202 | {"F0D5","∏"},
203 | {"F0D6","√"},
204 | {"F0D7","⋅"},
205 | {"F0D8","¬"},
206 | {"F0D9","∧"},
207 | {"F0DA","∨"},
208 | {"F0DB","⇔"},
209 | {"F0DC","⇐"},
210 | {"F0DD","⇑"},
211 | {"F0DE","⇒"},
212 | {"F0DF","⇓"},
213 | {"F0E0","◊"},
214 | {"F0E1","⟨"},
215 | {"F0E2","®"},
216 | {"F0E3","©"},
217 | {"F0E4","™"},
218 | {"F0E5","∑"},
219 | {"F0E6","⎛"},
220 | {"F0E7","⎜"},
221 | {"F0E8","⎝"},
222 | {"F0E9","⎡"},
223 | {"F0EA","⎢"},
224 | {"F0EB","⎣"},
225 | {"F0EC","⎧"},
226 | {"F0ED","⎨"},
227 | {"F0EE","⎩"},
228 | {"F0EF","⎪"},
229 | {"F0F0","□"},
230 | {"F0F1","〉"},
231 | {"F0F2","∫"},
232 | {"F0F3","⌠"},
233 | {"F0F4","⎮"},
234 | {"F0F5","⌡"},
235 | {"F0F6","⎞"},
236 | {"F0F7","⎟"},
237 | {"F0F8","⎠"},
238 | {"F0F9","⎤"},
239 | {"F0FA","⎥"},
240 | {"F0FB","⎦"},
241 | {"F0FC","⎫"},
242 | {"F0FD","⎬"},
243 | {"F0FE","⎭"},
244 | {"F0FF","□"}
245 | };
246 |
247 | ///
248 | /// Dictonary codes from wingdings char to unicode
249 | ///
250 | public static Dictionary WingdingsCharDictonary => new Dictionary
251 | {
252 | {"F020"," "},
253 | {"F021","🖉"},
254 | {"F022","✂"},
255 | {"F023","✁"},
256 | {"F024","👓"},
257 | {"F025","🕭"},
258 | {"F026","🕮"},
259 | {"F027","🕯"},
260 | {"F028","🕿"},
261 | {"F029","✆"},
262 | {"F02A","🖂"},
263 | {"F02B","🖃"},
264 | {"F02C","📪"},
265 | {"F02D","📫"},
266 | {"F02E","📬"},
267 | {"F02F","📭"},
268 | {"F030","🗀"},
269 | {"F031","🗁"},
270 | {"F032","🖹"},
271 | {"F033","🗏"},
272 | {"F034","🗐"},
273 | {"F035","🗄"},
274 | {"F036","⌛"},
275 | {"F037","🖮"},
276 | {"F038","🖰"},
277 | {"F039","🖲"},
278 | {"F03A","🖳"},
279 | {"F03B","🖴"},
280 | {"F03C","🖫"},
281 | {"F03D","🖬"},
282 | {"F03E","✇"},
283 | {"F03F","✍"},
284 | {"F040","🖎"},
285 | {"F041","✌"},
286 | {"F042","👌"},
287 | {"F043","👍"},
288 | {"F044","👎"},
289 | {"F045","☜"},
290 | {"F046","☞"},
291 | {"F047","☝"},
292 | {"F048","☟"},
293 | {"F049","🖐"},
294 | {"F04A","☺"},
295 | {"F04B","😐"},
296 | {"F04C","☹"},
297 | {"F04D","💣"},
298 | {"F04E","☠"},
299 | {"F04F","🏳"},
300 | {"F050","🏱"},
301 | {"F051","✈"},
302 | {"F052","☼"},
303 | {"F053","💧"},
304 | {"F054","❄"},
305 | {"F055","🕆"},
306 | {"F056","✞"},
307 | {"F057","🕈"},
308 | {"F058","✠"},
309 | {"F059","✡"},
310 | {"F05A","☪"},
311 | {"F05B","☯"},
312 | {"F05C","ॐ"},
313 | {"F05D","☸"},
314 | {"F05E","♈"},
315 | {"F05F","♉"},
316 | {"F060","♊"},
317 | {"F061","♋"},
318 | {"F062","♌"},
319 | {"F063","♍"},
320 | {"F064","♎"},
321 | {"F065","♏"},
322 | {"F066","♐"},
323 | {"F067","♑"},
324 | {"F068","♒"},
325 | {"F069","♓"},
326 | {"F06A","🙰"},
327 | {"F06B","🙵"},
328 | {"F06C","●"},
329 | {"F06D","🔾"},
330 | {"F06E","■"},
331 | {"F06F","□"},
332 | {"F070","🞐"},
333 | {"F071","❑"},
334 | {"F072","❒"},
335 | {"F073","⬧"},
336 | {"F074","⧫"},
337 | {"F075","◆"},
338 | {"F076","❖"},
339 | {"F077","⬥"},
340 | {"F078","⌧"},
341 | {"F079","⮹"},
342 | {"F07A","⌘"},
343 | {"F07B","🏵"},
344 | {"F07C","🏶"},
345 | {"F07D","🙶"},
346 | {"F07E","🙷"},
347 | {"F07F","□"},
348 | {"F080","⓪"},
349 | {"F081","①"},
350 | {"F082","②"},
351 | {"F083","③"},
352 | {"F084","④"},
353 | {"F085","⑤"},
354 | {"F086","⑥"},
355 | {"F087","⑦"},
356 | {"F088","⑧"},
357 | {"F089","⑨"},
358 | {"F08A","⑩"},
359 | {"F08B","⓿"},
360 | {"F08C","❶"},
361 | {"F08D","❷"},
362 | {"F08E","❸"},
363 | {"F08F","❹"},
364 | {"F090","❺"},
365 | {"F091","❻"},
366 | {"F092","❼"},
367 | {"F093","❽"},
368 | {"F094","❾"},
369 | {"F095","❿"},
370 | {"F096","🙢"},
371 | {"F097","🙠"},
372 | {"F098","🙡"},
373 | {"F099","🙣"},
374 | {"F09A","🙞"},
375 | {"F09B","🙜"},
376 | {"F09C","🙝"},
377 | {"F09D","🙟"},
378 | {"F09E","·"},
379 | {"F09f","•"},
380 | {"F0A0","▪"},
381 | {"F0A1","⚪"},
382 | {"F0A2","🞆"},
383 | {"F0A3","🞈"},
384 | {"F0A4","◉"},
385 | {"F0A5","◎"},
386 | {"F0A6","🔿"},
387 | {"F0A7","▪"},
388 | {"F0A8","◻"},
389 | {"F0A9","🟂"},
390 | {"F0AA","✦"},
391 | {"F0AB","★"},
392 | {"F0AC","✶"},
393 | {"F0AD","✴"},
394 | {"F0AE","✹"},
395 | {"F0AF","✵"},
396 | {"F0B0","⯐"},
397 | {"F0B1","⌖"},
398 | {"F0B2","⟡"},
399 | {"F0B3","⌑"},
400 | {"F0B4","⯑"},
401 | {"F0B5","✪"},
402 | {"F0B6","✰"},
403 | {"F0B7","🕐"},
404 | {"F0B8","🕑"},
405 | {"F0B9","🕒"},
406 | {"F0BA","🕓"},
407 | {"F0BB","🕔"},
408 | {"F0BC","🕕"},
409 | {"F0BD","🕖"},
410 | {"F0BE","🕗"},
411 | {"F0BF","🕘"},
412 | {"F0C0","🕙"},
413 | {"F0C1","🕚"},
414 | {"F0C2","🕛"},
415 | {"F0C3","⮰"},
416 | {"F0C4","⮱"},
417 | {"F0C5","⮲"},
418 | {"F0C6","⮳"},
419 | {"F0C7","⮴"},
420 | {"F0C8","⮵"},
421 | {"F0C9","⮶"},
422 | {"F0CA","⮷"},
423 | {"F0CB","🙪"},
424 | {"F0CC","🙫"},
425 | {"F0CD","🙕"},
426 | {"F0CE","🙔"},
427 | {"F0CF","🙗"},
428 | {"F0D0","🙖"},
429 | {"F0D1","🙐"},
430 | {"F0D2","🙑"},
431 | {"F0D3","🙒"},
432 | {"F0D4","🙓"},
433 | {"F0D5","⌫"},
434 | {"F0D6","⌦"},
435 | {"F0D7","⮘"},
436 | {"F0D8","⮚"},
437 | {"F0D9","⮙"},
438 | {"F0DA","⮛"},
439 | {"F0DB","⮈"},
440 | {"F0DC","⮊"},
441 | {"F0DD","⮉"},
442 | {"F0DE","⮋"},
443 | {"F0DF","🡨"},
444 | {"F0E0","🡪"},
445 | {"F0E1","🡩"},
446 | {"F0E2","🡫"},
447 | {"F0E3","🡬"},
448 | {"F0E4","🡭"},
449 | {"F0E5","🡯"},
450 | {"F0E6","🡯"},
451 | {"F0E7","🡮"},
452 | {"F0E8","🡸"},
453 | {"F0E9","🡺"},
454 | {"F0EA","🡹"},
455 | {"F0EB","🡻"},
456 | {"F0EC","🡼"},
457 | {"F0ED","🡽"},
458 | {"F0EE","🡿"},
459 | {"F0EF","🡾"},
460 | {"F0F0","⇦"},
461 | {"F0F1","⇨"},
462 | {"F0F2","⇧"},
463 | {"F0F3","⇩"},
464 | {"F0F4","⬄"},
465 | {"F0F5","⇳"},
466 | {"F0F6","⬁"},
467 | {"F0F7","⬃"},
468 | {"F0F8","⬂"},
469 | {"F0F9","🢬"},
470 | {"F0FA","🢭"},
471 | {"F0FB","🗶"},
472 | {"F0FC","✔"},
473 | {"F0FD","🗷"},
474 | {"F0FE","🗹"},
475 | };
476 |
477 | ///
478 | /// Default ctor
479 | ///
480 | public SymbolHandler()
481 | {
482 | DefaultSymbolHandler = new OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter.SymbolHandler();
483 | }
484 |
485 | ///
486 | /// Default handler that transforms every symbol into some html encoded font specific char
487 | ///
488 | ///
489 | ///
490 | ///
491 | public XElement TransformSymbol(XElement element, Dictionary fontFamily)
492 | {
493 | if (fontFamily.TryGetValue("font-family", out var currentSymbolFontFamily) && currentSymbolFontFamily == "Symbol")
494 | {
495 | var customChar = element.Attribute(W._char)?.Value;
496 |
497 | if (customChar != null && SymbolCharDictonary.TryGetValue(customChar, out var commonChar))
498 | {
499 | return new XElement(Xhtml.span, commonChar);
500 | }
501 | }
502 | else if (fontFamily.TryGetValue("font-family", out var currentWingdingsFontFamily) && currentWingdingsFontFamily == "Wingdings")
503 | {
504 | var customChar = element.Attribute(W._char)?.Value;
505 |
506 | if (customChar != null && WingdingsCharDictonary.TryGetValue(customChar, out var commonChar))
507 | {
508 | return new XElement(Xhtml.span, commonChar);
509 | }
510 | }
511 |
512 | return DefaultSymbolHandler.TransformSymbol(element, fontFamily);
513 | }
514 | }
515 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/TextSymbolToUnicodeHandler.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
2 | using System.Collections.Generic;
3 |
4 | namespace Codeuctivity.OpenXmlToHtml
5 | {
6 | ///
7 | /// Replaces any char of wingdings with the Unicode equivalent
8 | ///
9 | public class TextSymbolToUnicodeHandler : ITextHandler
10 | {
11 | ///
12 | /// Dictionary used to translate symbol chars to Unicode
13 | ///
14 | private static readonly Dictionary SymbolToUnicode = new Dictionary
15 | {
16 | { '','•' }
17 | };
18 |
19 | ///
20 | /// Replaces any char of wingdings with the Unicode equivalent
21 | ///
22 | public string TransformText(string text, Dictionary fontFamily)
23 | {
24 | if (fontFamily.TryGetValue("font-family", out var currentFontFamily) && currentFontFamily == "Symbol")
25 | {
26 | foreach (var item in SymbolToUnicode)
27 | {
28 | text = text.Replace(item.Key, item.Value);
29 | }
30 | }
31 |
32 | return text;
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/Tooling/Linux.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace Codeuctivity.OpenXmlToHtml.Tooling
6 | {
7 | public class Linux
8 | {
9 | public static readonly string ChromiumInstallCommand = "export DEBIAN_FRONTEND=noninteractive && apt update && apt upgrade -y && apt install mc libgconf-2-4 libatk1.0-0 libatk-bridge2.0-0 libgdk-pixbuf2.0-0 libgtk-3-0 libgbm-dev libasound2 libnss3 -y";
10 |
11 | public static void SetupDependencies()
12 | {
13 | var azureLinuxAppChromeDependencies = ChromiumInstallCommand;
14 |
15 | var escapedArgs = azureLinuxAppChromeDependencies.Replace("\"", "\\\"");
16 | var process = new Process
17 | {
18 | StartInfo = new ProcessStartInfo
19 | {
20 | FileName = "/bin/bash",
21 | Arguments = $"-c \"{escapedArgs}\"",
22 | RedirectStandardOutput = true,
23 | UseShellExecute = false,
24 | CreateNoWindow = true,
25 | }
26 | };
27 |
28 | process.Start();
29 | process.StandardOutput.ReadToEnd();
30 | process.WaitForExit();
31 |
32 | if (process.ExitCode != 0)
33 | {
34 | throw new Exception($"Failed to execute '{ChromiumInstallCommand}'");
35 | }
36 | }
37 |
38 | public static bool IsRunningOnAzureLinux()
39 | {
40 | var websiteSku = Environment.GetEnvironmentVariable("WEBSITE_SKU");
41 |
42 | if (string.IsNullOrEmpty(websiteSku))
43 | {
44 | return false;
45 | }
46 |
47 | return RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && websiteSku.Contains("Linux");
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/WebSafeFontsHandler.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
2 | using System.Linq;
3 | using System.Xml.Linq;
4 |
5 | namespace Codeuctivity.OpenXmlToHtml
6 | {
7 | ///
8 | /// Replaces any font that is not part a white list of fonts with Arial
9 | ///
10 | public class WebSafeFontsHandler : IFontHandler
11 | {
12 | ///
13 | /// Web Safe Fonts for HTML and CSS https://www.w3schools.com/cssref/css_websafe_fonts.asp
14 | ///
15 | public string[] WebSafeFontNames { get; private set; }
16 |
17 | private FontHandler FontHandler { get; }
18 |
19 | ///
20 | /// Default ctor
21 | ///
22 | public WebSafeFontsHandler()
23 | {
24 | WebSafeFontNames = new[] { "Arial", "Verdana", "Helvetica", "Tahoma", "Trebuchet MS", "Times New Roman", "Georgia", "Garamond", "Courier New", "Brush Script MT" };
25 | FontHandler = new FontHandler();
26 | }
27 |
28 | ///
29 | /// Use this ctor to use a custom list of WebSafeFontNames
30 | ///
31 | ///
32 | public WebSafeFontsHandler(string[] webSafeFontNames)
33 | {
34 | WebSafeFontNames = webSafeFontNames;
35 | FontHandler = new FontHandler();
36 | }
37 |
38 | ///
39 | /// Replaces any font not white listed
40 | ///
41 | ///
42 | ///
43 | public string TranslateParagraphStyleFont(XElement paragraph)
44 | {
45 | var unsafeFont = FontHandler.TranslateParagraphStyleFont(paragraph);
46 |
47 | return tranlateToWebSafeFont(unsafeFont);
48 | }
49 |
50 | ///
51 | /// Replaces any font not white listed
52 | ///
53 | ///
54 | ///
55 | public string TranslateRunStyleFont(XElement run)
56 | {
57 | var unsafeFont = FontHandler.TranslateRunStyleFont(run);
58 |
59 | return tranlateToWebSafeFont(unsafeFont);
60 | }
61 |
62 | private string tranlateToWebSafeFont(string unsafeFont)
63 | {
64 | if (WebSafeFontNames.Contains(unsafeFont))
65 | {
66 | return unsafeFont;
67 | }
68 |
69 | return "Arial";
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/OpenXmlToHtml/docs/nugetReadme.md:
--------------------------------------------------------------------------------
1 | Converts DOCX to HTML:
2 |
3 | ```csharp
4 | await new OpenXmlToHtml().ConvertToHtmlAsync(inputPathDocx, outputPathHtml);
5 | ```
6 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlCli/OpenXmlToHtmlCli.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | true
7 | win-x64
8 | true
9 |
10 |
11 |
12 |
13 | all
14 | runtime; build; native; contentfiles; analyzers; buildtransitive
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlCli/Program.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlToHtml;
2 | using System;
3 | using System.IO;
4 | using System.Threading.Tasks;
5 |
6 | namespace OpenXmlToHtmlCli
7 | {
8 | internal class Program
9 | {
10 | private static async Task Main(string[] args)
11 | {
12 | if (args.Length != 2)
13 | {
14 | Console.WriteLine("Usage: OpenXmlToHtmlCli ");
15 | return 1;
16 | }
17 |
18 | var inputPathDocx = args[0];
19 | var outputPathHtml = args[1];
20 |
21 | if (!File.Exists(inputPathDocx))
22 | {
23 | Console.WriteLine($"Could not find source {inputPathDocx}.");
24 | return 1;
25 | }
26 |
27 | if (File.Exists(outputPathHtml))
28 | {
29 | Console.WriteLine($"Destination {outputPathHtml} already exists.");
30 | return 1;
31 | }
32 |
33 | Console.WriteLine($"Converting {inputPathDocx} to {outputPathHtml}");
34 | await new OpenXmlToHtml().ConvertToHtmlAsync(inputPathDocx, outputPathHtml);
35 | return 0;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlCli/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "OpenXmlToHtmlCli": {
4 | "commandName": "Project",
5 | "commandLineArgs": "source.docx destination.html"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "dotnet-ef": {
6 | "version": "5.0.4",
7 | "commands": [
8 | "dotnet-ef"
9 | ]
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/Azure/LinuxSpecificContainerSetup.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlToHtml.Tooling;
2 | using Microsoft.Extensions.Hosting;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 |
6 | namespace OpenXmlToHtmlOpenApi.Azure
7 | {
8 | ///
9 | /// Setup dependencies on azure linux containers
10 | /// w
11 | public class AzureAndWslSpecificContainerSetup : IHostedService
12 | {
13 | ///
14 | public Task StartAsync(CancellationToken cancellationToken)
15 | {
16 | Linux.SetupDependencies();
17 |
18 | return Task.CompletedTask;
19 | }
20 |
21 | ///
22 | public Task StopAsync(CancellationToken cancellationToken)
23 | {
24 | { return Task.CompletedTask; }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/Controllers/OpenXmlConverterController.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.HtmlRenderer;
2 | using Codeuctivity.OpenXmlToHtml;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.AspNetCore.Mvc;
5 | using System;
6 | using System.IO;
7 | using System.Threading.Tasks;
8 |
9 | namespace OpenXmlToHtmlOpenApi.Controllers
10 | {
11 | ///
12 | /// OpenXml converter
13 | ///
14 | [ApiController]
15 | [Route("[controller]")]
16 | public class OpenXmlConverterController : ControllerBase
17 | {
18 | private readonly IOpenXmlToHtml _openXmlToHtml;
19 |
20 | ///
21 | /// OpenXmlConverter ctor
22 | ///
23 | ///
24 | public OpenXmlConverterController(IOpenXmlToHtml openXmlToHtml)
25 | {
26 | _openXmlToHtml = openXmlToHtml;
27 | }
28 |
29 | ///
30 | /// Converts OpenXmlFile to HTML
31 | ///
32 | ///
33 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
34 | /// HTML
35 | [HttpPost]
36 | [ProducesResponseType(200)]
37 | [ProducesResponseType(400)]
38 | public async Task ConvertToHtml(IFormFile openXmlFile, bool useWebSafeFonts)
39 | {
40 | if (openXmlFile.Length > 0)
41 | {
42 | var htmlStream = await _openXmlToHtml.ConvertToHtmlAsync(openXmlFile.OpenReadStream(), useWebSafeFonts);
43 | return File(htmlStream, "text/html");
44 | }
45 | return BadRequest("Request contains no document");
46 | }
47 |
48 | ///
49 | /// Converts OpenXmlFile to PDF
50 | ///
51 | ///
52 | /// Use 'true' to replace every non web safe font with some fallback. Default is false.
53 | /// PDF
54 | [HttpPost]
55 | [Route("ConvertToPdf")]
56 | [ProducesResponseType(200)]
57 | [ProducesResponseType(400)]
58 | public async Task ConvertToPdf(IFormFile openXmlFile, bool useWebSafeFonts)
59 | {
60 | await using var chromiumRenderer = await Renderer.CreateAsync();
61 | if (openXmlFile.Length > 0)
62 | {
63 | var pathHtml = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.html");
64 | var pathPdf = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.pdf");
65 |
66 | var htmlStream = await _openXmlToHtml.ConvertToHtmlAsync(openXmlFile.OpenReadStream(), useWebSafeFonts);
67 | try
68 | {
69 | using var fileStreamHtml = new FileStream(pathHtml, FileMode.CreateNew);
70 | await htmlStream.CopyToAsync(fileStreamHtml);
71 | await chromiumRenderer.ConvertHtmlToPdf(pathHtml, pathPdf);
72 | var pdf = await System.IO.File.ReadAllBytesAsync(pathPdf);
73 | return File(pdf, "application/pdf", $"{openXmlFile.FileName}.pdf");
74 | }
75 | finally
76 | {
77 | System.IO.File.Delete(pathHtml);
78 | System.IO.File.Delete(pathPdf);
79 | }
80 | }
81 | return BadRequest("Request contains no document");
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/OpenXmlToHtmlOpenApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | fd376f00-03ce-419b-883f-bfa8af935ee4
6 | $(CURRENT_VERSION)
7 | 0.0.1
8 | $(Version)
9 | $(Version)
10 | $(Version)
11 |
12 |
13 |
14 | .\OpenXmlToHtmlOpenApi\OpenXmlToHtmlOpenApi.xml
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/OpenXmlToHtmlOpenApi/OpenXmlToHtmlOpenApi.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OpenXmlToHtmlOpenApi
5 |
6 |
7 |
8 |
9 | Setup dependencies on azure linux containers
10 | w
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | OpenXml converter
21 |
22 |
23 |
24 |
25 | OpenXmlConverter ctor
26 |
27 |
28 |
29 |
30 |
31 | Converts OpenXmlFile to HTML
32 |
33 |
34 | Use 'true' to replace every non web safe font with some fallback. Default is false.
35 | HTML
36 |
37 |
38 |
39 | Converts OpenXmlFile to PDF
40 |
41 |
42 | Use 'true' to replace every non web safe font with some fallback. Default is false.
43 | PDF
44 |
45 |
46 |
47 | Program
48 |
49 |
50 |
51 |
52 | Main entry point
53 |
54 |
55 |
56 |
57 |
58 | Called on start
59 |
60 |
61 |
62 |
63 |
64 |
65 | Asp .net application startup code
66 |
67 |
68 |
69 |
70 | Startup
71 |
72 |
73 |
74 |
75 |
76 | Application configuration
77 |
78 |
79 |
80 |
81 | This method gets called by the runtime. Use this method to add services to the container.
82 |
83 |
84 |
85 |
86 |
87 | This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.Extensions.Hosting;
3 |
4 | namespace OpenXmlToHtmlOpenApi
5 | {
6 | ///
7 | /// Program
8 | ///
9 | public class Program
10 | {
11 | ///
12 | /// Main entry point
13 | ///
14 | ///
15 | public static void Main(string[] args)
16 | {
17 | CreateHostBuilder(args).Build().Run();
18 | }
19 |
20 | ///
21 | /// Called on start
22 | ///
23 | ///
24 | ///
25 | public static IHostBuilder CreateHostBuilder(string[] args)
26 | {
27 | return Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
28 | {
29 | webBuilder.UseStartup();
30 | });
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:54015",
7 | "sslPort": 0
8 | }
9 | },
10 | "$schema": "http://json.schemastore.org/launchsettings.json",
11 | "profiles": {
12 | "IIS Express": {
13 | "commandName": "IISExpress",
14 | "launchBrowser": true,
15 | "launchUrl": "index.html",
16 | "environmentVariables": {
17 | "ASPNETCORE_ENVIRONMENT": "Development"
18 | }
19 | },
20 | "OpenXmlToHtmlOpenApi": {
21 | "commandName": "Project",
22 | "launchBrowser": true,
23 | "launchUrl": "index.html",
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | },
27 | "applicationUrl": "https://localhost:5001;http://localhost:5000"
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/Startup.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlToHtml;
2 | using Codeuctivity.OpenXmlToHtml.Tooling;
3 | using Microsoft.AspNetCore.Builder;
4 | using Microsoft.AspNetCore.Hosting;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.DependencyInjection;
7 | using Microsoft.Extensions.Hosting;
8 | using Microsoft.OpenApi.Models;
9 | using OpenXmlToHtmlOpenApi.Azure;
10 | using System;
11 | using System.IO;
12 | using System.Reflection;
13 |
14 | namespace OpenXmlToHtmlOpenApi
15 | {
16 | ///
17 | /// Asp .net application startup code
18 | ///
19 | public class Startup
20 | {
21 | ///
22 | /// Startup
23 | ///
24 | ///
25 | public Startup(IConfiguration configuration)
26 | {
27 | Configuration = configuration;
28 | }
29 |
30 | ///
31 | /// Application configuration
32 | ///
33 | public IConfiguration Configuration { get; }
34 |
35 | private const string GithubProjectAdress = "https://github.com/Codeuctivity/OpenXmlToHtml";
36 |
37 | ///
38 | /// This method gets called by the runtime. Use this method to add services to the container.
39 | ///
40 | ///
41 | public void ConfigureServices(IServiceCollection services)
42 | {
43 | services.AddSingleton();
44 |
45 | if (Linux.IsRunningOnAzureLinux())
46 | {
47 | services.AddSingleton();
48 | }
49 |
50 | services.AddApplicationInsightsTelemetry();
51 | services.AddControllers();
52 | services.AddSwaggerGen(c =>
53 | {
54 | c.SwaggerDoc("v1", new OpenApiInfo
55 | {
56 | Version = "v2",
57 | Title = $"{Assembly.GetEntryAssembly().GetName().Name} {Assembly.GetEntryAssembly().GetName().Version}",
58 | Description = "A simple OpenApi wrapping access to OpenXmlToHtml",
59 | TermsOfService = new Uri(GithubProjectAdress),
60 | Contact = new OpenApiContact
61 | {
62 | Name = "Codeuctivity",
63 | Email = string.Empty,
64 | Url = new Uri(GithubProjectAdress),
65 | },
66 | License = new OpenApiLicense
67 | {
68 | Name = "Use under AGPL",
69 | Url = new Uri($"{GithubProjectAdress}/blob/main/LICENSE"),
70 | }
71 | });
72 |
73 | // Set the comments path for the Swagger JSON and UI.
74 | var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
75 | var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
76 | c.IncludeXmlComments(xmlPath);
77 | });
78 | }
79 |
80 | ///
81 | /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
82 | ///
83 | ///
84 | ///
85 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
86 | {
87 | if (env.IsDevelopment())
88 | {
89 | app.UseDeveloperExceptionPage();
90 | }
91 |
92 | app.UseHttpsRedirection();
93 |
94 | // Enable middleware to serve generated Swagger as a JSON endpoint.
95 | app.UseSwagger();
96 |
97 | // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
98 | app.UseSwaggerUI(c =>
99 | {
100 | c.SwaggerEndpoint("/swagger/v1/swagger.json", "OpenXmlToHtml V1");
101 | c.RoutePrefix = string.Empty;
102 | });
103 |
104 | app.UseRouting();
105 |
106 | app.UseAuthorization();
107 |
108 | app.UseEndpoints(endpoints =>
109 | {
110 | endpoints.MapControllers();
111 | });
112 | }
113 | }
114 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*"
10 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApiTests/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | # CA2007: Consider calling ConfigureAwait on the awaited task
4 | dotnet_diagnostic.CA2007.severity = none
5 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApiTests/AzureTests.cs:
--------------------------------------------------------------------------------
1 | using OpenXmlToHtmlOpenApi.Azure;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using System.Threading;
5 | using Xunit;
6 |
7 | namespace OpenXmlToHtmlOpenApiTests
8 | {
9 | public class AzureTests
10 | {
11 | [SkippableFact]
12 | public async void ShoulSetupChromeiumDependencies()
13 | {
14 | Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), "Setup code is designed for Ubuntu");
15 | Skip.If(System.Environment.UserName != "root");
16 | var azureSpecificContainerSetup = new AzureAndWslSpecificContainerSetup();
17 | await azureSpecificContainerSetup.StartAsync(new CancellationToken());
18 | }
19 |
20 | public static bool IsRunningOnWsl()
21 | {
22 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
23 | {
24 | return false;
25 | }
26 |
27 | var version = File.ReadAllText("/proc/version");
28 | var IsWsl = version.Contains("WSL");
29 | return IsWsl;
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApiTests/OpenXmlConverterControllerIntegrativeTests.cs:
--------------------------------------------------------------------------------
1 | using AngleSharp;
2 | using Microsoft.AspNetCore.Mvc.Testing;
3 | using System;
4 | using System.IO;
5 | using System.Net.Http;
6 | using System.Runtime.InteropServices;
7 | using System.Threading.Tasks;
8 | using Xunit;
9 |
10 | namespace OpenXmlToHtmlOpenApiTests
11 | {
12 | public class OpenXmlConverterControllerIntegrativeTests : IClassFixture>
13 | {
14 | private readonly WebApplicationFactory _factory;
15 |
16 | public OpenXmlConverterControllerIntegrativeTests(WebApplicationFactory factory)
17 | {
18 | _factory = factory;
19 | }
20 |
21 | [SkippableTheory]
22 | [InlineData("/", "text/html; charset=utf-8")]
23 | [InlineData("/swagger/v1/swagger.json", "application/json; charset=utf-8")]
24 | public async Task ShouldAccessEndpointSuccessfull(string route, string contentType)
25 | {
26 | Skip.If(IsRunningOnWsl());
27 |
28 | // Arrange
29 | var client = _factory.CreateClient();
30 | var expectedUrl = new Uri($"https://localhost{route}");
31 |
32 | // Act
33 | var response = await client.GetAsync(expectedUrl).ConfigureAwait(false);
34 |
35 | // Assert
36 | response.EnsureSuccessStatusCode();
37 | Assert.Equal(contentType, response.Content.Headers.ContentType.ToString());
38 | }
39 |
40 | private static bool IsRunningOnWsl()
41 | {
42 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
43 | {
44 | return false;
45 | }
46 |
47 | var version = File.ReadAllText("/proc/version");
48 | var IsWsl = version.Contains("Microsoft", StringComparison.InvariantCultureIgnoreCase);
49 | return IsWsl;
50 | }
51 |
52 | [SkippableFact]
53 | public async Task ShouldConvertOpenXmlToHtml()
54 | {
55 | Skip.If(IsRunningOnWsl());
56 |
57 | // Arrange
58 | var client = _factory.CreateClient();
59 | using var request = new HttpRequestMessage(new HttpMethod("POST"), "https://localhost/OpenXmlConverter");
60 | using var file = new ByteArrayContent(File.ReadAllBytes("../../../TestInput/BasicTextFormated.docx"));
61 | file.Headers.Add("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
62 | var multipartContent = new MultipartFormDataContent
63 | {
64 | { file, "openXmlFile", Path.GetFileName("BasicTextFormated.docx") }
65 | };
66 | request.Content = multipartContent;
67 |
68 | // Act
69 | var response = await client.SendAsync(request).ConfigureAwait(false);
70 |
71 | // Assert
72 | response.EnsureSuccessStatusCode();
73 | Assert.Equal("text/html", response.Content.Headers.ContentType.MediaType);
74 | await AssertHtmlContentAsync(response.Content, "Lorem Ipsum");
75 | }
76 |
77 | [SkippableFact]
78 | public async Task ShouldConvertOpenXmlToPdf()
79 | {
80 | Skip.If(IsRunningOnWsl());
81 |
82 | // Arrange
83 | var client = _factory.CreateClient();
84 | using var request = new HttpRequestMessage(new HttpMethod("POST"), "https://localhost/OpenXmlConverter/ConvertToPdf");
85 | using var file = new ByteArrayContent(File.ReadAllBytes("../../../TestInput/BasicTextFormated.docx"));
86 | file.Headers.Add("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
87 | var multipartContent = new MultipartFormDataContent
88 | {
89 | { file, "openXmlFile", Path.GetFileName("BasicTextFormated.docx") }
90 | };
91 | request.Content = multipartContent;
92 |
93 | // Act
94 | var response = await client.SendAsync(request).ConfigureAwait(false);
95 |
96 | // Assert
97 | response.EnsureSuccessStatusCode();
98 | Assert.Equal("application/pdf", response.Content.Headers.ContentType.MediaType);
99 | }
100 |
101 | private static async Task AssertHtmlContentAsync(HttpContent content, string expectedText)
102 | {
103 | var context = BrowsingContext.New(Configuration.Default);
104 |
105 | var convertedMarkup = await content.ReadAsStringAsync();
106 | var document = await context.OpenAsync(req => req.Content(convertedMarkup));
107 |
108 | var actualText = document.QuerySelector(".Codeuctivity-000001")?.TextContent;
109 | Assert.Equal(expectedText, actualText);
110 | }
111 | }
112 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApiTests/OpenXmlToHtmlOpenApiTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 |
6 | false
7 |
8 |
9 |
10 |
11 |
12 | all
13 | runtime; build; native; contentfiles; analyzers; buildtransitive
14 |
15 |
16 |
17 |
18 |
19 |
20 | all
21 | runtime; build; native; contentfiles; analyzers; buildtransitive
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApiTests/TestInput/BasicTextFormated.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlOpenApiTests/TestInput/BasicTextFormated.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlOpenApiTests/WebApplicationFactory.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Hosting;
2 | using Microsoft.AspNetCore.Mvc.Testing;
3 | using Microsoft.Extensions.DependencyInjection;
4 |
5 | namespace OpenXmlToHtmlOpenApiTests
6 | {
7 | public class OpenXmlToHtmlOpenApiTestFactory : WebApplicationFactory where TStartup : class
8 | {
9 | protected override void ConfigureWebHost(IWebHostBuilder builder)
10 | {
11 | // see https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests for things you could place here
12 |
13 | builder?.ConfigureServices(services =>
14 | {
15 | // Build the service provider.
16 | services.BuildServiceProvider();
17 | });
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | # CA2007: Consider calling ConfigureAwait on the awaited task
4 | dotnet_diagnostic.CA2007.severity = none
5 |
6 | # S125: Sections of code should not be commented out
7 | dotnet_diagnostic.S125.severity = silent
8 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/BreakHandlerAdapterTests.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools;
2 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
3 | using Codeuctivity.OpenXmlToHtml;
4 | using Moq;
5 | using System.Linq;
6 | using System.Xml.Linq;
7 | using Xunit;
8 |
9 | namespace OpenXmlToHtmlTests
10 | {
11 | public class BreakHandlerAdapterTests
12 | {
13 | [Fact]
14 | public void ShouldTranslatePageBreaks()
15 | {
16 | var breakHandler = new Mock();
17 | var breakHandlerAdapter = new PageBreakHandler(breakHandler.Object);
18 |
19 | var element = new XElement("br", new XAttribute(W.type, "page"));
20 |
21 | var actual = breakHandlerAdapter.TransformBreak(element);
22 |
23 | Assert.Equal("", actual.Single().ToString());
24 | breakHandler.Verify(m => m.TransformBreak(It.IsAny()), Times.Never());
25 | }
26 |
27 | [Fact]
28 | public void ShouldTranslatePage()
29 | {
30 | var breakHandler = new Mock();
31 | var breakHandlerAdapter = new PageBreakHandler(breakHandler.Object);
32 |
33 | var element = new XElement("br");
34 |
35 | breakHandlerAdapter.TransformBreak(element);
36 |
37 | breakHandler.Verify(m => m.TransformBreak(element), Times.Once);
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/BasicTextFormated.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/BasicTextFormated.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/EmptyDocument.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/EmptyDocument.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/Font.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/Font.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/Font.docx.png.diff.linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/Font.docx.png.diff.linux.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/Font.docx.png.diff.win.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/Font.docx.png.diff.win.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/Images.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/Images.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/Images.docx.png.diff.linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/Images.docx.png.diff.linux.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/SymbolRibbon.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/SymbolRibbon.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/Symbols.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/Symbols.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/Wingdings.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/Wingdings.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExpectedTestOutcome/WingdingsSymbols.docx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/ExpectedTestOutcome/WingdingsSymbols.docx.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/ExportImageHandlerTests.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools.OpenXMLWordprocessingMLToHtmlConverter;
2 | using Codeuctivity.OpenXmlToHtml;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Xunit;
8 |
9 | namespace OpenXmlToHtmlTests
10 | {
11 | public class ExportImageHandlerTests
12 | {
13 | [Fact]
14 | public async Task ShouldUseExportImageHandlerAsync()
15 | {
16 | var sourcePngFilePath = $"../../../TestInput/TestInput.png";
17 | var exportTarget = new Dictionary();
18 | using var fileStream = new FileStream(sourcePngFilePath, FileMode.Open, FileAccess.Read);
19 | using var memorystream = new MemoryStream();
20 | await fileStream.CopyToAsync(memorystream);
21 | var expectedImage = memorystream.ToArray();
22 |
23 | fileStream.Position = 0;
24 |
25 | var imageInfo = new ImageInfo
26 | {
27 | AltText = "AltText",
28 | Image = fileStream,
29 | };
30 |
31 | var exportImageHandler = new ExportImageHandler(exportTarget);
32 |
33 | var actual = exportImageHandler.TransformImage(imageInfo);
34 |
35 | Assert.True(exportTarget.Count == 1);
36 | var exportedImage = exportTarget.Single();
37 |
38 | Assert.Equal(exportedImage.Value, expectedImage);
39 | Assert.Equal($"
", actual.ToString());
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/OpenXmlToHtmlIntegrationTests.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.HtmlRenderer;
2 | using Codeuctivity.OpenXmlToHtml;
3 | using PdfSharp.Pdf.IO;
4 | using SixLabors.ImageSharp;
5 | using SixLabors.ImageSharp.PixelFormats;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Xml;
12 | using Xunit;
13 |
14 | namespace OpenXmlToHtmlTests
15 | {
16 | public class OpenXmlToHtmlIntegrationTests
17 | {
18 | private const string xhtmlPrimer = "();
58 |
59 | var actuelHtml = await OpenXmlToHtml.ConvertToHtmlAsync(sourceIpenXml, "fallbackTitle", exportedImages, false);
60 |
61 | Assert.Equal(2, exportedImages.Count);
62 |
63 | Assert.True(IsValidBitmap(exportedImages.First().Value));
64 | Assert.True(IsValidBitmap(exportedImages.Last().Value));
65 |
66 | AssertXhtmlIsValid(actuelHtml);
67 | }
68 |
69 | private static bool IsValidBitmap(byte[] blob)
70 | {
71 | var image = Image.Load(blob);
72 | return image.Width > 1 && image.Height > 1;
73 | }
74 |
75 | [Fact]
76 | public async Task ShouldConvertDocumentIntegrativeWithToExpectedPageQuantityTest()
77 | {
78 | var testFileName = "TwoPages.docx";
79 | var sourceOpenXmlFilePath = $"../../../TestInput/{testFileName}";
80 | var actualHtmlFilePath = Path.Combine(Path.GetTempPath(), $"Actual{testFileName}.html");
81 |
82 | if (File.Exists(actualHtmlFilePath))
83 | {
84 | File.Delete(actualHtmlFilePath);
85 | }
86 |
87 | await openXmlToHtml.ConvertToHtmlAsync(sourceOpenXmlFilePath, actualHtmlFilePath);
88 |
89 | AssertXhtmlIsValid(actualHtmlFilePath);
90 | await using var chromiumRenderer = await Renderer.CreateAsync();
91 | var pathPdfizedHtml = actualHtmlFilePath + ".pdf";
92 | await chromiumRenderer.ConvertHtmlToPdf(actualHtmlFilePath, pathPdfizedHtml);
93 | AssertPdfPageCount(pathPdfizedHtml, 2);
94 | }
95 |
96 | private static void AssertPdfPageCount(string pathPdfizedHtml, int expectePageQuantity)
97 | {
98 | var pdfReader = PdfReader.Open(pathPdfizedHtml, PdfDocumentOpenMode.ReadOnly);
99 | Assert.Equal(expectePageQuantity, pdfReader.PageCount);
100 | }
101 |
102 | private static void AssertXhtmlIsValid(string actualHtmlFilePath)
103 | {
104 | var messages = new StringBuilder();
105 | var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema, DtdProcessing = DtdProcessing.Ignore };
106 | settings.ValidationEventHandler += (sender, args) => messages.AppendLine(args.Message);
107 | var reader = XmlReader.Create(actualHtmlFilePath, settings);
108 | #pragma warning disable S108 // Nested blocks of code should not be left empty
109 | while (reader.Read()) { }
110 | #pragma warning restore S108 // Nested blocks of code should not be left empty
111 |
112 | if (!File.ReadAllText(actualHtmlFilePath).Contains(xhtmlPrimer))
113 | {
114 | messages.AppendLine("Xhtml root element missing");
115 | }
116 |
117 | Assert.True(messages.Length == 0, messages.ToString());
118 | }
119 |
120 | private void AssertXhtmlIsValid(Stream actualHtml)
121 | {
122 | var messages = new StringBuilder();
123 | var settings = new XmlReaderSettings { ValidationType = ValidationType.Schema, DtdProcessing = DtdProcessing.Ignore };
124 | settings.ValidationEventHandler += (sender, args) => messages.AppendLine(args.Message);
125 | var reader = XmlReader.Create(actualHtml, settings);
126 | #pragma warning disable S108 // Nested blocks of code should not be left empty
127 | while (reader.Read()) { }
128 | #pragma warning restore S108 // Nested blocks of code should not be left empty
129 |
130 | Assert.True(messages.Length == 0, messages.ToString());
131 | }
132 | }
133 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/OpenXmlToHtmlTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | false
6 | 9.0
7 | enable
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 | all
17 | runtime; build; native; contentfiles; analyzers; buildtransitive
18 |
19 |
20 |
21 |
22 | runtime; build; native; contentfiles; analyzers; buildtransitive
23 | all
24 |
25 |
26 |
27 |
28 | runtime; build; native; contentfiles; analyzers; buildtransitive
29 | all
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/SymbolHandlerTests.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools;
2 | using Codeuctivity.OpenXmlToHtml;
3 | using System.Collections.Generic;
4 | using System.Xml.Linq;
5 | using Xunit;
6 |
7 | namespace OpenXmlToHtmlTests
8 | {
9 | public class SymbolHandlerTests
10 | {
11 | [Fact]
12 | public void ShouldTranslateSymbolsBulletPointToUnicodeMiddlePoint()
13 | {
14 | var fontFamily = new Dictionary
15 | {
16 | { "font-family", "Symbol" }
17 | };
18 |
19 | var symbolHandler = new SymbolHandler();
20 | var element = new XElement("symbol", new XAttribute(W._char, "F0D7"));
21 |
22 | var actual = symbolHandler.TransformSymbol(element, fontFamily);
23 |
24 | Assert.Equal("⋅", actual.ToString());
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInfrastructure/DocumentAsserter.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.HtmlRenderer;
2 | using Codeuctivity.OpenXmlToHtml.Tooling;
3 | using Codeuctivity.SkiaSharpCompare;
4 | using SkiaSharp;
5 | using System;
6 | using System.IO;
7 | using System.Runtime.InteropServices;
8 | using System.Threading.Tasks;
9 | using Xunit;
10 |
11 | namespace OpenXmlToHtmlTests
12 | {
13 | internal static class DocumentAsserter
14 | {
15 | internal static async Task AssertRenderedHtmlIsEqual(string actualFilePath, string expectReferenceFilePath, int allowedPixelErrorCount)
16 | {
17 | var actualFullPath = Path.GetFullPath(actualFilePath);
18 | var expectFullPath = Path.GetFullPath(expectReferenceFilePath);
19 |
20 | Assert.True(File.Exists(actualFullPath), $"actualFilePath not found {actualFullPath}");
21 |
22 | var pathRasterizedHtml = actualFilePath + ".png";
23 | try
24 | {
25 | await using var chromiumRenderer = await Renderer.CreateAsync();
26 | await chromiumRenderer.ConvertHtmlToPng(actualFilePath, pathRasterizedHtml);
27 | }
28 | catch (PuppeteerSharp.ProcessException exception)
29 | {
30 | if (exception.Message.Contains("Failed to launch browser!"))
31 | {
32 | throw new Exception($"Run '{Linux.ChromiumInstallCommand}' in your test sytem.", exception);
33 | }
34 |
35 | throw;
36 | }
37 | Assert.True(File.Exists(expectFullPath), $"ExpectReferenceFilePath not found \n{expectFullPath}\n copy over \n{pathRasterizedHtml}\n if this is a new test case.");
38 |
39 | await AssertImageIsEqualAsync(pathRasterizedHtml, expectReferenceFilePath, allowedPixelErrorCount);
40 | }
41 |
42 | internal static async Task AssertImageIsEqualAsync(string actualImagePath, string expectImageFilePath, int allowedPixelErrorCount)
43 | {
44 | var actualFullPath = Path.GetFullPath(actualImagePath);
45 | var expectFullPath = Path.GetFullPath(expectImageFilePath);
46 |
47 | // Uncomment following line to update or create an expectation file
48 | //File.Copy(actualImagePath, expectImageFilePath, true);
49 |
50 | Assert.True(File.Exists(actualFullPath), $"actualImagePath not found {actualFullPath}");
51 | Assert.True(File.Exists(expectFullPath), $"ExpectReferenceImagePath not found \n{expectFullPath}\n copy over \n{actualFullPath}\n if this is a new test case.");
52 |
53 | var filePathInTestResultFolderOfExpectation = SaveToTestresults(expectImageFilePath, "Expected" + Path.GetFileName(expectImageFilePath));
54 | var filePathInTestResultFolderOfActual = SaveToTestresults(actualImagePath, Path.GetFileName(actualFullPath));
55 |
56 | if (Compare.ImagesAreEqual(actualFullPath, expectFullPath))
57 | {
58 | DroptFilesFromTestResultFolder(filePathInTestResultFolderOfExpectation, filePathInTestResultFolderOfActual);
59 | return;
60 | }
61 |
62 | var osSpecificDiffFileSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux" : "win";
63 |
64 | var allowedDiffImage = $"{expectFullPath}.diff.{osSpecificDiffFileSuffix}.png";
65 | var newDiffImage = $"{actualFullPath}.diff.png";
66 |
67 | if (!Compare.ImagesHaveEqualSize(actualFullPath, expectFullPath))
68 | {
69 | Assert.Fail($"Actual Dimension differs from expected \nExpected {expectFullPath}\ndiffers to actual {actualFullPath} \nReplace {expectFullPath} with the new value.");
70 | }
71 |
72 | using (var maskImage = Compare.CalcDiffMaskImage(actualFullPath, expectFullPath))
73 | {
74 | var png = maskImage.Encode(SKEncodedImageFormat.Png, 100);
75 | await File.WriteAllBytesAsync(newDiffImage, png.ToArray());
76 | }
77 |
78 | // Uncomment following line to update or create an allowed diff file
79 | // File.Copy(newDiffImage, allowedDiffImage, true);
80 |
81 | if (File.Exists(allowedDiffImage))
82 | {
83 | if (!Compare.ImagesHaveEqualSize(actualFullPath, allowedDiffImage))
84 | {
85 | Assert.Fail($"AllowedDiffImage Dimension differs from allowed \nReplace {allowedDiffImage} with {actualFullPath}.");
86 | }
87 |
88 | var resultWithAllowedDiff = Compare.CalcDiff(actualFullPath, expectFullPath, allowedDiffImage);
89 |
90 | Assert.True(resultWithAllowedDiff.PixelErrorCount <= allowedPixelErrorCount, $"Expected PixelErrorCount beyond {allowedPixelErrorCount} but was {resultWithAllowedDiff.PixelErrorCount}\nExpected {expectFullPath}\ndiffers to actual {actualFullPath}\n Diff is {newDiffImage}\n");
91 |
92 | DroptFilesFromTestResultFolder(filePathInTestResultFolderOfExpectation, filePathInTestResultFolderOfActual);
93 | return;
94 | }
95 |
96 | var result = Compare.CalcDiff(actualFullPath, expectFullPath);
97 |
98 | Assert.True(result.PixelErrorCount <= allowedPixelErrorCount, $"Expected PixelErrorCount beyond {allowedPixelErrorCount} but was {result.PixelErrorCount}\nExpected {expectFullPath}\ndiffers to actual {actualFullPath}\n Diff is {newDiffImage} \nReplace {actualFullPath} with the new value or store the diff as {allowedDiffImage}.");
99 |
100 | DroptFilesFromTestResultFolder(filePathInTestResultFolderOfExpectation, filePathInTestResultFolderOfActual);
101 | }
102 |
103 | private static void DroptFilesFromTestResultFolder(string filePathInTestResultFolderOfExpectation, string filePathInTestResultFolderOfActual)
104 | {
105 | File.Delete(filePathInTestResultFolderOfExpectation);
106 | File.Delete(filePathInTestResultFolderOfActual);
107 | }
108 |
109 | private static string SaveToTestresults(string filePath, string filename)
110 | {
111 | var netEnvironment = $"NetRuntime{Environment.Version}";
112 |
113 | var testResultDirectory = Path.Combine(Environment.CurrentDirectory, "../../../../TestResult");
114 | if (!Directory.Exists(testResultDirectory))
115 | {
116 | Directory.CreateDirectory(testResultDirectory);
117 | }
118 | var destinationPathInTestResultDirectory = Path.Combine(testResultDirectory, netEnvironment + filename);
119 |
120 | if (File.Exists(destinationPathInTestResultDirectory))
121 | {
122 | File.Delete(destinationPathInTestResultDirectory);
123 | }
124 |
125 | File.Copy(filePath, destinationPathInTestResultDirectory);
126 |
127 | return destinationPathInTestResultDirectory;
128 | }
129 | }
130 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/BasicTextFormated.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/BasicTextFormated.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/EmptyDocument.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/EmptyDocument.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/Font.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/Font.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/Images.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/Images.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/SymbolRibbon.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/SymbolRibbon.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/Symbols.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/Symbols.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/TestInput.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/TestInput.png
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/TwoPages.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/TwoPages.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/Wingdings.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/Wingdings.docx
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TestInput/WingdingsSymbols.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Codeuctivity/OpenXmlToHtml/649ac1b8d6f6ccb18f32e0c217b8a770d566a45b/OpenXmlToHtmlTests/TestInput/WingdingsSymbols.pdf
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/TextSymbolToUnicodeHandlerTests.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlToHtml;
2 | using System.Collections.Generic;
3 | using Xunit;
4 |
5 | namespace OpenXmlToHtmlTests
6 | {
7 | public class TextSymbolToUnicodeHandlerTests
8 | {
9 | [Theory]
10 | [InlineData("1", "•1", "Symbol")]
11 | [InlineData("1", "1", "arial")]
12 | public void ShouldTranslateTextWithCustomGlyphToUnicode(string original, string expectedEquivalent, string fontFamily)
13 | {
14 | var currentStyle = new Dictionary { { "font-family", fontFamily } };
15 |
16 | var WordprocessingTextSymbolToUnicodeHandler = new TextSymbolToUnicodeHandler();
17 |
18 | var actual = WordprocessingTextSymbolToUnicodeHandler.TransformText(original, currentStyle);
19 |
20 | Assert.Equal(expectedEquivalent, actual);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/OpenXmlToHtmlTests/WebSafeFontsHandlerTests.cs:
--------------------------------------------------------------------------------
1 | using Codeuctivity.OpenXmlPowerTools;
2 | using Codeuctivity.OpenXmlToHtml;
3 |
4 | using System.Xml.Linq;
5 | using Xunit;
6 |
7 | namespace OpenXmlToHtmlTests
8 | {
9 | public class WebSafeFontsHandlerTests
10 | {
11 | [Fact]
12 | public void ShouldTranslateFontInRunSymbolWithFontHandler()
13 | {
14 | var fontHandler = new WebSafeFontsHandler();
15 |
16 | var element = new XElement("run", new XElement(W.sym, new XAttribute(W.font, "SomeBadSymbolFont")), new XAttribute(PtOpenXml.FontName, "SomeBadRunFont"));
17 |
18 | var actual = fontHandler.TranslateRunStyleFont(element);
19 |
20 | Assert.Equal("Arial", actual);
21 | }
22 |
23 | [Fact]
24 | public void ShouldTranslateFontInRunWithFontHandler()
25 | {
26 | var fontHandler = new WebSafeFontsHandler();
27 |
28 | var element = new XElement("run", new XAttribute(PtOpenXml.FontName, "SomeBadRunFont"));
29 |
30 | var actual = fontHandler.TranslateRunStyleFont(element);
31 |
32 | Assert.Equal("Arial", actual);
33 | }
34 |
35 | [Fact]
36 | public void ShouldTranslateFontInParagraphWithFontHandler()
37 | {
38 | var fontHandler = new WebSafeFontsHandler();
39 |
40 | var element = new XElement("run", new XAttribute(PtOpenXml.FontName, "SomeBadRunFont"));
41 |
42 | var actual = fontHandler.TranslateParagraphStyleFont(element);
43 |
44 | Assert.Equal("Arial", actual);
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenXmlToHtml
2 |
3 | Converts docx to html
4 |
5 | [](https://www.nuget.org/packages/Codeuctivity.OpenXmlToHtml/) [](https://github.com/Codeuctivity/OpenXmlToHtml/actions/workflows/dotnet.yml)
6 |
7 | - .net implementation
8 | - No external infrastructure needed (No Microsoft Office or Libre Office needed)
9 | - Focused on Windows and Linux support
10 | - Demo CLI Api [OpenXmlToHtmlCli.zip](https://github.com/Codeuctivity/OpenXmlToHtml/releases)
11 |
12 | ```c#
13 | await OpenXmlToHtml.ConvertToHtmlAsync(inputPathDocx, outputPathHtml);
14 | ```
15 |
--------------------------------------------------------------------------------
/cla.md:
--------------------------------------------------------------------------------
1 | # Codeuctivity Individual Contributor License Agreement
2 |
3 | Thank you for your interest in contributing to open source software projects (“Projects”) made available by Codeuctivity. This Individual Contributor License Agreement (“Agreement”) sets out the terms governing any source code, object code, bug fixes, configuration changes, tools, specifications, documentation, data, materials, feedback, information or other works of authorship that you submit or have submitted, in any form and in any manner, to Codeuctivity in respect of any of the Projects (collectively “Contributions”).
4 |
5 | You agree that the following terms apply to all of your past, present and future Contributions. Except for the licenses granted in this Agreement, you retain all of your right, title and interest in and to your Contributions.
6 |
7 | **Copyright License.** You hereby grant, and agree to grant, to Codeuctivity a non-exclusive, perpetual, irrevocable, worldwide, fully-paid, royalty-free, transferable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute your Contributions and such derivative works, with the right to sublicense the foregoing rights through multiple tiers of sublicensees.
8 |
9 | **Patent License.** You hereby grant, and agree to grant, to Codeuctivity a non-exclusive, perpetual, irrevocable,
10 | worldwide, fully-paid, royalty-free, transferable patent license to make, have made, use, offer to sell, sell,
11 | import, and otherwise transfer your Contributions, where such license applies only to those patent claims
12 | licensable by you that are necessarily infringed by your Contributions alone or by combination of your
13 | Contributions with the Project to which such Contributions were submitted, with the right to sublicense the
14 | foregoing rights through multiple tiers of sublicensees.
15 |
16 | **Moral Rights.** To the fullest extent permitted under applicable law, you hereby waive, and agree not to
17 | assert, all of your “moral rights” in or relating to your Contributions for the benefit of Codeuctivity, its assigns, and
18 | their respective direct and indirect sublicensees.
19 |
20 | **Third Party Content/Rights.** If your Contribution includes or is based on any source code, object code, bug
21 | fixes, configuration changes, tools, specifications, documentation, data, materials, feedback, information or
22 | other works of authorship that were not authored by you (“Third Party Content”) or if you are aware of any
23 | third party intellectual property or proprietary rights associated with your Contribution (“Third Party Rights”),
24 | then you agree to include with the submission of your Contribution full details respecting such Third Party
25 | Content and Third Party Rights, including, without limitation, identification of which aspects of your
26 | Contribution contain Third Party Content or are associated with Third Party Rights, the owner/author of the
27 | Third Party Content and Third Party Rights, where you obtained the Third Party Content, and any applicable
28 | third party license terms or restrictions respecting the Third Party Content and Third Party Rights. For greater
29 | certainty, the foregoing obligations respecting the identification of Third Party Content and Third Party Rights
30 | do not apply to any portion of a Project that is incorporated into your Contribution to that same Project.
31 |
32 | **Representations.** You represent that, other than the Third Party Content and Third Party Rights identified by
33 | you in accordance with this Agreement, you are the sole author of your Contributions and are legally entitled
34 | to grant the foregoing licenses and waivers in respect of your Contributions. If your Contributions were
35 | created in the course of your employment with your past or present employer(s), you represent that such
36 | employer(s) has authorized you to make your Contributions on behalf of such employer(s) or such employer
37 | (s) has waived all of their right, title or interest in or to your Contributions.
38 |
39 | **Disclaimer.** To the fullest extent permitted under applicable law, your Contributions are provided on an "asis"
40 | basis, without any warranties or conditions, express or implied, including, without limitation, any implied
41 | warranties or conditions of non-infringement, merchantability or fitness for a particular purpose. You are not
42 | required to provide support for your Contributions, except to the extent you desire to provide support.
43 |
44 | **No Obligation.** You acknowledge that Codeuctivity is under no obligation to use or incorporate your Contributions
45 | into any of the Projects. The decision to use or incorporate your Contributions into any of the Projects will be
46 | made at the sole discretion of Codeuctivity or its authorized delegates.
47 |
48 | **Disputes.** This Agreement shall be governed by and construed in accordance with the laws of Austria, without giving effect to its principles or rules regarding conflicts of laws,
49 | other than such principles directing application of Austrian law. The parties hereby submit to venue in, and
50 | jurisdiction of the courts located in Vienna, Austria for purposes relating to this Agreement. In the event
51 | that any of the provisions of this Agreement shall be held by a court or other tribunal of competent jurisdiction
52 | to be unenforceable, the remaining portions hereof shall remain in full force and effect.
53 |
54 | **Assignment.** You agree that Codeuctivity may assign this Agreement, and all of its rights, obligations and licenses
55 | hereunder.
56 |
--------------------------------------------------------------------------------
/signatures/version1/cla.json:
--------------------------------------------------------------------------------
1 | {
2 | "signedContributors": []
3 | }
--------------------------------------------------------------------------------
/testenvironments.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1",
3 | "environments": [
4 | {
5 | "name": "Ubuntu",
6 | "type": "wsl",
7 | "wslDistribution": "Ubuntu"
8 | }
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------