简体   繁体   中英

How to change SVG color (when using the SVG as background in CSS)

I'm struggling to change the color of an svg object via css (svg as background css).

I have this

span {
    display:block;
    width: 12px;
    background: url('data:image/svg+xml;utf-8,<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><polygon points="6,4.5 0,0 0,1.208 6,5.708 12,1.208 12,0"/></svg>');
    height: 20px;
}

This works, but the color of the element is always black. I would like to change it color to a custom color (blue for example). By adding style="fill:#2C30FF" , the element just disappears and shows nothing, although this work fine if the svg element is included in the html (not css background)

See the fiddle for an example. There should display 3 elements but the second doesn't show because I added style="fill:#2C30FF"

JsFiddle

Why doesn't it work? Would really appreciate some tips.

# is a reserved character in URLs, it indicates the start of a fragment identifier .

You need to URL encode the # as %23

background: url('data:image/svg+xml;utf-8,<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ><polygon points="6,4.5 0,0 0,1.208 6,5.708 12,1.208 12,0" style="fill:%232C30FF;"/></svg>');

Updated fiddle

I have just implemented a java solution whereby I can load an SVG file and change the fill colors dynamically.

Here is my code- SvgImage.java

package com.svg.poc;

import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.BridgeException;
import org.apache.batik.bridge.GVTBuilder;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.bridge.ViewBox;
import org.apache.batik.dom.util.DOMUtilities;
import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.util.ParsedURL;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.svg.SVGDocument;
import org.w3c.dom.svg.SVGSVGElement;

import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;

public final class SvgImage {

    private GraphicsNode rootSvgNode;

    private SVGDocument svgDocument;

    public SvgImage(String imagePath) throws IOException {
        String parser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
        svgDocument = (SVGDocument) factory.createDocument(imagePath);
        rootSvgNode = getRootNode(svgDocument);
    }

    public SvgImage(SVGDocument document) {
        svgDocument = document;
        rootSvgNode = getRootNode(svgDocument);
    }


    private static GraphicsNode getRootNode(SVGDocument document) {
        UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
        BridgeContext bridgeContext = new BridgeContext(userAgentAdapter);
        GVTBuilder builder = new GVTBuilder();
        return builder.build(bridgeContext, document);
    }


    public BufferedImage getImage(Integer heightOverride, Integer widthOverride) {

        int height = (heightOverride == null || heightOverride.intValue() == 0) ? fetchExistingImageHeightValue() : heightOverride;
        int width = (widthOverride == null || widthOverride.intValue() == 0) ? fetchExistingImageWidthValue() : widthOverride;

        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = GraphicsUtil.createGraphics(bufferedImage);

        DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
        SVGDocument cloneDocument = (SVGDocument) DOMUtilities.deepCloneDocument(svgDocument, impl);
        SVGSVGElement root = cloneDocument.getRootElement();

        // @@TODO - Currently hardcoded the inbound new color for testing, will use the ReportConfiguration Colors soon.
        //String hardCodedHexColor = "#ff00ff"; // pink
        String hardCodedHexColor = "#008000"; // green
        updateTagFillColor(root.getElementsByTagName("rect"), hardCodedHexColor);
        updateTagFillColor(root.getElementsByTagName("path"), hardCodedHexColor);

        UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
        BridgeContext ctx = new BridgeContext(userAgentAdapter);
        ctx.setDynamic(true);

        GVTBuilder builder = new GVTBuilder();
        GraphicsNode gvtRoot = builder.build(ctx, cloneDocument);

        AffineTransform px = new AffineTransform();

        String ref = new ParsedURL(svgDocument.getBaseURI()).getRef();
        try {
            px = ViewBox.getViewTransform(ref, root, width, height, ctx);
        } catch (BridgeException ex) {
            ex.printStackTrace();
        }

        g2d.transform(px);

        gvtRoot.paint(g2d);

        // Cleanup and return image
        g2d.dispose();
        return bufferedImage;
    }

