diff options
Diffstat (limited to 'src/java/org/apache')
-rw-r--r-- | src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java | 628 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/PrintRenderer.java | 27 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/pdf/PDFRenderer.java | 516 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java | 8 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSGenerator.java | 132 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSGraphics2D.java | 84 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSImageUtils.java | 107 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSRenderer.java | 759 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSState.java | 160 | ||||
-rw-r--r-- | src/java/org/apache/fop/render/ps/PSXMLHandler.java | 17 |
10 files changed, 1541 insertions, 897 deletions
diff --git a/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java new file mode 100644 index 000000000..7663b5f2d --- /dev/null +++ b/src/java/org/apache/fop/render/AbstractPathOrientedRenderer.java @@ -0,0 +1,628 @@ +/* + * Copyright 2005 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. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render; + +import java.awt.Color; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.area.BlockViewport; +import org.apache.fop.area.CTM; +import org.apache.fop.area.RegionViewport; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.Viewport; +import org.apache.fop.datatypes.ColorType; +import org.apache.fop.image.FopImage; +import org.apache.fop.pdf.PDFState; +import org.apache.fop.render.pdf.CTMHelper; +import org.apache.fop.traits.BorderProps; + +/** + * Abstract base class for renderers like PDF and PostScript where many painting operations + * follow similar patterns which makes it possible to share some code. + */ +public abstract class AbstractPathOrientedRenderer extends PrintRenderer { + + /** + * Converts a ColorType to a java.awt.Color (sRGB). + * @param col the color + * @return the converted color + */ + protected Color toColor(ColorType col) { + return new Color(col.getRed(), col.getGreen(), col.getBlue()); + } + + /** + * 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) { + int borderPaddingStart = block.getBorderAndPaddingWidthStart(); + int borderPaddingBefore = block.getBorderAndPaddingWidthBefore(); + + float startx = currentIPPosition / 1000f; + float starty = currentBPPosition / 1000f; + float width = block.getIPD() / 1000f; + float height = block.getBPD() / 1000f; + + /* using start-indent now + Integer spaceStart = (Integer) block.getTrait(Trait.SPACE_START); + if (spaceStart != null) { + startx += spaceStart.floatValue() / 1000f; + }*/ + startx += block.getStartIndent() / 1000f; + startx -= block.getBorderAndPaddingWidthStart() / 1000f; + + width += borderPaddingStart / 1000f; + width += block.getBorderAndPaddingWidthEnd() / 1000f; + height += borderPaddingBefore / 1000f; + height += block.getBorderAndPaddingWidthAfter() / 1000f; + + drawBackAndBorders(block, startx, starty, + width, height); + } + + /** + * Handle the traits for a region + * This is used to draw the traits for the given page region. + * (See Sect. 6.4.1.2 of XSL-FO spec.) + * @param region the RegionViewport whose region is to be drawn + */ + protected void handleRegionTraits(RegionViewport region) { + Rectangle2D viewArea = region.getViewArea(); + float startx = (float)(viewArea.getX() / 1000f); + float starty = (float)(viewArea.getY() / 1000f); + float width = (float)(viewArea.getWidth() / 1000f); + float height = (float)(viewArea.getHeight() / 1000f); + + if (region.getRegionReference().getRegionClass() == FO_REGION_BODY) { + currentBPPosition = region.getBorderAndPaddingWidthBefore(); + currentIPPosition = region.getBorderAndPaddingWidthStart(); + } + drawBackAndBorders(region, startx, starty, width, height); + } + + + /** + * Draw the background and borders. + * This draws the background and border traits for an area given + * the position. + * + * @param area 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 area, + float startx, float starty, + float width, float height) { + // draw background then border + + BorderProps bpsBefore = (BorderProps)area.getTrait(Trait.BORDER_BEFORE); + BorderProps bpsAfter = (BorderProps)area.getTrait(Trait.BORDER_AFTER); + BorderProps bpsStart = (BorderProps)area.getTrait(Trait.BORDER_START); + BorderProps bpsEnd = (BorderProps)area.getTrait(Trait.BORDER_END); + + Trait.Background back; + back = (Trait.Background)area.getTrait(Trait.BACKGROUND); + if (back != null) { + endTextObject(); + + //Calculate padding rectangle + float sx = startx; + float sy = starty; + float paddRectWidth = width; + float paddRectHeight = height; + if (bpsStart != null) { + sx += bpsStart.width / 1000f; + paddRectWidth -= bpsStart.width / 1000f; + } + if (bpsBefore != null) { + sy += bpsBefore.width / 1000f; + paddRectHeight -= bpsBefore.width / 1000f; + } + if (bpsEnd != null) { + paddRectWidth -= bpsEnd.width / 1000f; + } + if (bpsAfter != null) { + paddRectHeight -= bpsAfter.width / 1000f; + } + + if (back.getColor() != null) { + updateColor(back.getColor(), true); + fillRect(sx, sy, paddRectWidth, paddRectHeight); + } + if (back.getFopImage() != null) { + FopImage fopimage = back.getFopImage(); + if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) { + saveGraphicsState(); + clipRect(sx, sy, paddRectWidth, paddRectHeight); + int horzCount = (int)((paddRectWidth + * 1000 / fopimage.getIntrinsicWidth()) + 1.0f); + int vertCount = (int)((paddRectHeight + * 1000 / fopimage.getIntrinsicHeight()) + 1.0f); + if (back.getRepeat() == EN_NOREPEAT) { + horzCount = 1; + vertCount = 1; + } else if (back.getRepeat() == EN_REPEATX) { + vertCount = 1; + } else if (back.getRepeat() == EN_REPEATY) { + horzCount = 1; + } + //change from points to millipoints + sx *= 1000; + sy *= 1000; + if (horzCount == 1) { + sx += back.getHoriz(); + } + if (vertCount == 1) { + sy += back.getVertical(); + } + for (int x = 0; x < horzCount; x++) { + for (int y = 0; y < vertCount; y++) { + // place once + Rectangle2D pos; + pos = new Rectangle2D.Float(sx + (x * fopimage.getIntrinsicWidth()), + sy + (y * fopimage.getIntrinsicHeight()), + fopimage.getIntrinsicWidth(), + fopimage.getIntrinsicHeight()); + drawImage(back.getURL(), pos); + } + } + + restoreGraphicsState(); + } else { + log.warn("Can't find background image: " + back.getURL()); + } + } + } + + boolean[] b = new boolean[] { + (bpsBefore != null), (bpsEnd != null), + (bpsAfter != null), (bpsStart != null)}; + if (!b[0] && !b[1] && !b[2] && !b[3]) { + return; + } + float[] bw = new float[] { + (b[0] ? bpsBefore.width / 1000f : 0.0f), + (b[1] ? bpsEnd.width / 1000f : 0.0f), + (b[2] ? bpsAfter.width / 1000f : 0.0f), + (b[3] ? bpsStart.width / 1000f : 0.0f)}; + float[] clipw = new float[] { + BorderProps.getClippedWidth(bpsBefore) / 1000f, + BorderProps.getClippedWidth(bpsEnd) / 1000f, + BorderProps.getClippedWidth(bpsAfter) / 1000f, + BorderProps.getClippedWidth(bpsStart) / 1000f}; + starty += clipw[0]; + height -= clipw[0]; + height -= clipw[2]; + startx += clipw[3]; + width -= clipw[3]; + width -= clipw[1]; + + boolean[] slant = new boolean[] { + (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])}; + if (bpsBefore != null) { + endTextObject(); + + float sx1 = startx; + float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1); + float ex1 = startx + width; + float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1); + float outery = starty - clipw[0]; + float clipy = outery + clipw[0]; + float innery = outery + bw[0]; + + saveGraphicsState(); + moveTo(sx1, clipy); + float sx1a = sx1; + float ex1a = ex1; + if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { + if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) { + sx1a -= clipw[3]; + } + if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { + ex1a += clipw[1]; + } + lineTo(sx1a, outery); + lineTo(ex1a, outery); + } + lineTo(ex1, clipy); + lineTo(ex2, innery); + lineTo(sx2, innery); + closePath(); + clip(); + drawBorderLine(sx1a, outery, ex1a, innery, true, true, + bpsBefore.style, bpsBefore.color); + restoreGraphicsState(); + } + if (bpsEnd != null) { + endTextObject(); + + float sy1 = starty; + float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1); + float ey1 = starty + height; + float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1); + float outerx = startx + width + clipw[1]; + float clipx = outerx - clipw[1]; + float innerx = outerx - bw[1]; + + saveGraphicsState(); + moveTo(clipx, sy1); + float sy1a = sy1; + float ey1a = ey1; + if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { + if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { + sy1a -= clipw[0]; + } + if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { + ey1a += clipw[2]; + } + lineTo(outerx, sy1a); + lineTo(outerx, ey1a); + } + lineTo(clipx, ey1); + lineTo(innerx, ey2); + lineTo(innerx, sy2); + closePath(); + clip(); + drawBorderLine(innerx, sy1a, outerx, ey1a, false, false, bpsEnd.style, bpsEnd.color); + restoreGraphicsState(); + } + if (bpsAfter != null) { + endTextObject(); + + float sx1 = startx; + float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1); + float ex1 = startx + width; + float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1); + float outery = starty + height + clipw[2]; + float clipy = outery - clipw[2]; + float innery = outery - bw[2]; + + saveGraphicsState(); + moveTo(ex1, clipy); + float sx1a = sx1; + float ex1a = ex1; + if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { + if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) { + sx1a -= clipw[3]; + } + if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { + ex1a += clipw[1]; + } + lineTo(ex1a, outery); + lineTo(sx1a, outery); + } + lineTo(sx1, clipy); + lineTo(sx2, innery); + lineTo(ex2, innery); + closePath(); + clip(); + drawBorderLine(sx1a, innery, ex1a, outery, true, false, bpsAfter.style, bpsAfter.color); + restoreGraphicsState(); + } + if (bpsStart != null) { + endTextObject(); + + float sy1 = starty; + float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1); + float ey1 = sy1 + height; + float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1); + float outerx = startx - clipw[3]; + float clipx = outerx + clipw[3]; + float innerx = outerx + bw[3]; + + saveGraphicsState(); + moveTo(clipx, ey1); + float sy1a = sy1; + float ey1a = ey1; + if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) { + if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { + sy1a -= clipw[0]; + } + if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { + ey1a += clipw[2]; + } + lineTo(outerx, ey1a); + lineTo(outerx, sy1a); + } + lineTo(clipx, sy1); + lineTo(innerx, sy2); + lineTo(innerx, ey2); + closePath(); + clip(); + drawBorderLine(outerx, sy1a, innerx, ey1a, false, true, bpsStart.style, bpsStart.color); + restoreGraphicsState(); + } + } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List) + */ + protected void renderBlockViewport(BlockViewport bv, List children) { + // clip and position viewport if necessary + + // save positions + int saveIP = currentIPPosition; + int saveBP = currentBPPosition; + //String saveFontName = currentFontName; + + CTM ctm = bv.getCTM(); + int borderPaddingStart = bv.getBorderAndPaddingWidthStart(); + int borderPaddingBefore = bv.getBorderAndPaddingWidthBefore(); + float x, y; + x = (float)(bv.getXOffset() + containingIPPosition) / 1000f; + y = (float)(bv.getYOffset() + containingBPPosition) / 1000f; + + if (bv.getPositioning() == Block.ABSOLUTE + || bv.getPositioning() == Block.FIXED) { + + //For FIXED, we need to break out of the current viewports to the + //one established by the page. We save the state stack for restoration + //after the block-container has been painted. See below. + List breakOutList = null; + if (bv.getPositioning() == Block.FIXED) { + breakOutList = breakOutOfStateStack(); + } + + CTM tempctm = new CTM(containingIPPosition, containingBPPosition); + ctm = tempctm.multiply(ctm); + + //This is the content-rect + float width = (float)bv.getIPD() / 1000f; + float height = (float)bv.getBPD() / 1000f; + + //Adjust for spaces (from margin or indirectly by start-indent etc. + Integer spaceStart = (Integer) bv.getTrait(Trait.SPACE_START); + if (spaceStart != null) { + x += spaceStart.floatValue() / 1000; + } + Integer spaceBefore = (Integer) bv.getTrait(Trait.SPACE_BEFORE); + if (spaceBefore != null) { + y += spaceBefore.floatValue() / 1000; + } + + float bpwidth = (borderPaddingStart + bv.getBorderAndPaddingWidthEnd()) / 1000f; + float bpheight = (borderPaddingBefore + bv.getBorderAndPaddingWidthAfter()) / 1000f; + + drawBackAndBorders(bv, x, y, width + bpwidth, height + bpheight); + + //Now adjust for border/padding + x += borderPaddingStart / 1000f; + y += borderPaddingBefore / 1000f; + + if (bv.getClip()) { + saveGraphicsState(); + clipRect(x, y, width, height); + } + + startVParea(ctm); + + currentIPPosition = 0; + currentBPPosition = 0; + + renderBlocks(bv, children); + endVParea(); + + if (bv.getClip()) { + restoreGraphicsState(); + } + + // clip if necessary + + if (breakOutList != null) { + restoreStateStackAfterBreakOut(breakOutList); + } + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + } else { + + Integer spaceBefore = (Integer)bv.getTrait(Trait.SPACE_BEFORE); + if (spaceBefore != null) { + currentBPPosition += spaceBefore.intValue(); + } + + //borders and background in the old coordinate system + handleBlockTraits(bv); + + CTM tempctm = new CTM(containingIPPosition, currentBPPosition); + ctm = tempctm.multiply(ctm); + + //Now adjust for border/padding + x += borderPaddingStart / 1000f; + y += borderPaddingBefore / 1000f; + + // clip if necessary + if (bv.getClip()) { + saveGraphicsState(); + float width = (float)bv.getIPD() / 1000f; + float height = (float)bv.getBPD() / 1000f; + clipRect(x, y, width, height); + } + + if (ctm != null) { + startVParea(ctm); + currentIPPosition = 0; + currentBPPosition = 0; + } + renderBlocks(bv, children); + if (ctm != null) { + endVParea(); + } + + if (bv.getClip()) { + restoreGraphicsState(); + } + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + + //Adjust BP position (alloc BPD + spaces) + if (spaceBefore != null) { + currentBPPosition += spaceBefore.intValue(); + } + currentBPPosition += (int)(bv.getAllocBPD()); + Integer spaceAfter = (Integer)bv.getTrait(Trait.SPACE_AFTER); + if (spaceAfter != null) { + currentBPPosition += spaceAfter.intValue(); + } + } + //currentFontName = saveFontName; + } + + /** + * Render an inline viewport. + * This renders an inline viewport by clipping if necessary. + * @param viewport the viewport to handle + */ + public void renderViewport(Viewport viewport) { + + float x = currentIPPosition / 1000f; + float y = (currentBPPosition + viewport.getOffset()) / 1000f; + float width = viewport.getIPD() / 1000f; + float height = viewport.getBPD() / 1000f; + // TODO: Calculate the border rect correctly. + float borderPaddingStart = viewport.getBorderAndPaddingWidthStart() / 1000f; + float borderPaddingBefore = viewport.getBorderAndPaddingWidthBefore() / 1000f; + float bpwidth = borderPaddingStart + + (viewport.getBorderAndPaddingWidthEnd() / 1000f); + float bpheight = borderPaddingBefore + + (viewport.getBorderAndPaddingWidthAfter() / 1000f); + + drawBackAndBorders(viewport, x, y, width + bpwidth, height + bpheight); + + if (viewport.getClip()) { + saveGraphicsState(); + + clipRect(x + borderPaddingStart, y + borderPaddingBefore, width, height); + } + super.renderViewport(viewport); + + if (viewport.getClip()) { + restoreGraphicsState(); + } + } + + /** + * Restores the state stack after a break out. + * @param breakOutList the state stack to restore. + */ + protected abstract void restoreStateStackAfterBreakOut(List breakOutList); + + /** + * Breaks out of the state stack to handle fixed block-containers. + * @return the saved state stack to recreate later + */ + protected abstract List breakOutOfStateStack(); + + /** Saves the graphics state of the rendering engine. */ + protected abstract void saveGraphicsState(); + + /** Restores the last graphics state of the rendering engine. */ + protected abstract void restoreGraphicsState(); + + /** Indicates the beginning of a text object. */ + protected abstract void beginTextObject(); + + /** Indicates the end of a text object. */ + protected abstract void endTextObject(); + + /** Clip using the current path. */ + protected abstract void clip(); + + /** + * Clip using a rectangular area. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the rectangle + * @param height the height of the rectangle + */ + protected abstract void clipRect(float x, float y, float width, float height); + + /** + * Moves the current point to (x, y), omitting any connecting line segment. + * @param x x coordinate + * @param y y coordinate + */ + protected abstract void moveTo(float x, float y); + + /** + * Appends a straight line segment from the current point to (x, y). The + * new current point is (x, y). + * @param x x coordinate + * @param y y coordinate + */ + protected abstract void lineTo(float x, float y); + + /** + * Closes the current subpath by appending a straight line segment from + * the current point to the starting point of the subpath. + */ + protected abstract void closePath(); + + /** + * Fill a rectangular area. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the rectangle + * @param height the height of the rectangle + */ + protected abstract void fillRect(float x, float y, float width, float height); + + /** + * Establishes a new foreground or fill color. + * @param col the color to apply (null skips this operation) + * @param fill true to set the fill color, false for the foreground color + */ + protected abstract void updateColor(ColorType col, boolean fill); + + /** + * Draw an image at the indicated location. + * @param url the URI/URL of the image + * @param pos the position of the image + */ + protected abstract void drawImage(String url, Rectangle2D pos); + + /** + * Draw a border segment of an XSL-FO style border. + * @param x1 starting x coordinate + * @param y1 starting y coordinate + * @param x2 ending x coordinate + * @param y2 ending y coordinate + * @param horz true for horizontal border segments, false for vertical border segments + * @param startOrBefore true for border segments on the start or before edge, + * false for end or after. + * @param style the border style (one of Constants.EN_DASHED etc.) + * @param col the color for the border segment + */ + protected abstract void drawBorderLine(float x1, float y1, float x2, float y2, + boolean horz, boolean startOrBefore, int style, ColorType col); + +} diff --git a/src/java/org/apache/fop/render/PrintRenderer.java b/src/java/org/apache/fop/render/PrintRenderer.java index aafed0355..1d97580b0 100644 --- a/src/java/org/apache/fop/render/PrintRenderer.java +++ b/src/java/org/apache/fop/render/PrintRenderer.java @@ -19,10 +19,16 @@ package org.apache.fop.render; // FOP +import org.apache.fop.area.Area; +import org.apache.fop.area.Trait; import org.apache.fop.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; +import org.apache.fop.image.FopImage; +import org.apache.fop.traits.BorderProps; // Java +import java.awt.Color; +import java.awt.geom.Rectangle2D; import java.util.List; /** Abstract base class of "Print" type renderers. */ @@ -44,4 +50,25 @@ public abstract class PrintRenderer extends AbstractRenderer { FontSetup.setup(fontInfo, fontList); } + /** + * Lightens up a color for groove, ridge, inset and outset border effects. + * @param col the color to lighten up + * @param factor factor by which to lighten up (negative values darken the color) + * @return the modified color + */ + protected Color lightenColor(Color col, float factor) { + float[] cols = new float[3]; + cols = col.getColorComponents(cols); + if (factor > 0) { + cols[0] += (1.0 - cols[0]) * factor; + cols[1] += (1.0 - cols[1]) * factor; + cols[2] += (1.0 - cols[2]) * factor; + } else { + cols[0] -= cols[0] * -factor; + cols[1] -= cols[1] * -factor; + cols[2] -= cols[2] * -factor; + } + return new Color(cols[0], cols[1], cols[2]); + } + } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 9d343314b..500baf3da 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -81,6 +81,7 @@ import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFStream; import org.apache.fop.pdf.PDFText; import org.apache.fop.pdf.PDFXObject; +import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.PrintRenderer; import org.apache.fop.render.RendererContext; import org.apache.fop.traits.BorderProps; @@ -103,7 +104,7 @@ text decoration * Renderer that renders areas to PDF * */ -public class PDFRenderer extends PrintRenderer { +public class PDFRenderer extends AbstractPathOrientedRenderer { /** * The mime type for pdf @@ -514,326 +515,11 @@ public class PDFRenderer extends PrintRenderer { */ protected void handleRegionTraits(RegionViewport region) { currentFontName = ""; - Rectangle2D viewArea = region.getViewArea(); - float startx = (float)(viewArea.getX() / 1000f); - float starty = (float)(viewArea.getY() / 1000f); - float width = (float)(viewArea.getWidth() / 1000f); - float height = (float)(viewArea.getHeight() / 1000f); - - if (region.getRegionReference().getRegionClass() == FO_REGION_BODY) { - currentBPPosition = region.getBorderAndPaddingWidthBefore(); - currentIPPosition = region.getBorderAndPaddingWidthStart(); - } - 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) { - int borderPaddingStart = block.getBorderAndPaddingWidthStart(); - int borderPaddingBefore = block.getBorderAndPaddingWidthBefore(); - - float startx = currentIPPosition / 1000f; - float starty = currentBPPosition / 1000f; - float width = block.getIPD() / 1000f; - float height = block.getBPD() / 1000f; - - /* using start-indent now - Integer spaceStart = (Integer) block.getTrait(Trait.SPACE_START); - if (spaceStart != null) { - startx += spaceStart.floatValue() / 1000f; - }*/ - startx += block.getStartIndent() / 1000f; - startx -= block.getBorderAndPaddingWidthStart() / 1000f; - - width += borderPaddingStart / 1000f; - width += block.getBorderAndPaddingWidthEnd() / 1000f; - height += borderPaddingBefore / 1000f; - height += block.getBorderAndPaddingWidthAfter() / 1000f; - - drawBackAndBorders(block, startx, starty, - width, height); - } - - /** - * Draw the background and borders. - * This draws the background and border traits for an area given - * the position. - * - * @param area 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 area, - float startx, float starty, - float width, float height) { - // draw background then border - - BorderProps bpsBefore = (BorderProps)area.getTrait(Trait.BORDER_BEFORE); - BorderProps bpsAfter = (BorderProps)area.getTrait(Trait.BORDER_AFTER); - BorderProps bpsStart = (BorderProps)area.getTrait(Trait.BORDER_START); - BorderProps bpsEnd = (BorderProps)area.getTrait(Trait.BORDER_END); - - Trait.Background back; - back = (Trait.Background)area.getTrait(Trait.BACKGROUND); - if (back != null) { - endTextObject(); - - //Calculate padding rectangle - float sx = startx; - float sy = starty; - float paddRectWidth = width; - float paddRectHeight = height; - if (bpsStart != null) { - sx += bpsStart.width / 1000f; - paddRectWidth -= bpsStart.width / 1000f; - } - if (bpsBefore != null) { - sy += bpsBefore.width / 1000f; - paddRectHeight -= bpsBefore.width / 1000f; - } - if (bpsEnd != null) { - paddRectWidth -= bpsEnd.width / 1000f; - } - if (bpsAfter != null) { - paddRectHeight -= bpsAfter.width / 1000f; - } - - if (back.getColor() != null) { - updateColor(back.getColor(), true, null); - currentStream.add(sx + " " + sy + " " - + paddRectWidth + " " + paddRectHeight + " re\n"); - currentStream.add("f\n"); - } - if (back.getFopImage() != null) { - FopImage fopimage = back.getFopImage(); - if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) { - saveGraphicsState(); - clip(sx, sy, paddRectWidth, paddRectHeight); - int horzCount = (int)((paddRectWidth - * 1000 / fopimage.getIntrinsicWidth()) + 1.0f); - int vertCount = (int)((paddRectHeight - * 1000 / fopimage.getIntrinsicHeight()) + 1.0f); - if (back.getRepeat() == EN_NOREPEAT) { - horzCount = 1; - vertCount = 1; - } else if (back.getRepeat() == EN_REPEATX) { - vertCount = 1; - } else if (back.getRepeat() == EN_REPEATY) { - horzCount = 1; - } - //change from points to millipoints - sx *= 1000; - sy *= 1000; - if (horzCount == 1) { - sx += back.getHoriz(); - } - if (vertCount == 1) { - sy += back.getVertical(); - } - for (int x = 0; x < horzCount; x++) { - for (int y = 0; y < vertCount; y++) { - // place once - Rectangle2D pos; - pos = new Rectangle2D.Float(sx + (x * fopimage.getIntrinsicWidth()), - sy + (y * fopimage.getIntrinsicHeight()), - fopimage.getIntrinsicWidth(), - fopimage.getIntrinsicHeight()); - putImage(back.getURL(), pos); - } - } - - restoreGraphicsState(); - } else { - log.warn("Can't find background image: " + back.getURL()); - } - } - } - - boolean[] b = new boolean[] { - (bpsBefore != null), (bpsEnd != null), - (bpsAfter != null), (bpsStart != null)}; - if (!b[0] && !b[1] && !b[2] && !b[3]) { - return; - } - float[] bw = new float[] { - (b[0] ? bpsBefore.width / 1000f : 0.0f), - (b[1] ? bpsEnd.width / 1000f : 0.0f), - (b[2] ? bpsAfter.width / 1000f : 0.0f), - (b[3] ? bpsStart.width / 1000f : 0.0f)}; - float[] clipw = new float[] { - BorderProps.getClippedWidth(bpsBefore) / 1000f, - BorderProps.getClippedWidth(bpsEnd) / 1000f, - BorderProps.getClippedWidth(bpsAfter) / 1000f, - BorderProps.getClippedWidth(bpsStart) / 1000f}; - starty += clipw[0]; - height -= clipw[0]; - height -= clipw[2]; - startx += clipw[3]; - width -= clipw[3]; - width -= clipw[1]; - - boolean[] slant = new boolean[] { - (b[3] && b[0]), (b[0] && b[1]), (b[1] && b[2]), (b[2] && b[3])}; - if (bpsBefore != null) { - endTextObject(); - - float sx1 = startx; - float sx2 = (slant[0] ? sx1 + bw[3] - clipw[3] : sx1); - float ex1 = startx + width; - float ex2 = (slant[1] ? ex1 - bw[1] + clipw[1] : ex1); - float outery = starty - clipw[0]; - float clipy = outery + clipw[0]; - float innery = outery + bw[0]; - - saveGraphicsState(); - moveTo(sx1, clipy); - float sx1a = sx1; - float ex1a = ex1; - if (bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { - if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) { - sx1a -= clipw[3]; - } - if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { - ex1a += clipw[1]; - } - lineTo(sx1a, outery); - lineTo(ex1a, outery); - } - lineTo(ex1, clipy); - lineTo(ex2, innery); - lineTo(sx2, innery); - closePath(); - clip(); - drawBorderLine(sx1a, outery, ex1a, innery, true, true, - bpsBefore.style, bpsBefore.color); - restoreGraphicsState(); - } - if (bpsEnd != null) { - endTextObject(); - - float sy1 = starty; - float sy2 = (slant[1] ? sy1 + bw[0] - clipw[0] : sy1); - float ey1 = starty + height; - float ey2 = (slant[2] ? ey1 - bw[2] + clipw[2] : ey1); - float outerx = startx + width + clipw[1]; - float clipx = outerx - clipw[1]; - float innerx = outerx - bw[1]; - - saveGraphicsState(); - moveTo(clipx, sy1); - float sy1a = sy1; - float ey1a = ey1; - if (bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { - if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { - sy1a -= clipw[0]; - } - if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { - ey1a += clipw[2]; - } - lineTo(outerx, sy1a); - lineTo(outerx, ey1a); - } - lineTo(clipx, ey1); - lineTo(innerx, ey2); - lineTo(innerx, sy2); - closePath(); - clip(); - drawBorderLine(innerx, sy1a, outerx, ey1a, false, false, bpsEnd.style, bpsEnd.color); - restoreGraphicsState(); - } - if (bpsAfter != null) { - endTextObject(); - - float sx1 = startx; - float sx2 = (slant[3] ? sx1 + bw[3] - clipw[3] : sx1); - float ex1 = startx + width; - float ex2 = (slant[2] ? ex1 - bw[1] + clipw[1] : ex1); - float outery = starty + height + clipw[2]; - float clipy = outery - clipw[2]; - float innery = outery - bw[2]; - - saveGraphicsState(); - moveTo(ex1, clipy); - float sx1a = sx1; - float ex1a = ex1; - if (bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { - if (bpsStart != null && bpsStart.mode == BorderProps.COLLAPSE_OUTER) { - sx1a -= clipw[3]; - } - if (bpsEnd != null && bpsEnd.mode == BorderProps.COLLAPSE_OUTER) { - ex1a += clipw[1]; - } - lineTo(ex1a, outery); - lineTo(sx1a, outery); - } - lineTo(sx1, clipy); - lineTo(sx2, innery); - lineTo(ex2, innery); - closePath(); - clip(); - drawBorderLine(sx1a, innery, ex1a, outery, true, false, bpsAfter.style, bpsAfter.color); - restoreGraphicsState(); - } - if (bpsStart != null) { - endTextObject(); - - float sy1 = starty; - float sy2 = (slant[0] ? sy1 + bw[0] - clipw[0] : sy1); - float ey1 = sy1 + height; - float ey2 = (slant[3] ? ey1 - bw[2] + clipw[2] : ey1); - float outerx = startx - clipw[3]; - float clipx = outerx + clipw[3]; - float innerx = outerx + bw[3]; - - saveGraphicsState(); - moveTo(clipx, ey1); - float sy1a = sy1; - float ey1a = ey1; - if (bpsStart.mode == BorderProps.COLLAPSE_OUTER) { - if (bpsBefore != null && bpsBefore.mode == BorderProps.COLLAPSE_OUTER) { - sy1a -= clipw[0]; - } - if (bpsAfter != null && bpsAfter.mode == BorderProps.COLLAPSE_OUTER) { - ey1a += clipw[2]; - } - lineTo(outerx, ey1a); - lineTo(outerx, sy1a); - } - lineTo(clipx, sy1); - lineTo(innerx, sy2); - lineTo(innerx, ey2); - closePath(); - clip(); - drawBorderLine(outerx, sy1a, innerx, ey1a, false, true, bpsStart.style, bpsStart.color); - restoreGraphicsState(); - } - } - - private Color lightenColor(Color col, float factor) { - float[] cols = new float[3]; - cols = col.getColorComponents(cols); - if (factor > 0) { - cols[0] += (1.0 - cols[0]) * factor; - cols[1] += (1.0 - cols[1]) * factor; - cols[2] += (1.0 - cols[2]) * factor; - } else { - cols[0] -= cols[0] * -factor; - cols[1] -= cols[1] * -factor; - cols[2] -= cols[2] * -factor; - } - return new Color(cols[0], cols[1], cols[2]); + super.handleRegionTraits(region); } - private void drawBorderLine(float x1, float y1, float x2, float y2, + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void drawBorderLine(float x1, float y1, float x2, float y2, boolean horz, boolean startOrBefore, int style, ColorType col) { float w = x2 - x1; float h = y2 - y1; @@ -1012,11 +698,33 @@ public class PDFRenderer extends PrintRenderer { } /** + * Clip a rectangular area. + * write a clipping operation given coordinates in the current + * transform. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the area + * @param height the height of the area + */ + protected void clipRect(float x, float y, float width, float height) { + currentStream.add(x + " " + y + " " + width + " " + height + " re "); + clip(); + } + + /** + * Clip an area. + */ + protected void clip() { + currentStream.add("W\n"); + currentStream.add("n\n"); + } + + /** * Moves the current point to (x, y), omitting any connecting line segment. * @param x x coordinate * @param y y coordinate */ - private void moveTo(float x, float y) { + protected void moveTo(float x, float y) { currentStream.add(x + " " + y + " m "); } @@ -1026,7 +734,7 @@ public class PDFRenderer extends PrintRenderer { * @param x x coordinate * @param y y coordinate */ - private void lineTo(float x, float y) { + protected void lineTo(float x, float y) { currentStream.add(x + " " + y + " l "); } @@ -1034,9 +742,16 @@ public class PDFRenderer extends PrintRenderer { * Closes the current subpath by appending a straight line segment from * the current point to the starting point of the subpath. */ - private void closePath() { + protected void closePath() { currentStream.add("h "); } + + /** + * @see org.apache.fop.render.AbstractPathOrientedRenderer#fillRect(float, float, float, float) + */ + protected void fillRect(float x, float y, float w, float h) { + currentStream.add(x + " " + y + " " + w + " " + h + " re f\n"); + } /** * Draw a line. @@ -1053,7 +768,7 @@ public class PDFRenderer extends PrintRenderer { /** * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List) - */ + *//* protected void renderBlockViewport(BlockViewport bv, List children) { // clip and position viewport if necessary @@ -1077,21 +792,7 @@ public class PDFRenderer extends PrintRenderer { //after the block-container has been painted. See below. List breakOutList = null; if (bv.getPositioning() == Block.FIXED) { - //break out - breakOutList = new java.util.ArrayList(); - PDFState.Data data; - while (true) { - data = currentState.getData(); - if (currentState.pop() == null) { - break; - } - if (breakOutList.size() == 0) { - comment("------ break out!"); - } - breakOutList.add(0, data); //Insert because of stack-popping - //getLogger().debug("Adding to break out list: " + data); - restoreGraphicsState(); - } + breakOutList = breakOutOfStateStack(); } CTM tempctm = new CTM(containingIPPosition, containingBPPosition); @@ -1122,7 +823,7 @@ public class PDFRenderer extends PrintRenderer { if (bv.getClip()) { saveGraphicsState(); - clip(x, y, width, height); + clipRect(x, y, width, height); } startVParea(ctm); @@ -1140,31 +841,7 @@ public class PDFRenderer extends PrintRenderer { // clip if necessary if (breakOutList != null) { - comment("------ restoring context after break-out..."); - PDFState.Data data; - Iterator i = breakOutList.iterator(); - while (i.hasNext()) { - data = (PDFState.Data)i.next(); - //getLogger().debug("Restoring: " + data); - currentState.push(); - saveGraphicsState(); - if (data.concatenations != null) { - Iterator tr = data.concatenations.iterator(); - while (tr.hasNext()) { - AffineTransform at = (AffineTransform)tr.next(); - currentState.setTransform(at); - double[] matrix = new double[6]; - at.getMatrix(matrix); - tempctm = new CTM(matrix[0], matrix[1], matrix[2], matrix[3], - matrix[4] * 1000, matrix[5] * 1000); - currentStream.add(CTMHelper.toPDFString(tempctm) + " cm\n"); - } - } - //TODO Break-out: Also restore items such as line width and color - //Left out for now because all this painting stuff is very - //inconsistent. Some values go over PDFState, some don't. - } - comment("------ done."); + restoreStateStackAfterBreakOut(breakOutList); } currentIPPosition = saveIP; @@ -1191,7 +868,7 @@ public class PDFRenderer extends PrintRenderer { saveGraphicsState(); float width = (float)bv.getIPD() / 1000f; float height = (float)bv.getBPD() / 1000f; - clip(x, y, width, height); + clipRect(x, y, width, height); } if (ctm != null) { @@ -1222,28 +899,59 @@ public class PDFRenderer extends PrintRenderer { } } currentFontName = saveFontName; - } - + }*/ + /** - * Clip an area. - * write a clipping operation given coordinates in the current - * transform. - * @param x the x coordinate - * @param y the y coordinate - * @param width the width of the area - * @param height the height of the area + * Breaks out of the state stack to handle fixed block-containers. + * @return the saved state stack to recreate later */ - protected void clip(float x, float y, float width, float height) { - currentStream.add(x + " " + y + " " + width + " " + height + " re "); - clip(); + protected List breakOutOfStateStack() { + List breakOutList = new java.util.ArrayList(); + PDFState.Data data; + while (true) { + data = currentState.getData(); + if (currentState.pop() == null) { + break; + } + if (breakOutList.size() == 0) { + comment("------ break out!"); + } + breakOutList.add(0, data); //Insert because of stack-popping + restoreGraphicsState(); + } + return breakOutList; } /** - * Clip an area. + * Restores the state stack after a break out. + * @param breakOutList the state stack to restore. */ - protected void clip() { - currentStream.add("W\n"); - currentStream.add("n\n"); + protected void restoreStateStackAfterBreakOut(List breakOutList) { + CTM tempctm; + comment("------ restoring context after break-out..."); + PDFState.Data data; + Iterator i = breakOutList.iterator(); + while (i.hasNext()) { + data = (PDFState.Data)i.next(); + currentState.push(); + saveGraphicsState(); + if (data.concatenations != null) { + Iterator tr = data.concatenations.iterator(); + while (tr.hasNext()) { + AffineTransform at = (AffineTransform)tr.next(); + currentState.setTransform(at); + double[] matrix = new double[6]; + at.getMatrix(matrix); + tempctm = new CTM(matrix[0], matrix[1], matrix[2], matrix[3], + matrix[4] * 1000, matrix[5] * 1000); + currentStream.add(CTMHelper.toPDFString(tempctm) + " cm\n"); + } + } + //TODO Break-out: Also restore items such as line width and color + //Left out for now because all this painting stuff is very + //inconsistent. Some values go over PDFState, some don't. + } + comment("------ done."); } /** @@ -1593,15 +1301,6 @@ public class PDFRenderer extends PrintRenderer { } /** - * Converts a ColorType to a java.awt.Color (sRGB). - * @param col the color - * @return the converted color - */ - private Color toColor(ColorType col) { - return new Color(col.getRed(), col.getGreen(), col.getBlue()); - } - - /** * Establishes a new foreground or fill color. * @param col the color to apply (null skips this operation) * @param fill true to set the fill color, false for the foreground color @@ -1625,6 +1324,11 @@ public class PDFRenderer extends PrintRenderer { } } + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void updateColor(ColorType col, boolean fill) { + updateColor(col, fill, null); + } + private void updateFont(String name, int size, StringBuffer pdf) { if ((!name.equals(this.currentFontName)) || (size != this.currentFontSize)) { @@ -1646,6 +1350,12 @@ public class PDFRenderer extends PrintRenderer { putImage(url, pos); } + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void drawImage(String url, Rectangle2D pos) { + endTextObject(); + putImage(url, pos); + } + /** * Adds a PDF XObject (a bitmap) to the PDF that will later be referenced. * @param url URL of the bitmap @@ -1792,32 +1502,6 @@ public class PDFRenderer extends PrintRenderer { } /** - * Render an inline viewport. - * This renders an inline viewport by clipping if necessary. - * @param viewport the viewport to handle - */ - public void renderViewport(Viewport viewport) { - - float x = currentIPPosition / 1000f; - float y = (currentBPPosition + viewport.getOffset()) / 1000f; - float width = viewport.getIPD() / 1000f; - float height = viewport.getBPD() / 1000f; - // TODO: Calculate the border rect correctly. - drawBackAndBorders(viewport, x, y, width, height); - - if (viewport.getClip()) { - saveGraphicsState(); - - clip(x, y, width, height); - } - super.renderViewport(viewport); - - if (viewport.getClip()) { - restoreGraphicsState(); - } - } - - /** * Render leader area. * This renders a leader area which is an area with a rule. * @param area the leader area to render diff --git a/src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java b/src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java index d970194c4..2c684d5b9 100644 --- a/src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java +++ b/src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 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. @@ -35,7 +35,6 @@ import org.apache.fop.fonts.FontSetup; * <tt>PSGraphics2D</tt>. * * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> - * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> * @version $Id$ * @see org.apache.fop.render.ps.PSGraphics2D */ @@ -218,15 +217,14 @@ public abstract class AbstractPSDocumentGraphics2D extends PSGraphics2D { } writePageHeader(); - gen.writeln("0.001 0.001 scale"); if ((this.viewportWidth != this.width || this.viewportHeight != this.height) && (this.viewportWidth > 0) && (this.viewportHeight > 0)){ gen.concatMatrix(this.width / this.viewportWidth, 0, 0, -1 * (this.height / this.viewportHeight), - 0, this.height * 1000); + 0, this.height); } else { - gen.concatMatrix(1, 0, 0, -1, 0, this.height * 1000); + gen.concatMatrix(1, 0, 0, -1, 0, this.height); } gen.writeDSCComment(DSCConstants.END_PAGE_SETUP); this.pagePending = true; diff --git a/src/java/org/apache/fop/render/ps/PSGenerator.java b/src/java/org/apache/fop/render/ps/PSGenerator.java index f7cf64c4b..9a21cb0db 100644 --- a/src/java/org/apache/fop/render/ps/PSGenerator.java +++ b/src/java/org/apache/fop/render/ps/PSGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 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. @@ -18,6 +18,7 @@ package org.apache.fop.render.ps; +import java.awt.Color; import java.awt.geom.AffineTransform; import java.io.OutputStream; import java.io.IOException; @@ -32,8 +33,7 @@ import java.util.Stack; * This class is used to output PostScript code to an OutputStream. * * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> - * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> - * @version $Id: PSGenerator.java,v 1.3 2003/03/07 09:46:30 jeremias Exp $ + * @version $Id$ */ public class PSGenerator { @@ -49,8 +49,8 @@ public class PSGenerator { private Stack graphicsStateStack = new Stack(); private PSState currentState; - private DecimalFormat df3 = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US)); - private DecimalFormat df1 = new DecimalFormat("0.#", new DecimalFormatSymbols(Locale.US)); + //private DecimalFormat df3 = new DecimalFormat("0.000", new DecimalFormatSymbols(Locale.US)); + private DecimalFormat df3 = new DecimalFormat("0.###", new DecimalFormatSymbols(Locale.US)); private DecimalFormat df5 = new DecimalFormat("0.#####", new DecimalFormatSymbols(Locale.US)); private StringBuffer tempBuffer = new StringBuffer(256); @@ -59,7 +59,7 @@ public class PSGenerator { public PSGenerator(OutputStream out) { this.out = out; this.currentState = new PSState(); - this.graphicsStateStack.push(this.currentState); + //this.graphicsStateStack.push(this.currentState); } /** @@ -72,13 +72,13 @@ public class PSGenerator { /** * Returns the selected PostScript level. - * (Hardcoded to level 3 for the moment.) + * (Hardcoded to level 2 for the moment.) * @return the PostScript level */ public int getPSLevel() { - return 3; + return 2; } - + /** * Writes a newline character to the OutputStream. * @@ -95,7 +95,7 @@ public class PSGenerator { * @return the formatted value */ public String formatDouble(double value) { - return df1.format(value); + return df3.format(value); } /** @@ -327,20 +327,35 @@ public class PSGenerator { public void saveGraphicsState() throws IOException { writeln("gsave"); - PSState state = (PSState)this.currentState.clone(); + PSState state = new PSState(this.currentState, false); this.graphicsStateStack.push(this.currentState); this.currentState = state; } /** * Restores the last graphics state of the rendering engine. + * @return true if the state was restored, false if there's a stack underflow. * @exception IOException In case of an I/O problem */ - public void restoreGraphicsState() throws IOException { - writeln("grestore"); - this.currentState = (PSState)this.graphicsStateStack.pop(); + public boolean restoreGraphicsState() throws IOException { + if (this.graphicsStateStack.size() > 0) { + writeln("grestore"); + this.currentState = (PSState)this.graphicsStateStack.pop(); + return true; + } else { + return false; + } } + + /** + * Returns the current graphics state. + * @return the current graphics state + */ + public PSState getCurrentState() { + return this.currentState; + } + /** * Concats the transformation matrix. * @param a A part @@ -352,14 +367,11 @@ public class PSGenerator { * @exception IOException In case of an I/O problem */ public void concatMatrix(double a, double b, - double c, double d, - double e, double f) throws IOException { - writeln("[" + formatDouble5(a) + " " - + formatDouble5(b) + " " - + formatDouble5(c) + " " - + formatDouble5(d) + " " - + formatDouble5(e) + " " - + formatDouble5(f) + "] concat"); + double c, double d, + double e, double f) throws IOException { + AffineTransform at = new AffineTransform(a, b, c, d, e, f); + concatMatrix(at); + } /** @@ -381,7 +393,13 @@ public class PSGenerator { public void concatMatrix(AffineTransform at) throws IOException { double[] matrix = new double[6]; at.getMatrix(matrix); - concatMatrix(matrix); + getCurrentState().concatMatrix(at); + writeln("[" + formatDouble5(matrix[0]) + " " + + formatDouble5(matrix[1]) + " " + + formatDouble5(matrix[2]) + " " + + formatDouble5(matrix[3]) + " " + + formatDouble5(matrix[4]) + " " + + formatDouble5(matrix[5]) + "] concat"); } /** @@ -400,18 +418,76 @@ public class PSGenerator { + " " + formatDouble(h) + " re"); } + + /** + * Establishes the specified line cap style. + * @param linecap the line cap style (0, 1 or 2) as defined by the setlinecap command. + * @exception IOException In case of an I/O problem + */ + public void useLineCap(int linecap) throws IOException { + if (getCurrentState().useLineCap(linecap)) { + writeln(linecap + " setlinecap"); + } + } /** - * Returns the current graphics state. - * @return the current graphics state + * Establishes the specified line width. + * @param width the line width as defined by the setlinewidth command. + * @exception IOException In case of an I/O problem */ - public PSState getCurrentState() { - return this.currentState; + public void useLineWidth(double width) throws IOException { + if (getCurrentState().useLineWidth(width)) { + writeln(formatDouble(width) + " setlinewidth"); + } + } + + /** + * Establishes the specified dash pattern. + * @param pattern the dash pattern as defined by the setdash command. + * @exception IOException In case of an I/O problem + */ + public void useDash(String pattern) throws IOException { + if (pattern == null) { + pattern = PSState.DEFAULT_DASH; + } + if (getCurrentState().useDash(pattern)) { + writeln(pattern + " setdash"); + } + } + + /** + * Establishes the specified color (RGB). + * @param col the color as defined by the setrgbcolor command. + * @exception IOException In case of an I/O problem + */ + public void useRGBColor(Color col) throws IOException { + if (col == null) { + col = PSState.DEFAULT_RGB_COLOR; + } + if (getCurrentState().useColor(col)) { + float[] comps = col.getColorComponents(null); + writeln(formatDouble(comps[0]) + + " " + formatDouble(comps[1]) + + " " + formatDouble(comps[2]) + + " setrgbcolor"); + } } - + /** + * Establishes the specified font and size. + * @param name name of the font for the "F" command (see FOP Std Proc Set) + * @param size size of the font + * @exception IOException In case of an I/O problem + */ + public void useFont(String name, float size) throws IOException { + if (getCurrentState().useFont(name, size)) { + writeln(name + " " + formatDouble(size) + " F"); + } + } + /** Used for the ATEND constant. See there. */ private static interface AtendIndicator { } + } diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2D.java b/src/java/org/apache/fop/render/ps/PSGraphics2D.java index 7959ce43f..be0c50aa6 100644 --- a/src/java/org/apache/fop/render/ps/PSGraphics2D.java +++ b/src/java/org/apache/fop/render/ps/PSGraphics2D.java @@ -73,18 +73,20 @@ import org.apache.fop.image.FopImage; * implementing a <tt>Graphic2D</tt> piece-meal. * * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a> - * @version $Id: PSGraphics2D.java,v 1.11 2003/03/11 08:42:24 jeremias Exp $ + * @version $Id$ * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D */ public class PSGraphics2D extends AbstractGraphics2D { + private static final AffineTransform IDENTITY_TRANSFORM = new AffineTransform(); + /** the logger for this class */ protected Log log = LogFactory.getLog(PSTextPainter.class); /** the PostScript generator being created */ protected PSGenerator gen; - private boolean clippingDisabled = true; + private boolean clippingDisabled = false; /** Currently valid FontState */ protected Font font; @@ -279,8 +281,8 @@ public class PSGraphics2D extends AbstractGraphics2D { Shape imclip = getClip(); writeClip(imclip); gen.concatMatrix(at); - PSImageUtils.renderFopImage(fopimg, - 1000 * x, 1000 * y, 1000 * width, 1000 * height, gen); + PSImageUtils.renderBitmapImage(fopimg, + x, y, width, height, gen); gen.restoreGraphicsState(); } catch (IOException ioe) { handleIOException(ioe); @@ -396,12 +398,12 @@ public class PSGraphics2D extends AbstractGraphics2D { /** @see org.apache.fop.image.FopImage#getIntrinsicWidth() */ public int getIntrinsicWidth() { - return (int)(getWidth() * 72000 / getHorizontalResolution()); + return (int)(getWidth() * 72 / getHorizontalResolution()); } /** @see org.apache.fop.image.FopImage#getIntrinsicHeight() */ public int getIntrinsicHeight() { - return (int)(getHeight() * 72000 / getVerticalResolution()); + return (int)(getHeight() * 72 / getVerticalResolution()); } /** @see org.apache.fop.image.FopImage#getHorizontalResolution() */ @@ -503,29 +505,29 @@ public class PSGraphics2D extends AbstractGraphics2D { int type = iter.currentSegment(vals); switch (type) { case PathIterator.SEG_CUBICTO: - gen.writeln(gen.formatDouble(1000 * vals[0]) + " " - + gen.formatDouble(1000 * vals[1]) + " " - + gen.formatDouble(1000 * vals[2]) + " " - + gen.formatDouble(1000 * vals[3]) + " " - + gen.formatDouble(1000 * vals[4]) + " " - + gen.formatDouble(1000 * vals[5]) + 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]) + " curveto"); break; case PathIterator.SEG_LINETO: - gen.writeln(gen.formatDouble(1000 * vals[0]) + " " - + gen.formatDouble(1000 * vals[1]) + gen.writeln(gen.formatDouble(vals[0]) + " " + + gen.formatDouble(vals[1]) + " lineto"); break; case PathIterator.SEG_MOVETO: - gen.writeln(gen.formatDouble(1000 * vals[0]) + " " - + gen.formatDouble(1000 * vals[1]) + gen.writeln(gen.formatDouble(vals[0]) + " " + + gen.formatDouble(vals[1]) + " M"); break; case PathIterator.SEG_QUADTO: - gen.writeln(gen.formatDouble(1000 * vals[0]) + " " - + gen.formatDouble(1000 * vals[1]) + " " - + gen.formatDouble(1000 * vals[2]) + " " - + gen.formatDouble(1000 * vals[3]) + " QUADTO "); + gen.writeln(gen.formatDouble(vals[0]) + " " + + gen.formatDouble(vals[1]) + " " + + gen.formatDouble(vals[2]) + " " + + gen.formatDouble(vals[3]) + " QUADTO "); break; case PathIterator.SEG_CLOSE: gen.writeln("closepath"); @@ -557,15 +559,23 @@ public class PSGraphics2D extends AbstractGraphics2D { preparePainting(); try { gen.saveGraphicsState(); + + AffineTransform trans = getTransform(); + boolean newTransform = gen.getCurrentState().checkTransform(trans) + && !trans.isIdentity(); + Shape imclip = getClip(); writeClip(imclip); + if (newTransform) { + gen.concatMatrix(trans); + } establishColor(getColor()); applyPaint(getPaint(), false); applyStroke(getStroke()); gen.writeln("newpath"); - PathIterator iter = s.getPathIterator(getTransform()); + PathIterator iter = s.getPathIterator(IDENTITY_TRANSFORM); processPathIterator(iter); doDrawing(false, true, false); gen.restoreGraphicsState(); @@ -589,7 +599,7 @@ public class PSGraphics2D extends AbstractGraphics2D { PathIterator iter = s.getPathIterator(getTransform()); processPathIterator(iter); // clip area - gen.writeln("clippath"); + gen.writeln("clip"); } catch (IOException ioe) { handleIOException(ioe); } @@ -624,14 +634,14 @@ public class PSGraphics2D extends AbstractGraphics2D { if (da != null) { gen.write("["); for (int count = 0; count < da.length; count++) { - gen.write("" + (1000 * (int)da[count])); + gen.write("" + ((int)da[count])); if (count < da.length - 1) { gen.write(" "); } } gen.write("] "); float offset = bs.getDashPhase(); - gen.writeln((1000 * (int)offset) + " setdash"); + gen.writeln(((int)offset) + " setdash"); } int ec = bs.getEndCap(); switch (ec) { @@ -661,10 +671,10 @@ public class PSGraphics2D extends AbstractGraphics2D { default: log.warn("Unsupported line join: " + lj); } float lw = bs.getLineWidth(); - gen.writeln(gen.formatDouble(1000 * lw) + " setlinewidth"); + gen.writeln(gen.formatDouble(lw) + " setlinewidth"); float ml = bs.getMiterLimit(); - gen.writeln(gen.formatDouble(1000 * ml) + " setmiterlimit"); + gen.writeln(gen.formatDouble(ml) + " setmiterlimit"); } } catch (IOException ioe) { handleIOException(ioe); @@ -857,9 +867,9 @@ public class PSGraphics2D extends AbstractGraphics2D { //Prepare correct transformation AffineTransform trans = getTransform(); - gen.writeln("[" + toArray(trans) + "] concat"); - gen.writeln(gen.formatDouble(1000 * x) + " " - + gen.formatDouble(1000 * y) + " moveto "); + gen.concatMatrix(trans); + gen.writeln(gen.formatDouble(x) + " " + + gen.formatDouble(y) + " moveto "); gen.writeln("1 -1 scale"); StringBuffer sb = new StringBuffer("("); @@ -874,22 +884,6 @@ public class PSGraphics2D extends AbstractGraphics2D { } } - /** - * Converts an AffineTransform to a value array. - * @param at AffineTransform to convert - * @return a String (array of six space-separated values) - */ - protected String toArray(AffineTransform at) { - final double[] vals = new double[6]; - at.getMatrix(vals); - return gen.formatDouble5(vals[0]) + " " - + gen.formatDouble5(vals[1]) + " " - + gen.formatDouble5(vals[2]) + " " - + gen.formatDouble5(vals[3]) + " " - + gen.formatDouble(1000 * vals[4]) + " " - + gen.formatDouble(1000 * vals[5]); - } - private void escapeText(final String text, StringBuffer target) { final int l = text.length(); for (int i = 0; i < l; i++) { diff --git a/src/java/org/apache/fop/render/ps/PSImageUtils.java b/src/java/org/apache/fop/render/ps/PSImageUtils.java index 7edc340ad..ebc67a4df 100644 --- a/src/java/org/apache/fop/render/ps/PSImageUtils.java +++ b/src/java/org/apache/fop/render/ps/PSImageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2004 The Apache Software Foundation. + * Copyright 2004-2005 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. @@ -22,20 +22,29 @@ import java.awt.color.ColorSpace; import java.io.IOException; import java.io.OutputStream; +import org.apache.commons.io.output.CountingOutputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.fop.image.EPSImage; import org.apache.fop.image.FopImage; import org.apache.fop.image.JpegImage; +import org.apache.fop.image.XMLImage; import org.apache.fop.util.ASCII85OutputStream; import org.apache.fop.util.Finalizable; import org.apache.fop.util.FlateEncodeOutputStream; import org.apache.fop.util.RunLengthEncodeOutputStream; +import org.w3c.dom.Document; /** * Utility code for rendering images in PostScript. */ public class PSImageUtils { + /** logging instance */ + protected static Log log = LogFactory.getLog(PSImageUtils.class); + /** - * Renders an image to PostScript. + * Renders a bitmap image to PostScript. * @param img image to render * @param x x position * @param y y position @@ -44,12 +53,26 @@ public class PSImageUtils { * @param gen PS generator * @throws IOException In case of an I/O problem while rendering the image */ - public static void renderFopImage(FopImage img, int x, int y, int w, int h, PSGenerator gen) throws IOException { + public static void renderBitmapImage(FopImage img, + float x, float y, float w, float h, PSGenerator gen) + throws IOException { + if (img instanceof JpegImage) { + if (!img.load(FopImage.ORIGINAL_DATA)) { + gen.commentln("%JPEG image could not be processed: " + img); + return; + } + } else { + if (!img.load(FopImage.BITMAP)) { + gen.commentln("%Bitmap image could not be processed: " + img); + return; + } + } boolean iscolor = img.getColorSpace().getType() != ColorSpace.CS_GRAY; byte[] imgmap = img.getBitmaps(); gen.saveGraphicsState(); + gen.commentln("%FOPBeginBitmap: " + img.getMimeType()); if (img.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { gen.writeln("/DeviceCMYK setcolorspace"); } else if (img.getColorSpace().getType() == ColorSpace.CS_GRAY) { @@ -108,22 +131,6 @@ public class PSImageUtils { gen.writeln(" RawData flushfile"); gen.writeln("} exec"); - /* - * for (int y=0; y<img.getHeight(); y++) { - * int indx = y * img.getWidth(); - * if (iscolor) indx*= 3; - * for (int x=0; x<img.getWidth(); x++) { - * if (iscolor) { - * writeASCIIHex(imgmap[indx++] & 0xFF); - * writeASCIIHex(imgmap[indx++] & 0xFF); - * writeASCIIHex(imgmap[indx++] & 0xFF); - * } else { - * writeASCIIHex(imgmap[indx++] & 0xFF); - * } - * } - * } - */ - OutputStream out = gen.getOutputStream(); out = new ASCII85OutputStream(out); if (img instanceof JpegImage) { @@ -143,8 +150,70 @@ public class PSImageUtils { } gen.writeln(""); + gen.commentln("%FOPEndBitmap"); gen.restoreGraphicsState(); } + public static void renderEPS(EPSImage img, + float x, float y, float w, float h, + PSGenerator gen) { + try { + if (!img.load(FopImage.ORIGINAL_DATA)) { + gen.commentln("%EPS image could not be processed: " + img); + return; + } + int[] bbox = img.getBBox(); + int bboxw = bbox[2] - bbox[0]; + int bboxh = bbox[3] - bbox[1]; + renderEPS(img.getEPSImage(), img.getDocName(), + x, y, w, h, + bbox[0], bbox[1], bboxw, bboxh, gen); + + } catch (Exception e) { + log.error("PSRenderer.renderImageArea(): Error rendering bitmap (" + + e.getMessage() + ")", e); + } + } + + /** + * Places an EPS file in the PostScript stream. + * @param rawEPS byte array containing the raw EPS data + * @param name name for the EPS document + * @param x x-coordinate of viewport in millipoints + * @param y y-coordinate of viewport in millipoints + * @param w width of viewport in millipoints + * @param h height of viewport in millipoints + * @param bboxx x-coordinate of EPS bounding box in points + * @param bboxy y-coordinate of EPS bounding box in points + * @param bboxw width of EPS bounding box in points + * @param bboxh height of EPS bounding box in points + * @throws IOException in case an I/O error happens during output + */ + public static void renderEPS(byte[] rawEPS, String name, + float x, float y, float w, float h, + int bboxx, int bboxy, int bboxw, int bboxh, + PSGenerator gen) throws IOException { + gen.writeln("BeginEPSF"); + gen.writeln("%%BeginDocument: " + name); + + gen.writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " translate"); + gen.writeln("0 " + gen.formatDouble(h) + " translate"); + gen.writeln("1 -1 scale"); + float sx = w / bboxw; + float sy = h / bboxh; + if (sx != 1 || sy != 1) { + gen.writeln(gen.formatDouble(sx) + " " + gen.formatDouble(sy) + " scale"); + } + if (bboxx != 0 || bboxy != 0) { + gen.writeln(gen.formatDouble(-bboxx) + " " + gen.formatDouble(-bboxy) + " translate"); + } + gen.writeln(gen.formatDouble(bboxy) + " " + gen.formatDouble(bboxy) + + " " + gen.formatDouble(bboxw) + " " + gen.formatDouble(bboxh) + " re clip"); + gen.writeln("newpath"); + gen.writeByteArr(rawEPS); + gen.writeln("%%EndDocument"); + gen.writeln("EndEPSF"); + gen.writeln(""); + } } diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 1a360990c..7413f7717 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -19,34 +19,38 @@ package org.apache.fop.render.ps; // Java +import java.awt.Color; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.OutputStream; +import java.util.Iterator; import java.util.List; // FOP import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; -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.Area; import org.apache.fop.area.BlockViewport; import org.apache.fop.area.CTM; import org.apache.fop.area.PageViewport; +import org.apache.fop.area.RegionViewport; import org.apache.fop.area.Trait; import org.apache.fop.area.inline.ForeignObject; +import org.apache.fop.area.inline.Image; +import org.apache.fop.area.inline.InlineParent; import org.apache.fop.area.inline.TextArea; import org.apache.fop.datatypes.ColorType; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.fo.Constants; import org.apache.fop.fonts.FontSetup; import org.apache.fop.fonts.Typeface; -import org.apache.fop.render.PrintRenderer; -import org.apache.fop.render.RendererContext; - +import org.apache.fop.image.EPSImage; import org.apache.fop.image.FopImage; import org.apache.fop.image.ImageFactory; -import org.apache.fop.traits.BorderProps; +import org.apache.fop.image.XMLImage; +import org.apache.fop.render.AbstractPathOrientedRenderer; +import org.apache.fop.render.RendererContext; import org.w3c.dom.Document; @@ -62,14 +66,14 @@ import org.w3c.dom.Document; * sure to also follow the DSC to make it simpler to programmatically modify * the generated Postscript files (ex. extract pages etc.). * <br> - * The PS renderer operates in millipoints as the layout engine. Since PostScript - * initially uses points, scaling is applied as needed. + * This renderer inserts FOP-specific comments into the PostScript stream which + * may help certain users to do certain types of post-processing of the output. + * These comments all start with "%FOP". * * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> - * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> - * @version $Id: PSRenderer.java,v 1.31 2003/03/11 08:42:24 jeremias Exp $ + * @version $Id$ */ -public class PSRenderer extends PrintRenderer { +public class PSRenderer extends AbstractPathOrientedRenderer { /** The MIME type for PostScript */ public static final String MIME_TYPE = "application/postscript"; @@ -84,11 +88,7 @@ public class PSRenderer extends PrintRenderer { protected PSGenerator gen; private boolean ioTrouble = false; - private String currentFontName; - private int currentFontSize; - private float currRed; - private float currGreen; - private float currBlue; + private boolean inTextMode = false; /** * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) @@ -144,7 +144,11 @@ public class PSRenderer extends PrintRenderer { */ protected void comment(String comment) { if (this.enableComments) { - writeln(comment); + if (comment.startsWith("%")) { + writeln(comment); + } else { + writeln("%" + comment); + } } } @@ -155,17 +159,129 @@ public class PSRenderer extends PrintRenderer { moveTo(this.currentIPPosition, this.currentBPPosition); } + /** @see org.apache.fop.render.AbstractPathOrientedRenderer#clip() */ + protected void clip() { + writeln("clip newpath"); + //writeln("newpath"); + } + /** - * Moves the cursor. - * @param x X coordinate - * @param y Y coordinate + * Clip an area. + * Write a clipping operation given coordinates in the current + * transform. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the area + * @param height the height of the area */ - protected void moveTo(int x, int y) { - writeln(x + " " + y + " M"); + protected void clipRect(float x, float y, float width, float height) { + try { + gen.defineRect(x, y, width, height); + gen.writeln("clip"); + //comment("clip here"); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } } + /** @see org.apache.fop.render.AbstractPathOrientedRenderer#moveTo(float, float) */ + protected void moveTo(float x, float y) { + writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " M"); + } + + /** @see org.apache.fop.render.AbstractPathOrientedRenderer#lineTo(float, float) */ + protected void lineTo(float x, float y) { + writeln(gen.formatDouble(x) + " " + gen.formatDouble(y) + " lineto"); + } + + /** @see org.apache.fop.render.AbstractPathOrientedRenderer#closePath() */ + protected void closePath() { + writeln("cp"); + } + + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void fillRect(float x, float y, float width, float height) { + try { + gen.defineRect(x, y, width, height); + gen.writeln("fill"); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void updateColor(ColorType col, boolean fill) { + try { + useColor(col); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void drawImage(String url, Rectangle2D pos) { + endTextObject(); + url = ImageFactory.getURL(url); + ImageFactory fact = ImageFactory.getInstance(); + FopImage fopimage = fact.getImage(url, userAgent); + if (fopimage == null) { + return; + } + if (!fopimage.load(FopImage.DIMENSIONS)) { + return; + } + float x = (float)pos.getX() / 1000f; + x += currentIPPosition / 1000f; + float y = (float)pos.getY() / 1000f; + y += currentBPPosition / 1000f; + float w = (float)pos.getWidth() / 1000f; + float h = (float)pos.getHeight() / 1000f; + try { + String mime = fopimage.getMimeType(); + if ("text/xml".equals(mime)) { + if (!fopimage.load(FopImage.ORIGINAL_DATA)) { + return; + } + Document doc = ((XMLImage) fopimage).getDocument(); + String ns = ((XMLImage) fopimage).getNameSpace(); + + renderDocument(doc, ns, pos); + } else if ("image/svg+xml".equals(mime)) { + if (!fopimage.load(FopImage.ORIGINAL_DATA)) { + return; + } + Document doc = ((XMLImage) fopimage).getDocument(); + String ns = ((XMLImage) fopimage).getNameSpace(); + + renderDocument(doc, ns, pos); + } else if (fopimage instanceof EPSImage) { + PSImageUtils.renderEPS((EPSImage)fopimage, x, y, w, h, gen); + } else { + PSImageUtils.renderBitmapImage(fopimage, x, y, w, h, gen); + } + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + /** + * 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(gen.formatDouble(startx) + " " + + gen.formatDouble(starty) + " M " + + gen.formatDouble(endx) + " " + + gen.formatDouble(endy) + " lineto stroke newpath"); + } + /** Saves the graphics state of the rendering engine. */ public void saveGraphicsState() { + endTextObject(); try { //delegate gen.saveGraphicsState(); @@ -176,6 +292,7 @@ public class PSRenderer extends PrintRenderer { /** Restores the last graphics state of the rendering engine. */ public void restoreGraphicsState() { + endTextObject(); try { //delegate gen.restoreGraphicsState(); @@ -186,12 +303,18 @@ public class PSRenderer extends PrintRenderer { /** Indicates the beginning of a text object. */ protected void beginTextObject() { - writeln("BT"); + if (!inTextMode) { + writeln("BT"); + inTextMode = true; + } } /** Indicates the end of a text object. */ protected void endTextObject() { - writeln("ET"); + if (inTextMode) { + writeln("ET"); + inTextMode = false; + } } /** @@ -226,80 +349,193 @@ public class PSRenderer extends PrintRenderer { } /** - * Draws a filled rectangle. - * @param x x-coordinate - * @param y y-coordinate - * @param w width - * @param h height - * @param col color to fill with - */ - protected void fillRect(float x, float y, float w, float h, - ColorType col) { - useColor(col); - writeln(gen.formatDouble(x) - + " " + gen.formatDouble(y) - + " " + gen.formatDouble(w) - + " " + gen.formatDouble(h) - + " rectfill"); - } - - /** - * Draws a stroked rectangle with the current stroke settings. - * @param x x-coordinate - * @param y y-coordinate - * @param w width - * @param h height - */ - protected void drawRect(float x, float y, float w, float h) { - writeln(gen.formatDouble(x) - + " " + gen.formatDouble(y) - + " " + gen.formatDouble(w) - + " " + gen.formatDouble(h) - + " rectstroke"); - } - - /** - * Clip an area. - * Write a clipping operation given coordinates in the current - * transform. - * @param x the x coordinate - * @param y the y coordinate - * @param width the width of the area - * @param height the height of the area - */ - protected void clip(float x, float y, float width, float height) { - writeln(x + " " + y + " " + width + " " + height + " rectclip"); - } - - /** * Changes the currently used font. * @param name name of the font * @param size font size */ public void useFont(String name, int size) { - if ((currentFontName != name) || (currentFontSize != size)) { - writeln(name + " " + size + " F"); - currentFontName = name; - currentFontSize = size; + try { + gen.useFont(name, size / 1000f); + } catch (IOException ioe) { + handleIOTrouble(ioe); } } - private void useColor(ColorType col) { - useColor(col.getRed(), col.getGreen(), col.getBlue()); + private void useColor(ColorType col) throws IOException { + gen.useRGBColor(toColor(col)); } - private void useColor(float red, float green, float blue) { - if ((red != currRed) || (green != currGreen) || (blue != currBlue)) { - writeln(gen.formatDouble(red) - + " " + gen.formatDouble(green) - + " " + gen.formatDouble(blue) - + " setrgbcolor"); - currRed = red; - currGreen = green; - currBlue = blue; + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void drawBackAndBorders(Area area, float startx, float starty, + float width, float height) { + if (area.hasTrait(Trait.BACKGROUND) + || area.hasTrait(Trait.BORDER_BEFORE) + || area.hasTrait(Trait.BORDER_AFTER) + || area.hasTrait(Trait.BORDER_START) + || area.hasTrait(Trait.BORDER_END)) { + comment("%FOPBeginBackgroundAndBorder: " + + startx + " " + starty + " " + width + " " + height); + super.drawBackAndBorders(area, startx, starty, width, height); + comment("%FOPEndBackgroundAndBorder"); } } - + + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void drawBorderLine(float x1, float y1, float x2, float y2, + boolean horz, boolean startOrBefore, int style, ColorType col) { + try { + float w = x2 - x1; + float h = y2 - y1; + if ((w < 0) || (h < 0)) { + log.error("Negative extent received. Border won't be painted."); + return; + } + switch (style) { + case Constants.EN_DASHED: + useColor(col); + if (horz) { + float unit = Math.abs(2 * h); + int rep = (int)(w / unit); + if (rep % 2 == 0) { + rep++; + } + unit = w / rep; + gen.useDash("[" + unit + "] 0"); + gen.useLineCap(0); + gen.useLineWidth(h); + float ym = y1 + (h / 2); + drawLine(x1, ym, x2, ym); + } else { + float unit = Math.abs(2 * w); + int rep = (int)(h / unit); + if (rep % 2 == 0) { + rep++; + } + unit = h / rep; + gen.useDash("[" + unit + "] 0"); + gen.useLineCap(0); + gen.useLineWidth(w); + float xm = x1 + (w / 2); + drawLine(xm, y1, xm, y2); + } + break; + case Constants.EN_DOTTED: + useColor(col); + gen.useLineCap(1); //Rounded! + if (horz) { + float unit = Math.abs(2 * h); + int rep = (int)(w / unit); + if (rep % 2 == 0) { + rep++; + } + unit = w / rep; + gen.useDash("[0 " + unit + "] 0"); + gen.useLineWidth(h); + float ym = y1 + (h / 2); + drawLine(x1, ym, x2, ym); + } else { + float unit = Math.abs(2 * w); + int rep = (int)(h / unit); + if (rep % 2 == 0) { + rep++; + } + unit = h / rep; + gen.useDash("[0 " + unit + "] 0"); + gen.useLineWidth(w); + float xm = x1 + (w / 2); + drawLine(xm, y1, xm, y2); + } + break; + case Constants.EN_DOUBLE: + useColor(col); + gen.useDash(null); + if (horz) { + float h3 = h / 3; + gen.useLineWidth(h3); + float ym1 = y1 + (h3 / 2); + float ym2 = ym1 + h3 + h3; + drawLine(x1, ym1, x2, ym1); + drawLine(x1, ym2, x2, ym2); + } else { + float w3 = w / 3; + gen.useLineWidth(w3); + float xm1 = x1 + (w3 / 2); + float xm2 = xm1 + w3 + w3; + drawLine(xm1, y1, xm1, y2); + drawLine(xm2, y1, xm2, y2); + } + break; + case Constants.EN_GROOVE: + case Constants.EN_RIDGE: + float colFactor = (style == EN_GROOVE ? 0.4f : -0.4f); + gen.useDash(null); + Color c = toColor(col); + if (horz) { + Color uppercol = lightenColor(c, -colFactor); + Color lowercol = lightenColor(c, colFactor); + float h3 = h / 3; + gen.useLineWidth(h3); + float ym1 = y1 + (h3 / 2); + gen.useRGBColor(uppercol); + drawLine(x1, ym1, x2, ym1); + gen.useRGBColor(c); + drawLine(x1, ym1 + h3, x2, ym1 + h3); + gen.useRGBColor(lowercol); + drawLine(x1, ym1 + h3 + h3, x2, ym1 + h3 + h3); + } else { + Color leftcol = lightenColor(c, -colFactor); + Color rightcol = lightenColor(c, colFactor); + float w3 = w / 3; + gen.useLineWidth(w3); + float xm1 = x1 + (w3 / 2); + gen.useRGBColor(leftcol); + drawLine(xm1, y1, xm1, y2); + gen.useRGBColor(c); + drawLine(xm1 + w3, y1, xm1 + w3, y2); + gen.useRGBColor(rightcol); + drawLine(xm1 + w3 + w3, y1, xm1 + w3 + w3, y2); + } + break; + case Constants.EN_INSET: + case Constants.EN_OUTSET: + colFactor = (style == EN_OUTSET ? 0.4f : -0.4f); + gen.useDash(null); + c = toColor(col); + if (horz) { + c = lightenColor(c, (startOrBefore ? 1 : -1) * colFactor); + gen.useLineWidth(h); + float ym1 = y1 + (h / 2); + gen.useRGBColor(c); + drawLine(x1, ym1, x2, ym1); + } else { + c = lightenColor(c, (startOrBefore ? 1 : -1) * colFactor); + gen.useLineWidth(w); + float xm1 = x1 + (w / 2); + gen.useRGBColor(c); + drawLine(xm1, y1, xm1, y2); + } + break; + case Constants.EN_HIDDEN: + break; + default: + useColor(col); + gen.useDash(null); + gen.useLineCap(0); + if (horz) { + gen.useLineWidth(h); + float ym = y1 + (h / 2); + drawLine(x1, ym, x2, ym); + } else { + gen.useLineWidth(w); + float xm = x1 + (w / 2); + drawLine(xm, y1, xm, y2); + } + } + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + /** * @see org.apache.fop.render.Renderer#startRenderer(OutputStream) */ @@ -402,8 +638,8 @@ public class PSRenderer extends PrintRenderer { + Math.round(pspageheight) + "]"); gen.writeln("/ImagingBBox null"); gen.writeln(">> setpagedevice"); - gen.writeln("0.001 0.001 scale"); - concatMatrix(1, 0, 0, -1, 0, pageheight); + //gen.writeln("0.001 0.001 scale"); + concatMatrix(1, 0, 0, -1, 0, pageheight / 1000f); gen.writeDSCComment(DSCConstants.END_PAGE_SETUP); @@ -415,6 +651,15 @@ public class PSRenderer extends PrintRenderer { gen.writeDSCComment(DSCConstants.END_PAGE); } + /** @see org.apache.fop.render.AbstractRenderer */ + protected void renderRegionViewport(RegionViewport port) { + if (port != null) { + comment("%FOPBeginRegionViewport: " + port.getRegionReference().getRegionName()); + super.renderRegionViewport(port); + comment("%FOPEndRegionViewport"); + } + } + /** * Paints text. * @param rx X coordinate @@ -424,7 +669,9 @@ public class PSRenderer extends PrintRenderer { */ protected void paintText(int rx, int bl, String text, Typeface font) { saveGraphicsState(); - writeln("1 0 0 -1 " + rx + " " + bl + " Tm"); + beginTextObject(); + writeln("1 0 0 -1 " + gen.formatDouble(rx / 1000f) + + " " + gen.formatDouble(bl / 1000f) + " Tm"); int initialSize = text.length(); initialSize += initialSize / 2; @@ -457,7 +704,11 @@ public class PSRenderer extends PrintRenderer { useFont(fontname, fontsize); ColorType ct = (ColorType)area.getTrait(Trait.COLOR); if (ct != null) { - useColor(ct); + try { + useColor(ct); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } } paintText(rx, bl, area.getTextArea(), f); @@ -495,130 +746,58 @@ public class PSRenderer extends PrintRenderer { super.renderText(area); //Updates IPD } - - /** - * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List) - */ - protected void renderBlockViewport(BlockViewport bv, List children) { - // clip and position viewport if necessary - - // save positions - int saveIP = currentIPPosition; - int saveBP = currentBPPosition; - String saveFontName = currentFontName; - - CTM ctm = bv.getCTM(); - - if (bv.getPositioning() == Block.ABSOLUTE) { - - currentIPPosition = 0; - currentBPPosition = 0; - - //closeText(); - endTextObject(); - - if (bv.getClip()) { - saveGraphicsState(); - int x = bv.getXOffset() + containingIPPosition; - int y = bv.getYOffset() + containingBPPosition; - int width = bv.getIPD(); - int height = bv.getBPD(); - clip(x, y, width, height); - } - - CTM tempctm = new CTM(containingIPPosition, containingBPPosition); - ctm = tempctm.multiply(ctm); - - startVParea(ctm); - handleBlockTraits(bv); - renderBlocks(bv, children); - endVParea(); - - if (bv.getClip()) { - restoreGraphicsState(); - } - beginTextObject(); - - // clip if necessary - - currentIPPosition = saveIP; - currentBPPosition = saveBP; - } else { - - if (ctm != null) { - currentIPPosition = 0; - currentBPPosition = 0; - - //closeText(); - endTextObject(); - - double[] vals = ctm.toArray(); - //boolean aclock = vals[2] == 1.0; - if (vals[2] == 1.0) { - ctm = ctm.translate(-saveBP - bv.getBPD(), -saveIP); - } else if (vals[0] == -1.0) { - ctm = ctm.translate(-saveIP - bv.getIPD(), -saveBP - bv.getBPD()); - } else { - ctm = ctm.translate(saveBP, saveIP - bv.getIPD()); - } - } - - // clip if necessary - if (bv.getClip()) { - if (ctm == null) { - //closeText(); - endTextObject(); + /** @see org.apache.fop.render.AbstractPathOrientedRenderer#breakOutOfStateStack() */ + protected List breakOutOfStateStack() { + try { + List breakOutList = new java.util.ArrayList(); + PSState state; + while (true) { + if (breakOutList.size() == 0) { + comment("------ break out!"); } - saveGraphicsState(); - int x = bv.getXOffset(); - int y = bv.getYOffset(); - int width = bv.getIPD(); - int height = bv.getBPD(); - clip(x, y, width, height); - } - - if (ctm != null) { - startVParea(ctm); - } - handleBlockTraits(bv); - renderBlocks(bv, children); - if (ctm != null) { - endVParea(); - } - - if (bv.getClip()) { - restoreGraphicsState(); - if (ctm == null) { - beginTextObject(); + state = gen.getCurrentState(); + if (!gen.restoreGraphicsState()) { + break; } + breakOutList.add(0, state); //Insert because of stack-popping } - if (ctm != null) { - beginTextObject(); + return breakOutList; + } catch (IOException ioe) { + handleIOTrouble(ioe); + return null; + } + } + + /** @see org.apache.fop.render.AbstractPathOrientedRenderer */ + protected void restoreStateStackAfterBreakOut(List breakOutList) { + try { + comment("------ restoring context after break-out..."); + PSState state; + Iterator i = breakOutList.iterator(); + while (i.hasNext()) { + state = (PSState)i.next(); + saveGraphicsState(); + state.reestablish(gen); } - - currentIPPosition = saveIP; - currentBPPosition = saveBP; - currentBPPosition += (int)(bv.getAllocBPD()); + comment("------ done."); + } catch (IOException ioe) { + handleIOTrouble(ioe); } - currentFontName = saveFontName; } - + /** * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM) */ protected void startVParea(CTM ctm) { - // Set the given CTM in the graphics state - //currentState.push(); - //currentState.setTransform(new AffineTransform(CTMHelper.toPDFArray(ctm))); saveGraphicsState(); // multiply with current CTM - //writeln(CTMHelper.toPDFString(ctm) + " cm\n"); final double[] matrix = ctm.toArray(); + matrix[4] /= 1000f; + matrix[5] /= 1000f; concatMatrix(matrix); // Set clip? - beginTextObject(); } /** @@ -627,182 +806,34 @@ public class PSRenderer extends PrintRenderer { protected void endVParea() { endTextObject(); restoreGraphicsState(); - //currentState.pop(); } - /** - * Handle the traits for a region - * This is used to draw the traits for the given page region. - * (See Sect. 6.4.1.2 of XSL-FO spec.) - * @param region the RegionViewport whose region is to be drawn - */ - protected void handleRegionTraits(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); + /** @see org.apache.fop.render.AbstractRenderer */ + protected void renderBlockViewport(BlockViewport bv, List children) { + comment("%FOPBeginBlockViewport: " + bv.toString()); + super.renderBlockViewport(bv, children); + comment("%FOPEndBlockViewport"); } + + /** @see org.apache.fop.render.AbstractRenderer */ + protected void renderInlineParent(InlineParent ip) { + float start = currentIPPosition / 1000f; + float top = (ip.getOffset() + currentBPPosition) / 1000f; + float width = ip.getIPD() / 1000f; + float height = ip.getBPD() / 1000f; + drawBackAndBorders(ip, start, top, 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.getIPD(), block.getBPD()); + super.renderInlineParent(ip); } - + /** - * 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 + * @see org.apache.fop.render.AbstractRenderer#renderImage(Image, Rectangle2D) */ - 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) { - fillRect(startx, starty, width, height, back.getColor()); - } - if (back.getURL() != null) { - ImageFactory fact = ImageFactory.getInstance(); - FopImage fopimage = fact.getImage(back.getURL(), userAgent); - if (fopimage != null && fopimage.load(FopImage.DIMENSIONS)) { - if (back.getRepeat() == EN_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; - useColor(bps.color); - 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; - useColor(bps.color); - 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; - useColor(bps.color); - 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; - useColor(bps.color); - 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 = ""; - } + public void renderImage(Image image, Rectangle2D pos) { + drawImage(image.getURL(), pos); } /** - * 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"); - } - - /** * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) */ public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { diff --git a/src/java/org/apache/fop/render/ps/PSState.java b/src/java/org/apache/fop/render/ps/PSState.java index e39697c69..7421c5f28 100644 --- a/src/java/org/apache/fop/render/ps/PSState.java +++ b/src/java/org/apache/fop/render/ps/PSState.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2004 The Apache Software Foundation. + * Copyright 1999-2005 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. @@ -18,21 +18,61 @@ package org.apache.fop.render.ps; +import java.io.IOException; import java.io.Serializable; +import java.util.List; +import java.awt.Color; import java.awt.geom.AffineTransform; /** * This class holds the current state of the PostScript interpreter. * * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> - * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a> - * @version $Id: PSState.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $ + * @version $Id$ */ -public class PSState implements Serializable, Cloneable { +public class PSState implements Serializable { + /** Default for setdash */ + public static final String DEFAULT_DASH = "[] 0"; + /** Default color in PostScript */ + public static final Color DEFAULT_RGB_COLOR = Color.black; + private AffineTransform transform = new AffineTransform(); + private List transformConcatList = new java.util.ArrayList(); - + private int linecap = 0; + private double linewidth = 1.0f; + private String dashpattern = DEFAULT_DASH; + private Color rgbColor = DEFAULT_RGB_COLOR; + + //Font state + private String fontname; + private float fontsize; + + /** + * Default constructor + */ + public PSState() { + //nop + } + + /** + * Copy constructor + * @param org the original to copy from + * @param copyTransforms true if the list of matrix concats should be cloned, too + */ + public PSState(PSState org, boolean copyTransforms) { + this.transform = (AffineTransform)org.transform.clone(); + if (copyTransforms) { + this.transformConcatList.addAll(org.transformConcatList); + } + this.linecap = org.linecap; + this.linewidth = org.linewidth; + this.dashpattern = org.dashpattern; + this.rgbColor = org.rgbColor; + this.fontname = org.fontname; + this.fontsize = org.fontsize; + } /** * Returns the transform. @@ -43,22 +83,118 @@ public class PSState implements Serializable, Cloneable { } /** + * Check the current transform. + * The transform for the current state is the combination of all + * transforms in the current state. The parameter is compared + * against this current transform. + * + * @param tf the transform the check against + * @return true if the new transform is different then the current transform + */ + public boolean checkTransform(AffineTransform tf) { + return !tf.equals(this.transform); + } + + /** * Concats the given transformation matrix with the current one. * @param transform The new transformation matrix */ public void concatMatrix(AffineTransform transform) { + this.transformConcatList.add(transform); this.transform.concatenate(transform); } /** - * @see java.lang.Object#clone() + * Establishes the specified line cap. + * @param value line cap (0, 1 or 2) as defined by the setlinecap command + * @return true if the line cap changed compared to the previous setting */ - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - // this shouldn't happen, since we are Cloneable - throw new InternalError(); + public boolean useLineCap(int value) { + if (linecap != value) { + linecap = value; + return true; + } else { + return false; + } + } + + /** + * Establishes the specified line width. + * @param value line width as defined by the setlinewidth command + * @return true if the line width changed compared to the previous setting + */ + public boolean useLineWidth(double value) { + if (linewidth != value) { + linewidth = value; + return true; + } else { + return false; + } + } + + /** + * Establishes the specified dash. + * @param pattern dash pattern as defined by the setdash command + * @return true if the dash pattern changed compared to the previous setting + */ + public boolean useDash(String pattern) { + if (!dashpattern.equals(pattern)) { + dashpattern = pattern; + return true; + } else { + return false; + } + } + + /** + * Establishes the specified color (RGB). + * @param value color as defined by the setrgbcolor command + * @return true if the color changed compared to the previous setting + */ + public boolean useColor(Color value) { + if (!rgbColor.equals(value)) { + rgbColor = value; + return true; + } else { + return false; + } + } + + /** + * Establishes the specified font and size. + * @param name name of the font for the "F" command (see FOP Std Proc Set) + * @param size size of the font + * @return true if the font changed compared to the previous setting + */ + public boolean useFont(String name, float size) { + if (name == null) { + throw new NullPointerException("font name must not be null"); + } + if (fontname == null || !fontname.equals(name) || fontsize != size) { + fontname = name; + fontsize = size; + return true; + } else { + return false; + } + } + + /** + * Reestablishes the graphics state represented by this instance by issueing the + * necessary commands. + * @param gen The generator to use for output + * @exception IOException In case of an I/O problem + */ + public void reestablish(PSGenerator gen) throws IOException { + for (int i = 0, len = transformConcatList.size(); i < len; i++) { + gen.concatMatrix((AffineTransform)transformConcatList.get(i)); + } + gen.useLineCap(linecap); + gen.useLineWidth(linewidth); + gen.useDash(dashpattern); + gen.useRGBColor(rgbColor); + if (fontname != null) { + gen.useFont(fontname, fontsize); } } diff --git a/src/java/org/apache/fop/render/ps/PSXMLHandler.java b/src/java/org/apache/fop/render/ps/PSXMLHandler.java index d73267d74..8c1fa1b3e 100644 --- a/src/java/org/apache/fop/render/ps/PSXMLHandler.java +++ b/src/java/org/apache/fop/render/ps/PSXMLHandler.java @@ -46,13 +46,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * PostScript XML handler. + * PostScript XML handler for SVG. Uses Apache Batik for SVG processing. * This handler handles XML for foreign objects when rendering to PostScript. * It renders SVG to the PostScript document using the PSGraphics2D. * The properties from the PostScript renderer are subject to change. * * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> - * @version $Id: PSXMLHandler.java,v 1.4 2003/03/11 08:42:24 jeremias Exp $ + * @version $Id$ */ public class PSXMLHandler implements XMLHandler { @@ -297,7 +297,7 @@ public class PSXMLHandler implements XMLHandler { builder = null; try { - gen.writeln("%SVG graphic start ---"); + gen.commentln("%FOPBeginSVG"); gen.saveGraphicsState(); /* * Clip to the svg area. @@ -305,18 +305,19 @@ public class PSXMLHandler implements XMLHandler { * an fo:block-container */ gen.writeln("newpath"); - gen.defineRect(xOffset, yOffset, w, h); + gen.defineRect(xOffset / 1000f, yOffset / 1000f, + psInfo.getWidth() / 1000f, psInfo.getWidth() / 1000f); gen.writeln("clip"); // 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. - gen.concatMatrix(sx, 0, 0, sy, xOffset, yOffset); + gen.concatMatrix(sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f); SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, - w / 1000f, h / 1000f); - if (!at.isIdentity()) { + psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f); + if (false && !at.isIdentity()) { double[] vals = new double[6]; at.getMatrix(vals); gen.concatMatrix(vals); @@ -345,7 +346,7 @@ public class PSXMLHandler implements XMLHandler { psInfo.psGenerator.restoreGraphicsState(); //psInfo.pdfState.pop(); - gen.writeln("%SVG graphic end ---"); + gen.commentln("%FOPEndSVG"); } catch (IOException ioe) { log.error("SVG graphic could not be rendered: " + ioe.getMessage(), ioe); |