deweese 2002/12/10 08:19:17 Modified: sources/org/apache/batik/ext/awt LinearGradientPaintContext.java MultipleGradientPaintContext.java RadialGradientPaintContext.java test-resources/org/apache/batik/test samplesRendering.xml Added: samples/tests/spec/paints linearGradientRepeat.svg Log: 1) Added Anti-aliasing for linear gradients when appropriate rendering hints are set (render quality or color rendering quality). 2) Fixed a bug in the anti-alias gradient lookup code. 3) Improved the anti-aliasing alg in radial gradients. 4) Added an additional test for linear gradients. Revision Changes Path 1.1 xml-batik/samples/tests/spec/paints/linearGradientRepeat.svg Index: linearGradientRepeat.svg =================================================================== <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <!-- ====================================================================== --> <!-- Copyright (C) The Apache Software Foundation. All rights reserved. --> <!-- --> <!-- This software is published under the terms of the Apache Software --> <!-- License version 1.1, a copy of which has been included with this --> <!-- distribution in the LICENSE file. --> <!-- ====================================================================== --> <!-- ====================================================================== --> <!-- @author [EMAIL PROTECTED] --> <!-- @author [EMAIL PROTECTED] --> <!-- @version $Id: linearGradientRepeat.svg,v 1.1 2002/12/10 16:19:16 deweese Exp $ --> <!-- ====================================================================== --> <?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body" width="450" height="500" viewBox="0 0 450 500"> <title><linearGradient> Repeat Test</title> <text class="title" x="50%" y="40"> <linearGradient> Repeat Test </text> <style type="text/css"><![CDATA[ .speed { clip-path:url(#speedClip); color-rendering:optimizeSpeed; } .default { clip-path:url(#defaultClip); color-rendering:auto; } .quality { clip-path:url(#qualityClip); color-rendering:optimizeQuality; } .saqLabel { font-family: Verdana, Helvetica; font-size: 5; text-anchor: middle; fill:black; stroke:none;} .line { fill:none; stroke:black; stroke-width:0.25; } ]]></style> <defs> <!-- Shape filled by linear gradients --> <g id="testShape"> <rect x="-25" y="-20" width="50" height="40" class="quality" /> <rect x="-25" y="-20" width="50" height="40" class="default" /> <rect x="-25" y="-20" width="50" height="40" class="speed" /> <text x="-16.5" y="24" class="saqLabel">Q</text> <line x1="-8" x2="-8" y1="20" y2="25" class="line" /> <text x="0" y="24" class="saqLabel">A</text> <line x1="8" x2="8" y1="20" y2="25" class="line" /> <text x="16.5" y="24" class="saqLabel">S</text> </g> <!-- Clip paths for the various color-rendering settings... --> <clipPath id="qualityClip"> <rect x="-25" y="-20" width="17" height="40"/> </clipPath> <clipPath id="defaultClip"> <rect x="-8" y="-20" width="16" height="40"/> </clipPath> <clipPath id="speedClip"> <rect x="8" y="-20" width="17" height="40"/> </clipPath> <!-- ========================================== --> <!-- Two gradients, one with no values defined --> <!-- and one with the default values specified --> <!-- They should create the same pattern --> <!-- ========================================== --> <linearGradient id="lgDefaults" spreadMethod="repeat"> <stop offset=".0" stop-color="gold" /> <stop offset=".49" stop-color="crimson" /> <stop offset=".51" stop-color="gold" /> <stop offset="1." stop-color="crimson" /> </linearGradient> <linearGradient id="lgUR" xlink:href="#lgDefaults" x1="25%" x2="75%" y1="75%" y2="25%"/> <linearGradient id="lgU" xlink:href="#lgDefaults" x1="25%" x2="25%" y1="75%" y2="25%"/> <linearGradient id="lgUL" xlink:href="#lgDefaults" x1="75%" x2="25%" y1="75%" y2="25%"/> <linearGradient id="lgL" xlink:href="#lgDefaults" x1="75%" x2="25%" y1="25%" y2="25%"/> <linearGradient id="lgDL" xlink:href="#lgDefaults" x1="75%" x2="25%" y1="25%" y2="75%"/> <linearGradient id="lgD" xlink:href="#lgDefaults" x1="25%" x2="25%" y1="25%" y2="75%"/> <linearGradient id="lgDR" xlink:href="#lgDefaults" x1="25%" x2="75%" y1="25%" y2="75%"/> <linearGradient id="lgR" xlink:href="#lgDefaults" x1="25%" x2="75%" y1="25%" y2="25%"/> </defs> <g transform="translate(70, 110) scale(2)" font-size="8"> <g transform="translate(0, 0)" text-anchor="middle"> <g transform="translate(0, 0)"> <use xlink:href="#testShape" fill="url(#lgR)" /> <text y="-23">Right</text> </g> <g transform="translate(0, 55)"> <use xlink:href="#testShape" fill="url(#lgUR)" /> <text y="-23">Up Right</text> </g> <g transform="translate(0, 110)"> <use xlink:href="#testShape" fill="url(#lgU)" /> <text y="-23">Up</text> </g> <g transform="translate(0, 165)"> <use xlink:href="#testShape" fill="url(#lgUL)" /> <text y="-23">Up Left</text> </g> </g> <g transform="translate(70, 0)" text-anchor="middle"> <g transform="translate(0, 0)"> <use xlink:href="#testShape" fill="url(#lgL)" /> <text y="-23">Left</text> </g> <g transform="translate(0, 55)"> <use xlink:href="#testShape" fill="url(#lgDL)" /> <text y="-23">Down Left</text> </g> <g transform="translate(0, 110)"> <use xlink:href="#testShape" fill="url(#lgD)" /> <text y="-23">Down</text> </g> <g transform="translate(0, 165)"> <use xlink:href="#testShape" fill="url(#lgDR)" /> <text y="-23">Down Right</text> </g> </g> </g> </svg> 1.8 +47 -5 xml-batik/sources/org/apache/batik/ext/awt/LinearGradientPaintContext.java Index: LinearGradientPaintContext.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/LinearGradientPaintContext.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- LinearGradientPaintContext.java 13 Sep 2001 21:55:52 -0000 1.7 +++ LinearGradientPaintContext.java 10 Dec 2002 16:19:17 -0000 1.8 @@ -30,8 +30,13 @@ * a device space coordinate, (X, Y): * g(X, Y) = dgdX*X + dgdY*Y + gc */ - private float dgdX, dgdY, gc; + private float dgdX, dgdY, gc, pixSz; + private static final int DEFAULT_IMPL = 1; + private static final int ANTI_ALIAS_IMPL = 3; + + private int fillMethod; + /** * Constructor for LinearGradientPaintContext. * @@ -106,11 +111,34 @@ float constX = dx/dSq; float constY = dy/dSq; - dgdX = a00*constX + a10*constY;//incremental change along gradient for +x - dgdY = a01*constX + a11*constY;//incremental change along gradient for +y + //incremental change along gradient for +x + dgdX = a00*constX + a10*constY; + //incremental change along gradient for +y + dgdY = a01*constX + a11*constY; + + float dgdXAbs = Math.abs(dgdX); + float dgdYAbs = Math.abs(dgdY); + if (dgdXAbs > dgdYAbs) pixSz = dgdXAbs; + else pixSz = dgdYAbs; //constant, incorporates the translation components from the matrix gc = (a02-start.x)*constX + (a12-start.y)*constY; + + Object colorRend = hints.get(RenderingHints.KEY_COLOR_RENDERING); + Object rend = hints.get(RenderingHints.KEY_RENDERING); + + fillMethod = DEFAULT_IMPL; + + if ((cycleMethod == MultipleGradientPaint.REPEAT) || + hasDiscontinuity) { + if (rend == RenderingHints.VALUE_RENDER_QUALITY) + fillMethod = ANTI_ALIAS_IMPL; + // ColorRend overrides rend. + if (colorRend == RenderingHints.VALUE_COLOR_RENDER_SPEED) + fillMethod = DEFAULT_IMPL; + else if (colorRend == RenderingHints.VALUE_COLOR_RENDER_QUALITY) + fillMethod = ANTI_ALIAS_IMPL; + } } protected void fillHardNoCycle(int[] pixels, int off, int adjust, @@ -448,7 +476,21 @@ //constant which can be pulled out of the inner loop final float initConst = (dgdX*x) + gc; - if (!isSimpleLookup) { + if (fillMethod == ANTI_ALIAS_IMPL) { + //initialize current value to be start. + for(int i=0; i<h; i++){ //for every row + float g = initConst + dgdY*(y+i); + + final int rowLimit = off+w; // end of row iteration + while(off < rowLimit){ //for every pixel in this row. + //get the color + pixels[off++] = indexGradientAntiAlias(g, pixSz); + g += dgdX; //incremental change in g + } + off += adjust; //change in off from row to row + } + } + else if (!isSimpleLookup) { if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { fillHardNoCycle(pixels, off, adjust, x, y, w, h); } 1.13 +2 -2 xml-batik/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java Index: MultipleGradientPaintContext.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- MultipleGradientPaintContext.java 11 Mar 2002 16:49:22 -0000 1.12 +++ MultipleGradientPaintContext.java 10 Dec 2002 16:19:17 -0000 1.13 @@ -888,7 +888,7 @@ // p1 and p2 my pass each other which will cause no end of // trouble. sz -= intSz; - weight = (1-sz)/(intSz+sz); + weight = sz/(intSz+sz); if (weight < 0.1) // The part of the color from the location will be swamped // by the averaged part of the gradient so just use the 1.7 +187 -47 xml-batik/sources/org/apache/batik/ext/awt/RadialGradientPaintContext.java Index: RadialGradientPaintContext.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/RadialGradientPaintContext.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- RadialGradientPaintContext.java 13 Sep 2001 21:55:52 -0000 1.6 +++ RadialGradientPaintContext.java 10 Dec 2002 16:19:17 -0000 1.7 @@ -508,53 +508,195 @@ final double constC = -(radiusSq) + (centerX * centerX) + (centerY * centerY); //coefficients of the quadratic equation (Ax^2 + Bx + C = 0) - double A, B, C; - double slope; //slope of the focus-perimeter line - double yintcpt; //y-intercept of the focus-perimeter line - double solutionX;//intersection with circle X coordinate - double solutionY;//intersection with circle Y coordinate - final float constX = (a00*x) + (a01*y) + a02;//const part of X coord - final float constY = (a10*x) + (a11*y) + a12; //const part of Y coord final float precalc2 = 2 * centerY;//const in inner loop quad. formula final float precalc3 =-2 * centerX;//const in inner loop quad. formula - float det; //determinant of quadratic formula (should always be >0) + //const part of X,Y coord (shifted to bottom left corner of pixel. + final float constX = (a00*(x-.5f)) + (a01*(y+.5f)) + a02; + final float constY = (a10*(x-.5f)) + (a11*(y+.5f)) + a12; float X; // User space point X coordinate float Y; // User space point Y coordinate - float g;//value specifying position in the gradient - float delta; // range around g to average for anti-aliasing - - float currentToFocusSq;//sq distance from the current pt. to focus - float intersectToFocusSq;//sq distance from the intersect pt. to focus - float deltaXSq; //temp variable for a change in X squared. - float deltaYSq; //temp variable for a change in Y squared. - - int j, end; //indexing variables for FOR loops - int indexer = off; //index variable for pixels array + int i, j; //indexing variables for FOR loops + int indexer = off-1; //index variable for pixels array // Size of a pixel in user space. - float pixSzSq = (float)(a00*a00+a01*a01+a10*a10+a11*a11); - + double pixSzSq = (float)(a00*a00+a01*a01+a10*a10+a11*a11); + double [] prevGs = new double[w+1]; + double deltaXSq, deltaYSq; + double solutionX, solutionY; + double slope, yintcpt, A, B, C, det; + double intersectToFocusSq, currentToFocusSq; + double g00, g01, g10, g11; + + // Set X,Y to top left corner of first pixel of first row. + X = constX - a01; + Y = constY - a11; + + // Calc top row of g's. + for (i=0; i <= w; i++) { + // special case to avoid divide by zero or very near zero + if (((X-focusX)>-0.000001) && + ((X-focusX)< 0.000001)) { + solutionX = focusX; + solutionY = centerY; + solutionY += (Y > focusY)?trivial:-trivial; + } + else { + // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0 + // Formula line: Y = Slope*x + Y0; + // + // So you substitue line into Circle and apply + // Quadradic formula. + + + //slope of the focus-current line + slope = (Y - focusY) / (X - focusX); + + yintcpt = Y - (slope * X); //y-intercept of that same line + + //use the quadratic formula to calculate the intersection + //point + A = (slope * slope) + 1; + + B = precalc3 + (-2 * slope * (centerY - yintcpt)); + + C = constC + (yintcpt* (yintcpt - precalc2)); + + det = Math.sqrt((B * B) - ( 4 * A * C)); + + solutionX = -B; + + //choose the positive or negative root depending + //on where the X coord lies with respect to the focus. + solutionX += (X < focusX)?-det:det; + + solutionX = solutionX / (2 * A);//divisor + + solutionY = (slope * solutionX) + yintcpt; + } + + //calculate the square of the distance from the current point + //to the focus and the square of the distance from the + //intersection point to the focus. Want the squares so we can + //do 1 square root after division instead of 2 before. + deltaXSq = solutionX - focusX; + deltaXSq = deltaXSq * deltaXSq; + + deltaYSq = solutionY - focusY; + deltaYSq = deltaYSq * deltaYSq; + + intersectToFocusSq = deltaXSq + deltaYSq; + + deltaXSq = X - focusX; + deltaXSq = deltaXSq * deltaXSq; + + deltaYSq = Y - focusY; + deltaYSq = deltaYSq * deltaYSq; + + currentToFocusSq = deltaXSq + deltaYSq; + + //want the percentage (0-1) of the current point along the + //focus-circumference line + prevGs[i] = Math.sqrt(currentToFocusSq / intersectToFocusSq); + + X += a00; //incremental change in X, Y + Y += a10; + } + for (j = 0; j < h; j++) { //for every row - X = (a01*j) + constX; //constants from column to column + // Set X,Y to bottom edge of pixel row. + X = (a01*j) + constX; //constants from row to row Y = (a11*j) + constY; - + + g10 = prevGs[0]; + // special case to avoid divide by zero or very near zero + if (((X-focusX)>-0.000001) && + ((X-focusX)< 0.000001)) { + solutionX = focusX; + solutionY = centerY; + solutionY += (Y > focusY)?trivial:-trivial; + } + else { + // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0 + // Formula line: Y = Slope*x + Y0; + // + // So you substitue line into Circle and apply + // Quadradic formula. + + + //slope of the focus-current line + slope = (Y - focusY) / (X - focusX); + + yintcpt = Y - (slope * X); //y-intercept of that same line + + //use the quadratic formula to calculate the intersection + //point + A = (slope * slope) + 1; + + B = precalc3 + (-2 * slope * (centerY - yintcpt)); + + C = constC + (yintcpt* (yintcpt - precalc2)); + + det = Math.sqrt((B * B) - ( 4 * A * C)); + + solutionX = -B; + + //choose the positive or negative root depending + //on where the X coord lies with respect to the focus. + solutionX += (X < focusX)?-det:det; + + solutionX = solutionX / (2 * A);//divisor + + solutionY = (slope * solutionX) + yintcpt; + } + + //calculate the square of the distance from the current point + //to the focus and the square of the distance from the + //intersection point to the focus. Want the squares so we can + //do 1 square root after division instead of 2 before. + deltaXSq = solutionX - focusX; + deltaXSq = deltaXSq * deltaXSq; + + deltaYSq = solutionY - focusY; + deltaYSq = deltaYSq * deltaYSq; + + intersectToFocusSq = deltaXSq + deltaYSq; + + deltaXSq = X - focusX; + deltaXSq = deltaXSq * deltaXSq; + + deltaYSq = Y - focusY; + deltaYSq = deltaYSq * deltaYSq; + + currentToFocusSq = deltaXSq + deltaYSq; + g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq); + prevGs[0] = g11; + + X += a00; //incremental change in X, Y + Y += a10; + //for every column (inner loop begins here) - for (end = indexer + w; indexer < end; indexer++) { - + for (i=1; i <= w; i++) { + g00 = g10; + g01 = g11; + g10 = prevGs[i]; + // special case to avoid divide by zero or very near zero if (((X-focusX)>-0.000001) && ((X-focusX)< 0.000001)) { solutionX = focusX; - solutionY = centerY; - solutionY += (Y > focusY)?trivial:-trivial; } - - else { - + else { + // Formula for Circle: (X-Xc)^2 + (Y-Yc)^2 - R^2 = 0 + // Formula line: Y = Slope*x + Y0; + // + // So you substitue line into Circle and apply + // Quadradic formula. + + //slope of the focus-current line slope = (Y - focusY) / (X - focusX); @@ -568,7 +710,7 @@ C = constC + (yintcpt* (yintcpt - precalc2)); - det = (float)Math.sqrt((B * B) - ( 4 * A * C)); + det = Math.sqrt((B * B) - ( 4 * A * C)); solutionX = -B; @@ -585,36 +727,34 @@ //to the focus and the square of the distance from the //intersection point to the focus. Want the squares so we can //do 1 square root after division instead of 2 before. - - deltaXSq = (float)solutionX - focusX; + deltaXSq = solutionX - focusX; deltaXSq = deltaXSq * deltaXSq; - - deltaYSq = (float)solutionY - focusY; + + deltaYSq = solutionY - focusY; deltaYSq = deltaYSq * deltaYSq; - + intersectToFocusSq = deltaXSq + deltaYSq; - + deltaXSq = X - focusX; deltaXSq = deltaXSq * deltaXSq; - + deltaYSq = Y - focusY; deltaYSq = deltaYSq * deltaYSq; - + currentToFocusSq = deltaXSq + deltaYSq; - - //want the percentage (0-1) of the current point along the - //focus-circumference line - g = (float)Math.sqrt(currentToFocusSq / intersectToFocusSq); + g11 = Math.sqrt(currentToFocusSq / intersectToFocusSq); + prevGs[i] = g11; //Get the color at this point - delta = (float)Math.sqrt(pixSzSq/intersectToFocusSq); - pixels[indexer] = indexGradientAntiAlias(g, delta); - + pixels[indexer+i] = indexGradientAntiAlias + ((float)((g00+g01+g10+g11)/4), + (float)Math.max(Math.abs(g11-g00), + Math.abs(g10-g01))); + X += a00; //incremental change in X, Y Y += a10; } //end inner loop - indexer += adjust; + indexer += (w+adjust); } //end outer loop } - } 1.89 +2 -1 xml-batik/test-resources/org/apache/batik/test/samplesRendering.xml Index: samplesRendering.xml =================================================================== RCS file: /home/cvs/xml-batik/test-resources/org/apache/batik/test/samplesRendering.xml,v retrieving revision 1.88 retrieving revision 1.89 diff -u -r1.88 -r1.89 --- samplesRendering.xml 25 Nov 2002 16:14:15 -0000 1.88 +++ samplesRendering.xml 10 Dec 2002 16:19:17 -0000 1.89 @@ -187,6 +187,7 @@ <test id="samples/tests/spec/paints/gradientLimit.svg" /> <test id="samples/tests/spec/paints/linearGradientOrientation.svg" /> <test id="samples/tests/spec/paints/linearGradientLine.svg" /> + <test id="samples/tests/spec/paints/linearGradientRepeat.svg" /> <test id="samples/tests/spec/paints/radialGradientLine.svg" /> <test id="samples/tests/spec/paints/gradientPoint.svg" /> <test id="samples/tests/spec/paints/patternPreserveAspectRatioA.svg" />
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]