From ef1fd8f1519e90cc86a8d74a38f59d45e153948e Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Wed, 26 Oct 2005 21:07:47 +0000 Subject: [PATCH] Bugzilla #37236: Fix for gradients and patterns for SVG to PDF transcoding. Improvement for break-out handling in PDF Renderer. Submitted by: Thomas Deweese git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@328731 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/pdf/PDFFactory.java | 4 +- src/java/org/apache/fop/pdf/PDFState.java | 44 ++--- .../apache/fop/render/pdf/PDFRenderer.java | 19 +- .../apache/fop/render/ps/PSGraphics2D.java | 9 + .../apache/fop/svg/PDFDocumentGraphics2D.java | 13 +- .../org/apache/fop/svg/PDFGraphics2D.java | 176 ++++++++++++------ 6 files changed, 163 insertions(+), 102 deletions(-) diff --git a/src/java/org/apache/fop/pdf/PDFFactory.java b/src/java/org/apache/fop/pdf/PDFFactory.java index bacb3251c..5ef2a72a1 100644 --- a/src/java/org/apache/fop/pdf/PDFFactory.java +++ b/src/java/org/apache/fop/pdf/PDFFactory.java @@ -688,7 +688,7 @@ public class PDFFactory { public PDFPattern makeGradient(PDFResourceContext res, boolean radial, PDFColorSpace theColorspace, List theColors, List theBounds, - List theCoords) { + List theCoords, List theMatrix) { PDFShading myShad; PDFFunction myfunky; PDFFunction myfunc; @@ -770,7 +770,7 @@ public class PDFFactory { } - myPattern = makePattern(res, 2, myShad, null, null, null); + myPattern = makePattern(res, 2, myShad, null, null, theMatrix); return (myPattern); } diff --git a/src/java/org/apache/fop/pdf/PDFState.java b/src/java/org/apache/fop/pdf/PDFState.java index f2ebe6ea9..15f4527c2 100644 --- a/src/java/org/apache/fop/pdf/PDFState.java +++ b/src/java/org/apache/fop/pdf/PDFState.java @@ -68,11 +68,11 @@ public class PDFState { Data copy; try { copy = (Data)getData().clone(); + getData().resetTransform(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e.getMessage()); } stateStack.add(copy); - data.resetConcatenations(); } /** @@ -280,16 +280,15 @@ public class PDFState { * @return the calculate combined transform for the current state */ public AffineTransform getTransform() { - AffineTransform tf; - AffineTransform at = new AffineTransform(); - for (Iterator iter = stateStack.iterator(); iter.hasNext();) { - Data d = (Data)iter.next(); - tf = d.transform; - at.concatenate(tf); - } - at.concatenate(getData().transform); - - return at; + AffineTransform tf; + AffineTransform at = new AffineTransform(); + for (Iterator iter = stateStack.iterator(); iter.hasNext();) { + Data d = (Data)iter.next(); + tf = d.transform; + at.concatenate(tf); + } + at.concatenate(getData().transform); + return at; } /** @@ -339,8 +338,6 @@ public class PDFState { public String fontName = ""; public Shape clip = null; public PDFGState gstate = null; - /** Log of all concatenation operations */ - public List concatenations = null; /** @see java.lang.Object#clone() */ @@ -362,19 +359,20 @@ public class PDFState { obj.fontName = this.fontName; obj.clip = this.clip; obj.gstate = this.gstate; - if (this.concatenations != null) { - obj.concatenations = new java.util.ArrayList(this.concatenations); - } return obj; } /** - * Forgets the previously made AffineTransform concatenations. + * Get the current Transform. */ - public void resetConcatenations() { - this.concatenations = null; + public AffineTransform getTransform() { + return transform; } - + + public void resetTransform() { + transform = new AffineTransform(); + } + /** * Concatenate the given AffineTransform with the current thus creating * a new viewport. Note that all concatenation operations are logged @@ -383,16 +381,12 @@ public class PDFState { * @param at Transformation to perform */ public void concatenate(AffineTransform at) { - if (this.concatenations == null) { - this.concatenations = new java.util.ArrayList(); - } - concatenations.add(at); transform.concatenate(at); } /** @see java.lang.Object#toString() */ public String toString() { - return super.toString() + ", " + this.transform + " | " + this.concatenations; + return super.toString() + ", " + this.transform; } } } diff --git a/src/java/org/apache/fop/render/pdf/PDFRenderer.java b/src/java/org/apache/fop/render/pdf/PDFRenderer.java index 69a96f432..ed129317b 100644 --- a/src/java/org/apache/fop/render/pdf/PDFRenderer.java +++ b/src/java/org/apache/fop/render/pdf/PDFRenderer.java @@ -928,21 +928,18 @@ public class PDFRenderer extends AbstractPathOrientedRenderer { comment("------ restoring context after break-out..."); PDFState.Data data; Iterator i = breakOutList.iterator(); + double[] matrix = new double[6]; 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"); - } + AffineTransform at = data.getTransform(); + if (!at.isIdentity()) { + currentState.setTransform(at); + 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 diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2D.java b/src/java/org/apache/fop/render/ps/PSGraphics2D.java index 4bfea700a..464840031 100644 --- a/src/java/org/apache/fop/render/ps/PSGraphics2D.java +++ b/src/java/org/apache/fop/render/ps/PSGraphics2D.java @@ -134,6 +134,15 @@ public class PSGraphics2D extends AbstractGraphics2D { */ public PSGraphics2D(PSGraphics2D g) { super(g); + + setPSGenerator(g.gen); + this.clippingDisabled = g.clippingDisabled; + this.font = g.font; + this.overrideFont = g.overrideFont; + this.currentFontName = g.currentFontName; + this.currentFontSize = g.currentFontSize; + this.currentColour = g.currentColour; + this.fontInfo = g.fontInfo; } /** diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java index d90857743..85e5f667f 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java @@ -305,12 +305,19 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D resourceContext = page; pdfContext.setCurrentPage(page); pageRef = page.referencePDF(); - graphicsState.setTransform(new AffineTransform(1.0, 0.0, 0.0, -1.0, 0.0, (double)height)); + + AffineTransform at = new AffineTransform(1.0, 0.0, 0.0, -1.0, + 0.0, (double)height); currentStream.write("1 0 0 -1 0 " + height + " cm\n"); if (svgWidth != 0) { - currentStream.write("" + PDFNumber.doubleOut(width / svgWidth) + " 0 0 " - + PDFNumber.doubleOut(height / svgHeight) + " 0 0 cm\n"); + double scaleX = width / svgWidth; + double scaleY = height / svgHeight; + at.scale(scaleX, scaleY); + currentStream.write("" + PDFNumber.doubleOut(scaleX) + " 0 0 " + + PDFNumber.doubleOut(scaleY) + " 0 0 cm\n"); } + // Remember the transform we installed. + graphicsState.setTransform(at); pdfContext.increasePageCount(); } diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java index 4d91422d3..b3a49da37 100644 --- a/src/java/org/apache/fop/svg/PDFGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java @@ -278,6 +278,15 @@ public class PDFGraphics2D extends AbstractGraphics2D { return currentStream.toString(); } + /** + * Get the string buffer from the currentStream, containing all + * the commands written into this Grpahics so far. + * @return the StringBuffer containing the PDF markup + */ + public StringBuffer getBuffer() { + return currentStream.getBuffer(); + } + /** * Set the Grpahics context. * @param c the graphics context to use @@ -829,17 +838,27 @@ public class PDFGraphics2D extends AbstractGraphics2D { LinearGradientPaint gp = (LinearGradientPaint)paint; Color[] cols = gp.getColors(); float[] fractions = gp.getFractions(); - Point2D p1 = gp.getStartPoint(); - Point2D p2 = gp.getEndPoint(); + //MultipleGradientPaint.CycleMethodEnum cycenum = gp.getCycleMethod(); //boolean cyclic = (cycenum == MultipleGradientPaint.REPEAT); - AffineTransform transform = graphicsState.getTransform(); - transform.concatenate(gp.getTransform()); + // This code currently doesn't support 'repeat' as PDF has + // no way to support this (we need to rasterize). + + // Build proper transform from gradient space to page space + // ('Patterns' don't get userspace transform). + AffineTransform transform; + transform = new AffineTransform(graphicsState.getTransform()); transform.concatenate(getTransform()); + transform.concatenate(gp.getTransform()); - p1 = transform.transform(p1, null); - p2 = transform.transform(p2, null); + List theMatrix = new java.util.ArrayList(); + double [] mat = new double[6]; + transform.getMatrix(mat); + for (int idx=0; idx scale) { - scale = gradt.getScaleY(); - } - ar = ar * scale; - ac = transform.transform(ac, null); - af = transform.transform(af, null); List theCoords = new java.util.ArrayList(); - // the center point af must be within the circle with - // radius ar centered at ac - theCoords.add(new Double(af.getX())); - theCoords.add(new Double(af.getY())); + double dx = af.getX()-ac.getX(); + double dy = af.getY()-ac.getY(); + double d = Math.sqrt(dx*dx+dy*dy); + if (d > ar) { + // the center point af must be within the circle with + // radius ar centered at ac so limit it to that. + double scale = (ar*.9999)/d; + dx = dx*scale; + dy = dy*scale; + } + + theCoords.add(new Double(ac.getX()+dx)); // Fx + theCoords.add(new Double(ac.getY()+dy)); // Fy theCoords.add(new Double(0)); - theCoords.add(new Double(ac.getX())); // Fx - theCoords.add(new Double(ac.getY())); // Fy + theCoords.add(new Double(ac.getX())); + theCoords.add(new Double(ac.getY())); theCoords.add(new Double(ar)); Color[] cols = rgp.getColors(); List someColors = new java.util.ArrayList(); for (int count = 0; count < cols.length; count++) { Color cc = cols[count]; - someColors.add(new PDFColor(cc.getRed(), cc.getGreen(), cc.getBlue())); + someColors.add(new PDFColor(cc.getRed(), cc.getGreen(), + cc.getBlue())); } float[] fractions = rgp.getFractions(); @@ -922,10 +951,12 @@ public class PDFGraphics2D extends AbstractGraphics2D { float offset = fractions[count]; theBounds.add(new Double(offset)); } - PDFColorSpace colSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB); - PDFPattern myPat = pdfDoc.getFactory().makeGradient( - resourceContext, true, colSpace, - someColors, theBounds, theCoords); + PDFColorSpace colSpace; + colSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB); + + PDFPattern myPat = pdfDoc.getFactory().makeGradient + (resourceContext, true, colSpace, + someColors, theBounds, theCoords, theMatrix); currentStream.write(myPat.getColorSpaceOut(fill)); @@ -937,7 +968,6 @@ public class PDFGraphics2D extends AbstractGraphics2D { private void createPattern(PatternPaint pp, boolean fill) { preparePainting(); - Rectangle2D rect = pp.getPatternRect(); FontInfo fontInfo = new FontInfo(); FontSetup.setup(fontInfo, null); @@ -947,41 +977,64 @@ public class PDFGraphics2D extends AbstractGraphics2D { PDFGraphics2D pattGraphic = new PDFGraphics2D(textAsShapes, fontInfo, pdfDoc, context, pageRef, "", 0); - pattGraphic.gc = (GraphicContext)this.gc.clone(); + pattGraphic.setGraphicContext(new GraphicContext()); pattGraphic.gc.validateTransformStack(); + pattGraphic.setRenderingHints(this.getRenderingHints()); pattGraphic.setOutputStream(outputStream); GraphicsNode gn = pp.getGraphicsNode(); - gn.paint(pattGraphic); - - StringWriter pattStream = new StringWriter(); - pattStream.write("q\n"); - - // this makes the pattern the right way up, since - // it is outside the original transform around the - // whole svg document - pattStream.write("1 0 0 -1 0 " + (rect.getHeight() + rect.getY()) + " cm\n"); + Rectangle2D gnBBox = gn.getBounds(); + Rectangle2D rect = pp.getPatternRect(); - pattStream.write(pattGraphic.getString()); - pattStream.write("Q"); + // if (!pp.getOverflow()) { + gn.paint(pattGraphic); + // } else { + // /* Commented out until SVN version of Batik is included */ + // // For overflow we need to paint the content from + // // all the tiles who's overflow will intersect one + // // tile (left->right, top->bottom). Then we can + // // simply replicate that tile as normal. + // double gnMinX = gnBBox.getX(); + // double gnMaxX = gnBBox.getX() + gnBBox.getWidth(); + // double gnMinY = gnBBox.getY(); + // double gnMaxY = gnBBox.getY() + gnBBox.getHeight(); + // double patMaxX = rect.getX() + rect.getWidth(); + // double patMaxY = rect.getY() + rect.getHeight(); + // double stepX = rect.getWidth(); + // double stepY = rect.getHeight(); + // + // int startX = (int)((rect.getX() - gnMaxX)/stepX); + // int startY = (int)((rect.getY() - gnMaxY)/stepY); + // + // int endX = (int)((patMaxX - gnMinX)/stepX); + // int endY = (int)((patMaxY - gnMinY)/stepY); + // + // pattGraphic.translate(startX*stepX, startY*stepY); + // for (int yIdx=startY; yIdx<=endY; yIdx++) { + // for (int xIdx=startX; xIdx<=endX; xIdx++) { + // gn.paint(pattGraphic); + // pattGraphic.translate(stepX,0); + // } + // pattGraphic.translate(-(endX-startX+1)*stepX, stepY); + // } + // } List bbox = new java.util.ArrayList(); - bbox.add(new Double(0)); - bbox.add(new Double(0)); - bbox.add(new Double(rect.getWidth() + rect.getX())); - bbox.add(new Double(rect.getHeight() + rect.getY())); - - List translate = new java.util.ArrayList(); - AffineTransform pattt = pp.getPatternTransform(); - pattt.translate(rect.getWidth() + rect.getX(), rect.getHeight() + rect.getY()); - double[] flatmatrix = new double[6]; - pattt.getMatrix(flatmatrix); - translate.add(new Double(flatmatrix[0])); - translate.add(new Double(flatmatrix[1])); - translate.add(new Double(flatmatrix[2])); - translate.add(new Double(flatmatrix[3])); - translate.add(new Double(flatmatrix[4])); - translate.add(new Double(flatmatrix[5])); + bbox.add(new Double(rect.getX())); + bbox.add(new Double(rect.getHeight()+rect.getY())); + bbox.add(new Double(rect.getWidth() +rect.getX())); + bbox.add(new Double(rect.getY())); + + AffineTransform transform; + transform = new AffineTransform(graphicsState.getTransform()); + transform.concatenate(getTransform()); + transform.concatenate(pp.getPatternTransform()); + + List theMatrix = new java.util.ArrayList(); + double [] mat = new double[6]; + transform.getMatrix(mat); + for (int idx=0; idx PDFDocument's resources) so addFonts() @@ -991,7 +1044,8 @@ public class PDFGraphics2D extends AbstractGraphics2D { PDFPattern myPat = pdfDoc.getFactory().makePattern( resourceContext, 1, res, 1, 1, bbox, rect.getWidth(), rect.getHeight(), - translate, null, pattStream.getBuffer()); + theMatrix, null, + pattGraphic.getBuffer()); currentStream.write(myPat.getColorSpaceOut(fill)); -- 2.39.5