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/25 22:48:05 UTC

cvs commit: xml-batik/sources/org/apache/batik/ext/awt/image/rendered AbstractRed.java

deweese     01/01/25 13:48:05

  Modified:    samples/tests enableBackground.svg
               sources/org/apache/batik/ext/awt/image GraphicsUtil.java
               sources/org/apache/batik/ext/awt/image/renderable
                        CompositeRable8Bit.java
               sources/org/apache/batik/ext/awt/image/rendered
                        AbstractRed.java
  Log:
  1) Started adding documentation for GraphicsUtil.
  
  2) Added cases to handle 'odd' situations in CompositeRable where some of
     the sources are "null" (meaning fully transparent image for AOI).
  
  2a) Worked around a JDK bug affecting over mode.
  
  3) Fixed a bug in the calculation of minTileX/minTileY in AbstractRed.
  
  4) Checked in a corrected enableBackground, now that we properly handle
     clipping of sources to feOffset.
  
  Revision  Changes    Path
  1.5       +81 -113   xml-batik/samples/tests/enableBackground.svg
  
  Index: enableBackground.svg
  ===================================================================
  RCS file: /home/cvs/xml-batik/samples/tests/enableBackground.svg,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- enableBackground.svg	2000/12/11 13:44:21	1.4
  +++ enableBackground.svg	2001/01/25 21:48:04	1.5
  @@ -28,166 +28,134 @@
       <g id="testContent">
   
         <text x="225" y="40" class="title">
  -    	Enable-Background Test
  +        Enable-Background Test
         </text>
     
         <g transform="translate(0, 60)">
  -      <defs>
  -        <g id="uglyBlobs" >
  -          <circle id="Circle1" cx="20" cy="65" r="15" style="fill:orange" />
  -     
  -          <circle id="Circle2" cx="40" cy="55" r="15" style="fill:red" />
  -     
  -          <rect   id="Rect1"   x="20" y="35" width="15" height="70" 
  -                  style="fill:DarkBlue" />
  -     
  -          <rect   id="Rect2"   x="30" y="15" width="15" height="70" 
  -                  rx="10" ry="10"
  -                  style="fill:Yellow" />
  -        </g>
  -
  -    	<filter id="OffsetBGX" filterUnits="userSpaceOnUse"
  -                x="0" y="0" width="120" height="120" >
  -          <feOffset in="BackgroundImage" dx="60" dy="0" />
  -    	</filter>
  -
  -    	<filter id="OffsetBGY" filterUnits="userSpaceOnUse"
  -                x="0" y="140" width="440" height="120" >
  -          <feOffset in="BackgroundImage" dx="0" dy="140" />
  -    	</filter>
  +        <defs>
  +          <g id="uglyBlobs" >
  +            <circle id="Circle1" cx="20" cy="65" r="15" style="fill:orange" />
  +       
  +            <circle id="Circle2" cx="40" cy="55" r="15" style="fill:red" />
  +       
  +            <rect   id="Rect1"   x="20" y="35" width="15" height="70" 
  +                    style="fill:DarkBlue" />
  +       
  +            <rect   id="Rect2"   x="30" y="15" width="15" height="70" 
  +                    rx="10" ry="10"
  +                    style="fill:Yellow" />
  +          </g>
     
  -      </defs>
  +          <filter id="OffsetBGX" filterUnits="userSpaceOnUse"
  +                  x="0" y="0" width="120" height="120" >
  +            <feOffset in="BackgroundImage" dx="60" dy="0" />
  +          </filter>
  +   
  +          <filter id="OffsetBGY" filterUnits="userSpaceOnUse"
  +                  x="0" y="0" width="440" height="260" >
  +            <feOffset in="BackgroundImage" dx="0" dy="140" />
  +          </filter>
  +        </defs>
  +   
  +        <g transform="translate(0 40)" class="legend">
     
  -      <g transform="translate(0 40)" class="legend">
  -
  -        <!-- ============================================== -->
  -        <!-- Enable Backgourn_1_*                           -->
  -        <!-- ============================================== -->
  -        <g transform="translate(0 20)" class="row1"
  -           style="enable-background:new 19 30 403 60">
  -    	  <g id="c1" transform="translate(20 0)"  
  -             style="enable-background:new;" >
  +          <!-- ============================================== -->
  +          <!-- Enable Background_1_*                          -->
  +          <!-- ============================================== -->
  +          <g transform="translate(0 20)" class="row1"
  +             style="enable-background:new 19 30 403 60">
  +            <g id="c1" transform="translate(20 0)"  
  +               style="enable-background:new;" >
                 <rect x="0" y="0" width="60" height="120" style="fill:Beige"/>
  -        
  -    	      <use xlink:href="#uglyBlobs" />
  +             
  +              <use xlink:href="#uglyBlobs" />
                 <rect x="0" y="0" width="1" height="1"
                         style="filter:url(#OffsetBGX)" />
  -
  +             
                 <rect x="0" y="0" width="60" height="120" 
                       style="fill:none; stroke:black; stroke-width:2"/>
                 <rect x="60" y="0" width="60" height="120" 
                       style="fill:none; stroke:black; stroke-width:2"/>
                 <g transform="translate(60, 135)">
  -               <text x="0" y="0" style="text-anchor:middle">
  -                Left Copied to right
  -               </text>
  -             </g>
  -    	  </g>
  -
  -    	  <g id="c2" transform="translate(160 0)">
  +                <text x="0" y="0" style="text-anchor:middle">
  +                 Left Copied to right
  +                </text>
  +              </g>
  +            </g>
  +  
  +            <g id="c2" transform="translate(160 0)">
                 <line x1="-5" y1="20" x2="125" y2="45"
                       style="stroke-width:5; stroke:#AA3333"/>
  -
  +              
                 <line x1="-5" y1="100" x2="125" y2="75"
                       style="stroke-width:5; stroke:#AA3333"/>
  -
  +              
                 <g style="enable-background:new">
  -                <rect x="0" y="0" width="60" height="120" style="fill:Beige"/>
  +                <rect x="0" y="0" width="60" height="120" 
  +                      style="fill:Beige"/>
                   <g style="opacity: 0.75">
                     <rect x="5" y="5" width="50" height="50" 
                           style="fill:deepPink"/>
  -    	          <use xlink:href="#uglyBlobs" style="opacity:0.75"/>
  +                  <use xlink:href="#uglyBlobs" style="opacity:0.75"/>
                     <rect x="0" y="0" width="120" height="120" 
                           style="filter:url(#OffsetBGX)" />
                   </g>
                 </g>
  -
  +              
                 <rect x="0" y="0" width="60" height="120" 
                       style="fill:none; stroke:black; stroke-width:2"/>
                 <rect x="60" y="0" width="60" height="120" 
                       style="fill:none; stroke:black; stroke-width:2"/>
                 <g transform="translate(60, 135)">
  -               <text x="0" y="0" style="text-anchor:middle">
  -                Right is transparent
  -               </text>
  -             </g>
  -    	  </g>
  -  
  -    	  <g id="c2" transform="translate(300 0)">
  +                <text x="0" y="0" style="text-anchor:middle">
  +                 Right is transparent
  +                </text>
  +              </g>
  +            </g>
  +   
  +            <g id="c2" transform="translate(300 0)">
                 <line x1="-5" y1="20" x2="125" y2="45"
                       style="stroke-width:5; stroke:#AA3333"/>
  -
  +            
                 <line x1="-5" y1="100" x2="125" y2="75"
                       style="stroke-width:5; stroke:#AA3333"/>
  -
  +            
                 <rect x="0" y="0" width="60" height="120" style="fill:Beige"/>
                 <g style="enable-background:new">
                   <ellipse cx="25" cy="45" rx="20" ry="30" 
                            style="fill:#AA00CC" />
  -
  +            
                   <g style="opacity: 0.75">
  -    	          <use xlink:href="#uglyBlobs"/>
  +                  <use xlink:href="#uglyBlobs"/>
                     <rect x="0" y="0" width="120" height="120" 
                           style="filter:url(#OffsetBGX)" />
                   </g>
                 </g>
  -
  +            
                 <rect x="0" y="0" width="60" height="120" 
                       style="fill:none; stroke:black; stroke-width:2"/>
                 <rect x="60" y="0" width="60" height="120" 
                       style="fill:none; stroke:black; stroke-width:2"/>
                 <g transform="translate(60, 135)">
  -               <text x="0" y="0" style="text-anchor:middle">
  -                Blobs opaquely merged w/ oval
  -               </text>
  -             </g>
  -    	  </g>
  -
  -          <rect x="0" y="0" width="10" height="10"
  -                style="filter:url(#OffsetBGY)" />
  -
  -          <g transform="translate(220, 270)">
  -           <text x="0" y="0" style="text-anchor:middle">
  -            Copy of middle of first row (by setting enable-background bounds)
  -           </text>
  -         </g>
  -	</g>
  -
  -        <!-- ============================================== -->
  -        <!-- BGEnable _2_*                                  -->
  -        <!-- ==============================================
  -        <g transform="translate(0 160)" class="row2" >
  -    	  <g id="c1" transform="translate(20 0)">
  -              <rect x="0" y="0" width="120" height="120" style="fill:Beige"/>
  -              <g transform="translate(60, 130)">
  -               <text x="0" y="0" style="text-anchor:middle">
  -                Test Case 2_1
  -               </text>
  -             </g>
  -    	  </g>
  -
  -    	  <g id="c1" transform="translate(160 0)">
  -              <rect x="0" y="0" width="120" height="120" style="fill:Beige"/>
  -              <g transform="translate(60, 130)">
  -               <text x="0" y="0" style="text-anchor:middle">
  -                Test Case 2_2
  -               </text>
  -             </g>
  -    	  </g>
  -
  -    	  <g id="c1" transform="translate(300 0)">
  -              <rect x="0" y="0" width="120" height="120" style="fill:Beige"/>
  -              <g transform="translate(60, 130)">
  -               <text x="0" y="0" style="text-anchor:middle">
  -                Test Case 2_3
  -               </text>
  -             </g>
  -    	  </g>
  -      
  -    	</g>
  - -->
  -
  -      </g>
  +                <text x="0" y="0" style="text-anchor:middle">
  +                 Blobs opaquely merged w/ oval
  +                </text>
  +              </g>
  +            </g>
  +  
  +            <!-- ============================================== -->
  +            <!-- BGEnable _2_*                                  -->
  +            <!-- ============================================== -->
  +            <rect x="0" y="0" width="10" height="10"
  +                  style="filter:url(#OffsetBGY)" />
  +            
  +            <g transform="translate(220, 270)">
  +             <text x="0" y="0" style="text-anchor:middle">
  +              Copy of middle of first row (by setting enable-background bounds)
  +             </text>
  +            </g>
  +          </g>
  +        </g>
         </g>
       </g>
   
  @@ -195,5 +163,5 @@
       <!-- Batik sample mark                                             -->
       <!-- ============================================================= -->
       <use xlink:href="../batikLogo.svg#Batik_Tag_Box" />
  -    
  +   
   </svg>
  
  
  
  1.4       +327 -23   xml-batik/sources/org/apache/batik/ext/awt/image/GraphicsUtil.java
  
  Index: GraphicsUtil.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/GraphicsUtil.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- GraphicsUtil.java	2001/01/24 19:49:29	1.3
  +++ GraphicsUtil.java	2001/01/25 21:48:04	1.4
  @@ -10,6 +10,7 @@
   
   import java.awt.color.ColorSpace;
   
  +import java.awt.Color;
   import java.awt.Graphics2D;
   import java.awt.GraphicsConfiguration;
   import java.awt.Point;
  @@ -40,7 +41,10 @@
   import java.util.Iterator;
   
   import org.apache.batik.ext.awt.image.renderable.AffineRable;
  +import org.apache.batik.ext.awt.image.rendered.AffineRed;
   import org.apache.batik.ext.awt.image.rendered.CachableRed;
  +import org.apache.batik.ext.awt.image.rendered.MultiplyAlphaRed;
  +import org.apache.batik.ext.awt.image.rendered.PadRed;
   import org.apache.batik.ext.awt.image.renderable.CompositeRable;
   import org.apache.batik.ext.awt.image.renderable.CompositeRule;
   import org.apache.batik.ext.awt.image.renderable.Filter;
  @@ -61,15 +65,31 @@
    * implementations.
    *
    * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
  - * @version $Id: GraphicsUtil.java,v 1.3 2001/01/24 19:49:29 deweese Exp $
  + * @version $Id: GraphicsUtil.java,v 1.4 2001/01/25 21:48:04 deweese Exp $
    */
   public class GraphicsUtil {
   
  +    /**
  +     * Draws <tt>ri</tt> into <tt>g2d</tt>.  It does this be
  +     * requesting tiles from <tt>ri</tt> and drawing them individually
  +     * in <tt>g2d</tt> it also takes care of some colorspace and alpha
  +     * issues.
  +     * @param g2d The Graphics2D to draw into.
  +     * @param ri  The image to be drawn.
  +     */
       public static void drawImage(Graphics2D g2d,
                                    RenderedImage ri) {
           drawImage(g2d, wrap(ri));
       }
   
  +    /**
  +     * Draws <tt>cr</tt> into <tt>g2d</tt>.  It does this be
  +     * requesting tiles from <tt>ri</tt> and drawing them individually
  +     * in <tt>g2d</tt> it also takes care of some colorspace and alpha
  +     * issues.
  +     * @param g2d The Graphics2D to draw into.
  +     * @param cr  The image to be drawn.
  +     */
       public static void drawImage(Graphics2D g2d,
                                    CachableRed cr) {
           ColorModel  srcCM = cr.getColorModel();
  @@ -92,9 +112,91 @@
                   cr = convertTosRGB(cr);
               else if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB))
                   cr = convertToLsRGB(cr);
  -            srcCM = cr.getColorModel();
           }
   
  +        AffineTransform at = g2d.getTransform();
  +        Shape clip = g2d.getClip();
  +
  +        if ( false) {
  +            // There has been a problem where the render tries to
  +            // request a zero pixel high region (due to a bug in the
  +            // complex clip handling).  I have at least temporarily
  +            // worked around this by changing the alpha state in
  +            // CompositeRable which changes code paths enough that the
  +            // renderer doesn't try to construct a zero height
  +            // SampleModel (which dies).
  +            //
  +            // However I suspect that this fix is fragile (other code
  +            // paths may trigger the bug), eventually we may need to
  +            // reinstate this code, which handles the clipping for the
  +            // Graphics2D.
  +            if ((clip != null) &&
  +                !(clip instanceof Rectangle2D)) {
  +
  +                // Let's work in device space...
  +                cr = new AffineRed(cr, at, g2d.getRenderingHints());
  +
  +                g2d.setTransform(new AffineTransform());
  +
  +            // This is now the clip in device space...
  +                clip = g2d.getClip();
  +
  +                Rectangle clipR = clip.getBounds();
  +
  +                if (clip instanceof Rectangle2D)
  +                    // Simple clip rect...
  +                    cr = new PadRed(cr, clipR, PadMode.ZERO_PAD, null);
  +                else {
  +                    // Complex clip...
  +                    /*
  +                 * System.out.println("Clip:" + clip);
  +                 * System.out.println("ClipR: " + clipR);
  +                 * System.out.println("crR: " + cr.getBounds());
  +                 * System.out.println("at: " + at);
  +                 */
  +
  +                    if (clipR.intersects(cr.getBounds()) == false)
  +                        return; // Nothing to draw...
  +                    clipR = clipR.intersection(cr.getBounds());
  +
  +                    BufferedImage bi = new BufferedImage
  +                        (clipR.width, clipR.height,
  +                         BufferedImage.TYPE_BYTE_GRAY);
  +
  +                    Graphics2D big2d = bi.createGraphics();
  +                    big2d.setRenderingHints(g2d.getRenderingHints());
  +
  +                    big2d.translate(-clipR.x, -clipR.y);
  +                    big2d.setPaint(Color.white);
  +                    big2d.fill(clip);
  +                    big2d.dispose();
  +                
  +                    CachableRed cCr;
  +                    cCr = new BufferedImageCachableRed(bi, clipR.x, clipR.y);
  +                    cr     = new MultiplyAlphaRed     (cr, cCr);
  +                }
  +                g2d.setClip(null);
  +            }
  +
  +            if (false) {
  +                Rectangle    clipR = clip.getBounds();
  +                BufferedImage bi   = new BufferedImage
  +                    (clipR.width, clipR.height,
  +                     BufferedImage.TYPE_BYTE_GRAY);
  +
  +                Graphics2D big2d = bi.createGraphics();
  +                big2d.setRenderingHints(g2d.getRenderingHints());
  +
  +                big2d.translate(-clipR.x, -clipR.y);
  +                big2d.setPaint(Color.white);
  +                big2d.fill(clip);
  +                big2d.dispose();
  +                org.apache.batik.test.gvt.ImageDisplay.showImage
  +                    ("Big2d: ", bi);
  +            }
  +        }
  +
  +        srcCM = cr.getColorModel();
           ColorModel drawCM = srcCM;
           if ((drawCM.hasAlpha()) && (g2dCM.hasAlpha())) {
               if (drawCM.isAlphaPremultiplied() != 
  @@ -109,13 +211,6 @@
           BufferedImage bi = new BufferedImage
               (drawCM, wr, drawCM.isAlphaPremultiplied(), null);
   
  -        /*
  -        Graphics2D big2d = bi.createGraphics();
  -        // Fully transparent black.
  -        big2d.setColor(new java.awt.Color(0,0,0,0));
  -        big2d.setComposite(java.awt.AlphaComposite.Src);
  -        */
  -
           int xt0 = cr.getMinTileX();
           int xt1 = xt0+cr.getNumXTiles();
           int yt0 = cr.getMinTileY();
  @@ -127,7 +222,7 @@
           Rectangle tR  = new Rectangle(0,0,tw,th);
           Rectangle iR  = new Rectangle(0,0,0,0);
   
  -        if (false) {
  +        if (false)
               System.out.println("CRR: " + crR + " TG: [" +
                                  xt0 +"," +
                                  yt0 +"," +
  @@ -135,37 +230,69 @@
                                  yt1 +"] Off: " +
                                  cr.getTileGridXOffset() +"," +
                                  cr.getTileGridXOffset());
  -        }
   
           DataBuffer db = wr.getDataBuffer();
           int yloc = yt0*th+cr.getTileGridYOffset();
  -        for (int y=yt0; y<yt1; y++) {
  +        for (int y=yt0; y<yt1; y++, yloc += th) {
               int xloc = xt0*tw+cr.getTileGridXOffset();
  -            for (int x=xt0; x<xt1; x++) {
  +            for (int x=xt0; x<xt1; x++, xloc+=tw) {
  +                tR.x = xloc;
  +                tR.y = yloc;
  +                Rectangle2D.intersect(crR, tR, iR);
  +
                   wr = Raster.createWritableRaster(srcSM, db,
                                                    new Point(xloc, yloc));
                   cr.copyData(wr);
                   coerceData(wr, srcCM, drawCM.isAlphaPremultiplied());
   
  -                tR.x = xloc;
  -                tR.y = yloc;
  -                Rectangle2D.intersect(crR, tR, iR);
  -
  -                // Make sure we only draw the region that was writting...
  +                // Make sure we only draw the region that was written...
                   BufferedImage subBI;
                   subBI = bi.getSubimage(iR.x-xloc, iR.y-yloc,
                                          iR.width,  iR.height);
  -                if (false)
  -                    System.out.println("IR: " + iR);
  +                if (false) {
  +                    System.out.println("Drawing: " + tR);
  +                    System.out.println("IR: "      + iR);
  +                    subBI = new BufferedImage(subBI.getColorModel(),
  +                                              subBI.getRaster(),
  +                                              subBI.isAlphaPremultiplied(),
  +                                              null) {
  +                            public BufferedImage getSubimage(int x, int y,
  +                                                             int w, int h) {
  +                                Exception e = new Exception
  +                                    ("Sub: [" + x + ", " + y + ", " +
  +                                     w + ", " + h + "]");
  +                                e.printStackTrace();
  +                                if (w<=0) w= 1;
  +                                if (h<=0) h= 1;
  +                                return super.getSubimage(x,y,w,h);
  +                            }
  +                        };
  +                }
   
                   g2d.drawImage(subBI, null, iR.x, iR.y);
                   // big2d.fillRect(0, 0, tw, th);
  -                xloc += tw;
               }
  -            yloc += th;
           }
  +
  +        g2d.setClip(clip);
  +        g2d.setTransform(at);
       }
   
  +    /**
  +     * Draws a <tt>Filter</tt> (<tt>RenderableImage</tt>) into a
  +     * Graphics 2D after taking into account a particular
  +     * <tt>RenderContext</tt>.<p>
  +     *
  +     * This method also attempts to unwind the rendering chain a bit.
  +     * So it knows about certain operations (like affine, pad,
  +     * composite), rather than applying each of these operations in
  +     * turn it accounts for there affects through modifications to the
  +     * Graphics2D. This avoids generating lots of intermediate images.
  +     *
  +     * @param g2d    The Graphics to draw into.
  +     * @param filter The filter to draw
  +     * @param rc The render context that controls the drawing operation.  
  +     */
       public static void drawImage(Graphics2D    g2d,
                                    Filter        filter,
                                    RenderContext rc) {
  @@ -185,6 +312,19 @@
           g2d.setRenderingHints(origRH);
       }
   
  +    /**
  +     * Draws a <tt>Filter</tt> (<tt>RenderableImage</tt>) into a
  +     * Graphics 2D.<p>
  +     *
  +     * This method also attempts to unwind the rendering chain a bit.
  +     * So it knows about certain operations (like affine, pad,
  +     * composite), rather than applying each of these operations in
  +     * turn it accounts for there affects through modifications to the
  +     * Graphics2D.  This avoids generating lots of intermediate images.
  +     *
  +     * @param g2d    The Graphics to draw into.
  +     * @param filter The filter to draw
  +     */
       public static void drawImage(Graphics2D g2d,
                                    Filter     filter) {
           if (filter instanceof AffineRable) {
  @@ -278,18 +418,27 @@
           g2d.setTransform(at);
       }
   
  +    /**
  +     * Standard prebuilt Linear_sRGB color model with no alpha
  +     */
       public final static ColorModel Linear_sRGB =
           new DirectColorModel(ColorSpace.getInstance
                                (ColorSpace.CS_LINEAR_RGB), 24,
                                0x00FF0000, 0x0000FF00,
                                0x000000FF, 0x0, false,
                                DataBuffer.TYPE_INT);
  +    /**
  +     * Standard prebuilt Linear_sRGB color model with premultiplied alpha.
  +     */
       public final static ColorModel Linear_sRGB_Pre =
           new DirectColorModel(ColorSpace.getInstance
                                (ColorSpace.CS_LINEAR_RGB), 32,
                                0x00FF0000, 0x0000FF00,
                                0x000000FF, 0xFF000000, true,
                                DataBuffer.TYPE_INT);
  +    /**
  +     * Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
  +     */
       public final static ColorModel Linear_sRGB_Unpre =
           new DirectColorModel(ColorSpace.getInstance
                                (ColorSpace.CS_LINEAR_RGB), 32,
  @@ -297,18 +446,27 @@
                                0x000000FF, 0xFF000000, false,
                                DataBuffer.TYPE_INT);
   
  +    /**
  +     * Standard prebuilt sRGB color model with no alpha.
  +     */
       public final static ColorModel sRGB =
           new DirectColorModel(ColorSpace.getInstance
                                (ColorSpace.CS_sRGB), 24,
                                0x00FF0000, 0x0000FF00,
                                0x000000FF, 0x0, false,
                                DataBuffer.TYPE_INT);
  +    /**
  +     * Standard prebuilt sRGB color model with premultiplied alpha.
  +     */
       public final static ColorModel sRGB_Pre =
           new DirectColorModel(ColorSpace.getInstance
                                (ColorSpace.CS_sRGB), 32,
                                0x00FF0000, 0x0000FF00,
                                0x000000FF, 0xFF000000, true,
                                DataBuffer.TYPE_INT);
  +    /**
  +     * Standard prebuilt sRGB color model with unpremultiplied alpha.
  +     */
       public final static ColorModel sRGB_Unpre =
           new DirectColorModel(ColorSpace.getInstance
                                (ColorSpace.CS_sRGB), 32,
  @@ -316,12 +474,27 @@
                                0x000000FF, 0xFF000000, false,
                                DataBuffer.TYPE_INT);
   
  +    /**
  +     * Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
  +     * based on premult flag.
  +     * @param premult True if the ColorModel should have premultiplied alpha.
  +     * @return        a ColorMdoel with Linear sRGB colorSpace and
  +     *                the alpha channel set in accordance with 
  +     *                <tt>premult</tt>
  +     */
       public static ColorModel makeLinear_sRGBCM(boolean premult) {
           if (premult)
               return Linear_sRGB_Pre;
           return Linear_sRGB_Unpre;
       }
   
  +    /**
  +     * Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
  +     * @param width   The desired width of the BufferedImage
  +     * @param height  The desired height of the BufferedImage
  +     * @param premult The desired state of alpha premultiplied
  +     * @return        The requested BufferedImage.
  +     */
       public static BufferedImage makeLinearBufferedImage(int width,
                                                           int height,
                                                           boolean premult) {
  @@ -330,6 +503,17 @@
           return new BufferedImage(cm, wr, premult, null);
       }
   
  +    /**
  +     * This method will return a CacheableRed that has it's data in
  +     * the linear sRGB colorspace. If <tt>src</tt> is already in
  +     * linear sRGB then this method does nothing and returns <tt>src</tt>.
  +     * Otherwise it creates a transform that will convert
  +     * <tt>src</tt>'s output to linear sRGB and returns that CacheableRed.
  +     *
  +     * @param src The image to convert to linear sRGB.
  +     * @return    An equivilant image to <tt>src</tt> who's data is in 
  +     *            linear sRGB.
  +     */
       public static CachableRed convertToLsRGB(CachableRed src) {
           ColorModel cm = src.getColorModel();
           ColorSpace cs = cm.getColorSpace();
  @@ -339,6 +523,16 @@
           return new Any2LsRGBRed(src);
       }
   
  +    /**
  +     * This method will return a CacheableRed that has it's data in
  +     * the sRGB colorspace. If <tt>src</tt> is already in
  +     * sRGB then this method does nothing and returns <tt>src</tt>.
  +     * Otherwise it creates a transform that will convert
  +     * <tt>src</tt>'s output to sRGB and returns that CacheableRed.
  +     *
  +     * @param src The image to convert to sRGB.
  +     * @return    An equivilant image to <tt>src</tt> who's data is in sRGB.
  +     */
       public static CachableRed convertTosRGB(CachableRed src) {
           ColorModel cm = src.getColorModel();
           ColorSpace cs = cm.getColorSpace();
  @@ -348,6 +542,19 @@
           return new Any2sRGBRed(src);
       }
   
  +    /**
  +     * Convertes any RenderedImage to a CacheableRed.  <p>
  +     * If <tt>ri</tt> is already a CacheableRed it casts it down and
  +     * returns it.<p>
  +     *
  +     * In cases where <tt>ri</tt> is not already a CacheableRed it
  +     * wraps <tt>ri</tt> with a helper class.  The wrapped
  +     * CacheableRed "Pretends" that it has no sources since it has no
  +     * way of inteligently handling the dependency/dirty region calls 
  +     * if it exposed the source.
  +     * @param ri The RenderedImage to convert.
  +     * @return   a CacheableRed that contains the same data as ri.  
  +     */
       public static CachableRed wrap(RenderedImage ri) {
           if (ri instanceof CachableRed)
               return (CachableRed) ri;
  @@ -356,6 +563,14 @@
           return new RenderedImageCachableRed(ri);
       }
   
  +    /**
  +     * An internal optimized version of copyData designed to work on
  +     * Integer packed data with a SinglePixelPackedSampleModel.  Only
  +     * the region of overlap between src and dst is copied.
  +     *
  +     * @param src The source of the data
  +     * @param dst The destination for the data.
  +     */
       protected static void copyData_INT_PACK(Raster src, WritableRaster dst) {
           // System.out.println("Fast copyData");
           int x0 = dst.getMinX();
  @@ -422,13 +637,21 @@
           }
       }
   
  +    /**
  +     * Copies data from one raster to another. Only the region of
  +     * overlap between src and dst is copied.  <tt>Src</tt> and
  +     * <tt>Dst</tt> must have compatible SampleModels.
  +     *
  +     * @param src The source of the data
  +     * @param dst The destination for the data.  
  +     */
       public static void copyData(Raster src, WritableRaster dst) {
           if (is_INT_PACK_Data(src.getSampleModel(), false) &&
               is_INT_PACK_Data(dst.getSampleModel(), false)) {
               copyData_INT_PACK(src, dst);
               return;
           }
  -        System.out.println("Slow copyData");
  +        // System.out.println("Slow copyData");
   
           int x0 = dst.getMinX();
           if (x0 < src.getMinX()) x0 = src.getMinX();
  @@ -455,10 +678,42 @@
           }
       }
   
  +    /**
  +     * Creates a new raster that has a <b>copy</b> of the data in
  +     * <tt>ras</tt>.  This is highly optimized for speed.  There is
  +     * no provision for changing any aspect of the SampleModel.
  +     *
  +     * This method should be used when you need to change the contents
  +     * of a Raster that you do not "own" (ie the result of a
  +     * <tt>getData</tt> call).
  +     * @param ras The Raster to copy.
  +     * @return    A writable copy of <tt>ras</tt>
  +     */
       public static WritableRaster copyRaster(Raster ras) {
           return copyRaster(ras, ras.getMinX(), ras.getMinY());
       }
   
  +    
  +    /**
  +     * Creates a new raster that has a <b>copy</b> of the data in
  +     * <tt>ras</tt>.  This is highly optimized for speed.  There is
  +     * no provision for changing any aspect of the SampleModel.
  +     * However you can specify a new location for the returned raster.
  +     *
  +     * This method should be used when you need to change the contents
  +     * of a Raster that you do not "own" (ie the result of a
  +     * <tt>getData</tt> call).
  +     *
  +     * @param ras The Raster to copy.
  +     *
  +     * @param minX The x location for the upper left corner of the
  +     *             returned WritableRaster.
  +     *
  +     * @param minY The y location for the upper left corner of the
  +     *             returned WritableRaster.
  +     *
  +     * @return    A writable copy of <tt>ras</tt>
  +     */
       public static WritableRaster copyRaster(Raster ras, int minX, int minY) {
           WritableRaster newSrcWR;
           WritableRaster ret = Raster.createWritableRaster
  @@ -512,10 +767,51 @@
           return ret;
       }
   
  +    /**
  +     * Coerces <tt>ras</tt> to be writable.  The returned Raster continues to 
  +     * reference the DataBuffer from ras, so modifications to the returned
  +     * WritableRaster will be seen in ras.<p>
  +     *
  +     * This method should only be used if you need a WritableRaster due to
  +     * an interface (such as to construct a BufferedImage), but have no
  +     * intention of modifying the contents of the returned Raster.  If
  +     * you have any doubt about other users of the data in <tt>ras</tt>,
  +     * use copyRaster (above).
  +     * @param ras The raster to make writable.
  +     * @return    A Writable version of ras (shares DataBuffer with 
  +     *            <tt>ras</tt>).
  +     */
       public static WritableRaster makeRasterWritable(Raster ras) {
           return makeRasterWritable(ras, ras.getMinX(), ras.getMinY());
       }
   
  +    /**
  +     * Coerces <tt>ras</tt> to be writable.  The returned Raster continues to 
  +     * reference the DataBuffer from ras, so modifications to the returned
  +     * WritableRaster will be seen in ras.<p>
  +     *
  +     * You can specify a new location for the returned WritableRaster, this
  +     * is especially useful for constructing BufferedImages which require
  +     * the Raster to be at (0,0).
  +     *
  +     * This method should only be used if you need a WritableRaster due to
  +     * an interface (such as to construct a BufferedImage), but have no
  +     * intention of modifying the contents of the returned Raster.  If
  +     * you have any doubt about other users of the data in <tt>ras</tt>,
  +     * use copyRaster (above).
  +     *
  +     * @param ras The raster to make writable.
  +     *
  +     * @param minX The x location for the upper left corner of the
  +     *             returned WritableRaster.
  +     *
  +     * @param minY The y location for the upper left corner of the
  +     *             returned WritableRaster.
  +     *
  +     * @return A Writable version of <tT>ras</tt> with it's upper left
  +     *         hand coordinate set to minX, minY (shares it's DataBuffer 
  +     *         with <tt>ras</tt>).  
  +     */
       public static WritableRaster makeRasterWritable(Raster ras,
                                                       int minX, int minY) {
           WritableRaster ret = Raster.createWritableRaster
  @@ -530,6 +826,14 @@
           return ret;
       }
   
  +    /**
  +     * Create a new ColorModel with it's alpha premultiplied state matching
  +     * newAlphaPreMult.
  +     * @param cm The ColorModel to change the alpha premult state of.
  +     * @param newAlphaPreMult The new state of alpha premult.
  +     * @return   A new colorModel that has isAlphaPremultiplied()
  +     *           equal to newAlphaPreMult.
  +     */
       public static ColorModel
           coerceColorModel(ColorModel cm, boolean newAlphaPreMult) {
           if (cm.isAlphaPremultiplied() == newAlphaPreMult)
  
  
  
  1.3       +53 -6     xml-batik/sources/org/apache/batik/ext/awt/image/renderable/CompositeRable8Bit.java
  
  Index: CompositeRable8Bit.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/renderable/CompositeRable8Bit.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CompositeRable8Bit.java	2001/01/24 19:49:31	1.2
  +++ CompositeRable8Bit.java	2001/01/25 21:48:04	1.3
  @@ -13,6 +13,8 @@
   import java.util.List;
   import java.util.Iterator;
   
  +import java.awt.AlphaComposite;
  +import java.awt.Color;
   import java.awt.color.ColorSpace;
   import java.awt.Composite;
   import java.awt.CompositeContext;
  @@ -41,7 +43,7 @@
    * the image are applied in the order they are in the List given.
    *
    * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
  - * @version $Id: CompositeRable8Bit.java,v 1.2 2001/01/24 19:49:31 deweese Exp $
  + * @version $Id: CompositeRable8Bit.java,v 1.3 2001/01/25 21:48:04 deweese Exp $
    */
   public class CompositeRable8Bit
       extends    AbstractRable
  @@ -137,13 +139,19 @@
               Rectangle2D.intersect(r, aoiR, r);
           }
   
  +        // This BufferedImage must be unpremultiplied or else when we
  +        // go to draw things get loopy.  If you want to try backing
  +        // this out check if the rendering problem persists by
  +        // bringing up samples/tests/feComposite.svg and rotating a
  +        // few degrees.  The zoom in/out and pan around a bit, it
  +        // ussually dies fairly quickly.
           BufferedImage bi;
           if (csIsLinear)
               bi = GraphicsUtil.makeLinearBufferedImage
  -            (r.width, r.height, true);
  +            (r.width, r.height, false);
           else
               bi = new BufferedImage(r.width, r.height, 
  -                                   BufferedImage.TYPE_INT_ARGB_PRE);
  +                                   BufferedImage.TYPE_INT_ARGB);
   
           Graphics2D g2d = bi.createGraphics();
   
  @@ -232,10 +240,49 @@
   
               // Get our sources image...
               RenderedImage ri = filt.createRendering(rc);
  -            // No output image keep going
  -            // FIXX: Should we do something different for IN/OUT/ARITH???
  +
               if (ri == null)
  -                continue;
  +                // Blank image...
  +                switch (rule.getRule()) {
  +                case CompositeRule.RULE_IN:
  +                    // For Mode IN One blank image kills all output
  +                    // (including any "future" images to be drawn).
  +                    return null;
  +
  +                case CompositeRule.RULE_ARITHMETIC: {
  +                    BufferedImage blank;
  +                    if (csIsLinear)
  +                        blank = GraphicsUtil.makeLinearBufferedImage
  +                            (r.width, r.height, true);
  +                    else
  +                        blank = new BufferedImage
  +                            (r.width, r.height, 
  +                             BufferedImage.TYPE_INT_ARGB_PRE);
  +                    ri = new BufferedImageCachableRed(blank, r.x, r.y);
  +                }
  +                break;
  +
  +                case CompositeRule.RULE_OUT:
  +                    {
  +                        // For mode OUT blank image clears output 
  +                        // up to this point.
  +                        g2d.setComposite(AlphaComposite.Clear);
  +                        g2d.setColor(new Color(0, 0, 0, 0));
  +                        g2d.fillRect(r.x, r.y, r.width, r.height);
  +                        g2d.setComposite(comp);
  +                    }
  +                    first = false;
  +                    continue;
  +
  +                default:
  +                    // All other cases we simple pretend the image
  +                    // didn't exist (fully transparent image has no
  +                    // affect).
  +                    first = false;
  +                    continue;
  +            }
  +                
  +
               CachableRed cr;
               cr = GraphicsUtil.wrap(ri);
   
  
  
  
  1.2       +3 -3      xml-batik/sources/org/apache/batik/ext/awt/image/rendered/AbstractRed.java
  
  Index: AbstractRed.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/rendered/AbstractRed.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractRed.java	2001/01/24 05:39:38	1.1
  +++ AbstractRed.java	2001/01/25 21:48:04	1.2
  @@ -42,7 +42,7 @@
    * the subclass implementation.
    *
    * @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
  - * @version $Id: AbstractRed.java,v 1.1 2001/01/24 05:39:38 vhardy Exp $
  + * @version $Id: AbstractRed.java,v 1.2 2001/01/25 21:48:04 deweese Exp $
    */
   public abstract class AbstractRed implements CachableRed {
   
  @@ -347,11 +347,11 @@
           // structure of the tile grid in general.
   
           x0 = bounds.x-tileGridXOff; // left edge in tile coords;
  -        if (x0 > 0) minTileX = (x0+tileWidth-1)/tileWidth;
  +        if (x0 > 0) minTileX = x0/tileWidth;
           else        minTileX = -(((-x0)+tileWidth-1)/tileWidth);
   
           y0 = bounds.y-tileGridYOff; // top edge in tile coords;
  -        if (y0 > 0) minTileY = (y0+tileHeight-1)/tileHeight;
  +        if (y0 > 0) minTileY = y0/tileHeight;
           else        minTileY = -(((-y0)+tileHeight-1)/tileHeight);