Convert XAML Flow Document to XPS with Style (multiple page, page size, header,

The original post is available here: 

 

Convert XAML Flow Document to XPS with Style (multiple page, page size, header, margin)

 

 

 

 

XPS is a fixed document format in which pages are pre-formated to a fixed page sixe. On the opposite of the spectrum, WPF provides flow document which can be paginated dynamically in XAML viewer. To bridge the two, WPF provides features to convert a flow document to fixed document in XPS format. Actually, you can convert any WPF Visual content to XPS.

While the default conversion is very easy to use, if you want more features, you need to write some code. This acticle shows how to convert WPF flow document to multiple page XPS with page size, margin, and header.

When a flow document is loaded in WPF, it returns an IDocumentPaginatorSource object. From it, you can get its DocumentPaginator object. When you're using XpsSerializationManager to convert a loaded flow document to XPS, it accepts a DocumentPaginator object. But the little know fact is that WPF allows you to wrap a new DocumentPaginator around a DocumentPaginator to control the conversion process.

Here is our DocumentPaginator wrapper class:

 

 

 

 

public class DocumentPaginatorWrapper : DocumentPaginator
  {

    Size m_PageSize;
    Size m_Margin;
    DocumentPaginator m_Paginator;
    Typeface m_Typeface;


    public DocumentPaginatorWrapper(DocumentPaginator paginator, Size pageSize, Size margin)
    {
      m_PageSize = pageSize;
      m_Margin = margin;
      m_Paginator = paginator;
      

      m_Paginator.PageSize = new Size(m_PageSize.Width  - margin.Width  * 2,
                                        m_PageSize.Height - margin.Height * 2);

    }

    Rect Move(Rect rect)
    {
      if (rect.IsEmpty)
      {
        return rect;
      }
      else
      {
        return new Rect(rect.Left + m_Margin.Width, rect.Top + m_Margin.Height,
                        rect.Width, rect.Height);
      }
    }


    public override DocumentPage GetPage(int pageNumber)
    {
      DocumentPage page = m_Paginator.GetPage(pageNumber);

      // ContainerVisual - the container of visual
      ContainerVisual newpage = new ContainerVisual();
      DrawingVisual title = new DrawingVisual();

      using (DrawingContext ctx = title.RenderOpen())
      {
        if (m_Typeface == null)
        {
          m_Typeface = new Typeface("Times New Roman");
        }
        // drawing header
        FormattedText text = new FormattedText("Page " + (pageNumber + 1),
          System.Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight,
          m_Typeface,
          14, Brushes.Black);

        ctx.DrawText(text, new Point(0, -96 / 4)); // 1/4 inch above page content
      }

      DrawingVisual background = new DrawingVisual();
      using (DrawingContext ctx = background.RenderOpen())
      {
        ctx.DrawRectangle(new SolidColorBrush(Color.FromRgb(240, 240, 240)), null, page.ContentBox);
      }

      newpage.Children.Add(background); // scale down page and center
      // ContainerVisual - the container of visual
      ContainerVisual smallerpage = new ContainerVisual();
      smallerpage.Children.Add(page.Visual);
      smallerpage.Transform = new MatrixTransform(0.95, 0, 0, 0.95,
                0.025 * page.ContentBox.Width, 0.025 * page.ContentBox.Height);
      newpage.Children.Add(smallerpage);
      newpage.Children.Add(title);

      newpage.Transform = new TranslateTransform(m_Margin.Width, m_Margin.Height);

      return new DocumentPage(newpage, m_PageSize, Move(page.BleedBox), Move(page.ContentBox));
    }

    public override bool IsPageCountValid
    {
      get { return m_Paginator.IsPageCountValid; }
    }

    public override int PageCount
    {
      get { return m_Paginator.PageCount;  }
    }

    public override Size PageSize
    {
      get
      {
        return m_Paginator.PageSize;
      }
      set
      {
        m_Paginator.PageSize = value;
      }
    }

    public override IDocumentPaginatorSource Source
    {
      get { return m_Paginator.Source; }
    }
  }
 

 

 

and 

 

 

 

The DocumentPaginatorWrapper constructor modifies the page size of the original paginator based on required page size and margin. The new GetPage method calls the original GetPage method to get a page, then adds a header Visual, a background Visual (just to show the original page), and then move the combined Visual by top left margin. To demonstrate that you can easily transform a Visual, the original page Visual is scaled down and centered within its original box.

Here is the code calling the wrapper class to load a flow XAML document and convert to an XPS document:

 

 

 

 

 

 

 public static int SaveAsXps(string filename)
    {
      object doc;


      FileInfo fileinfo = new FileInfo(filename);
      using(FileStream file = fileinfo.OpenRead())
      {
        System.Windows.Markup.ParserContext context = new System.Windows.Markup.ParserContext();
        context.BaseUri = new Uri(fileinfo.FullName, UriKind.Absolute);
        doc = System.Windows.Markup.XamlReader.Load(file, context);

      }

      if (!(doc is IDocumentPaginatorSource))
      {
        Console.WriteLine("DocumentPaginatorSource expected");
        return -1;
      }

      using (Package container = Package.Open(filename + ".xps", FileMode.Create))
      {

        using (XpsDocument xpsDoc = new XpsDocument(container, CompressionOption.Maximum))
        {
          XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(xpsDoc), false);
          DocumentPaginator paginator = ((IDocumentPaginatorSource)doc).DocumentPaginator;

          paginator = new DocumentPaginatorWrapper(paginator, new Size(768, 676), new Size(48, 48));

          rsm.SaveAsXaml(paginator);
        }
      }
      Console.WriteLine("{0} generated.", filename + ".xps");

      return 0;
    
    }

  }
 

 

 

