Bug 38731 - org.apache.fop.svg.PDFGraphics2D minor problems
Summary: org.apache.fop.svg.PDFGraphics2D minor problems
Status: CLOSED FIXED
Alias: None
Product: Fop - Now in Jira
Classification: Unclassified
Component: pdf (show other bugs)
Version: 0.20.5
Hardware: All All
: P4 enhancement
Target Milestone: ---
Assignee: fop-dev
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-02-21 10:14 UTC by Michal Sevcenko
Modified: 2012-04-01 06:28 UTC (History)
0 users



Attachments
the new suggested implementation of PDFGraphics2D.java (58.26 KB, text/plain)
2006-02-21 10:20 UTC, Michal Sevcenko
Details
PDFGraphics2D patched w.r.t. fop-0.91 (2.74 KB, patch)
2006-02-21 16:23 UTC, Michal Sevcenko
Details | Diff
a sample file for handling missing glyphs (2.13 KB, text/plain)
2006-02-21 16:36 UTC, Michal Sevcenko
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michal Sevcenko 2006-02-21 10:14:40 UTC
I have a few suggestions how to improve the PDFGraphics2D class to be more 
conforming to the java.awt.Graphics2D interface.

I use the FOP library for direct generation of PDF from a Java application 
(i.e. I do not use FOP for XML to PDF translation), but I think that the 
suggestions might be relevant to the FO processing as well.

I found the following problems in the class implementation:

1) When rendering text, the class uses Font.getSize instead of Font.getSize2D. 
This means that the text scales only with integer resolution, which results in 
big errors when rendering text with non-integer size.

2) Text rendering ignores Font's transformation matrix. The matrix is useful 
e.g. for generating slanted or narrowed/widened text. Enabling it is very easy 
(see below).

3) For some reason, drawImage(Image, int, int, ImageObserver) translates the 
white opaque pixels to transparent. I suggest not to set white color as 
transparent, but to change fully transparent pixels to some less usual color 
(I used 255,255,254), and setting this color as transparent.

4) I also changed the text rendering to automatically convert texts 
containing "unsupported chars" (chars that do not display in PDF correctly 
using default fonts) to curves. But this issue you probably solve elsewhere.

It would be also nice to have the PDFGraphics2D.currentStream field protected, 
so that I can fix these problems by subclassing the PDFGraphics2D and override 
the problematic methods instead of rebuilding the original FOP jar file.

Below see the commented diff of the PDFGraphics2D.java file (# precedes 
comments added to the diff) The diffis made against fop-0.20.5 source 
distribution. (unfortunately the line numbers may be slightly incorrect as I 
reformated the source code)

The diff:
----------------------------------------------------------------
71a72
> import java.awt.font.GlyphVector;
148c149
<     protected int currentFontSize;
---
>     protected float currentFontSize;

# in public boolean drawImage(Image, int, int, ImageObserver)

# change fully transparent pixels (alpha = 0) to (255,255,254)
360c361,365
<                         if (alpha != 255) {
---
>                         if (alpha == 0) {
>                             result[count++] = (byte) (0xFF);
>                             result[count++] = (byte) (0xFF);
>                             result[count++] = (byte) (0xFE);
>                         } else if (alpha != 255) {

# in class TempImage

#change transparent color to our special color
429c434
<         PDFColor transparent = new PDFColor(255, 255, 255);
---
>         PDFColor transparent = new PDFColor(255, 255, 254);

# a method that draws text as curves
923a929,933
>     private void drawStringAsGlyphs(String s, float x, float y) {
>         GlyphVector gv = getFont().createGlyphVector(getFontRenderContext(), 
s);
>         fill(gv.getOutline(x, y));
>     }
> 

# in public void drawString(String, float, float)

# draw unsupported text as string
949c959,962
<         // System.out.println("drawString(String)");
---
>         if (!isSupportedString(s)) {
>             drawStringAsGlyphs(s, x, y);
>             return;
>         }

# save font's transform
950a964
>         AffineTransform fontTransform = null;
952a967
>             fontTransform = gFont.getTransform();

#use fractional height instead of integer height
957c972
<             int siz = gFont.getSize();
---
>             float siz = gFont.getSize2D();
962c977
<                         weight, siz * 1000, 0);
---
>                         weight, (int) (siz * 1000 + 0.5), 0);
971c986
<         int size;
---
>         float size;
973c988
<         size = fontState.getFontSize() / 1000;
---
>         size = fontState.getFontSize() / 1000f;

# apply font transform if neccessary
1019a1035,1037
>         if (fontTransform != null && !fontTransform.isIdentity())
>             trans.concatenate(fontTransform);
> 

# new helper methods determining whether string is "supported"

