├── .gitattributes
├── .gitignore
├── .nuke
├── LICENSE
├── README.md
├── ReportDotNet.sln
├── ReportDotNet.sln.DotSettings
├── build.cmd
├── build.ps1
├── build.sh
├── build
├── .editorconfig
├── Build.cs
├── _build.csproj
└── _build.csproj.DotSettings
├── gif.gif
├── src
├── ReportDotNet.Core
│ ├── Alignment.cs
│ ├── BorderStyle.cs
│ ├── Borders.cs
│ ├── Cell.cs
│ ├── CellBuilder.cs
│ ├── CellParameters.cs
│ ├── Create.cs
│ ├── Factories.cs
│ ├── Field.cs
│ ├── FieldPart.cs
│ ├── Helpers.cs
│ ├── IDocument.cs
│ ├── IPageElement.cs
│ ├── Page.cs
│ ├── PageBuilder.cs
│ ├── PageLayout.cs
│ ├── PageOrientation.cs
│ ├── PageParameters.cs
│ ├── PageSize.cs
│ ├── Paragraph.cs
│ ├── ParagraphBuilder.cs
│ ├── ParagraphParameters.cs
│ ├── Part.cs
│ ├── Picture.cs
│ ├── PictureBuilder.cs
│ ├── PictureParameters.cs
│ ├── PicturePart.cs
│ ├── ReportDotNet.Core.csproj
│ ├── Row.cs
│ ├── RowBuilder.cs
│ ├── RowHeightType.cs
│ ├── RowParameters.cs
│ ├── StubPicture.cs
│ ├── StubPictureBuilder.cs
│ ├── StubPictureParameters.cs
│ ├── StubPicturePart.cs
│ ├── Table.cs
│ ├── TableBuilder.cs
│ ├── TableParameters.cs
│ ├── TextDirection.cs
│ ├── TextPart.cs
│ └── VerticalAlignment.cs
├── ReportDotNet.Docx
│ ├── Converters
│ │ ├── CellConverter.cs
│ │ ├── PageConverter.cs
│ │ ├── ParagraphConverter.cs
│ │ ├── PictureConverter.cs
│ │ ├── RowConverter.cs
│ │ └── TableConverter.cs
│ ├── CreateExtensions.cs
│ ├── DefaultStyles.cs
│ ├── DocxDocument.cs
│ ├── Extensions.cs
│ ├── FillRectangleOffsetsCalculator.cs
│ ├── Offsets.cs
│ ├── OpenXmlUnits.cs
│ ├── ReportDotNet.Docx.csproj
│ ├── ReportDotNet.Docx.nuspec
│ └── packages.config
└── ReportDotNet.Web
│ ├── App
│ ├── DirectoryWatcher.cs
│ ├── GoogleDocsUploader.cs
│ ├── ReportHub.cs
│ └── ReportRenderer.cs
│ ├── Controllers
│ └── HomeController.cs
│ ├── Examples
│ ├── PaymentOrder
│ │ ├── Data.cs
│ │ └── Template.cs
│ ├── Simple
│ │ └── Template.cs
│ ├── SimpleXml
│ │ ├── [Content_Types].xml
│ │ ├── _rels
│ │ │ └── .rels
│ │ ├── docProps
│ │ │ ├── app.xml
│ │ │ └── core.xml
│ │ └── word
│ │ │ ├── _rels
│ │ │ └── document.xml.rels
│ │ │ ├── document.xml
│ │ │ ├── fontTable.xml
│ │ │ ├── settings.xml
│ │ │ ├── styles.xml
│ │ │ ├── theme
│ │ │ └── theme1.xml
│ │ │ └── webSettings.xml
│ └── StampAndSigns
│ │ ├── AccountantSign.png
│ │ ├── BossSign.png
│ │ ├── Data.cs
│ │ ├── Stamp.png
│ │ └── Template.cs
│ ├── Program.cs
│ ├── ReportDotNet.Web.csproj
│ ├── Startup.cs
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ ├── wwwroot
│ ├── index.css
│ ├── index.html
│ ├── index.js
│ ├── jquery-3.1.1.js
│ ├── jquery-3.1.1.min.js
│ └── signalr.min.js
│ └── yarn.lock
└── tests
└── ReportDotNet.Core.Tests
├── CellBuilderTest.cs
├── ReportDotNet.Core.Tests.csproj
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
49 | ## Ignore Visual Studio temporary files, build results, and
50 | ## files generated by popular Visual Studio add-ons.
51 | ##
52 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
53 |
54 | # User-specific files
55 | *.suo
56 | *.user
57 | *.userosscache
58 | *.sln.docstates
59 |
60 | # User-specific files (MonoDevelop/Xamarin Studio)
61 | *.userprefs
62 |
63 | # Build results
64 | [Dd]ebug/
65 | [Dd]ebugPublic/
66 | [Rr]elease/
67 | [Rr]eleases/
68 | x64/
69 | x86/
70 | bld/
71 | [Bb]in/
72 | [Oo]bj/
73 | [Ll]og/
74 |
75 | # Visual Studio 2015 cache/options directory
76 | .vs/
77 | # Uncomment if you have tasks that create the project's static files in wwwroot
78 | #wwwroot/
79 |
80 | # MSTest test Results
81 | [Tt]est[Rr]esult*/
82 | [Bb]uild[Ll]og.*
83 |
84 | # NUNIT
85 | *.VisualState.xml
86 | TestResult.xml
87 |
88 | # Build Results of an ATL Project
89 | [Dd]ebugPS/
90 | [Rr]eleasePS/
91 | dlldata.c
92 |
93 | # .NET Core
94 | project.lock.json
95 | project.fragment.lock.json
96 | artifacts/
97 | **/Properties/launchSettings.json
98 |
99 | *_i.c
100 | *_p.c
101 | *_i.h
102 | *.ilk
103 | *.meta
104 | *.obj
105 | *.pch
106 | *.pdb
107 | *.pgc
108 | *.pgd
109 | *.rsp
110 | *.sbr
111 | *.tlb
112 | *.tli
113 | *.tlh
114 | *.tmp
115 | *.tmp_proj
116 | *.log
117 | *.vspscc
118 | *.vssscc
119 | .builds
120 | *.pidb
121 | *.svclog
122 | *.scc
123 |
124 | # Chutzpah Test files
125 | _Chutzpah*
126 |
127 | # Visual C++ cache files
128 | ipch/
129 | *.aps
130 | *.ncb
131 | *.opendb
132 | *.opensdf
133 | *.sdf
134 | *.cachefile
135 | *.VC.db
136 | *.VC.VC.opendb
137 |
138 | # Visual Studio profiler
139 | *.psess
140 | *.vsp
141 | *.vspx
142 | *.sap
143 |
144 | # TFS 2012 Local Workspace
145 | $tf/
146 |
147 | # Guidance Automation Toolkit
148 | *.gpState
149 |
150 | # ReSharper is a .NET coding add-in
151 | _ReSharper*/
152 | *.[Rr]e[Ss]harper
153 | *.DotSettings.user
154 |
155 | # JustCode is a .NET coding add-in
156 | .JustCode
157 |
158 | # TeamCity is a build add-in
159 | _TeamCity*
160 |
161 | # DotCover is a Code Coverage Tool
162 | *.dotCover
163 |
164 | # Visual Studio code coverage results
165 | *.coverage
166 | *.coveragexml
167 |
168 | # NCrunch
169 | _NCrunch_*
170 | .*crunch*.local.xml
171 | nCrunchTemp_*
172 |
173 | # MightyMoose
174 | *.mm.*
175 | AutoTest.Net/
176 |
177 | # Web workbench (sass)
178 | .sass-cache/
179 |
180 | # Installshield output folder
181 | [Ee]xpress/
182 |
183 | # DocProject is a documentation generator add-in
184 | DocProject/buildhelp/
185 | DocProject/Help/*.HxT
186 | DocProject/Help/*.HxC
187 | DocProject/Help/*.hhc
188 | DocProject/Help/*.hhk
189 | DocProject/Help/*.hhp
190 | DocProject/Help/Html2
191 | DocProject/Help/html
192 |
193 | # Click-Once directory
194 | publish/
195 |
196 | # Publish Web Output
197 | *.[Pp]ublish.xml
198 | *.azurePubxml
199 | # TODO: Comment the next line if you want to checkin your web deploy settings
200 | # but database connection strings (with potential passwords) will be unencrypted
201 | *.pubxml
202 | *.publishproj
203 |
204 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
205 | # checkin your Azure Web App publish settings, but sensitive information contained
206 | # in these scripts will be unencrypted
207 | PublishScripts/
208 |
209 | # NuGet Packages
210 | *.nupkg
211 | # The packages folder can be ignored because of Package Restore
212 | **/packages/*
213 | # except build/, which is used as an MSBuild target.
214 | !**/packages/build/
215 | # Uncomment if necessary however generally it will be regenerated when needed
216 | #!**/packages/repositories.config
217 | # NuGet v3's project.json files produces more ignorable files
218 | *.nuget.props
219 | *.nuget.targets
220 |
221 | # Microsoft Azure Build Output
222 | csx/
223 | *.build.csdef
224 |
225 | # Microsoft Azure Emulator
226 | ecf/
227 | rcf/
228 |
229 | # Windows Store app package directories and files
230 | AppPackages/
231 | BundleArtifacts/
232 | Package.StoreAssociation.xml
233 | _pkginfo.txt
234 |
235 | # Visual Studio cache files
236 | # files ending in .cache can be ignored
237 | *.[Cc]ache
238 | # but keep track of directories ending in .cache
239 | !*.[Cc]ache/
240 |
241 | # Others
242 | ClientBin/
243 | ~$*
244 | *~
245 | *.dbmdl
246 | *.dbproj.schemaview
247 | *.jfm
248 | *.pfx
249 | *.publishsettings
250 | orleans.codegen.cs
251 |
252 | # Since there are multiple workflows, uncomment next line to ignore bower_components
253 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
254 | #bower_components/
255 |
256 | # RIA/Silverlight projects
257 | Generated_Code/
258 |
259 | # Backup & report files from converting an old project file
260 | # to a newer Visual Studio version. Backup files are not needed,
261 | # because we have git ;-)
262 | _UpgradeReport_Files/
263 | Backup*/
264 | UpgradeLog*.XML
265 | UpgradeLog*.htm
266 |
267 | # SQL Server files
268 | *.mdf
269 | *.ldf
270 | *.ndf
271 |
272 | # Business Intelligence projects
273 | *.rdl.data
274 | *.bim.layout
275 | *.bim_*.settings
276 |
277 | # Microsoft Fakes
278 | FakesAssemblies/
279 |
280 | # GhostDoc plugin setting file
281 | *.GhostDoc.xml
282 |
283 | # Node.js Tools for Visual Studio
284 | .ntvs_analysis.dat
285 | node_modules/
286 |
287 | # Typescript v1 declaration files
288 | typings/
289 |
290 | # Visual Studio 6 build log
291 | *.plg
292 |
293 | # Visual Studio 6 workspace options file
294 | *.opt
295 |
296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
297 | *.vbw
298 |
299 | # Visual Studio LightSwitch build output
300 | **/*.HTMLClient/GeneratedArtifacts
301 | **/*.DesktopClient/GeneratedArtifacts
302 | **/*.DesktopClient/ModelManifest.xml
303 | **/*.Server/GeneratedArtifacts
304 | **/*.Server/ModelManifest.xml
305 | _Pvt_Extensions
306 |
307 | # Paket dependency manager
308 | .paket/paket.exe
309 | paket-files/
310 |
311 | # FAKE - F# Make
312 | .fake/
313 |
314 | # JetBrains Rider
315 | .idea/
316 | *.sln.iml
317 |
318 | # CodeRush
319 | .cr/
320 |
321 | # Python Tools for Visual Studio (PTVS)
322 | __pycache__/
323 | *.pyc
324 |
325 | # Cake - Uncomment if you are using it
326 | # tools/**
327 | # !tools/packages.config
328 |
329 | # Telerik's JustMock configuration file
330 | *.jmconfig
331 |
332 | # BizTalk build output
333 | *.btp.cs
334 | *.btm.cs
335 | *.odx.cs
336 | *.xsd.cs
337 |
--------------------------------------------------------------------------------
/.nuke:
--------------------------------------------------------------------------------
1 | ReportDotNet.sln
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Vyacheslav Mostovoy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ReportDotNet
2 |
3 | ### Write the code and see the resulting docx in real time
4 | 
5 |
--------------------------------------------------------------------------------
/ReportDotNet.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportDotNet.Core", "src\ReportDotNet.Core\ReportDotNet.Core.csproj", "{3BE01964-7B8B-40E1-9BC1-8FA13AB274AE}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportDotNet.Docx", "src\ReportDotNet.Docx\ReportDotNet.Docx.csproj", "{4D668235-EDD3-4C25-9CA7-59878E3D4FFB}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportDotNet.Core.Tests", "tests\ReportDotNet.Core.Tests\ReportDotNet.Core.Tests.csproj", "{92207667-DC9F-4DE8-954D-0067839B89CD}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReportDotNet.Web", "src\ReportDotNet.Web\ReportDotNet.Web.csproj", "{B0ED4323-F629-4FDC-AC84-7E7976D110FD}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{50E9C5BF-6D6E-4315-B5ED-2874B79DAC24}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {50E9C5BF-6D6E-4315-B5ED-2874B79DAC24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {50E9C5BF-6D6E-4315-B5ED-2874B79DAC24}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {3BE01964-7B8B-40E1-9BC1-8FA13AB274AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {3BE01964-7B8B-40E1-9BC1-8FA13AB274AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {3BE01964-7B8B-40E1-9BC1-8FA13AB274AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {3BE01964-7B8B-40E1-9BC1-8FA13AB274AE}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {4D668235-EDD3-4C25-9CA7-59878E3D4FFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {4D668235-EDD3-4C25-9CA7-59878E3D4FFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {4D668235-EDD3-4C25-9CA7-59878E3D4FFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {4D668235-EDD3-4C25-9CA7-59878E3D4FFB}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {92207667-DC9F-4DE8-954D-0067839B89CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {92207667-DC9F-4DE8-954D-0067839B89CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {92207667-DC9F-4DE8-954D-0067839B89CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {92207667-DC9F-4DE8-954D-0067839B89CD}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {B0ED4323-F629-4FDC-AC84-7E7976D110FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {B0ED4323-F629-4FDC-AC84-7E7976D110FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {B0ED4323-F629-4FDC-AC84-7E7976D110FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {B0ED4323-F629-4FDC-AC84-7E7976D110FD}.Release|Any CPU.Build.0 = Release|Any CPU
40 | EndGlobalSection
41 | GlobalSection(SolutionProperties) = preSolution
42 | HideSolutionNode = FALSE
43 | EndGlobalSection
44 | EndGlobal
45 |
--------------------------------------------------------------------------------
/ReportDotNet.sln.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | Space
3 | NEVER
4 | True
5 | True
6 | True
7 | True
8 | True
9 | True
10 | True
11 | True
12 | True
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | :; set -eo pipefail
2 | :; ./build.sh "$@"
3 | :; exit $?
4 |
5 | @ECHO OFF
6 | powershell -ExecutionPolicy ByPass -NoProfile %0\..\build.ps1 %*
7 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | Param(
3 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
4 | [string[]]$BuildArguments
5 | )
6 |
7 | Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
8 |
9 | Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { exit 1 }
10 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
11 |
12 | ###########################################################################
13 | # CONFIGURATION
14 | ###########################################################################
15 |
16 | $BuildProjectFile = "$PSScriptRoot\build\_build.csproj"
17 | $TempDirectory = "$PSScriptRoot\\.tmp"
18 |
19 | $DotNetGlobalFile = "$PSScriptRoot\\global.json"
20 | $DotNetInstallUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1"
21 | $DotNetChannel = "Current"
22 |
23 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
24 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
25 |
26 | ###########################################################################
27 | # EXECUTION
28 | ###########################################################################
29 |
30 | function ExecSafe([scriptblock] $cmd) {
31 | & $cmd
32 | if ($LASTEXITCODE) { exit $LASTEXITCODE }
33 | }
34 |
35 | # If global.json exists, load expected version
36 | if (Test-Path $DotNetGlobalFile) {
37 | $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
38 | if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
39 | $DotNetVersion = $DotNetGlobal.sdk.version
40 | }
41 | }
42 |
43 | # If dotnet is installed locally, and expected version is not set or installation matches the expected version
44 | if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
45 | (!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) {
46 | $env:DOTNET_EXE = (Get-Command "dotnet").Path
47 | }
48 | else {
49 | $DotNetDirectory = "$TempDirectory\dotnet-win"
50 | $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
51 |
52 | # Download install script
53 | $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
54 | New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
55 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
56 |
57 | # Install by channel or version
58 | if (!(Test-Path variable:DotNetVersion)) {
59 | ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
60 | } else {
61 | ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
62 | }
63 | }
64 |
65 | Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
66 |
67 | ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false -nologo -clp:NoSummary --verbosity quiet }
68 | ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
69 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | echo $(bash --version 2>&1 | head -n 1)
4 |
5 | set -eo pipefail
6 | SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
7 |
8 | ###########################################################################
9 | # CONFIGURATION
10 | ###########################################################################
11 |
12 | BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj"
13 | TEMP_DIRECTORY="$SCRIPT_DIR//.tmp"
14 |
15 | DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
16 | DOTNET_INSTALL_URL="https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.sh"
17 | DOTNET_CHANNEL="Current"
18 |
19 | export DOTNET_CLI_TELEMETRY_OPTOUT=1
20 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
21 |
22 | ###########################################################################
23 | # EXECUTION
24 | ###########################################################################
25 |
26 | function FirstJsonValue {
27 | perl -nle 'print $1 if m{"'$1'": "([^"]+)",?}' <<< ${@:2}
28 | }
29 |
30 | # If global.json exists, load expected version
31 | if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
32 | DOTNET_VERSION=$(FirstJsonValue "version" $(cat "$DOTNET_GLOBAL_FILE"))
33 | if [[ "$DOTNET_VERSION" == "" ]]; then
34 | unset DOTNET_VERSION
35 | fi
36 | fi
37 |
38 | # If dotnet is installed locally, and expected version is not set or installation matches the expected version
39 | if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version 2>&1) == "$DOTNET_VERSION") ]]; then
40 | export DOTNET_EXE="$(command -v dotnet)"
41 | else
42 | DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
43 | export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
44 |
45 | # Download install script
46 | DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
47 | mkdir -p "$TEMP_DIRECTORY"
48 | curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
49 | chmod +x "$DOTNET_INSTALL_FILE"
50 |
51 | # Install by channel or version
52 | if [[ -z ${DOTNET_VERSION+x} ]]; then
53 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
54 | else
55 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
56 | fi
57 | fi
58 |
59 | echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
60 |
61 | "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false -nologo -clp:NoSummary --verbosity quiet
62 | "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
63 |
--------------------------------------------------------------------------------
/build/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 | dotnet_style_qualification_for_field = false:warning
3 | dotnet_style_qualification_for_property = false:warning
4 | dotnet_style_qualification_for_method = false:warning
5 | dotnet_style_qualification_for_event = false:warning
6 | dotnet_style_require_accessibility_modifiers = never:warning
7 |
8 | csharp_style_expression_bodied_methods = true:silent
9 | csharp_style_expression_bodied_properties = true:warning
10 | csharp_style_expression_bodied_indexers = true:warning
11 | csharp_style_expression_bodied_accessors = true:warning
12 |
--------------------------------------------------------------------------------
/build/Build.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Nuke.Common;
3 | using Nuke.Common.Execution;
4 | using Nuke.Common.Git;
5 | using Nuke.Common.IO;
6 | using Nuke.Common.ProjectModel;
7 | using Nuke.Common.Tooling;
8 | using Nuke.Common.Tools.DotNet;
9 | using Nuke.Common.Tools.GitHub;
10 | using Nuke.Common.Tools.GitVersion;
11 | using Nuke.Common.Utilities.Collections;
12 | using static Nuke.Common.IO.FileSystemTasks;
13 | using static Nuke.Common.IO.PathConstruction;
14 | using static Nuke.Common.Tools.DotNet.DotNetTasks;
15 |
16 | [CheckBuildProjectConfigurations]
17 | class Build: NukeBuild
18 | {
19 | public static int Main() => Execute(x => x.Compile);
20 |
21 | [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")]
22 | readonly Configuration Configuration =
23 | IsLocalBuild
24 | ? Configuration.Debug
25 | : Configuration.Release;
26 |
27 | [Parameter("NuGet api key")] readonly string ApiKey;
28 | readonly string LicenseFile = RootDirectory / "LICENSE";
29 |
30 | [Parameter("Local nuget source")] readonly string LocalNugetSource;
31 |
32 | [Solution] readonly Solution Solution;
33 | [GitRepository] readonly GitRepository GitRepository;
34 | [GitVersion] readonly GitVersion GitVersion;
35 |
36 | AbsolutePath SourceDirectory => RootDirectory / "src";
37 | AbsolutePath TestsDirectory => RootDirectory / "tests";
38 | AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts";
39 |
40 | Target Clean
41 | => _ => _
42 | .Before(Restore)
43 | .Executes(() =>
44 | {
45 | SourceDirectory.GlobDirectories("**/bin", "**/obj")
46 | .ToArray()
47 | .ForEach(DeleteDirectory);
48 | TestsDirectory.GlobDirectories("**/bin", "**/obj")
49 | .ToArray()
50 | .ForEach(DeleteDirectory);
51 | EnsureCleanDirectory(ArtifactsDirectory);
52 | });
53 |
54 | Target Restore
55 | => _ => _
56 | .Executes(() =>
57 | {
58 | DotNetRestore(s => s
59 | .SetProjectFile(Solution));
60 | });
61 |
62 | Target Compile
63 | => _ => _
64 | .DependsOn(Restore)
65 | .Executes(() =>
66 | {
67 | DotNetBuild(s => s
68 | .SetProjectFile(Solution)
69 | .SetConfiguration(Configuration)
70 | .SetAssemblyVersion(GitVersion.AssemblySemVer)
71 | .SetFileVersion(GitVersion.AssemblySemFileVer)
72 | .SetInformationalVersion(GitVersion.InformationalVersion)
73 | .EnableNoRestore());
74 | });
75 |
76 | Target Pack
77 | => _ => _
78 | .DependsOn(Clean, Compile)
79 | .Executes(() =>
80 | {
81 | var licenseUrl =
82 | GitRepository.GetGitHubBrowseUrl(LicenseFile, "master");
83 | DotNetPack(s => s
84 | //.SetPackageReleaseNotes(changelogUrl)
85 | .SetWorkingDirectory(RootDirectory)
86 | .SetPackageLicenseUrl(licenseUrl)
87 | .SetProject(Solution.Path)
88 | .SetRepositoryUrl("https://github.com/mifopen/ReportDotNet")
89 | .EnableNoBuild()
90 | .SetConfiguration(Configuration)
91 | .EnableIncludeSymbols()
92 | .SetOutputDirectory(ArtifactsDirectory)
93 | .SetDescription("Docx reports generator")
94 | .SetAuthors("mif")
95 | .SetPackageTags("reports", "docx")
96 | .SetVersion(GitVersion.NuGetVersionV2));
97 | });
98 |
99 | Target Publish
100 | => _ => _
101 | .DependsOn(Pack)
102 | .Requires(() => ApiKey)
103 | .Requires(() => Equals(Configuration, Configuration.Release))
104 | .Executes(() =>
105 | {
106 | GlobFiles(ArtifactsDirectory, "*.nupkg")
107 | .NotEmpty()
108 | .Where(x => !x.EndsWith(".symbols.nupkg"))
109 | .ForEach(x => DotNetNuGetPush(s => s
110 | .SetTargetPath(x)
111 | .SetSource("https://api.nuget.org/v3/index.json")
112 | .SetApiKey(ApiKey)));
113 | });
114 |
115 | Target PublishLocal
116 | => _ => _
117 | .DependsOn(Pack)
118 | .Requires(() => LocalNugetSource)
119 | .Executes(() =>
120 | {
121 | EnsureExistingDirectory(LocalNugetSource);
122 | GlobFiles(ArtifactsDirectory, "*.nupkg")
123 | .NotEmpty()
124 | .Where(x => !x.EndsWith(".symbols.nupkg"))
125 | .ForEach(x => DotNetNuGetPush(s => s
126 | .SetTargetPath(x)
127 | .SetSource(LocalNugetSource)));
128 | });
129 | }
130 |
--------------------------------------------------------------------------------
/build/_build.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp3.0
6 | CS0649;CS0169
7 | ..
8 | ..
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/build/_build.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | DO_NOT_SHOW
3 | DO_NOT_SHOW
4 | Implicit
5 | Implicit
6 | ExpressionBody
7 | 0
8 | NEXT_LINE
9 | True
10 | False
11 | 120
12 | IF_OWNER_IS_SINGLE_LINE
13 | WRAP_IF_LONG
14 | False
15 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
16 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
17 | True
18 | True
19 | True
20 | True
21 | True
22 | True
23 | True
24 | True
25 | True
26 |
--------------------------------------------------------------------------------
/gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mifopen/ReportDotNet/6a5b69baee0894a39833da4d9957f60f6631ee47/gif.gif
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Alignment.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public enum Alignment
4 | {
5 | Left,
6 | Center,
7 | Right,
8 | Both
9 | }
10 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/BorderStyle.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public enum BorderStyle
4 | {
5 | Single,
6 | Dashed,
7 | DotDash,
8 | DotDotDash
9 | }
10 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Borders.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ReportDotNet.Core
4 | {
5 | [Flags]
6 | public enum Borders
7 | {
8 | None = 0,
9 | Top = 1 << 0,
10 | Left = 1 << 1,
11 | Bottom = 1 << 2,
12 | Right = 1 << 3,
13 | All = Top | Left | Bottom | Right
14 | }
15 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Cell.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class Cell
4 | {
5 | public CellParameters Parameters { get; }
6 |
7 | public Cell(CellParameters parameters)
8 | {
9 | Parameters = parameters;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/CellBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 |
5 | namespace ReportDotNet.Core
6 | {
7 | public class CellBuilder
8 | {
9 | private readonly CellParameters parameters = new CellParameters();
10 | private string text;
11 | private int? fontSize;
12 | private Alignment? alignment;
13 | private bool bold;
14 | private double? spaceBetweenLines;
15 |
16 | public CellBuilder Width(int? width) => Chain(p => p.Width = width);
17 | public CellBuilder Add(Paragraph paragraph) => Chain(p => p.Paragraph = paragraph);
18 | public CellBuilder Add(string text) => Chain(_ => this.text = text);
19 | public CellBuilder FontSize(int fontSize) => Chain(_ => this.fontSize = fontSize);
20 | public CellBuilder Alignment(Alignment alignment) => Chain(_ => this.alignment = alignment);
21 | public CellBuilder Bold(bool bold = true) => Chain(_ => this.bold = bold);
22 | public CellBuilder SpaceBetweenLines(double? spaceBetweenLines) => Chain(_ => this.spaceBetweenLines = spaceBetweenLines);
23 | public CellBuilder VerticalAlignment(VerticalAlignment verticalAlignment) => Chain(p => p.VerticalAlignment = verticalAlignment);
24 | public CellBuilder Borders(Borders borders) => Chain(p => p.Borders = borders);
25 | public CellBuilder MergeUp(bool mergeUp = true) => Chain(p => p.MergeUp = mergeUp);
26 | public CellBuilder MergeDown(bool mergeDown = true) => Chain(p => p.MergeDown = mergeDown);
27 | public CellBuilder MergeRight(bool mergeRight = true) => Chain(p => p.MergeRight = mergeRight);
28 | public CellBuilder MergeLeft(bool mergeLeft = true) => Chain(p => p.MergeLeft = mergeLeft);
29 | public CellBuilder TextDirection(TextDirection textDirection) => Chain(p => p.TextDirection = textDirection);
30 | public CellBuilder BackgroundColor(Color backgroundColor) => Chain(p => p.BackgroundColor = backgroundColor);
31 | public CellBuilder BorderSize(int borderSize) => Chain(p => p.BorderSize = borderSize);
32 |
33 | public CellBuilder Margin(int? left = null,
34 | int? right = null,
35 | int? top = null,
36 | int? bottom = null) => Chain(p =>
37 | {
38 | p.MarginLeft = left;
39 | p.MarginRight = right;
40 | p.MarginTop = top;
41 | p.MarginBottom = bottom;
42 |
43 | });
44 |
45 |
46 | public CellBuilder Borders(BorderStyle left = BorderStyle.Single,
47 | BorderStyle top = BorderStyle.Single,
48 | BorderStyle right = BorderStyle.Single,
49 | BorderStyle bottom = BorderStyle.Single) => Chain(p =>
50 | {
51 | p.LeftBorderStyle = left;
52 | p.TopBorderStyle = top;
53 | p.RightBorderStyle = right;
54 | p.BottomBorderStyle = bottom;
55 | });
56 |
57 | public Cell Build()
58 | {
59 | //todo clone parameters?
60 | parameters.Paragraph = parameters.Paragraph ?? new Paragraph(new ParagraphParameters
61 | {
62 | Parts = new List { new TextPart { Text = text } },
63 | FontSize = fontSize,
64 | Alignment = alignment,
65 | Bold = bold,
66 | SpaceBetweenLines = spaceBetweenLines
67 | });
68 | return new Cell(parameters);
69 | }
70 |
71 | public static implicit operator Cell(CellBuilder builder) => builder.Build();
72 |
73 | private CellBuilder Chain(Action action)
74 | {
75 | action(parameters);
76 | return this;
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/CellParameters.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 |
3 | namespace ReportDotNet.Core
4 | {
5 | public class CellParameters
6 | {
7 | public Paragraph Paragraph { get; set; }
8 | public int? Width { get; set; }
9 | public VerticalAlignment? VerticalAlignment { get; set; }
10 | public Borders? Borders { get; set; }
11 | public int? MarginLeft { get; set; }
12 | public int? MarginRight { get; set; }
13 | public int? MarginTop { get; set; }
14 | public int? MarginBottom { get; set; }
15 | public bool MergeDown { get; set; }
16 | public bool MergeUp { get; set; }
17 |
18 |
19 | public bool MergeLeft { get; set; }
20 | public bool MergeRight { get; set; }
21 |
22 | public BorderStyle LeftBorderStyle { get; set; }
23 | public BorderStyle TopBorderStyle { get; set; }
24 | public BorderStyle RightBorderStyle { get; set; }
25 | public BorderStyle BottomBorderStyle { get; set; }
26 | public TextDirection? TextDirection { get; set; }
27 | public Color? BackgroundColor { get; set; }
28 | public double? BorderSize { get; set; }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Create.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class Create
4 | {
5 | // ReSharper disable once UnassignedReadonlyField
6 | public static readonly Create Document;
7 | }
8 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Factories.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public static class Factories
4 | {
5 | public static PageBuilder Page() => new PageBuilder();
6 |
7 | public static TableBuilder Table(params Row[] rows) => new TableBuilder().Add(rows);
8 | public static TableBuilder Table(int width) => new TableBuilder().Width(width);
9 |
10 | public static RowBuilder Row() => new RowBuilder();
11 | public static RowBuilder Row(int height) => new RowBuilder().Height(height);
12 | public static RowBuilder Row(params Cell[] cells) => new RowBuilder().Add(cells);
13 |
14 | public static CellBuilder Cell() => new CellBuilder();
15 | public static CellBuilder Cell(int? width) => new CellBuilder().Width(width);
16 |
17 | public static CellBuilder Cell(string text,
18 | int? width = null) => new CellBuilder().Add(text).Width(width);
19 |
20 | public static ParagraphBuilder Paragraph() => new ParagraphBuilder();
21 | public static ParagraphBuilder Paragraph(string text) => new ParagraphBuilder().Add(text);
22 |
23 | public static PictureBuilder Picture(byte[] bytes) => new PictureBuilder().Bytes(bytes);
24 | public static StubPictureBuilder StubPicture() => new StubPictureBuilder();
25 | }
26 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Field.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public enum Field
4 | {
5 | PageNumber,
6 | PageCount
7 | }
8 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/FieldPart.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class FieldPart: Part
4 | {
5 | public Field Field { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Helpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public static class Helpers
7 | {
8 | public static int[] GetWidths(int width,
9 | IEnumerable initialWidths)
10 | {
11 | var result = new[] { width };
12 | foreach (var widths in initialWidths)
13 | result = Merge(result, widths);
14 | return result;
15 | }
16 |
17 | public static int[] GetSpans(int[] tableCols,
18 | int[] rowCols)
19 | {
20 | var result = new int[rowCols.Length];
21 |
22 | var c = 0;
23 | for (var i = 0; i < rowCols.Length; i++)
24 | {
25 | var rowCol = rowCols[i];
26 | for (int j = c, span = 1; j < tableCols.Length; j++, span++)
27 | {
28 | rowCol -= tableCols[j];
29 | if (rowCol < 0)
30 | throw new InvalidOperationException("Неправильно поделились колонки для таблицы");
31 | if (rowCol > 0)
32 | continue;
33 | result[i] = span;
34 | c = j + 1;
35 | break;
36 | }
37 | }
38 |
39 | return result;
40 | }
41 |
42 | private static int[] Merge(int[] a,
43 | int[] b)
44 | {
45 | var ar = new int[a.Length];
46 | a.CopyTo(ar, 0);
47 | var br = new int[b.Length];
48 | b.CopyTo(br, 0);
49 | var result = new List();
50 | for (int i = 0, j = 0; i < ar.Length || j < br.Length;)
51 | if (i == ar.Length)
52 | {
53 | result.Add(br[j]);
54 | j++;
55 | }
56 | else if (j == br.Length)
57 | {
58 | result.Add(ar[i]);
59 | i++;
60 | }
61 | else if (ar[i] == br[j])
62 | {
63 | result.Add(ar[i]);
64 | i++;
65 | j++;
66 | }
67 | else if (ar[i] > br[j])
68 | {
69 | result.Add(br[j]);
70 | ar[i] -= br[j];
71 | j++;
72 | }
73 | else
74 | {
75 | result.Add(ar[i]);
76 | br[j] -= ar[i];
77 | i++;
78 | }
79 | return result.ToArray();
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/IDocument.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public interface IDocument
4 | {
5 | IDocument AddPage(Page page);
6 | byte[] Save();
7 | void SetDefaultPageLayout(PageLayout pageLayout);
8 | PageLayout GetDefaultPageLayout();
9 | void SetDefaultFooter(Table table);
10 | Table GetDefaultFooter();
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/IPageElement.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public interface IPageElement
4 | {
5 | }
6 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Page.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class Page
4 | {
5 | public PageParameters Parameters { get; }
6 |
7 | public Page(PageParameters parameters)
8 | {
9 | Parameters = parameters;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PageBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public class PageBuilder
7 | {
8 | private readonly PageParameters parameters = new PageParameters();
9 |
10 | public PageBuilder Orientation(PageOrientation orientation) => Chain(p => p.Orientation = orientation);
11 | public PageBuilder HeaderMargin(int headerMargin) => Chain(p => p.HeaderMargin = headerMargin);
12 | public PageBuilder FooterMargin(int footerMargin) => Chain(p => p.FooterMargin = footerMargin);
13 | public PageBuilder Size(PageSize size) => Chain(p => p.Size = size);
14 | public PageBuilder Footer(Table footer) => Chain(p => p.Footer = footer);
15 |
16 | public PageBuilder Add(params Paragraph[] paragraphs) =>
17 | Chain(p => p.Elements.AddRange(paragraphs.Where(x => x != null)));
18 |
19 | public PageBuilder Add(params Table[] tables) =>
20 | Chain(p => p.Elements.AddRange(tables.Where(x => x != null)));
21 |
22 | public PageBuilder Margin(int? left = null,
23 | int? top = null,
24 | int? right = null,
25 | int? bottom = null) => Chain(p =>
26 | {
27 | p.MarginLeft = left;
28 | p.MarginTop = top;
29 | p.MarginRight = right;
30 | p.MarginBottom = bottom;
31 | });
32 |
33 | public Page Build() => new Page(parameters);
34 |
35 | public static implicit operator Page(PageBuilder builder) => builder.Build();
36 |
37 | private PageBuilder Chain(Action action)
38 | {
39 | action(parameters);
40 | return this;
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PageLayout.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class PageLayout
4 | {
5 | public PageLayout()
6 | {
7 | Size = PageSize.A4;
8 | }
9 |
10 | public PageOrientation? Orientation { get; set; }
11 | public int? MarginLeft { get; set; }
12 | public int? MarginTop { get; set; }
13 | public int? MarginRight { get; set; }
14 | public int? MarginBottom { get; set; }
15 | public int? FooterMargin { get; set; }
16 | public int? HeaderMargin { get; set; }
17 | public PageSize Size { get; set; }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PageOrientation.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public enum PageOrientation
4 | {
5 | Portrait,
6 | Landscape
7 | }
8 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PageParameters.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ReportDotNet.Core
4 | {
5 | public class PageParameters
6 | {
7 | public PageOrientation? Orientation { get; set; }
8 | public int? MarginLeft { get; set; }
9 | public int? MarginTop { get; set; }
10 | public int? MarginRight { get; set; }
11 | public int? MarginBottom { get; set; }
12 | public int? FooterMargin { get; set; }
13 | public int? HeaderMargin { get; set; }
14 | public PageSize Size { get; set; } = PageSize.A4;
15 | public Table Footer { get; set; }
16 | public readonly List Elements = new List();
17 | }
18 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PageSize.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class PageSize
4 | {
5 | public double Width { get; set; }
6 | public double Height { get; set; }
7 |
8 | public static readonly PageSize A4 = new PageSize { Width = 210, Height = 297 };
9 | }
10 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Paragraph.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class Paragraph: IPageElement
4 | {
5 | public ParagraphParameters Parameters { get; set; }
6 |
7 | public Paragraph(ParagraphParameters parameters)
8 | {
9 | Parameters = parameters;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/ParagraphBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public class ParagraphBuilder
7 | {
8 | private readonly ParagraphParameters parameters = new ParagraphParameters();
9 |
10 | public ParagraphBuilder FontSize(int fontSize) => Chain(p => p.FontSize = fontSize);
11 | public ParagraphBuilder Alignment(Alignment alignment) => Chain(p => p.Alignment = alignment);
12 | public ParagraphBuilder Bold(bool bold = true) => Chain(p => p.Bold = bold);
13 | public ParagraphBuilder SpaceBetweenLines(double spaceBetweenLines) => Chain(p => p.SpaceBetweenLines = spaceBetweenLines);
14 | public ParagraphBuilder Add(string text) => Chain(p => p.Parts.Add(new TextPart { Text = text }));
15 | public ParagraphBuilder Add(Field field) => Chain(p => p.Parts.Add(new FieldPart { Field = field }));
16 | public ParagraphBuilder Add(Picture picture) => Chain(p => p.Parts.Add(new PicturePart { Picture = picture }));
17 | public ParagraphBuilder Add(StubPicture stubPicture) => Chain(p => p.Parts.Add(new StubPicturePart { StubPicture = stubPicture }));
18 | public ParagraphBuilder BackgroundColor(Color color) => Chain(p => p.BackgroundColor = color);
19 |
20 | public Paragraph Build() => new Paragraph(parameters);
21 |
22 | public static implicit operator Paragraph(ParagraphBuilder builder) => builder.Build();
23 |
24 | private ParagraphBuilder Chain(Action action)
25 | {
26 | action(parameters);
27 | return this;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/ParagraphParameters.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public class ParagraphParameters
7 | {
8 | public int? FontSize { get; set; }
9 | public Alignment? Alignment { get; set; }
10 | public bool Bold { get; set; }
11 | public List Parts { get; set; } = new List();
12 | public double? SpaceBetweenLines { get; set; }
13 | public Color? BackgroundColor { get; set; }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Part.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public abstract class Part
4 | {
5 | }
6 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Picture.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class Picture
4 | {
5 | public PictureParameters Parameters { get; }
6 |
7 | public Picture(PictureParameters parameters)
8 | {
9 | Parameters = parameters;
10 | }
11 |
12 | public bool IsEmpty() => Parameters.Bytes == null || Parameters.Bytes.Length == 0;
13 | }
14 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PictureBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ReportDotNet.Core
4 | {
5 | public class PictureBuilder
6 | {
7 | private readonly PictureParameters parameters = new PictureParameters();
8 |
9 | public PictureBuilder Bytes(byte[] bytes) => Chain(p => p.Bytes = bytes);
10 | public PictureBuilder MaxWidth(int maxWidth) => Chain(p => p.MaxWidth = maxWidth);
11 | public PictureBuilder MaxHeight(int maxHeight) => Chain(p => p.MaxHeight = maxHeight);
12 | public PictureBuilder OffsetX(int? offsetX) => Chain(p => p.OffsetX = offsetX);
13 | public PictureBuilder OffsetY(int? offsetY) => Chain(p => p.OffsetY = offsetY);
14 | public PictureBuilder Description(string description) => Chain(p => p.Description = description);
15 |
16 | public Picture Build() => new Picture(parameters);
17 |
18 | public static implicit operator Picture(PictureBuilder builder) => builder.Build();
19 |
20 | private PictureBuilder Chain(Action action)
21 | {
22 | action(parameters);
23 | return this;
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PictureParameters.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class PictureParameters
4 | {
5 | public byte[] Bytes { get; set; }
6 | public int MaxWidth { get; set; }
7 | public int MaxHeight { get; set; }
8 | public int? OffsetX { get; set; }
9 | public int? OffsetY { get; set; }
10 | public string Description { get; set; }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/PicturePart.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class PicturePart: Part
4 | {
5 | public Picture Picture { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/ReportDotNet.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | 8
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Row.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public class Row
7 | {
8 | public RowParameters Parameters { get; }
9 | public Table Table { private get; set; }
10 |
11 | public Row(RowParameters parameters)
12 | {
13 | Parameters = parameters;
14 | }
15 |
16 | public int[] GetWidths()
17 | {
18 | if (Parameters.GetCells().Count(c => c.Parameters.Width == null) > 1)
19 | throw new InvalidOperationException("Multiple cells with relative width in one row aren't supported");
20 | var relativeCellWidth = Table.Parameters.Width - Parameters.GetCells().Sum(c => c.Parameters.Width ?? 0);
21 | return Parameters.GetCells().Select(x => x.Parameters.Width ?? relativeCellWidth).ToArray();
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/RowBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace ReportDotNet.Core
6 | {
7 | public class RowBuilder
8 | {
9 | private readonly RowParameters parameters = new RowParameters();
10 |
11 | public RowBuilder Height(int height) => Chain(p => p.Height = height);
12 | public RowBuilder HeightType(RowHeightType heightType) => Chain(p => p.HeightType = heightType);
13 |
14 | public RowBuilder Add(params Cell[] cells) =>
15 | Chain(p => p.AddCells(cells.Where(x => x != null)));
16 |
17 | public RowBuilder Add(IEnumerable cells) =>
18 | Chain(p => p.AddCells(cells.Where(x => x != null)));
19 |
20 | public Row Build() => new Row(parameters);
21 |
22 | public static implicit operator Row(RowBuilder builder) => builder.Build();
23 |
24 | private RowBuilder Chain(Action action)
25 | {
26 | action(parameters);
27 | return this;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/RowHeightType.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public enum RowHeightType
4 | {
5 | Exact,
6 | AtLeast
7 | }
8 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/RowParameters.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using static ReportDotNet.Core.Factories;
4 |
5 | namespace ReportDotNet.Core
6 | {
7 | public class RowParameters
8 | {
9 | public int? Height { get; set; }
10 | public RowHeightType HeightType { get; set; }
11 | private readonly List cells = new List();
12 |
13 | public void AddCells(IEnumerable cell) => cells.AddRange(cell);
14 |
15 | public Cell[] GetCells()
16 | {
17 | return cells.Any() ? cells.ToArray() : new[] { Cell().Build() };
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/StubPicture.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class StubPicture
4 | {
5 | public StubPictureParameters Parameters { get; }
6 |
7 | public StubPicture(StubPictureParameters parameters)
8 | {
9 | Parameters = parameters;
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/StubPictureBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public class StubPictureBuilder
7 | {
8 | private readonly StubPictureParameters parameters = new StubPictureParameters();
9 |
10 | public StubPictureBuilder Color(Color color) => Chain(p => p.Color = color);
11 | public StubPictureBuilder MaxWidth(int maxWidth) => Chain(p => p.MaxWidth = maxWidth);
12 | public StubPictureBuilder MaxHeight(int maxHeight) => Chain(p => p.MaxHeight = maxHeight);
13 | public StubPictureBuilder OffsetX(int? offsetX) => Chain(p => p.OffsetX = offsetX);
14 | public StubPictureBuilder OffsetY(int? offsetY) => Chain(p => p.OffsetY = offsetY);
15 | public StubPictureBuilder Description(string description) => Chain(p => p.Description = description);
16 |
17 | public StubPicture Build() => new StubPicture(parameters);
18 |
19 | public static implicit operator StubPicture(StubPictureBuilder builder) =>
20 | builder.Build();
21 |
22 | private StubPictureBuilder Chain(Action action)
23 | {
24 | action(parameters);
25 | return this;
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/StubPictureParameters.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using System.IO;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public class StubPictureParameters
7 | {
8 | public byte[] Bytes
9 | {
10 | get
11 | {
12 | var bitmap = new Bitmap(MaxWidth, MaxHeight);
13 | for (var i = 0; i < bitmap.Width; i++)
14 | for (var j = 0; j < bitmap.Height; j++)
15 | bitmap.SetPixel(i, j, Color.Black);
16 | return ImageToByte(bitmap);
17 | }
18 | }
19 |
20 | private static byte[] ImageToByte(Image img)
21 | {
22 | using var stream = new MemoryStream();
23 | img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
24 | return stream.ToArray();
25 | }
26 |
27 | public Color Color { get; set; } = Color.Black;
28 | public int MaxWidth { get; set; }
29 | public int MaxHeight { get; set; }
30 | public int? OffsetX { get; set; }
31 | public int? OffsetY { get; set; }
32 | public string Description { get; set; }
33 | }
34 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/StubPicturePart.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class StubPicturePart: Part
4 | {
5 | public StubPicture StubPicture { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/Table.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class Table: IPageElement
4 | {
5 | public TableParameters Parameters { get; }
6 |
7 | public Table(TableParameters parameters)
8 | {
9 | Parameters = parameters;
10 | foreach (var row in Parameters.Rows)
11 | row.Table = this;
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/TableBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ReportDotNet.Core
5 | {
6 | public class TableBuilder
7 | {
8 | private readonly TableParameters parameters = new TableParameters();
9 |
10 | public TableBuilder Borders(Borders borders) => Chain(p => p.Borders = borders);
11 | public TableBuilder FontSize(int fontSize) => Chain(p => p.FontSize = fontSize);
12 |
13 | public TableBuilder CellMargin(int? left = null,
14 | int? right = null,
15 | int? top = null,
16 | int? bottom = null) => Chain(p =>
17 | {
18 | p.CellMarginLeft = left;
19 | p.CellMarginRight = right;
20 | p.CellMarginTop = top;
21 | p.CellMarginBottom = bottom;
22 | });
23 |
24 | public TableBuilder Width(int width) => Chain(p => p.Width = width);
25 | public TableBuilder Add(params Row[] rows) => Chain(p => p.Rows.AddRange(rows));
26 | public TableBuilder Add(IEnumerable rows) => Chain(p => p.Rows.AddRange(rows));
27 |
28 | public Table Build() => new Table(parameters);
29 |
30 | public static implicit operator Table(TableBuilder builder) => builder.Build();
31 |
32 | private TableBuilder Chain(Action action)
33 | {
34 | action(parameters);
35 | return this;
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/TableParameters.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ReportDotNet.Core
4 | {
5 | public class TableParameters
6 | {
7 | public int Width { get; set; }
8 | public Borders? Borders { get; set; }
9 | public int? CellMarginLeft { get; set; }
10 | public int? CellMarginRight { get; set; }
11 | public int? CellMarginTop { get; set; }
12 | public int? CellMarginBottom { get; set; }
13 | public int? FontSize { get; set; }
14 | public List Rows { get; set; } = new List();
15 | }
16 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/TextDirection.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public enum TextDirection
4 | {
5 | LeftRight_TopBottom,
6 | RightLeft_TopBottom,
7 | LeftRight_BottomTop
8 | }
9 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/TextPart.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public class TextPart: Part
4 | {
5 | public string Text { get; set; }
6 | }
7 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Core/VerticalAlignment.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Core
2 | {
3 | public enum VerticalAlignment
4 | {
5 | Top,
6 | Center,
7 | Bottom,
8 | }
9 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Converters/CellConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DocumentFormat.OpenXml.Packaging;
3 | using DocumentFormat.OpenXml.Wordprocessing;
4 | using ReportDotNet.Core;
5 | using Color = System.Drawing.Color;
6 | using Table = ReportDotNet.Core.Table;
7 | using TextDirection = ReportDotNet.Core.TextDirection;
8 |
9 | namespace ReportDotNet.Docx.Converters
10 | {
11 | internal static class CellConverter
12 | {
13 | public static TableCell Convert(Cell cell,
14 | WordprocessingDocument document,
15 | Table table,
16 | int span)
17 | {
18 | var tableCell = new TableCell();
19 | var cellProperties = new TableCellProperties();
20 | var parameters = cell.Parameters;
21 |
22 | if (span > 1)
23 | cellProperties.GridSpan = new GridSpan { Val = span };
24 |
25 | cellProperties.TableCellVerticalAlignment = new TableCellVerticalAlignment
26 | {
27 | Val = GetVerticalAlignment(parameters.VerticalAlignment ?? VerticalAlignment.Bottom)
28 | };
29 |
30 | cellProperties.TableCellMargin = GetMargin(parameters.MarginLeft ?? table.Parameters.CellMarginLeft,
31 | parameters.MarginRight ?? table.Parameters.CellMarginRight,
32 | parameters.MarginTop ?? table.Parameters.CellMarginTop,
33 | parameters.MarginBottom ?? table.Parameters.CellMarginBottom);
34 |
35 | if (parameters.MergeDown)
36 | cellProperties.VerticalMerge = new VerticalMerge { Val = MergedCellValues.Restart };
37 | else if (parameters.MergeUp)
38 | cellProperties.VerticalMerge = new VerticalMerge();
39 |
40 | if (parameters.MergeRight)
41 | cellProperties.HorizontalMerge = new HorizontalMerge { Val = MergedCellValues.Restart };
42 | else if (parameters.MergeLeft)
43 | cellProperties.HorizontalMerge = new HorizontalMerge();
44 |
45 | var borders = parameters.Borders ?? table.Parameters.Borders ?? Borders.None;
46 | if (borders != Borders.None)
47 | cellProperties.TableCellBorders = new TableCellBorders
48 | {
49 | BottomBorder = borders.HasFlag(Borders.Bottom)
50 | ? GetBorder(parameters.BottomBorderStyle, parameters.BorderSize)
51 | : null,
52 | LeftBorder = borders.HasFlag(Borders.Left)
53 | ? GetBorder(parameters.LeftBorderStyle, parameters.BorderSize)
54 | : null,
55 | TopBorder = borders.HasFlag(Borders.Top)
56 | ? GetBorder(parameters.TopBorderStyle, parameters.BorderSize)
57 | : null,
58 | RightBorder = borders.HasFlag(Borders.Right)
59 | ? GetBorder(parameters.RightBorderStyle, parameters.BorderSize)
60 | : null
61 | };
62 |
63 | if (parameters.TextDirection.HasValue)
64 | cellProperties.TextDirection = new DocumentFormat.OpenXml.Wordprocessing.TextDirection { Val = ConvertTextDirection(parameters.TextDirection.Value) };
65 |
66 | if (parameters.BackgroundColor.HasValue)
67 | cellProperties.Shading = new Shading
68 | {
69 | Color = parameters.BackgroundColor.Value.ToHex(),
70 | Fill = "auto",
71 | Val = ShadingPatternValues.Solid
72 | };
73 |
74 | tableCell.AppendChild(ParagraphConverter.Convert(parameters.Paragraph, document, table.Parameters.FontSize));
75 |
76 | tableCell.TableCellProperties = cellProperties;
77 | return tableCell;
78 | }
79 |
80 | private static TBorder GetBorder(BorderStyle borderStyle,
81 | double? borderSize)
82 | where TBorder: BorderType, new()
83 | {
84 | return new TBorder
85 | {
86 | Val = BorderStyleToBorderValues(borderStyle),
87 | Color = Color.Black.ToHex(),
88 | Size = (uint) ((borderSize ?? 0.5) * 4),
89 | Space = 0
90 | };
91 | }
92 |
93 | private static TextDirectionValues ConvertTextDirection(TextDirection textDirection)
94 | {
95 | switch (textDirection)
96 | {
97 | case TextDirection.LeftRight_TopBottom:
98 | return TextDirectionValues.LefToRightTopToBottom;
99 | case TextDirection.RightLeft_TopBottom:
100 | return TextDirectionValues.TopToBottomRightToLeft;
101 | case TextDirection.LeftRight_BottomTop:
102 | return TextDirectionValues.BottomToTopLeftToRight;
103 | default:
104 | throw new ArgumentOutOfRangeException(nameof(textDirection), textDirection, null);
105 | }
106 | }
107 |
108 | private static BorderValues BorderStyleToBorderValues(BorderStyle borderStyle)
109 | {
110 | switch (borderStyle)
111 | {
112 | case BorderStyle.Single:
113 | return BorderValues.Single;
114 | case BorderStyle.Dashed:
115 | return BorderValues.Dashed;
116 | case BorderStyle.DotDash:
117 | return BorderValues.DotDash;
118 | case BorderStyle.DotDotDash:
119 | return BorderValues.DotDotDash;
120 | default:
121 | throw new ArgumentOutOfRangeException(nameof(borderStyle), borderStyle, null);
122 | }
123 | }
124 |
125 | private static TableCellMargin GetMargin(int? left,
126 | int? right,
127 | int? top,
128 | int? bottom)
129 | {
130 | if (left == null && right == null && top == null && bottom == null)
131 | return null;
132 |
133 | return new TableCellMargin
134 | {
135 | LeftMargin = left.HasValue
136 | ? new LeftMargin
137 | {
138 | Width = (left * OpenXmlUnits.Dxa).ToString(),
139 | Type = TableWidthUnitValues.Dxa
140 | }
141 | : null,
142 | RightMargin = right.HasValue
143 | ? new RightMargin
144 | {
145 | Width = (right * OpenXmlUnits.Dxa).ToString(),
146 | Type = TableWidthUnitValues.Dxa
147 | }
148 | : null,
149 | TopMargin = top.HasValue
150 | ? new TopMargin
151 | {
152 | Width = (top * OpenXmlUnits.Dxa).ToString(),
153 | Type = TableWidthUnitValues.Dxa
154 | }
155 | : null,
156 | BottomMargin = bottom.HasValue
157 | ? new BottomMargin
158 | {
159 | Width = (bottom * OpenXmlUnits.Dxa).ToString(),
160 | Type = TableWidthUnitValues.Dxa
161 | }
162 | : null
163 | };
164 | }
165 |
166 | private static TableVerticalAlignmentValues GetVerticalAlignment(VerticalAlignment verticalAlignment)
167 | {
168 | switch (verticalAlignment)
169 | {
170 | case VerticalAlignment.Top:
171 | return TableVerticalAlignmentValues.Top;
172 | case VerticalAlignment.Center:
173 | return TableVerticalAlignmentValues.Center;
174 | case VerticalAlignment.Bottom:
175 | return TableVerticalAlignmentValues.Bottom;
176 | default:
177 | throw new ArgumentOutOfRangeException(nameof(verticalAlignment), verticalAlignment, null);
178 | }
179 | }
180 | }
181 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Converters/PageConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using DocumentFormat.OpenXml;
4 | using DocumentFormat.OpenXml.Packaging;
5 | using DocumentFormat.OpenXml.Wordprocessing;
6 | using ReportDotNet.Core;
7 | using PageSize = DocumentFormat.OpenXml.Wordprocessing.PageSize;
8 | using Paragraph = DocumentFormat.OpenXml.Wordprocessing.Paragraph;
9 | using Table = ReportDotNet.Core.Table;
10 |
11 | namespace ReportDotNet.Docx.Converters
12 | {
13 | internal static class PageConverter
14 | {
15 | public static OpenXmlElement[] Convert(Page page,
16 | IDocument document,
17 | WordprocessingDocument wpDocument,
18 | bool isLastPage)
19 | {
20 | var parts = page.Parameters.Elements.Select(p => PartToOpenXmlElement(p, wpDocument));
21 |
22 | if (isLastPage)
23 | {
24 | FillSectionProperties(wpDocument,
25 | wpDocument.MainDocumentPart.Document.Body.GetSectionProperties(),
26 | page,
27 | document.GetDefaultPageLayout(),
28 | document.GetDefaultFooter());
29 | return parts.ToArray();
30 | }
31 |
32 | return parts.Concat(new[]
33 | {
34 | new Paragraph
35 | {
36 | ParagraphProperties = new ParagraphProperties
37 | {
38 | SectionProperties = FillSectionProperties(wpDocument,
39 | new SectionProperties(),
40 | page,
41 | document.GetDefaultPageLayout(),
42 | document.GetDefaultFooter())
43 | }
44 | }
45 | })
46 | .ToArray();
47 | }
48 |
49 | private static OpenXmlElement PartToOpenXmlElement(IPageElement part,
50 | WordprocessingDocument document)
51 | {
52 | var paragraph = part as Core.Paragraph;
53 | if (paragraph != null)
54 | return ParagraphConverter.Convert(paragraph, document);
55 |
56 | var table = part as Table;
57 | if (table != null)
58 | return TableConverter.Convert(table, document);
59 |
60 | throw new InvalidOperationException($"can't convert part of page with type [{part.GetType()}] to OpenXmlElement");
61 | }
62 |
63 | private static SectionProperties FillSectionProperties(WordprocessingDocument wpDocument,
64 | SectionProperties sectionProperties,
65 | Page page,
66 | PageLayout defaultPageLayout,
67 | Table defaultFooter)
68 | {
69 | var pageOrientation = page.Parameters.Orientation ?? defaultPageLayout.Orientation ?? PageOrientation.Portrait;
70 |
71 | var width = (uint) OpenXmlUnits.FromMmTo20thOfPoint(page.Parameters.Size.Width);
72 | var height = (uint) OpenXmlUnits.FromMmTo20thOfPoint(page.Parameters.Size.Height);
73 | sectionProperties.AppendChild(new PageSize
74 | {
75 | Orient = ConvertOrientation(pageOrientation),
76 | Width = pageOrientation == PageOrientation.Portrait ? width : height,
77 | Height = pageOrientation == PageOrientation.Portrait ? height : width
78 | });
79 | sectionProperties.AppendChild(new PageMargin
80 | {
81 | Left = (uint?) GetMargin(page.Parameters.MarginLeft, defaultPageLayout.MarginLeft),
82 | Top = GetMargin(page.Parameters.MarginTop, defaultPageLayout.MarginTop),
83 | Right = (uint?) GetMargin(page.Parameters.MarginRight, defaultPageLayout.MarginRight),
84 | Bottom = GetMargin(page.Parameters.MarginBottom, defaultPageLayout.MarginBottom),
85 | Header = (uint?) GetMargin(page.Parameters.HeaderMargin, defaultPageLayout.HeaderMargin),
86 | Footer = (uint?) GetMargin(page.Parameters.FooterMargin, defaultPageLayout.FooterMargin)
87 | });
88 | if (page.Parameters.Footer != null || defaultFooter != null)
89 | {
90 | var footerPart = wpDocument.MainDocumentPart.AddNewPart();
91 | var footerPartId = wpDocument.MainDocumentPart.GetIdOfPart(footerPart);
92 | sectionProperties.AppendChild(new FooterReference { Id = footerPartId, Type = HeaderFooterValues.Default });
93 | var footer = new Footer(TableConverter.Convert(page.Parameters.Footer ?? defaultFooter, wpDocument));
94 | footer.Save(footerPart);
95 | }
96 | return sectionProperties;
97 | }
98 |
99 | private static int? GetMargin(int? fromPage,
100 | int? fromDocument)
101 | {
102 | if (fromPage.HasValue || fromDocument.HasValue)
103 | return (fromPage ?? fromDocument) * OpenXmlUnits.Dxa;
104 | return null;
105 | }
106 |
107 | private static PageOrientationValues ConvertOrientation(PageOrientation orientation)
108 | {
109 | switch (orientation)
110 | {
111 | case PageOrientation.Portrait:
112 | return PageOrientationValues.Portrait;
113 | case PageOrientation.Landscape:
114 | return PageOrientationValues.Landscape;
115 | default:
116 | throw new ArgumentOutOfRangeException(nameof(orientation), orientation, null);
117 | }
118 | }
119 | }
120 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Converters/ParagraphConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using DocumentFormat.OpenXml;
4 | using DocumentFormat.OpenXml.Packaging;
5 | using DocumentFormat.OpenXml.Wordprocessing;
6 | using ReportDotNet.Core;
7 | using FontFamily = System.Drawing.FontFamily;
8 | using Paragraph = ReportDotNet.Core.Paragraph;
9 |
10 | namespace ReportDotNet.Docx.Converters
11 | {
12 | internal static class ParagraphConverter
13 | {
14 | public static OpenXmlElement Convert(Paragraph paragraph,
15 | WordprocessingDocument document,
16 | int? defaultFontSize = null)
17 | {
18 | var docxParagraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph();
19 | var parameters = paragraph.Parameters;
20 |
21 | var paragraphProperties = new ParagraphProperties();
22 |
23 | if (parameters.Alignment.HasValue)
24 | paragraphProperties.Justification = new Justification { Val = GetJustificationValues(parameters.Alignment.Value) };
25 |
26 | if (parameters.SpaceBetweenLines.HasValue)
27 | paragraphProperties.SpacingBetweenLines = new SpacingBetweenLines
28 | {
29 | LineRule = LineSpacingRuleValues.Auto,
30 | Line = (240 * parameters.SpaceBetweenLines.Value).ToString()
31 | };
32 |
33 | var runProperties = new RunProperties();
34 | if (parameters.Bold)
35 | runProperties.Bold = new Bold();
36 |
37 | var fontSize = parameters.FontSize ?? defaultFontSize;
38 | if (fontSize.HasValue)
39 | {
40 | var rPr = new ParagraphMarkRunProperties(new FontSize { Val = (fontSize.Value * 2).ToString() },
41 | new FontSizeComplexScript { Val = (fontSize.Value * 2).ToString() });
42 | paragraphProperties.AppendChild(rPr);
43 | runProperties.FontSize = new FontSize { Val = (fontSize.Value * 2).ToString() };
44 | runProperties.FontSizeComplexScript = new FontSizeComplexScript { Val = (fontSize.Value * 2).ToString() };
45 | }
46 |
47 | var defaultFont = FontFamily.GenericSansSerif.Name;
48 | runProperties.RunFonts = new RunFonts
49 | {
50 | Ascii = defaultFont,
51 | ComplexScript = defaultFont,
52 | HighAnsi = defaultFont
53 | };
54 |
55 | if (parameters.BackgroundColor.HasValue)
56 | runProperties.Shading = new Shading
57 | {
58 | Val = ShadingPatternValues.Clear,
59 | Color = "auto",
60 | Fill = parameters.BackgroundColor.Value.ToHex()
61 | };
62 |
63 | foreach (var run in parameters.Parts.Select(x => GetRun(document, x, runProperties)))
64 | docxParagraph.AppendChild(run);
65 | docxParagraph.ParagraphProperties = paragraphProperties;
66 | return docxParagraph;
67 | }
68 |
69 | private static Run GetRun(WordprocessingDocument document,
70 | Part part,
71 | RunProperties properties)
72 | {
73 | var run = new Run { RunProperties = properties.CloneNode(true) };
74 |
75 | var textPart = part as TextPart;
76 | if (textPart != null)
77 | {
78 | if (textPart.Text == null)
79 | return run;
80 |
81 | var lines = textPart.Text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
82 | for (var i = 0; i < lines.Length; i++)
83 | {
84 | if (i > 0)
85 | run.AppendChild(new Break());
86 | if (!string.IsNullOrEmpty(lines[i]))
87 | run.AppendChild(new Text(lines[i]) { Space = SpaceProcessingModeValues.Preserve });
88 | }
89 |
90 | return run;
91 | }
92 |
93 | var fieldPart = part as FieldPart;
94 | if (fieldPart != null)
95 | {
96 | run.AppendChild(new SimpleField { Instruction = GetInsructionForField(fieldPart.Field) });
97 | return run;
98 | }
99 |
100 | var picturePart = part as PicturePart;
101 | if (picturePart != null)
102 | {
103 | if (picturePart.Picture?.IsEmpty() == false)
104 | run.AppendChild(PictureConverter.Convert(picturePart.Picture, document));
105 | return run;
106 | }
107 |
108 | var stubPicturePart = part as StubPicturePart;
109 | if (stubPicturePart != null)
110 | {
111 | if (stubPicturePart.StubPicture != null)
112 | run.AppendChild(PictureConverter.Convert(stubPicturePart.StubPicture, document));
113 | return run;
114 | }
115 |
116 | throw new InvalidOperationException($"Can't process part of paragraph with type {part.GetType().FullName}");
117 | }
118 |
119 | private static JustificationValues GetJustificationValues(Alignment alignment)
120 | {
121 | switch (alignment)
122 | {
123 | case Alignment.Left:
124 | return JustificationValues.Left;
125 | case Alignment.Center:
126 | return JustificationValues.Center;
127 | case Alignment.Right:
128 | return JustificationValues.Right;
129 | case Alignment.Both:
130 | return JustificationValues.Both;
131 | default:
132 | throw new ArgumentOutOfRangeException(nameof(alignment), alignment, null);
133 | }
134 | }
135 |
136 | private static string GetInsructionForField(Field field)
137 | {
138 | switch (field)
139 | {
140 | case Field.PageNumber:
141 | return " PAGE \\* MERGEFORMAT ";
142 | case Field.PageCount:
143 | return " NUMPAGES \\* MERGEFORMAT ";
144 | default:
145 | throw new ArgumentOutOfRangeException(nameof(field), field, null);
146 | }
147 | }
148 | }
149 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Converters/PictureConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using System.IO;
3 | using DocumentFormat.OpenXml;
4 | using DocumentFormat.OpenXml.Drawing;
5 | using DocumentFormat.OpenXml.Drawing.Wordprocessing;
6 | using DocumentFormat.OpenXml.Packaging;
7 | using DocumentFormat.OpenXml.Wordprocessing;
8 | using ReportDotNet.Core;
9 | using Anchor = DocumentFormat.OpenXml.Drawing.Wordprocessing.Anchor;
10 | using BlipFill = DocumentFormat.OpenXml.Drawing.Pictures.BlipFill;
11 | using Color = System.Drawing.Color;
12 | using NonVisualDrawingProperties = DocumentFormat.OpenXml.Drawing.Pictures.NonVisualDrawingProperties;
13 | using NonVisualPictureDrawingProperties = DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureDrawingProperties;
14 | using NonVisualPictureProperties = DocumentFormat.OpenXml.Drawing.Pictures.NonVisualPictureProperties;
15 | using Outline = DocumentFormat.OpenXml.Drawing.Outline;
16 | using Picture = ReportDotNet.Core.Picture;
17 | using ShapeProperties = DocumentFormat.OpenXml.Drawing.Pictures.ShapeProperties;
18 | using VerticalAlignment = DocumentFormat.OpenXml.Drawing.Wordprocessing.VerticalAlignment;
19 |
20 | namespace ReportDotNet.Docx.Converters
21 | {
22 | internal static class PictureConverter
23 | {
24 | internal static OpenXmlElement Convert(StubPicture picture,
25 | WordprocessingDocument document)
26 | {
27 | return Convert(picture.Parameters.Bytes,
28 | picture.Parameters.MaxWidth,
29 | picture.Parameters.MaxHeight,
30 | picture.Parameters.OffsetX,
31 | picture.Parameters.OffsetY,
32 | picture.Parameters.Description,
33 | picture.Parameters.Color,
34 | document);
35 | }
36 |
37 | internal static OpenXmlElement Convert(Picture picture,
38 | WordprocessingDocument document)
39 | {
40 | return Convert(picture.Parameters.Bytes,
41 | picture.Parameters.MaxWidth,
42 | picture.Parameters.MaxHeight,
43 | picture.Parameters.OffsetX,
44 | picture.Parameters.OffsetY,
45 | picture.Parameters.Description,
46 | null,
47 | document);
48 | }
49 |
50 | private static OpenXmlElement Convert(byte[] bytes,
51 | int maxWidth,
52 | int maxHeight,
53 | int? offsetX,
54 | int? offsetY,
55 | string description,
56 | Color? color,
57 | WordprocessingDocument document)
58 | {
59 | var imagePart = document.MainDocumentPart.AddImagePart(ImagePartType.Png);
60 | imagePart.FeedData(new MemoryStream(bytes));
61 | int width, height;
62 | using (var img = Image.FromStream(new MemoryStream(bytes)))
63 | {
64 | width = img.Width;
65 | height = img.Height;
66 | }
67 |
68 | var offsets = FillRectangleOffsetsCalculator.Calculate(new Size(width, height), new Size(maxWidth, maxHeight));
69 | var offset = new Offset { X = 0, Y = 0 };
70 | if (offsetX.HasValue)
71 | offset.X = offsetX * OpenXmlUnits.EmuPerPixel;
72 | if (offsetY.HasValue)
73 | offset.Y = offsetY * OpenXmlUnits.EmuPerPixel;
74 |
75 | return new Drawing(
76 | new Anchor(
77 | new WrapNone(),
78 | new DocProperties
79 | {
80 | Id = 1,
81 | Name = "name",
82 | Description = description
83 | },
84 | new Graphic
85 | {
86 | GraphicData = new GraphicData(new DocumentFormat.OpenXml.Drawing.Pictures.Picture
87 | {
88 | NonVisualPictureProperties = new NonVisualPictureProperties
89 | {
90 | NonVisualDrawingProperties = new NonVisualDrawingProperties
91 | {
92 | Id = 0,
93 | Name = "name"
94 | },
95 | NonVisualPictureDrawingProperties =
96 | new NonVisualPictureDrawingProperties()
97 | },
98 | BlipFill = new BlipFill(new Stretch
99 | {
100 | FillRectangle = new FillRectangle
101 | {
102 | Top = offsets.Top,
103 | Left = offsets.Left,
104 | Bottom = offsets.Bottom,
105 | Right = offsets.Right
106 | }
107 | })
108 | {
109 | Blip = new Blip(color != null
110 | ? new ColorReplacement
111 | {
112 | RgbColorModelHex =
113 | new RgbColorModelHex
114 | {
115 | Val =
116 | color
117 | .Value
118 | .ToHex()
119 | }
120 | }
121 | : null)
122 | {
123 | Embed = document.MainDocumentPart.GetIdOfPart(imagePart),
124 | }
125 | },
126 | ShapeProperties = new ShapeProperties(new PresetGeometry
127 | {
128 | Preset = ShapeTypeValues.Rectangle,
129 | AdjustValueList = new AdjustValueList()
130 | },
131 | color != null
132 | ? new Outline(new SolidFill
133 | {
134 | RgbColorModelHex =
135 | new RgbColorModelHex
136 | {
137 | Val
138 | = color
139 | .Value
140 | .ToHex()
141 | }
142 | })
143 | : null)
144 | {
145 | Transform2D = new Transform2D
146 | {
147 | Offset = offset,
148 | Extents = new Extents
149 | {
150 | Cx = maxWidth * OpenXmlUnits
151 | .EmuPerPixel,
152 | Cy = maxHeight * OpenXmlUnits
153 | .EmuPerPixel
154 | }
155 | }
156 | }
157 | })
158 | {
159 | Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"
160 | }
161 | })
162 | {
163 | DistanceFromTop = 0,
164 | DistanceFromBottom = 0,
165 | DistanceFromLeft = 0,
166 | DistanceFromRight = 0,
167 | SimplePos = false,
168 | RelativeHeight = 0,
169 | BehindDoc = false,
170 | Locked = false,
171 | LayoutInCell = true,
172 | AllowOverlap = true,
173 | SimplePosition = new SimplePosition { X = 0, Y = 0 },
174 | HorizontalPosition = new HorizontalPosition
175 | {
176 | RelativeFrom = HorizontalRelativePositionValues.Column,
177 | HorizontalAlignment = new HorizontalAlignment("right")
178 | },
179 | VerticalPosition = new VerticalPosition
180 | {
181 | RelativeFrom = VerticalRelativePositionValues.Paragraph,
182 | VerticalAlignment = new VerticalAlignment("top")
183 | },
184 | Extent = new Extent
185 | {
186 | Cx = maxWidth * OpenXmlUnits.EmuPerPixel,
187 | Cy = maxHeight * OpenXmlUnits.EmuPerPixel
188 | },
189 | EffectExtent = new EffectExtent
190 | {
191 | LeftEdge = 0,
192 | TopEdge = 0,
193 | RightEdge = 0,
194 | BottomEdge = 0
195 | }
196 | });
197 | }
198 | }
199 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Converters/RowConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using DocumentFormat.OpenXml;
4 | using DocumentFormat.OpenXml.Packaging;
5 | using DocumentFormat.OpenXml.Wordprocessing;
6 | using ReportDotNet.Core;
7 | using Table = ReportDotNet.Core.Table;
8 |
9 | namespace ReportDotNet.Docx.Converters
10 | {
11 | internal static class RowConverter
12 | {
13 | public static TableRow Convert(Row row,
14 | WordprocessingDocument document,
15 | Table table,
16 | int[] tableWidths)
17 | {
18 | var docxRow = new TableRow();
19 | var parameters = row.Parameters;
20 | if (parameters.Height.HasValue)
21 | {
22 | docxRow.TableRowProperties = new TableRowProperties();
23 | docxRow.TableRowProperties.AppendChild(new TableRowHeight
24 | {
25 | Val = (uint) parameters.Height.Value * OpenXmlUnits.Dxa,
26 | HeightType = ConvertHeightType(parameters.HeightType)
27 | });
28 | }
29 |
30 | var spans = Helpers.GetSpans(tableWidths, row.GetWidths());
31 | var cells = parameters.GetCells().ToArray();
32 | for (var i = 0; i < cells.Length; i++)
33 | docxRow.AppendChild(CellConverter.Convert(cells[i], document, table, spans[i]));
34 |
35 | return docxRow;
36 | }
37 |
38 | private static EnumValue ConvertHeightType(RowHeightType heightType)
39 | {
40 | switch (heightType)
41 | {
42 | case RowHeightType.Exact:
43 | return HeightRuleValues.Exact;
44 | case RowHeightType.AtLeast:
45 | return HeightRuleValues.AtLeast;
46 | default:
47 | throw new ArgumentOutOfRangeException(nameof(heightType), heightType, null);
48 | }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Converters/TableConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using DocumentFormat.OpenXml;
3 | using DocumentFormat.OpenXml.Packaging;
4 | using DocumentFormat.OpenXml.Wordprocessing;
5 | using ReportDotNet.Core;
6 | using Table = ReportDotNet.Core.Table;
7 |
8 | namespace ReportDotNet.Docx.Converters
9 | {
10 | internal static class TableConverter
11 | {
12 | public static OpenXmlElement Convert(Table table,
13 | WordprocessingDocument document)
14 | {
15 | var parameters = table.Parameters;
16 | var widths = Helpers.GetWidths(parameters.Width, parameters.Rows.Select(x => x.GetWidths()));
17 | var docxTable = CreateTable(parameters.Width, widths);
18 | foreach (var row in parameters.Rows)
19 | docxTable.AppendChild(RowConverter.Convert(row, document, table, widths));
20 | return docxTable;
21 | }
22 |
23 | private static DocumentFormat.OpenXml.Wordprocessing.Table CreateTable(float width,
24 | int[] columnWidths)
25 | {
26 | var table = new DocumentFormat.OpenXml.Wordprocessing.Table();
27 | var tableProperties = new TableProperties
28 | {
29 | TableWidth = new TableWidth
30 | {
31 | Width = (width * OpenXmlUnits.Dxa).ToString(),
32 | Type = TableWidthUnitValues.Dxa
33 | },
34 | TableLayout = new TableLayout
35 | {
36 | Type = TableLayoutValues.Fixed
37 | }
38 | };
39 | table.AppendChild(tableProperties);
40 | table.AppendChild(new TableGrid(columnWidths.Select(x => new GridColumn { Width = (x * OpenXmlUnits.Dxa).ToString() })));
41 | return table;
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/CreateExtensions.cs:
--------------------------------------------------------------------------------
1 | using ReportDotNet.Core;
2 |
3 | namespace ReportDotNet.Docx
4 | {
5 | public static class CreateExtensions
6 | {
7 | public static IDocument Docx(this Create _) => new DocxDocument();
8 | }
9 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/DocxDocument.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 | using DocumentFormat.OpenXml;
5 | using DocumentFormat.OpenXml.Packaging;
6 | using DocumentFormat.OpenXml.Wordprocessing;
7 | using ReportDotNet.Core;
8 | using ReportDotNet.Docx.Converters;
9 | using Table = ReportDotNet.Core.Table;
10 |
11 | namespace ReportDotNet.Docx
12 | {
13 | internal class DocxDocument: IDocument
14 | {
15 | private readonly WordprocessingDocument document;
16 | private readonly MemoryStream memoryStream;
17 | private readonly List pages = new List();
18 | private PageLayout defaultPageLayout;
19 | private Table defaultFooter;
20 |
21 | public DocxDocument()
22 | {
23 | memoryStream = new MemoryStream();
24 | document = WordprocessingDocument.Create(memoryStream, WordprocessingDocumentType.Document);
25 | document.AddMainDocumentPart();
26 | document.MainDocumentPart.Document = new Document { Body = new Body() };
27 | var stylesPart = document.MainDocumentPart.AddNewPart();
28 | DefaultStyles.Styles.Value.Save(stylesPart);
29 | //todo looks ugly
30 | SetDefaultPageLayout(new PageLayout
31 | {
32 | Orientation = PageOrientation.Portrait
33 | });
34 | }
35 |
36 | public byte[] Save()
37 | {
38 | foreach (var page in pages)
39 | {
40 | var isLastPage = page == pages.Last();
41 | document.MainDocumentPart.Document.Body.Append(PageConverter.Convert(page, this, document, isLastPage));
42 | }
43 |
44 | using (memoryStream)
45 | using (document)
46 | document.Close();
47 | return memoryStream.ToArray();
48 | }
49 |
50 | public IDocument AddPage(Page page)
51 | {
52 | pages.Add(page);
53 | return this;
54 | }
55 |
56 | public void SetDefaultPageLayout(PageLayout pageLayout)
57 | {
58 | defaultPageLayout = pageLayout;
59 | }
60 |
61 | PageLayout IDocument.GetDefaultPageLayout()
62 | {
63 | return defaultPageLayout;
64 | }
65 |
66 | public void SetDefaultFooter(Table table)
67 | {
68 | defaultFooter = table;
69 | }
70 |
71 | public Table GetDefaultFooter()
72 | {
73 | return defaultFooter;
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using DocumentFormat.OpenXml;
3 | using DocumentFormat.OpenXml.Wordprocessing;
4 | using Color = System.Drawing.Color;
5 |
6 | namespace ReportDotNet.Docx
7 | {
8 | internal static class Extensions
9 | {
10 | public static string ToHex(this Color source)
11 | {
12 | return ByteToHex(source.R) + ByteToHex(source.G) + ByteToHex(source.B);
13 | }
14 |
15 | private static string ByteToHex(byte @byte)
16 | {
17 | var hex = @byte.ToString("X");
18 | return hex.Length < 2 ? "0" + hex : hex;
19 | }
20 |
21 | public static T CloneNode(this T element,
22 | bool deep)
23 | where T: OpenXmlElement
24 | {
25 | return (T) element.CloneNode(deep);
26 | }
27 |
28 | public static SectionProperties GetSectionProperties(this Body body)
29 | {
30 | var sectionProperties = body.Elements().ToArray();
31 | return sectionProperties.Any()
32 | ? sectionProperties.Single()
33 | : body.AppendChild(new SectionProperties());
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/FillRectangleOffsetsCalculator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 |
4 | namespace ReportDotNet.Docx
5 | {
6 | internal static class FillRectangleOffsetsCalculator
7 | {
8 | private const int OpenxmlPercentMultiplier = 1000;
9 |
10 | public static Offsets Calculate(Size imageSize,
11 | Size placeholderSize)
12 | {
13 | var widthRatio = 1.0 * imageSize.Width / placeholderSize.Width;
14 | var heightRatio = 1.0 * imageSize.Height / placeholderSize.Height;
15 |
16 | return widthRatio > heightRatio
17 | ? CenterVertical(imageSize, placeholderSize)
18 | : CenterHorizontal(imageSize, placeholderSize);
19 | }
20 |
21 | private static Offsets CenterVertical(Size imageSize,
22 | Size placeholderSize)
23 | {
24 | var imageNewWidth = placeholderSize.Width;
25 | var imageNewHeight = imageSize.Height * imageNewWidth / imageSize.Width;
26 |
27 | var verticalOffset = (placeholderSize.Height - imageNewHeight) / 2.0;
28 | var verticalOffsetInWordPercents = PercentOf(verticalOffset, placeholderSize.Height) * OpenxmlPercentMultiplier;
29 |
30 | return Offsets.VerticalCenter(Convert.ToInt32(verticalOffsetInWordPercents));
31 | }
32 |
33 | private static Offsets CenterHorizontal(Size imageSize,
34 | Size placeholderSize)
35 | {
36 | var newImageHeight = placeholderSize.Height;
37 | var newImageWidth = imageSize.Width * newImageHeight / imageSize.Height;
38 |
39 | var horizontalOffsetInPixels = (placeholderSize.Width - newImageWidth) / 2.0;
40 | var horizontalOffsetInWordPercents = PercentOf(horizontalOffsetInPixels, placeholderSize.Width) * OpenxmlPercentMultiplier;
41 |
42 | return Offsets.HorizontalCenter(Convert.ToInt32(horizontalOffsetInWordPercents));
43 | }
44 |
45 | private static double PercentOf(double value,
46 | double of)
47 | {
48 | return value / of * 100;
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/Offsets.cs:
--------------------------------------------------------------------------------
1 | namespace ReportDotNet.Docx
2 | {
3 | internal class Offsets
4 | {
5 | private Offsets(int? top,
6 | int? right,
7 | int? bottom,
8 | int? left)
9 | {
10 | Top = top;
11 | Bottom = bottom;
12 | Left = left;
13 | Right = right;
14 | }
15 |
16 | public static Offsets VerticalCenter(int verticalOffsetEachSide)
17 | {
18 | return new Offsets(NullIfZero(verticalOffsetEachSide),
19 | null,
20 | NullIfZero(verticalOffsetEachSide),
21 | null);
22 | }
23 |
24 | public static Offsets HorizontalCenter(int horizontalOffsetEachSide)
25 | {
26 | return new Offsets(null,
27 | NullIfZero(horizontalOffsetEachSide),
28 | null,
29 | NullIfZero(horizontalOffsetEachSide));
30 | }
31 |
32 | private static int? NullIfZero(int offset)
33 | {
34 | return offset == 0 ? (int?) null : offset;
35 | }
36 |
37 | public int? Top { get; private set; }
38 | public int? Right { get; private set; }
39 | public int? Bottom { get; private set; }
40 | public int? Left { get; private set; }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/OpenXmlUnits.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ReportDotNet.Docx
4 | {
5 | internal static class OpenXmlUnits
6 | {
7 | public const int Dxa = 15;
8 | public const int EmuPerPixel = 9525;
9 |
10 | public static int FromMmTo20thOfPoint(double mm)
11 | {
12 | return (int) Math.Round(mm / 10 / 2.54 * 72 * 20, MidpointRounding.AwayFromZero);
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/ReportDotNet.Docx.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | 8
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/ReportDotNet.Docx.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ReportDotNet.Docx
5 | $version$
6 | ReportDotNet.Docx
7 | mif.open@gmail.com
8 | mif.open@gmail.com
9 | https://github.com/mifopen/ReportDotNet
10 | false
11 | Simple .NET library for complex reports in docx format
12 | Hello! =)
13 | Copyright 2017
14 | reports docx reporting-engine reporting reporting-services docx-generator wysiwyg
15 |
16 |
--------------------------------------------------------------------------------
/src/ReportDotNet.Docx/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/ReportDotNet.Web/App/DirectoryWatcher.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Microsoft.AspNetCore.SignalR;
3 | using ReportDotNet.Web.Controllers;
4 |
5 | namespace ReportDotNet.Web.App
6 | {
7 | public class DirectoryWatcher
8 | {
9 | private readonly IHubContext hubContext;
10 |
11 | public DirectoryWatcher(IHubContext hubContext)
12 | {
13 | this.hubContext = hubContext;
14 | }
15 |
16 | private FileSystemWatcher currentWatcher;
17 | private string currentFolder;
18 |
19 | public void Watch(string templateFolder)
20 | {
21 | if (currentFolder == templateFolder)
22 | return;
23 |
24 | lock (this)
25 | {
26 | if (currentFolder == templateFolder)
27 | return;
28 |
29 | currentFolder = templateFolder;
30 |
31 | currentWatcher?.Dispose();
32 | currentWatcher = new FileSystemWatcher(templateFolder)
33 | {
34 | EnableRaisingEvents = true,
35 | IncludeSubdirectories = true
36 | };
37 | currentWatcher.Changed += Handler;
38 | currentWatcher.Renamed += Handler;
39 | }
40 | }
41 |
42 | private void Handler(object sender,
43 | FileSystemEventArgs e)
44 | {
45 | hubContext.Clients.All.SendCoreAsync("reportUpdated", new object[0]);
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Web/App/GoogleDocsUploader.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Google.Apis.Auth.OAuth2;
5 | using Google.Apis.Drive.v3;
6 | using Google.Apis.Services;
7 | using Google.Apis.Util.Store;
8 | using File = Google.Apis.Drive.v3.Data.File;
9 |
10 | namespace ReportDotNet.Web.App
11 | {
12 | public class GoogleDocsUploader
13 | {
14 | private static readonly string[] Scopes = {DriveService.Scope.DriveFile};
15 |
16 | public async Task Update(byte[] source)
17 | {
18 | UserCredential credential;
19 |
20 | using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read))
21 | {
22 | credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
23 | GoogleClientSecrets.Load(stream).Secrets,
24 | Scopes,
25 | "user",
26 | CancellationToken.None,
27 | new FileDataStore("token.json", true)
28 | );
29 | }
30 |
31 | var driveService = new DriveService(new BaseClientService.Initializer
32 | {
33 | HttpClientInitializer = credential,
34 | ApplicationName = "Google Docs API .NET Quickstart"
35 | });
36 |
37 |
38 | var fileMetadata = new File
39 | {
40 | // Name = Guid.NewGuid().ToString(),
41 | // MimeType = "application/vnd.google-apps.document"
42 | };
43 | await using (var stream = new MemoryStream(source))
44 | {
45 | var request = driveService.Files.Update(fileMetadata,
46 | "1K4_XzsMcgzIYjgNDgbMQUAMSNQibZy3Z92Y188AjTzk",
47 | stream,
48 | "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
49 |
50 | request.Fields = "id";
51 | await request.UploadAsync();
52 | return request.ResponseBody.Id;
53 | }
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Web/App/ReportHub.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.SignalR;
2 |
3 | namespace ReportDotNet.Web.App
4 | {
5 | public class ReportHub: Hub
6 | {
7 | public void ReportUpdated()
8 | {
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/src/ReportDotNet.Web/App/ReportRenderer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.IO.Compression;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Text.RegularExpressions;
8 | using Microsoft.CodeAnalysis;
9 | using Microsoft.CodeAnalysis.CSharp;
10 | using Microsoft.Extensions.DependencyModel;
11 | using ReportDotNet.Core;
12 | using ReportDotNet.Docx;
13 |
14 | namespace ReportDotNet.Web.App
15 | {
16 | public class ReportRenderer
17 | {
18 | public RenderedReport Render(string templateDirectoryPath)
19 | {
20 | return File.Exists(Path.Combine(templateDirectoryPath, "Template.cs"))
21 | ? RenderReportDotNetTemplate(templateDirectoryPath)
22 | : RenderUnzipedDocx(templateDirectoryPath);
23 | }
24 |
25 | private static RenderedReport RenderReportDotNetTemplate(string templateDirectoryPath)
26 | {
27 | var templatePath = Path.Combine(templateDirectoryPath, "Template.cs");
28 | var templateType = CreateTemplateType(templatePath);
29 | var log = new List();
30 | Action logAction = (lineNumber,
31 | line,
32 | obj) => log.Add($"#{lineNumber}: {line}: {obj}");
33 | var method = GetFillDocumentMethod(templateType);
34 | var document = Create.Document.Docx();
35 | var arguments = method.GetParameters().Length == 2
36 | ? new object[] {document, logAction}
37 | : new object[] {document, logAction, templateDirectoryPath};
38 | method.Invoke(null, arguments);
39 |
40 | return new RenderedReport
41 | {
42 | Log = log.ToArray(),
43 | Bytes = document.Save()
44 | };
45 | }
46 |
47 | private static RenderedReport RenderUnzipedDocx(string templateDirectoryPath)
48 | {
49 | const string zipFileName = "somefile.docx";
50 | File.Delete(zipFileName);
51 | ZipFile.CreateFromDirectory(templateDirectoryPath, zipFileName);
52 | var zipBytes = File.ReadAllBytes(zipFileName);
53 | File.Delete(zipFileName);
54 | return new RenderedReport
55 | {
56 | Log = new string[0],
57 | Bytes = zipBytes
58 | };
59 | }
60 |
61 | private static Type CreateTemplateType(string templatePath)
62 | {
63 | var defaultCompileLibraries = DependencyContext.Default.CompileLibraries;
64 | // .Where(x => x.Name.Contains("ReportDotNet")
65 | // || x.Name == "Microsoft.NETCore.App");
66 | var references = defaultCompileLibraries
67 | .SelectMany(cl => cl.ResolveReferencePaths())
68 | .Select(asm => MetadataReference.CreateFromFile(asm))
69 | .ToArray();
70 | var compilation = CSharpCompilation.Create(assemblyName: "NewReport.dll",
71 | syntaxTrees: new[] {GetSyntaxTree(templatePath)},
72 | references: references,
73 | options: new CSharpCompilationOptions(
74 | OutputKind.DynamicallyLinkedLibrary));
75 | try
76 | {
77 | using (var ms = new MemoryStream())
78 | {
79 | var result = compilation.Emit(ms);
80 | if (result.Success)
81 | {
82 | var types = Assembly.Load(ms.ToArray()).GetTypes().Where(x => x.Name == "Template").ToArray();
83 | if (types.Length != 1)
84 | throw new Exception(
85 | $"There must be at least one type with name Template in example {templatePath}");
86 |
87 | return types.Single();
88 | }
89 |
90 | var failures = result.Diagnostics.Where(diagnostic =>
91 | diagnostic.IsWarningAsError ||
92 | diagnostic.Severity == DiagnosticSeverity.Error);
93 | throw new InvalidOperationException(
94 | string.Join(Environment.NewLine, failures.Select(x => $"{x.Id}: {x.GetMessage()}")));
95 | }
96 | }
97 | finally
98 | {
99 | File.Delete(compilation.AssemblyName);
100 | }
101 | }
102 |
103 | private static MethodInfo GetFillDocumentMethod(Type type)
104 | {
105 | return type.GetMethods()
106 | .Single(m =>
107 | {
108 | var parameters = m.GetParameters();
109 | return m.IsStatic
110 | && parameters.Length >= 2
111 | && parameters[0].ParameterType == typeof(IDocument)
112 | && parameters[1].ParameterType == typeof(Action)
113 | && (parameters.Length == 2 || parameters[2].ParameterType == typeof(string));
114 | });
115 | }
116 |
117 | private static readonly Regex logRegex =
118 | new Regex("\\slog[(](.*)[)];", RegexOptions.Compiled | RegexOptions.Singleline);
119 |
120 | private static readonly Regex logParameterRegex =
121 | new Regex("\\sAction | | | |