Bug 49339

Summary: [PATCH] Incorrect AffineTransform in PSGenerator state due to AbstractPSDocumentGraphics2D.startPage method
Product: XMLGraphicsCommons - Now in Jira Reporter: Julien Aymé <julien.ayme>
Component: postscriptAssignee: XML Graphics Project Mailing List <general>
Severity: normal Keywords: PatchAvailable
Priority: P2    
Version: Trunk   
Target Milestone: --   
Hardware: All   
OS: All   
Attachments: The test case
The proposed patch
New enhanced Test case

Description Julien Aymé 2010-05-25 09:37:01 UTC
Created attachment 25483 [details]
The test case

Hi all,

I extended PSDocumentGraphics2D to generate a more optimized PS code, and I noticed that the PSGenerator always wrote the same transformation matrix again and again.

After some search, I found that the startPage method in AbstractPSDocumentGraphics2D uses the concatMatrix method of PSGenerator, which alters the PSGenerator current state to save the given AffineTransform.

I've attached a simple TestCase which shows the problem (fails with current trunk code), and I will attach a simple patch:
Use gen.writeln(gen.formatMatrix(at) + "concat") instead of gen.concatMatrix(at);
Comment 1 Julien Aymé 2010-05-25 09:37:45 UTC
Created attachment 25484 [details]
The proposed patch
Comment 2 Julien Aymé 2010-05-25 09:39:36 UTC
The proposed patch does not alter the rendering of the PostScript document (tested in our applications), and helps reducing the global weight of the generated document.
Comment 3 Jeremias Maerki 2010-05-30 11:46:18 UTC
Julien, I've tried several different approaches to see what the difference is in the generated PS file, but so far, I've never got a difference before and after applying your patch. I remember running into problems because I didn't register certain transformations with the PSGenerator's state. You say you extended PSDocumentGraphics2D. Could it be that some of these extensions have a side-effect which caused you to submit this change? Can you provide an example of the problem you're trying to solve here so I can compare the generated PS code? I've seen your test case, but I'd like to see the effect in PS code. Thanks!
Comment 4 Julien Aymé 2010-05-30 12:25:26 UTC
Hi Jeremias,

I'm not currently at work but I think I can provide a valid use case: I've modified the PSDocumentGraphics2D by adding some "batch" drawing.

The main pattern for the "batch" drawing, like in draw/fill(Shape) method, is:
- Save graphic state, 
- Concat matrix if required,
- Do batch drawing (mainly calls of Graphics2D fill(Shape) and drawString methods)
with no AffineTransform change (important).
- Restore graphic state.

The use case that triggered the issue was, if I remember well:
- Define an AffineTransform (different from Identity) into the Graphics.
- Call any of the "batch" drawing defined above.

The thing is, since I already defined the matrix before calling any of the PSDocumentGraphics2D method, it should not concat the matrix again. But my problem was that even if I just added the matrix to the GraphicState, the method checkTransform returned true, and the matrix was written once again.

I will check tomorrow that this use case was the right one (which triggered the issue).

PS: Thanks for the review of all my patch ;-)
Comment 5 Julien Aymé 2010-05-31 02:44:52 UTC
Created attachment 25499 [details]
New enhanced Test case

I've added a method in the test case which shows exactly the issue encountered when generating the whole PostScript document.
The use case is what I've described in my precedent comment, so here is a code example.
Comment 6 Julien Aymé 2010-06-03 09:49:02 UTC
There is two main benefits from this patch:
In our production environment, we noticed that the generated files weights 15% less (in average), and that the generation is a little faster (far less double formatting involved due to matrix not being written again).
Comment 7 Jeremias Maerki 2010-06-13 11:48:11 UTC
Patch applied: http://svn.apache.org/viewvc?rev=954244&view=rev

Thanks for explaining Julien. Your patch does indeed reduce the PS size in the way you use PSDocumentGraphics2D. However, you're using methods proprietary to PSGraphics2D. That's not the idea of Java2D. If you use plain Graphics2D methods, the problem isn't fixed. Since for every painting operation a new GS/GR pair is generated, the whole CT's are still always generated. At some point we'll have to get rid of the GS/GR pairs if they are not necessary. But at least your change doesn't hurt at all.