1070a1089,1115
>     private boolean isSupportedString(String s) {
>         for (int i = 0; i < s.length(); ++i)
>             if (!isSupportedChar(s.charAt(i)))
>                 return false;
>         return true;
>     }
> 
>     private boolean isSupportedChar(char c) {
>         if (c >= 0x20 && c < 0xFF)
>             return true;
>         return ("\u20AC\u201A\u0192\u201E\u2026\u2020\u2021\u02C6\u2030
\u0160"
>                 + "\u2039\u004F\u017D\u2018\u2019\u201C\u201D\u2022\u2013
\u2014"
>                 + "\u02DC\u2122\u0161\u203A\u006F\u017E\u0178\u00A1\u00A2
\u00A3"
>                 + "\u00A4\u00A5\u00A6\u00A7\u00A8\u00A9
\u00AA\u00AB\u00AC\u002D"
>                 + "\u00AE\u00AF\u00B0\u00B1\u00B2\u00B3\u00B4\u03BC\u00B6
\u00B7"
>                 + "\u00B8\u00B9\u00BA\u00BB\u00BC\u00BD\u00BE\u00BF\u00C0
\u00C1"
>                 + "\u00C2\u00C3\u00C4\u00C5\u00C6\u00C7\u00C8\u00C9
\u00CA\u00CB"
>                 + "\u00CC\u00CD\u00CE\u00CF\u00D0\u00D1\u00D2\u00D3\u00D4
\u00D5"
>                 + "\u00D6\u00D7\u00D8\u00D9
\u00DA\u00DB\u00DC\u00DD\u00DE\u00DF"
>                 + "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5\u00E6\u00E7\u00E8
\u00E9"
>                 + "\u00EA\u00EB\u00EC\u00ED\u00EE\u00EF\u00F0\u00F1\u00F2
\u00F3"
>                 + "\u00F4\u00F5\u00F6\u00F7\u00F8\u00F9
\u00FA\u00FB\u00FC\u00FD"
>                 + "\u00FE\u00FF\u004F\u006F\u0160\u0161\u0178
\u017D\u017E\u0192"
>                 + "\u2013\u2014\u2018\u2019\u201A\u201C\u201D\u201E\u2020
\u2021"
>                 + "\u2022\u2026\u2030\u2039\u203A\u20AC\u2122").indexOf(c) !
= -1;
>     }
> 
1367a1413
> 
1371a1418,1425
> 
>         // needed for compiling under jdk1.4
> 
>         public java.awt.image.VolatileImage createCompatibleVolatileImage(
>                 int width, int height, int transparency) {
>             return null;
>         }
>
Comment 1 Michal Sevcenko 2006-02-21 10:20:03 UTC
Created attachment 17756 [details]
the new suggested implementation of PDFGraphics2D.java
Comment 2 Jeremias Maerki 2006-02-21 10:25:08 UTC
I'm happy to see that the PDFGraphics2D is actually useful outside of FOP and
Batik. And thanks for your suggestions to improve the code. However, I would
like to encourage you to download the latest FOP source code (FOP Trunk) from
Subversion:
http://xmlgraphics.apache.org/fop/download.html
Subversion checkout URL: http://svn.apache.org/repos/asf/xmlgraphics/fop/trunk/

There have been major improvements in that area although most of what you
suggest hasn't been changed. Please apply the changes to FOP Trunk and attach a
patch generated by the "svn diff" command to this Bugzilla issue. We will then
review your changes and integrate them. Please note that the FOP 0.20.5
development line has been frozen.
Comment 3 Michal Sevcenko 2006-02-21 16:23:47 UTC
Created attachment 17757 [details]
PDFGraphics2D patched w.r.t. fop-0.91

I hope that the patch file is what you want, I'm not familiar with the
subversion system, I generated it using TortoiseSVN.

Few comments, as things changed quite a bit since my last post:

1) the code for generating string output mysteriously changed since last time,
the translation of text was moved from graphic's global transform to text's
local transform, so it was more difficult to combine with font's transform, but
I did it anyway, so hopefully it works. I tested it on two typical cases:
narrowed text and slanted text. Please note that I did not change drawString
with AttributedCharacterIterator as I do not use it, but the change is
analogous. Suprisingly this second method uses the "old" way of combining
graphic and text transforms, i.e. the text translation is combined with graphic
transform, and the text uses simple Y inverse transform

2) the transparency handling changed a lot, but the bug is still there. It
seems to me that it is sufficient to comment out forgotten
BitmapImage.setTransparent line. The transparency seems to be correctly handled
by a companion mask stream added to the primary bitmap stream.
Comment 4 Michal Sevcenko 2006-02-21 16:36:08 UTC
Created attachment 17758 [details]
a sample file for handling missing glyphs

Btw I moved the stuff for text->curve replacement to a subclass of
PDFGraphics2D, so I attach it for those who are interested; but I suspect it
won't be very useful of the FOP library itself :-|
Comment 5 Jeremias Maerki 2006-03-19 11:19:00 UTC
Patch applied: http://svn.apache.org/viewcvs?rev=386954&view=rev

Thank you, Michal, for this useful patch. Concerning your special code about
stroking text that contains unsupported characters: This would actually be
useful but not in the way you've implemented it. Our font subsystem has methods
to tell you which characters are available from a font (Font.hasChar(char)). So,
you can do this in a generic way and don't have to hard-code the characters.
Comment 6 Glenn Adams 2012-04-01 06:28:59 UTC
batch transition pre-FOP1.0 resolved+fixed bugs to closed+fixed