Optimize XPS markup


XPS is hot, so naturally more and more applications will be generating XPS. If your application has access to the XPS Document Writer, then the easiest way to generate XPS is just print to it. But there are cases you may want to generate XPS on your own, either because you can’t use the XPS Document Writer, or you want a better solution.


In case you want to generate XPS on your own, here are a few tips on how to generate better XPS markup:



  • Read the XPS spec. Understand what is really supported and what is not.
  • Play with the XPS Document Writer, just to see what kind of markup is generated by it. Remember the XPS Document Writer is also improving.
  • Play with XPS markup using XamlPad. XPS is a subset of XAML, so you can edit a little piece of XPS markup in XamlPad and see how is it rendered.
  • Check default values. If an attribute has a default value and the current value matches it, it does not need to be written down.
  • Use Canvas element. If a group of primitives share the same transformation, clipping, opacity, opacity mask, group them in a Canvas, set those attributes only once. But do not use Canvas to group a single primitive.
  • Use shorthand form for Path geometry, avoid using the Element from of Path if possible.
  • Use ResourceDictionary, if a gradient brush, image brush, or visual brush is used multiple times, put it into Resource Dictionary and reference to it.
  • Use integers. By default, coordinates in XPS is in 96-dpi, so to specify coordinates in higher resolution, you need to use floating point numbers. If you have lots of vector data, it will reduce markup size if you introduce a transformation at the top to increase the resolution to say, 600-dpi, and then use integers underneath. If you use floating point, your data would most likely to be in the form of xxx.yy; if you use integers, it could be zzzz, saving 2 bytes per number.
  • Optimize images: check image dimension, check image pixel format, check image compression, reuse image within the whole document.
  • Optimize fonts: use font subsetting.
  • Optimize input to your XPS generator:

    • Remove anything with opacity <= 0
    • Remove things with null brush
    • Remove things which are fully clipped.
    • Remve things which are overlapped fully on the top with an opaque object.
    • If OpacityMask is always opaque, remove it.
    • If OpacityMask is solid color brush, just extract the opacity out and mutiply to Opacity attribute.
    • Change degenerated gradient brush to solid color brush.
    • Remove primitives which are out of page boundary.
    • Merge simple primitives with the same brush, pen, font into a single primitive when possible.
    • Merge images adjacent to each other into single image when possible.

If you have issues and concerns about XPS, talk to us (xpsinfo @ microsoft . com)

Comments (1)

  1. Hi,

    We are in a situation where we process thousands of XAML markups(FixedDocuments), load them using XamlReader.Load(),Bind data and generating XPS using FixedDocumentSequence. The issues we are facing as follows. 1. High Memory consumption, FixedDocument are not Garbage collected till we close the app. 2. Unable to reuse the FixedDocuments after adding them to FixedDocumentSequence. 3. XamlReader.Load() and rendering time are very high.

    We taken care about removing default values, making sure the xaml markup as simple as possible, but we still have the issues. Please advise us for any possible optimization.