You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-users@xmlgraphics.apache.org by André Ávila <as...@nextech.com.br> on 2006/02/01 18:32:16 UTC

Replace color in entire document

Hello,

I want to change specific colors in a document (say, replace all green for red in the entire SVG). What would be the best way of doing it?

Here's what I'm trying to do. I'm using a GVTTreeWalker to traverse the whole GVT tree by calling nextGraphicsNode(). At each node I cast the resulting GraphicsNode to ShapeNode. I then change the Painter of the ShapeNode to the color I want. 

It works, but the problem is that I couldn't find a way to tell the current color of the node, and I need to know that to determine if the color is supposed to change or not.

I was also wondering if there's a better approach in terms of performance.

Any help will be most welcome!

Andre

Re: Replace color in entire document

Posted by Tonny Kohar <to...@kiyut.com>.
Hi,

On Thu, 2006-02-02 at 11:16 -0300, André Ávila wrote:

> 1) I couldn't find a way to read the color of the current GraphicsNode. I
> didn't use Cameron's code (from the "How do I parse..." thread), because he
> grabs the color from an SVGElement, and I don't have one - unless I could
> build one from a GraphicsNode, is it possible?

>>From GVT you can grab the SVGElement by using
SVGElement elt = (SVGElement)bridgeContext.getElement(graphicsNode);

Regards
Tonny Kohar
-- 
Sketsa 
SVG Graphics Editor
http://www.kiyut.com


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Replace color in entire document

Posted by André Ávila <as...@nextech.com.br>.
> > This method should work for any SVG currently displayed in an SVGCanvas.
> The
> > idea is a very simple 'replace color' feature: the user selects the
> original
> > color and the destination color, clicks 'replace' and the whole SVG gets
> > updated.
>
>         Apparently not "very simple" ;)

But it sounded so simple when I came up with it... :)

Anyway, thanks to your help I managed to make it work. The Stroke was all
that was missing. I also managed to select the colors using Cameron's and
Tonny's tips.

Performance is still very bad, but it is clear to me that it's sort of a
limitation of the technology. I think I'll go back to this issue later, when
I'm a little more familiar with Batik.

Some concepts are a little clearer to me now. You guys help have been
invaluable once again.

Best regards,

André


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Replace color in entire document

Posted by th...@kodak.com.
Hi André

André Ávila <as...@nextech.com.br> wrote on 02/02/2006 09:16:44 AM:

> I think I didn't state my problem clearly, sorry for that. I really 
cannot
> change the source, nor do I know exactly which elements have to be 
updated.

   I strongly suspected that from your original note...

> This method should work for any SVG currently displayed in an SVGCanvas. 
The
> idea is a very simple 'replace color' feature: the user selects the 
original
> color and the destination color, clicks 'replace' and the whole SVG gets
> updated.

        Apparently not "very simple" ;)


> Well, this code doesn't really work, but it was the closest I could get.
> Ideally, it should produce the same effect as the first one, but it's 
far
> from it:
> 
> 1) I couldn't find a way to read the color of the current GraphicsNode. 
I
> didn't use Cameron's code (from the "How do I parse..." thread), because 
he
> grabs the color from an SVGElement, and I don't have one - unless I 
could
> build one from a GraphicsNode, is it possible?

   Tonny's response is the correct way to go from a GraphicsNode to the
associated SVG Element.  You must have built the GVT tree with the Bridge
set to be 'dynamic'.

   The Painter objects should have a getter for the Paint.

> 2) I'm not sure that updating the ShapeNodes will cover all the elements 
in
> the SVG. Should I try to cast to other kinds of nodes as well?

   Well there is also Text, Marker (used to 'decorate' paths), and Image 
(which might have an entire 'child' SVG tree) Nodes.  In particular Text
is pretty tricky as a text element can change color several times within
one Node.  This is part of the reason working with the SVG is a bit 
cleaner.

> 3) The Painter update is not working as I would expect. Instead of being
> repainted, the nodes that have the Painter updated are disappearing from 
the
> SVG. Odd.

   This is odd.  There are a few things I noticed in the code.
First you aren't providing a Stroke object for the StrokeShapePainter
(so I would expect all strokes to disappear), there should also be a 
getter for the current stroke.

   Also many objects will have a CompositeShapePainter on them which
is a shape painter that uses multiple shape painters to do the work
(to support, fill, stroke and markers).

> I'm very new to Batik, SVG and most of its concepts, so I'm still 
confused
> about how things are supposed to work. I really appreciate you guys help 
on
> this.

   Well you are doing something that the system isn't really designed to
support so I don't know that there is anything close to an official way
to do what you want...


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Replace color in entire document

Posted by André Ávila <as...@nextech.com.br>.
Hello Thomas, Cameron,

I think I didn't state my problem clearly, sorry for that. I really cannot
change the source, nor do I know exactly which elements have to be updated.
This method should work for any SVG currently displayed in an SVGCanvas. The
idea is a very simple 'replace color' feature: the user selects the original
color and the destination color, clicks 'replace' and the whole SVG gets
updated.

Here's the first code I wrote to replace black for white in the entire SVG:

NodeList nodes = document.getElementsByTagName("g");

for(int i = 0; i < nodes.getLength(); i++) {
    if (nodes.item(i) instanceof SVGElement) {
        SVGElement element = (SVGElement) nodes.item(i);
        if (element.getAttribute("stroke").equals("rgb(0,0,0)"));
            element.setAttribute("stroke", "rgb(255,255,255)");
        if (element.getAttribute("fill").equals("rgb(0,0,0)"));
            element.setAttribute("fill", "rgb(255,255,255)");
    }
}

