Guest User

PostSharp PdfWordWrapper class

a guest
May 3rd, 2020
333
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.59 KB | None | 0 0
  1. using PdfSharp.Drawing;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text.RegularExpressions;
  5.  
  6. /// <summary>
  7. /// PdfWordWrapper
  8. /// wraps text to a specified line width for PDFsharp.
  9. /// Programmed by Huysentruit Wouter
  10. /// © Copyright by Fastload-Media.be
  11. /// https://forum.pdfsharp.net/viewtopic.php?p=3590#p3590
  12. /// </summary>
  13. public class PdfWordWrapper
  14. {
  15.     public enum Alignment { Left, Center, Right, Justify }
  16.  
  17.     private enum BlockType { Text, Space, LineBreak }
  18.  
  19.     private class Block
  20.     {
  21.         public Block(string text, BlockType type, XFont font, XBrush brush, XSize size, double descent)
  22.         {
  23.             this.Text = text;
  24.             this.Type = type;
  25.             this.Font = font;
  26.             this.Brush = brush;
  27.             this.Size = size;
  28.             this.Descent = descent;
  29.         }
  30.  
  31.         public string Text;
  32.         public BlockType Type;
  33.         public XFont Font;
  34.         public XBrush Brush;
  35.         public XSize Size;
  36.         public double Descent;
  37.         public double X = 0;
  38.     }
  39.  
  40.     private class Line
  41.     {
  42.         public List<Block> Blocks = new List<Block>();
  43.         public XSize Size = new XSize(0, 0);
  44.         public double Descent = 0;
  45.     }
  46.  
  47.     private XGraphics graphics;
  48.     private double width;
  49.     private List<Block> blocks = new List<Block>();
  50.     private List<Line> lines = new List<Line>();
  51.     private bool needsProcessing = false;
  52.     private XSize size = new XSize(0, 0);
  53.  
  54.     public PdfWordWrapper(XGraphics graphics, double width)
  55.     {
  56.         if (graphics == null)
  57.             throw new ArgumentNullException("graphics");
  58.  
  59.         this.graphics = graphics;
  60.         this.width = width;
  61.     }
  62.  
  63.     private void CreateBlocks(string text, XFont font, XBrush brush)
  64.     {
  65.         double spaceWidth = graphics.MeasureString("X X", font).Width - graphics.MeasureString("XX", font).Width;
  66.         double lineHeight = font.GetHeight();
  67.         double descent = -(lineHeight * font.Metrics.Descent / font.Metrics.XHeight);
  68.  
  69.         Regex regex = new Regex(@"(\s)|(\S+)");
  70.         text = text.Replace('\r', '\n');
  71.  
  72.         foreach (Match match in regex.Matches(text))
  73.         {
  74.             string value = match.Groups[0].Value;
  75.  
  76.             if ((value == null) || (value == ""))
  77.                 continue;
  78.  
  79.             if (value == " ")
  80.             {
  81.                 XSize size = graphics.MeasureString(value, font);
  82.                 size.Width = spaceWidth;
  83.                 size.Height = lineHeight;
  84.                 blocks.Add(new Block(value, BlockType.Space, font, null, size, descent));
  85.                 continue;
  86.             }
  87.  
  88.             if (value == "\n")
  89.             {
  90.                 blocks.Add(new Block(value, BlockType.LineBreak, null, null, new XSize(0, lineHeight), descent));
  91.                 continue;
  92.             }
  93.  
  94.             XSize blockSize = graphics.MeasureString(value, font);
  95.  
  96.             while (blockSize.Width > width)
  97.             {
  98.                 for (int i = value.Length - 1; i > 0; i--)
  99.                 {
  100.                     string part = value.Substring(0, i);
  101.  
  102.                     blockSize = graphics.MeasureString(part, font);
  103.                     blockSize.Height = lineHeight;
  104.  
  105.                     if (blockSize.Width > width)
  106.                         continue;
  107.  
  108.                     blocks.Add(new Block(part, BlockType.Text, font, brush, blockSize, descent));
  109.  
  110.                     value = value.Substring(i, value.Length - i);
  111.  
  112.                     if (value.Length == 0)
  113.                     {
  114.                         blockSize = XSize.Empty;
  115.                         break;
  116.                     }
  117.                 }
  118.             }
  119.  
  120.             if (value.Length > 0)
  121.                 blocks.Add(new Block(value, BlockType.Text, font, brush, blockSize, descent));
  122.         }
  123.  
  124.         needsProcessing = true;
  125.     }
  126.  
  127.     public void Process()
  128.     {
  129.         Line line = new Line();
  130.         bool lineBreak = false;
  131.  
  132.         size.Width = width;
  133.         size.Height = 0;
  134.  
  135.         foreach (Block block in blocks)
  136.         {
  137.             if (((line.Size.Width + block.Size.Width) > width) || lineBreak)
  138.             {   // Create a new line...
  139.                 // Skip space at the end of a line
  140.                 if (line.Blocks.Count > 0)
  141.                 {
  142.                     Block lastBlock = line.Blocks[line.Blocks.Count - 1];
  143.                     if (lastBlock.Type == BlockType.Space)
  144.                     {
  145.                         line.Size.Width -= lastBlock.Size.Width;
  146.                         line.Blocks.Remove(lastBlock);
  147.                     }
  148.                 }
  149.  
  150.                 // Add line to list
  151.                 lines.Add(line);
  152.  
  153.                 // Create new line
  154.                 line = new Line();
  155.  
  156.                 // Skip space at beginning of a new line
  157.                 if (block.Type == BlockType.Space)
  158.                     continue;
  159.  
  160.                 lineBreak = false;
  161.             }
  162.  
  163.             block.X = line.Size.Width;
  164.             line.Size.Width += block.Size.Width;
  165.             line.Blocks.Add(block);
  166.  
  167.             if (block.Descent > line.Descent)
  168.                 line.Descent = block.Descent;
  169.  
  170.             if (block.Size.Height > line.Size.Height)
  171.             {
  172.                 size.Height -= line.Size.Height;
  173.                 size.Height += block.Size.Height;
  174.                 line.Size.Height = block.Size.Height;
  175.             }
  176.  
  177.             if (block.Type == BlockType.LineBreak)
  178.                 lineBreak = true;
  179.         }
  180.  
  181.         if (line.Blocks.Count > 0)
  182.             lines.Add(line);
  183.  
  184.         // Override the measured width
  185.         size.Width = width;
  186.  
  187.         foreach (Line l in lines)
  188.             size.Height += l.Descent;
  189.  
  190.         needsProcessing = false;
  191.     }
  192.  
  193.     public void Clear()
  194.     {
  195.         blocks.Clear();
  196.         lines.Clear();
  197.         needsProcessing = false;
  198.     }
  199.  
  200.     public void Add(string text, XFont font, XBrush brush)
  201.     {
  202.         CreateBlocks(text, font, brush);
  203.     }
  204.  
  205.     public void Draw(XGraphics g, double x, double y, Alignment align)
  206.     {
  207.         if (needsProcessing)
  208.             Process();
  209.  
  210.         double lineOffsetX = 0;
  211.         double lineOffsetY = 0;
  212.         double justifySpacing = 0;
  213.         double justifyOffsetX = 0;
  214.  
  215.         foreach (Line line in lines)
  216.         {
  217.             lineOffsetY += line.Size.Height;
  218.  
  219.             if (align == Alignment.Center)
  220.                 lineOffsetX = (size.Width - line.Size.Width) / 2;
  221.  
  222.             if (align == Alignment.Right)
  223.                 lineOffsetX = size.Width - line.Size.Width;
  224.  
  225.             if (align == Alignment.Justify)
  226.             {
  227.                 int spaceCount = 0;
  228.                 foreach (Block block in line.Blocks)
  229.                     if (block.Type == BlockType.Space)
  230.                         spaceCount++;
  231.  
  232.                 justifyOffsetX = 0;
  233.                 justifySpacing = (size.Width - line.Size.Width) / (double)spaceCount;
  234.             }
  235.  
  236.             foreach (Block block in line.Blocks)
  237.             {
  238.                 if (block.Type == BlockType.LineBreak)
  239.                     continue;
  240.  
  241.                 if (block.Type == BlockType.Space)
  242.                 {
  243.                     if (align == Alignment.Justify)
  244.                         justifyOffsetX += justifySpacing;
  245.                     continue;
  246.                 }
  247.  
  248.                 g.DrawString(block.Text, block.Font, block.Brush, x + block.X + lineOffsetX + justifyOffsetX, y + lineOffsetY);
  249.             }
  250.  
  251.             lineOffsetY += line.Descent;
  252.         }
  253.     }
  254.  
  255.     public XSize Size
  256.     {
  257.         get { return size; }
  258.     }
  259. }
Add Comment
Please, Sign In to add comment