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/08/30 19:14:01 UTC
cvs commit: xml-batik/sources/org/apache/batik/extension/svg BatikHistogramNormalizationElement.java BatikHistogramNormalizationElementBridge.java BatikHistogramNormalizationFilter.java BatikHistogramNormalizationFilter8Bit.java HistogramRed.java BatikBridgeExtension.java BatikDomExtension.java BatikExtConstants.java
deweese 01/08/30 10:14:01
Modified: . build.xml
sources/org/apache/batik/extension/svg
BatikBridgeExtension.java BatikDomExtension.java
BatikExtConstants.java
Added: samples/extensions histogramNormalization.jpg
histogramNormalization.svg
sources/org/apache/batik/extension/svg
BatikHistogramNormalizationElement.java
BatikHistogramNormalizationElementBridge.java
BatikHistogramNormalizationFilter.java
BatikHistogramNormalizationFilter8Bit.java
HistogramRed.java
Log:
Added a Filter Extension example. A very simple minded Histogram
normalization operation.
Revision Changes Path
1.79 +2 -2 xml-batik/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/xml-batik/build.xml,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -r1.78 -r1.79
--- build.xml 2001/07/31 18:31:29 1.78
+++ build.xml 2001/08/30 17:14:01 1.79
@@ -44,7 +44,7 @@
[win32] .\build.bat help
- $Id: build.xml,v 1.78 2001/07/31 18:31:29 vhardy Exp $
+ $Id: build.xml,v 1.79 2001/08/30 17:14:01 deweese Exp $
-->
@@ -197,7 +197,7 @@
<gzip zipfile="${project}-${version}.tar.gz" src="${project}-${version}.tar"/>
<delete file="${project}-docs-${version}.tar"/>
- <cvs cvsRoot=":pserver:anoncvs@xml.apache.org:/home/cvspublic"
+ <cvs cvsRoot=":pserver:anoncvs@cvs.apache.org:/home/cvspublic"
package="xml-batik"
dest="xml-${project}"/>
<tar tarfile="${project}-src-${version}.tar" basedir="." includes="xml-${project}"/>
1.1 xml-batik/samples/extensions/histogramNormalization.jpg
<<Binary file>>
1.1 xml-batik/samples/extensions/histogramNormalization.svg
Index: histogramNormalization.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. -->
<!-- ====================================================================== -->
<!-- ====================================================================== -->
<!-- regularPoly extension tag test -->
<!-- -->
<!-- @author Thomas.DeWeese@Kodak.com -->
<!-- @version $Id: histogramNormalization.svg,v 1.1 2001/08/30 17:14:01 deweese Exp $ -->
<!-- ====================================================================== -->
<?xml-stylesheet type="text/css" href="extension.css" ?>
<svg id="body" width="450" height="500" xml:space="preserve"
viewBox="0 0 450 500"
xmlns:batikExt="http://xml.apache.org/batik/ext">
<title>Histogram Normalization Extension Tag</title>
<!-- ============================================================= -->
<!-- Test content -->
<!-- ============================================================= -->
<g id="testContent" class="legend" style="text-anchor:middle">
<text x="225" y="40" class="title">Histogram Normalization Extension Tag</text>
<g transform="translate(0, 75)">
<rect fill="#DAA" x="25" y="0" width="160" height="220"/>
<image xlink:href="histogramNormalization.jpg"
x="45" y="20" width="120" height="180"/>
<text x="105" y="235" text-anchor="middle">Before</text>
</g>
<g transform="translate(240,75)" >
<switch>
<g requiredExtensions=
"http://xml.apache.org/batik/ext/histogramNormalization/1.0">
<rect fill="#ADA" x="25" y="0" width="160" height="220"/>
<filter id="fix">
<feComponentTransfer>
<feFuncR type="gamma" exponent=".95"/>
<feFuncG type="gamma" exponent=".95"/>
<feFuncB type="gamma" exponent=".95"/>
</feComponentTransfer>
<batikExt:histogramNormalization trim="2"/>
</filter>
<image filter="url(#fix)"
xlink:href="histogramNormalization.jpg"
x="45" y="20" width="120" height="180"/>
<text x="105" y="235" text-anchor="middle">With Extension</text>
</g>
<g >
<rect fill="#DAA" x="25" y="0" width="160" height="220"/>
<image xlink:href="histogramNormalization.jpg"
x="45" y="20" width="120" height="180"/>
<text x="105" y="235" text-anchor="middle">Extension not present</text>
</g>
</switch>
</g>
</g>
<!-- ============================================================= -->
<!-- Batik sample mark -->
<!-- ============================================================= -->
<use xlink:href="../batikLogo.svg#Batik_Tag_Box" />
</svg>
1.2 +2 -0 xml-batik/sources/org/apache/batik/extension/svg/BatikBridgeExtension.java
Index: BatikBridgeExtension.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/extension/svg/BatikBridgeExtension.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- BatikBridgeExtension.java 2001/05/15 13:55:35 1.1
+++ BatikBridgeExtension.java 2001/08/30 17:14:01 1.2
@@ -39,6 +39,7 @@
String [] extensions = {
"http://xml.apache.org/batik/ext/poly/1.0" ,
"http://xml.apache.org/batik/ext/star/1.0" ,
+ "http://xml.apache.org/batik/ext/histogramNormalization/1.0" ,
};
Vector v = new Vector(extensions.length);
for (int i=0; i<extensions.length; i++) {
@@ -90,5 +91,6 @@
public void registerTags(BridgeContext ctx) {
ctx.putBridge(new BatikRegularPolygonElementBridge());
ctx.putBridge(new BatikStarElementBridge());
+ ctx.putBridge(new BatikHistogramNormalizationElementBridge());
}
}
1.3 +20 -0 xml-batik/sources/org/apache/batik/extension/svg/BatikDomExtension.java
Index: BatikDomExtension.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/extension/svg/BatikDomExtension.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- BatikDomExtension.java 2001/08/21 15:26:00 1.2
+++ BatikDomExtension.java 2001/08/30 17:14:01 1.3
@@ -81,6 +81,11 @@
(BATIK_EXT_NAMESPACE_URI,
BATIK_EXT_STAR_TAG,
new BatikStarElementFactory());
+
+ di.registerCustomElementFactory
+ (BATIK_EXT_NAMESPACE_URI,
+ BATIK_EXT_HISTOGRAM_NORMALIZATION_TAG,
+ new BatikHistogramNormalizationElementFactory());
}
/**
@@ -110,6 +115,21 @@
*/
public Element create(String prefix, Document doc) {
return new BatikStarElement(prefix, (AbstractDocument)doc);
+ }
+ }
+
+ /**
+ * To create a 'histogramNormalization' element.
+ */
+ protected static class BatikHistogramNormalizationElementFactory
+ implements SVGDOMImplementation.ElementFactory {
+ public BatikHistogramNormalizationElementFactory() {}
+ /**
+ * Creates an instance of the associated element type.
+ */
+ public Element create(String prefix, Document doc) {
+ return new BatikHistogramNormalizationElement
+ (prefix, (AbstractDocument)doc);
}
}
1.2 +9 -0 xml-batik/sources/org/apache/batik/extension/svg/BatikExtConstants.java
Index: BatikExtConstants.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/extension/svg/BatikExtConstants.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- BatikExtConstants.java 2001/05/15 13:55:35 1.1
+++ BatikExtConstants.java 2001/08/30 17:14:01 1.2
@@ -23,6 +23,10 @@
public static final String BATIK_EXT_STAR_TAG =
"star";
+ /** Tag name for Batik's star extension. */
+ public static final String BATIK_EXT_HISTOGRAM_NORMALIZATION_TAG =
+ "histogramNormalization";
+
/** Attribute name for sides attribute */
public static final String BATIK_EXT_SIDES_ATTRIBUTE =
"sides";
@@ -30,4 +34,9 @@
/** Attribute name for inner radius attribute */
public static final String BATIK_EXT_IR_ATTRIBUTE =
"ir";
+
+ /** Attribute name for trim percent attribute */
+ public static final String BATIK_EXT_TRIM_ATTRIBUTE =
+ "trim";
+
}
1.1 xml-batik/sources/org/apache/batik/extension/svg/BatikHistogramNormalizationElement.java
Index: BatikHistogramNormalizationElement.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.extension.svg;
import org.w3c.dom.Node;
import org.apache.batik.dom.AbstractDocument;
import org.apache.batik.extension.PrefixableStylableExtensionElement;
/**
* This class implements a histogram normalization extension to SVG.
*
* @author <a href="mailto:thomas.deweese@kodak.com">Thomas DeWeese</a>
* @version $Id: BatikHistogramNormalizationElement.java,v 1.1 2001/08/30 17:14:01 deweese Exp $
*/
public class BatikHistogramNormalizationElement
extends PrefixableStylableExtensionElement
implements BatikExtConstants {
/**
* Creates a new BatikHistogramNormalizationElement object.
*/
protected BatikHistogramNormalizationElement() {
}
/**
* Creates a new BatikHistogramNormalizationElement object.
* @param prefix The namespace prefix.
* @param owner The owner document.
*/
public BatikHistogramNormalizationElement(String prefix, AbstractDocument owner) {
super(prefix, owner);
}
/**
* <b>DOM</b>: Implements {@link org.w3c.dom.Node#getLocalName()}.
*/
public String getLocalName() {
return BATIK_EXT_HISTOGRAM_NORMALIZATION_TAG;
}
/**
* <b>DOM</b>: Implements {@link org.w3c.dom.Node#getNamespaceURI()}.
*/
public String getNamespaceURI() {
return BATIK_EXT_NAMESPACE_URI;
}
/**
* Returns a new uninitialized instance of this object's class.
*/
protected Node newNode() {
return new BatikHistogramNormalizationElement();
}
}
1.1 xml-batik/sources/org/apache/batik/extension/svg/BatikHistogramNormalizationElementBridge.java
Index: BatikHistogramNormalizationElementBridge.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.extension.svg;
import org.w3c.dom.Element;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import org.apache.batik.bridge.BridgeException;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.SVGUtilities;
import org.apache.batik.bridge.AbstractSVGFilterPrimitiveElementBridge;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.ext.awt.image.renderable.Filter;
import org.apache.batik.ext.awt.image.renderable.PadRable8Bit;
import org.apache.batik.ext.awt.image.PadMode;
/**
* Bridge class for a histogram normalization element.
*
* @author <a href="mailto:thomas.deweese@kodak.com">Thomas Deweese</a>
*/
public class BatikHistogramNormalizationElementBridge
extends AbstractSVGFilterPrimitiveElementBridge
implements BatikExtConstants {
/**
* Constructs a new bridge for the <histogramNormalization> element.
*/
public BatikHistogramNormalizationElementBridge() { /* nothing */ }
/**
* Returns the SVG namespace URI.
*/
public String getNamespaceURI() {
return BATIK_EXT_NAMESPACE_URI;
}
/**
* Returns 'histogramNormalization'.
*/
public String getLocalName() {
return BATIK_EXT_HISTOGRAM_NORMALIZATION_TAG;
}
/**
* Creates a <tt>Filter</tt> primitive according to the specified
* parameters.
*
* @param ctx the bridge context to use
* @param filterElement the element that defines a filter
* @param filteredElement the element that references the filter
* @param filteredNode the graphics node to filter
*
* @param inputFilter the <tt>Filter</tt> that represents the current
* filter input if the filter chain.
* @param filterRegion the filter area defined for the filter chain
* 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 createFilter(BridgeContext ctx,
Element filterElement,
Element filteredElement,
GraphicsNode filteredNode,
Filter inputFilter,
Rectangle2D filterRegion,
Map filterMap) {
// 'in' attribute
Filter in = getIn(filterElement,
filteredElement,
filteredNode,
inputFilter,
filterMap,
ctx);
if (in == null) {
return null; // disable the filter
}
// The default region is the union of the input sources
// regions unless 'in' is 'SourceGraphic' in which case the
// default region is the filterChain's region
Filter sourceGraphics = (Filter)filterMap.get(SVG_SOURCE_GRAPHIC_VALUE);
Rectangle2D defaultRegion;
if (in == sourceGraphics) {
defaultRegion = filterRegion;
} else {
defaultRegion = in.getBounds2D();
}
Rectangle2D primitiveRegion
= SVGUtilities.convertFilterPrimitiveRegion(filterElement,
filteredElement,
filteredNode,
defaultRegion,
filterRegion,
ctx);
float trim = 1;
String s = filterElement.getAttributeNS
(null, BATIK_EXT_TRIM_ATTRIBUTE);
if (s.length() != 0) {
try {
trim = SVGUtilities.convertSVGNumber(s);
} catch (NumberFormatException ex) {
throw new BridgeException
(filterElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object[] {BATIK_EXT_TRIM_ATTRIBUTE, s});
}
}
if (trim < 0) trim =0;
else if (trim > 100) trim=100;
Filter filter = in;
filter = new BatikHistogramNormalizationFilter8Bit(filter, trim/100);
filter = new PadRable8Bit(filter, primitiveRegion, PadMode.ZERO_PAD);
// update the filter Map
updateFilterMap(filterElement, filter, filterMap);
// handle the 'color-interpolation-filters' property
handleColorInterpolationFilters(filter, filterElement);
return filter;
}
/**
* Stolen from AbstractSVGFilterPrimitiveElementBridge.
* Converts on the specified filter primitive element, the specified
* attribute that represents an integer and with the specified
* default value.
*
* @param filterElement the filter primitive element
* @param attrName the name of the attribute
* @param defaultValue the default value of the attribute
*/
protected static int convertSides(Element filterElement,
String attrName,
int defaultValue) {
String s = filterElement.getAttributeNS(null, attrName);
if (s.length() == 0) {
return defaultValue;
} else {
int ret = 0;
try {
ret = SVGUtilities.convertSVGInteger(s);
} catch (NumberFormatException ex) {
throw new BridgeException
(filterElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object[] {attrName, s});
}
if (ret <3)
throw new BridgeException
(filterElement, ERR_ATTRIBUTE_VALUE_MALFORMED,
new Object[] {attrName, s});
return ret;
}
}
}
1.1 xml-batik/sources/org/apache/batik/extension/svg/BatikHistogramNormalizationFilter.java
Index: BatikHistogramNormalizationFilter.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.extension.svg;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderContext;
import org.apache.batik.ext.awt.image.renderable.FilterColorInterpolation;
import org.apache.batik.ext.awt.image.renderable.Filter;
import org.apache.batik.ext.awt.image.rendered.CachableRed;
import org.apache.batik.ext.awt.image.rendered.ColorMatrixRed;
public interface BatikHistogramNormalizationFilter
extends FilterColorInterpolation {
/**
* Returns the source to be offset.
*/
public Filter getSource();
/**
* Sets the source to be offset.
* @param src image to offset.
*/
public void setSource(Filter src);
/**
* Returns the trim percent for this normalization.
*/
public float getTrim();
/**
* Sets the trim percent for this normalization.
*/
public void setTrim(float trim);
}
1.1 xml-batik/sources/org/apache/batik/extension/svg/BatikHistogramNormalizationFilter8Bit.java
Index: BatikHistogramNormalizationFilter8Bit.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.extension.svg;
import java.awt.geom.AffineTransform;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.renderable.RenderContext;
import org.apache.batik.ext.awt.image.renderable.AbstractColorInterpolationRable;
import org.apache.batik.ext.awt.image.renderable.Filter;
import org.apache.batik.ext.awt.image.rendered.CachableRed;
import org.apache.batik.ext.awt.image.TransferFunction;
import org.apache.batik.ext.awt.image.LinearTransfer;
import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.ext.awt.image.rendered.ComponentTransferRed;
public class BatikHistogramNormalizationFilter8Bit
extends AbstractColorInterpolationRable
implements BatikHistogramNormalizationFilter {
private float trim = .01f;
/**
* Sets the source of the operation
*/
public void setSource(Filter src){
init(src, null);
}
/**
* Returns the source of the operation
*/
public Filter getSource(){
return (Filter)getSources().get(0);
}
/**
* Returns the trim percent for this normalization.
*/
public float getTrim() {
return trim;
}
/**
* Sets the trim percent for this normalization.
*/
public void setTrim(float trim) {
this.trim = trim;
touch();
}
public BatikHistogramNormalizationFilter8Bit(Filter src, float trim) {
setSource(src);
setTrim(trim);
}
protected int [] histo = null;
protected float slope, intercept;
/**
* This method computes the histogram of the image and
* from that the appropriate clipping points, which leads
* to a slope and intercept for a LinearTransfer function
*
* @param rc We get the set of rendering hints from rc.
*/
public void computeHistogram(RenderContext rc) {
if (histo != null)
return;
Filter src = getSource();
float scale = 100f/src.getWidth();
float yscale = 100f/src.getHeight();
if (scale > yscale) scale=yscale;
AffineTransform at = AffineTransform.getScaleInstance(scale, scale);
rc = new RenderContext(at, rc.getRenderingHints());
RenderedImage histRI = getSource().createRendering(rc);
histo = new HistogramRed(convertSourceCS(histRI)).getHistogram();
int t = (int)(histRI.getWidth()*histRI.getHeight()*trim+0.5);
int c, i;
for (c=0, i=0; i<255; i++) {
c+=histo[i];
// System.out.println("C[" + i + "] = " + c + " T: " + t);
if (c>=t) break;
}
int low = i;
for (c=0, i=255; i>0; i--) {
c+=histo[i];
// System.out.println("C[" + i + "] = " + c + " T: " + t);
if (c>=t) break;
}
int hi = i;
slope = 255f/(hi-low);
intercept = (slope*-low)/255f;
}
public RenderedImage createRendering(RenderContext rc) {
//
// Get source's rendered image
//
RenderedImage srcRI = getSource().createRendering(rc);
if(srcRI == null)
return null;
computeHistogram(rc);
SampleModel sm = srcRI.getSampleModel();
int bands = sm.getNumBands();
// System.out.println("Slope, Intercept: " + slope + ", " + intercept);
TransferFunction [] tfs = new TransferFunction[bands];
TransferFunction tf = new LinearTransfer(slope, intercept);
for (int i=0; i<tfs.length; i++)
tfs[i] = tf;
return new ComponentTransferRed(convertSourceCS(srcRI), tfs, null);
}
}
1.1 xml-batik/sources/org/apache/batik/extension/svg/HistogramRed.java
Index: HistogramRed.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.extension.svg;
import java.awt.Rectangle;
import java.awt.image.DataBufferByte;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.ext.awt.image.rendered.AbstractRed;
import org.apache.batik.ext.awt.image.rendered.Any2LumRed;
import org.apache.batik.ext.awt.image.rendered.CachableRed;
/**
*
* @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
* @version $Id: HistogramRed.java,v 1.1 2001/08/30 17:14:01 deweese Exp $
*/
public class HistogramRed extends AbstractRed {
// This is used to track which tiles we have computed
// a histogram for.
boolean [] computed;
int tallied = 0;
int [] bins = new int[256];
public HistogramRed(CachableRed src){
super(src, null);
int tiles = getNumXTiles()*getNumYTiles();
computed = new boolean[tiles];
}
public void tallyTile(Raster r) {
final int minX = r.getMinX();
final int minY = r.getMinY();
final int w = r.getWidth();
final int h = r.getHeight();
int [] samples = null;
int val;
for (int y=minY; y<minY+h; y++) {
samples = r.getPixels(minX, y, w, 1, samples);
for (int x=0; x<3*w; x++) {
// Simple fixed point conversion to lumincence.
val = samples[x++]*5; // Red
val += samples[x++]*9; // Green
val += samples[x++]*2; // blue
bins[val>>4]++;
}
}
tallied++;
}
public int [] getHistogram() {
if (tallied == computed.length)
return bins;
CachableRed src = (CachableRed)getSources().elementAt(0);
int yt0 = src.getMinTileY();
int xtiles = src.getNumXTiles();
int xt0 = src.getMinTileX();
int xt1 = xt0+xtiles-1;
for (int y=0; y<src.getNumYTiles(); y++) {
for (int x=0; x<xtiles; x++) {
int idx = (x+xt0)+y*xtiles;
if (computed[idx]) continue;
Raster r = src.getTile(x+xt0, y+yt0);
tallyTile(r);
computed[idx]=true;
}
}
return bins;
}
public WritableRaster copyData(WritableRaster wr) {
copyToRaster(wr);
return wr;
}
public Raster getTile(int tileX, int tileY) {
int yt = tileY-getMinTileY();
int xt = tileX-getMinTileX();
CachableRed src = (CachableRed)getSources().elementAt(0);
Raster r = src.getTile(tileX, tileY);
int idx = xt+yt*getNumXTiles();
if (computed[idx])
return r;
tallyTile(r);
computed[idx] = true;
return r;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org