The code above loads a flow XAML document and paginates it to 8 inch by 6 inch, with half inch margin.

 

Below is the sample output 

 


as you can see, the xps document has the following elements.

 

 

1. the header "page 1"

2. the content is centered with margins.

3. background is gray (240, 240, 240)

 

while the true content of the XpsDocument is actually a flow document. Here is the content of the FlowDocument.

 

 

 

<FlowDocument 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
  <Paragraph FontSize="18">Flow Format Example</Paragraph>

  <Paragraph>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy 
      nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi 
      enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis 
      nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
  </Paragraph>
  <Paragraph>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh 
      euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim 
      ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl 
      ut aliquip ex ea commodo consequat. Duis autem vel eum iriure.
  </Paragraph>

  <Paragraph FontSize="18">More flow elements</Paragraph>
  <Paragraph FontSize="15">Inline, font type and weight, and a List</Paragraph>

  <List>
    <ListItem>
      <Paragraph>ListItem 1</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>ListItem 2</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>ListItem 3</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>ListItem 4</Paragraph>
    </ListItem>
    <ListItem>
      <Paragraph>ListItem 5</Paragraph>
    </ListItem>
  </List>

  <Paragraph>
    <Bold>Bolded</Bold>
  </Paragraph>
  <Paragraph>
    <Underline>Underlined</Underline>
  </Paragraph>
  <Paragraph>
    <Bold>
      <Underline>Bolded and Underlined</Underline>
    </Bold>
  </Paragraph>
  <Paragraph>
    <Italic>Italic</Italic>
  </Paragraph>

  <Paragraph>
    <Span>The Span element, no inherent rendering</Span>
  </Paragraph>
  <Paragraph>
    <Run>The Run element, no inherent rendering</Run>
  </Paragraph>

  <Paragraph FontSize="15">Subscript, Superscript</Paragraph>

  <Paragraph>
    <Run Typography.Variants="Superscript">This text is Superscripted.</Run> This text isn't.
  </Paragraph>
  <Paragraph>
    <Run Typography.Variants="Subscript">This text is Subscripted.</Run> This text isn't.
  </Paragraph>
  <Paragraph>
    If a font does not support a particular form (such as Superscript) a default font form will be displayed.
  </Paragraph>

  <Paragraph FontSize="15">Blocks, breaks, paragraph</Paragraph>

  <Section>
    <Paragraph>A block section of text</Paragraph>
  </Section>
  <Section>
    <Paragraph>Another block section of text</Paragraph>
  </Section>

  <Paragraph>
    <LineBreak/>
  </Paragraph>
  <Section>
    <Paragraph>... and another section, preceded by a LineBreak</Paragraph>
  </Section>

  <Section BreakPageBefore="True"/>
  <Section>
    <Paragraph>... and another section, preceded by a PageBreak</Paragraph>
  </Section>

  <Paragraph>Finally, a paragraph. Note the break between this paragraph ...</Paragraph>
  <Paragraph TextIndent="25">... and this paragraph, and also the left indention.</Paragraph>

  <Paragraph>
    <LineBreak/>
  </Paragraph>

</FlowDocument>
 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值