Please find below some code I've written to modify the internal CSS within an
SVG document. 

What I need:
I need help with telling batik to update/redraw the drawing following the
modification. 

Detail:
I am not using Swing or any associated batik libraries and do not wish to.
What I want is for the GVTBuilder/GraphicsNode/Bridge or whatever to be
updated to take into account my CSS modification so that I can then do my
processing of the drawing. The resultant text SVG XML that I output should
also reflect all the changes.

I've searched this forum and found a few posts that appeared to already do
this but when I tried them, it didn't work. Plus they appeared to process
the text of the CSS using generic text processing tools, rather than
manipulate the batik objects that are associated with the CSS. 

For example:
http://www.nabble.com/modifying-css-in-live-svg-document-to3826681.html#a3826681

My solution manipulates the batik CSS objects. I have to say, the
documentation is very minimal in this area! But with the help of print outs,
debugging and Eclipse I achieved my solution.

I wrote this code because I am processing a SVG document from a commercial
drawing application, Corel version 12 which contains an internal CSS
definition, which has several styles defining the font size as negative. 

(I don't want to enter in a debate about the merits of various drawing
tools. Let us just assume that I have to work with the output of this tool.
)

The CSS negative font size attribute causes an exception when I attempt to
process the SVG - i.e. booting the CSS and DOM is OK but when I then try to
get attributes from the graphics e.g. getting bounding boxes, I get an
exception.

GlyphLayout.java:1024>> getUnderlineShape()
GlyphLayout.java:436>> getDecorationOutline()
StrokingTextPainter.java:1191>> getDecorationOutline()
StrokingTextPainter.java:1036>> getOutline()
TextNode.java:281>> getOutline()
AbstractGraphicsNodeBridge.java:492>> getBBox()
SVGLocatableSupport.java:77>> getBBox()
SVGOMTextElement.java:135>> getBBox()
XyOutsideLabelGraphicsFilter.java:113>> acceptNode()

The cause of this exception is apparently because negative font sizes are
illegal - as explaned in the response to my post of the original problem:

http://www.nabble.com/Need-to-process-negative-width-elements-without-causing-Exception-to16036194.html

Well of course, size of something in the real world can never be negative.
However I did think that it might not be, that perhaps it is a relative
figure, relative to the absolute value defined for something else  - much
like size attribute was used with the font tag in HTML. But it is illegal,
because the CSS style is not relative to/or inheriting from any other style,
so it can't be legal. And the CSS 2 specification says it is illegal,
according to the respondent to my post above.

Inkscape is more tolerant than batik; the text for the font is reflected -
i.e. backwards. Not sure whether this is as intended by the original
program. I'm just using Inkscape to view the output for reference purposes.
I don't wish to use it in any other way and need to use batik for the work I
am doing.

