Hi once more, >>> I believe that with FOP 0.20.5 tspans were handled too (however I might >>> be wrong), because PDF generated with old version were OK. >> I believe the old version ignored all the problems that >> sub-tspans with x & y cause and just rendered them as normal >> text. This might have 'worked' for your case but is why there >> was a 'stroke text' option as it would get many cases wrong. > I see, then maybe you can point out how to simply patch the TRUNK code > to work like 0.20.5 for 'tspans' even it is wrong ?? Of course I wish to > use it internally for myself as I'm generating lot of docbook documents > with SVG drawings with text.
Okay ... I was very anxious and did patch for the code by myself. Seems to work fine with my SVGs... I just took the PDFTextPainter code from 0.20.5 which was doing some counting for TSPANs. Attached patch... might be useful. Anyway... I have a now PERFECT FOP for my documents :))) Regards, -- Adam Strzelecki |: nanoant.com :|
Index: PDFTextElementBridge.java =================================================================== --- PDFTextElementBridge.java (revision 356302) +++ PDFTextElementBridge.java (working copy) @@ -1,12 +1,12 @@ /* * Copyright 1999-2004 The Apache Software Foundation. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -56,7 +56,7 @@ */ public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) { GraphicsNode node = super.createGraphicsNode(ctx, e); - if (node != null && isSimple(ctx, e, node)) { + if (node != null /*&& isSimple(ctx, e, node)*/) { ((TextNode)node).setTextPainter(getTextPainter()); } return node; @@ -80,6 +80,7 @@ * @return true if this text is simple of false if it cannot be * easily rendered using normal drawString on the PDFGraphics2D */ + /* private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode node) { // Font size, in user space units. float fs = TextUtilities.convertFontSize(element).floatValue(); @@ -111,12 +112,13 @@ case Node.CDATA_SECTION_NODE: } } - + */ /*if (CSSUtilities.convertFilter(element, node, ctx) != null) { return false; }*/ - + /* return true; } + */ } Index: PDFTextPainter.java =================================================================== --- PDFTextPainter.java (revision 356302) +++ PDFTextPainter.java (working copy) @@ -1,12 +1,12 @@ /* * Copyright 1999-2004 The Apache Software Foundation. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -82,84 +82,109 @@ * specified Graphics2D and context and font context. * @param node the TextNode to paint * @param g2d the Graphics2D to use + * @param context the rendering context. */ public void paint(TextNode node, Graphics2D g2d) { + // System.out.println("PDFText paint"); String txt = node.getText(); Point2D loc = node.getLocation(); - + /* + AttributedCharacterIterator aci = - node.getAttributedCharacterIterator(); - // reset position to start of char iterator + node.getAttributedCharacterIterator(); if (aci.getBeginIndex() == aci.getEndIndex()) { return; } + // reset position to start of char iterator char ch = aci.first(); if (ch == AttributedCharacterIterator.DONE) { return; } - TextNode.Anchor anchor; - anchor = (TextNode.Anchor) aci.getAttribute( - GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE); + */ + TextNode.Anchor anchor = + (TextNode.Anchor)node.getAttributedCharacterIterator().getAttribute(GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE); + if (anchor != null) { + } + /* + System.out.println("-----"+txt); + printAttrs(node.getAttributedCharacterIterator()); + */ + paintTextRuns(node.getTextRuns(), g2d, loc); - List gvtFonts; - gvtFonts = (List) aci.getAttribute( - GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES); + } + + protected void paintTextRuns(List textRuns, Graphics2D g2d, Point2D loc) { + Point2D currentloc = loc; + Iterator i = textRuns.iterator(); + while (i.hasNext()) { + StrokingTextPainter.TextRun run = + (StrokingTextPainter.TextRun)i.next(); + currentloc = paintTextRun(run, g2d, currentloc); + } + } + + + protected Point2D paintTextRun(StrokingTextPainter.TextRun run, Graphics2D g2d, Point2D loc) { + AttributedCharacterIterator aci = run.getACI(); + return paintACI(aci, g2d, loc); + } + + + protected String getText(AttributedCharacterIterator aci) { + StringBuffer sb = new StringBuffer(aci.getEndIndex()-aci.getBeginIndex()); + for (char c = aci.first(); c != AttributedCharacterIterator.DONE; c = aci.next()) { + sb.append(c); + } + return sb.toString(); + } + + + protected Point2D paintACI(AttributedCharacterIterator aci, Graphics2D g2d, Point2D loc) { + aci.first(); + + TextNode.Anchor anchor = + (TextNode.Anchor)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE); + + //Adjust position of span + Float xpos = + (Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.X); + Float ypos = + (Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.Y); + Float dxpos = + (Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.DX); + Float dypos = + (Float)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.DY); + if (xpos != null) loc.setLocation(xpos.doubleValue(), loc.getY()); + if (ypos != null) loc.setLocation(loc.getX(), ypos.doubleValue()); + if (dxpos != null) loc.setLocation(loc.getX()+dxpos.doubleValue(), loc.getY()); + if (dypos != null) loc.setLocation(loc.getX(), loc.getY()+dypos.doubleValue()); + + //Set up font + List gvtFonts = + (List)aci.getAttribute(GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES); TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO); - - if (tpi == null) { - return; - } - - Paint forg = tpi.fillPaint; - Paint strokePaint = tpi.strokePaint; - Float size = (Float) aci.getAttribute(TextAttribute.SIZE); + Paint forg = tpi.fillPaint;; + Float size = (Float)aci.getAttribute(TextAttribute.SIZE); if (size == null) { - return; + return loc; } Stroke stroke = tpi.strokeStroke; - /* - Float xpos = (Float) aci.getAttribute( - GVTAttributedCharacterIterator.TextAttribute.X); - Float ypos = (Float) aci.getAttribute( - GVTAttributedCharacterIterator.TextAttribute.Y); - */ - Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE); - Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT); + Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE); + Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT); - boolean useStrokePainter = false; - if (forg instanceof Color) { - Color col = (Color) forg; - if (col.getAlpha() != 255) { - useStrokePainter = true; - } - g2d.setColor(col); + g2d.setColor((Color)forg); } g2d.setPaint(forg); g2d.setStroke(stroke); - if (strokePaint != null) { - // need to draw using AttributedCharacterIterator - useStrokePainter = true; - } - - if (hasUnsupportedAttributes(aci)) { - useStrokePainter = true; - } - - // text contains unsupported information - if (useStrokePainter) { - PROXY_PAINTER.paint(node, g2d); - return; - } - String style = ((posture != null) && (posture.floatValue() > 0.0)) ? "italic" : "normal"; int weight = ((taWeight != null) - && (taWeight.floatValue() > 1.0)) ? Font.BOLD + && (taWeight.floatValue() > 1.0)) ? java.awt.Font.BOLD : Font.NORMAL; Font fontState = null; @@ -170,10 +195,6 @@ Iterator i = gvtFonts.iterator(); while (i.hasNext()) { GVTFontFamily fam = (GVTFontFamily) i.next(); - if (fam instanceof SVGFontFamily) { - PROXY_PAINTER.paint(node, g2d); - return; - } fontFamily = fam.getFamilyName(); if (fi.hasFont(fontFamily, style, weight)) { String fname = fontInfo.fontLookup(fontFamily, style, @@ -216,51 +237,24 @@ g2d.setFont(font); + //Get text and paint + String txt = getText(aci); float advance = getStringWidth(txt, fontState); float tx = 0; if (anchor != null) { switch (anchor.getType()) { - case TextNode.Anchor.ANCHOR_MIDDLE: - tx = -advance / 2; - break; - case TextNode.Anchor.ANCHOR_END: - tx = -advance; + case TextNode.Anchor.ANCHOR_MIDDLE: + tx = -advance / 2; + break; + case TextNode.Anchor.ANCHOR_END: + tx = -advance; } } - g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY())); + g2d.drawString(txt, (float)(loc.getX() + tx), (float)loc.getY()); + loc.setLocation(loc.getX()+(double)advance, loc.getY()); + return loc; } - private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) { - boolean hasunsupported = false; - Object letSpace = aci.getAttribute( - GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING); - if (letSpace != null) { - hasunsupported = true; - } - - Object wordSpace = aci.getAttribute( - GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING); - if (wordSpace != null) { - hasunsupported = true; - } - - AttributedCharacterIterator.Attribute key; - key = GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE; - Object writeMod = aci.getAttribute(key); - if (!GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals( - writeMod)) { - hasunsupported = true; - } - - Object vertOr = aci.getAttribute( - GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION); - if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals( - vertOr)) { - hasunsupported = true; - } - return hasunsupported; - } - private float getStringWidth(String str, Font fontState) { float wordWidth = 0; float whitespaceWidth = fontState.getWidth(fontState.mapChar(' ')); @@ -281,120 +275,61 @@ return wordWidth / 1000f; } - /** - * Get the outline shape of the text characters. - * This uses the StrokingTextPainter to get the outline - * shape since in theory it should be the same. - * - * @param node the text node - * @return the outline shape of the text characters - */ - public Shape getOutline(TextNode node) { - return PROXY_PAINTER.getOutline(node); - } - - /** - * Get the bounds. - * This uses the StrokingTextPainter to get the bounds - * since in theory it should be the same. - * - * @param node the text node - * @return the bounds of the text - */ - public Rectangle2D getBounds2D(TextNode node) { - return PROXY_PAINTER.getBounds2D(node); - } - - /** - * Get the geometry bounds. - * This uses the StrokingTextPainter to get the bounds - * since in theory it should be the same. - * @param node the text node - * @return the bounds of the text - */ - public Rectangle2D getGeometryBounds(TextNode node) { - return PROXY_PAINTER.getGeometryBounds(node); - } - - // Methods that have no purpose for PDF - - /** - * Get the mark. - * This does nothing since the output is pdf and not interactive. - * @param node the text node - * @param pos the position - * @param all select all - * @return null - */ public Mark getMark(TextNode node, int pos, boolean all) { + System.out.println("PDFText getMark"); return null; } - /** - * Select at. - * This does nothing since the output is pdf and not interactive. - * @param x the x position - * @param y the y position - * @param node the text node - * @return null - */ - public Mark selectAt(double x, double y, TextNode node) { + public Mark selectAt(double x, double y, + TextNode node) { + System.out.println("PDFText selectAt"); return null; } - /** - * Select to. - * This does nothing since the output is pdf and not interactive. - * @param x the x position - * @param y the y position - * @param beginMark the start mark - * @return null - */ public Mark selectTo(double x, double y, Mark beginMark) { + System.out.println("PDFText selectTo"); return null; } - /** - * Selec first. - * This does nothing since the output is pdf and not interactive. - * @param node the text node - * @return null - */ + public Mark selectAll(double x, double y, + TextNode node) { + System.out.println("PDFText selectAll"); + return null; + } + public Mark selectFirst(TextNode node) { + System.out.println("PDFText selectFirst"); return null; } - /** - * Select last. - * This does nothing since the output is pdf and not interactive. - * @param node the text node - * @return null - */ public Mark selectLast(TextNode node) { + System.out.println("PDFText selectLast"); return null; } - /** - * Get selected. - * This does nothing since the output is pdf and not interactive. - * @param start the start mark - * @param finish the finish mark - * @return null - */ - public int[] getSelected(Mark start, Mark finish) { + public int[] getSelected(Mark start, + Mark finish) { + System.out.println("PDFText getSelected"); return null; } - /** - * Get the highlighted shape. - * This does nothing since the output is pdf and not interactive. - * @param beginMark the start mark - * @param endMark the end mark - * @return null - */ public Shape getHighlightShape(Mark beginMark, Mark endMark) { + System.out.println("PDFText getHighlightShape"); return null; } + public Rectangle2D getBounds2D(TextNode node) { + return PROXY_PAINTER.getBounds2D(node); + } + + public Rectangle2D getGeometryBounds(TextNode node) { + return PROXY_PAINTER.getGeometryBounds(node); + } + + public Shape getOutline(TextNode node) { + return PROXY_PAINTER.getOutline(node); + } + + }
