jeremias 2003/03/11 00:42:24 Modified: src/org/apache/fop/render/ps PSXMLHandler.java PSRenderer.java PSProcSets.java PSGraphics2D.java Added: src/org/apache/fop/render/ps PSTextPainter.java Log: Port of the PDF TextPainter to PostScript. Support for SEG_QUADTO (curves). Some support for viewport traits (background and borders). Submitted by: Zhong Yi <[EMAIL PROTECTED]> Revision Changes Path 1.4 +16 -11 xml-fop/src/org/apache/fop/render/ps/PSXMLHandler.java Index: PSXMLHandler.java =================================================================== RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSXMLHandler.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- PSXMLHandler.java 7 Mar 2003 09:46:30 -0000 1.3 +++ PSXMLHandler.java 11 Mar 2003 08:42:24 -0000 1.4 @@ -50,24 +50,27 @@ */ package org.apache.fop.render.ps; -import org.apache.fop.render.XMLHandler; -import org.apache.fop.render.RendererContext; -import org.apache.fop.svg.SVGUserAgent; -import org.apache.fop.layout.FontInfo; +// Java +import java.awt.geom.AffineTransform; +import java.io.IOException; +// DOM import org.w3c.dom.Document; +import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.svg.SVGSVGElement; +// Batik import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.ViewBox; - import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.gvt.TextPainter; -import org.w3c.dom.svg.SVGDocument; -import org.w3c.dom.svg.SVGSVGElement; - -import java.awt.geom.AffineTransform; -import java.io.IOException; +// FOP +import org.apache.fop.render.XMLHandler; +import org.apache.fop.render.RendererContext; +import org.apache.fop.svg.SVGUserAgent; +import org.apache.fop.layout.FontInfo; /** * PostScript XML handler. @@ -300,7 +303,9 @@ transform.translate(xOffset / 1000f, yOffset / 1000f); //aBridge.setCurrentTransform(transform); //ctx.putBridge(aBridge); - + + TextPainter textPainter = new PSTextPainter(psInfo.getFontInfo()); + ctx.setTextPainter(textPainter); GraphicsNode root; try { root = builder.build(ctx, doc); 1.31 +197 -5 xml-fop/src/org/apache/fop/render/ps/PSRenderer.java Index: PSRenderer.java =================================================================== RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSRenderer.java,v retrieving revision 1.30 retrieving revision 1.31 diff -u -r1.30 -r1.31 --- PSRenderer.java 5 Mar 2003 20:38:26 -0000 1.30 +++ PSRenderer.java 11 Mar 2003 08:42:24 -0000 1.31 @@ -59,6 +59,9 @@ import java.util.Map; // FOP +import org.apache.fop.fo.properties.BackgroundRepeat; +import org.apache.fop.area.Area; +import org.apache.fop.area.RegionViewport; import org.apache.fop.apps.FOPException; import org.apache.fop.area.Block; import org.apache.fop.area.BlockViewport; @@ -73,9 +76,12 @@ import org.apache.fop.layout.FontInfo; import org.apache.fop.render.AbstractRenderer; import org.apache.fop.render.RendererContext; -import org.w3c.dom.Document; +import org.apache.fop.image.FopImage; +import org.apache.fop.image.ImageFactory; +import org.apache.fop.traits.BorderProps; +import org.w3c.dom.Document; /** * Renderer that renders to PostScript. * <br> @@ -416,14 +422,15 @@ {page.getPageNumber(), new Integer(this.currentPageNumber)}); final Integer zero = new Integer(0); - final Long pagewidth = new Long(Math.round(page.getViewArea().getWidth() / 1000f)); - final Long pageheight = new Long(Math.round(page.getViewArea().getHeight() / 1000f)); + final Long pagewidth = new Long(Math.round(page.getViewArea().getWidth())); + final Long pageheight = new Long(Math.round(page.getViewArea().getHeight())); gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] {zero, zero, pagewidth, pageheight}); gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP); gen.writeln("FOPFonts begin"); - concatMatrix(1, 0, 0, -1, 0, pageheight.doubleValue()); gen.writeln("0.001 0.001 scale"); + concatMatrix(1, 0, 0, -1, 0, pageheight.doubleValue()); + gen.writeDSCComment(DSCConstants.END_PAGE_SETUP); //Process page @@ -629,7 +636,7 @@ saveGraphicsState(); // multiply with current CTM - //currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n"); + //writeln(CTMHelper.toPDFString(ctm) + " cm\n"); final double matrix[] = ctm.toArray(); concatMatrix(matrix); @@ -646,7 +653,190 @@ //currentState.pop(); } + /** + * Handle the viewport traits. + * This is used to draw the traits for a viewport. + * + * @param region the viewport region to handle + */ + protected void handleViewportTraits(RegionViewport region) { + currentFontName = ""; + float startx = 0; + float starty = 0; + Rectangle2D viewArea = region.getViewArea(); + float width = (float)(viewArea.getWidth()); + float height = (float)(viewArea.getHeight()); + /* + Trait.Background back; + back = (Trait.Background)region.getTrait(Trait.BACKGROUND); + */ + drawBackAndBorders(region, startx, starty, width, height); + } + + /** + * Handle block traits. + * The block could be any sort of block with any positioning + * so this should render the traits such as border and background + * in its position. + * + * @param block the block to render the traits + */ + protected void handleBlockTraits(Block block) { + float startx = currentIPPosition; + float starty = currentBPPosition; + drawBackAndBorders(block, startx, starty, + block.getWidth(), block.getHeight()); + } + + /** + * Draw the background and borders. + * This draws the background and border traits for an area given + * the position. + * + * @param block the area to get the traits from + * @param startx the start x position + * @param starty the start y position + * @param width the width of the area + * @param height the height of the area + */ + protected void drawBackAndBorders(Area block, + float startx, float starty, + float width, float height) { + // draw background then border + + boolean started = false; + Trait.Background back; + back = (Trait.Background)block.getTrait(Trait.BACKGROUND); + if (back != null) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + + if (back.getColor() != null) { + updateColor(back.getColor(), true, null); + writeln(startx + " " + starty + " " + + width + " " + height + " rectfill"); + } + if (back.getURL() != null) { + ImageFactory fact = ImageFactory.getInstance(); + FopImage fopimage = fact.getImage(back.getURL(), userAgent); + if (fopimage != null && fopimage.load(FopImage.DIMENSIONS, userAgent)) { + if (back.getRepeat() == BackgroundRepeat.REPEAT) { + // create a pattern for the image + } else { + // place once + Rectangle2D pos; + pos = new Rectangle2D.Float((startx + back.getHoriz()) * 1000, + (starty + back.getVertical()) * 1000, + fopimage.getWidth() * 1000, + fopimage.getHeight() * 1000); + // putImage(back.url, pos); + } + } + } + } + + BorderProps bps = (BorderProps)block.getTrait(Trait.BORDER_BEFORE); + if (bps != null) { + float endx = startx + width; + + if (!started) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + + drawLine(startx, starty + bwidth / 2, endx, starty + bwidth / 2); + } + bps = (BorderProps)block.getTrait(Trait.BORDER_START); + if (bps != null) { + float endy = starty + height; + + if (!started) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + + drawLine(startx + bwidth / 2, starty, startx + bwidth / 2, endy); + } + bps = (BorderProps)block.getTrait(Trait.BORDER_AFTER); + if (bps != null) { + float sy = starty + height; + float endx = startx + width; + + if (!started) { + started = true; +// closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + + drawLine(startx, sy - bwidth / 2, endx, sy - bwidth / 2); + } + bps = (BorderProps)block.getTrait(Trait.BORDER_END); + if (bps != null) { + float sx = startx + width; + float endy = starty + height; + + if (!started) { + started = true; + // closeText(); + endTextObject(); + //saveGraphicsState(); + } + + float bwidth = bps.width ; + updateColor(bps.color, false, null); + writeln(bwidth + " setlinewidth"); + drawLine(sx - bwidth / 2, starty, sx - bwidth / 2, endy); + } + if (started) { + //restoreGraphicsState(); + beginTextObject(); + // font last set out of scope in text section + currentFontName = ""; + } + } + + /** + * Draw a line. + * + * @param startx the start x position + * @param starty the start y position + * @param endx the x end position + * @param endy the y end position + */ + private void drawLine(float startx, float starty, float endx, float endy) { + writeln(startx + " " + starty + " M "); + writeln(endx + " " + endy + " lineto"); + } + private void updateColor(ColorType col, boolean fill, StringBuffer pdf) { + writeln(gen.formatDouble(col.getRed()) + " " + + gen.formatDouble(col.getGreen()) + " " + + gen.formatDouble(col.getBlue()) + " setrgbcolor"); + } + + private void updateFont(String name, int size, StringBuffer pdf) { + + } + /** * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) */ @@ -677,6 +867,8 @@ new Integer(currentBlockIPPosition + (int) pos.getX())); context.setProperty(PSXMLHandler.PS_YPOS, new Integer(currentBPPosition + (int) pos.getY())); + //context.setProperty("strokeSVGText", options.get("strokeSVGText")); + /* context.setProperty(PDFXMLHandler.PDF_DOCUMENT, pdfDoc); context.setProperty(PDFXMLHandler.OUTPUT_STREAM, ostream); 1.3 +14 -1 xml-fop/src/org/apache/fop/render/ps/PSProcSets.java Index: PSProcSets.java =================================================================== RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSProcSets.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- PSProcSets.java 7 Mar 2003 09:46:30 -0000 1.2 +++ PSProcSets.java 11 Mar 2003 08:42:24 -0000 1.3 @@ -141,7 +141,20 @@ gen.writeln(" Tt setlinewidth stroke"); gen.writeln(" grestore"); gen.writeln("} bd"); - + + gen.writeln("/QUADTO {"); + gen.writeln("/Y22 exch store"); + gen.writeln("/X22 exch store"); + gen.writeln("/Y21 exch store"); + gen.writeln("/X21 exch store"); + gen.writeln("currentpoint"); + gen.writeln("/Y21 load 2 mul add 3 div exch"); + gen.writeln("/X21 load 2 mul add 3 div exch"); + gen.writeln("/X21 load 2 mul /X22 load add 3 div"); + gen.writeln("/Y21 load 2 mul /Y22 load add 3 div"); + gen.writeln("/X22 load /Y22 load curveto"); + gen.writeln("} bd"); + gen.writeln("%%EndResource"); } 1.11 +96 -42 xml-fop/src/org/apache/fop/render/ps/PSGraphics2D.java Index: PSGraphics2D.java =================================================================== RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSGraphics2D.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- PSGraphics2D.java 7 Mar 2003 09:46:30 -0000 1.10 +++ PSGraphics2D.java 11 Mar 2003 08:42:24 -0000 1.11 @@ -114,7 +114,10 @@ /** Currently valid FontState */ protected FontState fontState; - + + /** Overriding FontState */ + protected FontState overrideFontState = null; + /** * the current (internal) font name */ @@ -501,8 +504,9 @@ Shape imclip = getClip(); writeClip(imclip); Color c = getColor(); - gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue() - + " setrgbcolor"); + gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " " + + gen.formatDouble(c.getGreen() / 255.0) + " " + + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor"); applyPaint(getPaint(), false); applyStroke(getStroke()); @@ -533,10 +537,10 @@ + " M"); break; case PathIterator.SEG_QUADTO: - // psRenderer.write((1000 * PDFNumber.doubleOut(vals[0])) + - // " " + (1000 * PDFNumber.doubleOut(vals[1])) + " " + - // (1000 * PDFNumber.doubleOut(vals[2])) + " " + - // (1000 * PDFNumber.doubleOut(vals[3])) + " y\n"); + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " QUADTO "); break; case PathIterator.SEG_CLOSE: gen.writeln("closepath"); @@ -585,10 +589,10 @@ + " M"); break; case PathIterator.SEG_QUADTO: - // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) + - // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " + - // 1000 * PDFNumber.doubleOut(vals[2]) + " " + - // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n"); + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " QUADTO "); break; case PathIterator.SEG_CLOSE: gen.writeln("closepath"); @@ -803,32 +807,73 @@ * @see #setClip */ public void drawString(String s, float x, float y) { - try { - System.out.println("drawString(String)"); - gen.writeln("BT"); - Shape imclip = getClip(); - writeClip(imclip); - Color c = getColor(); - gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue() - + " setrgbcolor"); - - AffineTransform trans = getTransform(); - trans.translate(x, y); - double[] vals = new double[6]; - trans.getMatrix(vals); - - gen.writeln(gen.formatDouble(vals[0]) + " " - + gen.formatDouble(vals[1]) + " " - + gen.formatDouble(vals[2]) + " " - + gen.formatDouble(vals[3]) + " " - + gen.formatDouble(vals[4]) + " " - + gen.formatDouble(vals[5]) + " " - + gen.formatDouble(vals[6]) + " Tm [" + s + "]"); - - gen.writeln("ET"); - } catch (IOException ioe) { - handleIOException(ioe); + try { + if (overrideFontState == null) { + Font gFont = getFont(); + String n = gFont.getFamily(); + if (n.equals("sanserif")) { + n = "sans-serif"; + } + int siz = gFont.getSize(); + String style = gFont.isItalic() ? "italic" : "normal"; + String weight = gFont.isBold() ? "bold" : "normal"; + + //try { + //fontState = new FontState(n, fontState.getFontMetrics(),siz); + //} catch (org.apache.fop.apps.FOPException fope) { + //fope.printStackTrace(); + //} + } else { + fontState = overrideFontState; + overrideFontState = null; } + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + gen.writeln(c.getRed() / 255.0 + " " + + c.getGreen() / 255.0 + " " + + c.getBlue() / 255.0 + " setrgbcolor"); + + AffineTransform trans = getTransform(); + trans.translate(x, y); + double[] vals = new double[6]; + trans.getMatrix(vals); + gen.writeln(gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + " moveto "); + //String fontWeight = fontState.getFontWeight(); + StringBuffer sb = new StringBuffer(); + + int l = s.length(); + + if ((currentFontName != fontState.getFontName()) + || (currentFontSize != fontState.getFontSize())) { + gen.writeln(fontState.getFontName() + " " + fontState.getFontSize() + " F"); + currentFontName = fontState.getFontName(); + currentFontSize = fontState.getFontSize(); + } + for (int i = 0; i < l; i++) { + char ch = s.charAt(i); + char mch = fontState.mapChar(ch); + if (mch > 127) { + sb = sb.append("\\" + Integer.toOctalString(mch)); + } else { + String escape = "\\()[]{}"; + if (escape.indexOf(mch) >= 0) { + sb.append("\\"); + } + sb = sb.append(mch); + } + } + + String psString = null; + psString = " (" + sb.toString() + ") " + " t "; + + gen.writeln(" 1.0 -1.0 scale"); + gen.writeln(psString); + gen.writeln(" 1.0 -1.0 scale"); + } catch (IOException ioe) { + handleIOException(ioe); + } } /** @@ -917,8 +962,9 @@ Shape imclip = getClip(); writeClip(imclip); Color c = getColor(); - gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue() - + " setrgbcolor"); + gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " " + + gen.formatDouble(c.getGreen() / 255.0) + " " + + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor"); applyPaint(getPaint(), true); @@ -948,10 +994,10 @@ + " M"); break; case PathIterator.SEG_QUADTO: - // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) + - // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " + - // 1000 * PDFNumber.doubleOut(vals[2]) + " " + - // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n"); + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " QUADTO "); break; case PathIterator.SEG_CLOSE: gen.writeln("closepath"); @@ -1021,6 +1067,14 @@ fmg = bi.createGraphics(); } + /** + * Sets the overrideing font state. + * @param infont FontState to set + */ + public void setOverrideFontState(FontState infont) { + overrideFontState = infont; + } + /** * Gets the font metrics for the specified font. * @return the font metrics for the specified font. 1.1 xml-fop/src/org/apache/fop/render/ps/PSTextPainter.java Index: PSTextPainter.java =================================================================== /* * $Id$ * ============================================================================ * The Apache Software License, Version 1.1 * ============================================================================ * * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: "This product includes software * developed by the Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * * 4. The names "FOP" and "Apache Software Foundation" must not be used to * endorse or promote products derived from this software without prior * written permission. For written permission, please contact * [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", nor may * "Apache" appear in their name, without prior written permission of the * Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ============================================================================ * * This software consists of voluntary contributions made by many individuals * on behalf of the Apache Software Foundation and was originally created by * James Tauber <[EMAIL PROTECTED]>. For more information on the Apache * Software Foundation, please see <http://www.apache.org/>. */ package org.apache.fop.render.ps; import java.awt.Graphics2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.Font; import java.text.AttributedCharacterIterator; import java.awt.font.TextAttribute; import java.awt.Shape; import java.awt.Paint; import java.awt.Stroke; import java.awt.Color; import java.util.List; import java.util.Iterator; import org.apache.batik.gvt.text.Mark; import org.apache.batik.gvt.TextPainter; import org.apache.batik.gvt.TextNode; import org.apache.batik.gvt.text.GVTAttributedCharacterIterator; import org.apache.batik.gvt.font.GVTFontFamily; import org.apache.batik.bridge.SVGFontFamily; import org.apache.batik.gvt.renderer.StrokingTextPainter; import org.apache.fop.fonts.FontMetrics; import org.apache.fop.layout.FontState; import org.apache.fop.layout.FontInfo; /** * Renders the attributed character iterator of a <tt>TextNode</tt>. * This class draws the text directly into the PSGraphics2D so that * the text is not drawn using shapes which makes the PS files larger. * If the text is simple enough to draw then it sets the font and calls * drawString. If the text is complex or the cannot be translated * into a simple drawString the StrokingTextPainter is used instead. * * @todo handle underline, overline and strikethrough * @todo use drawString(AttributedCharacterIterator iterator...) for some * * @author <a href="mailto:[EMAIL PROTECTED]">Keiron Liddle</a> * @version $Id: PSTextPainter.java,v 1.15 2003/01/08 14:03:55 jeremias Exp $ */ public class PSTextPainter implements TextPainter { private FontInfo fontInfo; /** * Use the stroking text painter to get the bounds and shape. * Also used as a fallback to draw the string with strokes. */ protected static final TextPainter PROXY_PAINTER = StrokingTextPainter.getInstance(); /** * Create a new PS text painter with the given font information. * @param fi the fint info */ public PSTextPainter(FontInfo fi) { fontInfo = fi; } /** * Paints the specified attributed character iterator using the * specified Graphics2D and context and font context. * @param node the TextNode to paint * @param g2d the Graphics2D to use */ public void paint(TextNode node, Graphics2D g2d) { // System.out.println("PSText paint"); String txt = node.getText(); Point2D loc = node.getLocation(); AttributedCharacterIterator aci = node.getAttributedCharacterIterator(); // reset position to start of char iterator if (aci.getBeginIndex() == aci.getEndIndex()) { return; } char ch = aci.first(); if (ch == AttributedCharacterIterator.DONE) { return; } TextNode.Anchor anchor; anchor = (TextNode.Anchor) aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE); List gvtFonts; gvtFonts = (List) aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES); Paint forg = (Paint) aci.getAttribute(TextAttribute.FOREGROUND); Paint strokePaint; strokePaint = (Paint) aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.STROKE_PAINT); Float size = (Float) aci.getAttribute(TextAttribute.SIZE); if (size == null) { return; } Stroke stroke = (Stroke) aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.STROKE); /* 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); boolean useStrokePainter = false; if (forg instanceof Color) { Color col = (Color) forg; if (col.getAlpha() != 255) { useStrokePainter = true; } g2d.setColor(col); } 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)) ? FontInfo.BOLD : FontInfo.NORMAL; FontState fontState = null; FontInfo fi = fontInfo; boolean found = false; String fontFamily = null; if (gvtFonts != null) { 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, weight); FontMetrics metrics = fontInfo.getMetricsFor(fname); int fsize = (int)(size.floatValue() * 1000); fontState = new FontState(fname, metrics, fsize); found = true; break; } } } if (!found) { String fname = fontInfo.fontLookup("any", style, FontInfo.NORMAL); FontMetrics metrics = fontInfo.getMetricsFor(fname); int fsize = (int)(size.floatValue() * 1000); fontState = new FontState(fname, metrics, fsize); } else { if (g2d instanceof PSGraphics2D) { ((PSGraphics2D) g2d).setOverrideFontState(fontState); } } int fStyle = Font.PLAIN; if (weight == FontInfo.BOLD) { if (style.equals("italic")) { fStyle = Font.BOLD | Font.ITALIC; } else { fStyle = Font.BOLD; } } else { if (style.equals("italic")) { fStyle = Font.ITALIC; } else { fStyle = Font.PLAIN; } } Font font = new Font(fontFamily, fStyle, (int)(fontState.getFontSize() / 1000)); g2d.setFont(font); 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; } } g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY())); } 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, FontState fontState) { float wordWidth = 0; float whitespaceWidth = fontState.getWidth(fontState.mapChar(' ')); for (int i = 0; i < str.length(); i++) { float charWidth; char c = str.charAt(i); if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) { charWidth = fontState.getWidth(fontState.mapChar(c)); if (charWidth <= 0) { charWidth = whitespaceWidth; } } else { charWidth = whitespaceWidth; } wordWidth += charWidth; } 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 PS /** * 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("PSText 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) { System.out.println("PSText 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("PSText 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 selectFirst(TextNode node) { System.out.println("PSText 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("PSText 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) { System.out.println("PSText 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("PSText getHighlightShape"); return null; } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]