-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API Proposal]: Lightweight in-place XpsDocument modification APIs #10361
Comments
I think it would be helpful if the API changes also included the current members, or at least the relevant ones (like Add counterparts). Both the reader and writer interface derive from I am not a fan of *Reader interfaces having *Writer properties. They are unrelated, and changing the interfaces is breaking. Unless I overlooked something, there is no *Reader properties defined on existing interfaces, so there shouldn't be need to have interfaces for *Writer properties. You can define a Writer property directly on e.g. Furthermore, this assumes that the reader/writer are 1) random access 2) mutable. I think it is perfectly reasonable and desirable to have fast forward-only readers/writers. You could remove say a page by copying - implementing a reader that does not write it to the writer. If we are to have mutable writers, we should have a new set of interfaces with the Remove methods. |
Thanks @miloush. I've added the current interface members, and expanded it to include IDocumentStructureProvider and IStoryFragmentProvider. You're correct, I'd missed those - apologies. I understand the hesitation about blurring the *Reader and *Writer boundaries. These boundaries are already blurred though - Are the interface changes really a breaking change? It's my understanding that adding a DIM to an interface is described by the runtime documentation as permitted (link.) |
I think it is more useful for consumers to check whether something implements an interface with the stuff they want rather than getting exceptions when trying to use it. By the way have you seen https://learn.microsoft.com/en-us/windows/win32/printdocs/documents-xps? Maybe these interfaces could be used when creating a standalone library. |
I agree, but the new member's default implementation is purely to prevent the proposal from becoming a breaking change: If another class implementing the interface was compiled against the .NET 9.0 version of the interface, that type can be loaded in .NET 10.0+ and its methods can be bound to the new version. The WPF-provided implementation naturally wouldn't throw. Whether we add a new interface or modify the existing one, none of our options are ideal. If we add a new "IXpsFixedPageWriter2" interface which derives from IXpsFixedPageWriter and adds the relevant methods, that new interface needs to be exposed somehow. Changing the return type of var pgWriter = documentSequenceWriter.Pages[0]; // or similar
// .NET vNext
if (pgWriter is IXpsFixedPageWriter2 pgWriter2)
{
pgWriter2.RemoveFont(fontToRemove);
}
else
{
// .NET 9.0 doesn't support this method, use alternative approach here
} When upgrading to .NET vNext, this code becomes: var pgWriter2 = documentSequenceWriter.Pages[0] as IXpsFixedPageWriter2;
pgWriter2.RemoveFont(fontToRemove); In this situation, our documented return type is no longer as accurate - consumers have to "just know" that to (for e.g.) remove fonts from a page, they need to cast the return value to its derived type. From a newcomer's perspective, that lack of discoverability could be confusing; even if documented there's no way to fix the root cause of that confusion without introducing a breaking change. On the other hand: adding a default implementation means that if a downstream library implements IXpsFixedPageWriter but doesn't implement the new methods, those methods will throw at runtime. That's a poor consumer experience too, but there's at least a path to fix it without needing any breaking changes. What do you think about adding
Thanks for these. I did see those and did consider writing a library - but while I was testing, I found that the majority of the performance improvements with XPS processing actually came from being able to modify individual pages in an XPS document in their own threads. I think that if we can work out a sensible way to make this API proposal to let the writer interfaces modify XPS documents (rather than just create them) then it'll actually provide the majority of the performance improvements. |
What about say I also noticed that there are these implementations:
So in practice you don't need to have the writer properties on readers, you can just cast them to writers.
Taking a step back, how do the proposed changes enable this? Removing pages seems to be the only useful thing that the API allows. Without being able to edit or access the page content, the others like removing font and images don't seem to be very useful. This also corresponds to your example usage. There is also nothing to guarantee thread safety. All the classes share an instance of |
Background and motivation
Relates to #4000, providing the API proposal for the ability to read and rewrite the structure of an XPS document.
There are three objectives with this proposal:
IXpsFixedDocumentSequenceWriter
for anXpsDocument
's existingFixedDocumentSequence
. At present, the only way to access anIXpsFixedDocumentSequenceWriter
is to create one - and only one can be created perXpsDocument
, so it's not possible to amend existingXpsDocument
s.FixedDocumentSequence
,FixedDocument
andFixedPage
's reader APIs to their writer APIs. This should be simple enough: the underlying implementation implements both interfaces, so I expect these three properties could potentially just returnthis
.IXps*Reader
can be modified fromIXps*Writer
.The wider goal is to allow an XPS document's XML structure to be inspected in a way which doesn't involve instantiating full WPF controls (with the thread affinity this implies) or using STA threads in the way that the existing
XpsDocumentWriter
API requires. With that said, this enables some functionality too - being able to navigate from a page'sIXpsFixedPageReader
to itsIXpsFixedPageWriter
means that we can get to the rawXmlWriter
APIs, so any future XPS support can build on these types.Although #4000 relates to modifying and printing XPS documents, this proposal only addresses the modification aspect - I think that's where the largest speed/memory usage improvement lies.
API Proposal
All of these members have default interface members which throw a NotImplementedException; this is to avoid introducing source breaking changes.
API Usage
Alternative Designs
XPS support could be moved into its own library, separate to WPF and similar to OpenXML. This could make XPS support cross-platform, but it'd need a much larger effort and it'd need someone to maintain that library.
For the moment, the key obstacle is the inability to read and update XPS documents without instantiating WPF controls and by using multiple threads. I expect that once it becomes possible to open an XPS document, iterate through its pages and access each page's
XmlReader
andXmlWriter
, this functionality can be used as building blocks if somebody wants to build a strongly-typed API later.Risks
No response
The text was updated successfully, but these errors were encountered: