You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by de...@apache.org on 2001/01/05 16:49:21 UTC

cvs commit: xml-batik/sources/org/apache/batik/util/awt/svg SVGConvolveOp.java

deweese     01/01/05 07:49:21

  Modified:    resources/org/apache/batik/refimpl/bridge/resources
                        Messages.properties
               sources/org/apache/batik/gvt/filter ConvolveMatrixRable.java
                        PadMode.java
               sources/org/apache/batik/refimpl/bridge
                        SVGBridgeContext.java
               sources/org/apache/batik/refimpl/gvt/filter
                        ConcreteBackgroundRable.java
                        ConcreteConvolveMatrixRable.java
                        ConcreteGaussianBlurRable.java PadRed.java
               sources/org/apache/batik/util SVGConstants.java
               sources/org/apache/batik/util/awt/svg SVGConvolveOp.java
  Added:       samples/tests feConvolveMatrix.svg
               sources/org/apache/batik/refimpl/bridge
                        SVGFeConvolveMatrixElementBridge.java
  Log:
  * Added support for PadMode REPLICATE (AKA duplicate) in PadRed.java
  
  * Fixed a bug in ConcreteBackgroundRable for the case where there
    was no child of node with background-enable:true before the child
    requesting the background.
  
  * Fixed a few constants in SVGConstants.
  
  * Switched FeConvolveMatrix on (new bridge, almost finished implementation).
    Still needs to handle bias (hard), and preserveAlpha (tricky but not
    too bad).
  
  * Fixed a few documentation bugs in GaussianBlurRable
  
  * Added Messages for feConvolveMatrix bridge
  
  Revision  Changes    Path
  1.22      +30 -1     xml-batik/resources/org/apache/batik/refimpl/bridge/resources/Messages.properties
  
  Index: Messages.properties
  ===================================================================
  RCS file: /home/cvs/xml-batik/resources/org/apache/batik/refimpl/bridge/resources/Messages.properties,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- Messages.properties	2000/11/29 16:00:38	1.21
  +++ Messages.properties	2001/01/05 15:49:16	1.22
  @@ -220,7 +220,36 @@
   The attribute "in2" on <feComposite> is required
   
   feComposite.operator.invalid = \
  -The value "{0}" of the attribute "operator" is invalid
  +The value "{0}" of the attribute "operator" on <feComposite> is invalid
  +
  +##### <feConvolveMatrix> #####
  +
  +feConvolveMatrix.order.notPosInt = \
  +The attribute "order" on <feConvolveMatrix> must contain positive integers(s).
  +
  +feConvolveMatrix.kernelMatrix.tooMany = \
  +The attribute "kernelMatrix" on <feConvolveMatrix> contains too many values.
  +
  +feConvolveMatrix.kernelMatrix.notEnough = \
  +The attribute "kernelMatrix" on <feConvolveMatrix> contains too few values.
  +
  +feConvolveMatrix.divisor.zero = \
  +The attribute "divisor" on <feConvolveMatrix> can not be zero.
  +
  +feConvolveMatrix.targetX.invalid = \
  +The attribute "targetX" on <feConvolveMatrix> must lie within the kernel.
  +
  +feConvolveMatrix.targetY.invalid = \
  +The attribute "targetY" on <feConvolveMatrix> must lie within the kernel.
  +
  +feConvolveMatrix.edgeMode.invalid = \
  +The value "{0}" of the attribute "edgeMode" on <feConvolveMatrix> is invalid.
  +
  +feConvolveMatrix.kernelUnitLength.notPositive = \
  +The attribute "kernelUnitLength" on <feConvolveMatrix> must contain positive number(s).
  +
  +feConvolveMatrix.preserveAlpha.invalid = \
  +The value "{0}" of the attribute "preserveAlpha" on <feConvolveMatrix> is invalid.
   
   ##### <feDisplacementMap> #####
   
  
  
  
  1.1                  xml-batik/samples/tests/feConvolveMatrix.svg
  
  Index: feConvolveMatrix.svg
  ===================================================================
  <?xml version="1.0" standalone="no"?>
  <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000802//EN"
  "http://www.w3.org/TR/2000/CR-SVG-20000802/DTD/svg-20000802.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.                                                         -->
  <!-- ========================================================================= -->
  
  <!-- ========================================================================= -->
  <!-- Test description here                                                     -->
  <!--                                                                           -->
  <!-- @author deweese@kodak.com                                                 -->
  <!-- @version $Id $  -->
  <!-- ========================================================================= -->
  
  <?xml-stylesheet type="text/css" href="test.css" ?>
  
  <svg id="body" width="450" height="500" viewBox="0 0 450 500">
  <title>feMerge Test</title>
  
    <!-- ============================================================= -->
    <!-- Test content                                                  -->
    <!-- ============================================================= -->
    <g id="testContent">
  
      <text x="225" y="40" class="title">
    	feConvolveMatrix Text
      </text>
  
      <defs>
  
  
    	<filter id="conv-rep-tr" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="0 0 0 0 0 0 0 0 0 0 1
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0"
           edgeMode="duplicate" />
    	</filter>
  
    	<filter id="conv-centX" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="0 0 0 0 0 0 0 0 0 0 10
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0"
           targetX="10"
           edgeMode="duplicate" />
    	</filter>
  
    	<filter id="conv-centY" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="0 0 0 0 0 0 0 0 0 0 10
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0"
           targetY="0"
           edgeMode="duplicate" />
    	</filter>
  
    	<filter id="conv-rep-bl" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         1 0 0 0 0 0 0 0 0 0 0"
           edgeMode="duplicate" />
    	</filter>
  
    	<filter id="conv-rep-br" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 1"
           edgeMode="duplicate" />
    	</filter>
  
    	<filter id="conv-rep-tl" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="1 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0"
           edgeMode="duplicate" />
    	</filter>
  
    	<filter id="conv-none-tr" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="0 0 0 0 0 0 0 0 0 0 1
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0"
           edgeMode="none" />
    	</filter>
  
    	<filter id="conv-none-tl" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="1 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0"
           edgeMode="none" />
    	</filter>
  
    	<filter id="conv-none-bl" x="0" y="0" width="1" height="1">
          <feConvolveMatrix order="11 11"
           kernelMatrix="0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         0 0 0 0 0 0 0 0 0 0 0
                         1 0 0 0 0 0 0 0 0 0 0"
           kernelUnitLength="4"
           edgeMode="none" />
    	</filter>
  
        <linearGradient id="grad" y2="100%">
          <stop offset="0%"   style="stop-color:#FF0" />
          <stop offset="100%" style="stop-color:#F00" />
        </linearGradient>
  
        <g id="content">
          <rect   x="15" y="15" width="90" height="90" 
                  style="fill:url(#grad)" />
  
          <circle id="Circle1" cx="40" cy="65" r="25" 
                  style="fill:yellowGreen" />
     
          <circle id="Circle2" cx="80" cy="55" r="25" style="fill:darkBlue" />
     
          <rect   id="Rect1"   x="40" y="35" width="30" height="70" 
                  rx="15" ry="15"
                  style="fill:dodgerBlue" />
     
          <rect   id="Rect2"   x="60" y="15" width="30" height="70" 
                  rx="10" ry="10"
                  style="fill:Green" />
        </g>
  
      </defs>
  
      <g transform="translate(0 40)" class="legend">
  
        <!-- ============================================== -->
        <!-- Convolve_Matrix_1_*                            -->
        <!-- ============================================== -->
        <g transform="translate(0 20)" class="row1" >
          <g transform="translate(20,0)" >
            <g style="filter:url(#conv-rep-tr)">
              <use xlink:href="#content" />
            </g>
        
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             1.1 Replicate Top &amp; Right
            </text>
          </g>
        
          <g transform="translate(160,0)" >
            <g style="filter:url(#conv-centX)">
              <use xlink:href="#content" />
            </g>
        
            <text transform="translate(60, 118)"
                  x="0" y="0" style="text-anchor:middle">
             1.2 Replicate Top, targetX
            </text>
          </g>
        
          <g transform="translate(300,0)" >
            <g style="filter:url(#conv-centY)">
              <use xlink:href="#content" />
            </g>
        
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             1.3 Replicate Right, targetY, norm
            </text>
          </g>
        </g>   <!-- end row1 -->
  
        <!-- ============================================== -->
        <!-- Convolve_Matrix_2_*                            -->
        <!-- ============================================== -->
        <g transform="translate(0 160)" class="row2" >
          <g transform="translate(20,0)" >
            <g style="filter:url(#conv-rep-bl)">
              <use xlink:href="#content" />
            </g>
  
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             3.1 Rep Bottom &amp; Left
            </text>
          </g>
  
          <g transform="translate(160,0)" >
            <g style="filter:url(#conv-rep-br)">
              <use xlink:href="#content" />
            </g>
  
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             3.2 Rep Bottom &amp; Right
            </text>
          </g>
  
          <g transform="translate(300,0)" >
            <g style="filter:url(#conv-rep-tl)">
              <use xlink:href="#content" />
            </g>
  
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             3.3 Rep Top &amp; Left
            </text>
          </g>
        </g>   <!-- end row2 -->
  
        <!-- ============================================== -->
        <!-- Convolve_Matrix_3_*                            -->
        <!-- ============================================== -->
        <g transform="translate(0 300)" class="row3" >
          <g transform="translate(20,0)" >
            <g style="filter:url(#conv-none-tr)">
              <use xlink:href="#content" />
            </g>
  
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             3.1 None Top &amp; Right
            </text>
          </g>
  
          <g transform="translate(160,0)" >
            <g style="filter:url(#conv-none-tl)">
              <use xlink:href="#content" />
            </g>
  
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             3.2 None Top &amp; Left
            </text>
          </g>
  
          <g transform="translate(300,0)" >
            <g style="filter:url(#conv-none-bl)">
              <use xlink:href="#content" />
            </g>
  
            <text transform="translate(60, 130)"
                  x="0" y="0" style="text-anchor:middle">
             3.3 None Bottom &amp; Left
            </text>
          </g>
        </g>  <!-- end row3-->
  
      </g> <!-- end legend -->
  
    </g> <!-- end test content -->
  
    <!-- ============================================================= -->
    <!-- Batik sample mark                                             -->
    <!-- ============================================================= -->
    <use xlink:href="../batikLogo.svg#Batik_Tag_Box" />
    
  </svg>
  
  
  1.2       +38 -1     xml-batik/sources/org/apache/batik/gvt/filter/ConvolveMatrixRable.java
  
  Index: ConvolveMatrixRable.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/filter/ConvolveMatrixRable.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ConvolveMatrixRable.java	2000/12/11 13:44:21	1.1
  +++ ConvolveMatrixRable.java	2001/01/05 15:49:17	1.2
  @@ -9,12 +9,13 @@
   package org.apache.batik.gvt.filter;
   
   import java.awt.image.Kernel;
  +import java.awt.Point;
   
   /**
    * Convolves an image with a convolution matrix.
    *
    * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
  - * @version $Id: ConvolveMatrixRable.java,v 1.1 2000/12/11 13:44:21 deweese Exp $
  + * @version $Id: ConvolveMatrixRable.java,v 1.2 2001/01/05 15:49:17 deweese Exp $
    */
   public interface ConvolveMatrixRable extends Filter {
   
  @@ -42,12 +43,24 @@
       public void setKernel(Kernel k);
   
       /**
  +     * Returns the target point of the kernel (what pixel under the kernel
  +     * should be set to the result of convolution).
  +     */
  +    public Point getTarget();
  +
  +    /**
  +     * Sets the target point of the kernel (what pixel under the kernel
  +     * should be set to the result of the convolution).
  +     */
  +    public void setTarget(Point pt);
  +
  +    /**
        * Returns the shift value to apply to the result of convolution
        */
       public double getBias();
       
       /**
  -     * Returns the shift value to apply to the result of convolution
  +     * Sets the shift value to apply to the result of convolution
        */
       public void setBias(double bias);
   
  @@ -60,4 +73,28 @@
        * Sets the current edge handling mode.
        */
       public void setEdgeMode(PadMode edgeMode);
  +
  +    /**
  +     * Returns the [x,y] distance in user space between kernel values
  +     */
  +    public double [] getKernelUnitLength();
  +
  +    /**
  +     * Sets the [x,y] distance in user space between kernel values
  +     * If set to zero then one pixel in device space will be used.
  +     */
  +    public void setKernelUnitLength(double [] kernelUnitLength);
  +
  +    /**
  +     * Returns false if the convolution should affect the Alpha channel
  +     */
  +    public boolean getPreserveAlpha();
  +
  +    /**
  +     * Sets Alpha channel handling.
  +     * A value of False indicates that the convolution should apply to
  +     * the Alpha Channel
  +     */
  +    public void setPreserveAlpha(boolean preserveAlpha);
   }
  +
  
  
  
  1.2       +9 -1      xml-batik/sources/org/apache/batik/gvt/filter/PadMode.java
  
  Index: PadMode.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/filter/PadMode.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- PadMode.java	2000/10/10 18:40:11	1.1
  +++ PadMode.java	2001/01/05 15:49:17	1.2
  @@ -13,7 +13,7 @@
    * the CompositeRable operation. (over, in, out, atop, xor, arith)
    *
    * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
  - * @version $Id: PadMode.java,v 1.1 2000/10/10 18:40:11 hillion Exp $
  + * @version $Id: PadMode.java,v 1.2 2001/01/05 15:49:17 deweese Exp $
    */
   public final class PadMode implements java.io.Serializable {
         /** Pad edges with zeros */
  @@ -22,12 +22,18 @@
         /** Pad edges by replicating edge pixels */
       public static final int MODE_REPLICATE = 2;
   
  +      /** Pad edges by wrapping around edge pixels */
  +    public static final int MODE_WRAP = 3;
  +
         /** Pad edges with zeros */
       public static final PadMode ZERO_PAD = new PadMode(MODE_ZERO_PAD);
   
         /** Pad edges by replicating edge pixels */
       public static final PadMode REPLICATE = new PadMode(MODE_REPLICATE);
   
  +      /** Pad edges by replicating edge pixels */
  +    public static final PadMode WRAP = new PadMode(MODE_WRAP);
  +
       /**
        * Returns the mode of this pad mode.
        */
  @@ -57,6 +63,8 @@
               return ZERO_PAD;
           case MODE_REPLICATE:
               return REPLICATE;
  +        case MODE_WRAP:
  +            return WRAP;
           default:
               throw new Error("Unknown Pad Mode type");
           }
  
  
  
  1.26      +4 -1      xml-batik/sources/org/apache/batik/refimpl/bridge/SVGBridgeContext.java
  
  Index: SVGBridgeContext.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/refimpl/bridge/SVGBridgeContext.java,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -u -r1.25 -r1.26
  --- SVGBridgeContext.java	2000/12/28 09:37:43	1.25
  +++ SVGBridgeContext.java	2001/01/05 15:49:18	1.26
  @@ -21,7 +21,7 @@
    *
    * @author <a href="mailto:Thierry.Kormann@sophia.inria.fr">Thierry Kormann</a>
    * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
  - * @version $Id: SVGBridgeContext.java,v 1.25 2000/12/28 09:37:43 hillion Exp $
  + * @version $Id: SVGBridgeContext.java,v 1.26 2001/01/05 15:49:18 deweese Exp $
    */
   public class SVGBridgeContext extends ConcreteBridgeContext
           implements SVGConstants {
  @@ -88,6 +88,9 @@
   
           putBridge(SVG_NAMESPACE_URI, SVG_FE_COMPOSITE_TAG,
                     new SVGFeCompositeElementBridge());
  +
  +        putBridge(SVG_NAMESPACE_URI, SVG_FE_CONVOLVE_MATRIX_TAG,
  +                  new SVGFeConvolveMatrixElementBridge());
   
           putBridge(SVG_NAMESPACE_URI, SVG_FE_DISPLACEMENT_MAP_TAG,
                     new SVGFeDisplacementMapElementBridge());
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/refimpl/bridge/SVGFeConvolveMatrixElementBridge.java
  
  Index: SVGFeConvolveMatrixElementBridge.java
  ===================================================================
  /*****************************************************************************
   * 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.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.refimpl.bridge;
  
  import java.awt.geom.Rectangle2D;
  import java.awt.Point;
  import java.awt.image.Kernel;
  
  import java.util.StringTokenizer;
  
  import java.util.Map;
  
  import org.apache.batik.bridge.BridgeContext;
  import org.apache.batik.bridge.BridgeMutationEvent;
  import org.apache.batik.bridge.FilterPrimitiveBridge;
  import org.apache.batik.bridge.IllegalAttributeValueException;
  
  import org.apache.batik.gvt.GraphicsNode;
  import org.apache.batik.gvt.GraphicsNodeRenderContext;
  import org.apache.batik.gvt.filter.Filter;
  import org.apache.batik.gvt.filter.ConvolveMatrixRable;
  import org.apache.batik.gvt.filter.PadMode;
  import org.apache.batik.gvt.filter.PadRable;
  
  import org.apache.batik.refimpl.bridge.resources.Messages;
  import org.apache.batik.refimpl.gvt.filter.ConcreteConvolveMatrixRable;
  import org.apache.batik.refimpl.gvt.filter.ConcretePadRable;
  
  import org.apache.batik.util.SVGConstants;
  import org.apache.batik.util.UnitProcessor;
  
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  import org.w3c.dom.css.CSSStyleDeclaration;
  
  /**
   * This class bridges an SVG <tt>feConvolveMatrix</tt> element with a concrete
   * <tt>ConvolveMatrixRable</tt>
   *
   * @author <a href="mailto:Thomas.DeWeese@Kodak.com">Thomas DeWeese</a>
   * @version $Id: SVGFeConvolveMatrixElementBridge.java,v 1.1 2001/01/05 15:49:18 deweese Exp $
   */
  public class SVGFeConvolveMatrixElementBridge implements FilterPrimitiveBridge,
                                                         SVGConstants {
      /**
       * Returns the <tt>Filter</tt> that implements the filter
       * operation modeled by the input DOM element
       *
       * @param filteredNode the node to which the filter will be attached.
       * @param bridgeContext the context to use.
       * @param filterElement DOM element that represents a filter abstraction
       * @param in the <tt>Filter</tt> that represents the current
       *        filter input if the filter chain.
       * @param filterRegion the filter area defined for the filter chained
       *        the new node will be part of.
       * @param filterMap a map where the mediator can map a name to the
       *        <tt>Filter</tt> it creates. Other <tt>FilterBridge</tt>s
       *        can then access a filter node from the filterMap if they
       *        know its name.
       */
      public Filter create(GraphicsNode filteredNode,
                           BridgeContext bridgeContext,
                           Element filterElement,
                           Element filteredElement,
                           Filter in,
                           Rectangle2D filterRegion,
                           Map filterMap){
  
          // Extract kernel Order (Size)
          String attrStr;
          attrStr = filterElement.getAttributeNS(null, SVG_ORDER_ATTRIBUTE);
  
          Float orderPair[] = SVGUtilities.buildFloatPair(attrStr);
  
          int orderX=0, orderY=0;
          if (orderPair[0] != null) {
              orderX = (int)orderPair[0].floatValue();
              if (orderX != (int)orderPair[0].floatValue())
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.order.notPosInt", null));
          }
  
          if (orderX <= 0)
              throw new IllegalAttributeValueException
                  (Messages.formatMessage
                   ("feConvolveMatrix.order.notPosInt", null));
  
          if (orderPair[1] == null)
              orderY = orderX;
          else {
              orderY = (int)orderPair[1].floatValue();
              if (orderY != (int)orderPair[1].floatValue())
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.order.notPosInt", null));
          }
          if (orderY <= 0)
              throw new IllegalAttributeValueException
                  (Messages.formatMessage
                   ("feConvolveMatrix.order.notPosInt", null));
  
  
          float [] kernel = new float[orderX*orderY];
          attrStr = filterElement.getAttributeNS
              (null, SVG_KERNEL_MATRIX_ATTRIBUTE);
          {
              StringTokenizer st = new StringTokenizer(attrStr);
              int i=0;
              while (st.hasMoreTokens()) {
                  kernel[i++] = SVGUtilities.convertSVGNumber
                      (SVG_KERNEL_MATRIX_ATTRIBUTE, st.nextToken());
                  if (i == orderX*orderY) break;
              }
  
              if (st.hasMoreTokens())
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.kernelMatrix.tooMany", null));
  
              if (i != orderX*orderY)
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.kernelMatrix.notEnough", null));
          }
  
          attrStr = filterElement.getAttributeNS(null, SVG_DIVISOR_ATTRIBUTE);
          float divisor = 0;
          if (attrStr.length() != 0) {
              divisor = SVGUtilities.convertSVGNumber
                  (SVG_DIVISOR_ATTRIBUTE, attrStr);
          } else {
              // Default is sum of kernel values (if sum is zero then 1.0).
              for (int i=0; i<kernel.length; i++)
                  divisor += kernel[i];
              if (divisor == 0.0f) divisor = 1.0f;
          }
          if (divisor == 0.0f) 
              throw new IllegalAttributeValueException
                  (Messages.formatMessage
                       ("feConvolveMatrix.divisor.zero", null));
  
          attrStr = filterElement.getAttributeNS(null, SVG_BIAS_ATTRIBUTE);
          float bias = 0.0f;
          if (attrStr.length() != 0) {
              bias = SVGUtilities.convertSVGNumber(SVG_BIAS_ATTRIBUTE, attrStr);
          }
  
  
          attrStr = filterElement.getAttributeNS(null, SVG_TARGET_X_ATTRIBUTE);
          int targetX=orderX/2;
          if (attrStr.length() != 0) {
              targetX = SVGUtilities.convertSVGInteger
                  (SVG_TARGET_X_ATTRIBUTE, attrStr);
          }
          if ((targetX < 0) || (targetX >= orderX))
              throw new IllegalAttributeValueException
                  (Messages.formatMessage
                   ("feConvolveMatrix.targetX.invalid", null));
  
  
          attrStr = filterElement.getAttributeNS(null, SVG_TARGET_Y_ATTRIBUTE);
          int targetY=orderY/2;
          if (attrStr.length() != 0) {
              targetY = SVGUtilities.convertSVGInteger
                  (SVG_TARGET_Y_ATTRIBUTE, attrStr);
          }
          if ((targetY < 0) || (targetY >= orderY))
              throw new IllegalAttributeValueException
                  (Messages.formatMessage
                   ("feConvolveMatrix.targetY.invalid", null));
  
  
          attrStr = filterElement.getAttributeNS(null, SVG_EDGE_MODE_ATTRIBUTE);
          PadMode padMode = PadMode.REPLICATE;
          if (attrStr.length() != 0) {
              attrStr = attrStr.toLowerCase();
  
              if (attrStr.equals(SVG_DUPLICATE_VALUE))
                  padMode = PadMode.REPLICATE;
              else if (attrStr.equals(SVG_WRAP_VALUE))
                  padMode = PadMode.WRAP;
              else if (attrStr.equals(SVG_NONE_VALUE))
                  padMode = PadMode.ZERO_PAD;
              else
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.edgeMode.invalid",
                                         new Object[] { attrStr }));
          }
  
          attrStr = filterElement.getAttributeNS
              (null, SVG_KERNEL_UNIT_LENGTH_ATTRIBUTE);
          double [] kernelUnitLength = null;
          if (attrStr.length() != 0) {
              Float [] fp = SVGUtilities.buildFloatPair(attrStr);
              kernelUnitLength = new double[2];
  
              if (fp[0] != null)
                  kernelUnitLength[0] = fp[0].floatValue();
  
              if (fp[1] != null)
                  kernelUnitLength[1] = fp[1].floatValue();
              else
                  kernelUnitLength[1] = kernelUnitLength[0];
          }
  
          if (kernelUnitLength != null) {
              if (kernelUnitLength[0] <= 0)
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.kernelUnitLength.notPositive", null));
              if (kernelUnitLength[1] <= 0)
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.kernelUnitLength.notPositive", null));
          }
  
          attrStr = filterElement.getAttributeNS
              (null, SVG_PRESERVE_ALPHA_ATTRIBUTE);
          boolean preserveAlpha = false;
          if (attrStr.length() != 0) {
              attrStr = attrStr.toLowerCase();
              if (attrStr.equals("false"))
                  preserveAlpha = false;
              else if (attrStr.equals("true"))
                  preserveAlpha = true;
              else
                  throw new IllegalAttributeValueException
                      (Messages.formatMessage
                       ("feConvolveMatrix.preserveAlpha.invalid",
                                         new Object[] { attrStr }));
          }
  
          // Get source
          String inAttr = filterElement.getAttributeNS(null, SVG_IN_ATTRIBUTE);
          in = CSSUtilities.getFilterSource(filteredNode,
                                            inAttr,
                                            bridgeContext,
                                            filteredElement,
                                            in,
                                            filterMap);
  
          if (in == null)
              return null;
  
          //
          // The default region is the input source's region unless the
          // source is SourceGraphics, in which case the default region
          // is the filter chain's region
          //
          Filter sourceGraphics = (Filter)filterMap.get(VALUE_SOURCE_GRAPHIC);
  
          Rectangle2D defaultRegion = in.getBounds2D();
          if (in == sourceGraphics) {
              defaultRegion = filterRegion;
          }
  
          CSSStyleDeclaration cssDecl
              = bridgeContext.getViewCSS().getComputedStyle(filterElement, null);
  
          UnitProcessor.Context uctx
              = new DefaultUnitProcessorContext(bridgeContext, cssDecl);
  
          GraphicsNodeRenderContext rc = 
                           bridgeContext.getGraphicsNodeRenderContext();
          Rectangle2D convolveArea
              = SVGUtilities.convertFilterPrimitiveRegion(filterElement,
                                                          filteredElement,
                                                          defaultRegion,
                                                          filteredNode,
                                                          rc,
                                                          uctx);
  
          PadRable pad;
          pad = new ConcretePadRable(in, convolveArea, PadMode.ZERO_PAD);
  
          // Build filter
          ConvolveMatrixRable convolve;
          convolve = new ConcreteConvolveMatrixRable(pad);
  
          // Rotate the kernel 180 deg.
          int len2 = kernel.length/2;
          int len1 = kernel.length-1;
          for (int i=0; i<len2; i++) {
              float tmp      = kernel[i];
              kernel[i]      = kernel[len1-i];
              kernel[len1-i] = tmp;
          }
  
          for (int i=0; i<kernel.length; i++)
              kernel[i] /= divisor;
          
          convolve.setKernel(new Kernel(orderX, orderY, kernel));
          convolve.setTarget(new Point(targetX, targetY));
          convolve.setBias(bias);
          convolve.setEdgeMode(padMode);
          convolve.setKernelUnitLength(kernelUnitLength);
          convolve.setPreserveAlpha(preserveAlpha);
  
          // Get result attribute if any
          String result = filterElement.getAttributeNS(null,ATTR_RESULT);
          if((result != null) && (result.trim().length() > 0)){
              filterMap.put(result, convolve);
          }
  
          return convolve;
      }
  
      /**
       * Update the <tt>Filter</tt> object to reflect the current
       * configuration in the <tt>Element</tt> that models the filter.
       */
      public void update(BridgeMutationEvent evt) {
          // <!> FIXME : TODO
      }
  }
  
  
  
  1.6       +25 -8     xml-batik/sources/org/apache/batik/refimpl/gvt/filter/ConcreteBackgroundRable.java
  
  Index: ConcreteBackgroundRable.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/refimpl/gvt/filter/ConcreteBackgroundRable.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- ConcreteBackgroundRable.java	2000/12/19 17:56:45	1.5
  +++ ConcreteBackgroundRable.java	2001/01/05 15:49:18	1.6
  @@ -40,7 +40,7 @@
    * createRendering methods.
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: ConcreteBackgroundRable.java,v 1.5 2000/12/19 17:56:45 billh Exp $
  + * @version $Id: ConcreteBackgroundRable.java,v 1.6 2001/01/05 15:49:18 deweese Exp $
    */
   public class ConcreteBackgroundRable
       extends    AbstractRable {
  @@ -237,6 +237,12 @@
       public Filter getBackground(GraphicsNode gn,
                                   GraphicsNode child,
                                   GraphicsNodeRenderContext rc) {
  +        if (gn == null) {
  +            throw new IllegalArgumentException
  +                ("BackgroundImage requested yet no parent has " +
  +                 "'enable-background:new'");
  +        }
  +
           Rectangle2D r2d = null;
           if (gn instanceof CompositeGraphicsNode) {
               CompositeGraphicsNode cgn = (CompositeGraphicsNode)gn;
  @@ -246,27 +252,39 @@
           Vector srcs = new Vector();
           if (r2d == null) {
               Filter f = getBackground(gn.getParent(), gn, rc);
  -            if (f == null)
  -                return null;
  -            srcs.add(f);
  +            if (f != null)
  +              srcs.add(f);
           }
   
  +        GraphicsNodeRableFactory gnrf;
  +        gnrf = rc.getGraphicsNodeRableFactory();
  +
           if (child != null) {
               CompositeGraphicsNode cgn = (CompositeGraphicsNode)gn;
               List children = cgn.getChildren();
               Iterator i = children.iterator();
               while (i.hasNext()) {
                   GraphicsNode childGN = (GraphicsNode)i.next();
  +                // System.out.println("Parent: "      + cgn + 
  +                //                    "\n  Child: "   + child + 
  +                //                    "\n  ChildGN: " + childGN);
                   if (childGN == child)
                       break;
                   GraphicsNodeRable gnr;
  -                GraphicsNodeRableFactory gnrf;
  -                gnrf = rc.getGraphicsNodeRableFactory();
                   gnr  = gnrf.createGraphicsNodeRable(childGN, rc);
                   gnr.setUsePrimitivePaint(false);
                   srcs.add(gnr);
               }
           }
  +        /*  If this is uncommented then children appear in background img.
  +        else {
  +            // System.out.println("Parent: "      + gn);
  +            GraphicsNodeRable gnr;
  +            gnr  = gnrf.createGraphicsNodeRable(gn);
  +            srcs.add(gnr);
  +        }
  +        */
  +
           if (srcs.size() == 0)
               return null;
   
  @@ -328,12 +346,11 @@
           Filter f = getBackground(node, null, gnrc);
           if ( f == null)
               return null;
  -
           // org.apache.batik.test.gvt.ImageDisplay.showImage
           //     ("PrePad", f.createRendering(renderContext));
   
           Rectangle2D r2d = getBounds2D();
  -        f = new ConcretePadRable(f, r2d, PadMode.ZERO_PAD);
  +        // f = new ConcretePadRable(f, r2d, PadMode.ZERO_PAD);
           // System.out.println("Bounds: " + r2d);
   
           RenderedImage ri = f.createRendering(renderContext);
  
  
  
  1.2       +220 -4    xml-batik/sources/org/apache/batik/refimpl/gvt/filter/ConcreteConvolveMatrixRable.java
  
  Index: ConcreteConvolveMatrixRable.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/refimpl/gvt/filter/ConcreteConvolveMatrixRable.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ConcreteConvolveMatrixRable.java	2000/12/11 13:44:22	1.1
  +++ ConcreteConvolveMatrixRable.java	2001/01/05 15:49:19	1.2
  @@ -8,19 +8,37 @@
   
   package org.apache.batik.refimpl.gvt.filter;
   
  +import java.awt.Point;
  +import java.awt.RenderingHints;
  +import java.awt.Shape;
  +
  +import java.awt.geom.Rectangle2D;
  +import java.awt.geom.AffineTransform;
  +
  +import java.awt.image.BufferedImage;
  +import java.awt.image.BufferedImageOp;
  +import java.awt.image.ColorModel;
  +import java.awt.image.ConvolveOp;
   import java.awt.image.Kernel;
  +import java.awt.image.Raster;
   import java.awt.image.RenderedImage;
   import java.awt.image.renderable.RenderContext;
  +import java.awt.image.WritableRaster;
   
   import org.apache.batik.gvt.filter.PadMode;
   import org.apache.batik.gvt.filter.ConvolveMatrixRable;
   import org.apache.batik.gvt.filter.Filter;
  +import org.apache.batik.gvt.filter.CachableRed;
   
   /**
    * Convolves an image with a convolution matrix.
    *
  + * Known limitations:
  + *   Does not support bias other than zero - pending 16bit pathway
  + *   Does not support edgeMode="wrap" - pending Tile code.
  + *
    * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
  - * @version $Id: ConcreteConvolveMatrixRable.java,v 1.1 2000/12/11 13:44:22 deweese Exp $
  + * @version $Id: ConcreteConvolveMatrixRable.java,v 1.2 2001/01/05 15:49:19 deweese Exp $
    */
   public class ConcreteConvolveMatrixRable 
       extends    AbstractRable 
  @@ -28,10 +46,14 @@
   {
   
       Kernel kernel;
  -    double bias;
  +    Point  target;
  +    float bias;
       PadMode edgeMode;
  +    float [] kernelUnitLength = new float[2];
  +
  +    boolean preserveAlpha = false;;
   
  -    ConcreteConvolveMatrixRable(Filter source) {
  +    public ConcreteConvolveMatrixRable(Filter source) {
           super(source);
       }
   
  @@ -60,6 +82,14 @@
           this.kernel = k;
       }
   
  +    public Point getTarget() {
  +        return (Point)target.clone();
  +    }
  +
  +    public void setTarget(Point pt) {
  +        this.target = (Point)pt.clone();
  +    }
  +
       /**
        * Returns the shift value to apply to the result of convolution
        */
  @@ -72,7 +102,7 @@
        */
       public void setBias(double bias) {
           touch();
  -        this.bias = bias;
  +        this.bias = (float)bias;
       }
   
       /**
  @@ -90,8 +120,194 @@
           this.edgeMode = edgeMode;
       }
   
  +    /**
  +     * Returns the [x,y] distance in user space between kernel values
  +     */
  +    public double [] getKernelUnitLength() {
  +        if (kernelUnitLength == null) 
  +            return null;
  +
  +        double [] ret = new double[2];
  +        ret[0] = kernelUnitLength[0];
  +        ret[1] = kernelUnitLength[1];
  +        return ret;
  +    }
  +
  +    /**
  +     * Sets the [x,y] distance in user space between kernel values
  +     * If set to zero then device space will be used.
  +     */
  +    public void setKernelUnitLength(double [] kernelUnitLength) {
  +        touch();
  +        if (kernelUnitLength == null) {
  +            this.kernelUnitLength = null;
  +            return;
  +        }
  +
  +        if (this.kernelUnitLength == null)
  +            this.kernelUnitLength = new float[2];
  +            
  +        this.kernelUnitLength[0] = (float)kernelUnitLength[0];
  +        this.kernelUnitLength[1] = (float)kernelUnitLength[1];
  +    }
  +
  +    /**
  +     * Returns false if the convolution should affect the Alpha channel
  +     */
  +    public boolean getPreserveAlpha() {
  +        return preserveAlpha;
  +    }
  +
  +    /**
  +     * Sets Alpha channel handling.
  +     * A value of False indicates that the convolution should apply to
  +     * the Alpha Channel
  +     */
  +    public void setPreserveAlpha(boolean preserveAlpha) {
  +        touch();
  +        this.preserveAlpha = preserveAlpha;
  +    }
  +
       public RenderedImage createRendering(RenderContext rc) {
  -        return null;
  +        // Just copy over the rendering hints.
  +        RenderingHints rh = rc.getRenderingHints();
  +        if (rh == null) rh = new RenderingHints(null);
  +
  +        // update the current affine transform
  +        AffineTransform at = rc.getTransform();
  +
  +
  +        // This splits out the scale and applies it
  +        // prior to the Gaussian.  Then after appying the gaussian
  +        // it applies the shear (rotation) and translation components.
  +        double sx = at.getScaleX();
  +        double sy = at.getScaleY();
  +
  +        double shx = at.getShearX();
  +        double shy = at.getShearY();
  +
  +        double tx = at.getTranslateX();
  +        double ty = at.getTranslateY();
  +
  +        // The Scale is the "hypotonose" of the matrix vectors.  This
  +        // represents the complete scaling value from user to an
  +        // intermediate space that is scaled similarly to device
  +        // space.
  +        double scaleX = Math.sqrt(sx*sx + shy*shy);
  +        double scaleY = Math.sqrt(sy*sy + shx*shx);
  +
  +        // These values represent the scale factor to the intermediate
  +        // coordinate system where we will apply our convolution.
  +        if (kernelUnitLength != null) {
  +            if (kernelUnitLength[0] > 0.0) 
  +                scaleX = 1/kernelUnitLength[0];
  +        
  +            if (kernelUnitLength[1] > 0.0) 
  +                scaleY = 1/kernelUnitLength[1];
  +        }
  +        
  +        Shape aoi = rc.getAreaOfInterest();
  +        if(aoi == null)
  +            aoi = getBounds2D();
  +
  +        Rectangle2D r = aoi.getBounds2D();
  +
  +        int kw = kernel.getWidth();
  +        int kh = kernel.getHeight();
  +        int kx = target.x;
  +        int ky = target.y;
  +
  +        // Grow the region in usr space.
  +        { 
  +            double rx0 = r.getX() -(kx/scaleX);
  +            double ry0 = r.getY() -(ky/scaleY);
  +            double rx1 = rx0 + r.getWidth()  + (kw-1)/scaleX;
  +            double ry1 = ry0 + r.getHeight() + (kh-1)/scaleY;
  +            r = new Rectangle2D.Double(Math.floor(rx0),
  +                                       Math.floor(ry0),
  +                                       Math.ceil (rx1-Math.floor(rx0)),
  +                                       Math.ceil (ry1-Math.floor(ry0)));
  +        }
  +        // This will be the affine transform between our usr space and
  +        // an intermediate space which is scaled according to
  +        // kernelUnitLength and is axially aligned with our user
  +        // space.
  +        AffineTransform srcAt 
  +            = AffineTransform.getScaleInstance(scaleX, scaleY);
  +
  +        // Here we update the translate to account for the phase shift
  +        // (if any) introduced by setting targetX, targetY in SVG.
  +        tx += target.x - kernel.getXOrigin();
  +        ty += target.y - kernel.getYOrigin();
  +
  +        // This is the affine transform between our intermediate
  +        // coordinate space (where the convolution takes place) and
  +        // the real device space, or null (if we don't need an
  +        // intermediate space).
  +
  +        // The shear/rotation simply divides out the
  +        // common scale factor in the matrix.
  +        AffineTransform resAt = new AffineTransform(sx/scaleX, shy/scaleX,
  +                                                    shx/scaleY, sy/scaleY,
  +                                                    tx, ty);
  +
  +        RenderedImage ri;
  +        ri = getSource().createRendering(new RenderContext(srcAt, r, rh));
  +        if (ri == null)
  +            return null;
  +
  +        CachableRed cr;
  +        cr = ConcreteRenderedImageCachableRed.wrap(ri);
  +
  +        Shape devShape = srcAt.createTransformedShape(aoi);
  +        r = devShape.getBounds2D();
  +        r = new Rectangle2D.Double(Math.floor(r.getX()-kx), 
  +                                   Math.floor(r.getY()-ky),
  +                                   Math.ceil (r.getX()+r.getWidth())-
  +                                   Math.floor(r.getX())+(kw-1), 
  +                                   Math.ceil (r.getY()+r.getHeight())-
  +                                   Math.floor(r.getY())+(kh-1));
  +
  +        if (!r.getBounds().equals(cr.getBounds())) {
  +            if (edgeMode == PadMode.WRAP)
  +                throw new IllegalArgumentException
  +                    ("edgeMode=\"wrap\" is not supported by ConvolveMatrix.");
  +            cr = new PadRed(cr, r.getBounds(), edgeMode, rh);
  +        }
  +
  +        if (bias != 0.0)
  +            throw new IllegalArgumentException
  +                ("Only bias equals zero is supported in ConvolveMatrix.");
  +        
  +        BufferedImageOp op = new ConvolveOp(kernel, 
  +                                            ConvolveOp.EDGE_NO_OP,
  +                                            rh);
  +
  +        ColorModel cm = cr.getColorModel();
  +
  +        // OK this is a bit of a cheat. We Pull the DataBuffer out of
  +        // The read-only raster that getData gives us. And use it to
  +        // build a WritableRaster.  This avoids a copy of the data.
  +        Raster rr = cr.getData();
  +        Point  pt = new Point(0,0);
  +        WritableRaster wr = Raster.createWritableRaster(rr.getSampleModel(),
  +                                                        rr.getDataBuffer(),
  +                                                        pt);
  +        
  +        BufferedImage srcBI;
  +        srcBI = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null);
  +
  +        BufferedImage destBI;
  +        destBI = op.filter(srcBI, null);
  +
  +        cr = new ConcreteBufferedImageCachableRed(destBI,
  +                                                  (int)r.getX(),
  +                                                  (int)r.getY());
  +        cr = new PadRed(cr, r.getBounds(), PadMode.ZERO_PAD, rh);
  +        if (!resAt.isIdentity())
  +            cr = new AffineRed(cr, resAt, null);
  +
  +        return cr;
       }
       
   }
  
  
  
  1.9       +3 -3      xml-batik/sources/org/apache/batik/refimpl/gvt/filter/ConcreteGaussianBlurRable.java
  
  Index: ConcreteGaussianBlurRable.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/refimpl/gvt/filter/ConcreteGaussianBlurRable.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- ConcreteGaussianBlurRable.java	2000/11/21 20:54:22	1.8
  +++ ConcreteGaussianBlurRable.java	2001/01/05 15:49:19	1.9
  @@ -33,7 +33,7 @@
    * GaussianBlurRable implementation
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com>Vincent Hardy</a>
  - * @version $Id: ConcreteGaussianBlurRable.java,v 1.8 2000/11/21 20:54:22 deweese Exp $
  + * @version $Id: ConcreteGaussianBlurRable.java,v 1.9 2001/01/05 15:49:19 deweese Exp $
    */
   public class ConcreteGaussianBlurRable
       extends    AbstractRable
  @@ -220,7 +220,7 @@
               return null;
   
           CachableRed cr;
  -        cr = new ConcreteRenderedImageCachableRed(ri);
  +        cr = ConcreteRenderedImageCachableRed.wrap(ri);
   
           Shape devShape = srcAt.createTransformedShape(aoi);
           r = devShape.getBounds2D();
  @@ -231,7 +231,7 @@
           if (!r.getBounds().equals(cr.getBounds()))
               cr = new PadRed(cr, r.getBounds(), PadMode.ZERO_PAD, rh);
           
  -        ColorModel cm = ri.getColorModel();
  +        ColorModel cm = cr.getColorModel();
   
           // OK this is a bit of a cheat. We Pull the DataBuffer out of
           // The read-only raster that getData gives us. And use it to
  
  
  
  1.4       +180 -2    xml-batik/sources/org/apache/batik/refimpl/gvt/filter/PadRed.java
  
  Index: PadRed.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/refimpl/gvt/filter/PadRed.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- PadRed.java	2000/11/17 19:40:17	1.3
  +++ PadRed.java	2001/01/05 15:49:19	1.4
  @@ -29,11 +29,12 @@
    * This is an implementation of a Pad operation as a RenderedImage.
    *
    * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
  - * @version $Id: PadRed.java,v 1.3 2000/11/17 19:40:17 deweese Exp $ */
  + * @version $Id: PadRed.java,v 1.4 2001/01/05 15:49:19 deweese Exp $ */
   public class PadRed extends AbstractRed {
   
       static final boolean DEBUG=false;
   
  +    PadMode padMode;
       RenderingHints hints;
   
       /**
  @@ -54,6 +55,8 @@
                 bounds.x, bounds.y,
                 null);
   
  +        this.padMode = padMode;
  +
           if (DEBUG) {
               System.out.println("Src: " + src + " Bounds: " + bounds + 
                                  " Off: " +
  @@ -61,6 +64,7 @@
                                  src.getTileGridYOffset());
           }
           this.hints = hints;
  +
       }
   
       public WritableRaster copyData(WritableRaster wr) {
  @@ -80,6 +84,18 @@
               src.copyData(srcWR);
           }
   
  +        if (padMode == PadMode.ZERO_PAD) {
  +            handleZero(wr);
  +        } else if (padMode == PadMode.REPLICATE) {
  +            handleReplicate(wr);
  +        } else if (padMode == PadMode.WRAP) {
  +            handleWrap(wr);
  +        }
  +
  +        return wr;
  +    }
  +
  +    protected void handleZero(WritableRaster wr) {
           // NOTE: I'm ignoring the pad mode here. I really need
           //       to check what the mode is and pad out the edges
           //       of wr.  For now I just zero them...
  @@ -97,6 +113,11 @@
           // Fully transparent black.
           g2d.setColor(new Color(0,0,0,0));
                              
  +        // Get my source.
  +        CachableRed src  = (CachableRed)getSources().get(0);
  +        Rectangle   srcR = src.getBounds();
  +        Rectangle   wrR  = wr.getBounds();
  +
           int x      = wrR.x;
           int y      = wrR.y;
           int width  = wrR.width;
  @@ -182,8 +203,165 @@
               g2d.fillRect(x0, y, w, height);
               width-=w;
           }
  +    }
   
  -        return wr;
  +
  +    protected void handleReplicate(WritableRaster wr) {
  +        // Get my source.
  +        CachableRed src  = (CachableRed)getSources().get(0);
  +        Rectangle   srcR = src.getBounds();
  +        Rectangle   wrR  = wr.getBounds();
  +
  +        int x      = wrR.x;
  +        int y      = wrR.y;
  +        int width  = wrR.width;
  +        int height = wrR.height;
  +
  +        Rectangle   r    = wrR.intersection(srcR);
  +
  +        // We split the edge drawing up into four parts.
  +        //
  +        //  +-----------------------------+
  +        //  | 3    | 1             | 4    |
  +        //  |      +---------------+      |
  +        //  /      /               /      /
  +        //  /      / src           /      /
  +        //  /      /               /      /
  +        //  /      /               /      /
  +        //  |      +---------------+      |
  +        //  |      | 2             |      |
  +        //  +-----------------------------+
  +        // 
  +
  +        // Draw #1
  +        if (y < srcR.y) {
  +            int repW = r.width;
  +            int repX = srcR.x;
  +            int wrX  = srcR.x;
  +            int wrY  = y;
  +            if (x+width <= srcR.x) {
  +                // we are off to the left of src. so set repX to the
  +                // left most pixel...
  +                repW = 1;
  +                repX = srcR.x;
  +                wrX  = x+width-1;
  +            } else if (x >= srcR.x+srcR.width) {
  +                // we are off to the right of src, so set repX to
  +                // the right most pixel
  +                repW = 1;
  +                repX = srcR.x+srcR.width-1;
  +                wrX  = x;
  +            }
  +
  +            // This fills the top row of section 1 from src (we
  +            // go to src instead of getting the data from wr because
  +            // in some cases wr will be completely off the top of src
  +            WritableRaster wr1 = wr.createWritableChild(wrX, wrY,
  +                                                        repW, 1, 
  +                                                        repX, srcR.y, null);
  +            src.copyData(wr1);
  +            wrY++;
  +
  +            int endY = srcR.y;
  +            if (y+height < endY) endY = y+height;
  +
  +            if (wrY < endY) {
  +                int [] pixels = wr.getPixels(wrX, wrY-1, 
  +                                             repW, 1, (int [])null);
  +                while (wrY < srcR.y) {
  +                    wr.setPixels(wrX, wrY, repW, 1, pixels);
  +                    wrY++;
  +                }
  +            }
  +        }
  +        
  +        // Draw #2
  +        if ((y+height) > (srcR.y+srcR.height)) {
  +            int repW = r.width;
  +            int repX = srcR.x;
  +            int repY = srcR.y+srcR.height-1;
  +
  +            int wrX  = srcR.x;
  +            int wrY  = srcR.y+srcR.height;
  +            if (wrY < y) wrY = y;
  +
  +            if (x+width <= srcR.x) {
  +                // we are off to the left of src. so set repX to the
  +                // left most pixel...
  +                repW = 1;
  +                repX = srcR.x;
  +                wrX  = x+width-1;
  +            } else if (x >= srcR.x+srcR.width) {
  +                // we are off to the right of src, so set repX to
  +                // the right most pixel
  +                repW = 1;
  +                repX = srcR.x+srcR.width-1;
  +                wrX  = x;
  +            }
  +
  +            // First we get the top row of pixels from src. (we
  +            // go to src instead of getting the data from wr because
  +            // in some cases wr will be completely off the bottom of src).
  +            WritableRaster wr1 = wr.createWritableChild(wrX, wrY,
  +                                                        repW, 1, 
  +                                                        repX, repY, null);
  +            // This fills the top row of section 2 from src 
  +            src.copyData(wr1);
  +            wrY++;
  +
  +            int endY = y+height;
  +            if (wrY < endY) {
  +                // This fills the rest of section 2 from the first line.
  +                int [] pixels = wr.getPixels(wrX, wrY-1, 
  +                                             repW, 1, (int [])null);
  +                while (wrY < endY) {
  +                    wr.setPixels(wrX, wrY, repW, 1, pixels);
  +                    wrY++;
  +                }
  +            }
  +        }
  +                                                        
  +        // Draw #3
  +        if (x < srcR.x) {
  +            // We are garunteed that we have a column of pixels down
  +            // the edge of 1 and src.  We simply replicate this column
  +            // out to the edges of 2.
  +            int wrX = srcR.x;
  +            if (x+width <= srcR.x) {
  +                wrX = x+width-1;
  +            }
  +
  +            int xLoc = x;
  +            int [] pixels = wr.getPixels(wrX, y, 1, height, (int [])null);
  +            while (xLoc < wrX) {
  +                wr.setPixels(xLoc, y, 1, height, pixels);
  +                xLoc++;
  +            }
  +        }
  +
  +        // Draw #4
  +        if (x+width > srcR.x+srcR.width) {
  +            // We are garunteed that we have a column of pixels down
  +            // the edge of 1 and src.  We simply replicate this column
  +            // out to the edges of 3.
  +            int wrX = srcR.x+srcR.width-1;
  +            if (x >= srcR.x+srcR.width) {
  +                wrX = x;
  +            }
  +
  +            int xLoc = wrX+1;
  +            int endX = x+width-1;
  +            int [] pixels = wr.getPixels(wrX, y, 1, height, (int [])null);
  +            while (xLoc < endX) {
  +                wr.setPixels(xLoc, y, 1, height, pixels);
  +                xLoc++;
  +            }
  +        }
  +    }
  +
  +    protected void handleWrap(WritableRaster wr) {
  +
  +        handleZero(wr);
       }
   
           /**
  
  
  
  1.36      +4 -3      xml-batik/sources/org/apache/batik/util/SVGConstants.java
  
  Index: SVGConstants.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/util/SVGConstants.java,v
  retrieving revision 1.35
  retrieving revision 1.36
  diff -u -r1.35 -r1.36
  --- SVGConstants.java	2000/12/28 09:37:51	1.35
  +++ SVGConstants.java	2001/01/05 15:49:20	1.36
  @@ -13,7 +13,7 @@
    *
    * @author <a href="vincent.hardy@eng.sun.com">Vincent Hardy</a>
    * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
  - * @version $Id: SVGConstants.java,v 1.35 2000/12/28 09:37:51 hillion Exp $
  + * @version $Id: SVGConstants.java,v 1.36 2001/01/05 15:49:20 deweese Exp $
    */
   public interface SVGConstants extends CSSConstants {
       String SVG_PUBLIC_ID =
  @@ -101,7 +101,7 @@
       String SVG_DIVISOR_ATTRIBUTE = "divisor";
       String SVG_DX_ATTRIBUTE = "dx";
       String SVG_DY_ATTRIBUTE = "dy";
  -    String SVG_EDGE_MODE_ATTRIBUTE = "edgemode";
  +    String SVG_EDGE_MODE_ATTRIBUTE = "edgeMode";
       String SVG_ELEVATION_ATTRIBUTE = "elevation";
       String SVG_ENABLE_BACKGROUND_ATTRIBUTE = CSS_ENABLE_BACKGROUND_PROPERTY;
       String SVG_EXPONENT_ATTRIBUTE = "exponent";
  @@ -133,6 +133,7 @@
       String SVG_K3_ATTRIBUTE = "k3";
       String SVG_K4_ATTRIBUTE = "k4";
       String SVG_KERNEL_MATRIX_ATTRIBUTE = "kernelMatrix";
  +    String SVG_KERNEL_UNIT_LENGTH_ATTRIBUTE = "kernelUnitLength";
       String SVG_KERNEL_UNIT_LENGTH_X_ATTRIBUTE = "kernelUnitLengthX";
       String SVG_KERNEL_UNIT_LENGTH_Y_ATTRIBUTE = "kernelUnitLengthY";
       String ATTR_LIGHT_COLOR = "lightColor";
  @@ -147,7 +148,7 @@
       String SVG_OFFSET_ATTRIBUTE = "offset";
       String ATTR_OPACITY = CSS_OPACITY_PROPERTY;
       String SVG_OPERATOR_ATTRIBUTE = "operator";
  -    String ATTR_ORDER = "order";
  +    String SVG_ORDER_ATTRIBUTE = "order";
       String SVG_ORDER_X_ATTRIBUTE = "orderX";
       String SVG_ORDER_Y_ATTRIBUTE = "orderY";
       String ATTR_PATTERN_CONTENT_UNITS = "patternContentUnits";
  
  
  
  1.5       +2 -2      xml-batik/sources/org/apache/batik/util/awt/svg/SVGConvolveOp.java
  
  Index: SVGConvolveOp.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/util/awt/svg/SVGConvolveOp.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- SVGConvolveOp.java	2000/12/28 09:37:54	1.4
  +++ SVGConvolveOp.java	2001/01/05 15:49:20	1.5
  @@ -24,7 +24,7 @@
    * an SVG filter descriptor.
    *
    * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
  - * @version $Id: SVGConvolveOp.java,v 1.4 2000/12/28 09:37:54 hillion Exp $
  + * @version $Id: SVGConvolveOp.java,v 1.5 2001/01/05 15:49:20 deweese Exp $
    * @see                org.apache.batik.util.awt.svg.SVGBufferedImageOp
    */
   public class SVGConvolveOp extends AbstractSVGFilterConverter{
  @@ -76,7 +76,7 @@
                   domFactory.createElement(SVG_FE_CONVOLVE_MATRIX_TAG);
   
               // Convert the kernel size
  -            feConvolveMatrixDef.setAttribute(ATTR_ORDER,
  +            feConvolveMatrixDef.setAttribute(SVG_ORDER_ATTRIBUTE,
                                                kernel.getWidth() + SPACE +
                                                kernel.getHeight());