Thomas DeWeese wrote:

It is possible that we do not calculate the effected bounds of
the change to the document when the filter effect is added (although
in my testing this has worked).  I'll try and take a look.

Well I hacked it down, and now my "short" example program is over 200 lines. I hope this won't be too painful for you. The program dynamically creates a document that looks like the following:

<svg>
  <defs>
     <filter xmlns:xlink="http://www.w3.org/1999/xlink";
             filterUnits="objectBoundingBox"
             xlink:type="simple"
             xlink:actuate="onRequest"
             id="filter-bgGroup"
             xlink:show="replace">
        <feImage result="background"
                 xmlns:xlink="http://www.w3.org/1999/xlink";
                 xlink:href="#bgGroup"
                 xlink:type="simple"
                 xlink:actuate="onRequest"
                 xlink:show="replace"/>
        <feComposite operator="in" in2="SourceGraphic" in="background"/>
     </filter>
 </defs>

<g style="stroke:black; stroke-opacity:1; stroke-linejoin:round; stroke-linecap:round; fill:black; stroke-width: 20px; " id="bgGroup">

    <image x="0" y="0"
           width="100%" height="100%"
           xmlns:xlink="http://www.w3.org/1999/xlink";

xlink:href="http://erudycja.rutgers.edu/~armhold/svg/eiffel.jpg";
           xlink:type="simple"
           xlink:actuate="onRequest"
           preserveAspectRatio="xMidYMid meet"
           xlink:show="replace"/>
</g>

<rect x="10%" y="20%"
      width="80%" height="60%"
      fill="white"/>

<g style="stroke:black; stroke-opacity:1; stroke-linejoin:round; stroke-linecap:round; fill:black; stroke-width: 20px; filter: url(#filter-bgGroup);" id="drawing_group">

</g>

</svg>


First, it displays an image from a .jpg file. Then it draws a white rectangle which partially obscures the image. Then the user can "erase" parts of this rectangle by drawing with the left mouse button, to reveal the image again. You'll see that the drawing doesn't seem to update properly. If you then click the right mouse button, the doc will get re-loaded, and the drawing thus becomes visible.

I hope this will be useful. Thanks as always for looking into this.


-- George Armhold Rutgers University eLearning Grant, DCIS
package edu.rutgers.elearning.scribble;

import java.io.*;
import java.util.*;
import java.net.*;

import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;

import org.w3c.dom.*;
import org.w3c.dom.svg.*;

import org.apache.batik.swing.svg.*;
import org.apache.batik.bridge.*;
import org.apache.batik.dom.svg.*;
import org.apache.batik.util.*;


/** 
 * Draw using a background filter.
 * 
 * - let image load.
 * - draw with left mouse button.
 * - force screen updates with right mouse button clicks.
 * 
 */
public class FilterTest extends JSVGComponent {
  private static final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
  private static final String xlinkNS = "http://www.w3.org/1999/xlink";;
  private static final String eiffelURL = 
"http://erudycja.rutgers.edu/~armhold/svg/eiffel.jpg";;
  private final DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
  private Element bgFilter;
  private Element drawingGroup;
  private java.awt.event.MouseEvent lineStart;

