diff --git a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs
index ee171a0fd..f34b0c124 100644
--- a/src/EPPlus.Export.Pdf.Tests/PdfTests.cs
+++ b/src/EPPlus.Export.Pdf.Tests/PdfTests.cs
@@ -27,14 +27,11 @@ public class PdfTests : TestBase
/* BIG PDF TODO
* This should be turned into tickets on github..
*
- * Cells: Cutting Text in general. Check cells at text length
* Cells: Display errors option
* Cells: Icons
* Cells: Pictures in cells
* Cells: Remove stroke from solid fill and adjust size and position of cell more precise and only use fill command.
*
- * Merged Cells: Merged cells with no color set will have the color set to white to hide gridlines. They should not have color set to keep tranparency if we want to include background.
- *
* Tables: Table Implementation
* Tables: Fix order of applying table styling. Right now Table is used if it exsists, but cell styling should be prioritised and table should be ignored if cell has styluing.
*
@@ -42,17 +39,12 @@ public class PdfTests : TestBase
*
* Gradients: Make diamond gradients instead of radial gradtient in from corner and center gradient
*
- * Text: Bold (Can now do back up bold if bold font not found)
- * Text: Italic (Can now do back up italic if italic font not found)
- * Text: Underline (Basic underline done, need double and single and double accounting)
- * Text: Strikethrough (Done, small adjustments to line to match excel perhaps)
- * Text: Superscript (Done, might need adjustments such as moving it towrds top of cell more)
- * Text: Subscript (Done, might need adjustments. Excel adjusts cell height and moves subscript lower inside the cell)
+ * Text: Set up to use back up techniques when not embedding font
* Text: Equations
* Text: Shrink To Fit
- * Text: Broken text hide when overlapping other cells with text
- * Text: Center vertical text
+ * Text: Implement vertical text again
*
+ * Layout: Respect Page Breaks
* Layout: Center on page Horizontal and vertical
* Layout: Scaling
* Layout: Fit to number of pages
@@ -63,15 +55,16 @@ public class PdfTests : TestBase
* Layout: Selected worksheets to pdf
* Layout: Cell range to pdf
* Layout: Remove empty last page
- * Layout: Calculate width and height of cells more correctly
- * Layout: Fix Mask away stuff outside margins being broken
+ * Layout: Calculate height of cells more correctly
+ * Layout: Print Area
+ * Layout: Print titles
*
* Borders: Adjust and make border look better
*
* Pivot Table: Pivot table implementation
*
- * Drawings: Shapes
- * Drawings Pictures
+ * Drawings: Pictures
+ * Drawings Shapes
* Drawings: Charts
* Drawings: 3D models
*
@@ -84,14 +77,15 @@ public class PdfTests : TestBase
public void TestWritePdf()
{
using var p = OpenTemplatePackage("PDFTest.xlsx");
+ //using var p = OpenTemplatePackage("PdfGrids\\PdfTextTest.xlsx");
//using var p = OpenTemplatePackage("PDFTest - Copy (2).xlsx");
-
//using var p = OpenTemplatePackage("PdfBorders.xlsx");
//using var p = OpenTemplatePackage("PdfGrids\\3 2 Page Crazy Cells.xlsx");
//using var p = OpenTemplatePackage("PdfGrids\\3 2 Page Crazy Cells Merged.xlsx");
//using var p = OpenTemplatePackage("Gradient.xlsx");
//using var p = OpenTemplatePackage("PatternFill.xlsx");
var ws = p.Workbook.Worksheets[0];
+ //var ws = p.Workbook.Worksheets[1];
PdfPageSettings pageSettings = new PdfPageSettings();
pageSettings.ShowGridLines = true;
pageSettings.PageSize = PdfPageSize.A4;
@@ -103,135 +97,25 @@ public void TestWritePdf()
pageSettings.PrintAsText = true;
ExcelPdf pedeef = new ExcelPdf(ws, pageSettings);
- pedeef.CreatePdf("c:\\epplustest\\pdf\\FullPageTest40.pdf");
+ pedeef.CreatePdf("c:\\epplustest\\pdf\\FullPageTest44.pdf");
}
- static byte[] HexStringToBytes(string hex)
- {
- hex = hex.Replace(" ", "").Replace("\n", "").Replace("\r", "");
- int length = hex.Length;
- byte[] bytes = new byte[length / 2];
- for (int i = 0; i < length; i += 2)
- {
- bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
- }
- return bytes;
- }
-
- static byte[] DecompressZlib(byte[] compressed)
- {
- // Skip the first two bytes if they are zlib header (78 9C)
- int offset = 0;
- if (compressed.Length > 2 && compressed[0] == 0x78)
- offset = 2;
-
- using (var input = new MemoryStream(compressed, offset, compressed.Length - offset))
- using (var deflate = new System.IO.Compression.DeflateStream(input, System.IO.Compression.CompressionMode.Decompress))
- using (var output = new MemoryStream())
- {
- deflate.CopyTo(output);
- return output.ToArray();
- }
- }
[TestMethod]
- public void TestReadCompressedPdfObj()
+ public void TestWritePdf2()
{
- // Paste your hex string here (can be very long)
- string hexInput = "78 9C EC 7D 09 60 17 C5 F5 FF CC EC 7E 93 90 9B 00 E1 08 98 6F 08 84 84 DC E1 08 97 18 EE FB 4C 80 04 51 F3 CD 45 02 B9 CC 01 82 1C 11 11 69 B4 D6 2A 45 44 2B 8A D6 03 50 03 5A C5 FB B6 96 2A D5 56 AD 5A AA 28 82 08 16 95 7A 00 95 EC FF 33 6F 77 BF D9 EF 91 6F 12 D4 DA FE FE EE E6 CD CC BE 79 33 F3 E6 7A EF CD EC EC 37 8C 33 C6 BA C2 51 59 D6 A4 F1 13 26 6A 6F 9E 5D C4 78 54 3E 63 62 C3 A4 D9 B3 B2 F7 AC FA 66 0F 63 D3 2F 63 EC E9 7B 27 65 CF 1B 3B 70 45 D8 51 C6 83 EC 8C 85 3E 3D 2B 3B 35 63 EA E9 BB DF 63 8C BF 82 5C F2 B3 73 C6 E4 5C FC EA F8 99 8C F7 3A 85 E7 92 C2 0A 47 75 C8 3B 7E 89 8C 75 7B 07 CF 0D 85 CB EA EC 71 9F 74 3B C9 58 7C 30 9E 9F 2D A9 5E 5C B1 E0 9A B0 70 C6 22 73 19 0B BB 72 B1 A3 B6 9A F9 B3 28 94 57 8E F8 E0 C5 E5 2B 4A 7A DC 7C FF 1A D0 BF CA 98 6D 57 69 B1 A3 28 F6 CB E8 33 28 6F 3A E2 87 96 02 11 7C AB FA 31 9E D7 E3 B9 5F 69 45 DD 65 09 6F AA 87 C1 7B 3C 63 5D 1E 58 5A 5C 53 19 F1 52 D8 16 C6 86 6D 44 FC E4 F2 AA 42 C7 46 65 C3 B7 8C A5 A0 3E 81 A1 15 8E CB AA 03 AE 0C FB 17 D2 DF 8B 78 7B 45 71 9D E3 C6 D3 99 A7 19 EF 79 10 B8 1E 95 8E 8A E2 9A BF 4F 8F 45 FA D7 91 DF E5 D5 55 B5 75 DA 36 96 01 FE 64 F9 F6 EA 9A E2 6A DB 83 9F 1F 65 AC FF 01 94 99 C2 64 5B 0A C6 6E 4A EA 9F 71 49 D8 A8 AF 59 CF 00 26 AF 7F DC 55 7F 46 FA 1F 1E BD A4 FF 77 79 67 5F 0D 78 2A A0 2B B3 33 3F 49 4B 17 D2 F9 5F 79 F6 19 C6 3A 5D F2 5D DE A9 AF 02 9E A2 9C 2C 97 FA 86 C4 D8 FC 58 0A FA 29 8C 29 48 19 CE 52 81 E2 A2 30 EC 4A 3C 71 A6 AA 03 F8 F5 88 0D B0 0D 52 5F 43 92 AD BA 2F 5E 63 25 E2 EF F0 83 98 2A E4 A5 DA 99 B8 1A F1 8A 99 F7 8C 6C BB 9D 3D CB 42 CE 7E A7 F3 10 D0 55 0C B2 33 BE 4D C6 29 A7 6C 63 65 4D 99 A2 94 81 8B 89 28 05 C0 7E BE 7E 92 CB F6 07 76 E7 4F CD C3 CF D7 FF D6 A5 F6 61 05 DE F0 CA 47 DE F1 FF 89 4B 0D 65 9B BE 6F 1E FC 4F DA 71 09 3F 04 3F FF 0D 97 58 F1 FD DB E4 E7 AB FD 97 32 8E CD FD A9 79 F8 F9 FA F9 FA F9 FA F9 FA F9 FA F9 FA F9 FA F9 FA FF E5 12 8F B2 CB 7E 6A 1E 7E BE 7E BE FE 73 17 7F E0 27 28 54 EE 2E CA 5D BE AE 70 69 97 97 A9 4C EE AB 46 B2 70 60 FC 58 5F 36 86 CD 60 C5 AC 94 2D 61 35 6C 07 7B 4E 64 6A 1A E2 75 7C 91 2B 5E F9 52 7B 16 39 30 B6 93 3D CE 8E F0 40 6D 4C F3 09 E7 2E 65 B8 5B C9 27 D8 57 59 53 6F DE 72 D3 E6 AB 37 5C B5 FE CA 75 57 34 AC 5D B3 7A D5 E5 2B 57 5C B6 7C 59 7D 5D 6D CD A5 D5 55 95 15 E5 4B 97 94 95 2E 2E 29 2E 2A 2C 70 E4 5F 72 F1 45 8B 2E 5C 98 97 BB 60 FE BC 9C EC 39 B3 67 CD 9C 31 7D DA D4 29 93 27 4D 8C 8F 0E 0F EC 94 C4 77 07 05 8E 8B 1D 57 1C 98 9C C4 76 07 06 21 18 94 9C C4 9B FC C6 35 F9 13 B2 69 56 A2 BD 29 6B 4E 6E CC B4 B9 B9 13 C6 47 C5 C4 E4 45 C5 C6 34 65 35 A9 FD 27 48 70 14 35 16 9A 11 79 C8 02 A9 90 16 59 4C CB 8E 9D 36 67 61 AE 7D 42 63 3E 45 02 93 E3 F2 A4 C7 0F 73 C6 19 A1 26 31 2E 27 B7 69 62 22 9E 2C CF 93 E8 D9 F9 38 D9 2D 7A 8A 19 1D 6B 6F 62 B3 1B 1B 8B 76 33 A5 3F F0 59 51 BB 39 05 6C E3 AE C9 43 4D F2 62 9B 0A 12 63 63 62 73 8B 41 BB 3B 80 05 C7 E4 E4 8F 43 28 D8 0C 71 FB 24 E4 68 DF 1B CE 0A 00 85 0B 62 F7 72 23 B4 30 B7 C9 9E 5F 92 37 19 D4 4C F4 6F A2 BF EC BD 6C 48 EC 65 7A 38 BF C9 5E 68 B7 37 F9 F5 8F 2D 98 9D DB 18 D3 C4 F3 63 A3 8C E7 B9 B9 68 31 EE 88 6A 8C 89 8D B1 E7 E5 ED D5 9E EB 2D A9 63 63 90 97 60 63 77 C7 F2 8D 73 76 67 F1 8D D9 0B 73 1F 43 77 DB 37 E6 E4 EE 11 5C 8C CB 1F 9B B7 BB 1F E2 72 1F B3 33 96 45 58 21 B1 12 29 1F EC F2 81 4D E3 E8 99 3D 22 80 E8 A3 1E CB 62 AC 81 62 55 42 D0 73 21 6A 41 B8 00 13 C7 59 E1 5E A1 E3 C2 F5 82 E2 A8 A0 2C 8C EC C2 BD AA 1E 93 65 52 AB C0 05 E8 B8 06 9D 3A DE A0 0E 40 4C B8 8C 79 9C 09 8C 58 8A D4 2F B4 12 7A 26 2B D0 96 15 90 D5 29 2B 58 84 08 F4 85 44 ED 01 E6 71 D0 76 E2 EC A1 60 1E C2 A3 76 23 CF B9 84 DE CB 1B 76 77 CA 8A 7A 8C 72 9A 6B 50 36 80 52 E2 1A 9C 38 70 2E C9 2C 19 A1 3C BD E2 F3 5A 6A 30 6F 61 EE 43 C1 0C F9 93 0B 8A B1 F2 4A 4E 9A B0 5B CC 4C 8C 6D 19 D6 73 72 D1 7B 13 76 F3 99 89 F9 18 DA F2 51 E9 3F C1 8E 61 DD 94 95 9D 2B 69 F3 A3 30 E6 31 BA C7 27 27 C9 D1 65 CF 8D 2D 8E 8A CD DB DD B5 6B 63 F5 84 DD E1 E1 E3 A6 35 8E C3 40 C6 58 A3 01 B6 DB E1 17 97 9F D8 A8 0F 39 39 D0 62 C3 47 60 98 2A FD A7 14 C6 4E CC 07 49 2C A6 0D FE A6 00 55 38 DF 9E DF 54 90 9F 88 A0 3D 7C 62 E3 44 39 2A 1C 92 9A 45 EE 16 4A FF DD 5C ED CF 47 B3 D1 68 37 BF E0 A6 C0 D8 E2 B1 4D 41 B1 63 9D 31 17 B0 0B F4 18 3F 19 E3 1F 3B B6 89 47 EA AD 3E 21 76 82 BD 47 59 63 61 6C 01 46 60 D6 EC DC C5 51 25 79 0E E4 DD 94 15 EB 68 52 63 C7 46 ED 56 D9 58 CC 97 1E 1C 55 9A B0 9B CD 4C 44 DD A6 61 0C CE 4A 9C 7D 21 26 A9 6C 0C 7B 63 E3 78 FB EE 2C 35 CE 51 E8 90 CF E3 63 30 EF 1B 8D A8 D8 F1 E3 F3 2C 29 26 D8 1B 9B B2 1C 85 F9 A0 98 90 47 C4 98 89 40 4E 88 75 D8 8B D0 CA A8 2E 5A 2E 3B 16 C1 85 0B 65 9A 9C 85 B9 8D C1 45 B1 45 B1 68 E1 AC AC 46 07 AA 1D 65 2F CC 8B 6A CC 2B A4 16 47 7A B0 C6 92 93 6C 2D D2 C9 10 4E 42 CE F9 FE 85 25 70 F6 DA 59 41 7E 6C 81 8E 90 B3 D3 1D B7 D8 1D 51 02 2A 2B 2E 76 AA 2C 8E 7C 4E 7E E3 D4 D8 09 45 A0 90 E0 28 6A 52 30 E2 62 EC 45 79 FA 90 61 B3 49 6E B4 4A C4 2D 44 76 F4 29 65 DE 18 3E D2 7C E2 C6 13 1E F0 D7 D8 B4 D8 F5 B1 D4 F9 38 51 42 3E 5A 2D 45 1F 2B 4D 6A 9C 1C 79 B9 31 4D 4B A2 9A CA F3 12 9D 24 8E A6 86 02 7B A3 3D 3C 76 44 AC 74 28 F1 24 09 F9 4D 36 04 1A 0A 1D 52 38 F9 C9 B1 07 C4 54 20 EC B9 05 18 CB C8 70 62 7E A3 39 E2 90 4C 8D 73 96 D4 54 99 E8 92 25 44 2A CF 41 D1 A2 BF AC 4E 53 C3 6C 7B 7E 9E 3D 3F 1F 58 CC 9E 98 28 7B 93 0D BE BD C4 21 07 97 14 BB B3 F5 FA CC 86 EC 87 E7 68 CC 46 5A 26 27 50 54 93 3F 34 40 89 A3 38 36 06 D2 BA 49 4E 5A BD F5 25 8F 2A B8 63 D9 B9 4D 2C AA B1 31 B6 B1 89 83 C5 FE 13 41 8C EC E3 9A FC E2 A6 48 0F 7F D5 89 B1 8E 62 74 A2 2C CF EE 28 A6 B4 13 C1 2E B5 8E CC 2D 6A 42 6C 4C 1E 48 44 7F 6A 4B 34 1C A4 45 81 74 0A 1B 31 1A 9B 2E C2 6C B3 F5 EF DC 18 D1 68 1F DE 08 A9 75 11 04 AE 1A 57 38 3F 1F 6A C1 1E 6E 9F 68 A7 AE 76 60 24 CB 46 98 22 9F F2 90 91 4E D8 A9 BF 24 44 7A FA 8B 6B AA 48 DC 7D 91 7F FF 16 0C FD 55 25 EA C4 01 94 2B 38 9B 9B DB 34 DB 24 F1 A7 3F 04 2E 4D 6C 12 DD 87 21 52 56 9E CF 85 FC 50 A9 A3 64 E3 D9 FA 4F 41 F3 66 61 54 45 C9 D4 F6 26 91 93 6B 74 0F A5 9F 22 93 46 99 1D A6 27 03 86 C4 AE 54 8B 31 26 BF 41 3A BF 7A A1 7E F4 17 4C 7F 9D FA 37 05 F4 47 47 37 A9 E0 41 8F F6 97 D5 69 19 04 08 83 69 3D 8D 42 EC EA 15 40 18 45 D9 8D 18 AA 48 BE F1 A0 F6 2F A6 3A E9 EA D0 2E C5 27 0C 05 47 AC 84 A8 BD DA B3 B3 21 23 F3 63 25 E4 E5 C9 E2 03 A8 20 99 82 B2 6E D4 33 96 CD E5 27 23 BD 35 85 51 92 FE 17 24 FF A6 50 15 AC E8 40 FA F3 27 9E 65 9C 5E 25 9B 6B C3 1B AD F7 18 0C 2F BD E5 62 8C 4B 8E 19 59 CB AB 8D 59 69 CC BB E2 A8 A6 D2 BC C4 22 3D 95 9F 21 C1 ED 90 A8 90 DC 85 73 C8 DA B8 10 B3 21 36 C6 1F 72 0C D5 C7 AC B2 37 65 27 42 89 50 DD AE D6 5B 75 AA 2E 1D E4 A8 E4 13 63 D9 44 8C 21 23 00 C3 B1 89 C5 4E E6 D2 61 98 5A B1 93 9B 04 1E 9D A1 D8 3D 82 F1 80 D8 61 D2 EB 14 3B 6C B7 E0 FE 90 F6 52 18 85 87 04 43 D0 37 16 E6 17 E9 8A 1A AD CC 86 45 8D 92 A6 91 1F 75 74 27 EA DB 65 52 34 E5 E4 DA A2 D4 3C 1A 32 71 4D CB 13 8D 51 AC BB CB 12 9D F1 CB E5 9C F4 37 5B 32 40 C6 35 3A 23 6D 94 DD 72 7D 6C C4 19 EE B2 C4 00 AF A9 1A 03 DA 57 58 80 D1 9B 4D 9D 28 4E 4A A3 B8 00 DF 45 29 7A 07 4D D5 BB 6B AA D0 73 9E AA CB 09 60 E3 0A 1B 1B A5 68 DB 7D 51 A8 9C A1 C1 71 9D 81 8F 00 6B C3 C1 E4 70 83 4B B4 CD 2A B0 32 5B 16 1D 40 18 7A C4 74 F3 97 EC E8 DD D6 3F 08 11 E1 A0 7D 4E 1F DA 41 88 0C 07 37 CF 45 E9 54 F8 7B 0C C6 FD B2 44 93 5A 6F 04 F0 1D D8 5F 1F E7 46 B4 91 5A 1F 9D CB 13 F3 10 9A 28 21 1F 24 13 25 18 33 29 C8 98 A5 C1 6E 52 DF C8 5E EF D3 4E AE 91 B1 CE CC A4 A2 8F 75 E6 28 9F 76 F3 60 D8 C0 6A 94 0D 25 C6 D9 C3 D1 5C 23 A8 3D E3 C0 2A 9E 1B 47 EC E6 FE 71 06 81 4D 12 88 FE 23 1A 1B 83 4C F9 2F C5 FF 63 30 40 19 19 97 2C AF D1 1D D1 B4 1A FD 81 BE 0E F1 1E 13 E0 8E 0D 21 B4 D1 CB 21 4E 5F 22 8D E9 10 38 AE 29 68 9C B4 5F A4 6E EA 24 07 40 0A FA 77 F5 4B 86 CC 21 73 C2 D2 30 84 92 53 D1 8A ED 21 DB DE DF 14 09 55 89 66 5A B3 DD 4A 68 4A 1B 69 DD B0 39 B9 AB 81 95 2D F5 92 D4 24 4D 1C BE 2D 2E 46 42 94 6C 3A 2A 4D 8E F1 AA 44 C3 D0 5D 2D 7B 77 1D 65 B7 2E D1 6E 2F 83 9D 35 8E C3 DA 82 A2 2C 93 AA CA 2E A9 03 E2 48 C8 35 C2 E0 29 73 38 48 0E D1 32 A6 07 6C A9 B9 D2 3A C6 0A 20 36 DC CE 47 B1 51 FA 62 28 D6 58 67 40 07 A8 FD 73 47 45 0D CF C3 BA 62 AF F6 69 EF 3C 5D 54 09 28 79 40 4E A3 DD 1E DE 19 51 8D F6 08 2C 34 9A AE A2 E6 35 E2 62 09 07 2D EE 17 67 50 C9 1A 5C 85 C9 A9 D3 49 EE 83 45 E3 B4 6C 34 82 5C 91 05 0E 8B 0A 94 AB 3C 73 81 B5 25 D1 57 B4 5D A6 87 94 6A BA 24 F6 B2 18 D9 14 4D F3 63 57 C0 58 18 17 DB 64 B7 2F 82 48 04 72 52 EF BC C6 46 A8 D3 C6 58 B9 92 9A 9F AB BB 32 8A 27 F5 96 96 81 B4 62 0C DA A8 DE 58 A3 B5 3C 06 F7 96 C3 CD B1 57 7B A8 B7 5C 2E 39 4B BB DC 2C AD 06 A5 C9 40 A3 59 5C 53 A1 D7 D2 E4 28 E3 17 EA 63 0D 7F C4 FE EE A1 2C 56 2F 5F 8D 33 0A 6D 5C D4 B8 10 EB C3 98 A6 3E B2 60 83 0F 3C 86 F6 CE A3 1C C0 C9 16 C9 09 CB D2 2E 49 D3 A2 2F 4E D7 A2 2F 4A AD 89 5E 94 7A 63 F4 85 A9 5A F4 C2 14 2D 3A 2F E5 B5 E8 DC 24 2D 7A 41 B2 16 3D 3F F9 B5 E8 79 89 5A 74 4E C2 D4 E8 EC 04 2D 7A EE 40 2D 7A CE C0 9D D1 B3 13 EC D1 B3 E2 27 44 CF 8C DF 19 3D 23 5E 8B 9E 3E 40 8B 9E 16 A7 45 4F 8D 4B 8C 9E D2 6F 71 F4 E4 7E AF 45 4F EA A7 45 4F EC AF 45 4F E8 BF 33 7A 7C AC 16 3D AE AF 16 3D 36 E6 B5 E8 31 31 5A 74 56 CC CE E8 0B EC AF 45 8F B6 6B D1 E7 DB 6F 8C 1E 65 4F 8D 1E 79 5E 4D F4 88 F3 B4 E8 E1 D1 5A F4 B0 E8 86 E8 CC 3E 35 D1 43 FB 68 D1 43 FA BC 16 3D B8 F7 6B D1 83 7A 6B D1 19 BD 77 46 A7 A7 D5 44 A7 24 9D 1F 9D 9C 54 13 3D 30 E1 E2 E8 FE 28 AB 5F AF A8 9E 8B 62 FB 66 45 F7 55 7A F5 5C 14 D3 EB FC 68 FB 28 04 A2 CF 5B 1C 7D 5E 42 8F C8 45 7D BA 6B D1 BD 23 B5 E8 A8 21 3D 47 5C D8 63 68 E4 88 0B 7B 65 CD 90 E1 EE 32 DC AD E7 C8 C8 D2 85 5D 86 47 CC EB 3C 3C 7C 5E 44 5E 78 5E C8 F0 E0 79 B6 E1 EA BC E0 3C 35 2F 55 9D A5 5E A2 2A D1 F0 D6 AA DB D4 3F AB 9A EA 17 36 34 74 5E D0 F0 C0 79 FE C3 FD E6 85 E6 05 E6 F9 61 51 FC 6C 56 4F BF 88 6E 13 59 5E A7 E1 01 F3 94 E1 62 5E 40 9E C8 0B 67 4A 56 96 8D 3F C6 AF 67 39 89 D3 F6 FA 6B 73 A7 35 05 CC BE B0 89 6F 6C EA 9F 2D 5D AC 28 9A FC 36 36 B1 79 0B 2F CC DD CD F9 75 79 57 FD F2 97 AC CF D8 69 4D D7 67 E7 EE 51 18 82 30 32 C5 B8 39 B9 BB 55 E5 BA BC B1 2C 91 25 26 4A 60 89 7A 30 B1 B6 CE C4 49 97 5B 6E 06 90 7F 2C 51 0F E8 F1 89 7A 32 23 EC 7C 48 34 49 0D BC 4B 4C 0F C6 6C 63 E5 CD 22 6C DD 59 84 F2 35 8B 60 4C 3B 61 42 F3 56 ED 9F 12 AF 3F B3 55 EC 0A 56 81 7B 39 2B C2 2D C3 2B 59 35 5B C6 B2 59 31 AB 67 E5 6C 31 28 96 C2 AD 65 4B D8 DF 98 83 2D 64 35 2C 07 14 8B D9 E5 A0 DE C0 4A 91 62 19 DC 4B F1 BC 9E E5 B3 2A E4 74 39 9B 81 F4 B9 94 83 03 94 E5 88 5D 86 DC 57 53 4E 92 7E 2E 9E CA 10 7B 25 F2 9C 87 3C 8B 80 AD 61 73 D8 02 76 11 28 2E D5 4F A6 29 65 B6 A9 4C 61 61 AC 0B 4B 66 A9 59 BD 06 76 B7 F7 1A 60 EB A7 06 76 2D 0B 54 C3 C3 53 FA F4 EB D2 85 8B 1A 16 50 83 DA 67 84 BF 9C D1 79 10 9C C4 CE 11 DD 87 A7 A5 5F DA 39 A6 73 FF BE 71 43 06 0F 1D 94 11 D9 AD AB 9F 2D A6 73 0C 8F 1B 9A 39 74 E8 90 C1 71 B1 7D FD BA C5 9A 31 FE 7E 7E FE 4A 59 F3 C4 98 94 94 98 BE 69 A9 CD 15 E2 D8 D9 48 3E 4A 1D 32 64 70 FA E4 69 93 73 CA 6F AC 5F 7E DD A4 D1 A9 31 AA 6D EA 99 47 3E 48 ED 1B 9B 92 12 DB 37 F5 B7 EA 8B DF 7D 99 B3 34 39 69 4A E6 A8 39 79 73 57 6D BC 7C E9 9C FC CC 84 99 C3 E5 7E 1D F8 57 65 0F F8 B3 40 16 95 15 12 A8 06 F8 F9 31 F0 AA 12 B3 E0 71 78 EA A0 CE E0 B2 96 0F E2 B1 4A 8C D2 25 46 51 F9 CB 8F F2 E7 1E AE 6B 8E 5C F1 3B 7E C3 1F 6D 63 CF 3C CD 1B 9A 1B 44 84 B8 9A 41 A3 53 8E 7E 2F F8 C5 C9 BD 3A EE A7 FE 39 16 16 F7 23 22 88 73 7E D9 7C 96 38 58 9E 3D BC 13 3D DF 0F A5 86 B1 11 59 F6 00 FF DB FC B9 6D 83 3F 57 C2 D8 2D 48 A1 74 0A 51 82 83 FD 98 1F D8 08 30 D8 C8 E8 1C 31 3C B5 FB 70 7E C9 45 9D 07 5D 72 91 74 C1 52 67 B0 C4 07 75 8E 35 FC 3B 9F E6 BB 26 F1 DF 3D 76 DF E8 E6 C5 CB 9B F3 2F B0 8D FD EE A0 62 3F F3 B4 DA F4 DD 29 25 E0 DF B3 51 DB 02 ED 4B 65 A3 1C 6F 2C 9A CD C8 4A 0E 0F 8E 6C 88 E4 F5 91 DC 2F 32 F4 B7 A1 DC 16 DA 29 7C 4A 69 28 EF A3 86 AA 31 F6 D0 C0 9A 10 56 D3 2B 28 C0 BF A6 4B 38 0B 92 6C 64 C8 3F 74 1B 1F 3E BC F3 A0 8B 12 75 66 E0 80 99 09 7D E3 64 17 CA 9E EA DE 19 3C 0D F0 F3 1B 90 31 34 B3 73 1C 75 61 D7 48 FE EC D2 DB E6 5D 78 67 E5 C5 9B E2 6F DF 12 90 76 E3 98 8B 1A 06 F4 BF 7C 61 4D FD A5 61 CB 3E BD 7F CF D1 4B 2F 9C C1 3F 3A F3 F4 AF 26 2D 58 77 C9 24 FE 50 4E F1 4B 2F 3C F3 27 E2 F8 0B E5 0A 35 80 F5 62 31 AC 4F 56 68 54 24 0B 0B 63 D1 92 27 9D 25 B4 CC F0 D4 88 E1 AE 1C C8 B1 12 D3 35 32 72 10 38 18 14 2A 78 0C 71 21 02 6F 7C 62 61 EE C3 D7 3C F2 17 C1 CF 6E 18 52 7B F1 85 8E AE DB C3 2F DA DA FC 2B FE BE B2 B2 BC 62 4D F8 FA 23 37 DE 79 72 C3 D9 CF 43 FA 07 95 DD 57 30 7D CA BC 95 63 44 F1 CD DB B6 A0 C7 36 61 94 AF 43 CB 75 65 D3 B3 92 B7 06 F2 E5 41 DC 2F 28 70 5B 20 5F 13 C8 2B 02 B9 4D E9 CA B6 31 DE 88 EE 0B 64 91 DD C2 15 3F FF 1A CE 6A 82 58 20 31 89 76 A3 56 D3 5B 0B AE DE 72 D4 87 9D 75 96 D1 8D 83 89 4D FF CE 9B EE 18 78 D3 B2 1B D6 DF D9 7D DC F8 4B D6 0F B0 8D 6D 8E 19 51 BA E7 8E B3 33 C5 2D 23 CA C6 14 0C 3B 1B C5 84 76 BC 79 2B 9F 82 59 17 C4 BA B3 AC AC B8 AA 9E 5C 59 DA ED F2 6E A2 5B 58 40 98 ED B7 36 6E DB 08 E8 D9 A3 2C 62 45 84 88 08 F6 F7 03 37 A1 C4 CA FE 8C 8B 24 2B 34 86 06 A1 17 2F 01 17 E3 86 A0 A5 86 80 95 AE 7E B1 5D 2C 53 B1 5B FC F9 13 B6 5F 7E C3 93 29 43 86 A4 24 0F 1D DA BC 75 DD 98 05 EA F8 7F BF FC 8B 5B 6C DF 0E 8E 8F 1F 32 24 3E 7E 30 E3 C4 4B A6 72 0A BC 84 3E 62 29 C9 35 DF 6E F1 63 C6 6C 5F F3 2B E4 31 21 1B 79 BC 72 9D D1 AA 62 81 AA B2 50 96 92 D5 53 09 35 9B D0 9F 85 87 75 A2 26 F4 AB A1 16 74 6B 40 6A B7 EE 68 B7 41 DD D0 60 B2 C5 B6 AA FD AF 2A 8B E8 76 41 E1 B4 F3 94 53 BF 9B BA F8 C6 7E E3 93 CF F6 C3 F8 99 2B 92 C5 EB B6 1C D6 9B C5 61 FC 84 D8 FB F4 89 09 08 0B E8 A1 F4 62 C1 5D 58 EA A0 17 33 BA 63 28 67 C8 E9 34 C6 18 3F 99 A6 D8 A1 7E 91 1D 63 8C E5 21 7E 34 90 87 8C 2E 3D 7F C5 3F 36 E7 64 4D 58 74 BD B8 6F C3 EC 0D B3 1B FD D2 AE 4A 9C 5A 67 DF BB ED 02 91 3C B8 64 7A 69 79 82 92 99 3B 61 F2 EC C6 CB 53 6A 96 9C FD B6 72 E4 A4 CA 99 A3 7E A3 4C 9F 33 72 BC 94 39 97 29 D5 02 B3 93 75 82 BC 0C FD 7D A0 CA 96 84 AA E0 25 31 03 4C 80 87 21 83 68 FC 3A 43 FC D9 A0 B0 9B 43 82 9B 97 06 85 DE 1C 12 A4 54 5F F2 40 79 5E 5E E5 7D 05 97 3C 5C 92 97 57 B2 A3 8C 71 FE 80 ED 51 A5 9B DF 0B 90 C1 81 0F 31 BE 84 B1 54 B4 FE 98 2E 83 14 FE C0 83 7B 8F DB 1E E5 C1 CD 5F 49 41 7D 09 DB C8 B6 FE 4F DF 6F FF 7C 7B BF 79 AA E5 AE FD 5E F7 13 6D DD 82 8B F3 FE 23 F7 AC FF D1 FB E6 9F EF 9F EF 9F EF 9F EF FF C9 FB F9 9F EF 9F E4 7E FB 3F 79 D3 A9 11 79 9A 64 3C DC 4E 2C 8D CE A7 70 B5 8B B6 89 09 72 BF 82 7B 9C E7 B2 13 DA 11 B8 5F 69 47 D4 2E B0 F5 37 C1 15 E4 9E D0 8E C3 FD 8A BE 07 89 E3 FB CD 93 29 CA 30 23 5F E9 06 E3 89 1B 27 63 FC 95 F1 46 58 61 41 CA 34 23 AC 5A 68 6C AC B3 52 6C 84 FD 58 2F 27 8D 3F 1B AE 2C 33 C2 21 FC 45 E5 41 23 1C CA 12 6D B5 46 38 DC 92 4F E7 96 B2 E0 F8 D9 6E 33 C2 9C D9 6C 77 19 61 0B 3F 3C 88 F9 29 B3 8D 70 08 E8 EF 93 A7 77 D4 4E 48 5A 6D 7B D0 08 73 D6 23 38 DA 08 0B 16 1A 9C 69 84 15 16 19 3C C1 08 AB 16 1A 1B EB 1B BC C2 08 FB B1 C1 4E 1A 7F 56 13 7C 8B 11 0E 60 11 B6 A7 8C 70 27 D6 3B 24 C4 08 07 B1 9C 90 04 23 1C CC D2 42 56 1B E1 10 65 63 C8 FD 46 38 94 CD EF 3C C4 08 87 5B CA ED DC C2 1B 2A 14 DC F9 1A 23 CC 59 60 E7 9B 8C B0 85 7F D4 3D 38 78 96 11 0E 01 FD 1D F7 D9 33 D2 32 06 DB 67 94 15 D6 54 D5 56 95 D4 D9 C7 55 D5 54 57 D5 38 EA CA AA 2A 53 EC 63 CA CB ED 73 CB 16 97 D6 D5 DA E7 16 D7 16 D7 2C 2B 2E 4A B1 E7 94 16 DB FB CA 2F 3F FB DA EB 1C 05 E5 C5 F6 AA 12 7B 5D 69 59 AD BD A4 AA B2 CE BE DC 51 6B 2F 2A 5E 56 5C 5E 55 5D 5C 64 2F AB B4 57 3B 6A EA EC F5 B5 65 95 8B ED 0E 7B 6D 5D 7D D1 0A 7B C1 0A FB 98 CA A2 9A EB EC 13 EB 0B 4B 6B ED 55 95 48 5F 6C AF 29 2E 2F 5E E6 A8 2C A4 0C 65 FE 32 49 B5 A3 AC A6 D6 1E 5F 5A 57 57 5D 3B 22 35 75 71 59 5D 69 7D 41 4A 61 55 45 AA 03 39 14 27 97 C8 1C 52 0D EA 64 A2 4E 2D 28 AF 2A 48 AD 70 D4 D6 15 D7 A4 4E 9F 32 6E C2 CC EC 09 29 15 45 09 29 A8 5B F5 8A 1A 59 1D 54 3A 7D B8 95 87 14 FB EC E2 9A 8A B2 DA 5A 54 DB 8E AA 94 16 D7 14 83 CB C5 35 8E CA BA E2 A2 24 7B 49 4D 31 B1 55 58 EA A8 59 5C 9C 64 AF AB B2 3B 2A 57 D8 AB 8B 6B 6A 91 A0 AA A0 CE 51 56 A9 D7 B0 10 65 38 5B 44 B6 E8 72 47 4D 31 88 8B EC 8E DA DA AA C2 32 07 F2 B3 17 55 15 D6 57 14 57 D6 51 33 DB 4B CA CA 8B 51 47 D9 06 7D B3 8D 14 7D 13 A8 90 A2 62 47 B9 6C 44 19 67 46 D9 97 A3 11 AA EA EB D0 60 B5 75 35 65 85 32 8F 24 10 15 96 D7 17 49 1E CC E8 F2 B2 8A 32 A3 04 6A 5E BD 1F 91 69 7D 2D 6A 20 F9 4C B2 57 54 15 95 95 48 BF 98 AA 55 5D 5F 50 5E 56 5B 9A 64 2F 2A 93 59 17 D4 D7 01 59 2B 91 85 C5 95 32 15 EA 91 5A 55 63 AF 2D C6 C0 40 0E 65 E0 9B EA DA C2 1D D1 C8 52 AA 65 83 D6 19 4D 44 E5 2E 2F AD AA 70 AD 89 1C 34 F5 E8 BA DA D2 62 4A 53 54 85 26 A3 12 97 14 17 D6 49 8C 24 2F A9 2A 2F AF 5A 2E AB 56 58 55 59 54 26 6B 54 3B 82 86 A1 A3 A0 6A 59 31 55 45 EF D6 CA AA 3A 70 AA 73 20 DB BF BA A5 53 8D A8 DA 52 07 58 2F 28 36 DA 4B 1F A2 0E 4B 6D 6A 64 E9 B5 75 E8 F7 32 34 3D A6 02 15 E7 5E CB 94 31 D5 75 55 B5 F6 99 8E 9A 9A AA E5 73 8B 17 D7 97 3B 6A 08 A5 63 92 D3 87 A7 C9 2B 79 88 43 7A F3 D1 06 92 87 8C 94 B4 B4 91 B3 06 0D 1D A2 A7 06 83 0E 7B 5D 8D A3 A8 B8 C2 51 B3 D4 2C A2 65 2A 2E AE A9 AA AF A6 51 57 55 51 ED A8 04 7B 29 2D 91 B5 F5 D5 D5 E5 65 E0 5F CE BA 14 7B 5E 55 BD BD C2 B1 42 F6 AD 65 32 A2 01 0B 6B 8A 1D B2 17 D1 A3 D5 E5 8E 15 7A F7 54 D7 94 21 16 AD 59 87 41 88 81 69 74 96 1C 9A 18 F5 92 0B A3 C7 ED 98 43 15 D4 2A 46 A0 44 1F 3D 1E BC 56 D7 54 15 D5 17 D6 A1 EF 20 25 90 36 49 A6 31 0B 40 13 2F 2F 2D 2B 2C 75 13 13 66 17 B4 70 5F 55 59 BE C2 1E 5F 96 60 2F AE 28 28 2E B2 90 23 07 5F DC 12 39 0D 7E CB 9C A8 75 E9 63 67 5E 23 A9 05 E2 CB 50 4A 5D 71 85 94 75 35 65 28 B5 A8 6A 79 65 79 95 A3 C8 B5 F5 1C 7A 53 15 D7 C8 EA 54 A1 28 B8 F5 75 D5 98 5D 90 71 72 3C 81 A6 B4 B8 BC DA B5 45 21 38 21 1C 74 72 D9 21 72 24 D6 54 95 96 15 94 81 E7 14 53 96 41 08 D4 A6 54 98 2D 48 32 AD 6E 45 75 15 64 4E 75 E9 8A 54 0C ED FA BA 05 C5 72 58 2F 28 2B AA 2B 9D 52 E7 40 9F B0 FB 98 9D 65 40 7D 67 B0 C1 08 CD 60 65 AC 90 D5 B0 2A 56 0B 28 61 75 C0 8D 43 A8 86 55 93 EB 00 A6 0C A1 4A 96 82 98 31 AC 1C B7 9D CD 05 6E 31 2B 45 5C 2D 3D 15 C3 2F 06 F5 32 B8 45 44 99 83 D8 62 F8 7D D9 52 8A A9 44 C8 0E 7A 07 2B 40 0E 32 46 96 26 31 A5 C8 4B E6 52 42 A5 C8 F2 97 83 4A 62 8A 40 27 73 2C 47 4C 35 E5 6C 07 6D 25 DC 6A 50 D4 10 6D 3D 28 25 6E 31 C2 0E 40 2D B0 F5 A0 5C 81 70 01 B9 63 10 5B 04 EA 4F 11 9E 88 B8 42 94 58 4B E5 57 1A E5 4B 6E 6A A8 1C 59 9E 03 F8 42 0B 87 26 FF 66 29 B2 EC 32 60 64 1E F1 D4 06 75 C0 D5 B2 11 2C 15 F7 62 C4 C9 3C EB 51 7A 0A F2 A9 62 15 C0 3A 0C 1E 8A 59 32 F2 34 79 48 75 CB 3B D9 92 77 2A B5 53 15 DC 54 E4 E0 A0 7A 49 DA 54 36 9D 4D 41 0F 4D 60 33 59 36 DC 14 C4 16 B1 04 6A F3 71 D4 4E 2B 40 65 F6 8E DE D3 E9 6C 78 AB ED 20 D3 CD A6 9C 2B A8 1F 6A 8D DE B6 1B BD 52 4A 71 C5 46 5B 2E A6 11 51 49 BC 14 B1 24 EA 35 19 DB D2 5A 32 57 D9 37 8B 81 4B A2 F6 AD A2 9E A9 A4 F4 D5 94 5B AD 51 82 AC 5D 1D D5 B8 D2 A5 0F 0B 8D 7A 78 8E 11 73 8C 2E A7 32 8A 8D 9C 8B C8 AF A5 D8 42 50 3A 0C FE E4 08 92 98 7A D4 AD 98 B8 6E 19 CD 92 F3 32 EA 71 BD 1F EB 9C E3 35 DB AD 8C BE 68 DD 96 9A C8 31 E9 A0 39 50 E6 32 7E DC 53 C9 51 AC 8F 84 2A 94 5F 67 8C 30 D9 8B 35 34 E3 4C 3E 92 8C 9C 0A 91 67 3D BD 3A D3 DB C1 3D 75 39 9E 2B 08 67 AD 43 CB E8 B5 CE 47 9D D3 7A 9A 93 49 96 F6 94 E1 0A 84 65 29 25 CE E7 62 4B 6F 55 D3 B8 2D A7 D6 2E 25 4C 11 85 75 AE 0B 88 17 9D B2 D6 49 59 48 6D 6B 96 A5 F7 47 2A C9 0E 3B 61 75 89 A1 F3 50 66 B4 77 4B BF 7A 6B BB 24 4B BF EA 75 A9 76 8E D0 3A B7 51 D4 52 DF E5 D4 5A 15 3E FB C4 94 34 F5 C6 AC AB 25 CA 96 72 8A C8 95 39 B7 D4 71 09 28 0A A9 5C 9D C6 CC 5D CA AB 72 9A A3 CB 9D BD 56 48 3C 15 11 9F 65 06 7F 23 2C D2 50 4A BF 2A 92 69 2D BD 62 9D AD 95 C0 D5 19 6D 6A 6D 03 73 FC B7 B4 83 75 A6 BA A6 AA A5 19 A8 B7 7A 81 51 EB 96 F1 65 95 A2 8E 56 FA A6 C6 59 F7 5A 1A 6F 95 94 BB 3E EA 75 AD D0 52 BB B6 FA 32 05 72 A7 9A 5A 4E D2 CE 24 6C 0D B5 99 D4 1A 8B E9 45 B4 C4 B5 50 59 69 92 49 76 A5 39 EF 64 36 04 B1 E6 D3 7C 63 1C 98 ED 90 81 D2 24 7E 24 9B C5 06 B1 A1 A0 B5 96 AD B7 A0 83 78 95 52 4C B6 45 05 95 B5 D4 A3 16 DE B4 E2 62 7A AE 47 8E 2D B2 4E 8E B7 6A 6A 21 BD F5 52 50 FF 3A 43 6B C9 5C 1C A4 1D 8A 8D B1 6A EA 0A 5D 53 2C A7 3B 85 7A D3 B5 AC 16 BD 51 87 F1 21 5B 5C 97 BB D5 C8 61 05 B0 A6 A6 AC 35 74 83 B5 0C CF 14 32 F7 5A 67 9E DE 6A 56 4B B5 AA A6 D9 AC 8F 0F B3 04 A9 1D F2 A8 D6 76 2A 69 85 53 AE 78 D7 DC FA 0C 29 A4 9E 77 38 65 85 2E 43 AA A9 A7 57 B8 CC EE 6A 1A FD 7A DA 42 23 97 62 E3 D9 E1 36 E2 EB 9C 52 5D D7 45 66 5F B9 CA 20 BB A1 27 2B 2C 63 D9 15 53 E2 22 1B DB EE F7 6A 7A 2E 22 8D 59 67 C8 05 DD D6 D1 CB 4D 72 96 E3 5E 03 7D 96 2D 37 FA A0 B4 95 36 33 AD 1D F7 59 EA AD ED 65 9A 72 0A C5 83 3E 01 BE 1C C3 05 4E 19 E6 99 BB CE C3 B9 B6 6D 4B EE 2D 9A C9 BB 1E F3 56 03 AB 8E 74 E5 6B A4 65 0C C8 9A E8 75 A9 A3 F2 4C BB B3 86 F4 F3 0A 43 2A 2F A7 9A 57 D1 BC F5 35 F6 1C 2E A3 AA 98 FA A5 CA 70 EB 0C 6B C6 6E 68 D5 6A 43 B7 EA 76 A6 29 3F F5 7C 4A 49 73 55 FB 1C A3 BA 45 5C 69 F4 4C 4B EE E6 0C 31 65 B6 1C 3F A5 A4 3F CB 8C 76 4E F1 B0 1B 75 4B A5 F6 9C E4 81 AE 55 64 5D 16 20 77 53 9B 2C 40 A8 88 B8 9A 42 52 5C 9F 27 E6 6F 4A 69 B7 CA DF C8 F2 72 71 B9 F3 C6 02 35 8D 85 D1 0E 57 0F 0C F0 40 E6 07 93 71 28 1B 0D 53 51 9E E8 51 C6 4F 9C 9E C3 F2 0B 57 D4 94 B3 55 E5 8E BA 4A 76 03 53 E4 0E 0A 9B 2D D7 A1 6C 7E C5 D2 8A A5 EC 62 3A EB C3 D9 6D CC 46 FE 76 E4 1C 00 78 5B 79 15 F9 85 03 73 2B ED DB 85 13 0D 37 42 B7 83 62 BB 73 AF 91 D1 EF 66 E9 5F C9 29 C8 CF C6 36 30 65 EC A4 B9 76 B6 21 7B EE 58 B8 F3 A6 C9 30 9A 22 60 CC C2 09 68 EC 71 63 72 A4 3B 57 BA D3 C6 2C 84 3B 63 D6 74 B8 73 67 CD 80 9B 43 B1 39 73 A7 C9 6E E1 2B 57 AE 5A CF D4 CB BF B9 66 32 C2 5B 57 DA 99 B8 BC 74 E5 40 84 C7 AF 1C 0F 77 F6 CA 34 B8 E5 2B CB E1 BE BF F2 2E B8 E1 2B BE 81 DB 77 C5 49 26 CF ED 28 46 6B F1 F5 AF CA 9A F2 65 6B 7B 77 E4 5E B3 72 CD CA B5 B7 E1 DE 45 F7 E3 C6 FD CA DA B8 35 0D FA DD F0 9D 79 5F D1 AB E1 95 86 07 9C 77 6F 3C 79 DC 6B 36 E8 F7 BA 53 6B AE ED D0 DD E4 E5 BE C1 2B D6 EB BD 36 AD 21 65 CD 8E 86 14 F3 5E 73 9B BC D7 16 18 F7 08 C0 DB FA BD 66 0B DD B7 B9 DD ED 2E 89 4A FB 78 ED 49 FD 5E 73 97 CB DD B4 76 BC 71 17 B8 DC 33 2D B7 13 BB 66 C7 DA 82 86 8F D6 EC D0 EF B5 B9 66 C8 7A BB E5 63 A6 94 3C B8 62 9E 5F 5B 6E DE 6B 1E B1 DE 0D 59 6B 9E C4 ED 82 5B F3 FC 9A E7 1B B2 E4 7D C5 30 97 78 E0 C9 7F D2 C4 21 B7 27 09 FB E6 9A F7 D6 EC 07 BC 87 90 7E BF 42 38 13 AB C7 C0 6D 98 4F 38 3D 5C BE 76 D9 DA 65 6B 0E AE 5D D6 C0 AE A8 BB 62 F3 15 7B AF 78 7F CD 91 35 9F AD 39 B9 E6 D4 DA 86 35 CD EB 02 D6 AA 6B 03 AF 98 BF B6 71 ED A6 86 2D F2 BE 72 FF D5 13 D7 86 37 AC 73 BD D7 46 B6 DC 44 17 2A EF 75 19 4C DC 7A 40 8E FA BB 8F 6C 1B CD D6 41 F8 58 2E ED 5B 57 91 A2 7D E7 55 D2 F8 BC B4 7F 77 3C 8D DB E5 D7 CE 92 0E B4 83 C8 DF 7B 4A AD 19 EE 69 7A A0 DF 09 D4 DE 71 CB 93 D2 49 2A 03 BF 9F 75 22 FF 09 4B 36 7A 4A 1F BF 92 A5 FD D5 17 6B 74 D6 93 69 DB 7C 50 1C D7 DE 23 FF 8C CF 7C FE E5 0C B5 AB BF F4 72 BD C6 38 5B 54 3B 69 F8 07 7D 51 B5 FF D2 0E FD 78 D4 CE 54 34 7A B5 AF 75 F0 72 F5 33 E3 0D FA 4A C3 7F 05 70 B8 CD DC DB D7 B6 C7 B5 CF DA A0 78 C4 F0 F7 B6 12 FF 07 D7 32 7D B7 85 3E 42 8D 91 EC 1E F7 AD 19 A3 55 1B 18 59 D3 4F 7C F3 F7 03 D6 74 AF AB EF 11 FF 07 B7 67 97 3E B0 8C 45 6A 01 8C DA 20 EF B3 05 1A BD 27 93 5F D6 CB F0 FD 46 FD E4 93 DD 88 6F 76 62 9C E3 DA 88 F9 85 11 E8 67 41 7A FC 02 A7 B6 49 FB 35 BC 6E DE 6B 41 14 7F 94 BC B9 CD 0C 0B BD B6 DD D2 1A B7 C0 89 F0 92 47 CB B8 6C 76 7D 6E A5 CC 4A CB 43 27 03 F7 85 EF 34 6D 5F 6D CD 3C ED 1E C3 6F AD 4F 0F 58 64 C7 01 4F 8D E2 76 FD 9F FD B5 53 43 C6 AA 34 03 55 66 D4 B4 AD 99 A5 9D 6E D1 38 6E 57 CB AF 40 08 F7 28 D7 31 DD 4A CE 3E FA B5 3D E9 5B 49 F9 B5 CE 8F F6 4F 8B 86 EA E7 9B 5E 2F CD D4 A3 DA 2A CB 48 F7 AA AB 71 05 B1 D0 76 B1 13 41 72 A0 3D 97 67 7E 76 72 13 01 93 0D CC 64 E6 75 9E 7A BB 4C 2D A9 FD 8D 5C 8B 14 68 A9 AD F6 AE AB DE 35 2D 8E 96 1C 5A D7 CB 3E 4A DE DF 2E AA 0E 6A 6C A9 35 B4 43 96 B1 A8 DB 3E 5E E6 B2 F6 AD E7 88 D5 DE F0 96 5F AB 65 B5 A9 8F 40 73 AF CF D8 76 B4 5B EB 56 5A 87 5B DD 39 26 A8 55 BB B5 AF 06 3E AE 44 67 7E ED CE 87 DA 33 AE A3 05 9D 8B DD 66 49 19 E1 69 0D 7A B3 0E 7D 5C C3 9D E9 DA BD AE 20 4A B7 FD 8E B6 7F 97 F6 FB FC 72 AD B6 85 E6 EC 4F A2 99 3A DE 43 2E B2 C6 B9 36 D1 0E B6 2E D3 B5 1D 86 FF 4B 46 12 57 7B CB 25 F6 84 33 A5 57 99 EB D1 B2 2D B3 C1 94 44 A1 B2 D7 B4 7D AC 55 E9 49 3C FB D0 12 FF 8D 97 55 4A 40 32 B6 7F FC BA B5 97 55 0F B7 A7 B7 5D CA FD D2 25 4F CB 08 35 72 52 A9 0F 82 7C C8 34 EF A3 DA 1D EB 39 4F BB 39 79 F1 61 05 53 9C AF 78 CB A5 AD D3 35 A0 B6 4D 2B D3 FE 06 2D 02 4B 5C 7B 4A FB 33 73 DA B2 4E CA BB 01 1F 68 9B 98 5D 5B E1 82 87 DC D4 9E 31 C2 FF 32 B9 85 AD BE B7 45 92 6A FB CC B5 B1 B6 DD 92 72 B9 07 3B FA CA 70 BA 4F 96 3D AC 13 E2 96 69 C7 9C 88 3E DA FD E4 C3 72 D0 1E F6 95 55 1B 56 B1 49 B5 BD 6D 9A 8E 5F BA 8D D2 0E 3A AB 85 6F B1 39 3B 68 E1 9B A9 3A A0 65 CF C5 0E FA 31 F3 69 25 77 37 9B E6 C7 2D ED 7F F7 6A AF 4E B3 AC F7 F7 B5 49 BB CF DD 86 D0 4E 42 E7 1D 30 73 F2 B0 53 DA D8 A9 A0 CB 58 3B 68 9A 94 40 18 D5 72 BE DB 48 43 7E E0 46 A9 32 66 B5 7A B5 F7 75 5E DA B5 6B E5 EF CB 16 B6 5E 24 CD DE F7 11 FF B5 5E 2B DF F3 AF E3 96 90 F6 9C E1 5F EF 11 63 C8 23 73 A4 B7 67 ED D1 76 5F 82 66 57 7B 79 EB F8 25 F7 98 AC 35 71 5D 75 59 F0 9B 4C BB 08 E1 FB 0D 7F BF B6 57 1B 2E 35 95 1B ED 1A ED 7E ED 2F 14 BA DB 05 6F 91 8A 6D 70 B5 4D A7 C3 FD 87 56 28 A4 64 AD D6 1E F6 AD 47 E8 8A 27 57 6A 30 EF 7B DD 77 7B 41 5A 6D 87 5B 2C 1A AC E5 3A 9F B5 B9 FA F5 9A B3 35 FE 19 6F BD 0F EB 49 6A F4 BB 3B 66 EB 7A CC E8 7F 79 A5 6A C7 68 37 5B 5C 6B EA 48 F9 3E F2 6B D7 0A 9C 28 CF 49 43 B8 58 80 2D 32 F2 84 B6 DB 08 6D 71 4B D0 4D DB 64 E1 AC 9F E7 98 F7 BE 36 70 CE EA 93 AD B5 A3 76 9D 11 88 70 F2 62 F7 C1 73 07 2D 7C DA AD A6 9D 20 EB CE A7 C7 7C 75 1B E3 90 90 B4 4E D1 5E F6 C8 CF C7 FE A9 EF DD 7E 63 CF E6 71 1F 14 27 B4 0F 7D E5 E0 23 65 CB 2E EF 09 F3 D9 E7 1B A4 0F DD B5 80 B4 6D 4D 7D E6 5E 47 CB 9B 20 77 9D E5 3D F7 77 DA 7E EF 61 50 FA D8 EF 75 86 DB 7C 5B 61 A1 35 EA AC CF 1E EB 88 D4 A5 AF 94 8D C6 B3 73 FC 7B 0B B5 FF EA A0 BC 39 97 12 0E D3 BE 99 45 1F 3B DF 2A 9A B9 B9 49 54 68 18 DA 37 F5 32 7A 7D 58 2C AE 2B 76 8F 58 7D 5C F9 90 CD B0 94 F4 B7 8A BE 2D 07 AF 1C 68 97 03 AE B2 3C 3B A5 9F A5 44 B9 53 54 AB D5 3A 63 CC 1D 87 FD 58 EB 8D D1 2A 98 EB 5B 54 AC BB A0 67 6F 91 9A CE F9 3E C6 B5 CC 43 AD DA 11 86 34 90 12 0F 73 72 3F 34 8E AF F7 12 D9 DA 76 17 5B C0 CD C2 31 2C 33 5A FD D2 EF F2 9C 26 1D 76 AC 25 8E D6 95 76 83 3C DE 25 ED 97 4E 1D 35 54 A7 90 F5 EF C0 3E 41 2B 76 80 F3 0A 6A 6F 4E 1D BD 68 BD 7C 5C DA 24 DA 93 F4 FC 02 B9 72 8C D9 0D 12 BB 0B 3D A8 B4 FB 28 68 D6 F4 8D D6 ED 2A 2F E5 BD D0 06 C1 8F 56 53 0B 0F EE FD 62 6F 95 34 A2 4D 0A EB 35 C1 ED 39 DE 2B 55 FB AE 3B 51 66 1F 0F EC 64 2F 94 3E 2E 43 A3 7E EB 6B 2C 6A CD 16 AD F4 84 F6 29 F9 AF B4 2E 03 3B 7C DE E0 78 5B 6F 98 4C 89 D6 EE 37 C5 4E 8D 69 E1 A5 C5 22 F4 61 B7 42 96 44 B8 8D B0 AE 96 B0 33 C6 D0 8B FE EE F8 36 AE 3E AD 9C CD F3 7D E9 96 92 DD 59 A2 F5 0D 94 BB BD 73 B0 ED EC CC F5 8B 07 FE 10 49 6B D5 1D DB 3E 26 3D AE 0E 8D 6D 57 89 DF EA 95 D8 6A 4C 87 AC 49 17 ED 37 A0 23 29 BD 5E ED DC D3 FC 29 AE 73 EE 3D EF B9 75 C0 46 F2 35 F7 5B E6 BB D3 CE F3 66 E3 76 68 AE B8 D8 06 23 5B 21 6A BF 74 FC BE EF 1F 3A 30 FA 3B 66 4B 9E FB 5B BA EF 7B 75 FC B4 9F 5C 7B BA 58 83 CE BD 65 ED 39 57 29 DC 62 6B 39 A5 93 D0 36 C1 1E BC CA C3 1A 5C A7 3D AC BD 25 6D 46 ED 76 17 FC 41 4B D8 F7 EE 3A ED 53 69 FB 60 E7 B6 B2 FB 24 E5 20 2C D4 4D 9A E5 BF 42 B6 62 31 EB D6 60 95 91 E6 7E 8D CE 4B CA 3D 32 ED 39 ED 41 2F 39 DF 02 F8 90 76 38 36 1B 28 D2 E1 5A 99 61 C3 BA C8 12 70 F0 8C E5 E9 5D 73 27 C6 6A 4D 79 79 F7 DD 8D 76 25 17 7A AF 5B BB 2E A9 03 FC 8D 56 9C AC 6B 7B A3 34 68 62 B9 26 D1 8E 6A BF A7 E7 E3 AE F6 81 85 AF 63 72 C4 40 FE D8 8D D4 7D CC 3A 31 FD 1D 8E CB 0C C3 7A CE 75 6D 14 68 E0 AD 35 F5 1C F9 FD 68 AF D5 63 27 D2 72 05 B5 B6 9F 6A C1 F7 33 56 EB 93 5D 2C 87 57 F4 91 67 9C B6 7A 03 AB 87 77 E5 69 14 84 53 CD 71 63 3D 83 D6 F2 76 1E A3 D6 FA 36 89 C6 8D B6 C7 F9 7C 0B 9D 09 30 57 AF 6F 69 ED D2 3F DA 00 A2 F3 71 F2 55 CB 6E 4F 3E 96 CB F9 CE A6 65 8D DF D2 FE 3E 77 47 3E F3 26 0B BC 9C F3 38 E8 1D EF FB 3A 97 33 C5 E7 7E B9 EC 9E 19 25 1B FB 3B 27 DC A9 BC 9E 75 75 19 5D E7 FA 8E E7 C7 7A 37 E4 32 7B DA B5 02 73 8E EC BB BD A7 72 8E 78 AF 6F 8A DB 71 52 8C 7E C3 96 72 F5 F5 F6 BF 23 97 AA CB 5E CC AA 6E 34 6B E5 79 B3 3F 51 4E F5 6E 94 2D B6 72 3A C5 5F EF F5 CD 82 6A 70 F9 B2 AB 6D ED 7C FB EB 73 D7 5B DB 4B 6F 8F 7D 9C BD D1 1A B5 B3 E4 5B F5 89 A5 24 6D 0D C9 48 7D 0F 55 9E CB 0D 71 49 7D 9C C6 A9 BE DE D0 67 B0 7C 1B F5 9E 2F 9E 98 DC 21 D4 4B 90 75 8B 32 70 FA BC D4 ED 94 3E D6 79 EA 7C 4F D1 8E 99 EB 73 1F AA D9 0B 4D 27 AF A4 FA E5 D4 7D F2 3F 61 91 24 8E 90 6D A5 9D A6 3D E7 66 EA 69 37 E9 A0 4B DD 36 76 AA F4 53 AF 91 AC E5 A4 B0 8E 3F ED 5C 13 B6 E7 1C 5F 94 CF 58 8F 53 97 C6 89 4E 7D 5F C8 DA 92 76 AF 3C 7A CC 1C DA 77 F9 B3 11 F6 B2 3A D2 9E 31 F2 76 DD 2F F1 B4 5B F5 91 D4 22 61 82 DA 7A 67 E4 F5 7D 8F D4 70 3B 58 76 FB DF 66 B4 FF A2 DD 39 C3 56 D2 57 F2 CE 11 28 DF DA EE 87 15 74 80 F6 F8 F6 D2 F3 41 23 D9 18 8B F6 D5 71 46 2F 3A EB 1A A4 BD E4 2C C4 F3 74 86 9C 67 CF 78 B6 3C 9D B4 DC CB FA A0 7D 9F F1 FC DE C1 95 6B 97 E7 16 5A E7 FE AB F1 06 56 EE C8 9F 75 4F 6F 49 29 E3 8F 7A A0 8D 11 A5 7D E5 A4 7B C6 A4 F6 CE 91 25 47 97 55 5F 47 35 30 5D D6 37 80 72 9C 59 ED D2 96 5D 90 23 CE D0 AB E4 CA 6F 7B 7A 39 43 56 1E E8 6D 94 F6 4F A7 55 60 9E EF BD D4 9B 0C 71 9B E5 A2 9D AB B1 7E ED 5E B5 59 F7 6B AC 23 C3 0E 98 EF 2D 81 C5 32 6A EB 8C B6 6E 3D C8 36 F3 D4 91 1E 72 C6 AD A7 DA 7B 3E BF B5 93 D0 1D BB CC D6 92 B9 B5 2D 01 DD CE F8 B4 E7 B2 B6 95 2F 1B A7 E5 DD BA F1 FC B9 25 5C E2 0C 5A 78 84 44 90 F2 F1 0E 6F 71 AD 94 71 DC D7 1C F4 42 6F AC AB F4 3D 47 97 F7 58 3A C6 8B 24 6C D7 FB E5 83 AD C6 3C D1 16 C5 0F 7D B9 D4 EA 5C BE DA F2 61 77 74 F4 64 09 D6 8A 07 DA 7B F6 A5 A5 8C 76 9C A5 F8 3F 7E EE 0A 12 E4 1C F6 80 89 AE 43 BA BC 3D 6F 82 2D FA D6 F3 6A 43 66 19 72 D3 8B 74 95 EF AA B5 A7 28 F4 35 EE 37 A4 AE 41 CF 9F F6 D4 9A B4 5E FF 4C 72 6A 9C B8 FA C4 53 A2 6A FF 20 4F 5A 83 2F 53 1E E6 0E E4 69 F3 64 53 5B 5F 89 50 DE 3E CE 7F B7 2E C5 8D 3A 1E B0 CC B6 76 49 72 73 87 83 F6 8D F6 99 21 AF 94 29 CE 90 E5 5D 89 F6 92 BB CD E7 BA 37 65 58 16 FB E8 D4 AD E4 2C 91 B9 BD 6B 69 B1 76 B4 B7 E8 5C AE 73 A6 A2 27 DC 6D 72 6A 51 B7 EF 57 CC 37 DD AE A7 C9 0F 7A AD 44 BB CE D6 6B DB E9 3B 12 17 5A D8 8A DE 73 FC 81 AF D6 DE 43 F9 48 F1 FD BE AD F0 86 3F D8 A1 6C 52 CF A1 E4 73 DF 89 69 E3 0B 6D CB 0C F1 7C 73 66 F4 A8 87 05 E9 4C F3 A3 EE 10 59 BF CA 74 D7 1C 2D EB D3 37 68 1E 1C D0 7E 6D 9C 94 90 92 34 C2 7D CC 33 FD 74 D5 5A AC 9C 0E 32 F3 BB 5E 7F 16 4A 3B C5 03 30 DB 3E 34 66 BF 3F ED 5C 58 CF B8 E8 7B E6 7E DA 28 DD FA 31 CF A2 19 F2 E3 0D B2 98 54 9D 23 E3 84 CC 7E B9 3F A8 2D 37 4F 55 B8 BD 11 B5 4A 19 95 F6 CE 4F B8 D6 CF F8 02 D8 6C FB 43 AE 3B E3 DE 75 68 BB BE AB 32 D7 DA 07 DB A6 6D CF F5 E3 BD FD A0 77 E0 DF 92 FE 68 36 F9 36 5C F7 F5 B2 DC 5D B7 9E 41 7B 5C DF 3F F6 72 EE C6 F9 8D 8C 65 FD 60 7C F3 EF 7B AF 4C 7B 9F 7A F9 55 1F 14 6F 18 9A A0 95 D3 3E 34 CA DA 7D E2 D4 9D CA C8 BB 7D 6F 65 CD 34 3E 76 18 DD 39 D0 DE B6 84 BD 4A 53 AC F6 2D DF BB 39 6B F2 3D BE DC F2 7D 79 BE 47 A1 53 E4 FE 6E 7A D0 65 5F DC 7D DD 62 60 DB 9C 17 CE DD D5 03 1D D7 24 AD E4 78 D4 18 BD 2F 41 1F 1F D2 BE 35 7E EB A0 75 4B A4 A5 6D 83 8C 37 1C 83 3C 68 5A CE 4E 78 EE 7E B4 72 86 C0 85 66 8E 8F 48 CF FD 32 D7 B2 E4 7A 2E C2 28 25 AC ED B2 8C B4 2D 27 00 5B 3F CD E2 71 6E D0 5B FA F6 5F ED 97 48 FF 0B 2B 11 DF 67 07 5B 49 73 C2 62 DF FD 47 DF DE 58 78 F8 FE 7A 41 6D 25 DC 7E 1E 3C 65 53 8B C5 F0 13 B5 8B B7 AB 65 47 F1 07 CC B3 E5 44 87 F9 16 ED 0B 53 EB D1 7A 8C BE 1B 35 BE C3 F3 76 EA FF 3B CB FB 87 17 DA F1 1B 24 CE F3 D5 D6 37 E4 3E E8 DB DC 59 80 2C F6 DC 83 F5 3C 5F D7 81 AB FD F3 DD E3 8C 7E C7 2F EB FE 97 DA 01 49 D3 62 A1 E8 69 AC FB BC 2D DF EE B6 A1 75 CF 49 6E 76 FC 34 89 6E FD FE D3 82 E9 E0 7E 91 71 79 EE C2 B6 BF A7 FE 23 35 B5 5C B3 BF 47 5A 6F 35 FD C9 E4 D0 0F F5 3D CD F7 E0 E0 B8 A1 AB AC 6F 6E 22 C8 12 F1 FA DE 80 F6 39 F4 73 1B DD 8C 2F 80 07 58 5A B0 B5 9D 9B 18 67 7A 0F 39 E7 A9 A5 B4 F1 3E 18 6E F3 6D 46 6B 67 47 E4 7E 11 ED 85 2D D7 77 8E B4 DF 7A E7 C7 A0 3E AE AD 77 CA 20 73 05 E8 C7 9C EF 26 DA FA A5 21 A6 FF 66 91 F7 18 EA 75 B2 4E ED 3E 32 F0 15 E7 2D D7 F6 6B FB FF C4 EF 34 D8 01 E6 E9 80 8E 9C 1B B4 3B 43 7A AA 1F E6 AD CE 0F 78 F9 FE 7D 3A A2 F0 5C 19 9C 68 59 ED 77 F4 17 0C DA 7F FD 40 72 AC 45 C3 B9 7D 4B AF BD 6B 09 17 7B E5 E0 10 BD 3D 6E 79 03 65 77 23 F0 F8 7D 8C 73 3D 8B EB A5 8D 5B 6D D7 FF 85 35 86 E7 A5 FD DD F0 F5 5D 07 4F 29 E9 ED FC 83 EB FE F2 39 9E 4B 68 B1 1E 7D 8D D5 F6 7C A5 DC 66 49 E6 6F EC 6D 6F 4B A2 6A 09 CE D0 E5 16 AC C7 8E BF CB 2F BC 99 EF D5 F5 3D 7C B9 AB 20 F7 06 69 1F D1 FC 3D 8B 96 DF B5 D0 BE 6E E5 17 01 7D B4 86 F6 84 73 E5 DC A1 5D A1 56 F3 FB F1 76 F2 7E A2 13 D2 9E 73 CF FB 49 9A FF E6 8B AC 06 B9 72 BB 47 AE C2 B4 83 74 76 57 90 4C 77 7B D7 6B BC 33 92 EF E2 F4 AF D5 3F 34 F6 91 FC 2D 7B 2C FA 49 B7 C3 CC 7C 67 DE F2 1D A3 21 1D 7D FD BA A9 B3 A4 D6 BF FA 90 EB CA FB 74 DF 82 D3 DF FD E9 6D 2F D7 33 76 E3 24 60 BF 9F 46 3E B6 C8 FD B6 CF 60 D2 A9 06 37 3D 81 95 A9 F3 BC B1 C7 BB B6 83 DF 83 2F 8B CC 6C 63 37 DA EB DB 23 CF B2 5B D9 C9 6D 5D 5B B5 C8 1B B7 7E D1 4E 7B D4 D4 97 7C 6E 6B 7D DA 6E 89 D0 DC 4E BB C2 DB 2F CE 69 FB 5B D7 42 EE 1A C4 65 AF DD FD 97 62 3A B0 8F EE 11 6F 9D 07 BA 36 3D E8 3B 85 7B DB B7 6E A5 58 C6 B1 F3 DB F4 36 72 7E 87 DE B0 77 E4 AB A1 03 ED DD E1 D7 8C 6F 29 E9 7B 61 2A A1 D5 77 E2 D3 DC D3 50 78 AF C7 A9 A3 3B 5C 9E 74 F9 F6 84 3C 57 4F 52 6A 38 33 CE D8 6B 63 0C 0A E7 2F 7F E8 33 D4 B2 07 76 C2 90 41 2D BF 19 F2 8E EB 33 69 6A 63 B4 B8 EF FE 68 2F 79 FC CE F6 4E B7 2A F9 BB F6 AB B6 53 FF 4D 45 6D A8 0B 55 2B 6B 11 67 B9 3E F7 F0 B5 93 74 E6 D2 F3 B7 B0 5A 28 5E D5 EE 22 DF 67 FF 7A FB 9D 04 FA 96 5B 9E 82 F8 83 F1 2D 8E FC 15 96 43 5E CF D7 CB 13 0F 87 D1 17 76 A7 AC D0 7F 49 17 35 A5 DF 30 88 B6 CE 1F ED 19 7A EB 65 E4 A3 BD 65 C6 E8 7C 1A 61 4F EB 45 FF 8A 24 D7 47 25 FC 3C ED 25 A3 C5 5B 34 7C 3F A3 77 27 5B 5B 84 F6 1C A4 E6 0C A2 B7 33 27 48 17 36 53 FF BA 9F DA 91 ED 21 CF AE 38 F7 1C 2D 65 9A AB 72 FD A4 A4 60 6E BB 9E 48 67 9E BC 71 D9 07 F4 AC 08 FD 06 83 AF 5F DB 3C DD FA 9B 19 27 97 66 ED 3A FC 8D DC 0F 64 99 B5 AC DA BC 49 EB A1 5E 70 2D 1C 9C 26 89 F4 5F B4 1B 7F 6E D7 0F 50 83 76 FE 76 AD A5 4C 8B 64 6E 53 0F 9D DB 7B CD 0E F3 E4 56 EA B9 ED 07 9F 7B 79 ED B2 26 7F 7C 9B F3 87 FD CA F7 C7 BF 5C CE 05 9F D3 AF 4B 7F 9F F1 DF 81 DF D1 6D F9 1A B0 C3 23 CB D5 8E E9 70 FA 76 C9 56 AF B3 D0 DE C1 92 5C AF 3A 2F B8 0E FF 92 F0 F7 BE 5A 7D EF E6 F5 C4 71 EB 67 DB EC 2E 2D E4 EB 3C 82 EB E5 53 87 FC FF 79 75 44 C6 F8 3C EB FF 3F B9 43 F9 7D 2E CB AF A7 38 DF 30 EB BF D9 45 52 C1 EB 77 65 C6 BB CE A3 B0 2A 5D BF 10 91 FB 03 D2 7A 94 FB 1A 2D DF E1 B8 F7 4D EB EF AD AD A5 0D 6B F7 CC 6E ED 4B 16 39 4F 2C BF 46 D2 F6 17 16 E7 F4 95 41 3B BF 22 F1 9E E2 7F 60 C4 7D 9F DF 9A D0 BF 32 B4 AE FA DB FE 45 C8 76 5D 6D F4 54 B8 CF D8 B6 AE 05 CC F3 6D 97 79 CA EB C7 7F 0B D6 EE F3 64 EE D7 4F 37 92 7E E8 92 7F B8 FC FE D7 6C CF 1F E1 FA 2F FB AD 7A DA 4D B9 1A 81 9E B4 5A BF 9E 5C 7A 43 EF ED 17 CC B5 BD 34 D3 F5 FF 67 96 AD 95 7B C6 93 17 61 F6 B4 F3 B7 B8 0E 38 4F 1F F8 D8 9F F7 5E A6 1B C5 18 2F 5F 01 8C F1 91 A0 BD FF C5 A5 1D 57 DB DC FD 9F BF FE CB 6C 5D FA 1A FC 5F B4 A7 49 BF E8 44 7B 85 5F B4 FA 5B 73 FB 28 FE 06 7A B0 7E 1F 6A 9E 47 3D E8 46 6F 7E 8F D0 B2 B2 F3 F2 2B 3D 1E A5 F8 1A 8D 1D BC DA F1 C5 E2 B9 D8 48 1D 5E 45 7B FD D2 EE 7B 5A 67 EE BC 78 CD CF D7 2F 40 FC 7C FD D7 5F 3F DC DB 75 F3 44 C4 7F FB E5 B4 70 84 E5 F7 A7 BD EE 54 1A 67 30 24 BD EB 28 B7 EE A9 3B D7 52 6E 2D E9 F2 3B 2F 3E F9 39 97 BD 2F 97 2F C0 58 CB 2E 91 7C 0F FF 3D 77 5D FF E7 AE 9E 8C 67 3E C2 38 E3 EA 8B F2 BF 3C F3 07 B9 3C E5 A9 66 BE 9A F9 76 E6 C1 CC 63 F2 7F 3F AB 4F 20 4E CD DC 9C 79 6B E6 F6 CC 7B 65 FF 65 EE 00 DC 85 38 55 DD A3 BE A4 BE AC FE 41 B6 63 E6 F3 80 57 00 FB 09 04 53 10 8B DC D4 47 D4 57 90 FF 9F D4 77 59 57 C2 3E A2 3E 0E EC 93 EA 0B CC 46 D8 10 60 6D 4E DA C7 41 2B E3 FC 90 F3 1F 58 28 51 74 66 BD 33 DF CC 7C 2F B3 2E 73 3F DD 75 99 2B 33 1B 32 37 64 5E 9B 79 03 B8 DC 92 79 5B E6 2B 99 77 59 EE 1D 99 4D 99 8F 64 3E 89 34 CF B3 DE E0 E6 45 C0 2E 03 5E B4 80 B7 67 13 C0 4D 26 EC BD A1 67 DA 07 99 4F 3B F3 B1 03 83 36 CD 9C 0B 18 61 C0 5C 0B 78 7B D6 81 0D 7D 12 F0 3C 01 CF CC 02 4C 64 7C E8 C6 F6 41 E6 74 67 9E B1 C8 61 30 B0 AF 03 F6 1A F0 3A 81 18 EA 67 C1 BF 6E 81 BD 4E 10 D2 0C 1A 2A B9 C9 22 50 86 BE 0D FC D3 80 17 01 7E ED 84 7D 2D 65 B2 4B 30 56 E4 6F A1 F4 66 FD E1 0F 60 C3 B0 4E 18 C1 46 D2 7F 5B 1F 8D A7 2C 96 C7 86 B3 0B D9 1A 96 CD 1A D8 AF D9 72 76 23 DB C9 7E C1 1E 60 8F B1 ED EC 09 F6 25 42 5F 71 1B 3B CC FD 79 27 F6 2D 0F E2 C1 EC 0C 0F E5 09 EC 3B 9E C8 67 F1 1E 7C 0E 2F E4 E7 F3 62 BE 9A CF E6 6B 79 23 2F E3 D7 F2 07 78 3D 7F 04 F7 16 BE 97 3F CE 6F E6 4F E1 BE 95 3F CB F7 F1 DF F2 57 F9 7E 7E 2F 7F 9D BF C9 77 F2 B7 F9 DF 78 13 FF 07 EE 3D FC 43 DC 0F F1 43 FC 08 7F 98 9F C4 BD 97 7F C5 BF E1 8F F1 53 5C E3 4F 0A 45 F8 F3 17 45 27 11 C4 FF 28 42 45 18 7F 55 44 88 3E 7C BF 88 16 03 F9 7B 22 49 A4 F0 23 62 88 18 CE 3F 15 A3 C4 F9 FC 84 18 27 66 F0 2F C4 1C 31 87 FF 5B 64 8B 1C FE 9D 98 2F 16 F0 66 91 27 16 0A 26 F2 71 0B 51 24 96 20 DF 0A DC 81 A2 1A 77 90 58 2E 1A 44 B0 D8 80 3B 52 5C 27 6E 10 DD C5 CD E2 76 D1 5B 6C 17 BB 44 3F F1 A0 D8 2D 52 C5 C3 B8 33 C4 A3 B8 07 89 C7 C5 53 62 B0 78 46 3C 2B 86 89 97 C5 7E 31 42 BC 2E DE 42 D9 7F 13 EF 88 29 E2 3D DC D3 C4 01 DC D3 C5 FB E2 03 31 43 7C 88 7B 96 F8 58 7C 26 66 8B CF C5 17 E0 E6 24 EE 0B C5 37 E2 3B B1 48 34 E3 2E 54 98 02 CE 14 7F C5 5F 2C 56 3A 29 9D 44 A9 12 A4 04 89 32 25 4C 09 13 4B 94 CE 4A 67 B1 54 E9 AE 74 17 E5 4A 94 12 25 2A 94 3E 4A 1F 51 A9 D8 15 BB A8 52 FA 2A FD 44 B5 12 A7 C4 89 5A 25 41 49 10 75 CA 70 65 84 A8 57 46 29 A3 C4 72 65 AC 32 56 5C A6 8E 56 47 8B 15 EA 04 75 82 58 A9 6E 53 B7 89 CB D5 87 D4 DF 8B 55 EA DF D5 BF 8B B5 EA 27 EA 51 D1 A0 9E B0 D9 C4 3A C6 95 63 D0 22 5C 39 6A B8 2F 13 E6 20 64 55 24 EB 4B E1 93 E4 7E 4D EE 5B D2 65 F1 14 3E 0E 9A C3 6C 2C A5 DA 44 98 47 19 17 A5 12 23 EE 80 C6 E1 A2 5E D2 C0 7D 07 EE 67 DA 27 A0 A9 97 78 65 AD F6 04 B9 7F 22 77 1F B9 5F C0 DD A6 3D 07 77 AB 76 3D 72 2E C4 6A 90 2B 2B B4 F7 99 40 FE C7 91 FB 26 0A 1D 22 8E 04 B8 98 AC 26 23 95 E0 BD D8 58 1E 85 B1 2F 63 4F 02 DF 0D B8 BE 6C 0D 8F 63 F3 09 F7 3E E8 4E 38 E9 C2 99 00 47 FB C4 EF C1 89 00 57 37 22 3F 48 5D 65 8D F6 09 B8 00 9D 72 97 B6 4B D9 A1 5D 87 D0 56 6D 93 B2 0D B2 57 31 72 EE 89 9C 0E D2 D3 5E A4 3A 80 A7 3F D0 D3 CB 78 CA C6 D3 21 7A 7A 4B F2 80 A7 7D F4 F4 14 E2 BE C1 D3 7B 4C 31 39 E0 FD 59 1F 8A 3B 01 CA 7E 88 3B 8E E1 F0 AA 76 B7 78 1B F0 0F ED 34 E2 6A B4 C7 95 7A A6 2A AB B4 06 A6 A2 2D 3E 01 F5 13 46 99 07 80 F1 63 F1 BC 1F 4B 46 FA 0C 4A 6F 13 59 DA C3 A8 D7 01 B4 FC 16 71 3F 68 8F 6A DB 81 5D 08 CC B5 80 5F 02 6E 02 EC 44 6A 9B 98 A7 BD 2B 1C 80 06 C0 D5 80 6B B4 77 99 8D 3D AF 1D 54 66 6B CB 94 F9 DA 93 4A 0D 78 A8 D7 FE C8 6C 7C AD 76 33 42 07 D1 13 5B 64 BF 81 87 01 CC 0F 35 89 40 4D 82 C0 D9 61 94 74 C0 A8 C7 01 19 A3 7D C6 A3 B4 D3 88 79 10 31 EB 10 D3 07 31 DB 99 9F F2 01 72 3A 08 38 04 C0 18 52 03 B4 9B D5 4E DA CD CC 1F B9 F5 44 6E 3D B8 9D 25 20 DD 7E A4 5B 6E B4 E1 13 14 1B 8E 1C 35 6E D7 BE 40 EC 0B 88 FD 85 51 DE 33 88 7D 84 31 8E 95 96 88 04 74 07 F4 00 64 00 E4 37 A6 FE CA 1D DA 5A 65 3B D2 DC A9 3D 80 7E 7D 49 F9 9D F6 8C 72 37 9E EF D1 76 B3 00 E5 4B 94 75 12 F0 2F C0 57 80 53 80 D3 80 33 80 7F 6B FB 25 05 C6 A0 1C FF FF 02 7C 05 38 05 38 0D 38 03 F8 37 A4 6E 27 B4 CD 09 50 A9 A0 52 41 A5 82 4A 05 95 0A 2A 15 54 2A A8 54 16 88 FE BC 45 A9 C5 18 AA 67 19 68 87 91 68 87 91 68 87 91 68 83 91 68 83 91 6A 10 74 7D 08 51 5E A6 1D 41 AF 5F A5 AC C6 48 5F 8B 76 6F D0 3E 43 8A 6C A4 C8 46 8A 6C A4 C8 46 8A 6C 96 8E D2 E5 17 25 11 4C 01 A8 00 1B C0 0F E0 0F 08 00 74 02 04 D2 6F 8C 47 B0 60 40 08 20 14 10 06 08 07 74 06 C8 BB 0B A0 2B A0 1B 20 12 D0 9D FE 7B 6D 04 66 8F CA 16 00 6E D4 76 30 F9 3F 89 7E 03 D8 0C B8 09 B0 13 B3 73 17 E6 E9 03 E8 A1 07 01 4D 80 DD 80 3D 80 87 30 8B 1E 46 DC EF 01 8F 00 1E 05 EC 05 3C 06 78 1C F0 04 E0 49 C0 53 80 21 AC 37 46 4D 1F C0 79 80 68 80 7C 8F 16 03 18 0E 18 05 C8 02 C8 DF 5F 1B 0B 18 07 18 0F 98 00 28 03 2C 01 2C 05 94 03 2A 00 95 80 2A 40 35 E0 52 40 0D A0 16 50 07 90 92 67 19 60 39 E0 32 C0 0A C0 4A C0 E5 80 55 80 D5 80 35 80 B5 80 06 C0 15 80 75 80 2B 01 1B 30 C2 BF 44 5F 9C 04 FC 0B F0 15 E0 14 E0 34 E0 0C E0 DF DA 41 35 09 73 33 0D 90 01 FA 0B 18 C7 9C 14 72 5E 03 54 39 3F 01 7E 00 7F 40 00 A0 13 20 10 10 04 08 06 84 00 42 01 61 80 70 40 67 40 04 A0 0B A0 2B A0 1B 20 12 D0 1D D0 43 BB 85 F5 84 3F 1F F2 66 01 E0 46 6D 39 FA 67 39 FA 67 39 FA 67 39 FA 67 39 93 3B 1A BB B4 75 E8 9F 03 E8 9F 03 E8 9F 03 E8 9F 03 E8 9F 03 E8 9F 27 D0 3F EB D0 3F EB D0 3F EB D0 3F EB D0 3F EB D0 3F EB D0 3F EB D0 3F EB D0 3F EB D0 3F EB D8 D3 D0 07 CF 00 9E 05 3C A7 BD CC D7 6B EF F3 BF 68 C7 F8 FB 80 4F 00 C7 00 9F 01 CE 6A C7 84 0A 08 D0 8E 61 4C 96 61 6C 62 2E C2 16 89 82 3F 1A ED D1 93 E5 B2 45 78 BA 18 B7 9D E5 E3 8E 61 EB D9 55 D0 30 57 B3 46 58 2B 37 B2 9B A0 55 76 B2 5D 2C 19 B6 C8 F3 2C 95 BD C6 FE C9 C6 B3 CF 71 17 93 6D 52 42 B6 C9 65 B0 4D 7A B0 CB 79 2F C8 8B 5F F0 F3 F8 79 EC 1A 3E 80 27 B1 6B 79 0A 4F 61 37 F0 74 3E 88 DD C8 87 F0 89 6C 33 9F C1 0B D9 BD B0 59 4A D8 33 BC 94 2F 65 CF F1 0A 7E 1D 7B 89 DF C8 7F C3 3E E1 5B F9 56 76 8C 6F E3 77 B1 E3 FC 6E FE 00 FB 92 EF E6 BB 61 F5 C0 A2 61 FF 86 45 F2 14 6C 9F 97 F8 1F 38 E7 7F E2 AF 71 95 FF 19 B7 3F FF 0B 2C 9A 00 D8 33 7F 03 1F EF E2 0E E6 7F C7 1D 42 D6 4D 28 FF 98 1F E6 61 FC 53 DC 9D F9 09 FE 39 8F E0 5F C3 BA E9 0A DB 46 E3 91 B0 45 04 EF 2E 54 E1 C7 7B C0 16 09 E4 51 B0 6E 22 78 6F D1 55 74 E5 7D 60 8B 74 E7 E7 C1 D2 B1 73 BB E8 0F 7B A7 AF 48 81 BD 13 0F 2B 64 10 4F 10 63 C4 18 9E 28 26 8A 49 3C 09 76 C6 0C 9E 22 2E 11 97 F0 34 E1 10 85 3C 5D 94 8A 52 3E 58 54 89 2A 3E 44 D4 8A 3A 3E 54 AC 12 0D 7C 98 B8 52 5C C9 CF 17 8D A2 91 8F 86 9D 73 23 BF 40 6C 13 B7 F3 31 E2 21 F1 10 1F 27 F6 8A BD 7C 3C 6C 9B A7 F9 04 F1 AA 78 95 4F 12 6F 8B B7 F9 64 F1 0F F1 0F 3E 05 F6 CB C7 7C 2A 6C 98 CF F8 34 65 B6 32 9B 4F 57 E6 2B F3 F9 0C A5 46 A9 E1 33 95 7A 65 19 9F A5 5C A6 5C C6 E7 28 2B 95 95 7C AE B2 4A 59 CB B3 95 9B 94 9B F8 02 E5 B7 CA 6F 79 AE 72 87 72 07 CF 53 EE 51 EE E1 0B 95 1D CA 0E 7E A1 F2 81 72 90 2F 52 0E 29 87 F8 C5 CA 51 E5 28 BF 44 39 A6 1C E3 F9 CA E7 CA E7 DC A1 7C A9 7C C5 0B 94 53 CA 77 BC 44 69 56 9A F9 52 15 C2 87 97 AB 68 32 5E A1 E2 E2 95 AA 9F EA C7 AB D4 00 35 90 57 AB C1 6A 30 AF 55 43 D5 50 5E A7 26 AB C9 BC 9E 9D C0 BC DB 24 7F CD 1B F3 6E 13 E6 DD 26 CC BB 4D 98 77 9B 30 EF 36 61 DE 6D C2 BC DB 84 79 B7 09 F3 6E 13 E6 DD 26 CC BB 4D 98 77 9B 30 EF 36 61 DE 6D C2 BC DB 84 79 B7 09 F3 6E 13 E6 DD 26 FA 0F 56 91 80 EE 80 1E 5A 2A E6 DD 26 CC BB 4D 98 77 9B 30 66 BB 31 50 B0 DF 00 36 03 6E 02 EC C4 58 DE 05 ED FE 00 FC 07 01 4D 80 DD 80 3D 80 87 30 F7 1E 46 DC EF 01 8F 00 1E 05 EC 05 3C 06 78 1C F0 04 E0 49 C0 53 80 D7 40 BB 1F F0 67 C0 EB 80 37 00 7F 01 FC 15 F0 26 E0 2D C0 DB 80 BF 01 DE 05 BC 07 F8 3B 40 FE AF A2 7F 00 DE 07 7C 00 90 FF 89 F0 43 C0 47 80 43 80 8F 01 87 01 B0 A8 D8 A7 00 69 C5 1D 07 7C 06 F8 27 E0 04 E0 73 C0 17 80 2F 01 27 01 FF 02 7C 05 F8 1A F0 0D E0 5B C0 29 C0 69 C0 19 C0 77 80 B3 80 66 80 A6 1D E7 0C 00 F9 C7 21 FF 38 E4 1F 87 FC E3 90 7F 1C B2 8F 43 F6 71 C8 3E 1E 04 FB 25 58 DB C1 43 E0 87 C2 0F 03 84 03 3A 03 22 00 23 40 33 12 30 0A 70 3E 60 34 E0 02 C0 18 C0 58 C0 38 C0 78 C0 04 C0 44 C0 24 C0 64 C0 14 C0 54 C0 34 C0 74 C0 0C C0 4C C0 2C C0 6C C0 1C C0 5C 40 36 20 07 B0 00 B0 48 DB CF 2F 02 5C 0C B8 04 90 0F 70 00 0A 00 C5 AC 0F E4 47 1F BE 18 50 0A 28 03 2C D1 0E F2 A5 80 72 40 05 A0 12 50 05 A8 06 5C 0A A8 01 D4 02 EA 00 B0 9C F8 32 C0 72 C0 65 80 15 80 95 80 CB 01 AB 00 AB 51 FF 35 F0 D7 C2 6F 00 5C 01 58 07 B8 12 70 15 60 03 E0 6A C0 46 C0 2F 00 8D 80 6B 00 D7 02 7E 09 B8 0E 70 23 EA B0 09 F0 1B C0 66 C0 4D 80 2D 80 9B 01 5B 01 B7 00 6E 05 DC 06 D8 06 B8 1D 70 07 60 3B E0 4E C0 5D 80 DF 01 EE 06 DC 03 B8 17 70 1F 60 07 60 27 60 17 E0 7E C0 03 80 DD 28 6F 0F E0 11 ED 51 7E 42 7B 54 44 02 BA 03 7A 00 32 00 83 00 AF 6A F7 C2 92 BD 57 1C 66 15 E2 08 E0 13 C0 51 36 4B 7C CA DE 15 C7 D8 2C 58 33 03 60 CD 0C 80 35 33 00 D6 CC 00 58 33 03 C4 D6 B4 B1 A9 1F 31 96 36 39 6D EC 80 CD 6E 7E A3 F4 07 5C EF FA EC C5 EF 20 7D 72 B0 4E E7 51 EE AD 86 BF 5D F7 9D F1 F7 1A FE 03 86 FF B0 F4 93 23 92 61 71 26 9F 97 1C 31 E0 71 E9 A7 1E 4D A5 7D FF B4 77 D2 5E D6 FD 01 2E FE 80 67 3D F0 F4 CB 3B 03 DE 19 F0 BE 9B FF 17 6F F8 B4 99 A9 67 E0 E6 A4 CD 4C 5A E5 DB 1F F0 B1 F4 07 7C E1 FA EC E9 27 AD 33 9E 8F E9 F4 EE F9 0F F8 C6 F0 BF D3 7D 3D 3E 5E C4 07 30 16 1F 9A 36 33 BE 2B E1 D7 A7 35 12 7F DB D3 EE D5 FD F8 2D DE FC F8 5E CE 78 3B F9 0B D3 82 5D FD 78 3A 29 92 56 92 16 01 B7 46 DF 46 4B AB 49 2B 89 9F EF DD 4F 2B 37 9E 93 A4 1F 9F A1 A7 B3 D0 0D 33 FC D1 06 BD 19 3F 5E FA A9 6F A7 D2 DE 68 EA DB F1 53 A9 A4 1E 69 E7 11 9F B3 75 3F 6D 6C 5A 44 7C 81 F4 E3 E7 EB BE FE 1C BF C8 C4 BB F9 AF A6 51 BF A5 5F 9B 7E 83 EE C7 57 5A FD F8 52 0F 7C 9D E1 AF 34 DB 2F ED 81 B4 87 65 7B B5 E2 37 48 3F 7E 83 EB B3 A7 9F 3C 53 A7 F3 C8 EF 5A DD 77 C5 B7 4E 17 7F 97 1B FE 06 D7 F4 D2 8F BF 4D 8F 27 9F E8 E3 77 C4 37 A1 B6 8F A4 3D 9E F6 2C D5 CB F0 93 1B 93 AF A7 F8 27 E3 E9 DB 00 F8 CF BB F8 AF E8 F8 A4 3D 49 7B 75 3F FE 3D AB 1F FF A6 2B 3E FE A0 FE 1C 7F 44 F7 D3 FA A5 0D 74 F5 E3 E9 24 7B FC 49 FD 39 FE 94 EE 27 4C 4F C8 4A C8 4D B8 18 FE 60 EF 7E 7C 33 F9 AA 07 5D 20 F9 F1 09 91 86 DF 9B FC 70 B7 E7 F8 84 BE 86 9F E2 96 7E 84 E1 9B F9 4E 34 FC B9 E4 17 25 2C A1 76 DA 9C 7C AB EE 27 2C 73 F3 AB AD CF 69 43 D3 46 91 BF 39 2D 4D F7 13 D6 B9 FA 69 97 51 7D 57 79 C4 6F 34 FC EB 0C 9F 7E AB 20 8D A5 F9 E9 7E C2 56 37 FF 76 E9 67 A8 69 90 1B 19 E1 19 6A C2 5E C3 BF DB F5 39 ED 1B E3 79 97 F4 13 F6 78 D0 3F 6D D0 99 F8 17 A5 9F B2 21 19 F2 36 E5 86 94 0D 09 1F 19 FE 3E DD 1F 30 59 FA 09 07 5C 9F 11 FF B6 9B 6F A6 7B DD A0 FF A8 15 3A C3 4F B9 56 A7 F3 28 F7 A8 E1 9F D0 7D 67 FC 57 86 7F 46 F7 E5 30 82 BF 25 E5 36 D9 2E 29 5B 06 52 BB A5 AF 1C 48 72 6C 60 C4 C0 1E F4 5C 90 5E AA FB 03 FB 59 FD 81 E7 79 E0 69 5C A6 66 0D 4C 1B 38 D4 D3 1F 38 6A E0 58 8A DF 98 0C BD 93 B2 03 FE E3 BA 3F 70 B2 EB B3 13 3F 53 FA 03 F3 9D CF 39 DE FD E4 67 8D E7 85 06 BD 7B FE 25 86 5F 6E E0 29 1E 23 E2 3B 9D 9F 81 35 F2 39 6D FD 40 8C B3 94 27 4D 3F 63 62 06 9D 77 18 78 EB C0 35 86 BF DE F0 1B 0D FF 7A C3 DF 6C F8 F4 7D 4E EA B2 94 02 57 7F 20 E9 0B 2C 86 A0 6F 52 42 53 EF 4E 81 BE 49 DD 93 7A F7 C0 77 0C FF 01 D7 E7 D4 5D C6 F3 CB D2 1F F8 B0 99 CE 49 FF B8 E1 3F 6B A5 83 FF AA F4 19 5D 29 A1 E9 95 E9 24 97 07 FE 25 A5 AB EE 0F 7C 47 AF 6F 2A CD 97 81 EF 1B FE C7 03 E9 BB 9C 81 DF 25 8A C4 00 E9 0F FC 42 F7 8D E7 6F 4C BC AB 9F BA 35 95 E6 53 FA FC D4 4D BA 9F 48 BF 66 9E BE 21 31 D4 FA 9C D8 D5 2D 7E 7E A2 DD 25 DD B0 F4 5E E9 A3 D3 C7 A7 0F 4B 1C 6F F8 71 6E CF 49 D2 4F 6C 79 CE F0 EE A7 1C D4 E9 3C F2 1B AD FB AE F8 D6 E9 12 2B DD F0 53 AD E9 13 E7 27 CE 4E 2C 48 2C 85 BF 48 FA 26 7D 62 5D E2 4A 7D FE A4 E6 EA 7E 7A 83 3E 1F 52 27 92 7F 77 E2 B5 86 DF 60 F5 13 37 E8 F8 E4 2F 92 BF D1 FD C4 2D 56 3F F1 06 57 7C E2 6D FA 73 E2 5D BA 9F BA 31 9D E6 6F E2 8E C4 27 13 9F F7 E2 37 19 FE 23 BA 9F BA 2C 75 49 EA BA B4 1C F8 AB 74 3F F1 15 B7 E7 FD D2 4F 7C D3 83 EE 3D E3 D9 05 DF 3A 5D E2 67 6E F8 83 AE E9 13 8F 58 E9 D2 43 D3 69 9C A6 4E 4F 9D AB FB 89 A7 DC FC 93 2E CF 83 53 47 90 1F 9E AC 8F EB F0 D4 48 37 9F FE 2F 52 62 B3 7B 7C 92 6A 3C 1B 7E 12 D1 25 45 EA F9 25 45 26 85 BB F9 BD A5 9F D1 37 55 CA FF 94 8C BE 49 59 86 DF D7 F0 E3 A5 9F 34 C2 F5 D9 E2 9B F4 29 06 9D F9 3C D8 D5 4F 7D 51 8F F7 28 67 A2 11 6F E2 A7 1B FE 5C C3 CF 95 7E EA BE D4 D7 A9 3E FB 92 2E 26 FF E2 D4 22 DD 4F 5A 62 F8 45 6E BE 89 27 7D 6C AE 13 9C F6 7F 49 EA 57 BA 9F B4 CC E5 D9 D3 7E 27 FB 1B 2D 45 FA 38 A5 57 92 71 72 3B 6D 8D EE 27 19 BF 21 94 74 9D F5 D9 B4 53 D3 7A 24 E9 FA D9 B0 3B 9D 76 B4 69 9F 99 F6 97 B9 1E 31 EC 22 E4 73 BB E1 D3 B7 AC A6 1D 81 99 C2 0C 3C FD C7 1A D3 0E 43 E8 69 BD 1E A6 FD AC DB DD A6 FD 9C F4 62 D2 3E BD 5C DD BE 4B 7A 3D 89 7E 77 D3 F4 11 D2 E9 3E D2 EB D7 C2 BF AB 9F 74 22 E9 2B 97 7A 98 BE 1B FF 2D F6 8E E1 7B F0 AF FB E9 1B 8C D6 74 AE 27 92 CE 78 CB DF A4 77 B6 E3 D8 64 3F EB 3A D1 5C E7 A5 CD 4C EE A7 F7 57 B2 D1 8E C9 69 86 4F A7 DB 52 7A 25 9B 7C 8C 35 FC C9 46 BB CC 34 EC F2 EB 0D 3F 47 FA 88 37 FE 7B 5A 72 BE E1 1B FF 85 20 D9 38 1F 99 6C AC 81 92 C9 8E 4B 5E 93 BC DE 5A 5F D3 9E 36 ED 45 B3 5F 5A EC 2B D3 1E D3 7D D3 9E 41 4A E3 BB F2 E4 07 A4 EB 69 57 E8 76 01 62 48 9E A4 BC 92 32 5A A7 4F 5F 64 A4 33 7E 31 36 F9 65 EB 73 EA C6 94 F1 46 7E FA 3A C8 D4 13 A6 5C 37 EC A1 16 B9 93 4C EB 5A 53 1E 21 9F 8F E9 B9 6F 32 F4 6A 6A 8A 29 D7 CD 74 69 EB 93 C9 EE 70 B7 07 4C 7D 6D DA 0D 29 BD 52 EC E4 C7 A5 24 E9 7C A4 1C 49 39 99 02 D9 97 62 FC AF 47 D3 47 1C F8 73 D6 73 98 5E 4F B3 1E E9 5B 52 A6 1A CF F4 FB 68 29 F3 53 16 B9 D4 C3 2C AF 34 05 EB B9 94 3A D3 6F 19 6F 29 A4 D7 60 6F 36 58 ED 4E D3 6E 44 BE 77 E9 F6 53 4A 93 6E 3F A5 3C 22 7D C0 F3 46 BB 1B DF 50 A7 BC 69 F8 EF 19 F5 39 68 E8 6D AA 17 FC CF A4 8F F4 CD 7A BB 9A F2 59 97 E3 A6 FC 46 A8 B7 DE BE A9 F1 B2 7D 9D 7A C0 D4 B3 86 FE 30 FB CB 29 07 5B F4 56 B5 8B 5E 32 EC 21 D3 1E 31 ED 1A D3 0E 6B 91 BB A9 4F 5B E5 B4 53 DE 1A F2 A3 55 F9 69 CA 4B 73 5D E2 2E DF 4C 79 64 CA 11 B7 F5 B7 87 1C 74 97 1F E6 FA 89 66 2B E6 FB 4C F2 73 D2 8C 59 99 46 B3 11 F9 CB DD 20 99 8F F9 BF 14 59 5A BE 1E 6F EC 3F 18 EB 2C 53 6E 3B CB 35 F7 45 36 A7 5D AF FB 06 D5 E6 B4 5B BD F2 67 CA 39 53 0E BD 93 46 F3 C3 9C CF 69 64 6D A6 7D 61 CE 67 D3 0E 4F 9F 9F 6E 9C FC 4A 0F 20 D7 B0 07 CC F9 87 90 9D 9E A7 A6 1B 5F E2 A4 27 19 7E 86 4E A7 CF 83 F4 A9 66 FD D2 67 EB F9 3A 9F 5D C6 BD 39 DF 4C 3B CD 94 B3 CE 7D 8F 2D BA 5D 95 7E 57 FA 8E 74 FA 65 B6 01 33 0D 0A FD D7 C9 D9 80 1C C3 A7 96 4E 7F 32 FD F9 F4 57 D2 F7 A7 BF 99 FE 5E FA C1 F4 23 C0 18 67 3B 5B F5 3F 6B E3 F9 94 E1 37 EB ED 97 11 48 72 B0 6F 46 A4 3E 0E 33 7A 1B 3E D9 19 E0 23 5F A7 CF 30 E4 50 C6 60 B7 67 D3 CF 72 F3 BD E3 05 2B 66 9C FE 67 E7 48 36 0A FE 68 36 11 A1 C9 6C 11 1B 4F 6F C1 F2 58 3E 28 16 B2 C5 EC 05 84 5E 62 7F 62 4F D1 3B AF 17 E9 9D D7 61 F6 2F 6E 63 47 B8 3F EF C1 4E CB B7 5D 3C 48 BE ED E2 21 7C 00 4F E1 A1 F2 3D 17 8F E4 43 78 21 EF C9 8B F9 52 3E 99 57 F0 DF F0 59 F2 AD 16 BF 4C BE D5 E2 2B E4 5B 2D BE 56 BE D5 E2 1B F9 23 FC 45 FE 0B FE 0A DF C7 B7 F0 FD B8 6F E1 AF F3 B7 F9 AD FC 1D DC 77 F2 F7 70 DF C5 0F E0 FE 1D 7F 9F 1F 42 CA 23 FC 28 DF C5 8F F1 93 FC 41 FE 95 E8 C4 F7 8A 20 11 C2 F7 8B 30 D1 99 BF 21 BA 88 2E FC 4D D1 4D 9C C7 DF 12 31 62 00 FF 40 0C A4 B3 39 69 62 30 3F 2E 86 8A 49 FC 0B 31 4D CC 10 42 9E CD 11 36 91 8D DB 4F CC 13 79 C2 5F 5C 88 3B 58 5C 84 3B 44 BE C3 12 A1 F2 1D 16 F2 2D 16 25 22 42 2C 11 4B 45 57 51 21 AA 45 A4 7C 93 25 7A 89 E5 E2 5A D1 5B 5C 27 AE 17 19 E2 06 DC 43 C4 26 DC 43 C5 66 DC 99 62 8B B8 5D 0C 13 77 89 1D 62 8C B8 5F 3C 28 26 8B DD E2 61 94 FD 08 EE 59 F2 0D 97 98 2D 9E C2 3D 47 3C 87 7B AE 78 41 EC 03 2F AF 8A 37 C0 C5 5F 71 3B C4 5B E2 6D 51 20 DE 15 EF 89 22 71 40 1C 06 17 47 C5 31 94 FF 19 EE 5A F1 05 EE 3A 71 1A 77 BD F8 37 EE 65 E2 AC D0 C4 72 45 51 42 C4 4A 25 4C 89 13 57 29 F1 4A BC F8 AD 32 50 19 28 6E 53 92 94 64 B1 8D 4E E2 DC A1 8C 56 46 8B ED CA 7E E5 CF E2 4E F9 E6 4B FC 4E 39 A4 7C 22 EE 51 3E 57 BE 12 BB E4 7B 2E B1 47 BE E7 12 8F CA F7 5C 62 AF 7C CF 25 1E 93 EF B9 C4 E3 F2 3D 97 78 42 0D 50 7B 88 27 D5 24 35 49 BC A6 A6 A8 29 62 BF 9A A6 0E 12 7F 56 87 A8 43 C4 5F 99 E0 13 E9 3D AB 8D F5 C0 3D 8D F5 C4 6D 63 BD 59 0C 53 58 7F DC 09 6C 00 EE 04 8C BD E1 C0 8C C2 AD B0 2C 36 01 EE 24 DC 09 6C 3E 5B 80 18 F9 2E 36 81 95 B1 2B 81 DF 80 5B 61 D7 B0 5F 23 3F F9 46 F6 3C B6 85 ED 60 01 6C 27 EE 3C B6 0B 77 28 BB 1F 77 00 7B 80 ED 61 D1 EC 21 DC 0B D9 C3 18 B9 A1 EC 69 F6 1C 4B 64 CF 63 34 47 D0 68 8E C0 68 FE 1B F3 63 EF E0 F6 67 EF 62 44 FB B1 23 EC 13 84 8F B2 33 E0 FB DF B8 FD D9 77 18 E5 9C FB 71 3F E6 4F EF 77 39 0F E4 81 AC 1F 46 7B 10 1B CC 83 79 30 8B C2 98 0F 61 41 18 F3 11 08 77 E1 91 A0 EC CE BB B3 60 DE 03 73 C3 1F E3 BF 27 8B C3 0C E9 85 70 14 8F 42 B8 37 EF 83 B0 7C 37 1C C7 A3 79 34 C2 76 6E 47 38 86 C7 20 DC 97 F7 45 B8 1F EF 87 70 7F DE 9F 15 F2 38 1E 8F 70 02 4F 40 9E 03 F9 40 84 13 79 0A 4B E3 A9 3C 95 15 F3 34 9E C6 4A E8 BD 72 30 E6 DB 70 B8 23 F8 05 E0 33 8B 67 81 72 0C CF 41 78 1E 9F 07 FC 7C 3E 1F 98 05 7C 01 30 B9 FC 42 60 16 F1 02 D6 13 73 B4 10 F8 62 5E C6 E2 F9 12 BE 8A 75 E2 AB F9 6A D4 68 0D 5F 83 F0 5A 7E 25 C2 EB F9 7A 76 29 BF 8A 5F 87 F0 AF F8 0D 68 81 1B F9 AD C8 E7 36 FE 00 DC DD 7C 0F 5A 43 BE 99 EE CE 9F E1 CF B0 19 FC 05 FE 02 B3 63 4E BF C8 46 F1 3F F1 3F B1 74 39 AB 59 20 7F 83 BF 01 F7 2F FC 2F AC 2B FF 2B 7F 93 85 F3 B7 F8 5B 6C 36 E6 FA DB 6C A0 7C 6F CD FA 60 86 BF 8F D8 0F F8 07 48 F5 21 FF 90 CD E2 1F F1 43 48 75 84 1F 61 73 F9 27 FC 13 C4 7E CA 3F 65 73 30 FF 8F 21 7C 9C 1F 47 EC 67 FC 33 84 4F F0 13 E0 E1 0B FE 05 4A FF 8A 7F 05 FC D7 FC 1B 94 F2 2D FF 16 E1 53 FC 14 F0 A7 F9 69 70 75 96 9F 65 5D 21 01 14 16 88 81 AD 22 6C 13 7E 2C 1C 12 C0 9F 0D 14 01 22 00 98 4E 22 90 F5 81 34 08 61 99 90 00 61 CC 2E C2 85 3C 9F D5 59 74 66 E9 F2 BD 38 93 EF C5 7B B0 EE 90 03 51 C8 A7 B7 E8 0D 9A 3E E2 3C 36 0C 72 A7 1F 30 FD C5 00 E4 19 2F E2 41 99 28 92 90 73 B2 48 06 1E E6 21 F0 A9 22 15 E1 0C 31 08 39 0C 16 83 11 1E 2A 86 B1 41 62 B8 18 CE 92 C4 08 31 82 5D 2C 46 8A 31 28 71 AC 18 CB F2 C5 38 31 81 A9 62 A2 98 C8 7A 8B 49 62 12 C2 93 C5 0C C4 CE 14 33 59 2C E4 C9 6C 46 12 0D F8 B9 22 1B E1 1C 91 83 F0 3C 31 8F F5 97 27 0F 59 98 C8 15 B9 C0 E4 89 3C 96 2A 16 8A 85 2C 06 72 26 1F 94 0E E1 00 4D 81 28 40 3E 85 A2 90 C9 73 89 45 CC 21 A5 1E E8 17 8B C5 AC 9B 7C 8B CF 6A 45 99 28 63 E3 21 07 97 00 B3 54 2C 05 65 B9 28 67 05 F2 04 23 30 95 A2 12 A5 54 8B 6A E0 2F 15 97 22 B7 1A 51 83 70 AD A8 05 CF 75 A2 0E E1 65 62 19 2B 85 DC 5C 8E 9C 2F 13 2B 40 BF 52 AC 44 F8 72 71 39 68 56 8B 35 A0 69 10 0D E0 E7 0A B1 1E E1 AB C4 06 C4 5E 2D AE 06 66 A3 F8 05 E8 1B 45 23 F8 BF 46 5C 03 CC B5 E2 97 A8 C5 75 E2 3A 94 FE 2B 71 3D 1B 2D 7E 2D 7E 8D 30 64 31 72 BB 51 DC 88 1C 20 91 C1 C9 6F C4 66 84 6F 12 37 81 7E 8B D8 82 F0 CD E2 16 B4 F3 AD E2 36 E4 BF 4D 6C 03 FD 1D E2 0E 84 B7 8B 3B 11 7B 97 B8 07 E1 7B C5 0E 94 B8 53 EC 44 AA 5D 62 17 F0 F7 8B FB D1 02 0F 88 07 C1 43 93 68 02 CD 6E B1 1B 34 7B C4 1E 84 1F 12 0F A1 F4 87 C5 C3 A0 FC BD F8 3D AB 86 A4 7F 14 78 C8 7A E4 FF 98 78 0C E1 C7 C5 93 88 85 DC 07 E5 D3 E2 69 F0 F6 8C 78 01 98 17 C5 8B C0 BC 24 5E 02 CD CB E2 65 56 27 FE 20 F6 21 FC AA 78 95 0D 15 7F 16 7F 66 33 A1 19 DE 60 8B A4 6E 60 5D E4 79 08 E0 DF 15 EF B2 0B E5 39 4F 60 FE 21 FE C1 E6 8B F7 C5 FB 6C 81 F8 40 7C C0 46 8A 83 E2 20 CB 91 67 3E D9 74 F1 91 F8 88 CD 13 87 C4 21 96 0D 4D F2 09 CB 80 2E 39 CA 46 88 4F C5 A7 2C 17 5A E5 18 C2 D0 2B 48 F5 85 F8 12 B9 41 AF C0 85 5E 81 0B BD C2 BA 40 AF 28 2C 44 51 15 95 9D AF D8 14 1B 1B A7 F8 29 7E 2C 4B 9E 14 65 63 94 00 25 00 E1 4E 4A 27 D6 59 09 54 02 59 A5 12 A4 04 23 1C A2 84 B0 22 25 54 09 45 38 4C 09 43 AA 70 25 9C D5 C8 73 A4 C8 2D 42 89 60 8B 95 2E 4A 17 36 55 E9 AA 74 03 26 52 89 64 15 F2 7C 29 1B A0 F4 50 7A 00 D3 53 E9 C9 2E 51 7A 29 BD 80 89 52 A2 D8 24 A5 B7 D2 1B 3C F4 51 CE 63 13 94 68 25 06 F8 BE 4A 5F 50 C6 2A B1 88 ED A7 F4 43 B8 BF D2 1F 5C C5 29 03 50 6E 82 92 00 37 51 49 04 3E 59 49 81 9B AA A4 02 33 4C 19 86 72 87 2B C3 81 19 A9 8C 84 7B BE 72 3E F0 93 94 49 70 A1 1D D9 44 A9 1D 59 5F E5 43 E5 23 76 81 3C 1D 82 F0 C7 CA 61 36 56 39 A2 1C 61 65 CA 27 CA 27 6C 89 3C 23 C2 CA 95 2F 94 2F D8 45 F2 A4 08 8B 84 06 FD 37 DC B3 CA 59 D6 4B D1 14 8D F5 52 B9 CA E1 A2 F9 E0 DA 54 1B 5C 7F D5 1F 6E 80 DA 89 F5 55 03 D5 40 36 44 0D 52 83 D8 14 79 76 04 E1 10 35 04 E1 50 35 14 E1 30 35 8C 25 AB E1 6A 38 4B 51 3B AB 9D 11 8E 50 23 10 EE A2 76 65 93 D5 6E 6A 37 60 22 D5 48 60 BA AB DD 11 EE A1 F6 40 18 BA 99 29 6A AA 9A CA FC A1 9B D3 10 4E 57 D3 D9 52 15 E6 26 C2 83 D4 41 AC 0A 7A 7A B2 53 4F F7 84 EE 94 A7 A2 26 91 9E EE C3 FA 42 43 73 16 CF 86 01 2F F5 74 1F D8 88 23 11 96 DA 9A D3 C9 A9 A9 A4 B3 ED B0 1E 27 42 5F 4E 66 53 E0 4E C5 7D 01 34 FE 3C 84 A5 16 BF 80 E5 42 0F 67 B1 0B 61 5D 0E 22 EB 72 10 E9 F5 41 CC 01 1B D3 1F 36 66 29 DC 32 56 8F 3C 97 B1 CB 51 EA 2A B6 0E E1 2B 71 07 B0 F5 B8 2F 66 57 E1 2E 22 0B 80 D3 99 AC C1 B0 03 6E 00 D7 D2 0E 48 86 1D B0 8D 05 B1 DB D9 EF 58 2C BB 1B 36 41 10 D9 04 C5 64 13 44 90 4D 10 44 36 41 0A D9 04 25 64 13 44 90 4D 30 84 6C 82 6E 64 13 74 83 4D 70 08 76 C0 C7 B0 06 54 B2 06 14 58 03 FF 84 AD 22 6D DE 0A F6 2F DC D5 74 DA 4B 25 6B 40 25 6B 20 8D AC 81 4B C9 1A 88 23 6B A0 13 59 03 71 B0 06 BA B1 2E B0 88 07 B2 61 D0 D9 49 6C 3C 4F E6 C9 AC 8E CE 82 8D 27 9D DD 85 74 76 17 E8 EC 89 4C E1 93 F8 74 E8 E0 19 3C 1B E1 1C 68 6E 15 9A 7B 3E C2 52 5B 0F 27 6D 7D 1E 69 6B 85 4E 8D 8D E0 8B F9 62 B6 9A 97 42 73 8F E0 35 7C 39 34 A8 D4 DC BA CE EE 44 3A BB 81 74 76 27 D2 D9 69 FC 1E 7E 2F D2 4A 3D DD 9B 3F CA F7 B2 68 3A 47 16 C3 9F E6 4F 43 23 4A CD DD 99 3F CB 9F 67 89 A4 BF C3 48 7F 47 C3 2A 7F 05 F8 3F F2 7D C0 E8 5A FC 75 FE 3A 9B 42 BA 3C 9D 74 79 12 E9 F2 9E A4 CB 17 92 2E CF 90 96 3B 52 C1 72 87 0B CB 9D F5 80 5E 3F 08 57 6A F4 3C 68 F4 8F 90 F6 90 53 AF 2F 22 BD 3E 0A 56 FD 51 60 A4 5E 1F 65 D1 EB 3D F8 3F F9 3F 41 7F 82 7F 0E CE BF E0 5F 82 93 93 FC 24 9B 66 D1 F1 49 A4 E3 43 49 C7 87 91 8E 8F E6 67 A0 E3 C3 78 33 6F 06 0F 1A D7 20 EB E5 E7 2B 3D 04 17 9C 75 96 E7 DD A0 71 15 58 00 E9 64 01 24 91 05 D0 93 2C 80 0C 58 00 90 62 58 55 04 81 5E 5A 00 81 64 01 84 91 05 70 11 59 00 9D E5 3A 03 6E 37 D1 0D 6E A4 E8 0E F9 DE 43 F4 64 89 16 6B 20 8C AC 81 68 8B 35 D0 13 6B 91 81 D0 25 D2 1A C8 B0 58 03 3D B1 3A 49 43 59 E9 22 9D 4D 21 9B A0 B7 C5 26 18 4D 36 41 57 B2 09 96 C0 26 18 C9 A6 89 51 22 8B 0D 90 27 EF 58 14 D9 07 C1 64 1F 08 B2 0F 42 C8 3E 98 88 95 C6 34 E0 A7 C3 4A 08 21 CB 40 C8 B5 0E 5C 69 13 8C 25 9B 20 94 6C 02 41 36 C1 38 B9 FA 61 B4 FA 81 8B D5 0F 72 C6 EA 07 AE B4 03 04 69 FD AE 86 D6 97 FA BE 2B E9 FB 50 79 B2 0F 34 BA D6 C7 AA 08 65 49 ED 2E A0 DD 57 22 56 EA F5 60 B1 4A AC 02 3F AB A1 D7 43 A0 D7 AF 00 66 9D 58 07 1E AE 14 57 22 ED 7A 68 FA 60 D2 F4 82 34 FD 58 D2 F4 A1 A4 E9 43 A0 E9 AF 45 AC D4 F1 5D 49 C7 0B D2 EE 21 A4 D7 83 E5 4A 0B AE D4 E8 C1 D0 E8 5B 41 73 0B 34 BA 20 8D 1E 82 F5 D7 ED 28 57 EA 72 41 BA 3C 94 F4 F7 00 D2 DF E3 48 73 87 92 E6 EE 4A 9A 3B CA D0 DC 58 9F C1 95 3A 3B 84 F4 74 88 5C 9F 21 FF 17 A0 A7 83 A1 A7 5F 42 AC D4 D0 57 40 43 FF 11 69 F7 41 4F 0B D2 D3 23 C5 6B E2 35 68 DF FD 62 3F B4 B2 D4 D9 B9 E2 75 F1 3A 3B 9F 34 F7 62 D2 DC 91 58 D5 BD C5 26 93 FE 1E 49 FA FB 7C D2 DF 91 F2 3B 0D 58 5D 52 8B 17 90 16 2F 24 2D 3E 86 B4 F8 25 A4 C5 27 93 16 CF 27 2D 3E 5D 9E 82 44 0E 87 C5 61 E4 20 75 79 24 E9 F2 31 A4 CB A7 93 2E 1F 23 D7 88 C0 4B 5D 1E 49 BA 3C 92 74 79 24 E9 F2 52 D2 E5 4B 49 97 CF 26 5D 5E 45 BA 3C 9C 74 F9 7C D2 E5 33 49 97 AF 91 5F 80 B0 39 4A 30 34 7A 0D 69 F4 5A D2 E5 B3 49 97 CF 27 5D 1E 4E BA BC 9E 74 79 38 74 79 57 B6 52 E9 06 8D 3E 83 34 FA 2A D2 E8 09 A4 D1 C3 49 A3 97 93 46 5F 46 1A 3D 81 34 FA 1C D2 E8 73 49 A3 27 90 46 0F 27 8D 9E 00 8D DE 1F E1 38 25 0E FC 60 45 8B 3C B1 A2 05 06 2B 5A B8 58 D1 C2 C5 8A 16 AE D4 D9 D9 A4 B3 53 49 5B A7 92 B6 9E 45 DA 7A 39 69 EB CB 48 5B 5F 4E DA BA 8C B4 75 2F D2 D6 BD 94 EF 94 EF 58 3F B9 EA 65 FD E4 AA 17 2E 44 03 5C 5C 70 B1 EA 85 2B B5 75 2A 69 EB 09 A4 AD E7 91 B6 9E 40 DA 7A 1E 69 EB 09 A4 AD 87 92 B6 CE 24 6D 3D 94 B4 75 26 69 EB 1C D2 D6 43 49 5B 67 92 B6 1E 4A DA 3A 93 B4 35 97 2B 69 43 5B 73 D2 D6 2B 48 5B 73 D2 D6 6B E5 DA 9A 55 42 07 7E A9 EE 91 DF ED 35 6F 85 CB 9A B1 62 15 AC 79 3D B9 D0 9C DA 3A 65 BF 0C DB C6 32 11 74 6D D0 0D 41 5B 82 30 23 82 D6 05 6D 0C DA 1A 74 3B 42 97 05 AD 09 BA 35 68 3B 42 95 41 75 41 B7 05 C9 AF F9 90 0F 01 93 29 75 D7 56 88 D5 9D 66 CB 23 F7 4F E4 0E 27 7C 20 B9 11 70 B9 ED 8F 12 EF 77 8B C4 F8 BD 40 EE D7 E4 6E 21 B7 84 62 97 51 5A 4A E5 77 07 85 F5 9C B3 28 9F 49 E4 E6 49 97 F8 E6 EA 74 8A 1D 4B 6E 86 74 09 5F CC C2 E1 C6 FA BF 2F 5D AA 73 2C 95 18 EB 77 35 B9 25 E4 A2 74 FE B9 FF BD 14 06 0F 8A 46 34 D7 C8 76 11 F7 51 F8 3E C9 83 58 47 E1 75 54 D3 75 B2 2C 91 40 39 27 50 EC 60 CA 3F 81 72 4E A0 5A C8 DF D8 E4 FC 98 A4 64 7F 61 11 84 97 75 DC 45 ED BE 8B 52 6D 96 79 B2 53 32 CC 4E C9 1C 10 BE 9A DC 12 72 41 CF 7F 41 E5 CE 96 A9 80 21 FE 29 87 34 E2 E1 3A 0A DF 46 F8 DB 28 FF BB 09 BF 8B 78 DB 45 5C ED 22 AE 76 51 7D 77 49 4A F5 4F C4 CF 2E AA AF DC 7F 87 2B 53 F9 1D 25 FC 52 AA E3 70 CA 73 29 E5 3F 9C F2 EC 41 6D D2 95 F0 3D 08 DF 43 E6 CF 9F 91 18 7E 9B 8C E5 CF 10 7E 35 F5 EF 1A 2A 7D 35 95 BE 83 C2 6B 29 9F B5 94 C3 5A 1D 4F 65 AD 25 CE 57 13 7E 35 F1 B9 9A 28 57 D3 D8 58 43 34 AB 25 8D FA 86 C4 2B 13 88 4F 3B E1 ED 84 19 27 4B 84 2B 39 39 4D 5C 9D A1 F0 19 59 0A DC 12 72 65 7B 1E 26 FC 61 1A 57 4B FD 5E 23 F7 76 E9 52 AA A5 14 BB D4 AF 98 DC 2D 34 A2 64 8D 6C FA 38 24 F7 4B A2 D4 6C D7 91 7B 3E B9 43 C8 FD 06 EE 37 FE 51 14 2E 02 3F 5D 6C BF 44 DA 70 AA 4B 28 71 1B 0A D9 C2 F9 A7 D4 56 27 6D 37 90 8B D1 2E 42 A8 16 4F 12 65 2A 51 A6 12 E5 B7 B6 2B E1 9E 25 0E BF D5 5D DB A5 12 43 3C 7C 6B 1B 45 EE 10 72 E5 1C 39 2C BF E9 E1 FB 94 CF A4 6B 5B 4E EE 15 70 FF 48 EE 1F 6C 5D A4 DB FC 6B C2 83 43 11 E0 F7 37 8C AB 23 B2 14 F6 11 8D C0 4F 6D 7D 09 33 84 DC 4B C9 2D 94 EE D9 C3 14 FE 25 95 BE 5E BA DA 77 70 DF C2 8A 85 B3 63 32 1F 9E 48 F8 44 92 0C C7 6C 63 10 9E 4D 35 9A 23 BF 32 12 41 34 36 C2 64 BB C1 95 A5 DB 64 B9 22 50 D6 4B A8 E4 DA 68 9C D8 64 BD E0 FE 92 5C 70 22 84 F2 0F E9 52 CB 08 5B 0D DA EA 90 9C E3 CA 6F 69 24 D8 24 87 4A 16 8D E4 2C 6A B7 5A 99 96 1D 26 7E 6A A9 4D 1E A5 36 DF 47 FC FF 95 F0 7F A5 36 AC A6 79 3A A4 59 B6 73 35 E1 E3 29 87 5B 6D D7 22 67 7F DB 2A 72 0B 64 5B 11 6F FE B6 C1 E4 26 93 FB 4F 72 2F 84 7B 97 6D 09 B9 92 E7 DF 35 6B C8 61 27 F5 CE 4E EA 97 6D 54 EE 2D 54 D6 36 5B 35 B5 40 83 74 FD 7E 4B 73 4A BA A1 E4 86 51 29 61 B6 46 72 D3 C9 3D 89 54 47 FD 36 52 38 1F 75 1C 6E 5B 49 61 DD D5 73 BB 08 34 07 68 06 25 18 AE 9C 11 49 D4 FE F7 12 66 B3 DF 73 70 7B 52 38 88 F0 8C 30 9F E8 B3 9B DA B6 2B 85 EB 49 96 BE 49 DC 1E 21 4C 5F 8A ED 4B A3 34 87 30 0A 49 83 40 C2 24 53 EC D7 14 4E A2 3C F5 7E 8F A5 70 2C 71 32 99 7A 47 B3 8D 83 9C E1 86 3C 94 B1 BF 21 CA DF F8 6D A5 B4 5B 69 3C 48 77 93 9C 83 70 B7 92 A4 92 F2 E4 1E 0A D7 93 1B 44 B1 41 46 98 24 24 85 3F 91 2E FB 8A 38 7F 87 72 BE 87 78 BB 87 78 1B 4B 3C 8C D3 35 85 1C 93 BC 9C C6 46 39 F5 CE B7 14 FE 56 0F 53 6F A6 CB BE 83 84 C9 A3 DC 24 7E 27 D1 DC 4F DA 47 91 61 51 27 C7 21 FF 2B 95 B8 4F F9 56 F6 94 C4 B3 8F 68 16 1C 91 DF D9 F1 3E B2 BE 08 4B 7A 85 F8 51 88 9F 3B 89 9F FB E5 0C E2 4F 53 CE CF D1 28 FD A3 FC 1A 8F BF 43 98 BF 11 9F 7F 87 35 C2 61 AB C9 B4 2F 52 3E 01 54 3B CA 41 DC 46 5F F2 4D A7 56 DD 2E 47 2C 3F 65 93 12 EF 4B E2 4A B3 2D 45 6C 94 8C 55 BA 52 89 5D 28 E7 EF 6C B2 0D EF 96 78 7E 44 79 43 4A 0F 59 6B 7E 3E 95 75 97 AD 4C F2 43 39 FC D1 56 0E 4C 1F 9A 89 7D A8 65 6C BA 4B F3 DA 46 F9 1F A6 F0 CD 94 DB 51 CA 67 27 C9 A5 9D 44 F9 3B 66 A3 F0 2F A9 EE C0 A8 DD 88 F3 3A A9 D3 D5 49 94 6A 9B 3E 3B A8 76 21 14 1B 02 8B 0B 35 A2 F0 5D 84 0F 27 37 4C DA 31 22 4C CE 53 E1 4F 34 C1 D4 23 01 44 E9 6F C3 AA 5F 39 21 F1 FC 2C E5 F9 16 B5 55 18 7D EB 48 5A 43 B1 53 1F 1D D6 FB 88 B8 ED 4E AD 17 A6 7C 4D 6D 9B 47 73 6A 31 28 CF 27 FA E1 24 13 86 52 6E BF D0 C7 36 B9 14 2B CE A7 11 75 40 B7 0A 28 FC 21 51 1E 26 CC 66 B2 01 4E 51 78 36 D1 F7 24 9A 67 88 E6 19 0A 9F A1 58 3F 8A F5 D3 F3 97 61 35 88 B8 1A 4C 3C 4C A1 F0 66 E2 39 D4 66 97 79 52 F8 94 9C 1D 7C 08 B5 E1 19 9A 29 9B 28 CF E3 94 FF 71 CA 4D 10 E6 B4 2E 3F 89 66 17 85 77 49 BC 8D 6C 09 E5 22 CA 3F 89 F0 BA DC B8 8F DC 8F 09 F3 31 85 AF A1 F0 7D B0 FC A1 1F 29 CF 13 84 99 CE BA 92 C6 44 BF F0 D7 49 56 87 51 0B 7F 42 23 ED 5E E2 E4 5E EA 3B 1B B9 34 02 C5 E7 3A 0D 8D 90 2E FA 88 A2 9A 1E 26 FB ED 7A E2 E7 73 CA BF 0F CD C4 20 3D 4C 79 D2 5C E0 27 49 FB 1C 24 DD 74 50 91 5F 69 87 13 4D B8 F2 21 DC 19 14 BE 4E 9F 23 7A 3B 53 AA B3 A4 3B 98 26 BF 7B 65 EA 0A A4 7D 5A BA DA 6F 65 AB 8A 26 A2 6F A2 96 19 2C 5D F5 CF C4 89 3E 62 BB 51 DA 6F C8 6D 92 F8 E6 45 7E 48 DB 7C A1 74 B5 57 A5 2E D0 FE 46 32 9F EC 28 B4 89 B4 40 FE 28 DB 07 2D 0F 1A 11 E5 B7 46 B6 0F E5 16 26 2D 64 65 01 B5 DE 09 29 0F 9B B3 A5 E5 D6 9C 23 5D 1E 41 39 44 50 EF 4C A7 96 99 4E E1 5E B2 BE 58 0D C9 AF CF 7B 1B E3 59 7E CF 5B 4C E1 58 A9 79 11 0A 64 AB D8 79 4C 19 3F 71 7A 0E 1F 5C B8 A2 A6 9C 0F 2B 77 D4 55 F2 99 2C 85 57 F2 65 A2 51 BE B3 E1 1B F8 75 B8 37 F3 DB 9C F7 DD F4 AE F5 11 FE 34 7F 99 EF E7 6F CB 37 2C FC 08 6F E6 27 F8 37 BC 59 2C 13 7E B8 1B 44 A8 88 14 E7 89 38 91 22 86 8A D1 62 A2 98 29 E6 8B 8B 45 09 56 F8 76 87 A3 BC 4E 1C 28 74 D4 16 8B 11 85 85 15 D5 E2 33 E9 2A AC A8 BC 6C B1 C8 2A AA AC AA 10 13 4B 6A 1C 85 E2 1B 20 1C 62 7A 79 65 7D 85 98 5B 5E 55 58 2E 72 C9 BD 98 DC 22 72 97 90 5B 4D EE 32 72 57 91 BB 8E DC 8D E4 5E 47 EE 26 64 53 23 B6 56 C9 DC 6E AF AA 29 AA 14 1F 57 CB F0 DD B5 65 95 25 62 57 6D 6D 5A BA D8 03 37 43 EC 85 3B 48 3C 5D 5B 5F 50 2B 5E AC AD AF AE 15 FB EA 24 E5 EB 2B 8B 6B AA B0 CE 9E CA 98 98 C8 94 B1 93 E6 DA 45 5D F6 DC B1 76 71 D7 BC 69 08 BF A9 EC 62 01 63 16 4E B0 2B EF 8D 1B 93 63 57 03 C7 CD 85 3B 62 DA 98 85 76 75 C9 8C 59 D3 ED EA D6 B9 B3 66 D8 D5 7D 39 32 F6 4C CE DC 69 76 DB 40 7D A5 E4 7F 1B 23 C9 EF 3F 4A 7F 86 E5 AB CF F6 63 C6 F3 ED F4 5B 37 1C 6B 67 FD 79 B3 EE 2B FD 0C BA EF E8 D7 67 B8 78 DE E9 53 BC B4 13 E8 F9 88 E1 17 19 7E 81 E1 E7 1B FE C5 86 BF C8 F0 17 1A 7E AE E1 EF 33 F2 AD 31 9E 27 1A F9 CF 37 FC 1D 86 5F 67 F8 07 40 1F 00 BA A9 4E 5F 4F 57 AA FB F2 57 5C A4 EF A7 AF 12 A1 6D A8 1E 42 3D 0F 2B 55 3D 34 4C 9D 4A 21 55 9D AB 6E 54 8B D4 65 24 CD 06 90 1B 4F 6E 2F 72 13 C8 25 79 48 BF 0E C4 59 17 72 69 A6 B3 40 72 49 32 D0 EF 53 72 FA 65 1E 4E BF F3 CA D9 FF 2B ED DA 83 B3 2A AE F8 39 7B 36 09 A9 C8 23 A4 69 4B DB F8 55 D1 3F 20 7E C5 08 24 4D 2C D3 A9 4E 5B 35 F2 08 04 75 40 1D 02 21 F9 4A 9A 84 7C 5F 08 20 88 D4 16 95 47 48 78 24 BC 34 88 88 40 EB 0B 02 A3 11 7C 86 F0 8C A5 34 A0 96 52 6B 2D 3A D3 76 C6 8E F5 0F 44 4A FA 3B E7 5E 6A 3A 25 75 A2 C9 DC DF DD DD 9C DD FB D8 B3 67 CF 3E EE 2F 7D 0D AD 37 21 EB FB 8C 03 8F 8D BF 95 8D 7F 30 F8 B6 97 29 F0 5A CD FA D9 E6 39 A6 0C 43 F3 8B E8 6A 43 DD 6B 63 B5 64 E7 08 A9 57 24 CA 47 43 7D 2C A4 BC 0D CA 20 EB C3 34 A4 76 75 85 D7 75 48 4D C2 F3 A6 20 35 1D 77 97 81 EB EA 0C FA E0 30 57 A6 FD 47 86 AE F0 BE BB 4B 7F A5 97 F2 03 7A 29 3F A8 47 79 4E 4E D6 91 7E D2 DF 0D DB 20 AF B8 14 E9 43 09 7D 7E F2 10 9D 83 4F CE 24 8C C8 93 F4 5B 79 4E 4E A3 F1 40 D7 85 91 50 52 A7 E1 5B A8 1B D3 9E A4 67 89 53 9F C6 19 A3 9E D4 9D 38 63 1C 90 FA 52 A0 C1 A9 B0 A6 DA 6B A7 B6 E3 DC A2 79 C9 25 B5 24 B5 22 74 1C A1 F9 F0 95 5D D2 31 72 6E A4 6B 47 E8 0D 12 B9 53 7F 11 3E 8A 27 A9 A7 26 9E CA 31 C4 A0 C5 DC C2 BB F5 E8 F6 EE E5 0B BF FB D4 5E CA 5F D6 4B F9 BE BD 94 BF BC 97 F2 FD 7A 29 DF BF 97 F2 03 7B 29 9F D6 A3 BC C0 66 0C 86 BD 3B 1A B6 AF 4C 4B C9 44 4A 6B 98 62 32 02 CD 91 F3 61 CA 77 2C 65 93 B1 5A 7C 96 42 21 CB C5 39 4B 11 93 C9 B2 83 BA A5 A8 C7 3C 38 4C F1 61 AE BD E4 A4 53 DA C2 34 E7 95 47 42 D7 7B DA 68 3F B5 D3 01 3A 48 87 FC 59 3A 4C 47 E8 28 7A BD 1C 97 8B A2 58 1C 24 AF A4 41 3A 0B EF 46 B8 DD BA 82 EB 9E 77 2F B8 56 F7 A2 DB AB 5F A4 1B DB CE AB EE 35 F7 BA 6B C3 15 1E A5 74 A9 90 4A A9 92 59 52 2D 71 49 E8 F7 E7 52 2B 73 64 AE CC 93 7B 65 BE 2C 90 FB 64 A1 DC 2F 8B 20 7D 3F A4 97 C9 72 A9 93 15 52 2F 0D B2 52 56 C9 6A 59 D3 83 F4 12 CA 94 9F CB 03 F2 0B F9 A5 2C 96 07 E5 21 79 58 96 C8 52 19 2B E3 64 BC 14 CA 04 99 28 45 32 49 6E 97 3B 2E 55 2A 9E E4 38 5D 75 C9 BB BB 54 09 67 E5 13 39 27 9F 7A E7 C5 7B 9F E4 93 7D 8A FF AA CF F0 5F F3 5F F7 2D 28 6B 3A 5D C5 AB 78 35 AF 81 7F D1 C4 6B FD 27 BC 8E D7 F3 06 DE C8 8F F8 73 F0 34 9A 79 13 3F E6 3F E5 CD FC 38 6F E1 27 E0 77 3C C9 DB 78 3B EF E0 5F F1 AF F9 29 7E DA 1D 70 07 DD 21 F4 4D EC 8B 69 A8 FB AB FB 87 4F C6 DD 2C 96 46 D9 2A 7B A4 5D 4E CA FB F0 C5 2A 24 57 46 CB 4D 72 0B EE 71 92 4C 91 62 29 53 7E 22 71 D2 47 FA 49 3A 3C A5 88 5C 23 59 92 FD BF 72 B8 CB A1 14 E7 96 9E EA 19 76 44 AD CB 97 78 06 FE 16 EC 11 AC 53 A8 1F A3 5C 2E 9E 6A FF E7 E8 49 BB 6B 0B 9E 3C D0 30 D8 BA 46 69 92 B5 B2 4E D6 CB 06 D9 28 8F C8 A3 D2 2C 3B FE 6F 0D AC F1 8D BE C9 AF F5 EB FC 7A BF C1 6F 44 8D C0 8A 73 86 A2 CB 53 94 0F F1 5E 33 82 56 66 73 C9 3A F3 C3 7E 17 DE C9 4D BE 10 21 F8 08 5E 67 22 85 33 78 88 A6 23 CF 1C E8 99 F6 7E EC 97 F8 06 6D 4D 9E 70 D5 BE E4 F8 32 94 AD 38 CC E4 36 C9 F6 40 0E 9A 73 47 60 07 6C E7 8F DA 83 C9 90 D1 F8 19 F3 16 04 12 15 A2 2B B8 9E EA A8 91 EF E1 32 0B 33 C5 A8 83 83 3B DD 61 F9 98 3A EC 1C 43 AA 96 DC 28 CD 61 C9 B8 3F D2 76 D8 8D 2D 0E E9 29 7E A7 6F 53 66 38 7F D0 1F F2 87 AD 57 66 82 85 E1 3D 2E 17 6D F8 88 38 1E 2B 3F 90 1F F1 83 32 46 C6 70 9D 96 11 DC 2F 5A C7 1A F4 BC 9F C5 2B A4 96 D4 37 4B A3 9B E9 56 2A A0 DB 68 0C 8D A5 71 E8 EF 0A 69 02 4D A4 22 E5 CB 40 FF D4 E9 3E 70 7F FB AF 7C 8B 2C DF 20 7E 99 8F F0 09 97 EF 6E 70 3F 54 EE 0B F7 13 77 B3 BB C5 15 C0 73 2E 74 45 6E B2 9B E2 EE D2 B5 32 B4 98 16 EB E9 72 50 46 85 2C 03 56 CA 72 60 95 28 8B D3 2C 59 01 AC 96 7A 60 5C 1A 80 09 59 09 AC 91 55 C0 D9 A2 BC 52 B5 DA 92 71 FD 39 C0 71 32 17 38 5E E6 01 0B E5 5E E0 04 99 0F 9C 28 0B 80 45 72 1F 70 92 2C 04 DE 0E 5B E3 D0 AA 17 59 8D DC 89 DC 29 B8 F2 03 B0 12 4D F2 98 BC 28 FB 11 AF 82 65 A9 83 1E 6E 96 BD D2 8E F8 2C D8 99 15 D0 CA C7 65 9F 1C 40 BC 1A 6D B3 1E 3A BA 45 5E 92 83 88 C7 61 83 1A A0 B1 4F C8 CB 72 08 F1 04 2C D2 4A E8 EF 56 79 45 0E 23 5E 03 FB B4 0A DA FC A4 BC 2A 47 10 9F 0D 6B B5 1A BA BD 4D 5E 43 4F 90 82 27 59 0A 5B D7 2C DB E5 75 E9 A0 3E B8 2B 68 0A EA A6 11 FA D5 2A 6D 56 A3 1D 3A 8E B7 F5 F4 6F D8 4A FA 60 5B FD BC C2 F6 EB 44 20 91 1C E8 6C 50 A3 B6 7E 93 2E E7 3D 3C 3B DF DF A7 51 A6 DF 05 CD BE 32 2C A9 03 25 9D E1 33 A1 D6 3A AB BD BE 96 53 C7 DB 71 1C 3D D4 3E 74 15 BA 4B 6F D0 6F E8 18 FD 96 8E D3 EF A8 93 4E D0 49 7A 93 DE A2 B7 E9 F7 74 8A FE 40 A7 E9 8F F4 0E FD 89 DE A5 3F D3 7B BA 6F 00 77 DD 8F FB F3 00 1E C8 69 D0 E1 3C D5 FD 40 4F F8 2F CA 0D E7 F2 3E 47 5F CA DC 4C 5D C5 74 1B 02 BD C3 BB D9 84 BA DA 8C FA D8 82 77 BE 15 EF 75 1B DE DD 87 78 EA 8F E4 9F F2 B1 9C 97 7F C9 05 E9 42 9B 65 3C FD 00 3F D0 A7 A1 1D 2F F5 CB FC 72 5F E7 57 F8 7A DF E0 77 F1 77 95 69 CC AC C5 30 BA E7 62 18 AD F6 59 68 E7 10 3F 1A F6 20 4F DE B1 B4 62 7E C6 DA FC 73 D6 06 77 02 87 59 BE C0 1F 67 B3 39 A4 7E 63 18 D2 43 19 35 83 32 27 5B 3C ED 62 DC F2 12 7C 0A 0A 25 F5 47 E7 3E A4 38 56 3E 3D 0C CF 9B 5E 5E 51 8A B3 7E E7 31 32 1E 84 95 37 74 E4 8C CA 8A C4 C4 CA CA F2 78 5E 64 44 F4 FA 9C E8 88 FC 48 CD 8C CA EC 19 89 BC 48 76 34 3B 37 3A 3C 3F 32 AD 26 7B 56 4D 5E E4 BA E8 A8 68 4E B4 AA 32 9E C8 CE 8F 94 96 CF AD 2A 8B 17 C4 8A F3 22 A3 A2 C3 A3 A3 F2 23 3F 8B 6B 51 E5 9A 32 3C 9A 1B BD 2E 37 3F 52 55 5D F9 D3 92 69 89 48 69 2C 11 A9 2E 99 1D 8B C7 2A 2B 20 FF BD E1 39 53 A7 8D B8 BE 00 A3 EA AC C8 8D 18 61 67 45 7E 5C 5D 52 32 33 2B 32 3B 76 6D 90 5A 5C 7A 6D F0 87 78 75 18 A8 99 69 81 2F 94 C9 DE 79 1F F3 56 D2 0D B3 C8 D5 96 96 25 F0 B2 B8 76 7A A2 8C 61 0B 63 89 A9 E5 7C 39 FE 9A 0C FF 2A 6A E3 15 DD C2 50 0F 91 6A 1C CF 07 56 59 6B 8D 74 37 7C 11 8E 29 A1 9F E6 F8 22 DF AA C6 C2 FF 34 EA 0A FE C3 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 C6 C9 C8 B6 13 86 C3 7D B1 CA C9 C8 C6 C9 C8 CA C9 08 1C CF 3A 67 52 C2 0B 80 0B 19 63 02 E5 64 A4 80 63 D4 D9 2E 14 56 66 46 E0 3E DE 07 7C 85 E1 15 28 33 A3 CE 38 71 27 F0 24 EB 1A C4 69 3E AD F3 6F FC 2E F0 3D 7E 5F E7 88 58 E7 CF 3F 66 5D 9D 39 CB 5D 3A 03 E9 52 80 A9 0E 23 13 65 66 04 A6 B9 6F 03 AF 70 43 75 EE CB 45 81 68 7D C0 1B DC F7 81 37 BA DB 80 BA 23 82 95 99 11 A8 7B 21 58 99 19 75 84 AD 63 6C 65 66 04 EA 3E 07 B6 BD 0D AC CC 8C C0 C5 6E B1 CE 41 B9 95 3A 3B 8A 51 3E 2B 33 23 F0 19 F7 1C 50 F7 0F B0 32 33 02 5B 1D 9E 4B 7D 00 60 BB D3 19 B0 63 EE 04 F0 4D A7 8C 83 BA E2 CF B6 E2 CF CA CC 08 D4 F5 7D 56 66 46 9D 25 73 3A 0B FA 91 C3 93 AA E7 03 BC E0 2E E8 EC 96 68 3F A9 6B F4 6C AB F3 6C EB F2 6C 6B F1 6C AB F0 6C EB EC 2C DF 94 6B 80 BA EF 4D 67 3B D1 EB DA 2A 39 2B 03 23 5A EF 68 B4 7A 56 06 46 E0 DD FE 6E 60 B3 6F 06 3E E5 77 C2 03 D8 E5 77 23 BC C7 BF 8D F0 29 7F 0A E1 0F 3C DA B3 72 32 9A C6 AA A6 EA 68 5D E7 AA B2 A9 3B 13 EC A5 19 5E 2F F2 C8 D2 BF 01 A8 06 97 38"; // truncated for example
-
- // Convert hex string to byte array
- byte[] compressedBytes = HexStringToBytes(hexInput);
-
- // Decompress using DeflateStream (zlib)
- byte[] uncompressedBytes = DecompressZlib(compressedBytes);
-
- // Convert uncompressed bytes to hex string
- string uncompressedHex = BitConverter.ToString(uncompressedBytes).Replace("-", " ");
- string text = Encoding.ASCII.GetString(uncompressedBytes);
- }
-
- [TestMethod]
- public void ChartToSVG()
- {
- string chart = "\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n Apples\r\n Oranges\r\n Bananas\r\n \r\n \r\n \r\n \r\n \r\n \r\n 10\r\n 20\r\n 15\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n";
- string chart2 = "\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n Sheet1!$B$1\r\n \r\n \r\n \r\n Amount\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n Sheet1!$A$2:$A$4\r\n \r\n \r\n \r\n PDF\r\n \r\n \r\n ??????\r\n \r\n \r\n Profit\r\n \r\n \r\n \r\n \r\n \r\n \r\n Sheet1!$B$2:$B$4\r\n \r\n General\r\n \r\n \r\n 1\r\n \r\n \r\n 500\r\n \r\n \r\n 1000\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n";
- // Load chart1.xml
- XDocument chartDoc = XDocument.Parse(chart2);
- XNamespace c = "http://schemas.openxmlformats.org/drawingml/2006/chart";
-
- // Extract categories and values
- var ser = chartDoc.Descendants(c + "ser").FirstOrDefault();
-
- var categories = ser
- .Descendants(c + "cat")
- .Descendants(c + "strCache")
- .Descendants(c + "pt")
- .Select(pt => pt.Element(c + "v")?.Value)
- .ToList();
-
- var values = ser
- .Descendants(c + "val")
- .Descendants(c + "numCache")
- .Descendants(c + "pt")
- .Select(pt => double.Parse(pt.Element(c + "v")?.Value ?? "0"))
- .ToList();
-
- // Dimensions for SVG
- int width = 600, height = 400;
- int margin = 50;
- int barWidth = 40;
- int spacing = 20;
-
- double maxValue = values.Max();
- double scaleY = (height - 2 * margin) / maxValue;
-
- // Create SVG root
- XNamespace svgNs = "http://www.w3.org/2000/svg";
- XElement svg = new XElement(svgNs + "svg",
- new XAttribute("xmlns", svgNs),
- new XAttribute("width", width),
- new XAttribute("height", height),
- new XElement(svgNs + "rect", // Background
- new XAttribute("x", 0),
- new XAttribute("y", 0),
- new XAttribute("width", width),
- new XAttribute("height", height),
- new XAttribute("fill", "white"))
- );
-
- // Draw bars
- for (int i = 0; i < values.Count; i++)
- {
- double barHeight = values[i] * scaleY;
- double x = margin + i * (barWidth + spacing);
- double y = height - margin - barHeight;
-
- svg.Add(new XElement(svgNs + "rect",
- new XAttribute("x", x),
- new XAttribute("y", y),
- new XAttribute("width", barWidth),
- new XAttribute("height", barHeight),
- new XAttribute("fill", "steelblue")));
-
- // Add category label
- svg.Add(new XElement(svgNs + "text",
- new XAttribute("x", x + barWidth / 2),
- new XAttribute("y", height - margin + 15),
- new XAttribute("text-anchor", "middle"),
- new XAttribute("font-size", "12"),
- categories[i]));
-
- // Add value label
- svg.Add(new XElement(svgNs + "text",
- new XAttribute("x", x + barWidth / 2),
- new XAttribute("y", y - 5),
- new XAttribute("text-anchor", "middle"),
- new XAttribute("font-size", "12"),
- values[i].ToString()));
- }
+ using var p = OpenTemplatePackage("PDFTest2.xlsx");
+ PdfPageSettings pageSettings = new PdfPageSettings();
+ pageSettings.ShowGridLines = true;
+ pageSettings.PageSize = PdfPageSize.A4;
+ pageSettings.Orientation = Orientations.Portrait;
+ pageSettings.Margins = PdfMargins.Normal;
+ pageSettings.ShowGridLines = true;
+ //Debug Flags
+ pageSettings.Debug = true;
+ pageSettings.PrintAsText = true;
- // Save to SVG file
- svg.Save("chart.svg");
+ ExcelPdf pedeef = new ExcelPdf(p.Workbook.Worksheets.First(), pageSettings);
+ pedeef.CreatePdf("c:\\epplustest\\pdf\\EmojiTest.pdf");
}
}
}
diff --git a/src/EPPlus.Export.Pdf/ExcelPdf.cs b/src/EPPlus.Export.Pdf/ExcelPdf.cs
index 11ae3f555..3c5007408 100644
--- a/src/EPPlus.Export.Pdf/ExcelPdf.cs
+++ b/src/EPPlus.Export.Pdf/ExcelPdf.cs
@@ -16,14 +16,13 @@ Date Author Change
using System.Text;
using OfficeOpenXml;
using EPPlus.Graphics;
-using System.Drawing;
-using EPPlus.Export.Pdf.Pdfhelpers;
using EPPlus.Export.Pdf.PdfLayout;
using EPPlus.Export.Pdf.PdfObjects;
using EPPlus.Export.Pdf.PdfResources;
using EPPlus.Export.Pdf.PdfSettings;
using OfficeOpenXml.Style;
using EPPlus.Fonts.OpenType;
+using OfficeOpenXml.Interfaces.Fonts;
namespace EPPlus.Export.Pdf
{
@@ -87,28 +86,6 @@ public ExcelPdf(ExcelRangeBase Range, PdfPageSettings pageSettings = null)
//PageSettings = pageSettings == null ? new PdfPageSettings() : pageSettings;
}
- //Get font label //need to update this one too for same reasons as AddFontData
- internal PdfFontResource GetFontResource(string fontName, FontSubFamily subFamily, double fontSize)
- {
- if (!Dictionaries.Fonts.ContainsKey(fontName))
- {
- int label = 1;
- if (Dictionaries.Fonts.Count > 0)
- {
- label = Dictionaries.Fonts.Last().Value.labelNumber + 1;
- }
- PdfFontResource fr = new PdfFontResource(fontName, subFamily, label, PageSettings);
- if (fontName != "Courier New")
- {
- Document.Add(fr.GetFontDescriptorObject(Document.Count + 1));
- Document.Add(fr.GetWidthsObject(Document.Count + 1));
- }
- Document.Add(fr.GetFontObject(Document.Count + 1));
- Dictionaries.Fonts.Add(fontName, fr);
- }
- return Dictionaries.Fonts[fontName];
- }
-
//Get the label to use for pattern.
internal string GetPatternLabel(PdfCellLayout layout)
{
@@ -123,17 +100,32 @@ internal string GetPatternLabel(PdfCellLayout layout)
return null;
}
- //Add Fonts //Need to update this method a bit. We should check for all default fonts and not only courier new?
+ //Add Fonts //Need to update this method a bit. We should check for all default fonts and not only courier new? Also need to check if we are allowed to embedd the font.
internal void AddFontData()
{
- foreach (var font in Dictionaries.Fonts)
+ if (PageSettings.EmbeddFonts)
+ {
+ foreach (var font in Dictionaries.Fonts)
+ {
+ //font.Value.CreateGidsAndCharMaps();
+ var CidSet = font.Value.GetCidSet(Document.Count + 1);
+ if (CidSet != null) Document.Add(CidSet);
+ Document.Add(font.Value.GetEmbeddedFontStreamObject(Document.Count + 1));
+ Document.Add(font.Value.GetFontDescriptorObject(Document.Count + 1));
+ Document.Add(font.Value.GetCIDFontObject(Document.Count + 1));
+ Document.Add(font.Value.GetUnicodeCmapObject(Document.Count + 1));
+ Document.Add(font.Value.GetType0FontDictObject(Document.Count + 1));
+ font.Value.GetFontObject(Document.Count);
+ }
+ }
+ else
{
- if (font.Key != "Courier New")
+ foreach (var font in Dictionaries.Fonts)
{
Document.Add(font.Value.GetFontDescriptorObject(Document.Count + 1));
Document.Add(font.Value.GetWidthsObject(Document.Count + 1));
+ Document.Add(font.Value.GetFontObject(Document.Count + 1));
}
- Document.Add(font.Value.GetFontObject(Document.Count + 1));
}
}
@@ -167,6 +159,7 @@ private PdfPage AddPage(int pagesObjectNumber, List contentObjectNumbers, P
Document.Add(page);
return page;
}
+
//Create Pages
private PdfPages AddPages()
{
@@ -174,6 +167,7 @@ private PdfPages AddPages()
Document.Add(pages);
return pages;
}
+
//Create Catalog
private PdfCatalog AddCatalog(int pagesObjectNumber)
{
@@ -187,13 +181,14 @@ private void AddContent(Transform pageLayout, PdfPage page)
{
var cells = pageLayout.ChildObjects.Where(t => t is PdfCellLayout || t is PdfCellContentLayout || t is PdfCellBorderLayout).GroupBy(t => t.Name);
var contentStream = new PdfContentStream(Document.Count + 1);
+ contentStream.AddCommand($"% {pageLayout.Name} start");
+ //Add clipping rectangle around page content.
+ contentStream.AddCommand("q");
+ contentStream.AddMarginClipping(pageLayout, PageSettings.ContentBounds);
if (PageSettings.ShowGridLines)
{
contentStream.AddInnerGridLines(pageLayout);
}
- //Add clipping rectangle around page content.
- contentStream.AddCommand("q");
- contentStream.AddMarginClipping(pageLayout, PageSettings.ContentBounds);
foreach (var cell in cells)
{
foreach (var cellPart in cell)
@@ -223,6 +218,7 @@ private void AddContent(Transform pageLayout, PdfPage page)
AddHeaderFooter(contentStream, pageLayout, page);
Document.Add(contentStream);
page.contentObjectNumbers.Add(contentStream.objectNumber);
+ contentStream.AddCommand($"% {pageLayout.Name} end");
}
//Add Header Footer
@@ -236,6 +232,7 @@ private void AddHeaderFooter(PdfContentStream contentStream, Transform pageLayou
}
}
+ //Add Info
private PdfInfoObject AddInfoObject()
{
var info = new PdfInfoObject(Document.Count + 1, _workheets[0].Workbook._package.File.Name);
@@ -285,7 +282,7 @@ public void CreatePdf(string Filename)
foreach (var pdfobj in Document)
{
crossRefTable.AddPosition(fs.Position);
- bw.Write(pdfobj.ToPdfBytes());
+ pdfobj.ToPdfBytes(bw);
debugString += pdfobj.ToPdfString();
}
//Write CrossReference
@@ -308,59 +305,5 @@ public void CreatePdf(string Filename)
}
}
}
-
- #region DEBUG
- //These methods need to be rewritten if they should be used.
-
- //internal void DrawMarginAndHeaderLines(PdfContentBounds bounds, PdfPage page)
- //{
- // var content = new PdfContentStream(Document.Count + 1);
- // //Bottom line
- // DrawLine(content, Color.Black, 0, bounds.Bottom, PageSettings.PageSize.WidthPu, bounds.Bottom);
- // DrawLine(content, new Color(1, 0, 1), bounds.X, bounds.Bottom, bounds.X + bounds.Width, bounds.Bottom);
- // //Top line
- // DrawLine(content, Color.Black, 0, bounds.Top, PageSettings.PageSize.WidthPu, bounds.Top);
- // DrawLine(content, new Color(1, 0, 1), bounds.X, bounds.Top, bounds.X + bounds.Width, bounds.Top);
- // //Left line
- // DrawLine(content, Color.Black, bounds.Left, 0, bounds.Left, 0);
- // DrawLine(content, new Color(1, 0, 1), bounds.Left, bounds.Y + bounds.Height, bounds.Left, bounds.Y + bounds.Height);
- // //Right line
- // DrawLine(content, Color.Black, bounds.Right, 0, bounds.Right, 0);
- // DrawLine(content, new Color(1, 0, 1), bounds.Right, bounds.Y + bounds.Height, bounds.Right, bounds.Y + bounds.Height);
- // //Header line
- // DrawLine(content, new Color(1, 0, 1), bounds.Right, bounds.HeaderY, bounds.Left, bounds.HeaderY);
- // DrawLine(content, new Color(1, 0, 1), bounds.CenterHeaderX, bounds.Top, bounds.CenterHeaderX, bounds.Top);
- // DrawLine(content, new Color(1, 0, 1), bounds.RightHeaderX, bounds.Top, bounds.RightHeaderX, bounds.Top);
- // //Footer line
- // DrawLine(content, new Color(1, 0, 1), bounds.Right, bounds.FooterY, bounds.Left, bounds.FooterY);
- // DrawLine(content, new Color(1, 0, 1), bounds.CenterFooterX, bounds.Bottom, bounds.CenterFooterX, bounds.Bottom);
- // DrawLine(content, new Color(1, 0, 1), bounds.RightFooterX, bounds.Bottom, bounds.RightFooterX, bounds.Bottom);
- // Document.Add(content);
- // page.contentObjectNumbers.Add(content.objectNumber);
- //}
-
- //internal void DrawLine(PdfContentStream content, Color color, double x1, double y1, double x2, double y2)
- //{
- // content.AddCommand(color.ToStrokeCommand());
- // content.AddCommand($"{x1.ToPdfString()} {y1.ToPdfString()} m");
- // content.AddCommand($"{x2.ToPdfString()} {y2.ToPdfString()} l");
- // content.AddCommand("S");
- //}
-
- //internal void DrawCrossHair(Color color, double x, double y, double size = 2)
- //{
- // var half = size / 2d;
- // var content = new PdfContentStream(Document.Count + 1);
- // content.AddCommand(color.ToStrokeCommand());
- // content.AddCommand($"{x.ToPdfString()} {(y - half).ToPdfString()} m");
- // content.AddCommand($"{x.ToPdfString()} {(y + half).ToPdfString()} l");
- // content.AddCommand($"{(x - half).ToPdfString()} {y.ToPdfString()} m");
- // content.AddCommand($"{(x + half).ToPdfString()} {y.ToPdfString()} l");
- // content.AddCommand("S");
- // Document.Add(content);
- //}
-
-
- #endregion
}
}
diff --git a/src/EPPlus.Export.Pdf/PdfFontData/PdfFontDataReader.cs b/src/EPPlus.Export.Pdf/PdfFontData/PdfFontDataReader.cs
deleted file mode 100644
index 1a7d8a767..000000000
--- a/src/EPPlus.Export.Pdf/PdfFontData/PdfFontDataReader.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-/*************************************************************************************************
- Required Notice: Copyright (C) EPPlus Software AB.
- This software is licensed under PolyForm Noncommercial License 1.0.0
- and may only be used for noncommercial purposes
- https://polyformproject.org/licenses/noncommercial/1.0.0/
-
- A commercial license to use this software can be purchased at https://epplussoftware.com
- *************************************************************************************************
- Date Author Change
- *************************************************************************************************
- 27/11/2025 EPPlus Software AB EPPlus 9
- *************************************************************************************************/
-using OfficeOpenXml.Core.Worksheet.Core.Worksheet.Fonts.GenericMeasurements;
-using OfficeOpenXml.Core.Worksheet.Core.Worksheet.Fonts;
-using System;
-using System.IO;
-using System.Text;
-using EPPlus.Graphics;
-
-namespace EPPlus.Export.Pdf.PdfFontData
-{
- internal class PdfFontDataReader
- {
- public static readonly Encoding FileEncoding = Encoding.UTF8;
-
- public static PdfFontProperties Deserialize(Stream stream)
- {
- using (var reader = new BinaryReader(stream, FileEncoding))
- {
- var metrics = new PdfFontProperties();
- metrics.Version = reader.ReadUInt16();
- metrics.Family = (FontMetricsFamilies)reader.ReadUInt16();
- metrics.SubFamily = (FontSubFamilies)reader.ReadUInt16();
- metrics.LineHeight1em = reader.ReadSingle();
- metrics.DefaultWidthClass = (FontMetricsClass)reader.ReadByte();
- var nClassWidths = reader.ReadUInt16();
- if (nClassWidths == 0)
- {
- return metrics;
- }
- for (var x = 0; x < nClassWidths; x++)
- {
- var cls = (FontMetricsClass)reader.ReadByte();
- var width = reader.ReadSingle();
- metrics.ClassWidths[cls] = width;
- }
- var nClasses = reader.ReadUInt16();
- for (var x = 0; x < nClasses; x++)
- {
- var cls = (FontMetricsClass)reader.ReadByte();
- var nRanges = reader.ReadUInt16();
- for (var rngIx = 0; rngIx < nRanges; rngIx++)
- {
- var start = reader.ReadUInt16();
- var end = reader.ReadUInt16();
- for (var c = start; c <= end; c++)
- {
- metrics.CharMetrics[Convert.ToChar(c)] = cls;
- }
- }
- var nCharactersInClass = reader.ReadUInt16();
- if (nCharactersInClass == 0) continue;
- for (int y = 0; y < nCharactersInClass; y++)
- {
- var cCode = reader.ReadUInt16();
- var c = Convert.ToChar(cCode);
- metrics.CharMetrics[c] = cls;
- }
- }
- //we use height and width as xmax and ymax instead of actual width and height.
- metrics.FontBBox = new Rect();
- metrics.FontBBox.Width = reader.ReadInt16();
- metrics.FontBBox.X = reader.ReadInt16();
- metrics.FontBBox.Height = reader.ReadInt16();
- metrics.FontBBox.Y = reader.ReadInt16();
- metrics.ItalicAngle = reader.ReadDouble();
- metrics.Ascent = reader.ReadInt16();
- metrics.Descent = reader.ReadInt16();
- metrics.Capheight = reader.ReadInt16();
- metrics.Flags = reader.ReadInt32();
- metrics.StemV = reader.ReadDouble();
- metrics.FirstChar = 32;
- metrics.LastChar = 255;
- return metrics;
- }
- }
- }
-}
diff --git a/src/EPPlus.Export.Pdf/PdfFontData/PdfFontProperties.cs b/src/EPPlus.Export.Pdf/PdfFontData/PdfFontProperties.cs
deleted file mode 100644
index e5e7ad9a1..000000000
--- a/src/EPPlus.Export.Pdf/PdfFontData/PdfFontProperties.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-/*************************************************************************************************
- Required Notice: Copyright (C) EPPlus Software AB.
- This software is licensed under PolyForm Noncommercial License 1.0.0
- and may only be used for noncommercial purposes
- https://polyformproject.org/licenses/noncommercial/1.0.0/
-
- A commercial license to use this software can be purchased at https://epplussoftware.com
- *************************************************************************************************
- Date Author Change
- *************************************************************************************************
- 27/11/2025 EPPlus Software AB EPPlus 9
- *************************************************************************************************/
-using OfficeOpenXml.Core.Worksheet.Core.Worksheet.Fonts.GenericMeasurements;
-using OfficeOpenXml.Core.Worksheet.Core.Worksheet.Fonts;
-using System.Collections.Generic;
-using EPPlus.Graphics;
-
-namespace EPPlus.Export.Pdf.PdfFontData
-{
- internal class PdfFontProperties
- {
- public FontMetricsFamilies Family { get; set; }
-
- public FontSubFamilies SubFamily { get; set; }
- public ushort Version { get; set; }
-
- public uint FontKey { get; set; }
-
- public float LineHeight1em { get; set; }
-
- public FontMetricsClass DefaultWidthClass { get; set; }
-
- public Dictionary ClassWidths { get; private set; }
-
- public Dictionary CharMetrics { get; private set; }
-
- public int Flags { get; set; }
-
- public Rect FontBBox { get; set; }
-
- public double ItalicAngle { get; set; }
-
- public int Ascent { get; set; }
-
- public int Descent { get; set; }
-
- public double StemV { get; set; }
-
- public short Capheight { get; set; }
-
- public int FirstChar { get; set; }
-
- public int LastChar { get; set; }
-
- public PdfFontProperties()
- {
- ClassWidths = new Dictionary();
- CharMetrics = new Dictionary();
- }
-
- public static uint GetKey(FontMetricsFamilies family, FontSubFamilies subFamily)
- {
- var k1 = (ushort)family;
- var k2 = (ushort)subFamily;
- return (uint)(k1 << 16 | k2 & 0xffff);
- }
-
- public uint GetKey()
- {
- return GetKey(Family, SubFamily);
- }
- }
-}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/IBorderLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/IBorderLayout.cs
index 2abdf0af0..1e7f190fa 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/IBorderLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/IBorderLayout.cs
@@ -13,8 +13,14 @@ Date Author Change
namespace EPPlus.Export.Pdf.PdfLayout
{
+ ///
+ /// Interface for border objects
+ ///
internal interface IBorderLayout
{
+ ///
+ /// Update Border positions.
+ ///
abstract void UpdateLocalBorderPosition();
}
}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/IShadingLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/IShadingLayout.cs
index 76a725543..06493c999 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/IShadingLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/IShadingLayout.cs
@@ -14,8 +14,14 @@ Date Author Change
namespace EPPlus.Export.Pdf.PdfLayout
{
+ ///
+ /// Interface for shading objects.
+ ///
internal interface IShadingLayout
{
+ ///
+ /// Update position matrix.
+ ///
abstract void UpdateShadingPositionMatrix(PdfPageSettings pageSettings);
}
}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/ITextLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/ITextLayout.cs
new file mode 100644
index 000000000..6c4e68017
--- /dev/null
+++ b/src/EPPlus.Export.Pdf/PdfLayout/ITextLayout.cs
@@ -0,0 +1,13 @@
+using EPPlus.Fonts.OpenType.Integration;
+using System.Collections.Generic;
+
+namespace EPPlus.Export.Pdf.PdfLayout
+{
+ internal interface ITextLayout
+ {
+ public List TextFormats { get; set; }
+ public double TextLength { get; set; }
+ public double TextHeight { get; set; }
+ public TextLayoutEngine TextLayoutEngine{ get; set; }
+ }
+}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfCatalogLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfCatalogLayout.cs
index e0a7b731a..577555841 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfCatalogLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfCatalogLayout.cs
@@ -10,16 +10,22 @@ Date Author Change
*************************************************************************************************
27/11/2025 EPPlus Software AB EPPlus 9
*************************************************************************************************/
-using System.Collections.Generic;
-using System.Linq;
-using System;
-using OfficeOpenXml;
using EPPlus.Export.Pdf.PdfResources;
using EPPlus.Export.Pdf.PdfSettings;
+using EPPlus.Fonts.OpenType;
+using EPPlus.Fonts.OpenType.Integration;
+using EPPlus.Fonts.OpenType.TextShaping;
using EPPlus.Graphics;
using EPPlus.Graphics.Math;
using EPPlus.Graphics.Units;
+using OfficeOpenXml;
+using OfficeOpenXml.Interfaces.Fonts;
+using OfficeOpenXml.Style;
using OfficeOpenXml.Style.HeaderFooterTextFormat;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
namespace EPPlus.Export.Pdf.PdfLayout
{
@@ -38,22 +44,60 @@ public PdfCatalogLayout(ExcelWorkbook workbook, PdfPageSettings pageSettings, Pd
public PdfCatalogLayout(ExcelWorksheet worksheet, PdfPageSettings pageSettings, PdfDictionaries dictionaries)
: base(0, 0, 0, 0)
{
+ Stopwatch sw = Stopwatch.StartNew();
+
Name = worksheet.Name + " Catalog";
var WorksheetLayout = AddChild(new PdfWorksheetLayout(worksheet, pageSettings, dictionaries));
- string wsLayout = ToHierarchyString();
+ sw.Stop();
+ var t1 = sw.ElapsedMilliseconds;
+ sw.Reset();
+ sw.Start();
+
+ //CreateFontSubsets(pageSettings, dictionaries.Fonts);
var PagesLayout = CreatePagesLayoutObject();
+ sw.Stop();
+ var t2 = sw.ElapsedMilliseconds;
+ sw.Reset();
+ sw.Start();
+
CreatePageLayoutObjects(worksheet, pageSettings, WorksheetLayout as PdfWorksheetLayout, PagesLayout);
- string pagesLayout = ToHierarchyString();
- AddCellsToPageLayout(WorksheetLayout, PagesLayout);
- string cellsInPages = ToHierarchyString();
- HandleMergedCellsAndDrawings(pageSettings, dictionaries, WorksheetLayout, PagesLayout);
- string mergedCellsInPages = ToHierarchyString();
- ConvertToPDFCoordiantes(pageSettings, PagesLayout);
- string ConvertedCoordinates = ToHierarchyString();
- AdjustAndSort(PagesLayout);
- RemoveChild(WorksheetLayout);
+ sw.Stop();
+ var t3 = sw.ElapsedMilliseconds;
+ sw.Reset();
+ sw.Start();
+
AddHeaderFooter(worksheet, pageSettings, dictionaries, PagesLayout);
- string FinalPagesLayout = ToHierarchyString();
+ sw.Stop();
+ var t8 = sw.ElapsedMilliseconds;
+ sw.Reset();
+ sw.Start();
+
+ PopulatePages(pageSettings, dictionaries, WorksheetLayout, PagesLayout);
+ sw.Stop();
+ var t4 = sw.ElapsedMilliseconds;
+ sw.Reset();
+ sw.Start();
+
+ //AddCellsToPageLayout(WorksheetLayout, PagesLayout);
+ //HandleMergedCellsAndDrawings(pageSettings, dictionaries, WorksheetLayout, PagesLayout);
+ MoveCellToPageFromContent(pageSettings, dictionaries, PagesLayout);
+ sw.Stop();
+ var t5 = sw.ElapsedMilliseconds;
+ sw.Reset();
+ sw.Start();
+
+ ProocessPageAndCells(pageSettings, dictionaries, PagesLayout);
+ sw.Stop();
+ var t6 = sw.ElapsedMilliseconds;
+ sw.Reset();
+ sw.Start();
+
+ //ConvertToPDFCoordiantes(pageSettings, PagesLayout, worksheet);
+ AdjustAndSort(PagesLayout, dictionaries);
+ RemoveChild(WorksheetLayout);
+ sw.Stop();
+ var t7 = sw.ElapsedMilliseconds;
+ sw.Reset();
}
//Create the pages layout.
@@ -68,13 +112,16 @@ private PdfPagesLayout CreatePagesLayoutObject()
//Create page and content objects.
private void CreatePageLayoutObjects(ExcelWorksheet worksheet, PdfPageSettings pageSettings, PdfWorksheetLayout worksheetLayout, PdfPagesLayout pages)
{
+
+ /*Speculating how to make page breaks work. When we have all pages we create a pages map. we find all rows and columns that has a page break and then we rezise the content object until it reaches the page break*/
+
//Get x cooridiantes to break for new page
List xBreaks = new List() { 0d };
double currentWidth = 0, boundsWidth = pageSettings.ContentBounds.Width;
for (int j = 1; j <= worksheet.Dimension._toCol; j++)
{
if (worksheet.Column(j).Hidden) { continue; }
- var width = UnitConversion.ExcelColumnWidthToPoints(worksheet.Column(j).Width, worksheetLayout.ZeroCharWidth);
+ var width = UnitConversion.ExcelColumnWidthToPoints(worksheet.Column(j).Width, PdfWorksheetLayout.ZeroCharWidth);
if (currentWidth + width >= boundsWidth)
{
xBreaks.Add(currentWidth);
@@ -126,67 +173,149 @@ private void CreatePageLayoutObjects(ExcelWorksheet worksheet, PdfPageSettings p
}
}
- //Go though all the cells in WorksheetLayout and add them to the overlapping page.
- private void AddCellsToPageLayout(Transform WorksheetLayout, PdfPagesLayout pages)
+ //Internal class for storing bounds for pages
+ private class PageData
{
- var cells = WorksheetLayout.ChildObjects.Where(x => x is PdfCellLayout || x is PdfCellContentLayout || x is PdfCellBorderLayout).ToList();
- foreach (var cell in cells)
+ public PdfPageLayout Page;
+ public Rect Bounds; // replace BoundingBox with whatever your bounds type is
+
+ public PageData(PdfPageLayout page, Rect bounds)
{
- var cellBounds = cell.GetGlobalBoundingbox();
- foreach (var page in pages.ChildObjects)
- {
- var contentbounds = page.ChildObjects[0].GetGlobalBoundingbox();
- if (IntersectsFully(contentbounds, cellBounds))
- {
- page.ChildObjects[0].AddChild(cell);
- break;
- }
- }
+ Page = page;
+ Bounds = bounds;
}
}
- //Handle merged cells and drawings by checking which pages intersects with them and then make copies for each page.
- private void HandleMergedCellsAndDrawings(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Transform WorksheetLayout, PdfPagesLayout pages)
+ private Dictionary shaperCache = new Dictionary();
+ private Dictionary layoutEngineCache = new Dictionary();
+
+ //Move cells to their overlapping pages.
+ private void PopulatePages(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Transform WorksheetLayout, PdfPagesLayout pages)
{
- var mcd = WorksheetLayout.ChildObjects.Where(x => x is PdfMergedCellLayout || x is PdfCellContentLayout || x is PdfCellBorderLayout || x is PdfDrawingLayout).ToList();
- foreach (var mergedCell in mcd)
+
+ var pageData = new List();
+ foreach (PdfPageLayout p in pages.ChildObjects)
+ {
+ pageData.Add(new PageData(p, p.ChildObjects[0].GetGlobalBoundingbox()));
+
+ var hfs = p.ChildObjects.Where(x => x is PdfHeaderFooterLayout).ToArray();
+ foreach(var hf in hfs )
+ LayoutAndShapeText(pageSettings, dictionaries, shaperCache, layoutEngineCache, (PdfHeaderFooterLayout)hf);
+ }
+ pageData.Sort((a, b) => a.Bounds.Top.CompareTo(b.Bounds.Top));
+
+ var transforms = new List(WorksheetLayout.ChildObjects);
+ foreach (var t in transforms)
{
- var m = mergedCell as PdfMergedCellLayout;
- var c = mergedCell as PdfCellContentLayout;
- var b = mergedCell as PdfCellBorderLayout;
- var d = mergedCell as PdfDrawingLayout;
- var bounds = mergedCell.GetGlobalBoundingbox();
- foreach (var page in pages.ChildObjects)
+ var cellBounds = t.GetGlobalBoundingbox();
+
+ // Pass 1: check if ANY page fully contains this transform.
+ // If so, we use only that page and skip all partial intersects.
+ PageData fullIntersectPage = null;
+ foreach (var pd in pageData)
{
- if (Intersects(bounds, page.ChildObjects[0].GetGlobalBoundingbox()))
+ if (pd.Bounds.Top > cellBounds.Bottom) break;
+ if (pd.Bounds.Bottom < cellBounds.Top) continue;
+
+ if (IntersectsFully(pd.Bounds, cellBounds))
{
- if (m is PdfMergedCellLayout)
+ fullIntersectPage = pd;
+ break;
+ }
+ }
+ // Pass 2: assign to pages.
+ foreach (var pd in pageData)
+ {
+ if (pd.Bounds.Top > cellBounds.Bottom) break;
+ if (pd.Bounds.Bottom < cellBounds.Top) continue;
+
+ bool fullIntersect = fullIntersectPage != null && pd == fullIntersectPage;
+ bool partialIntersect = fullIntersectPage == null && !fullIntersect && Intersects(cellBounds, pd.Bounds);
+
+ if (!fullIntersect && !partialIntersect) continue;
+
+ var page = pd.Page;
+
+ if (t is PdfMergedCellLayout merged)
+ {
+ if (fullIntersect)
+ {
+ page.ChildObjects[0].AddChild(merged);
+ break;
+ }
+ else
{
- var copy = new PdfMergedCellLayout(dictionaries, m.cell, m.CellStyle, m.LocalPosition.X, m.LocalPosition.Y + m.Size.Y, m.Size.X, m.Size.Y, m.LocalScale.X, m.LocalScale.Y, m.LocalRotation, WorksheetLayout);
- copy.Name = m.Name;
- copy.Z = m.Z;
+ var copy = new PdfMergedCellLayout(dictionaries, merged.cell, merged.CellStyle,
+ merged.LocalPosition.X, merged.LocalPosition.Y + merged.Size.Y,
+ merged.Size.X, merged.Size.Y,
+ merged.LocalScale.X, merged.LocalScale.Y,
+ merged.LocalRotation, WorksheetLayout);
+ copy.Name = merged.Name;
+ copy.Z = merged.Z;
+ copy.address = merged.address;
page.ChildObjects[0].AddChild(copy);
}
- else if (c is PdfCellContentLayout)
+ }
+ else if (t is PdfCellLayout cell)
+ {
+ if (fullIntersect)
+ {
+ page.AddCell(cell);
+ break;
+ }
+ }
+ else if (t is PdfCellContentLayout cellContent)
+ {
+ if (fullIntersect)
+ {
+ page.AddCell(cellContent);
+ LayoutAndShapeText(pageSettings, dictionaries, shaperCache, layoutEngineCache, cellContent);
+ break;
+ }
+ else
{
- var copy = new PdfCellContentLayout(c.cell, c.CellStyle, pageSettings, c.LocalPosition.X, c.LocalPosition.Y, c.Size.X, c.Size.Y, c.LocalScale.X, c.LocalScale.Y, c.LocalRotation, WorksheetLayout, dictionaries);
- copy.Name = c.Name;
- copy.Z = c.Z;
+ var copy = new PdfCellContentLayout(cellContent.cell, cellContent.CellStyle, pageSettings,
+ cellContent.LocalPosition.X, cellContent.LocalPosition.Y,
+ cellContent.Size.X, cellContent.Size.Y,
+ cellContent.LocalScale.X, cellContent.LocalScale.Y,
+ cellContent.LocalRotation, WorksheetLayout, dictionaries);
+ copy.Name = cellContent.Name;
+ copy.Z = cellContent.Z;
page.ChildObjects[0].AddChild(copy);
+ LayoutAndShapeText(pageSettings, dictionaries, shaperCache, layoutEngineCache, copy);
+ }
+ }
+ else if (t is PdfCellBorderLayout border)
+ {
+ if (fullIntersect)
+ {
+ page.AddCell(border);
+ break;
}
- else if (b is PdfCellBorderLayout)
+ else
{
- var copy = new PdfCellBorderLayout(b.cell, null, b.LocalPosition.X, b.LocalPosition.Y + b.Size.Y, b.Size.X, b.Size.Y, b.LocalScale.X, b.LocalScale.Y, b.LocalRotation, WorksheetLayout);
- copy.Name = b.Name;
- copy.Z = b.Z;
- copy.BorderData = b.BorderData;
- copy.range = b.range;
- copy.IsMerged = b.IsMerged;
+ var copy = new PdfCellBorderLayout(border.cell, null,
+ border.LocalPosition.X, border.LocalPosition.Y + border.Size.Y,
+ border.Size.X, border.Size.Y,
+ border.LocalScale.X, border.LocalScale.Y,
+ border.LocalRotation, WorksheetLayout);
+ copy.Name = border.Name;
+ copy.Z = border.Z;
+ copy.BorderData = border.BorderData;
+ copy.range = border.range;
+ copy.IsMerged = border.IsMerged;
page.ChildObjects[0].AddChild(copy);
}
- else if (d is PdfDrawingLayout) //NOT IMPLEMENTED
+ }
+ else if (t is PdfDrawingLayout drawing)
+ {
+ if (fullIntersect)
+ break;
+ else
{
- var copy = new PdfDrawingLayout(null, d.LocalPosition.X, d.LocalPosition.Y, d.Size.X, d.Size.Y);
+ var copy = new PdfDrawingLayout(null,
+ drawing.LocalPosition.X, drawing.LocalPosition.Y,
+ drawing.Size.X, drawing.Size.Y);
page.ChildObjects[0].AddChild(copy);
}
}
@@ -194,29 +323,399 @@ private void HandleMergedCellsAndDrawings(PdfPageSettings pageSettings, PdfDicti
}
}
- //Restore the positions of the content, move content children to page and remove content object.
- private void ConvertToPDFCoordiantes(PdfPageSettings pageSettings, PdfPagesLayout pages)
+ //Font handling, Text shaping and layouting wrapped text
+ //Font handling, Text shaping and layouting wrapped text
+ private static void LayoutAndShapeText(PdfPageSettings pageSettings, PdfDictionaries dictionaries, Dictionary shaperCache, Dictionary layoutEngineCache, ITextLayout text)
{
+ for (int i = 0; i < text.TextFormats.Count; i++)
+ {
+ var fd = text.TextFormats[i];
+ fd.FontProvider = dictionaries.Fonts[fd.FullFontName].fontSubsetManager.CreateSubsettedProvider();
+
+ if (!shaperCache.TryGetValue(fd.FontProvider, out var shaper))
+ {
+ shaper = new TextShaper(fd.FontProvider);
+ shaperCache[fd.FontProvider] = shaper;
+ }
+
+ if (!layoutEngineCache.TryGetValue(fd.FontProvider, out var layoutEngine))
+ {
+ layoutEngine = new TextLayoutEngine(shaper);
+ layoutEngineCache[fd.FontProvider] = layoutEngine;
+ }
+
+ var options = ShapingOptions.Default;
+ options.ApplyPositioning = true;
+ options.ApplySubstitutions = true;
+
+ var shaped = shaper.Shape(fd.Text, options);
+ var usedFonts = shaper.GetUsedFonts().ToList();
+ var fontIdMap = new Dictionary();
+
+ var allProviderFonts = fd.FontProvider.GetAllFonts().ToList();
+
+ for (byte fontId = 0; fontId < usedFonts.Count; fontId++)
+ {
+ var font = usedFonts[fontId];
+
+ if (!dictionaries.Fonts.ContainsKey(font.FullName))
+ {
+ int label = 1;
+ if (dictionaries.Fonts.Count > 0)
+ {
+ label = dictionaries.Fonts.Last().Value.labelNumber + 1;
+ }
+ var fontResource = new PdfFontResource(font.FullName, font.NameTable.GetSubfamilyEnum(), label, pageSettings);
+ fontResource.fontData = font;
+ dictionaries.Fonts.Add(font.FullName, fontResource);
+ }
+ fontIdMap[fontId] = dictionaries.Fonts[font.FullName].Label;
+ }
+
+ text.TextLayoutEngine = layoutEngine;
+ fd.ShapedText = shaped;
+ fd.FontIdMap = fontIdMap;
+ fd.UsedFonts = usedFonts;
+ text.TextFormats[i] = fd;
+ shaper.ResetFontTracking();
+ }
+ }
+
+ //Create a map for page
+ private void MoveCellToPageFromContent(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfPagesLayout pages)
+ {
+ List entriesToRemove = new();
foreach (PdfPageLayout page in pages.ChildObjects)
{
+ page.CreateMap();
page.ChildObjects[0].LocalPosition = new Vector2(pageSettings.Margins.LeftPu, pageSettings.Margins.TopPu);
var contentObjects = page.ChildObjects[0].ChildObjects.ToList();
- foreach (var child in contentObjects)
+ for (int i = 0; i < contentObjects.Count; i++)
{
+ var child = contentObjects[i];
page.AddChild(child);
if (child is IShadingLayout iSl)
iSl.UpdateShadingPositionMatrix(pageSettings);
- if (child is IBorderLayout iBl)
- iBl.UpdateLocalBorderPosition();
+ if (child is PdfMergedCellLayout m)
+ {
+ var localFromRow = m.address._fromRow - page.FromRow;
+ var localFromCol = m.address._fromCol - page.FromCol;
+ var localToRow = m.address._toRow - page.FromRow;
+ var localToCol = m.address._toCol - page.FromCol;
+ int colCount = 0;
+ int rowCount = 0;
+ bool remove = true;
+
+ for (int r = localFromRow; r <= localToRow; r++)
+ {
+ if (r >= (page.ToRow - page.FromRow) + 1) break;
+ if (r < 0)
+ {
+ rowCount++;
+ continue;
+ }
+ for (int c = localFromCol; c <= localToCol; c++)
+ {
+ if (c >= (page.ToCol - page.FromCol) + 1) break;
+ if (c < 0)
+ {
+ colCount++;
+ continue;
+ }
+ page.Map[r, c].Name = ExcelRange.GetColumnLetter(m.cell._fromCol + colCount) + (m.cell._fromRow + rowCount);
+ page.Map[r, c].cell = m;
+ page.Map[r, c].Type = PageMap.CellType.Merged;
+ page.Map[r, c].content = contentObjects.OfType().FirstOrDefault(t => t.Name == m.Name);
+ if (page.Map[r, c].content != null) page.Map[r, c].content.Clip = true;
+ page.Map[r, c].border = contentObjects.OfType().FirstOrDefault(t => t.Name == m.Name);
+ page.Map[r, c].row = m.cell._fromRow + rowCount;
+ page.Map[r, c].col = m.cell._fromCol + colCount;
+ colCount++;
+ remove = false;
+ }
+ rowCount++;
+ colCount = 0;
+ }
+ if (remove)
+ {
+ entriesToRemove.Add(child.Name);
+ }
+ }
+ else if (child is PdfCellLayout l)
+ {
+ var localFromRow = l.cell._fromRow - page.FromRow;
+ var localFromCol = l.cell._fromCol - page.FromCol;
+ page.Map[localFromRow, localFromCol].Name = l.Name;
+ page.Map[localFromRow, localFromCol].cell = l;
+ page.Map[localFromRow, localFromCol].Type = PageMap.CellType.Normal;
+ page.Map[localFromRow, localFromCol].content = contentObjects.OfType().FirstOrDefault(t => t.Name == l.Name);
+ page.Map[localFromRow, localFromCol].border = contentObjects.OfType().FirstOrDefault(t => t.Name == l.Name);
+ page.Map[localFromRow, localFromCol].row = l.cell._fromRow;
+ page.Map[localFromRow, localFromCol].col = l.cell._fromCol;
+ page.Map[localFromRow, localFromCol].RightTextBucketSpill = page.Map[localFromRow, localFromCol].content != null ? page.Map[localFromRow, localFromCol].content.RightTextSpillLength : 0d;
+ page.Map[localFromRow, localFromCol].LeftTextBucketSpill = page.Map[localFromRow, localFromCol].content != null ? page.Map[localFromRow, localFromCol].content.LeftTextSpillLength : 0d;
+ }
}
page.RemoveChild(page.ChildObjects[0]);
- page.GenerateGridLines();
- page.ChildObjects.RemoveAll(x => x.Name.Contains("*")); //Remove all content with * in its name. Better approach would be to not add them at all, But they are needed for grid lines.
+ foreach (var entry in entriesToRemove)
+ {
+ var cell = contentObjects.OfType().FirstOrDefault(t => t.Name == entry);
+ var content = contentObjects.OfType().FirstOrDefault(t => t.Name == entry);
+ var border = contentObjects.OfType().FirstOrDefault(t => t.Name == entry);
+ page.RemoveChild(content);
+ page.RemoveChild(border);
+ page.RemoveChild(cell);
+ }
+ }
+ }
+
+ private void ProocessPageAndCells(PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfPagesLayout pages)
+ {
+ foreach (PdfPageLayout page in pages.ChildObjects)
+ {
+ var rowCount = page.ToRow - page.FromRow + 1;
+ var colCount = page.ToCol - page.FromCol + 1;
+
+ // ── Interior vertical lines ──────────────────────────────────────────
+ var activeVertical = new Dictionary();
+ Action flushVertical = delegate (int col)
+ {
+ VerticalLineRun run;
+ if (activeVertical.TryGetValue(col, out run))
+ {
+ double x = page.Map[run.RowStart, col].cell.LocalPosition.X;
+ double y1 = page.Map[run.RowStart, col].cell.LocalPosition.Y;
+ double y2 = page.Map[run.RowEnd, col].cell.LocalPosition.Y
+ + page.Map[run.RowEnd, col].cell.Size.Y;
+ page.GridLines.Add(new GridLine(x, y1, x, y2));
+ activeVertical.Remove(col);
+ }
+ };
+ Action addVertical = delegate (int r, int c)
+ {
+ VerticalLineRun run;
+ if (activeVertical.TryGetValue(c, out run))
+ {
+ if (run.RowEnd == r - 1)
+ run.RowEnd = r;
+ else
+ {
+ flushVertical(c);
+ activeVertical[c] = new VerticalLineRun { Col = c, RowStart = r, RowEnd = r };
+ }
+ }
+ else
+ {
+ activeVertical[c] = new VerticalLineRun { Col = c, RowStart = r, RowEnd = r };
+ }
+ };
+
+ // ── Interior horizontal lines ────────────────────────────────────────
+ var activeHorizontal = new Dictionary();
+ Action flushHorizontal = delegate (int row)
+ {
+ HorizontalLineRun run;
+ if (activeHorizontal.TryGetValue(row, out run))
+ {
+ double y = page.Map[row, run.ColStart].cell.LocalPosition.Y;
+ double x1 = page.Map[row, run.ColStart].cell.LocalPosition.X;
+ double x2 = page.Map[row, run.ColEnd].cell.LocalPosition.X
+ + page.Map[row, run.ColEnd].cell.Size.X;
+ page.GridLines.Add(new GridLine(x1, y, x2, y));
+ activeHorizontal.Remove(row);
+ }
+ };
+ Action AddHorizontalSegment = delegate (int r, int c)
+ {
+ HorizontalLineRun run;
+ if (activeHorizontal.TryGetValue(r, out run))
+ {
+ if (run.ColEnd == c - 1)
+ run.ColEnd = c;
+ else
+ {
+ flushHorizontal(r);
+ activeHorizontal[r] = new HorizontalLineRun { Row = r, ColStart = c, ColEnd = c };
+ }
+ }
+ else
+ {
+ activeHorizontal[r] = new HorizontalLineRun { Row = r, ColStart = c, ColEnd = c };
+ }
+ };
+
+ // ── Main loop ────────────────────────────────────────────────────────
+ for (int row = 0; row < rowCount; row++)
+ {
+ // Flush horizontal runs not continued into this row
+ foreach (int key in new List(activeHorizontal.Keys))
+ flushHorizontal(key);
+
+ // Flush vertical runs that didn't continue
+ foreach (int key in new List(activeVertical.Keys))
+ {
+ if (activeVertical[key].RowEnd < row)
+ flushVertical(key);
+ }
+
+ for (int col = 0; col < colCount; col++)
+ {
+ var cell = page.Map[row, col];
+ PageMap leftCell = new PageMap();
+ PageMap rightCell = new PageMap();
+ if (col != 0) leftCell = page.Map[row, col - 1];
+ if (col != colCount - 1) rightCell = page.Map[row, col + 1];
+
+ // ── Text-spill propagation ───────────────────────────────────
+ if (leftCell.cell != null)
+ {
+ if (leftCell.content != null)
+ {
+ if (leftCell.content.RightTextSpillLength > 0d)
+ {
+ if (cell.content != null)
+ {
+ // Spill collides with content — clip the source and force a gridline
+ leftCell.content.Clip = true;
+ addVertical(row, col);
+ }
+ else
+ {
+ cell.RightTextBucketSpill = leftCell.content.RightTextSpillLength - cell.cell.Size.X;
+ }
+ }
+ }
+ else if (leftCell.RightTextBucketSpill > 0d)
+ {
+ if (cell.content != null)
+ {
+ // Bucket spill collides with content — walk back to find origin and clip it, force a gridline
+ for (int i = col - 1; i >= 0; i--)
+ {
+ var originCell = page.Map[row, i];
+ if (originCell.content != null)
+ {
+ originCell.content.Clip = true;
+ break;
+ }
+ }
+ addVertical(row, col);
+ }
+ else
+ {
+ cell.RightTextBucketSpill = leftCell.RightTextBucketSpill - cell.cell.Size.X;
+ }
+ }
+ }
+
+ if (cell.content != null)
+ {
+ if (cell.content.LeftTextSpillLength > 0d)
+ {
+ double spill = cell.content.LeftTextSpillLength;
+ for (int i = col; i > 0; i--)
+ {
+ var prevCell = page.Map[row, i - 1];
+ if (prevCell.content != null)
+ {
+ // Spill collides with content — clip and force a gridline at the boundary
+ cell.content.Clip = true;
+ cell.content.CreateClippingRect(cell.cell, prevCell.cell.LocalPosition.X + prevCell.cell.Size.X);
+ addVertical(row, i);
+ break;
+ }
+ prevCell.LeftTextBucketSpill = spill - prevCell.cell.Size.X;
+ spill -= prevCell.cell.Size.X;
+ page.Map[row, i - 1] = prevCell;
+ if (spill <= 0d) break;
+ }
+ }
+
+ cell.content.GidsAndCharMap(dictionaries);
+ }
+
+ // ── Gridline collection ──────────────────────────────────────
+
+ // Interior horizontal — only between two rows (skip top page edge)
+ if (row > 0)
+ {
+ var t = page.Map[row - 1, col];
+ bool differentTop = t.cell != cell.cell;
+
+ // Border data is only stored at the merged cell's origin row — walk up to find it
+ int topOriginRow = row - 1;
+ while (topOriginRow > 0 && page.Map[topOriginRow - 1, col].cell == t.cell)
+ topOriginRow--;
+ var topBorder = page.Map[topOriginRow, col].border;
+
+ int cellOriginRow = row;
+ while (cellOriginRow > 0 && page.Map[cellOriginRow - 1, col].cell == cell.cell)
+ cellOriginRow--;
+ var cellBorder = page.Map[cellOriginRow, col].border;
+
+ bool borderTop = (topBorder != null && topBorder.BorderData.Bottom.BorderStyle != ExcelBorderStyle.None) ||
+ (cellBorder != null && cellBorder.BorderData.Top.BorderStyle != ExcelBorderStyle.None);
+
+ if (differentTop && !borderTop)
+ AddHorizontalSegment(row - 1, col);
+ }
+
+ // Interior vertical — only between two columns (skip left page edge)
+ if (col > 0)
+ {
+ var l = page.Map[row, col - 1];
+ bool differentLeft = l.cell != cell.cell;
+ bool spillLeft = l.RightTextBucketSpill > 0 || cell.LeftTextBucketSpill > 0;
+
+ // Border data is only stored at the merged cell's origin column — walk left to find it
+ int leftOriginCol = col - 1;
+ while (leftOriginCol > 0 && page.Map[row, leftOriginCol - 1].cell == l.cell)
+ leftOriginCol--;
+ var leftBorder = page.Map[row, leftOriginCol].border;
+
+ int cellOriginCol = col;
+ while (cellOriginCol > 0 && page.Map[row, cellOriginCol - 1].cell == cell.cell)
+ cellOriginCol--;
+ var cellBorderV = page.Map[row, cellOriginCol].border;
+
+ bool borderLeft = (leftBorder != null && leftBorder.BorderData.Right.BorderStyle != ExcelBorderStyle.None) ||
+ (cellBorderV != null && cellBorderV.BorderData.Left.BorderStyle != ExcelBorderStyle.None);
+
+ if (differentLeft && !spillLeft && !borderLeft)
+ addVertical(row, col);
+ }
+
+ page.Map[row, col] = cell;
+ }
+ }
+
+ // ── Final flush ──────────────────────────────────────────────────────
+ foreach (int key in new List(activeVertical.Keys))
+ flushVertical(key);
+ foreach (int key in new List(activeHorizontal.Keys))
+ flushHorizontal(key);
+
+ // ── Border lines (4 outer edges, derived from the corner cells) ──────
+ var tl = page.Map[0, 0].cell; // bottom-left
+ var br = page.Map[0, colCount - 1].cell; // bottom-right
+ var bl = page.Map[rowCount - 1, 0].cell; // top-left
+ var tr = page.Map[rowCount - 1, colCount - 1].cell; // top-right
+
+ double left = bl.LocalPosition.X;
+ double right = br.LocalPosition.X + br.Size.X;
+ double bottom = bl.LocalPosition.Y;
+ double top = tl.LocalPosition.Y + tl.Size.Y;
+
+ page.BorderLines.Add(new GridLine(left, bottom, right, bottom)); // bottom
+ page.BorderLines.Add(new GridLine(left, top, right, top)); // top
+ page.BorderLines.Add(new GridLine(left, bottom, left, top)); // left
+ page.BorderLines.Add(new GridLine(right, bottom, right, top)); // right
+ page.ChildObjects.RemoveAll(x => x is PdfCellLayout && ((PdfCellLayout)x).delete == true);
}
}
//Make final adjustments and sort children for drawing order.
- private void AdjustAndSort(PdfPagesLayout pages)
+ private void AdjustAndSort(PdfPagesLayout pages, PdfDictionaries dictionaries)
{
foreach (PdfPageLayout page in pages.ChildObjects)
{
@@ -227,11 +726,11 @@ private void AdjustAndSort(PdfPagesLayout pages)
{
cellLayout.AdjustForGridLines();
}
- if (child is PdfCellContentLayout contentLayout)
+ else if (child is PdfCellContentLayout content)
{
- contentLayout.CreateClippingRect(page.ChildObjects);
+ content.CreateClippingRect(page.ChildObjects);
}
- if (child is PdfMergedCellLayout mergedLayout)
+ else if (child is PdfMergedCellLayout mergedLayout)
{
mergedLayout.AdjustForGridLines();
}
@@ -247,7 +746,7 @@ private void AdjustAndSort(PdfPagesLayout pages)
}
}
- private void AddHeaderFooter(ExcelWorksheet ws, PdfPageSettings settings, PdfDictionaries dictionaries, PdfPagesLayout pages)
+ private void AddHeaderFooter(ExcelWorksheet ws, PdfPageSettings pageSettings, PdfDictionaries dictionaries, PdfPagesLayout pages)
{
int pageNumber = 1;
//loop pages and check which header it should use
@@ -305,22 +804,28 @@ private void AddHeaderFooter(ExcelWorksheet ws, PdfPageSettings settings, PdfDic
centerF = ws.HeaderFooter.OddFooter.Centered;
rightF = ws.HeaderFooter.OddFooter.RightAligned;
}
- var lh = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(leftH, ws, settings, dictionaries, pageNumber, pages.ChildObjects.Count));
- lh.LocalPosition = new Vector2(settings.Margins.LeftPu, settings.PageSize.HeightPu - settings.Margins.HeaderPu);
+ var lh = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(leftH, ws, pageSettings, dictionaries, pageNumber, pages.ChildObjects.Count));
+ lh.Name = "LeftHeader";
+ lh.LocalPosition = new Vector2(pageSettings.Margins.LeftPu, pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu);
lh.AdjustPositionByTextLength('l', 'h');
- var ch = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(centerH, ws, settings, dictionaries, pageNumber, pages.ChildObjects.Count));
- ch.LocalPosition = new Vector2(settings.PageSize.WidthPu / 2d, settings.PageSize.HeightPu - settings.Margins.HeaderPu);
+ var ch = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(centerH, ws, pageSettings, dictionaries, pageNumber, pages.ChildObjects.Count));
+ ch.Name = "CenterHeader";
+ ch.LocalPosition = new Vector2(pageSettings.PageSize.WidthPu / 2d, pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu);
ch.AdjustPositionByTextLength('c', 'h');
- var rh = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(rightH, ws, settings, dictionaries, pageNumber, pages.ChildObjects.Count));
- rh.LocalPosition = new Vector2(settings.PageSize.WidthPu - settings.Margins.RightPu, settings.PageSize.HeightPu - settings.Margins.HeaderPu);
+ var rh = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(rightH, ws, pageSettings, dictionaries, pageNumber, pages.ChildObjects.Count));
+ rh.Name = "RightHeader";
+ rh.LocalPosition = new Vector2(pageSettings.PageSize.WidthPu - pageSettings.Margins.RightPu, pageSettings.PageSize.HeightPu - pageSettings.Margins.HeaderPu);
rh.AdjustPositionByTextLength('r', 'h');
- var lf = pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(leftF, ws, settings, dictionaries, pageNumber, pages.ChildObjects.Count));
- lf.LocalPosition = new Vector2(settings.Margins.LeftPu, settings.Margins.FooterPu);
- var cf = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(centerF, ws, settings, dictionaries, pageNumber, pages.ChildObjects.Count));
- cf.LocalPosition = new Vector2(settings.PageSize.WidthPu / 2d, settings.Margins.FooterPu);
+ var lf = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(leftF, ws, pageSettings, dictionaries, pageNumber, pages.ChildObjects.Count));
+ lf.Name = "LeftFooter";
+ lf.LocalPosition = new Vector2(pageSettings.Margins.LeftPu, pageSettings.Margins.FooterPu);
+ var cf = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(centerF, ws, pageSettings, dictionaries, pageNumber, pages.ChildObjects.Count));
+ cf.Name = "CenterFooter";
+ cf.LocalPosition = new Vector2(pageSettings.PageSize.WidthPu / 2d, pageSettings.Margins.FooterPu);
cf.AdjustPositionByTextLength('c', 'f');
- var rf = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(rightF, ws, settings, dictionaries, pageNumber, pages.ChildObjects.Count));
- rf.LocalPosition = new Vector2(settings.PageSize.WidthPu - settings.Margins.RightPu, settings.Margins.FooterPu);
+ var rf = (PdfHeaderFooterLayout)pages.ChildObjects[i].AddChild(new PdfHeaderFooterLayout(rightF, ws, pageSettings, dictionaries, pageNumber, pages.ChildObjects.Count));
+ rf.Name = "RightFooter";
+ rf.LocalPosition = new Vector2(pageSettings.PageSize.WidthPu - pageSettings.Margins.RightPu, pageSettings.Margins.FooterPu);
rf.AdjustPositionByTextLength('r', 'f');
pageNumber++;
}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellBorderLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellBorderLayout.cs
index 7f3f20c90..20280fd57 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellBorderLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellBorderLayout.cs
@@ -11,34 +11,30 @@ Date Author Change
27/11/2025 EPPlus Software AB EPPlus 9
*************************************************************************************************/
using EPPlus.Export.Pdf.Pdfhelpers;
-using EPPlus.Export.Pdf.PdfSettings;
using EPPlus.Graphics;
-using EPPlus.Graphics.Math;
using OfficeOpenXml;
-using OfficeOpenXml.Core.Worksheet.XmlWriter;
-using OfficeOpenXml.FormulaParsing.Excel.Functions;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using OfficeOpenXml.Style;
using OfficeOpenXml.Style.Dxf;
using OfficeOpenXml.Style.Table;
using OfficeOpenXml.Table;
-using System.Drawing;
+using System.Diagnostics;
namespace EPPlus.Export.Pdf.PdfLayout
{
+ [DebuggerDisplay("Border: {Name}")]
internal class PdfCellBorderLayout : Transform , IBorderLayout
{
public PdfCellBordersData BorderData;
public bool IsMerged = false;
+ public ExcelRangeBase cell;
public string range;
- internal PdfCellStyleOverride TableStyle;
+ internal PdfCellStyle TableStyle;
public PdfCellBorderLayout() { }
- public PdfCellBorderLayout(ExcelRangeBase cell, PdfCellStyleOverride tableStyle, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null)
+ public PdfCellBorderLayout(ExcelRangeBase cell, PdfCellStyle tableStyle, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null)
: base(x, y-height, width, height, scaleX, scaleY, rotation, parent)
{
this.cell = cell;
@@ -178,6 +174,12 @@ public void UpdateLocalBorderPosition()
Last Total Cell
*/
+
+
+ /*
+ * Following methods needs to be refactored into 1 method.
+ * Less code is more good.
+ */
public static ExcelDxfBorderItem GetTopBorderItem(ExcelRangeBase cell, ExcelBorderItem xfBorder, ExcelTable table, ExcelTableNamedStyle tableStyle)
{
var range = table.Range;
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellContentLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellContentLayout.cs
index b2213b74f..8feb06240 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellContentLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellContentLayout.cs
@@ -10,71 +10,76 @@ Date Author Change
*************************************************************************************************
27/11/2025 EPPlus Software AB EPPlus 9
*************************************************************************************************/
-using EPPlus.Export.Pdf.Pdfhelpers;
using EPPlus.Export.Pdf.PdfResources;
using EPPlus.Export.Pdf.PdfSettings;
using EPPlus.Fonts.OpenType;
+using EPPlus.Fonts.OpenType.Integration;
using EPPlus.Graphics;
-using EPPlus.Graphics.Math;
using OfficeOpenXml;
using OfficeOpenXml.Interfaces.Drawing.Text;
+using OfficeOpenXml.Interfaces.Fonts;
using OfficeOpenXml.Style;
+using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
+using System.Xml.Serialization;
+using Vector2 = EPPlus.Graphics.Math.Vector2;
namespace EPPlus.Export.Pdf.PdfLayout
{
- internal class PdfCellContentLayout : Transform
+ [DebuggerDisplay("Content: {Name}")]
+ internal class PdfCellContentLayout : Transform, ITextLayout
{
public PdfCellLines Lines = new PdfCellLines();
public PdfCellAlignmentData CellAlignmentData;
public bool Clip;
public Rect Clipping;
- public PdfCellStyleOverride CellStyle;
-
+ public PdfCellStyle CellStyle;
+ public ExcelRangeBase cell;
+ public TextLayoutEngine textLayoutEngine;
+ private List textFormats = new List();
+ private double textLength = 0;
+ private double textHeight = 0;
+ public double LeftTextSpillLength = 0d;
+ public double RightTextSpillLength = 0d;
private double bottomMargin = 3.5d; //Guessed number
private double rightMargin = 1.4d; //I guessed this one too..
+ //internal static FontMeasurerTrueType fontMeasurerTrueType = new FontMeasurerTrueType();
+ //internal static MeasurementFont font = new MeasurementFont();
- internal static FontMeasurerTrueType fontMeasurerTrueType = new FontMeasurerTrueType();
- internal static MeasurementFont font = new MeasurementFont();
+ public List TextFormats { get => textFormats; set => textFormats = value; }
+ public double TextLength { get => textLength; set => textLength = value; }
+ public double TextHeight { get => textHeight; set => textHeight = value; }
+ public TextLayoutEngine TextLayoutEngine { get => textLayoutEngine; set => textLayoutEngine = value; }
- public PdfCellContentLayout(ExcelRangeBase cell, PdfCellStyleOverride CellStyle, PdfPageSettings pageSettings, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null, PdfDictionaries dictionaries = null)
+ public PdfCellContentLayout(ExcelRangeBase cell, PdfCellStyle CellStyle, PdfPageSettings pageSettings, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null, PdfDictionaries dictionaries = null)
: base(x, y, width, height, scaleX, scaleY, rotation, parent)
{
this.cell = cell;
this.CellStyle = CellStyle;
- if (cell.IsRichText)
- {
- //HandleRichText(pageSettings, dictionaries, width, height, x, cell.Style.TextRotation);
- HandleRichText(pageSettings, dictionaries, x, y, width, height, cell.Style.TextRotation, CellStyle);
- }
- else
- {
- cell._rtc = new ExcelRichTextCollection(cell.Text, cell);
- HandleRichText(pageSettings, dictionaries, x, y, width, height, cell.Style.TextRotation, CellStyle);
- //HandleText(pageSettings, dictionaries, x, y, width, height, cell.Style.TextRotation);
- }
CellAlignmentData = new PdfCellAlignmentData();
CellAlignmentData.HorizontalAlignment = cell.Style.HorizontalAlignment;
CellAlignmentData.VerticalAlignment = cell.Style.VerticalAlignment;
CellAlignmentData.Indent = cell.Style.Indent;
CellAlignmentData.WrapText = cell.Style.WrapText;
- CellAlignmentData.ShrinkToFit = cell.Style.ShrinkToFit; //Need to fix Transform issues and then implement a method that sets scale on the text object.
+ CellAlignmentData.ShrinkToFit = cell.Style.ShrinkToFit;
CellAlignmentData.TextRotation = (cell.Style.TextRotation >= 90) ? ((cell.Style.TextRotation == 255) ? 0 : 90 - cell.Style.TextRotation) : cell.Style.TextRotation;
CellAlignmentData.IsVertical = cell.Style.TextRotation == 255 ? true : false;
CellAlignmentData.TextDirection = cell.Style.ReadingOrder;
+ if (!cell.IsRichText) cell._rtc = new ExcelRichTextCollection(cell.Text, cell);
+ HandleText(pageSettings, dictionaries, x, y, width, height, CellAlignmentData.TextRotation, CellStyle);
+ CalculateTextSpill(width, CellAlignmentData.TextRotation);
LocalPosition = CalculateAlignmentPositionAndTextOffsets(cell, x, y, width, height);
- Size = new Vector2(x + width - LocalPosition.X, y + height - LocalPosition.Y);
- CheckClipping(cell, width);
+ Size = new Vector2(x + width - LocalPosition.X, y + height - LocalPosition.Y);
+ CheckClipping(cell, x, y, width, height);
}
- private void HandleRichText(PdfPageSettings pageSettings, PdfDictionaries dictionaries, double x, double y, double maxWidth, double maxHeight, double rotation, PdfCellStyleOverride CellStyle)
+ private void HandleText(PdfPageSettings pageSettings, PdfDictionaries dictionaries, double x, double y, double maxWidth, double maxHeight, double rotation, PdfCellStyle CellStyle)
{
- List characters = new List();
- List Words = new List();
bool bold = false, italic = false, underline = false, strike = false;
ExcelUnderLineType underLineType = ExcelUnderLineType.None;
- if(CellStyle.dxfFont != null)
+ if (CellStyle.dxfFont != null)
{
bold = CellStyle.dxfFont.Bold != null ? (bool)CellStyle.dxfFont.Bold : false;
italic = CellStyle.dxfFont.Italic != null ? (bool)CellStyle.dxfFont.Italic : false;
@@ -85,219 +90,113 @@ private void HandleRichText(PdfPageSettings pageSettings, PdfDictionaries dictio
for (int i = 0; i < cell.RichText.Count; i++)
{
var rt = cell.RichText[i];
- for (int j = 0; j < rt.Text.Length; j++)
+ var textformat = new PdfTextFormat();
+ textformat.Text = rt.Text;
+ textformat.FontName = rt.FontName;
+ textformat.FontFamily = rt.Family;
+ textformat.FontSize = rt.Size;
+ textformat.Bold = rt.Bold || bold;
+ textformat.Italic = rt.Italic || italic;
+ textformat.Strike = rt.Strike || strike;
+ textformat.Underline = rt.UnderLine || underline;
+ textformat.UnderlineType = rt.UnderLineType == ExcelUnderLineType.None ? underLineType : rt.UnderLineType;
+ textformat.SuperScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Superscript;
+ textformat.SubScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Subscript;
+ textformat.FontColor = rt.Color;
+ textformat.SubFamily = FontSubFamily.Regular;
+ if (textformat.Bold)
{
- var character = new PdfCellTextItem();
- character.Text = rt.Text[j].ToString();
- character.FontName = rt.FontName;
- character.FontFamily = rt.Family;
- character.FontSize = rt.Size;
- character.Bold = rt.Bold || bold;
- character.Italic = rt.Italic || italic;
- character.Strike = rt.Strike || strike;
- character.Underline = rt.UnderLine || underline;
- character.UnderlineType = rt.UnderLineType == ExcelUnderLineType.None ? underLineType : rt.UnderLineType;
- character.SuperScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Superscript;
- character.SubScript = rt.VerticalAlign == ExcelVerticalAlignmentFont.Subscript;
- character.FontColor = rt.Color;
- character.SubFamily = FontSubFamily.Regular;
- if (character.Bold)
+ textformat.SubFamily = FontSubFamily.Bold;
+ if (textformat.Italic)
{
- character.SubFamily = FontSubFamily.Bold;
- if (character.Italic)
- {
- character.SubFamily = FontSubFamily.BoldItalic;
- }
+ textformat.SubFamily = FontSubFamily.BoldItalic;
}
- else if (character.Italic)
- {
- character.SubFamily = FontSubFamily.Italic;
- }
- font.FontFamily = character.FontName;
- font.Size = (float)character.FontSize;
- font.Style = ((cell.Style.Font.Bold ? MeasurementFontStyles.Bold : 0) |
- (cell.Style.Font.Italic ? MeasurementFontStyles.Italic : 0) |
- (cell.Style.Font.Strike ? MeasurementFontStyles.Strikeout : 0) |
- (cell.Style.Font.UnderLine ? MeasurementFontStyles.Underline : 0))
- switch
- {
- 0 => MeasurementFontStyles.Regular,
- var s => s
- };
- var result = fontMeasurerTrueType.MeasureText(character.Text, font);
- character.TextLength = result.Width;
- character.LineHeight = result.Height;
- character.FontHeight = result.FontHeight;
- var fontData = GetFontResourceData(dictionaries.Fonts, pageSettings, character);
- double gbox = (fontData.Os2Table.sTypoAscender - fontData.Os2Table.sTypoDescender) * (cell.Style.Font.Size / fontData.HeadTable.UnitsPerEm);
- character.GlyphBox = new Rect();
- character.GlyphBox.Width = gbox;
- character.GlyphBox.Height = gbox;
- character.characterOffset = (x + (character.GlyphBox.Width - result.Width) / 2d) - x;
- characters.Add(character);
- }
- }
- var w = new PdfCellWord();
- for (int i = 0; i < characters.Count; i++)
- {
- var t = characters[i];
- if (char.IsWhiteSpace(t.Text[0]))
- {
- Words.Add(w);
- w = new PdfCellWord();
- w.Characters.Add(t);
- Words.Add(w);
- w = new PdfCellWord();
}
- else
+ else if (textformat.Italic)
{
- w.Characters.Add(t);
+ textformat.SubFamily = FontSubFamily.Italic;
}
- if (i == characters.Count - 1)
+
+ this.textFormats.Add(textformat);
+ if (!dictionaries.Fonts.ContainsKey(textformat.FullFontName))
{
- Words.Add(w);
+ int label = 1;
+ if (dictionaries.Fonts.Count > 0)
+ {
+ label = dictionaries.Fonts.Last().Value.labelNumber + 1;
+ }
+ dictionaries.Fonts.Add(textformat.FullFontName, new PdfFontResource(textformat.FontName, textformat.SubFamily, label, pageSettings));
}
+ var manger = dictionaries.Fonts[textformat.FullFontName].fontSubsetManager;
+ manger.AddText(textformat.Text);
}
- if (rotation == 255)
+ }
+
+ private void CalculateTextSpill(double maxWidth, double rotation)
+ {
+ if (maxWidth < textLength)
{
- Lines.WritingMode = PdfWritingMode.VerticalTtb;
- if (cell.Style.WrapText)
+ if (rotation != 0)
{
- double lineHeight = 0d;
- var line = new PdfCellLine();
- for (int i = 0; i < Words.Count; i++)
+ var baseVec = new Vector2(textLength, 0);
+ var rad = rotation * Math.PI / 180.0d;
+ var rotVec = new Vector2(textLength * Math.Cos(rad), textLength * Math.Sin(rad));
+ var length = Vector2.Project(rotVec, baseVec).Length;
+ if (length > maxWidth)
{
- if (Words[i].TextHeight > maxHeight)
+ if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.General)
{
- double lineCount = Words[i].TextHeight / maxHeight;
- int currentIndex = 0;
- while (lineCount > 0)
+ if (double.TryParse(cell.Value.ToString(), out double value))
+ {
+ LeftTextSpillLength = textLength;
+ }
+ else
{
- PdfCellWord newWord = new PdfCellWord();
- double wordlength = 0;
- for (int j = currentIndex; j < Words[i].Characters.Count; j++)
- {
- if (wordlength + Words[i].Characters[j].LineHeight > maxHeight)
- {
- currentIndex = j;
- break;
- }
- else
- {
- newWord.Characters.Add(Words[i].Characters[j]);
- wordlength += Words[i].Characters[j].LineHeight;
- }
- }
- line.Words.Add(newWord);
- Lines.Lines.Add(line);
- lineCount--;
- line = new PdfCellLine();
+ RightTextSpillLength = textLength;
}
}
- else if (lineHeight + Words[i].TextHeight < maxHeight)
+ else if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Left)
{
- lineHeight += Words[i].TextHeight;
- line.Words.Add(Words[i]);
+ RightTextSpillLength = length;
}
- else
+ else if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Right)
{
- Lines.Lines.Add(line);
- lineHeight = Words[i].TextHeight;
- line = new PdfCellLine();
- line.Words.Add(Words[i]);
+ LeftTextSpillLength = length;
}
+ else if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Center)
+ {
+ LeftTextSpillLength = length / 2d;
+ RightTextSpillLength = length / 2d;
+ }
+
}
- Lines.Lines.Add(line);
+ return;
}
- else
+ if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.General)
{
- var line = new PdfCellLine();
- foreach (var word in Words)
+ if (double.TryParse(cell.Value.ToString(), out double value))
{
- line.Words.Add(word);
+ LeftTextSpillLength = textLength - Size.X;
}
- Lines.Lines.Add(line);
- }
- }
- else
- {
- Lines.WritingMode = PdfWritingMode.HorizontalLtr;
- if (cell.Style.WrapText)
- {
- double lineLength = 0d;
- var line = new PdfCellLine();
- for (int i = 0; i < Words.Count; i++)
+ else
{
- if (Words[i].TextLength > maxWidth)
- {
- double lineCount = Words[i].TextLength / maxWidth;
- int currentIndex = 0;
- while (lineCount > 0)
- {
- PdfCellWord newWord = new PdfCellWord();
- double wordlength = 0;
- for (int j = currentIndex; j < Words[i].Characters.Count; j++)
- {
- if (wordlength + Words[i].Characters[j].TextLength > maxWidth)
- {
- currentIndex = j;
- break;
- }
- else
- {
- newWord.Characters.Add(Words[i].Characters[j]);
- wordlength += Words[i].Characters[j].TextLength;
- }
- }
- line.Words.Add(newWord);
- Lines.Lines.Add(line);
- lineCount--;
- line = new PdfCellLine();
- }
- }
- else if (lineLength + Words[i].TextLength < maxWidth)
- {
- lineLength += Words[i].TextLength;
- line.Words.Add(Words[i]);
- }
- else
- {
- Lines.Lines.Add(line);
- lineLength = Words[i].TextLength;
- line = new PdfCellLine();
- line.Words.Add(Words[i]);
- }
+ RightTextSpillLength = textLength - Size.X;
}
- Lines.Lines.Add(line);
}
- else
+ else if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Left)
{
- var line = new PdfCellLine();
- foreach (var word in Words)
- {
- line.Words.Add(word);
- }
- Lines.Lines.Add(line);
+ RightTextSpillLength = textLength - Size.X;
}
- }
- Lines.Lines.RemoveAll(l => l.Words.Count <= 0);
- }
-
- //Get font data from fontResources. If font does not exsist, add it to fontResources.
- private OpenTypeFont GetFontResourceData(Dictionary fontResources, PdfPageSettings pageSettings, PdfCellTextItem FontData)
- {
- if (!fontResources.ContainsKey(FontData.FullFontName))
- {
- int label = 1;
- if (fontResources.Count > 0)
+ else if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Right)
{
- label = fontResources.Last().Value.labelNumber + 1;
+ LeftTextSpillLength = textLength - Size.X;
+ }
+ else if (CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Center)
+ {
+ LeftTextSpillLength = (textLength - Size.X) / 2d;
+ RightTextSpillLength = (textLength - Size.X) / 2d;
}
- PdfFontResource fr = new PdfFontResource(FontData.FontName, FontData.SubFamily, label, pageSettings);
- fontResources.Add(FontData.FullFontName, fr);
- fontResources.Last().Value.fontData = PdfTextData.GetFontData(pageSettings, FontData.FontName, FontData.SubFamily);
}
- return fontResources[FontData.FullFontName].fontData;
}
//Calculate text position from alignment and offsets for each line of text.
@@ -307,58 +206,58 @@ private Vector2 CalculateAlignmentPositionAndTextOffsets(ExcelRangeBase cell, do
double y = 0d;
double xOffset = 0d;
double yOffset = 0d;
- double textLength = Lines.TextLength;
- double textHeight = Lines.TextHeight;
- double fontHeight = Lines.FontHeight;
- double lineHeight = Lines.LineHeight;
- if (CellAlignmentData.IsVertical)
- {
+ //double textLength = Lines.TextLength;
+ //double textHeight = Lines.TextHeight;
+ //double fontHeight = Lines.FontHeight;
+ //double lineHeight = Lines.LineHeight;
+ //if (CellAlignmentData.IsVertical)
+ //{
//Need to place vertical text a bit better. It appears each character is monospaced when using vertical. so we should define a common glyphbox that we then use for placing and measuring vertical text.
- switch (CellAlignmentData.HorizontalAlignment)
- {
- case ExcelHorizontalAlignment.Left:
- x = cellX + rightMargin;
- break;
- case ExcelHorizontalAlignment.Fill:
- case ExcelHorizontalAlignment.General:
- case ExcelHorizontalAlignment.Center:
- x = cellX + (cellWidth - Lines.Height) / 2d;
- break;
- case ExcelHorizontalAlignment.Right:
- x = cellX + (cellWidth - Lines.Height) - rightMargin;
- break;
- }
- switch (CellAlignmentData.VerticalAlignment)
- {
- case ExcelVerticalAlignment.Top:
- y = (CellY + cellHeight) - (fontHeight / 2d) - bottomMargin;
- break;
- case ExcelVerticalAlignment.Center:
- y = CellY + (cellHeight / 2d) + (Lines.Lines[0].TextHeight / 4d);
- break;
- case ExcelVerticalAlignment.Bottom:
- y = CellY + (Lines.Lines[0].TextHeight - Lines.Lines[0].Words[0].Characters[0].LineHeight) + bottomMargin;
- break;
- }
- for (int i = 1; i < Lines.Lines.Count; i++)
- {
- //xOffset += Lines.LineHeight;
- switch (CellAlignmentData.VerticalAlignment)
- {
- case ExcelVerticalAlignment.Top:
- Lines.Lines[i].Offset = 0d;
- break;
- case ExcelVerticalAlignment.Center:
- Lines.Lines[i].Offset = CellY + (cellHeight / 2d) + (Lines.Lines[i].TextHeight / 4d) - y;
- break;
- case ExcelVerticalAlignment.Bottom:
- Lines.Lines[i].Offset = (CellY + (Lines.Lines[i].TextHeight - Lines.Lines[i].Words[0].Characters[0].LineHeight) + bottomMargin) - y;
- break;
- }
- }
- }
- else
- {
+ //switch (CellAlignmentData.HorizontalAlignment)
+ //{
+ //case ExcelHorizontalAlignment.Left:
+ // x = cellX + rightMargin;
+ // break;
+ //case ExcelHorizontalAlignment.Fill:
+ //case ExcelHorizontalAlignment.General:
+ //case ExcelHorizontalAlignment.Center:
+ // x = cellX + (cellWidth - Lines.Height) / 2d;
+ // break;
+ //case ExcelHorizontalAlignment.Right:
+ // x = cellX + (cellWidth - Lines.Height) - rightMargin;
+ // break;
+ //}
+ //switch (CellAlignmentData.VerticalAlignment)
+ //{
+ // case ExcelVerticalAlignment.Top:
+ // y = (CellY + cellHeight) - (fontHeight / 2d) - bottomMargin;
+ // break;
+ // case ExcelVerticalAlignment.Center:
+ // y = CellY + (cellHeight / 2d) + (Lines.Lines[0].TextHeight / 4d);
+ // break;
+ // case ExcelVerticalAlignment.Bottom:
+ // y = CellY + (Lines.Lines[0].TextHeight - Lines.Lines[0].Words[0].Characters[0].LineHeight) + bottomMargin;
+ // break;
+ //}
+ //for (int i = 1; i < Lines.Lines.Count; i++)
+ //{
+ // //xOffset += Lines.LineHeight;
+ // switch (CellAlignmentData.VerticalAlignment)
+ // {
+ // case ExcelVerticalAlignment.Top:
+ // Lines.Lines[i].Offset = 0d;
+ // break;
+ // case ExcelVerticalAlignment.Center:
+ // Lines.Lines[i].Offset = CellY + (cellHeight / 2d) + (Lines.Lines[i].TextHeight / 4d) - y;
+ // break;
+ // case ExcelVerticalAlignment.Bottom:
+ // Lines.Lines[i].Offset = (CellY + (Lines.Lines[i].TextHeight - Lines.Lines[i].Words[0].Characters[0].LineHeight) + bottomMargin) - y;
+ // break;
+ // }
+ //}
+ //}
+ //else
+ //{
switch (CellAlignmentData.HorizontalAlignment)
{
case ExcelHorizontalAlignment.Fill:
@@ -385,10 +284,10 @@ private Vector2 CalculateAlignmentPositionAndTextOffsets(ExcelRangeBase cell, do
switch (CellAlignmentData.VerticalAlignment)
{
case ExcelVerticalAlignment.Top:
- y = (CellY + cellHeight) - (fontHeight / 2d) - bottomMargin;
+ y = (CellY + cellHeight) - (textHeight / 2d) - bottomMargin;
break;
case ExcelVerticalAlignment.Center:
- y = CellY + (cellHeight / 2d) - (lineHeight / 4d); ;
+ y = CellY + (cellHeight / 2d) - (textHeight / 4d); ;
break;
case ExcelVerticalAlignment.Bottom:
y = CellY + bottomMargin;
@@ -405,48 +304,54 @@ private Vector2 CalculateAlignmentPositionAndTextOffsets(ExcelRangeBase cell, do
double rot = CellAlignmentData.TextRotation * System.Math.PI / 180.0;
x += textLength * (1 - System.Math.Cos(rot));
}
- for (int i = 1; i < Lines.Lines.Count; i++)
- {
- yOffset += Lines.LineHeight;
- switch (CellAlignmentData.HorizontalAlignment)
- {
- case ExcelHorizontalAlignment.Fill:
- case ExcelHorizontalAlignment.General:
- if (double.TryParse(cell.Value.ToString(), out double value))
- {
- Lines.Lines[i].Offset = -Lines.Lines[i].TextLength;
- }
- else
- {
- Lines.Lines[i].Offset = 0d;
- }
- break;
- case ExcelHorizontalAlignment.Left:
- Lines.Lines[i].Offset = 0d;
- break;
- case ExcelHorizontalAlignment.Center:
- Lines.Lines[i].Offset = (cellX + (cellWidth - Lines.Lines[i].TextLength) / 2d) - x;
- break;
- case ExcelHorizontalAlignment.Right:
- Lines.Lines[i].Offset = (cellX + (cellWidth - Lines.Lines[i].TextLength) - rightMargin) - x;
- break;
- }
- }
- }
- return new Vector2(x + xOffset, y + yOffset);
+ //for (int i = 1; i < Lines.Lines.Count; i++)
+ //{
+ // yOffset += Lines.LineHeight;
+ // switch (CellAlignmentData.HorizontalAlignment)
+ // {
+ // case ExcelHorizontalAlignment.Fill:
+ // case ExcelHorizontalAlignment.General:
+ // if (double.TryParse(cell.Value.ToString(), out double value))
+ // {
+ // Lines.Lines[i].Offset = -Lines.Lines[i].TextLength;
+ // }
+ // else
+ // {
+ // Lines.Lines[i].Offset = 0d;
+ // }
+ // break;
+ // case ExcelHorizontalAlignment.Left:
+ // Lines.Lines[i].Offset = 0d;
+ // break;
+ // case ExcelHorizontalAlignment.Center:
+ // Lines.Lines[i].Offset = (cellX + (cellWidth - Lines.Lines[i].TextLength) / 2d) - x;
+ // break;
+ // case ExcelHorizontalAlignment.Right:
+ // Lines.Lines[i].Offset = (cellX + (cellWidth - Lines.Lines[i].TextLength) - rightMargin) - x;
+ // break;
+ // }
+ //}
+ //}
+ return new Vector2(x, y);
}
//Check if clipping is needed.
- private void CheckClipping(ExcelRangeBase cell, double width)
+ private void CheckClipping(ExcelRangeBase cell, double x, double y, double width, double height)
{
- if (Lines.TextLength >= width || cell.Merge)
+ if (textLength >= width || cell.Merge)
{
if (cell.Merge ||
- CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Fill ||
- CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Left && cell.Worksheet.Cells[cell._fromRow, cell._fromCol + 1].Value != null ||
- CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Right && cell.Worksheet.Cells[cell._fromRow, cell._fromCol - 1 <= 0 ? 1 : cell._fromCol - 1].Value != null)
+ CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Fill )
+ //CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Left && cell.Worksheet.Cells[cell._fromRow, cell._fromCol + 1].Value != null ||
+ //CellAlignmentData.HorizontalAlignment == ExcelHorizontalAlignment.Right && cell.Worksheet.Cells[cell._fromRow, cell._fromCol - 1 <= 0 ? 1 : cell._fromCol - 1].Value != null)
{
- Clip = true;
+ Clipping = new Rect()
+ {
+ X = x + rightMargin,
+ Y = y,
+ Width = width - rightMargin * 2,
+ Height = height
+ };
}
}
}
@@ -470,5 +375,56 @@ internal void CreateClippingRect(List cells)
}
}
}
+
+ //Create clipping rectangle.
+ internal void CreateClippingRect(PdfCellLayout cell, double targetX)
+ {
+ //need a way to detect starting X position if text is spilled from left or right
+ var width = targetX - cell.LocalPosition.X;
+ Clipping = new Rect()
+ {
+ X = cell.LocalPosition.X + rightMargin,
+ Y = cell.LocalPosition.Y,
+ Width = width - rightMargin * 2,
+ Height = cell.Size.Y
+ };
+ }
+
+ internal void GidsAndCharMap(PdfDictionaries dictionaries)
+ {
+ foreach (var tf in TextFormats)
+ {
+ var usedFonts = tf.UsedFonts;
+
+ foreach (var glyph in tf.ShapedText.Glyphs)
+ {
+ if (glyph.FontId >= usedFonts.Count)
+ continue;
+
+ var font = usedFonts[glyph.FontId];
+
+ dictionaries.Fonts[font.FullName].Gids.Add(glyph.GlyphId);
+ dictionaries.Fonts[font.FullName].fontData = font;
+
+ if (!dictionaries.Fonts[font.FullName].charactermappings.ContainsKey(glyph.GlyphId))
+ {
+ var chars = ExtractCharactersForGlyph(glyph, tf.Text);
+ if (!string.IsNullOrEmpty(chars))
+ {
+ dictionaries.Fonts[font.FullName].charactermappings[glyph.GlyphId] = chars;
+ }
+ }
+ }
+ }
+ }
+ private string ExtractCharactersForGlyph(ShapedGlyph glyph, string textLine)
+ {
+ var chars = new System.Text.StringBuilder();
+ for (int i = 0; i < glyph.CharCount && glyph.ClusterIndex + i < textLine.Length; i++)
+ {
+ chars.Append(textLine[glyph.ClusterIndex + i]);
+ }
+ return chars.ToString();
+ }
}
}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellData.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellData.cs
index 96cbd3957..ce68e2958 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellData.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellData.cs
@@ -12,11 +12,16 @@ Date Author Change
*************************************************************************************************/
using EPPlus.Export.Pdf.Pdfhelpers;
using EPPlus.Fonts.OpenType;
+using EPPlus.Fonts.OpenType.Integration;
using EPPlus.Graphics;
+using OfficeOpenXml.Interfaces.Fonts;
using OfficeOpenXml.Style;
using System.Collections.Generic;
using System.Drawing;
+/*
+ * This file could probably be trimmed a lot and remove unnessacry stuff.
+ */
namespace EPPlus.Export.Pdf.PdfLayout
{
public enum PdfWritingMode
@@ -192,7 +197,7 @@ public double FontHeight
internal class PdfCellWord
{
- public List Characters = new List();
+ public List Characters = new List();
private string _text = null;
public string Text
{
@@ -257,8 +262,15 @@ public double FontHeight
}
}
- internal struct PdfCellTextItem
+ internal struct PdfTextFormat
{
+ public IFontProvider FontProvider;
+ //sometimes a font can have other fonts for certain characters. Key as the glyph id, Value is the font label.
+ //public Dictionary FontIDLabel;
+ public Dictionary FontIdMap;
+ public List UsedFonts;
+ public ShapedText ShapedText;
+
public string FontName;
public int FontFamily;
public FontSubFamily SubFamily;
@@ -273,16 +285,27 @@ internal struct PdfCellTextItem
public string Text;
public Color FontColor;
public double TextLength;
+ public double TextHeight;
public double LineHeight;
public double FontHeight;
public Rect GlyphBox;
public double characterOffset;
public List GlyphPositions;
public string FullFontName
- { get { return FontName + " " + SubFamily; } }
+ {
+ get
+ {
+ string subfam = " " + SubFamily.ToString();
+ if (SubFamily == FontSubFamily.Regular)
+ subfam = "";
+ else if (SubFamily == FontSubFamily.BoldItalic)
+ subfam = " Bold Italic";
+ return FontName + subfam;
+ }
+ }
//Compares stylings.
- public bool Equals(PdfCellTextItem other)
+ public bool Equals(PdfTextFormat other)
{
if (!string.Equals(FontName, other.FontName))
return false;
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellLayout.cs
index 9fec5a87a..72adc9884 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellLayout.cs
@@ -10,29 +10,36 @@ Date Author Change
*************************************************************************************************
27/11/2025 EPPlus Software AB EPPlus 9
*************************************************************************************************/
-using EPPlus.Graphics;
-using EPPlus.Graphics.Math;
-using System.Drawing;
+using EPPlus.Export.Pdf.Pdfhelpers;
using EPPlus.Export.Pdf.PdfResources;
using EPPlus.Export.Pdf.PdfSettings;
+using EPPlus.Graphics;
+using EPPlus.Graphics.Math;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
using System.Linq;
-using EPPlus.Export.Pdf.Pdfhelpers;
namespace EPPlus.Export.Pdf.PdfLayout
{
+ [DebuggerDisplay("Cell: {Name}")]
internal class PdfCellLayout : Transform, IShadingLayout
{
+ public ExcelRangeBase cell;
public PdfCellFillData CellFillData;
- public PdfCellStyleOverride CellStyle;
+ public PdfCellStyle CellStyle;
+ public double LeftTextSpillLength = 0d;
+ public double RightTextSpillLength = 0d;
+ public bool delete = false;
- public PdfCellLayout(PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyleOverride CellStyle, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null)
+ public PdfCellLayout(PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyle CellStyle, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null)
: base(x, y-height, width, height, scaleX, scaleY, rotation, parent)
{
if (cell != null)
{
+ this.cell = cell;
this.CellStyle = CellStyle;
var xfFill = CellStyle.xfFill;
var dxfFill = CellStyle.dxfFill;
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfCellStyle.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellStyle.cs
new file mode 100644
index 000000000..5fb4817b8
--- /dev/null
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfCellStyle.cs
@@ -0,0 +1,41 @@
+using System;
+using EPPlus.Export.Pdf.Pdfhelpers;
+using OfficeOpenXml;
+using OfficeOpenXml.Style;
+using OfficeOpenXml.Style.Dxf;
+
+namespace EPPlus.Export.Pdf.PdfLayout
+{
+ ///
+ /// Holds the styles for the cell.
+ /// xf styles is the base style and dxf styles is an override(sort of) that can come from tables or conditional formatting.
+ /// They are used in the following priority:
+ /// 1. xf style that is not default
+ /// 2. dxf style if it exsist
+ /// 3. deault xf style
+ ///
+ internal class PdfCellStyle
+ {
+ //Fill
+ internal ExcelFill xfFill { get; set; }
+ internal ExcelDxfFill dxfFill { get; set; }
+
+ //Borders
+ internal ExcelBorderItem xfTop { get; set; }
+ internal ExcelBorderItem xfBottom { get; set; }
+ internal ExcelBorderItem xfLeft { get; set; }
+ internal ExcelBorderItem xfRight { get; set; }
+ internal ExcelBorderItem xfDiagonalUp { get; set; }
+ internal ExcelBorderItem xfDiagonalDown { get; set; }
+ internal ExcelDxfBorderItem dxfTop { get; set; }
+ internal ExcelDxfBorderItem dxfBottom { get; set; }
+ internal ExcelDxfBorderItem dxfLeft { get; set; }
+ internal ExcelDxfBorderItem dxfRight { get; set; }
+ internal ExcelDxfBorderItem dxfHorizontal { get; set; }
+ internal ExcelDxfBorderItem dxfVertical { get; set; }
+
+ //Fonts
+ internal ExcelFont xfFont { get; set; }
+ internal ExcelDxfFontBase dxfFont { get; set; }
+ }
+}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfContentLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfContentLayout.cs
index 90a33d1b9..c3bf49b4d 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfContentLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfContentLayout.cs
@@ -16,6 +16,9 @@ Date Author Change
namespace EPPlus.Export.Pdf.PdfLayout
{
+ ///
+ /// Represents the content area for a page in the pdf document.
+ ///
internal class PdfContentLayout : Transform
{
public PdfContentLayout(double x, double y, PdfContentBounds bounds)
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfDrawingLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfDrawingLayout.cs
index 33d59df65..9d89c81e2 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfDrawingLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfDrawingLayout.cs
@@ -16,6 +16,7 @@ Date Author Change
namespace EPPlus.Export.Pdf.PdfLayout
{
+ //NOT IMPLEMENTED YET.
internal class PdfDrawingLayout : Transform
{
public ExcelDrawing Drawing;
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfHeaderFooterLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfHeaderFooterLayout.cs
index d211aa04d..8730fa24d 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfHeaderFooterLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfHeaderFooterLayout.cs
@@ -10,120 +10,144 @@ Date Author Change
*************************************************************************************************
27/11/2025 EPPlus Software AB EPPlus 9
*************************************************************************************************/
-using EPPlus.Export.Pdf.Pdfhelpers;
using EPPlus.Export.Pdf.PdfResources;
using EPPlus.Export.Pdf.PdfSettings;
using EPPlus.Fonts.OpenType;
+using EPPlus.Fonts.OpenType.Integration;
using EPPlus.Graphics;
using EPPlus.Graphics.Math;
using OfficeOpenXml;
using OfficeOpenXml.Interfaces.Drawing.Text;
+using OfficeOpenXml.Interfaces.Fonts;
+using OfficeOpenXml.Style;
using OfficeOpenXml.Style.HeaderFooterTextFormat;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text;
+using static System.Net.Mime.MediaTypeNames;
namespace EPPlus.Export.Pdf.PdfLayout
{
- internal class PdfHeaderFooterLayout : Transform
+ internal class PdfHeaderFooterLayout : Transform, ITextLayout
{
- public PdfCellWord textLine = new PdfCellWord();
+ private List textFormats = new List();
+ private double textLength { get; set; }
+ private double textHeight { get; set; }
+ private TextLayoutEngine textLayoutEngine;
- public PdfHeaderFooterLayout(ExcelHeaderFooterTextCollection textCollection, ExcelWorksheet ws, PdfPageSettings settings, PdfDictionaries dictionaries, int pageNumber, int totalPages)
+ public List TextFormats { get => textFormats; set => textFormats = value; }
+ public double TextLength { get => textLength; set => textLength = value; }
+ public double TextHeight { get => textHeight; set => textHeight = value; }
+ public TextLayoutEngine TextLayoutEngine { get => textLayoutEngine; set => textLayoutEngine = value; }
+
+ public PdfHeaderFooterLayout(ExcelHeaderFooterTextCollection textCollection, ExcelWorksheet ws, PdfPageSettings pageSettings, PdfDictionaries dictionaries, int pageNumber, int totalPages)
{
for( int i=1; i < textCollection.Count; i++)
{
var text = textCollection[i];
var ns = ws.Workbook.Styles.GetNormalStyle();
- PdfCellTextItem textItem = new PdfCellTextItem();
- textItem.FontName = string.IsNullOrEmpty( text.FontName) ? ns.Style.Font.Name : text.FontName;
- textItem.FontSize = text.FontSize == null ? ns.Style.Font.Size : (double)text.FontSize;
- textItem.Bold = text.Bold;
- textItem.Italic = text.Italic;
- textItem.Strike = text.Striketrough;
- textItem.SubScript = text.SubScript;
- textItem.SuperScript = text.SuperScript;
- textItem.Underline = text.Underline;
- textItem.FontColor = text.Color;
+ PdfTextFormat textFormat = new PdfTextFormat();
+ textFormat.FontName = string.IsNullOrEmpty( text.FontName) ? ns.Style.Font.Name : text.FontName;
+ textFormat.FontSize = text.FontSize == null ? ns.Style.Font.Size : (double)text.FontSize;
+ textFormat.Bold = text.Bold;
+ textFormat.Italic = text.Italic;
+ textFormat.Strike = text.Striketrough;
+ textFormat.SubScript = text.SubScript;
+ textFormat.SuperScript = text.SuperScript;
+ textFormat.Underline = text.Underline;
+ textFormat.UnderlineType = textFormat.Underline ? ExcelUnderLineType.Single : ExcelUnderLineType.None;
+ if (text.DoubleUnderline) textFormat.Underline = true;
+ textFormat.UnderlineType = text.DoubleUnderline ? ExcelUnderLineType.Double : textFormat.UnderlineType;
+ textFormat.FontColor = text.Color;
+ textFormat.SubFamily = FontSubFamily.Regular;
+ if (textFormat.Bold)
+ {
+ textFormat.SubFamily = FontSubFamily.Bold;
+ if (textFormat.Italic)
+ {
+ textFormat.SubFamily = FontSubFamily.BoldItalic;
+ }
+ }
+ else if (textFormat.Italic)
+ {
+ textFormat.SubFamily = FontSubFamily.Italic;
+ }
+
switch (text.FormatCode)
{
case ExcelHeaderFooterFormattingCodes.SheetName:
- textItem.Text += ws.Name;
+ textFormat.Text += ws.Name;
break;
case ExcelHeaderFooterFormattingCodes.CurrentDate:
- textItem.Text += DateTime.Now.ToString("yyyy-MM-dd");
+ textFormat.Text += DateTime.Now.ToString($"yyyy-MM-dd");
break;
case ExcelHeaderFooterFormattingCodes.FileName:
- textItem.Text += ws._package.File.Name;
+ textFormat.Text += ws._package.File.Name;
break;
case ExcelHeaderFooterFormattingCodes.NumberOfPages:
- textItem.Text += totalPages.ToString();
+ textFormat.Text += totalPages.ToString();
break;
case ExcelHeaderFooterFormattingCodes.PageNumber:
- textItem.Text += pageNumber;
+ textFormat.Text += pageNumber;
break;
case ExcelHeaderFooterFormattingCodes.CurrentTime:
- textItem.Text += DateTime.Now.ToString("HH:mm");
+ textFormat.Text += DateTime.Now.ToString("HH:mm");
break;
case ExcelHeaderFooterFormattingCodes.FilePath:
- textItem.Text += ws._package.File.FullName;
+ textFormat.Text += ws._package.File.Directory.FullName + "\\";
break;
default:
- textItem.Text += text.Text;
+ textFormat.Text += text.Text;
break;
}
- GetFontResourceData(dictionaries.Fonts, settings, textItem);
+ PdfFontResource.GetFontResourceData(dictionaries.Fonts, pageSettings, textFormat);
MeasurementFont font = new MeasurementFont();
- font.FontFamily = textItem.FontName;
- font.Size = (float)textItem.FontSize;
- font.Style = ((textItem.Bold ? MeasurementFontStyles.Bold : 0) |
- (textItem.Italic ? MeasurementFontStyles.Italic : 0) |
- (textItem.Strike ? MeasurementFontStyles.Strikeout : 0) |
- (textItem.Underline ? MeasurementFontStyles.Underline : 0))
+ font.FontFamily = textFormat.FontName;
+ font.Size = (float)textFormat.FontSize;
+ font.Style = ((textFormat.Bold ? MeasurementFontStyles.Bold : 0) |
+ (textFormat.Italic ? MeasurementFontStyles.Italic : 0) |
+ (textFormat.Strike ? MeasurementFontStyles.Strikeout : 0) |
+ (textFormat.Underline ? MeasurementFontStyles.Underline : 0))
switch
{
0 => MeasurementFontStyles.Regular,
var s => s
};
FontMeasurerTrueType fontMeasurerTrueType = new FontMeasurerTrueType();
- var result = fontMeasurerTrueType.MeasureText(textItem.Text, font);
- textItem.TextLength = result.Width;
- textItem.FontHeight = result.FontHeight;
- textItem.LineHeight = result.Height;
- textLine.Characters.Add(textItem);
- }
- }
-
- //Get font data from fontResources. If font does not exsist, add it to fontResources.
- private OpenTypeFont GetFontResourceData(Dictionary fontResources, PdfPageSettings pageSettings, PdfCellTextItem FontData)
- {
- if (!fontResources.ContainsKey(FontData.FullFontName))
- {
- int label = 1;
- if (fontResources.Count > 0)
+ var result = fontMeasurerTrueType.MeasureText(textFormat.Text, font);
+ textFormat.TextLength = result.Width;
+ textLength += result.Width;
+ textFormat.TextHeight = result.Height;
+ textHeight = result.Height;
+ textFormats.Add(textFormat);
+ if (!dictionaries.Fonts.ContainsKey(textFormat.FullFontName))
{
- label = fontResources.Last().Value.labelNumber + 1;
+ int label = 1;
+ if (dictionaries.Fonts.Count > 0)
+ {
+ label = dictionaries.Fonts.Last().Value.labelNumber + 1;
+ }
+ dictionaries.Fonts.Add(textFormat.FullFontName, new PdfFontResource(textFormat.FontName, textFormat.SubFamily, label, pageSettings));
}
- PdfFontResource fr = new PdfFontResource(FontData.FontName, FontData.SubFamily, label, pageSettings);
- fontResources.Add(FontData.FullFontName, fr);
- fontResources.Last().Value.fontData = PdfTextData.GetFontData(pageSettings, FontData.FontName, FontData.SubFamily);
+ var manger = dictionaries.Fonts[textFormat.FullFontName].fontSubsetManager;
+ manger.AddText(textFormat.Text);
}
- return fontResources[FontData.FullFontName].fontData;
}
public void AdjustPositionByTextLength(char rc, char hf)
{
if (rc == 'r')
{
- LocalPosition = new Vector2(LocalPosition.X - textLine.TextLength, LocalPosition.Y);
+ LocalPosition = new Vector2(LocalPosition.X - textLength, LocalPosition.Y);
}
else if (rc == 'c')
{
- LocalPosition = new Vector2(LocalPosition.X - (textLine.TextLength/2d), LocalPosition.Y);
+ LocalPosition = new Vector2(LocalPosition.X - (textLength/2d), LocalPosition.Y);
}
if (hf == 'h')
{
- LocalPosition = new Vector2(LocalPosition.X, LocalPosition.Y - textLine.LineHeight);
+ LocalPosition = new Vector2(LocalPosition.X, LocalPosition.Y - textHeight);
}
}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfMergedCellLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfMergedCellLayout.cs
index 5c1ec1e96..51e7c1b67 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfMergedCellLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfMergedCellLayout.cs
@@ -10,33 +10,29 @@ Date Author Change
*************************************************************************************************
27/11/2025 EPPlus Software AB EPPlus 9
*************************************************************************************************/
+using EPPlus.Export.Pdf.PdfResources;
using EPPlus.Graphics;
using EPPlus.Graphics.Math;
-using System.Drawing;
-using EPPlus.Export.Pdf.PdfResources;
using OfficeOpenXml;
+using OfficeOpenXml.Drawing.EMF;
using OfficeOpenXml.Style;
+using System.Diagnostics;
+using System.Drawing;
namespace EPPlus.Export.Pdf.PdfLayout
{
+ [DebuggerDisplay("Merged: {Name}")]
internal class PdfMergedCellLayout : PdfCellLayout
{
+ public ExcelAddressBase address;
-
- public PdfMergedCellLayout(PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyleOverride CellStyle, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null)
+ public PdfMergedCellLayout(PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyle CellStyle, double x, double y, double width, double height, double scaleX = 1, double scaleY = 1, double rotation = 0, Transform parent = null)
: base(dictionaries, cell, CellStyle, x, y, width, height, scaleX, scaleY, rotation, parent)
{
this.cell = cell;
- var fill = cell.Style.Fill;
- if(!fill.HasGradient && fill.PatternType == ExcelFillStyle.None)
- {
- CellFillData.BackgroundColor = Color.White;
- CellFillData.PatternStyle = ExcelFillStyle.Solid;
- CellFillData.enhanceGridLine = true;
- }
-
}
+ //Slightly shift position for cleaner result after gridlines are created.
public new void AdjustForGridLines()
{
if (CellFillData.BackgroundColor.Equals(Color.White) && CellFillData.PatternStyle == ExcelFillStyle.Solid)
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfPageLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfPageLayout.cs
index e3a902543..9e7782a76 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfPageLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfPageLayout.cs
@@ -10,19 +10,89 @@ Date Author Change
*************************************************************************************************
27/11/2025 EPPlus Software AB EPPlus 9
*************************************************************************************************/
+using EPPlus.Graphics;
+using OfficeOpenXml;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.DateAndTime;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
+using OfficeOpenXml.Table.PivotTable;
+using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
-using EPPlus.Graphics;
namespace EPPlus.Export.Pdf.PdfLayout
{
+ [DebuggerDisplay("Cell: {Name}")]
+ internal struct PageMap
+ {
+ public string Name;
+ public int row;
+ public int col;
+ public PdfCellLayout cell;
+ public PdfCellContentLayout content;
+ public PdfCellBorderLayout border;
+ public enum CellType
+ {
+ Normal,
+ Merged,
+ }
+ public CellType Type;
+
+ //Scoops up text spill from adjecent cells
+ public double LeftTextBucketSpill;
+ public double RightTextBucketSpill;
+ }
+
+ internal class VerticalLineRun
+ {
+ public int Col;
+ public int RowStart;
+ public int RowEnd;
+ }
+
+ internal class HorizontalLineRun
+ {
+ public int Row;
+ public int ColStart;
+ public int ColEnd;
+ }
+
+ [DebuggerDisplay("{Name}")]
internal class PdfPageLayout : Transform
{
internal List GridLines = new List();
internal List BorderLines = new List();
+ public int FromRow = int.MaxValue;
+ public int ToRow = 0;
+ public int FromCol = int.MaxValue;
+ public int ToCol = 0;
+ public int RowCount = 0;
+ public int ColCount = 0;
+
+ public PageMap[,] Map;
+
public PdfPageLayout(double x, double y, double width, double height)
- :base(x, y, width, height) { }
+ : base(x, y, width, height) { }
+
+ public void AddCell(Transform cell)
+ {
+ if (cell is PdfCellLayout cl)
+ {
+ FromRow = Math.Min(FromRow, cl.cell._fromRow);
+ ToRow = Math.Max(ToRow, cl.cell._toRow);
+ FromCol = Math.Min(FromCol, cl.cell._fromCol);
+ ToCol = Math.Max(ToCol, cl.cell._toCol);
+ }
+ ChildObjects[0].AddChild(cell);
+ }
+
+ public void CreateMap()
+ {
+ RowCount = ToRow - FromRow + 1;
+ ColCount = ToCol - FromCol + 1;
+ Map = new PageMap[RowCount, ColCount];
+ }
internal void GenerateGridLines()
{
@@ -33,8 +103,8 @@ internal void GenerateGridLines()
foreach (var c in cells)
{
if (c is PdfMergedCellLayout) continue;
- yCoords.Add(c.LocalPosition.Y + c.Size.Y); // Top
- yCoords.Add(c.LocalPosition.Y); // Bottom
+ yCoords.Add(c.LocalPosition.Y + c.Size.Y); // Top
+ yCoords.Add(c.LocalPosition.Y); // Bottom
xCoords.Add(c.LocalPosition.X); // Left
xCoords.Add(c.LocalPosition.X + c.Size.X); // Right
}
@@ -59,5 +129,196 @@ internal void GenerateGridLines()
GridLines.Add(line);
}
}
+
+ internal void GenerateVerticalGridLines(ExcelWorksheet ws)
+ {
+ int addedColumns = PdfWorksheetLayout.AddColumnsForNonWrappedText(ws);
+ bool resetStart = true;
+ var startX = 0d;
+ var startY = 0d;
+ var endX = 0d;
+ var endY = 0d;
+ for (int col = FromCol+1; col <= ToCol; col++)
+ {
+ double length = 0;
+ //string name = "";
+ //var f = ws.Cells[FromRow, col];
+ //var start = ChildObjects.Where(x => x.Name == f.Address || x.Name == f.Address + "_m" || x.Name == f.Address + "*").ToList();
+ for (int row = FromRow; row <= ToRow; row++)
+ {
+ var cell = ws.Cells[row, col];
+ var name = cell.Address;
+ var layouts = ChildObjects.Where(x => x.Name == cell.Address || x.Name == cell.Address + "_m" || x.Name == cell.Address + "*").ToList();
+ PdfMergedCellLayout m = null;
+ PdfCellLayout l = null;
+ foreach (var layout in layouts)
+ {
+ if (layout is PdfMergedCellLayout) m = (PdfMergedCellLayout)layout;
+ else if (layout is PdfCellLayout) l = (PdfCellLayout)layout;
+ }
+ if (l != null)
+ {
+ if (l.LeftTextSpillLength > 0)
+ {
+ length = 0;
+ if (startX != 0d)
+ {
+ var line = new GridLine(startX, startY, endX, endY);
+ GridLines.Add(line);
+ resetStart = true;
+ }
+ }
+ else
+ {
+ length += l.Size.Y;
+ endX = l.LocalPosition.X;
+ endY = l.LocalPosition.Y;
+ if (resetStart)
+ {
+ startX = l.LocalPosition.X;
+ startY = l.LocalPosition.Y + l.Size.Y;
+ resetStart = false;
+ }
+ }
+ }
+ else if (m != null)
+ {
+ length += m.Size.Y;
+ endX = m.LocalPosition.X;
+ endY = m.LocalPosition.Y;
+ if (resetStart)
+ {
+ startX = m.LocalPosition.X;
+ startY = m.LocalPosition.Y + m.Size.Y;
+ resetStart = false;
+ }
+ }
+ else if (l == null && m == null)
+ {
+ if (length > 0)
+ {
+ length = 0;
+ if (startX != 0d)
+ {
+ var line = new GridLine(startX, startY, endX, endY);
+ GridLines.Add(line);
+ resetStart = true;
+ }
+ }
+ }
+ }
+ if (startX != 0d)
+ {
+ var line2 = new GridLine(startX, startY, endX, endY);
+ GridLines.Add(line2);
+ }
+ resetStart = true;
+ }
+ }
+
+ internal void GenerateHorizontalGridLines(ExcelWorksheet ws)
+ {
+ int addedColumns = PdfWorksheetLayout.AddColumnsForNonWrappedText(ws);
+ bool resetStart = true;
+ var startX = 0d;
+ var startY = 0d;
+ var endX = 0d;
+ var endY = 0d;
+ for (int row = FromRow+1; row <= ToRow; row++)
+ {
+ double length = 0;
+ //string name = "";
+ //var f = ws.Cells[row, FromCol];
+ //var start = ChildObjects.Where(x => x.Name == f.Address || x.Name == f.Address + "_m" || x.Name == f.Address + "*").ToList();
+ for (int col = FromCol; col <= ToCol; col++)
+ {
+ var cell = ws.Cells[row, col];
+ var name = cell.Address;
+ var layouts = ChildObjects.Where(x => x.Name == cell.Address || x.Name == cell.Address + "_m" || x.Name == cell.Address + "*").ToList();
+ PdfMergedCellLayout m = null;
+ PdfCellLayout l = null;
+ foreach (var layout in layouts)
+ {
+ if (layout is PdfMergedCellLayout) m = (PdfMergedCellLayout)layout;
+ else if (layout is PdfCellLayout) l = (PdfCellLayout)layout;
+ }
+ if (l != null)
+ {
+ length += l.Size.X;
+ endX = l.LocalPosition.X + l.Size.X;
+ endY = l.LocalPosition.Y + l.Size.Y;
+ if (resetStart)
+ {
+ startX = l.LocalPosition.X;
+ startY = l.LocalPosition.Y + l.Size.Y;
+ resetStart = false;
+ }
+ }
+ else if (m != null)
+ {
+ length += m.Size.X;
+ endX = m.LocalPosition.X + m.Size.X;
+ endY = m.LocalPosition.Y + m.Size.Y;
+ if (resetStart)
+ {
+ startX = m.LocalPosition.X;
+ startY = m.LocalPosition.Y + m.Size.Y;
+ resetStart = false;
+ }
+ }
+ else if (l == null && m == null)
+ {
+ if (length > 0)
+ {
+ length = 0;
+ if (startX != 0d)
+ {
+ var line = new GridLine(startX, startY, endX, endY);
+ GridLines.Add(line);
+ resetStart = true;
+ }
+ }
+ }
+ }
+ if (startX != 0d)
+ {
+ var line2 = new GridLine(startX, startY, endX, endY);
+ GridLines.Add(line2);
+ }
+ resetStart = true;
+ }
+ }
+
+ internal void GenerateBorderLines()
+ {
+ HashSet xCoords = new HashSet();
+ HashSet yCoords = new HashSet();
+ // Collect all unique X and Y coordinates.
+ var cells = ChildObjects.Where(x => x is PdfCellLayout).ToList();
+ foreach (var c in cells)
+ {
+ if (c is PdfMergedCellLayout) continue;
+ yCoords.Add(c.LocalPosition.Y + c.Size.Y); // Top
+ yCoords.Add(c.LocalPosition.Y); // Bottom
+ xCoords.Add(c.LocalPosition.X); // Left
+ xCoords.Add(c.LocalPosition.X + c.Size.X); // Right
+ }
+ double minX = cells.Where(c => c is not PdfMergedCellLayout).Min(c => c.LocalPosition.X);
+ double maxX = cells.Where(c => c is not PdfMergedCellLayout).Max(c => c.LocalPosition.X + c.Size.X);
+ double minY = cells.Where(c => c is not PdfMergedCellLayout).Min(c => c.LocalPosition.Y);
+ double maxY = cells.Where(c => c is not PdfMergedCellLayout).Max(c => c.LocalPosition.Y + c.Size.Y);
+ foreach (var x in xCoords.OrderBy(v => v))
+ {
+ var line = new GridLine(x, minY, x, maxY);
+ if (x == minX || x == maxX)
+ BorderLines.Add(line);
+ }
+ foreach (var y in yCoords.OrderBy(v => v))
+ {
+ var line = new GridLine(minX, y, maxX, y);
+ if (y == minY || y == maxY)
+ BorderLines.Add(line);
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfPagesLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfPagesLayout.cs
index 78595f734..fac513593 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfPagesLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfPagesLayout.cs
@@ -15,6 +15,9 @@ Date Author Change
namespace EPPlus.Export.Pdf.PdfLayout
{
+ ///
+ /// Represents the pages object in the pdf document.
+ ///
internal class PdfPagesLayout : Transform
{
internal ExcelRangeBase Range;
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfTableLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfTableLayout.cs
deleted file mode 100644
index be0b31818..000000000
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfTableLayout.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using System;
-using EPPlus.Export.Pdf.Pdfhelpers;
-using OfficeOpenXml;
-using OfficeOpenXml.Style;
-using OfficeOpenXml.Style.Dxf;
-
-namespace EPPlus.Export.Pdf.PdfLayout
-{
- internal enum TableCellStyle
- {
- Header,
- OddRow,
- EvenRow,
- TotalRow,
- FirstColumn,
- LastColumn,
- OddColumn,
- EvenColumn,
- WholeTable
- }
-
- [Flags]
- public enum TableBorderStyle
- {
- None = 0,
- Top = 1 << 0,
- Bottom = 1 << 1,
- Left = 1 << 2,
- Right = 1 << 3,
- Horizontal = 1 << 4,
- Vertical = 1 << 5
- }
-
- internal class PdfCellStyleOverride
- {
- internal TableCellStyle TableCellStyleType { get; set; }
- internal ExcelTableStyleElement MainStyleFill;
- internal ExcelTableStyleElement WholeStyleFill;
-
- internal ExcelFill xfFill;
- internal ExcelDxfFill dxfFill;
-
-
- internal ExcelBorderItem xfTop;
- internal ExcelBorderItem xfBottom;
- internal ExcelBorderItem xfLeft;
- internal ExcelBorderItem xfRight;
- internal ExcelBorderItem xfDiagonalUp;
- internal ExcelBorderItem xfDiagonalDown;
-
- internal ExcelDxfBorderItem dxfTop;
- internal ExcelDxfBorderItem dxfBottom;
- internal ExcelDxfBorderItem dxfLeft;
- internal ExcelDxfBorderItem dxfRight;
- internal ExcelDxfBorderItem dxfHorizontal;
- internal ExcelDxfBorderItem dxfVertical;
-
- internal ExcelFont xfFont;
- internal ExcelDxfFontBase dxfFont;
-
-
- internal TableBorderStyle borderStyleType = TableBorderStyle.None;
-
- //internal PdfCellFillData ApplyStyle()
- //{
- // var CellFillData = new PdfCellFillData();
- // if (dxfFill != null)
- // {
- // CellFillData.PatternStyle = dxfFill.PatternType != null ? (ExcelFillStyle)dxfFill.PatternType : xfFill.PatternType;
- // if (CellFillData.PatternStyle == ExcelFillStyle.Solid)
- // {
- // CellFillData.BackgroundColor = PdfColor.SetColorFromHex(dxfFill.BackgroundColor.LookupColor());
- // }
- // if (CellFillData.PatternStyle != ExcelFillStyle.None)
- // {
- // CellFillData.BackgroundColor = PdfColor.SetColorFromHex(dxfFill.PatternColor.Color == null ? "#FFFFFFFF" : dxfFill.PatternColor.LookupColor());
- // CellFillData.PatternColor = PdfColor.SetColorFromHex(dxfFill.BackgroundColor.LookupColor());
- // CellFillData.id = AddPatternResourceData(dictionaries.Patterns, CellFillData.PatternStyle.ToString() + CellFillData.PatternColor.ToHexString() + CellFillData.BackgroundColor.ToHexString());
- // }
- // if (dxfFill.Gradient != null)
- // {
- // CellFillData.GradientFillData = new PdfCellGradientFillData();
- // CellFillData.GradientFillData.GradientType = dxfFill.Gradient.GradientType == null ? ExcelFillGradientType.None : (ExcelFillGradientType)dxfFill.Gradient.GradientType;
- // CellFillData.GradientFillData.Color1 = PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[0].Color.LookupColor());
- // CellFillData.GradientFillData.Color2 = PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[1].Color.LookupColor());
- // CellFillData.GradientFillData.Color3 = PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[2].Color.LookupColor());
- // CellFillData.GradientFillData.Degree = dxfFill.Gradient.Degree == null ? 0 : (double)dxfFill.Gradient.Degree;
- // CellFillData.GradientFillData.Top = dxfFill.Gradient.Top == null ? 0 : (double)dxfFill.Gradient.Top;
- // CellFillData.GradientFillData.Bottom = dxfFill.Gradient.Bottom == null ? 0 : (double)dxfFill.Gradient.Bottom;
- // CellFillData.GradientFillData.Left = dxfFill.Gradient.Left == null ? 0 : (double)dxfFill.Gradient.Left;
- // CellFillData.GradientFillData.Right = dxfFill.Gradient.Right == null ? 0 : (double)dxfFill.Gradient.Right;
- // CellFillData.id = CellFillData.GradientFillData.ToString();
- // AddShadingResourceData(dictionaries.Shadings, CellFillData.id);
- // }
- // }
- // else
- // {
- // CellFillData.PatternStyle = xfFill.PatternType;
- // if (CellFillData.PatternStyle == ExcelFillStyle.Solid)
- // {
- // CellFillData.BackgroundColor = PdfColor.SetColorFromHex(xfFill.BackgroundColor.LookupColor());
- // }
- // if (CellFillData.PatternStyle != ExcelFillStyle.None)
- // {
-
- // }
- // if (dxfFill.Gradient != null)
- // {
-
- // }
- // }
- // return CellFillData;
- //}
-
- internal ExcelFill GetAppliedFill()
- {
- ExcelFill Fill = new ExcelFill(xfFill._styles, xfFill._styles.PropertyChange, xfFill._positionID, xfFill._address, int.MinValue);
- if (xfFill.PatternType != ExcelFillStyle.None)
- {
- Fill.PatternType = xfFill.PatternType;
- Fill.BackgroundColor.SetColor(PdfColor.SetColorFromHex(xfFill.BackgroundColor.LookupColor()));
- Fill.PatternColor.SetColor(PdfColor.SetColorFromHex(xfFill.PatternColor.LookupColor()));
- }
- if (xfFill.HasGradient)
- {
- Fill.Gradient.Type = xfFill.Gradient.Type;
- Fill.Gradient.Color1.SetColor(PdfColor.SetColorFromHex(xfFill.Gradient.Color1.LookupColor()));
- Fill.Gradient.Color2.SetColor(PdfColor.SetColorFromHex(xfFill.Gradient.Color2.LookupColor()));
- Fill.Gradient.Color3.SetColor(PdfColor.SetColorFromHex(xfFill.Gradient.Color3.LookupColor()));
- Fill.Gradient.Degree = xfFill.Gradient.Degree;
- Fill.Gradient.Top = xfFill.Gradient.Top;
- Fill.Gradient.Bottom = xfFill.Gradient.Bottom;
- Fill.Gradient.Left = xfFill.Gradient.Left;
- Fill.Gradient.Right = xfFill.Gradient.Right;
- }
- if (dxfFill != null)
- {
- if (dxfFill.PatternType != null)
- Fill.PatternType = (ExcelFillStyle)dxfFill.PatternType;
-
- if (dxfFill.BackgroundColor?.Color != null)
- Fill.BackgroundColor.SetColor(PdfColor.SetColorFromHex(dxfFill.BackgroundColor.LookupColor()));
-
- if (dxfFill.PatternColor?.Color != null)
- Fill.PatternColor.SetColor(PdfColor.SetColorFromHex(dxfFill.PatternColor.LookupColor()));
-
- if (dxfFill.Gradient != null && dxfFill.Gradient.HasValue)
- {
- if (dxfFill.Gradient.GradientType != null)
- Fill.Gradient.Type = (ExcelFillGradientType)dxfFill.Gradient.GradientType;
-
- if (dxfFill.Gradient.Colors[0] != null)
- Fill.Gradient.Color1.SetColor(PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[0].Color.LookupColor()));
- if (dxfFill.Gradient.Colors[1] != null)
- Fill.Gradient.Color2.SetColor(PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[1].Color.LookupColor()));
- if (dxfFill.Gradient.Colors[2] != null)
- Fill.Gradient.Color3.SetColor(PdfColor.SetColorFromHex(dxfFill.Gradient.Colors[2].Color.LookupColor()));
- if (dxfFill.Gradient.Degree.HasValue && !double.IsNaN(dxfFill.Gradient.Degree.Value))
- {
- Fill.Gradient.Degree = (double)dxfFill.Gradient.Degree;
- }
- if (dxfFill.Gradient.Top.HasValue && !double.IsNaN(dxfFill.Gradient.Top.Value))
- {
- Fill.Gradient.Top = (double)dxfFill.Gradient.Top;
- }
- if (dxfFill.Gradient.Bottom.HasValue && !double.IsNaN(dxfFill.Gradient.Bottom.Value))
- {
- Fill.Gradient.Bottom = (double)dxfFill.Gradient.Bottom;
- }
- if (dxfFill.Gradient.Left.HasValue && !double.IsNaN(dxfFill.Gradient.Left.Value))
- {
- Fill.Gradient.Left = (double)dxfFill.Gradient.Left;
- }
- if (dxfFill.Gradient.Right.HasValue && !double.IsNaN(dxfFill.Gradient.Right.Value))
- {
- Fill.Gradient.Right = (double)dxfFill.Gradient.Right;
- }
- }
- }
- return Fill;
- }
- }
-}
diff --git a/src/EPPlus.Export.Pdf/PdfLayout/PdfWorksheetLayout.cs b/src/EPPlus.Export.Pdf/PdfLayout/PdfWorksheetLayout.cs
index def47abff..f26154972 100644
--- a/src/EPPlus.Export.Pdf/PdfLayout/PdfWorksheetLayout.cs
+++ b/src/EPPlus.Export.Pdf/PdfLayout/PdfWorksheetLayout.cs
@@ -17,11 +17,12 @@ Date Author Change
using EPPlus.Graphics.Math;
using EPPlus.Graphics.Units;
using OfficeOpenXml;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup;
using OfficeOpenXml.Interfaces.Drawing.Text;
using OfficeOpenXml.Style;
-using OfficeOpenXml.Style.Dxf;
using OfficeOpenXml.Style.Table;
using OfficeOpenXml.Table;
+using System;
using System.Collections.Generic;
using System.Linq;
@@ -29,28 +30,29 @@ namespace EPPlus.Export.Pdf.PdfLayout
{
internal class PdfWorksheetLayout : Transform
{
- public readonly double ZeroCharWidth;
+ public static double ZeroCharWidth;
public PdfWorksheetLayout(ExcelWorksheet worksheet, PdfPageSettings pageSettings, PdfDictionaries dictionaries)
{
double x = 0d, y = 0d, totalWidth = 0d;
ZeroCharWidth = GetThemeFont0Width(worksheet);
List checkedMergedCells = new List();
+ int addedColumns = AddColumnsForNonWrappedText(worksheet);
for(int row = 1; row<= worksheet.Dimension._toRow; row++)
{
if(worksheet.Row(row).Hidden) continue;
var height = UnitConversion.ExcelRowHeightToPoints(worksheet.Row(row).Height);
x = 0d;
- for (int col = 1; col <= worksheet.Dimension._toCol; col++)
+ for (int col = 1; col <= worksheet.Dimension._toCol + addedColumns; col++)
{
if(worksheet.Column(col).Hidden) continue;
var width = UnitConversion.ExcelColumnWidthToPoints(worksheet.Column(col).Width, ZeroCharWidth);
var cell = worksheet.Cells[row, col];
- var cellStyle = new PdfCellStyleOverride();
+ var cellStyle = new PdfCellStyle();
GetFillStyles(cell, cellStyle);
GetBorderStyles(cell, cellStyle);
GetFontStyles(cell, cellStyle);
- PdfCellBorderLayout border = HandleEdgeBorders(cell, cellStyle, x, y, width, height);
+ PdfCellBorderLayout border = HandleEdgeBorders(cell, cellStyle, cell.Address, x, y, width, height);
if (cell.Merge)
{
HandleMergedCell(worksheet, pageSettings, dictionaries, cell, cellStyle, checkedMergedCells, x, y);
@@ -69,7 +71,72 @@ public PdfWorksheetLayout(ExcelWorksheet worksheet, PdfPageSettings pageSettings
Size = new Vector2(totalWidth, y);
}
- private void GetBorderStyles(ExcelRangeBase cell, PdfCellStyleOverride cellStyle)
+ ///
+ /// Check if we need to add additional columns to accomodate text that is not wrapped and overlaps other cell.s
+ ///
+ /// The worksheet to check.
+ /// The number of columns to add.
+ public static int AddColumnsForNonWrappedText(ExcelWorksheet ws)
+ {
+ double columnWidth = UnitConversion.ExcelColumnWidthToPoints(ws.Column(ws.Dimension._toCol).Width, ZeroCharWidth);
+ int columnsToAdd = 0;
+ FontMeasurerTrueType fontMeasurerTrueType = new FontMeasurerTrueType();
+ MeasurementFont font = new MeasurementFont();
+ double textLength = 0;
+ for (int row = 1; row <= ws.Dimension._toRow; row++)
+ {
+ var cell = ws.Cells[row, ws.Dimension._toCol];
+ if ((!string.IsNullOrEmpty(cell.Text) || cell.RichText.Count > 0) && !cell.Style.WrapText && !cell.Merge)
+ {
+ if (cell.IsRichText)
+ {
+ foreach (var rt in cell.RichText)
+ {
+ font.FontFamily = rt.FontName;
+ font.Size = (float)rt.Size;
+ font.Style = ((cell.Style.Font.Bold ? MeasurementFontStyles.Bold : 0) |
+ (cell.Style.Font.Italic ? MeasurementFontStyles.Italic : 0) |
+ (cell.Style.Font.Strike ? MeasurementFontStyles.Strikeout : 0) |
+ (cell.Style.Font.UnderLine ? MeasurementFontStyles.Underline : 0))
+ switch
+ {
+ 0 => MeasurementFontStyles.Regular,
+ var s => s
+ };
+ var result = fontMeasurerTrueType.MeasureText(rt.Text, font);
+ textLength += result.Width;
+ }
+ }
+ else
+ {
+ font.FontFamily = cell.Style.Font.Name;
+ font.Size = (float)cell.Style.Font.Size;
+ font.Style = ((cell.Style.Font.Bold ? MeasurementFontStyles.Bold : 0) |
+ (cell.Style.Font.Italic ? MeasurementFontStyles.Italic : 0) |
+ (cell.Style.Font.Strike ? MeasurementFontStyles.Strikeout : 0) |
+ (cell.Style.Font.UnderLine ? MeasurementFontStyles.Underline : 0))
+ switch
+ {
+ 0 => MeasurementFontStyles.Regular,
+ var s => s
+ };
+ var result = fontMeasurerTrueType.MeasureText(cell.Text, font);
+ textLength += result.Width;
+ }
+ //loop next col width until text is included
+ //increase columns to add
+ while (textLength > columnWidth)
+ {
+ columnsToAdd++;
+ columnWidth += UnitConversion.ExcelColumnWidthToPoints(ws.Column(ws.Dimension._toCol + columnsToAdd).Width, ZeroCharWidth);
+ }
+ }
+ }
+ return columnsToAdd;
+ }
+
+ //Get Border styles from cell, tables and conditional formatting. TODO: Add support for Conditional formatting.
+ private void GetBorderStyles(ExcelRangeBase cell, PdfCellStyle cellStyle)
{
/* Kika på varje del av border top bottom left right
@@ -108,7 +175,8 @@ private void GetBorderStyles(ExcelRangeBase cell, PdfCellStyleOverride cellStyle
}
}
- public void GetFillStyles( ExcelRangeBase cell, PdfCellStyleOverride cellStyle)
+ //Get Fill style from cell, tables and conditional formatting. TODO: Add support for Conditional formatting.
+ public void GetFillStyles( ExcelRangeBase cell, PdfCellStyle cellStyle)
{
if (cell.Style.Fill.IsEmpty())
{
@@ -168,7 +236,9 @@ public void GetFillStyles( ExcelRangeBase cell, PdfCellStyleOverride cellStyle)
}
cellStyle.xfFill = cell.Style.Fill;
}
- public void GetFontStyles(ExcelRangeBase cell, PdfCellStyleOverride cellStyle)
+
+ //Get Font style from cell, tables and conditional formatting. TODO: Add support for Conditional formatting.
+ public void GetFontStyles(ExcelRangeBase cell, PdfCellStyle cellStyle)
{
var tables = cell.Worksheet.Tables.GetIntersectingRanges(cell);
if (tables.Count > 0)
@@ -251,15 +321,16 @@ public void GetFontStyles(ExcelRangeBase cell, PdfCellStyleOverride cellStyle)
}
//Create cell.
- private void HandleCell(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, double x, double y, double width, double height, PdfCellStyleOverride CellStyle)
+ private void HandleCell(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, double x, double y, double width, double height, PdfCellStyle CellStyle)
{
//We add empty cells for gridline calculation later. We just marked them for deletion by addng * to their name.
- string deleteMark = !cell.IsEmpty() || cell.Worksheet.ExistsStyleInner(cell._fromRow, cell._toCol) ? "" : "*";
+ bool delete = cell.IsEmpty() && !cell.Worksheet.ExistsStyleInner(cell._fromRow, cell._toCol);
var cl0 = new PdfCellLayout(dictionaries, cell, CellStyle, x, y, width, height, 1, 1, 0, this);
- cl0.Name = cell.Address + deleteMark;
+ cl0.Name = cell.Address;
cl0.Z = 1;
- AddCellContent(pageSettings, dictionaries, cell, CellStyle, x, y-height, width, height, 2);
- var border = HandleDiagonalBorders(cell, CellStyle, x, y, width, height);
+ cl0.delete = delete;
+ AddCellContent(pageSettings, dictionaries, cell, CellStyle, cell.Address, x, y - height, width, height, 2);
+ var border = HandleDiagonalBorders(cell, CellStyle, cell.Address, x, y, width, height);
if (border != null)
{
border.InitDiagonalBorders(cell, width, height);
@@ -267,7 +338,7 @@ private void HandleCell(PdfPageSettings pageSettings, PdfDictionaries dictionari
}
//Create merged cell.
- private void HandleMergedCell(ExcelWorksheet worksheet, PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyleOverride CellStyle, List checkedMergedCells, double x, double y)
+ private void HandleMergedCell(ExcelWorksheet worksheet, PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyle CellStyle, List checkedMergedCells, double x, double y)
{
string mergeAddress = worksheet.MergedCells[cell.Start.Row, cell.Start.Column];
if (!checkedMergedCells.Contains(mergeAddress))
@@ -282,12 +353,14 @@ private void HandleMergedCell(ExcelWorksheet worksheet, PdfPageSettings pageSett
{
width += UnitConversion.ExcelColumnWidthToPoints(worksheet.Column(l).Width, ZeroCharWidth);
}
- var mergedCell = AddChild(new PdfMergedCellLayout(dictionaries, worksheet.Cells[address._fromRow, address._fromCol], CellStyle, x, y, width, height));
- mergedCell.Name = cell.Address + "_m";
+ var mergedCell = new PdfMergedCellLayout(dictionaries, worksheet.Cells[address._fromRow, address._fromCol], CellStyle, x, y, width, height);
+ mergedCell.Name = address.Address;//cell.Address + "_m";
mergedCell.Z = 5;
- AddCellContent(pageSettings, dictionaries, cell, CellStyle, x, y-height, width, height, 6);
+ mergedCell.address = address;
+ AddChild(mergedCell);
+ AddCellContent(pageSettings, dictionaries, cell, CellStyle, address.Address, x, y-height, width, height, 6);
checkedMergedCells.Add(mergeAddress);
- var border = HandleDiagonalBorders(cell, null, x, y, width, height);
+ var border = HandleDiagonalBorders(cell, null, address.Address, x, y, width, height);
if (border != null)
{
border.InitDiagonalBorders(cell, width, height);
@@ -297,25 +370,25 @@ private void HandleMergedCell(ExcelWorksheet worksheet, PdfPageSettings pageSett
}
//Create content.
- private void AddCellContent(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyleOverride CellStyle, double x, double y, double width, double height, int zOrder)
+ private void AddCellContent(PdfPageSettings pageSettings, PdfDictionaries dictionaries, ExcelRangeBase cell, PdfCellStyle CellStyle, string name, double x, double y, double width, double height, int zOrder)
{
if (!string.IsNullOrEmpty(cell.Text))
{
var cellContent = new PdfCellContentLayout(cell, CellStyle, pageSettings, x, y, width, height, 1, 1, 0, this, dictionaries);
- cellContent.Name = cell.Address + "_c";
+ cellContent.Name = name;// + "_c";
cellContent.Z = zOrder;
}
}
//Create Edge borders.
- private PdfCellBorderLayout HandleEdgeBorders(ExcelRangeBase cell, PdfCellStyleOverride tableStyle, double x, double y, double width, double height)
+ private PdfCellBorderLayout HandleEdgeBorders(ExcelRangeBase cell, PdfCellStyle tableStyle, string name, double x, double y, double width, double height)
{
bool edges = new[] { cell.Style.Border.Top.Style, cell.Style.Border.Bottom.Style, cell.Style.Border.Left.Style, cell.Style.Border.Right.Style }.All(s => s == ExcelBorderStyle.None);
bool edges2 = new[] { tableStyle.dxfTop, tableStyle.dxfBottom, tableStyle.dxfLeft, tableStyle.dxfRight }.Any(s => s != null && s.HasValue);
if (!edges || edges2)
{
var clb0 = new PdfCellBorderLayout(cell, tableStyle, x, y, width, height, 1, 1, 0, this);
- clb0.Name = cell.Address + "_b";
+ clb0.Name = name;// + "_b";
clb0.Z = 7;
return clb0;
}
@@ -323,13 +396,13 @@ private PdfCellBorderLayout HandleEdgeBorders(ExcelRangeBase cell, PdfCellStyleO
}
//Create Diagonal borders.
- private PdfCellBorderLayout HandleDiagonalBorders(ExcelRangeBase cell, PdfCellStyleOverride TableStyle, double x, double y, double width, double height)
+ private PdfCellBorderLayout HandleDiagonalBorders(ExcelRangeBase cell, PdfCellStyle TableStyle, string name, double x, double y, double width, double height)
{
bool diagonals = new[] { cell.Style.Border.Diagonal.Style }.All(s => s == ExcelBorderStyle.None);
if (!diagonals)
{
var clb0 = new PdfCellBorderLayout(cell, TableStyle, x, y, width, height, 1, 1, 0, this);
- clb0.Name = cell.Address + "_b";
+ clb0.Name = name;// + "_b";
clb0.Z = 7;
return clb0;
}
@@ -347,6 +420,7 @@ private void HandleDrawings(ExcelWorksheet worksheet)
}
}
+ //Get the width of the character 0 from the current themes default font style. It's used to calculate width of cells.
private double GetThemeFont0Width(ExcelWorksheet ws)
{
FontMeasurerTrueType fontMeasurerTrueType = new FontMeasurerTrueType();
diff --git a/src/EPPlus.Export.Pdf/PdfObjects/PdfCatalog.cs b/src/EPPlus.Export.Pdf/PdfObjects/PdfCatalog.cs
index 8510b85ae..a288bbc02 100644
--- a/src/EPPlus.Export.Pdf/PdfObjects/PdfCatalog.cs
+++ b/src/EPPlus.Export.Pdf/PdfObjects/PdfCatalog.cs
@@ -10,6 +10,8 @@ Date Author Change
*************************************************************************************************
10/07/2025 EPPlus Software AB EPPlus.Fonts.OpenType 1.0
*************************************************************************************************/
+using System.IO;
+
namespace EPPlus.Export.Pdf.PdfObjects
{
internal class PdfCatalog : PdfObject
@@ -27,5 +29,11 @@ internal override string RenderDictionary()
return $"<< /Type /Catalog\n" +
$" /Pages {pagesObjectNumber} 0 R >>";
}
+
+ internal override void RenderDictionary(BinaryWriter bw)
+ {
+ WriteAscii(bw, $"<< /Type /Catalog\n" +
+ $" /Pages {pagesObjectNumber} 0 R >>");
+ }
}
}
diff --git a/src/EPPlus.Export.Pdf/PdfObjects/PdfContentStream.cs b/src/EPPlus.Export.Pdf/PdfObjects/PdfContentStream.cs
index fc7cd0665..d17bb7ff0 100644
--- a/src/EPPlus.Export.Pdf/PdfObjects/PdfContentStream.cs
+++ b/src/EPPlus.Export.Pdf/PdfObjects/PdfContentStream.cs
@@ -14,17 +14,16 @@ Date Author Change
using EPPlus.Export.Pdf.PdfLayout;
using EPPlus.Export.Pdf.PdfResources;
using EPPlus.Export.Pdf.PdfSettings;
-using EPPlus.Fonts.OpenType;
using EPPlus.Graphics;
using EPPlus.Graphics.Math;
-using OfficeOpenXml;
+using OfficeOpenXml.Interfaces.Fonts;
using OfficeOpenXml.Style;
using System;
using System.Collections.Generic;
using System.Drawing;
+using System.IO;
using System.Linq;
using System.Text;
-using static System.Net.Mime.MediaTypeNames;
namespace EPPlus.Export.Pdf.PdfObjects
{
@@ -35,7 +34,7 @@ internal class PdfContentStream : PdfObject
public PdfContentStream(int objectNumber, string command = null, int version = 0)
: base(objectNumber, version)
{
- if(!string.IsNullOrEmpty(command))
+ if (!string.IsNullOrEmpty(command))
{
commands.Add(command);
}
@@ -65,7 +64,7 @@ public void AddCellLayout(PdfCellLayout cell, string label)
commands.Add("q");
commands.Add($"{GridLine.HalfWidth.ToPdfString()} w");
commands.Add(cell.CellFillData.BackgroundColor.ToFillCommand());
- commands.Add( cell.CellFillData.enhanceGridLine ? Color.Black.ToStrokeCommand() : cell.CellFillData.BackgroundColor.ToStrokeCommand());
+ commands.Add(cell.CellFillData.enhanceGridLine ? Color.Black.ToStrokeCommand() : cell.CellFillData.BackgroundColor.ToStrokeCommand());
commands.Add($"{cell.LocalPosition.X.ToPdfString()} {cell.LocalPosition.Y.ToPdfString()} {cell.Size.X.ToPdfString()} {cell.Size.Y.ToPdfString()} re");
commands.Add("B");
commands.Add("Q");
@@ -120,6 +119,108 @@ internal PdfFontResource GetFontResource(PdfDictionaries Dictionaries, PdfPageSe
return Dictionaries.Fonts[fontName];
}
+ public void AddText(ITextLayout cell, Vector2 position, double textRotation, PdfDictionaries dictionaries, PdfPageSettings pageSettings)
+ {
+ double advanceX = 0;
+ double rotation = textRotation * System.Math.PI / 180.0;
+ for (int i = 0; i < cell.TextFormats.Count; i++)
+ {
+ var textFormat = cell.TextFormats[i];
+ var shapedText = textFormat.ShapedText;
+ var textLength = shapedText.GetWidthInPoints((float)textFormat.FontSize);
+ var color = textFormat.FontColor;
+ var fontResrouce = GetFontResource(dictionaries, pageSettings, textFormat.FullFontName, textFormat.SubFamily, textFormat.FontSize);
+ double size = textFormat.FontSize;
+ double scale = textFormat.FontSize / fontResrouce.fontData.HeadTable.UnitsPerEm;
+ Matrix3x3 textMatrix = new Matrix3x3(System.Math.Cos(rotation), System.Math.Sin(rotation), -System.Math.Sin(rotation), System.Math.Cos(rotation), position.X, position.Y);
+ commands.Add("BT");
+ textMatrix = textMatrix * Matrix3x3.Translation(advanceX, 0);
+ if (textFormat.SuperScript)
+ {
+ var supOffX = fontResrouce.fontData.Os2Table.ySuperscriptXOffset * scale;
+ var supOffY = fontResrouce.fontData.Os2Table.ySuperscriptYOffset * scale;
+ var supSizeY = fontResrouce.fontData.Os2Table.ySuperscriptYSize * scale;
+ textMatrix = textMatrix * Matrix3x3.Translation(supOffX, supOffY);
+ size = supSizeY;
+ }
+ else if (textFormat.SubScript)
+ {
+ var supOffX = fontResrouce.fontData.Os2Table.ySubscriptXOffset * scale;
+ var supOffY = fontResrouce.fontData.Os2Table.ySubscriptYOffset * scale;
+ var supSizeY = fontResrouce.fontData.Os2Table.ySubscriptYSize * scale;
+ textMatrix = textMatrix * Matrix3x3.Translation(supOffX, supOffY);
+ size = supSizeY;
+ }
+ if (textFormat.Underline)
+ {
+ var underlinePos = fontResrouce.fontData.PostTable.underlinePosition * scale;
+ var underlineWidth = fontResrouce.fontData.PostTable.underlineThickness * scale;
+ var start = textMatrix.Transform(new Vector2(0, underlinePos));
+ var end = textMatrix.Transform(new Vector2(textLength, underlinePos));
+ commands.Add($"{underlineWidth.ToPdfString()} w");
+ commands.Add($"{start.X.ToPdfString()} {start.Y.ToPdfString()} m");
+ commands.Add($"{end.X.ToPdfString()} {end.Y.ToPdfString()} l");
+ commands.Add($"S");
+ }
+ if (textFormat.Strike)
+ {
+ var strikePos = fontResrouce.fontData.Os2Table.yStrikeoutPosition * scale;
+ var strikeWidth = fontResrouce.fontData.Os2Table.yStrikeoutSize * scale;
+ var start = textMatrix.Transform(new Vector2(0, strikePos));
+ var end = textMatrix.Transform(new Vector2(textLength, strikePos));
+ commands.Add($"{strikeWidth.ToPdfString()} w");
+ commands.Add($"{start.X.ToPdfString()} {start.Y.ToPdfString()} m");
+ commands.Add($"{end.X.ToPdfString()} {end.Y.ToPdfString()} l");
+ commands.Add($"S");
+ }
+ commands.Add(color.ToFillCommand());
+ commands.Add($"{textMatrix.A.ToPdfString()} {textMatrix.B.ToPdfString()} {textMatrix.C.ToPdfString()} {textMatrix.D.ToPdfString()} {textMatrix.E.ToPdfString()} {textMatrix.F.ToPdfString()} Tm");
+
+ // FIX: Always use fontIdMap to determine the initial font.
+ // FontId=0 does NOT always mean "primary font" — when the text starts
+ // with a fallback character (e.g. emoji), FontId=0 IS the fallback font.
+ // The fontIdMap correctly maps FontId → PDF font label in all cases.
+ byte currentFontId = shapedText.Glyphs.Length > 0 ? shapedText.Glyphs[0].FontId : (byte)0;
+ string currentFontLabel = textFormat.FontIdMap.ContainsKey(currentFontId)
+ ? textFormat.FontIdMap[currentFontId]
+ : fontResrouce.Label;
+ commands.Add($"/{currentFontLabel} {size.ToPdfString()} Tf");
+
+ var sb = new StringBuilder();
+ sb.Append("[");
+ for (int j = 0; j < shapedText.Glyphs.Length; j++)
+ {
+ var glyph = shapedText.Glyphs[j];
+
+ if (glyph.FontId != currentFontId)
+ {
+ // Close TJ array, switch font, open new TJ array
+ sb.Append("] TJ\n");
+ sb.Append($"/{textFormat.FontIdMap[glyph.FontId]} {size.ToPdfString()} Tf\n");
+ sb.Append("[");
+ currentFontId = glyph.FontId;
+ }
+
+ sb.Append($"<{glyph.GlyphId:X4}>");
+ int kerning = glyph.XAdvance - glyph.BaseAdvance;
+
+ if (kerning != 0)
+ {
+ double adjustment = -(kerning * 1000.0 / 1000);
+ sb.Append($" {adjustment.ToPdfStringF0()}");
+ }
+
+ if (j < shapedText.Glyphs.Length - 1)
+ {
+ sb.Append(" ");
+ }
+ }
+ advanceX += textLength;
+ commands.Add(sb.ToString() + "] TJ");
+ commands.Add("ET");
+ }
+ }
+
public void AddText(Vector2 position, PdfCellLines lines, PdfCellAlignmentData alignment, PdfDictionaries dictionaries, PdfPageSettings pageSettings)
{
double rot = alignment.TextRotation * System.Math.PI / 180.0;
@@ -133,8 +234,8 @@ public void AddText(Vector2 position, PdfCellLines lines, PdfCellAlignmentData a
bool useModifiedMatrix = false;
commands.Add("BT");
commands.Add($"{textMatrix.A.ToPdfString()} {textMatrix.B.ToPdfString()} {textMatrix.C.ToPdfString()} {textMatrix.D.ToPdfString()} {textMatrix.E.ToPdfString()} {textMatrix.F.ToPdfString()} Tm");
- PdfCellTextItem lastCharacter = line.Words[0].Characters[0];
- PdfCellTextItem currentStyle = line.Words[0].Characters[0];
+ PdfTextFormat lastCharacter = line.Words[0].Characters[0];
+ PdfTextFormat currentStyle = line.Words[0].Characters[0];
string textRun = string.Empty;
double textAdvance = 0d;
double textVAdvance = 0d;
@@ -159,7 +260,7 @@ public void AddText(Vector2 position, PdfCellLines lines, PdfCellAlignmentData a
}
}
- if(wordIndex == words.Characters.Count && j < line.Words.Count - 1)
+ if (wordIndex == words.Characters.Count && j < line.Words.Count - 1)
{
wordIndex = 0;
continue;
@@ -255,7 +356,7 @@ public void AddText(Vector2 position, PdfCellLines lines, PdfCellAlignmentData a
useModifiedMatrix = false;
textRun = string.Empty;
textAdvance = 0;
-
+
if (wordIndex < words.Characters.Count)
{
currentStyle = words.Characters[wordIndex];
@@ -281,16 +382,22 @@ public void AddCellContentLayout(PdfCellContentLayout cell, PdfDictionaries dict
{
commands.Add($"% Content Start: {cell.Name}");
commands.Add("q");
- AddText(cell.LocalPosition, cell.Lines, cell.CellAlignmentData, dictionaries, pageSettings);
+ if (cell.Clip) AddClipping(cell);
+ AddText(cell, cell.LocalPosition, cell.CellAlignmentData.TextRotation, dictionaries, pageSettings);
commands.Add("Q");
commands.Add($"% Content End: {cell.Name}");
}
+ private void AddClipping(PdfCellContentLayout cell)
+ {
+ commands.Add($"{cell.Clipping.X.ToPdfString()} {cell.Clipping.Y.ToPdfString()} {cell.Clipping.Width.ToPdfString()} {cell.Clipping.Height.ToPdfString()} re W n");
+ }
+
public void AddCellContentLayout(PdfHeaderFooterLayout cell, PdfDictionaries dictionaries, PdfPageSettings pageSettings)
{
commands.Add($"% HeaderFooter Start: {cell.Name}");
commands.Add("q");
- //AddText(cell.LocalPosition, cell.Lines, cell.CellAlignmentData, dictionaries, pageSettings);
+ AddText(cell, cell.LocalPosition, 0, dictionaries, pageSettings);
commands.Add("Q");
commands.Add($"% HeaderFooter End: {cell.Name}");
}
@@ -308,15 +415,17 @@ public void AddInnerGridLines(Transform pageLayout)
string w, h;
if (line.X1 == line.X2)
{
- w = GridLine.Width.ToPdfString();
- h = System.Math.Abs(line.Y2 - line.Y1).ToPdfString();
+ w = GridLine.Width.ToPdfStringF4();
+ h = System.Math.Abs(line.Y2 - line.Y1).ToPdfStringF4();
}
else
{
- w = System.Math.Abs(line.X2 - line.X1).ToPdfString();
- h = GridLine.Width.ToPdfString();
+ w = System.Math.Abs(line.X2 - line.X1).ToPdfStringF4();
+ h = GridLine.Width.ToPdfStringF4();
}
- commands.Add($"{line.X1.ToPdfString()} {line.Y1.ToPdfString()} {w} {h} re");
+ var x = Math.Min(line.X1, line.X2);
+ var y = Math.Min(line.Y1, line.Y2);
+ commands.Add($"{x.ToPdfStringF4()} {y.ToPdfStringF4()} {w} {h} re");
}
commands.Add("f");
commands.Add("Q");
@@ -335,8 +444,8 @@ public void AddOuterGridBorder(Transform pageLayout)
commands.Add(Color.Black.ToStrokeCommand());
foreach (var line in pl.BorderLines)
{
- commands.Add($"{line.X1.ToPdfString()} {line.Y1.ToPdfString()} m");
- commands.Add($"{line.X2.ToPdfString()} {line.Y2.ToPdfString()} l");
+ commands.Add($"{line.X1.ToPdfStringF4()} {line.Y1.ToPdfStringF4()} m");
+ commands.Add($"{line.X2.ToPdfStringF4()} {line.Y2.ToPdfStringF4()} l");
}
commands.Add("S");
commands.Add("Q");
@@ -345,7 +454,7 @@ public void AddOuterGridBorder(Transform pageLayout)
public void AddMarginClipping(Transform pageLayout, PdfContentBounds bounds)
{
- if(pageLayout is not PdfPageLayout pl) return;
+ if (pageLayout is not PdfPageLayout pl) return;
commands.Add($"% Margin Clip Start");
double y = bounds.Top;
@@ -366,6 +475,13 @@ internal override string RenderDictionary()
return $"<< /Length {bytes.Length} >>\n" + $"stream\n{content}endstream";
}
+ internal override void RenderDictionary(BinaryWriter bw)
+ {
+ var content = string.Join("\n", commands.ToArray()) + "\n";
+ var bytes = Encoding.ASCII.GetBytes(content);
+ WriteAscii(bw, $"<< /Length {bytes.Length} >>\nstream\n{content}\nendstream");
+ }
+
private string FixEscapeCharacters(string text)
{
return text.Replace(@"\", @"\\").Replace(@"(", @"\(").Replace(@")", @"\)");
diff --git a/src/EPPlus.Export.Pdf/PdfObjects/PdfFonts/CIDSystemInfo.cs b/src/EPPlus.Export.Pdf/PdfObjects/PdfFonts/CIDSystemInfo.cs
new file mode 100644
index 000000000..6d404fb54
--- /dev/null
+++ b/src/EPPlus.Export.Pdf/PdfObjects/PdfFonts/CIDSystemInfo.cs
@@ -0,0 +1,22 @@
+/*************************************************************************************************
+ Required Notice: Copyright (C) EPPlus Software AB.
+ This software is licensed under PolyForm Noncommercial License 1.0.0
+ and may only be used for noncommercial purposes
+ https://polyformproject.org/licenses/noncommercial/1.0.0/
+
+ A commercial license to use this software can be purchased at https://epplussoftware.com
+ *************************************************************************************************
+ Date Author Change
+ *************************************************************************************************
+ 27/11/2025 EPPlus Software AB EPPlus 9
+ *************************************************************************************************/
+
+namespace EPPlus.Export.Pdf.PdfObjects.PdfFonts
+{
+ internal class CIDSystemInfo
+ {
+ public string Registry { get; set; }
+ public string Ordering { get; set; }
+ public int Supplement { get; set; }
+ }
+}
diff --git a/src/EPPlus.Export.Pdf/PdfObjects/PdfFonts/PdfCIDFont.cs b/src/EPPlus.Export.Pdf/PdfObjects/PdfFonts/PdfCIDFont.cs
new file mode 100644
index 000000000..93b714006
--- /dev/null
+++ b/src/EPPlus.Export.Pdf/PdfObjects/PdfFonts/PdfCIDFont.cs
@@ -0,0 +1,158 @@
+/*************************************************************************************************
+ Required Notice: Copyright (C) EPPlus Software AB.
+ This software is licensed under PolyForm Noncommercial License 1.0.0
+ and may only be used for noncommercial purposes
+ https://polyformproject.org/licenses/noncommercial/1.0.0/
+
+ A commercial license to use this software can be purchased at https://epplussoftware.com
+ *************************************************************************************************
+ Date Author Change
+ *************************************************************************************************
+ 27/11/2025 EPPlus Software AB EPPlus 9
+ *************************************************************************************************/
+using EPPlus.Fonts.OpenType;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace EPPlus.Export.Pdf.PdfObjects.PdfFonts
+{
+ public enum CIDFontSubtype
+ {
+ CIDFontType0,
+ CIDFontType2
+ }
+
+ internal class PdfCIDFont : PdfObject
+ {
+ private readonly CIDFontSubtype Subtype;
+ private readonly string BaseFont;
+ private readonly CIDSystemInfo CIDInfoObject;
+ private readonly int FontDescriptorObjectNumber;
+
+ private readonly int? DW; // Default width
+ private readonly List