    private void updateTagFillColor(NodeList nodeList, String newFillColor) {

        for (int i = 0; i < nodeList.getLength(); i++) {
            Node node = nodeList.item(i);
            NamedNodeMap namedNodeMap = node.getAttributes();
            for (int j = 0; j < namedNodeMap.getLength(); j++) {
                Node namedNode = namedNodeMap.item(j);
                if (namedNode.getNodeName().equalsIgnoreCase("fill")) {

                    StringBuilder beforeBuilder = new StringBuilder("\nBefore update: ")
                            .append("node name=" + namedNode.getNodeName())
                            .append(", node value=" + namedNode.getNodeValue());
                    System.out.println(beforeBuilder.toString());

                    namedNode.setNodeValue(newFillColor); // Change the color of the fill attribute.

                    StringBuilder afterBuilder = new StringBuilder("After update: ")
                            .append("node name=" + namedNode.getNodeName())
                            .append(", node value=" + namedNode.getNodeValue());
                    System.out.println(afterBuilder.toString());
                }
            }
        }
    }

    private int fetchExistingImageWidthValue() {
        return new Double(rootSvgNode.getBounds().getWidth()).intValue();
    }

    private int fetchExistingImageHeightValue() {
        return new Double(rootSvgNode.getBounds().getHeight()).intValue();
    }

}

Implementations: (That call this class - Interface)

package com.svg.poc;

import java.awt.image.BufferedImage;

public interface SvgIconImageRenderer {

    BufferedImage getSvgImage(String svgImageFilePath);

    BufferedImage getSvgImage(String svgImageFilePath, Integer heightOverride, Integer widthOverride);

}

Implementations: (That call this class - Implementation class)

package com.svg.poc;

import org.springframework.stereotype.Component;

import java.awt.image.BufferedImage;

@Component
public class SvgIconImageRendererImpl implements SvgIconImageRenderer {

    public BufferedImage getSvgImage(String svgImageFilePath) {
        return getSvgImage(svgImageFilePath, null, null);
    }

    public BufferedImage getSvgImage(String svgImageFilePath, Integer heightOverride, Integer widthOverride) {
        try {
            SvgImage svgImage = new SvgImage(getClass().getResource(svgImageFilePath).toURI().toString());
            return svgImage.getImage(heightOverride, widthOverride);
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

}

Test case:

package com.svg.poc;

import org.apache.batik.swing.JSVGCanvas;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;

public class SVGImageLoaderTest {

    private SvgIconImageRenderer svgIconImageRenderer = new SvgIconImageRendererImpl();

    private static final String ICON_HOUSES_SVG_URL_PATH = "/icon-houses.svg";

    public static void main(String[] args) {
        JFrame f = new JFrame("Svg Image test");
        SVGImageLoaderTest app = new SVGImageLoaderTest(f);

        f.getContentPane().add(app.createComponents());
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.setSize(400, 400);
        f.setVisible(true);
    }

    JFrame frame;
    JSVGCanvas svgCanvas = new JSVGCanvas();

    public SVGImageLoaderTest(JFrame f) {
        frame = f;
    }

    public JComponent createComponents() {
        BufferedImage bufferedSvgImage = svgIconImageRenderer.getSvgImage(ICON_HOUSES_SVG_URL_PATH);
        JLabel label = new JLabel(new ImageIcon(bufferedSvgImage));

        final JPanel panel = new JPanel(new BorderLayout());
        JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));

        p.add(label);
        panel.add(p, BorderLayout.NORTH);
        panel.add(svgCanvas, BorderLayout.CENTER);

        return panel;
    }

}

icon-houses.svg

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve">

    <g>

      <rect x="5" y="5" width="200" fill="#ff0000" height="30" rx="15" ry="15" stroke="gray" />

      <rect x="5" y="45" width="400" fill="#ff0000" height="30" rx="15" ry="15" stroke="gray" />

      <path display="inline" fill="#8D8379" d="M243.754,124.987c-31.017,0-56.246,25.249-56.246,56.257
        c0,28.494,45.661,106.85,50.86,115.676c1.128,1.911,3.173,3.08,5.386,3.08c2.212,0,4.27-1.169,5.395-3.08
        c5.208-8.826,50.862-87.182,50.862-115.676C300.011,150.236,274.771,124.987,243.754,124.987 M243.754,212.498
        c-17.241,0-31.255-14.015-31.255-31.254c0-17.229,14.014-31.256,31.255-31.256c17.24,0,31.254,14.026,31.254,31.256
        C275.008,198.483,260.995,212.498,243.754,212.498"/>

    </g>

    <polygon display="inline" fill="#8D8379" points="149.046,153.722 149.013,153.722 149.08,153.722     "/>

</svg>

maven dependencies:

<dependencies>
        <!--svg image dependencies-->
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-transcoder</artifactId>
            <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-swing</artifactId>
            <version>1.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>xmlgraphics-commons</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.2.2.RELEASE</version>
        </dependency>
    </dependencies>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM