keiron 01/06/22 07:16:48 Modified: src/org/apache/fop/render/ps PSRenderer.java Added: src/org/apache/fop/render/ps PSGraphics2D.java Log: added support for rendering SVG graphics to ps not fully functional Revision Changes Path 1.2 +210 -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.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- PSRenderer.java 2001/06/22 09:08:50 1.1 +++ PSRenderer.java 2001/06/22 14:16:46 1.2 @@ -1,4 +1,4 @@ -/* $Id: PSRenderer.java,v 1.1 2001/06/22 09:08:50 keiron Exp $ +/* $Id: PSRenderer.java,v 1.2 2001/06/22 14:16:46 keiron Exp $ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources. @@ -18,14 +18,36 @@ import org.apache.fop.datatypes.*; import org.apache.fop.fo.properties.*; import org.apache.fop.render.pdf.Font; +import org.apache.fop.image.*; +import org.apache.batik.bridge.*; +import org.apache.batik.swing.svg.*; +import org.apache.batik.swing.gvt.*; +import org.apache.batik.gvt.*; +import org.apache.batik.gvt.renderer.*; +import org.apache.batik.gvt.filter.*; +import org.apache.batik.gvt.event.*; + // SVG import org.w3c.dom.svg.SVGSVGElement; import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.*; +import org.w3c.dom.svg.*; // Java import java.io.*; import java.util.*; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.Vector; +import java.util.Hashtable; +import java.awt.geom.AffineTransform; +import java.awt.geom.Dimension2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.font.FontRenderContext; +import java.awt.Dimension; /** * Renderer that renders to PostScript. @@ -401,17 +423,94 @@ public void renderSVGArea(SVGArea area) { int x = this.currentXPosition; int y = this.currentYPosition; - SVGSVGElement svg = - ((SVGDocument) area.getSVGDocument()).getRootElement(); + Document doc = area.getSVGDocument(); + SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); int w = (int)(svg.getWidth().getBaseVal().getValue() * 1000); int h = (int)(svg.getHeight().getBaseVal().getValue() * 1000); + float sx = 1, sy = -1; + int xOffset = x, yOffset = y; + /* + * Clip to the svg area. + * Note: To have the svg overlay (under) a text area then use + * an fo:block-container + */ comment("% --- SVG Area"); - /**@todo Implement SVG */ + write("gsave"); + if (w != 0 && h != 0) { +/* write("newpath"); + write(x / 1000f + " " + y / 1000f + " M"); + write((x + w) / 1000f + " " + y / 1000f + " rlineto"); + write((x + w) / 1000f + " " + (y - h) / 1000f + + " rlineto"); + write(x / 1000f + " " + (y - h) / 1000f + " rlineto"); + write("closepath"); + write("clippath"); +*/ } + // transform so that the coordinates (0,0) is from the top left + // and positive is down and to the right. (0,0) is where the + // viewBox puts it. + write(xOffset + + " " + yOffset + " translate"); + write(sx + " " + sy + " " + " scale"); + + + UserAgent userAgent = new MUserAgent(new AffineTransform()); + + GVTBuilder builder = new GVTBuilder(); + GraphicsNodeRenderContext rc = getRenderContext(); + BridgeContext ctx = new BridgeContext(userAgent, rc); + GraphicsNode root; + PSGraphics2D graphics = + new PSGraphics2D(false, area.getFontState(), this, + currentFontName, currentFontSize, currentXPosition, + currentYPosition); + graphics.setGraphicContext( + new org.apache.batik.ext.awt.g2d.GraphicContext()); + graphics.setRenderingHints(rc.getRenderingHints()); + try { + root = builder.build(ctx, doc); + root.paint(graphics, rc); + } catch (Exception e) { + MessageHandler.errorln("Error: svg graphic could not be rendered: " + e.getMessage()); + //e.printStackTrace(); + } + + write("grestore"); + comment("% --- SVG Area end"); movetoCurrPosition(); } + public GraphicsNodeRenderContext getRenderContext() { + GraphicsNodeRenderContext nodeRenderContext = null; + if (nodeRenderContext == null) { + RenderingHints hints = new RenderingHints(null); + hints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + hints.put(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + + FontRenderContext fontRenderContext = + new FontRenderContext(new AffineTransform(), true, + true); + + TextPainter textPainter = new StrokingTextPainter(); + //TextPainter textPainter = new PDFTextPainter(); + + GraphicsNodeRableFactory gnrFactory = + new ConcreteGraphicsNodeRableFactory(); + + nodeRenderContext = new GraphicsNodeRenderContext( + new AffineTransform(), null, hints, + fontRenderContext, textPainter, gnrFactory); + nodeRenderContext.setTextPainter(textPainter); + } + + return nodeRenderContext; + } + public void renderBitmap(FopImage img, int x, int y, int w, int h) { try { boolean iscolor = img.getColorSpace().getColorSpace() != @@ -502,7 +601,10 @@ //if (imagecount!=4) return; comment("% --- ImageArea"); - renderBitmap(area.getImage(), x, y, w, h); + if(area.getImage() instanceof SVGImage) { + } else { + renderBitmap(area.getImage(), x, y, w, h); + } comment("% --- ImageArea end"); } @@ -853,4 +955,107 @@ } } + protected class MUserAgent implements UserAgent { + AffineTransform currentTransform = null; + /** + * Creates a new SVGUserAgent. + */ + protected MUserAgent(AffineTransform at) { + currentTransform = at; + } + + /** + * Displays an error message. + */ + public void displayError(String message) { + System.err.println(message); + } + + /** + * Displays an error resulting from the specified Exception. + */ + public void displayError(Exception ex) { + ex.printStackTrace(System.err); + } + + /** + * Displays a message in the User Agent interface. + * The given message is typically displayed in a status bar. + */ + public void displayMessage(String message) { + System.out.println(message); + } + + /** + * Returns a customized the pixel to mm factor. + */ + public float getPixelToMM() { + return 0.264583333333333333333f; // 72 dpi + } + + /** + * Returns the language settings. + */ + public String getLanguages() { + return "en";//userLanguages; + } + + /** + * Returns the user stylesheet uri. + * @return null if no user style sheet was specified. + */ + public String getUserStyleSheetURI() { + return null;//userStyleSheetURI; + } + + /** + * Returns the class name of the XML parser. + */ + public String getXMLParserClassName() { + String parserClassName = System.getProperty("org.xml.sax.parser"); + if (parserClassName == null) { + parserClassName = "org.apache.xerces.parsers.SAXParser"; + } + return parserClassName;//application.getXMLParserClassName(); + } + + /** + * Opens a link in a new component. + * @param doc The current document. + * @param uri The document URI. + */ + public void openLink(SVGAElement elt) { + //application.openLink(uri); + } + + public Point getClientAreaLocationOnScreen() { + return new Point(0, 0); + } + + public void setSVGCursor(java.awt.Cursor cursor) { + } + + public AffineTransform getTransform() { + return currentTransform; + } + + public Dimension2D getViewportSize() { + return new Dimension(100, 100); + } + + public EventDispatcher getEventDispatcher() { + return null; + } + + public boolean supportExtension(String str) { + return false; + } + + public boolean hasFeature(String str) { + return false; + } + + public void registerExtension(BridgeExtension be) { + } + } } 1.1 xml-fop/src/org/apache/fop/render/ps/PSGraphics2D.java Index: PSGraphics2D.java =================================================================== /* $Id: PSGraphics2D.java,v 1.1 2001/06/22 14:16:45 keiron Exp $ * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. * For details on use and redistribution please refer to the * LICENSE file included with these sources." */ package org.apache.fop.render.ps; import org.apache.fop.pdf.*; import org.apache.fop.layout.*; import org.apache.fop.fonts.*; import org.apache.fop.render.pdf.*; import org.apache.fop.image.*; import org.apache.fop.datatypes.ColorSpace; import org.apache.batik.ext.awt.g2d.*; import java.text.AttributedCharacterIterator; import java.text.CharacterIterator; import java.awt.*; import java.awt.Font; import java.awt.Image; import java.awt.image.*; import java.awt.font.*; import java.awt.geom.*; import java.awt.image.renderable.*; import java.io.*; import java.util.Map; import java.util.Vector; /** * This concrete implementation of <tt>AbstractGraphics2D</tt> is a * simple help to programmers to get started with their own * implementation of <tt>Graphics2D</tt>. * <tt>DefaultGraphics2D</tt> implements all the abstract methods * is <tt>AbstractGraphics2D</tt> and makes it easy to start * implementing a <tt>Graphic2D</tt> piece-meal. * * @author <a href="mailto:[EMAIL PROTECTED]">Keiron Liddle</a> * @version $Id: PSGraphics2D.java,v 1.1 2001/06/22 14:16:45 keiron Exp $ * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D */ public class PSGraphics2D extends AbstractGraphics2D { boolean standalone = false; /** the PDF Document being created */ protected PSRenderer psRenderer; protected FontState fontState; /** the current (internal) font name */ protected String currentFontName; /** the current font size in millipoints */ protected int currentFontSize; /** the current vertical position in millipoints from bottom */ protected int currentYPosition = 0; /** the current horizontal position in millipoints from left */ protected int currentXPosition = 0; /** the current colour for use in svg */ PDFColor currentColour = new PDFColor(0, 0, 0); FontInfo fontInfo; /** * Create a new PDFGraphics2D with the given pdf document info. * This is used to create a Graphics object for use inside an already * existing document. */ public PSGraphics2D(boolean textAsShapes, FontState fs, PSRenderer ren, String font, int size, int xpos, int ypos) { super(textAsShapes); psRenderer = ren; currentFontName = font; currentFontSize = size; currentYPosition = ypos; currentXPosition = xpos; fontState = fs; } public PSGraphics2D(boolean textAsShapes) { super(textAsShapes); } public void setGraphicContext(GraphicContext c) { gc = c; } /** * This constructor supports the create method */ public PSGraphics2D(PSGraphics2D g) { super(g); } /** * Creates a new <code>Graphics</code> object that is * a copy of this <code>Graphics</code> object. * @return a new graphics context that is a copy of * this graphics context. */ public Graphics create() { return new PSGraphics2D(this); } /** * Draws as much of the specified image as is currently available. * The image is drawn with its top-left corner at * (<i>x</i>, <i>y</i>) in this graphics context's coordinate * space. Transparent pixels in the image do not affect whatever * pixels are already there. * <p> * This method returns immediately in all cases, even if the * complete image has not yet been loaded, and it has not been dithered * and converted for the current output device. * <p> * If the image has not yet been completely loaded, then * <code>drawImage</code> returns <code>false</code>. As more of * the image becomes available, the process that draws the image notifies * the specified image observer. * @param img the specified image to be drawn. * @param x the <i>x</i> coordinate. * @param y the <i>y</i> coordinate. * @param observer object to be notified as more of * the image is converted. * @see java.awt.Image * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ public boolean drawImage(Image img, int x, int y, ImageObserver observer) { //System.err.println("drawImage:x, y"); final int width = img.getWidth(observer); final int height = img.getHeight(observer); if (width == -1 || height == -1) { return false; } Dimension size = new Dimension(width, height); BufferedImage buf = buildBufferedImage(size); java.awt.Graphics2D g = buf.createGraphics(); g.setComposite(AlphaComposite.SrcOver); g.setBackground(new Color(1, 1, 1, 0)); g.setPaint(new Color(1, 1, 1, 0)); g.fillRect(0, 0, width, height); g.clip(new Rectangle(0, 0, buf.getWidth(), buf.getHeight())); if (!g.drawImage(img, 0, 0, observer)) { return false; } g.dispose(); final byte[] result = new byte[buf.getWidth() * buf.getHeight() * 3]; final byte[] mask = new byte[buf.getWidth() * buf.getHeight()]; Raster raster = buf.getData(); DataBuffer bd = raster.getDataBuffer(); int count = 0; int maskpos = 0; switch (bd.getDataType()) { case DataBuffer.TYPE_INT: int[][] idata = ((DataBufferInt) bd).getBankData(); for (int i = 0; i < idata.length; i++) { for (int j = 0; j < idata[i].length; j++) { //mask[maskpos++] = (byte)((idata[i][j] >> 24) & 0xFF); if(((idata[i][j] >> 24) & 0xFF) != 255) { result[count++] = (byte)0xFF; result[count++] = (byte)0xFF; result[count++] = (byte)0xFF; } else { result[count++] = (byte)((idata[i][j] >> 16) & 0xFF); result[count++] = (byte)((idata[i][j] >> 8) & 0xFF); result[count++] = (byte)((idata[i][j]) & 0xFF); } } } break; default: // error break; } try { FopImage fopimg = new TempImage(width, height, result, mask); AffineTransform at = getTransform(); double[] matrix = new double[6]; at.getMatrix(matrix); psRenderer.write("gsave"); Shape imclip = getClip(); writeClip(imclip); //psRenderer.write("" + matrix[0] + " " + matrix[1] + // " " + matrix[2] + " " + matrix[3] + " " + // matrix[4] + " " + matrix[5] + " cm\n"); psRenderer.renderBitmap(fopimg, x, y, width, height); psRenderer.write("grestore"); } catch (Exception e) { e.printStackTrace(); } return true; } public BufferedImage buildBufferedImage(Dimension size) { return new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB); } class TempImage implements FopImage { int m_height; int m_width; int m_bitsPerPixel; ColorSpace m_colorSpace; int m_bitmapSiye; byte[] m_bitmaps; byte[] m_mask; PDFColor transparent = new PDFColor(255, 255, 255); TempImage(int width, int height, byte[] result, byte[] mask) throws FopImageException { this.m_height = height; this.m_width = width; this.m_bitsPerPixel = 8; this.m_colorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); //this.m_isTransparent = false; //this.m_bitmapsSize = this.m_width * this.m_height * 3; this.m_bitmaps = result; this.m_mask = mask; } public String getURL() { return "" + m_bitmaps; } // image size public int getWidth() throws FopImageException { return m_width; } public int getHeight() throws FopImageException { return m_height; } // DeviceGray, DeviceRGB, or DeviceCMYK public ColorSpace getColorSpace() throws FopImageException { return m_colorSpace; } // bits per pixel public int getBitsPerPixel() throws FopImageException { return m_bitsPerPixel; } // For transparent images public boolean isTransparent() throws FopImageException { return transparent != null; } public PDFColor getTransparentColor() throws FopImageException { return transparent; } public byte[] getMask() throws FopImageException { return m_mask; } // get the image bytes, and bytes properties // get uncompressed image bytes public byte[] getBitmaps() throws FopImageException { return m_bitmaps; } // width * (bitsPerPixel / 8) * height, no ? public int getBitmapsSize() throws FopImageException { return m_width * m_height * 3; } // get compressed image bytes // I don't know if we really need it, nor if it // should be changed... public byte[] getRessourceBytes() throws FopImageException { return null; } public int getRessourceBytesSize() throws FopImageException { return 0; } // return null if no corresponding PDFFilter public PDFFilter getPDFFilter() throws FopImageException { return null; } // release memory public void close() {} } /** * Draws as much of the specified image as has already been scaled * to fit inside the specified rectangle. * <p> * The image is drawn inside the specified rectangle of this * graphics context's coordinate space, and is scaled if * necessary. Transparent pixels do not affect whatever pixels * are already there. * <p> * This method returns immediately in all cases, even if the * entire image has not yet been scaled, dithered, and converted * for the current output device. * If the current output representation is not yet complete, then * <code>drawImage</code> returns <code>false</code>. As more of * the image becomes available, the process that draws the image notifies * the image observer by calling its <code>imageUpdate</code> method. * <p> * A scaled version of an image will not necessarily be * available immediately just because an unscaled version of the * image has been constructed for this output device. Each size of * the image may be cached separately and generated from the original * data in a separate image production sequence. * @param img the specified image to be drawn. * @param x the <i>x</i> coordinate. * @param y the <i>y</i> coordinate. * @param width the width of the rectangle. * @param height the height of the rectangle. * @param observer object to be notified as more of * the image is converted. * @see java.awt.Image * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { System.out.println("drawImage"); return true; } /** * Disposes of this graphics context and releases * any system resources that it is using. * A <code>Graphics</code> object cannot be used after * <code>dispose</code>has been called. * <p> * When a Java program runs, a large number of <code>Graphics</code> * objects can be created within a short time frame. * Although the finalization process of the garbage collector * also disposes of the same system resources, it is preferable * to manually free the associated resources by calling this * method rather than to rely on a finalization process which * may not run to completion for a long period of time. * <p> * Graphics objects which are provided as arguments to the * <code>paint</code> and <code>update</code> methods * of components are automatically released by the system when * those methods return. For efficiency, programmers should * call <code>dispose</code> when finished using * a <code>Graphics</code> object only if it was created * directly from a component or another <code>Graphics</code> object. * @see java.awt.Graphics#finalize * @see java.awt.Component#paint * @see java.awt.Component#update * @see java.awt.Component#getGraphics * @see java.awt.Graphics#create */ public void dispose() { //System.out.println("dispose"); psRenderer = null; fontState = null; currentFontName = null; currentColour = null; fontInfo = null; } /** * Strokes the outline of a <code>Shape</code> using the settings of the * current <code>Graphics2D</code> context. The rendering attributes * applied include the <code>Clip</code>, <code>Transform</code>, * <code>Paint</code>, <code>Composite</code> and * <code>Stroke</code> attributes. * @param s the <code>Shape</code> to be rendered * @see #setStroke * @see #setPaint * @see java.awt.Graphics#setColor * @see #transform * @see #setTransform * @see #clip * @see #setClip * @see #setComposite */ public void draw(Shape s) { //System.out.println("draw(Shape)"); psRenderer.write("gsave"); Shape imclip = getClip(); writeClip(imclip); Color c = getColor(); psRenderer.write(c.getRed() + " " + c.getGreen() + " " + c.getBlue() + " setrgbcolor"); applyPaint(getPaint(), false); applyStroke(getStroke()); psRenderer.write("newpath"); PathIterator iter = s.getPathIterator(getTransform()); while (!iter.isDone()) { double vals[] = new double[6]; int type = iter.currentSegment(vals); switch (type) { case PathIterator.SEG_CUBICTO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " " + PDFNumber.doubleOut(1000 * vals[2]) + " " + PDFNumber.doubleOut(1000 * vals[3]) + " " + PDFNumber.doubleOut(1000 * vals[4]) + " " + PDFNumber.doubleOut(1000 * vals[5]) + " curveto"); break; case PathIterator.SEG_LINETO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " lineto"); break; case PathIterator.SEG_MOVETO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " 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"); break; case PathIterator.SEG_CLOSE: psRenderer.write("closepath"); break; default: break; } iter.next(); } doDrawing(false, true, false); psRenderer.write("grestore"); } protected void writeClip(Shape s) { PathIterator iter = s.getPathIterator(getTransform()); psRenderer.write("newpath"); while (!iter.isDone()) { double vals[] = new double[6]; int type = iter.currentSegment(vals); switch (type) { case PathIterator.SEG_CUBICTO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " " + PDFNumber.doubleOut(1000 * vals[2]) + " " + PDFNumber.doubleOut(1000 * vals[3]) + " " + PDFNumber.doubleOut(1000 * vals[4]) + " " + PDFNumber.doubleOut(1000 * vals[5]) + " curveto"); break; case PathIterator.SEG_LINETO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " lineto"); break; case PathIterator.SEG_MOVETO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " 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"); break; case PathIterator.SEG_CLOSE: psRenderer.write("closepath"); break; default: break; } iter.next(); } // clip area psRenderer.write("clippath"); } protected void applyPaint(Paint paint, boolean fill) { if(paint instanceof GradientPaint) { GradientPaint gp = (GradientPaint)paint; Color c1 = gp.getColor1(); Color c2 = gp.getColor2(); Point2D p1 = gp.getPoint1(); Point2D p2 = gp.getPoint2(); boolean cyclic = gp.isCyclic(); Vector theCoords = new Vector(); theCoords.addElement( new Double(p1.getX())); theCoords.addElement( new Double(p1.getY())); theCoords.addElement( new Double(p2.getX())); theCoords.addElement( new Double(p2.getY())); Vector theExtend = new Vector(); theExtend.addElement(new Boolean(true)); theExtend.addElement(new Boolean(true)); Vector theDomain = new Vector(); theDomain.addElement(new Double(0)); theDomain.addElement(new Double(1)); Vector theEncode = new Vector(); theEncode.addElement(new Double(0)); theEncode.addElement(new Double(1)); theEncode.addElement(new Double(0)); theEncode.addElement(new Double(1)); Vector theBounds = new Vector(); theBounds.addElement(new Double(0)); theBounds.addElement(new Double(1)); Vector theFunctions = new Vector(); Vector someColors = new Vector(); PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(), c1.getBlue()); someColors.addElement(color1); PDFColor color2 = new PDFColor(c2.getRed(), c2.getGreen(), c2.getBlue()); someColors.addElement(color2); ColorSpace aColorSpace = new ColorSpace(ColorSpace.DEVICE_RGB); } else if(paint instanceof TexturePaint) { } } protected void applyStroke(Stroke stroke) { if(stroke instanceof BasicStroke) { BasicStroke bs = (BasicStroke)stroke; float[] da = bs.getDashArray(); if(da != null) { psRenderer.write("["); for(int count = 0; count < da.length; count++) { psRenderer.write("" + (1000 * (int)da[count])); if(count < da.length - 1) { psRenderer.write(" "); } } psRenderer.write("] "); float offset = bs.getDashPhase(); psRenderer.write((1000 * (int)offset) + " setdash"); } int ec = bs.getEndCap(); switch(ec) { case BasicStroke.CAP_BUTT: psRenderer.write(0 + " setlinecap"); break; case BasicStroke.CAP_ROUND: psRenderer.write(1 + " setlinecap"); break; case BasicStroke.CAP_SQUARE: psRenderer.write(2 + " setlinecap"); break; } int lj = bs.getLineJoin(); switch(lj) { case BasicStroke.JOIN_MITER: psRenderer.write(0 + " setlinejoin"); break; case BasicStroke.JOIN_ROUND: psRenderer.write(1 + " setlinejoin"); break; case BasicStroke.JOIN_BEVEL: psRenderer.write(2 + " setlinejoin"); break; } float lw = bs.getLineWidth(); psRenderer.write(PDFNumber.doubleOut(1000 * lw) + " setlinewidth"); float ml = bs.getMiterLimit(); psRenderer.write(PDFNumber.doubleOut(1000 * ml) + " setmiterlimit"); } } /** * Renders a {@link RenderedImage}, * applying a transform from image * space into user space before drawing. * The transformation from user space into device space is done with * the current <code>Transform</code> in the <code>Graphics2D</code>. * The specified transformation is applied to the image before the * transform attribute in the <code>Graphics2D</code> context is applied. * The rendering attributes applied include the <code>Clip</code>, * <code>Transform</code>, and <code>Composite</code> attributes. Note * that no rendering is done if the specified transform is * noninvertible. * @param img the image to be rendered * @param xform the transformation from image space into user space * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip */ public void drawRenderedImage(RenderedImage img, AffineTransform xform) { System.out.println("drawRenderedImage"); } /** * Renders a * {@link RenderableImage}, * applying a transform from image space into user space before drawing. * The transformation from user space into device space is done with * the current <code>Transform</code> in the <code>Graphics2D</code>. * The specified transformation is applied to the image before the * transform attribute in the <code>Graphics2D</code> context is applied. * The rendering attributes applied include the <code>Clip</code>, * <code>Transform</code>, and <code>Composite</code> attributes. Note * that no rendering is done if the specified transform is * noninvertible. *<p> * Rendering hints set on the <code>Graphics2D</code> object might * be used in rendering the <code>RenderableImage</code>. * If explicit control is required over specific hints recognized by a * specific <code>RenderableImage</code>, or if knowledge of which hints * are used is required, then a <code>RenderedImage</code> should be * obtained directly from the <code>RenderableImage</code> * and rendered using *{@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}. * @param img the image to be rendered * @param xform the transformation from image space into user space * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip * @see #drawRenderedImage */ public void drawRenderableImage(RenderableImage img, AffineTransform xform) { System.out.println("drawRenderableImage"); } /** * Renders the text specified by the specified <code>String</code>, * using the current <code>Font</code> and <code>Paint</code> attributes * in the <code>Graphics2D</code> context. * The baseline of the first character is at position * (<i>x</i>, <i>y</i>) in the User Space. * The rendering attributes applied include the <code>Clip</code>, * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and * <code>Composite</code> attributes. For characters in script systems * such as Hebrew and Arabic, the glyphs can be rendered from right to * left, in which case the coordinate supplied is the location of the * leftmost character on the baseline. * @param s the <code>String</code> to be rendered * @param x, y the coordinates where the <code>String</code> * should be rendered * @see #setPaint * @see java.awt.Graphics#setColor * @see java.awt.Graphics#setFont * @see #setTransform * @see #setComposite * @see #setClip */ public void drawString(String s, float x, float y) { System.out.println("drawString(String)"); psRenderer.write("BT"); Shape imclip = getClip(); writeClip(imclip); Color c = getColor(); psRenderer.write(c.getRed() + " " + c.getGreen() + " " + c.getBlue() + " setrgbcolor"); AffineTransform trans = getTransform(); trans.translate(x, y); double[] vals = new double[6]; trans.getMatrix(vals); psRenderer.write(PDFNumber.doubleOut(vals[0]) + " " + PDFNumber.doubleOut(vals[1]) + " " + PDFNumber.doubleOut(vals[2]) + " " + PDFNumber.doubleOut(vals[3]) + " " + PDFNumber.doubleOut(vals[4]) + " " + PDFNumber.doubleOut(vals[5]) + " " + PDFNumber.doubleOut(vals[6]) + " Tm [" + s + "]"); psRenderer.write("ET"); } /** * Renders the text of the specified iterator, using the * <code>Graphics2D</code> context's current <code>Paint</code>. The * iterator must specify a font * for each character. The baseline of the * first character is at position (<i>x</i>, <i>y</i>) in the * User Space. * The rendering attributes applied include the <code>Clip</code>, * <code>Transform</code>, <code>Paint</code>, and * <code>Composite</code> attributes. * For characters in script systems such as Hebrew and Arabic, * the glyphs can be rendered from right to left, in which case the * coordinate supplied is the location of the leftmost character * on the baseline. * @param iterator the iterator whose text is to be rendered * @param x, y the coordinates where the iterator's text is to be * rendered * @see #setPaint * @see java.awt.Graphics#setColor * @see #setTransform * @see #setComposite * @see #setClip */ public void drawString(AttributedCharacterIterator iterator, float x, float y) { System.err.println("drawString(AttributedCharacterIterator)"); psRenderer.write("BT"); Shape imclip = getClip(); writeClip(imclip); Color c = getColor(); currentColour = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); psRenderer.write(currentColour.getColorSpaceOut(true)); c = getBackground(); PDFColor col = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); psRenderer.write(col.getColorSpaceOut(false)); AffineTransform trans = getTransform(); trans.translate(x, y); double[] vals = new double[6]; trans.getMatrix(vals); for(char ch = iterator.first(); ch != CharacterIterator.DONE; ch = iterator.next()) { Map attr = iterator.getAttributes(); psRenderer.write(PDFNumber.doubleOut(vals[0]) + " " + PDFNumber.doubleOut(vals[1]) + " " + PDFNumber.doubleOut(vals[2]) + " " + PDFNumber.doubleOut(vals[3]) + " " + PDFNumber.doubleOut(vals[4]) + " " + PDFNumber.doubleOut(vals[5]) + " " + PDFNumber.doubleOut(vals[6]) + " Tm [" + ch + "]"); } psRenderer.write("ET"); } /** * Fills the interior of a <code>Shape</code> using the settings of the * <code>Graphics2D</code> context. The rendering attributes applied * include the <code>Clip</code>, <code>Transform</code>, * <code>Paint</code>, and <code>Composite</code>. * @param s the <code>Shape</code> to be filled * @see #setPaint * @see java.awt.Graphics#setColor * @see #transform * @see #setTransform * @see #setComposite * @see #clip * @see #setClip */ public void fill(Shape s) { //System.err.println("fill"); psRenderer.write("gsave"); Shape imclip = getClip(); writeClip(imclip); Color c = getColor(); psRenderer.write(c.getRed() + " " + c.getGreen() + " " + c.getBlue() + " setrgbcolor"); applyPaint(getPaint(), true); psRenderer.write("newpath"); PathIterator iter = s.getPathIterator(getTransform()); while (!iter.isDone()) { double vals[] = new double[6]; int type = iter.currentSegment(vals); switch (type) { case PathIterator.SEG_CUBICTO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " " + PDFNumber.doubleOut(1000 * vals[2]) + " " + PDFNumber.doubleOut(1000 * vals[3]) + " " + PDFNumber.doubleOut(1000 * vals[4]) + " " + PDFNumber.doubleOut(1000 * vals[5]) + " curveto"); break; case PathIterator.SEG_LINETO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " lineto"); break; case PathIterator.SEG_MOVETO: psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " + PDFNumber.doubleOut(1000 * vals[1]) + " 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"); break; case PathIterator.SEG_CLOSE: psRenderer.write("closepath"); break; default: break; } iter.next(); } doDrawing(true, false, iter.getWindingRule() == PathIterator.WIND_EVEN_ODD); psRenderer.write("grestore"); } protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) { if (fill) { if (stroke) { if (!nonzero) psRenderer.write("stroke"); else psRenderer.write("stroke"); } else { if (!nonzero) psRenderer.write("fill"); else psRenderer.write("fill"); } } else { //if(stroke) psRenderer.write("stroke"); } } /** * Returns the device configuration associated with this * <code>Graphics2D</code>. */ public GraphicsConfiguration getDeviceConfiguration() { //System.out.println("getDeviceConviguration"); return GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().getDefaultConfiguration(); } /** * Used to create proper font metrics */ private Graphics2D fmg; { BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); fmg = bi.createGraphics(); } /** * Gets the font metrics for the specified font. * @return the font metrics for the specified font. * @param f the specified font * @see java.awt.Graphics#getFont * @see java.awt.FontMetrics * @see java.awt.Graphics#getFontMetrics() */ public FontMetrics getFontMetrics(Font f) { return fmg.getFontMetrics(f); } /** * Sets the paint mode of this graphics context to alternate between * this graphics context's current color and the new specified color. * This specifies that logical pixel operations are performed in the * XOR mode, which alternates pixels between the current color and * a specified XOR color. * <p> * When drawing operations are performed, pixels which are the * current color are changed to the specified color, and vice versa. * <p> * Pixels that are of colors other than those two colors are changed * in an unpredictable but reversible manner; if the same figure is * drawn twice, then all pixels are restored to their original values. * @param c1 the XOR alternation color */ public void setXORMode(Color c1) { System.out.println("setXORMode"); } /** * Copies an area of the component by a distance specified by * <code>dx</code> and <code>dy</code>. From the point specified * by <code>x</code> and <code>y</code>, this method * copies downwards and to the right. To copy an area of the * component to the left or upwards, specify a negative value for * <code>dx</code> or <code>dy</code>. * If a portion of the source rectangle lies outside the bounds * of the component, or is obscured by another window or component, * <code>copyArea</code> will be unable to copy the associated * pixels. The area that is omitted can be refreshed by calling * the component's <code>paint</code> method. * @param x the <i>x</i> coordinate of the source rectangle. * @param y the <i>y</i> coordinate of the source rectangle. * @param width the width of the source rectangle. * @param height the height of the source rectangle. * @param dx the horizontal distance to copy the pixels. * @param dy the vertical distance to copy the pixels. */ public void copyArea(int x, int y, int width, int height, int dx, int dy) { System.out.println("copyArea"); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]