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:[EMAIL PROTECTED]:/home/cvspublic" + <cvs cvsRoot=":pserver:[EMAIL PROTECTED]:/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 [EMAIL PROTECTED] --> <!-- @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:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">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:[EMAIL PROTECTED]">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: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]