Here is an excerpt of the SVG file with the internal CSS with the offending
negative font size value (then read on beyond it for more information and
the code I've written):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Creator: CorelDRAW -->
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/";
   xmlns:cc="http://web.resource.org/cc/";
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
   xmlns:svg="http://www.w3.org/2000/svg";
   xmlns="http://www.w3.org/2000/svg";
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
   xml:space="preserve"
   width="297mm"
   height="210mm"
   style="shape-rendering:geometricPrecision;
text-rendering:geometricPrecision; image-rendering:optimizeQuality;
fill-rule:evenodd; clip-rule:evenodd"
   viewBox="0 0 297 210"
   id="svg13071"
   sodipodi:version="0.32"
   inkscape:version="0.45.1"
   inkscape:output_extension="org.inkscape.output.svg.inkscape"
   sodipodi:docbase="C:\Documents and Settings\rdavis\Desktop"><metadata
   id="metadata13993"><rdf:RDF><cc:Work
       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
         rdf:resource="http://purl.org/dc/dcmitype/StillImage";
/></cc:Work></rdf:RDF></metadata><sodipodi:namedview
   inkscape:window-height="975"
   inkscape:window-width="1280"
   inkscape:pageshadow="2"
   inkscape:pageopacity="0.0"
   guidetolerance="10.0"
   gridtolerance="10.0"
   objecttolerance="10.0"
   borderopacity="1.0"
   bordercolor="#666666"
   pagecolor="#ffffff"
   id="base"
   inkscape:zoom="1.1670775"
   inkscape:cx="526.18109"
   inkscape:cy="372.04724"
   inkscape:window-x="-4"
   inkscape:window-y="-4"
   inkscape:current-layer="Artwork" />
 <defs
   id="defs13073">
  <style
   type="text/css"
   id="style13484">
   
    @font-face { font-family:&quot;Arial&quot;;src:url(&quot;#FontID2&quot;)
format(svg)}
    @font-face { font-family:&quot;Humnst777 Blk
BT&quot;;src:url(&quot;#FontID1&quot;) format(svg)}
    @font-face { font-family:&quot;Humnst777
BT&quot;;src:url(&quot;#FontID0&quot;) format(svg)}

    .fil3 {fill:#1F1A17}
 
    .fnt10 {font-weight:normal;font-size:-6.9144;font-family:'Humnst777 BT'}
  
   
  </style>
 </defs>
 
 <g
   id="EC_x0020_Markup">
  <metadata
   id="CorelCorpID_5Corel-Layer" />
  <text
   x="73.0257"
   y="11.3166"
   class="fil3 fnt10"
   id="text13892">91098-01</text>
 </g>
</svg>

Batik is not very defensive at all with this. When I process it, the
exception I get originates from non-batik code in the awt, when it tries to
render a negative stroke width of a font - here's that excerpt from the
exception call stack again

GlyphLayout.java:1024>> getUnderlineShape()
GlyphLayout.java:436>> getDecorationOutline()
StrokingTextPainter.java:1191>> getDecorationOutline()
StrokingTextPainter.java:1036>> getOutline()
TextNode.java:281>> getOutline()
AbstractGraphicsNodeBridge.java:492>> getBBox()
SVGLocatableSupport.java:77>> getBBox()
SVGOMTextElement.java:135>> getBBox()
XyOutsideLabelGraphicsFilter.java:113>> acceptNode()

In batik's GlyphLayout a call is made to awt.

So being pragmatic I have decided to write my own code to intercept the
non-compliant styles. It works, almost - the batikl object associated with
the CSS style is updated successfully when I change the value from a
negative to a positive value - I can see this from the inspect feature in
the Eclipse IDE debugger.

Here is the code below.

What is does is seek out the offending negative font size CSS style, make it
positive. Then it finds the SVG elements that use the style. At this point I
want to tell batik to update them but don't know how. See also my comments
after the code.



import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Pattern;

import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.css.dom.CSSOMStyleDeclaration;
import org.apache.batik.css.engine.CSSEngine;
import org.apache.batik.css.engine.CSSStyleSheetNode;
import org.apache.batik.css.engine.FontFaceRule;
import org.apache.batik.css.engine.Rule;
import org.apache.batik.css.engine.SVGCSSEngine;
import org.apache.batik.css.engine.StyleDeclaration;
import org.apache.batik.css.engine.StyleRule;
import org.apache.batik.css.engine.StyleSheet;
import org.apache.batik.css.engine.sac.CSSConditionalSelector;
import org.apache.batik.css.engine.value.FloatValue;
import org.apache.batik.css.engine.value.Value;
import org.apache.batik.css.engine.value.css2.FontSizeManager;
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.ext.awt.geom.Polygon2D;
import org.apache.batik.gvt.AbstractGraphicsNode;
import org.apache.batik.gvt.CompositeGraphicsNode;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.gvt.RootGraphicsNode;
import org.apache.batik.parser.AWTPathProducer;
import org.apache.batik.parser.AWTPolygonProducer;
import org.apache.batik.util.XMLResourceDescriptor;
import org.jaxen.JaxenException;

import org.w3c.css.sac.Selector;
import org.w3c.css.sac.SelectorList;
import org.w3c.dom.css.CSSFontFaceRule;
import org.w3c.dom.css.CSSPrimitiveValue;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGElement;
import org.w3c.dom.svg.SVGLocatable;
import org.w3c.dom.svg.SVGRect;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class Filter implements NodeFilter
{

        private Shape labelOutlineShape = null;

        private Document doc;
        private UserAgent userAgent;
        private DocumentLoader loader;
        private BridgeContext ctx;
        private GVTBuilder builder;
        private RootGraphicsNode rootGN;

        Filter(Document entireLabelSVGw3cDoc,
            String labelOutlineId) throws Exception
        {
                doc = entireLabelSVGw3cDoc;

                Element labelOutlineElement = entireLabelSVGw3cDoc
                    .getElementById(labelOutlineId);

                String shapeType = labelOutlineElement.getTagName();
                String points = "";

                BootSvgAndCssDom();



        }


        public void updateElementsUsingCSSStyle(
            CSSConditionalSelector cssConditionalSelector,
            BridgeContext bridgeContext, CompositeGraphicsNode
compositeGraphicsNode)
        {
                List rootGNchildren = compositeGraphicsNode.getChildren();

                int gnsize = compositeGraphicsNode.size();

                for (ListIterator gniterator = rootGNchildren.listIterator(); 
gniterator
                    .hasNext();)
                {
                        Object object = gniterator.next();

                        if (object instanceof CompositeGraphicsNode)
                        {

                                
updateElementsUsingCSSStyle(cssConditionalSelector, bridgeContext,
                                    (CompositeGraphicsNode) object);
                        }
                        else
                        {
                                if (object instanceof GraphicsNode)
                                {
                                        GraphicsNode graphicsNode = 
(GraphicsNode) object;

                                        Element element = 
ctx.getElement(graphicsNode);

                                        if (element != null)
                                        {
                                                String elementName = 
element.getTagName();

                                                
System.out.println("element.getTagName() " + elementName);

                                                String elementStyleClass = 
element.getAttribute("class");

                                                boolean b = 
cssConditionalSelector.match(element, elementName);

                                                if (b)
                                                {

                                                        int idx = 
compositeGraphicsNode.indexOf(graphicsNode);

                                                        
System.out.println("match");

                                                        
compositeGraphicsNode.remove(idx);

                                                }

                                        }

                                        return;
                                }
                        }

                        System.out.println("object.toString() " + 
object.toString());

                }
        }



        private void BootSvgAndCssDom() throws Exception
        {
                userAgent = new UserAgentAdapter();
                loader = new DocumentLoader(userAgent);
                ctx = new BridgeContext(userAgent, loader);
                ctx.setDynamicState(BridgeContext.DYNAMIC);
                builder = new GVTBuilder();

                rootGN = (RootGraphicsNode) builder.build(ctx, doc);

                SVGCSSEngine cssEngine = (SVGCSSEngine) 
ctx.getCSSEngineForElement(doc
                    .getDocumentElement());

                int fontSizePropertyIndex = 0;

                for (int svgValueManagersIndex = 0; svgValueManagersIndex <
(cssEngine.SVG_VALUE_MANAGERS).length; svgValueManagersIndex++)
                {
                        if (cssEngine.SVG_VALUE_MANAGERS[svgValueManagersIndex] 
instanceof
FontSizeManager)
                        {
                                System.out.println("found font size manager " + 
svgValueManagersIndex);

                                fontSizePropertyIndex = svgValueManagersIndex;
                        }
                }

                NodeList listOfTextElements = doc.getElementsByTagName("text");

                int listOfTextElementsLength = listOfTextElements.getLength();

                // assuming one style sheet?

                List styleSheetsList = cssEngine.getStyleSheetNodes();

                CSSStyleSheetNode cssNode = (CSSStyleSheetNode) 
styleSheetsList.get(0);

                StyleSheet styleSheet = cssNode.getCSSStyleSheet();

                int numRules = styleSheet.getSize();

                for (int ruleIndex = 0; ruleIndex < numRules; ruleIndex++)
                {
                        System.out.println("styleSheet.getRule(" + ruleIndex + 
") "
                            + styleSheet.getRule(ruleIndex));

                        Rule rule = styleSheet.getRule(ruleIndex);



                        if (rule instanceof StyleRule)
                        {
                                StyleRule sr = ((StyleRule) rule);

                                System.out.println("rule.getType() " + 
rule.getType());

                                StyleDeclaration sd = ((StyleRule) 
rule).getStyleDeclaration();

                                System.out.println("sr.toString() " + 
sr.toString());

                                System.out.println("sd.toString() " + 
sd.toString());


                                int sdlen = sd.size();

                                Vector listOfIndexToNegativeFontSizes;
                                Vector listOfReplacementPostiveFontSizes;

                                for (int sdindex = 0; sdindex < sdlen; 
sdindex++)
                                {

                                        Value val = sd.getValue(sdindex);

                                        
System.out.println("sd.getIndex(sdindex) " + sd.getIndex(sdindex));

                                        if (sd.getIndex(sdindex) == 
fontSizePropertyIndex)
                                        {
                                                System.out.println("found font 
size");

                                                float aFloatValue = 
Float.valueOf(val.getCssText());

                                                if (aFloatValue < 0.0F)
                                                {
                                                        System.out.println("is 
negative:" + aFloatValue);
                                                        FloatValue 
positiveFloatValueObj = new FloatValue(
                                                            
CSSPrimitiveValue.CSS_NUMBER, Math.abs(aFloatValue));

                                                        sd.put(sdindex, 
positiveFloatValueObj,
                                                            
CSSPrimitiveValue.CSS_NUMBER, false);

                                                        
System.out.println("sd.toString() " + sd.toString());

                                                        SelectorList sl = 
sr.getSelectorList();

                                                        int sllen = 
sl.getLength();

                                                        for (int slindex = 0; 
slindex < sllen; slindex++)
                                                        {

                                                                // seek out 
effected elements
                                                                Selector 
selector = sl.item(slindex);

                                                                if (selector 
instanceof CSSConditionalSelector)
                                                                {
                                                                        
CSSConditionalSelector cssConditionalSelector =
(CSSConditionalSelector) selector;

                                                                        String 
styleClass = cssConditionalSelector.toString();

                                                                        
System.out.println("cssConditionalSelector.toString() "
                                                                            + 
styleClass);

                                                                        
updateElementsUsingCSSStyle(cssConditionalSelector, ctx,
                                                                            
rootGN);

                                                                        for 
(int indexOfTextElements = 0; indexOfTextElements <
listOfTextElementsLength; indexOfTextElements++)
                                                                        {
                                                                                
Element aTextElement = (Element) listOfTextElements
                                                                                
    .item(indexOfTextElements);



                                                                                
String elementStyleClass = aTextElement
                                                                                
    .getAttribute("class");

                                                                                
boolean b = cssConditionalSelector.match(aTextElement,
                                                                                
    aTextElement.getTagName());

                                                                                
if (b)
                                                                                
{


                                                                                
        GraphicsNode elementGN = ctx
                                                                                
            .getGraphicsNode(aTextElement);



                                                                                
        int gni = rootGN.indexOf(elementGN);

                                                                                
        rootGN.remove(elementGN);

                                                                                
        System.out.println(elementGN.toString());


                                                                                
}

                                                                        }

                                                                }

                                                        }


                                                }

                                        }








                                } // end style declaration iteration



                                System.out.println("StyleRule");
                        } // end instanceof style rule

                        System.out.println("rule.toString()" + rule.toString());
                }

                System.out.println("styleSheet.getSize() " + 
styleSheet.getSize());

                System.out.println("styleSheet.toString() " + 
styleSheet.toString());

                int numCssNodes = styleSheetsList.size();

                System.out.println("got here");

        }

}






However, the batik system is not completely updated - because when I then go
on to process the drawing - I still get the same exception. 

So my question is - how to update the entire batik system?

I've already started to look into this - there is this thing called
RunnableQueue. But again, the documentation is almost non-existent - i.e.
here and also: http://xmlgraphics.apache.org/batik/

I think this code would be useful to anyone who wants to update the CSS
whether or not it is compliant.

Please help.




-- 
View this message in context: 
http://www.nabble.com/Modifying-internal-CSS-in-SVG-document---partial-solution---need-help-with-batik-re-draw-update-tp16275087p16275087.html
Sent from the Batik - Users mailing list archive at Nabble.com.


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

Reply via email to