  public FilterTest() {
    setDocumentState(JSVGComponent.ALWAYS_DYNAMIC);    

    final SVGDocument doc = createDocument();

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
          FilterTest.this.setSVGDocument(doc);
        }
      });

    // left mouse button: draw
    // right mouse button: reload svg
    addMouseListener(new MouseAdapter() {
        public void mousePressed(java.awt.event.MouseEvent e) {
          if (SwingUtilities.isLeftMouseButton(e)) {
            lineStart = e;
          } else {
            setSVGDocument(getSVGDocument());
          }
        }
      });

    addMouseMotionListener(new MouseMotionAdapter() {
        public void mouseDragged(java.awt.event.MouseEvent lineStop) {
          addLine(drawingGroup, lineStart, lineStop);
          lineStart = lineStop;
        }
      });

  }

  public SVGDocument createDocument() {
    SVGDocument doc = 
      (SVGDocument) impl.createDocument(svgNS, "svg", null);

    // create an image that will serve as the background
    // we will draw with
    Element bgGroup = getGroup(doc, "bgGroup", null);
    bgGroup.appendChild(getImage(doc, eiffelURL));
    bgFilter = createFilter(doc, bgGroup);

    // <g> element which we will draw into
    drawingGroup = getGroup(doc, "drawing_group", bgFilter);

    Element root = doc.getDocumentElement();
    root.appendChild(bgGroup);

    // add a rect that obscures the image
    root.appendChild(createRect(doc, "white"));

    // add our line group, now we're ready for mouse events
    root.appendChild(drawingGroup);

    return doc;
  }

  private static Element getGroup(Document document,
                                  String id,
                                  Element filter) {

    Element group = document.createElementNS(svgNS, "g");
    group.setAttributeNS(null, "id", id);

    String style = getStyle();

    if (filter != null) {
      style += "filter: url(#"  + filter.getAttribute("id") + ");";
    }

    group.setAttributeNS(null, "style", style);

    return group;
  }


  private Element getImage(Document doc, String url) {
    Element image = doc.createElementNS(svgNS, "image");
    image.setAttributeNS(xlinkNS, "xlink:href", url);
    image.setAttributeNS(null, "x", "0");
    image.setAttributeNS(null, "y", "0");
    image.setAttributeNS(null, "width", "100%");
    image.setAttributeNS(null, "height", "100%");

    return image;
  }

  private Element createRect(Document doc, String color) {
    Element rect = doc.createElementNS(svgNS, "rect");
    rect.setAttributeNS(null, "fill", color);
    rect.setAttributeNS(null, "x", "10%");
    rect.setAttributeNS(null, "y", "20%");
    rect.setAttributeNS(null, "width", "80%");
    rect.setAttributeNS(null, "height", "60%");

    return rect;
 }


  private void addLine(final Element group, 
                       final java.awt.event.MouseEvent lineStart,
                       final java.awt.event.MouseEvent lineStop) 
  {
    UpdateManager updateManager = getUpdateManager();    
    RunnableQueue rq = updateManager.getUpdateRunnableQueue();

    rq.invokeLater(new Runnable() {
        public void run() {
          Document doc = group.getOwnerDocument();
          Element line = doc.createElementNS(svgNS, "line");
          line.setAttributeNS(null, "x1", Integer.toString(lineStart.getX()));
          line.setAttributeNS(null, "y1", Integer.toString(lineStart.getY()));
          line.setAttributeNS(null, "x2", Integer.toString(lineStop.getX()));
          line.setAttributeNS(null, "y2", Integer.toString(lineStop.getY()));
          group.appendChild(line);
        }
      });
  }


  // create or return existing <defs> element
  private static Element getDefs(Document document) {
    Element defs = null;
    NodeList nodes = document.getElementsByTagName("svg:defs");

    if (nodes.getLength() > 1)
      throw new IllegalStateException("more than one <defs> element in doc!");

    if (nodes.getLength() == 1) {
      defs = (Element) nodes.item(0);
    } else {
      defs = document.createElementNS(svgNS, "defs");
      Element root = document.getDocumentElement();
      Node firstChild = root.getFirstChild();
      root.insertBefore(defs, firstChild);
    }

    return defs;
  }

  /**
   * Create a filter in the <defs> section of the specified document.
   */
  private static Element createFilter(Document document,
                                      Element bgGroup) 
  {
    // create filter
    Element filter = document.createElementNS(svgNS, "filter");
    filter.setAttributeNS(null, "id", "filter-" + bgGroup.getAttribute("id"));
    filter.setAttributeNS(null, "filterUnits", "objectBoundingBox");

    // create feImage
    Element feImage = document.createElementNS(svgNS, "feImage");
    feImage.setAttributeNS(null, "result", "background");
    feImage.setAttributeNS(xlinkNS, "xlink:href", 
                           "#" + bgGroup.getAttribute("id"));
    filter.appendChild(feImage);

    // create feComposite
    Element feComposite = document.createElementNS(svgNS, "feComposite");
    feComposite.setAttributeNS(null, "in", "background");
    feComposite.setAttributeNS(null, "in2", "SourceGraphic");
    feComposite.setAttributeNS(null, "operator", "in");
    filter.appendChild(feComposite);
    
    // append the filter to <defs>, and we're done
    Element defs = getDefs(document);
    defs.appendChild(filter);

    return filter;
  }

  private static String getStyle() {
    return 
      "stroke:black; stroke-opacity:1; " +
      "stroke-linejoin:round; " +
      "stroke-linecap:round; " +
      "fill:black; stroke-width: 20px; ";
  };


  public static void main(String[] args) throws Exception {
    JFrame frame = new JFrame("FilterTest");

    FilterTest canvas = new FilterTest();
    frame.getContentPane().add(canvas);

    frame.pack();
    frame.setSize(new Dimension(500, 500));
    frame.setVisible(true);
  }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to