This is not nearly what one would call 'good code', but it produces the
exact effect that I want. However, it is very slow, so I went to the next
idea, which was to traverse the GVT tree updating each GraphicsNode.

GraphicsNode gvtRoot = svgCanvas.getGraphicsNode();

GVTTreeWalker walker = new GVTTreeWalker(gvtRoot);

GraphicsNode currNode = null;

while ((currNode = walker.nextGraphicsNode()) != null) {
    if (currNode instanceof ShapeNode) {
        ShapeNode sn = (ShapeNode) currNode;

        ShapePainter sp = sn.getShapePainter();

        if (sp instanceof StrokeShapePainter) {
            StrokeShapePainter painter = new
StrokeShapePainter(sn.getShape());
            painter.setPaint(Color.WHITE);
            sn.setShapePainter(painter);
        }
        else if (sp instanceof FillShapePainter) {
            FillShapePainter painter = new FillShapePainter(sn.getShape());
            painter.setPaint(Color.WHITE);
            sn.setShapePainter(painter);
        }
    }
}

Well, this code doesn't really work, but it was the closest I could get.
Ideally, it should produce the same effect as the first one, but it's far
from it:

1) I couldn't find a way to read the color of the current GraphicsNode. I
didn't use Cameron's code (from the "How do I parse..." thread), because he
grabs the color from an SVGElement, and I don't have one - unless I could
build one from a GraphicsNode, is it possible?

2) I'm not sure that updating the ShapeNodes will cover all the elements in
the SVG. Should I try to cast to other kinds of nodes as well?

3) The Painter update is not working as I would expect. Instead of being
repainted, the nodes that have the Painter updated are disappearing from the
SVG. Odd.

I'm very new to Batik, SVG and most of its concepts, so I'm still confused
about how things are supposed to work. I really appreciate you guys help on
this.

Thank you,

André


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Replace color in entire document

Posted by th...@kodak.com.
Hi all,

> Andr vila:
> > I want to change specific colors in a document (say, replace all green
> > for red in the entire SVG). What would be the best way of doing it?

Cameron McCormack <ca...@aka.mcc.id.au> wrote on 02/01/2006 
05:03:27 PM:

> I think it would be better to do it in a non-Batik-specific way.  In SVG
> 1.1 there is no 'solidColor' paint server as there is in 1.2, but you
> can achieve the same thing with a 'linearGradient' with a single stop.

   If you can change the source I would use a CSS 'class' to change
these.  Then you can twiddle a style element in the document and Batik 
will automatically update the CSS properties. 

> Unfortunately there is a bug with Batik where updates to a referenced
> paint server do not cause an object to be repainted, which is why I have
> the
> 
>   evt.target.setAttributeNS(null, 'fill', 'url(#c) ');
> 
> line in there to force the rect to be repainted.

        I think part of the problem is that this would assume he
knows all the elements that need to be updated - I suspect he doesn't.
The CSS class let's him avoid knowing exactly what elements need to
be updated - however I suspect that even this won't be great for him.

        I would still avoid using the GVT tree and use the DOM. 
Walking/updating the GVT tree should really be considered a method 
of last resort.  That said, while you can do this through the DOM
(see Cameron's message on getting a Java Color from style info) my
guess is that walking the GVT will be much faster and for some
things (like used content) will be more complete.

> This shouldn't be any worse wrt performance than using a plain solid
> colour as your fill.
> 
>   <svg xmlns="http://www.w3.org/2000/svg"
>        version="1.1" width="400" height="400">
>     <linearGradient id="c">
>       <stop id="s" offset="0" stop-color="orange"/>
>     </linearGradient>
> 
>     <rect width="100" height="100" fill="url(#c)"
>           onclick="document.getElementById('s')
>                            .setAttributeNS(null, 'stop-color', 'pink');
>                    evt.target.setAttributeNS(null, 'fill', 'url(#c) 
');"/>
>   </svg>
> 

> 
> Cameron
> 
> -- 
>  Cameron McCormack         ICQ: 26955922
>  cam (at) mcc.id.au         MSN: cam (at) mcc.id.au
>  http://mcc.id.au/         JBR: heycam (at) jabber.org
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
> For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Replace color in entire document

Posted by Cameron McCormack <ca...@aka.mcc.id.au>.
Hi Andre.

Andr vila:
> I want to change specific colors in a document (say, replace all green
> for red in the entire SVG). What would be the best way of doing it?

I think it would be better to do it in a non-Batik-specific way.  In SVG
1.1 there is no 'solidColor' paint server as there is in 1.2, but you
can achieve the same thing with a 'linearGradient' with a single stop.
This shouldn't be any worse wrt performance than using a plain solid
colour as your fill.

  <svg xmlns="http://www.w3.org/2000/svg"
       version="1.1" width="400" height="400">
    <linearGradient id="c">
      <stop id="s" offset="0" stop-color="orange"/>
    </linearGradient>
  
    <rect width="100" height="100" fill="url(#c)"
          onclick="document.getElementById('s')
                           .setAttributeNS(null, 'stop-color', 'pink');
                   evt.target.setAttributeNS(null, 'fill', 'url(#c) ');"/>
  </svg>

Unfortunately there is a bug with Batik where updates to a referenced
paint server do not cause an object to be repainted, which is why I have
the

  evt.target.setAttributeNS(null, 'fill', 'url(#c) ');

line in there to force the rect to be repainted.

Cameron

-- 
 Cameron McCormack			ICQ: 26955922
 cam (at) mcc.id.au			MSN: cam (at) mcc.id.au
 http://mcc.id.au/			JBR: heycam (at) jabber.org

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org