SVG Pattern Paint

A discussion forum for JFreeSVG (a fast, lightweight, SVG generator for the Java platform).
Locked
remiohead
Posts: 201
Joined: Fri Oct 02, 2009 3:53 pm
antibot: No, of course not.

SVG Pattern Paint

Post by remiohead » Mon Jan 27, 2014 11:56 pm

I wrote this class to add some basic geometric pattern paint support (we use such paints with JFreeChart). It uses SVGGraphics2D own paint methods to construct the pattern definition. Please feel free to incorporate it or parts of it or just the idea into any future version.

Code: Select all

public class SVGPatternPaint 
	implements 	Paint {
	
	private final int width;
	private final int height;
	private final PatternPainter painter;

	public SVGPatternPaint(
			final int width,
			final int height,
			final PatternPainter painter) {
		this.width = width;
		this.height = height;
		this.painter = painter;
	}
	
	public void writeSvg(
			final String id,
			final SVGGraphics2D g2,
			final StringBuilder sb) {
		sb.append("<pattern ")
			.append("id=\""+id+"\" ")
			.append("width=\""+this.width+"\" ")
			.append("height=\""+this.height+"\" ")
			.append("patternUnits=\"userSpaceOnUse\" ")
			.append(">");
		this.painter.paintPattern(g2);
		sb.append("</pattern>");
	}
	
	@Override
	public int getTransparency() {
		return 0;
	}

	@Override
	public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
			Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) {
		return new PaintContext() {
			@Override
			public void dispose() {}

			@Override
			public ColorModel getColorModel() {
				return ColorModel.getRGBdefault();
			}

			@Override
			public Raster getRaster(int x, int y, int w, int h) {
				return getColorModel().createCompatibleWritableRaster(w, h);
			}
		};
	}
	
	public static interface PatternPainter {
		void paintPattern(Graphics2D g2);
	}

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: SVG Pattern Paint

Post by david.gilbert » Sun Feb 02, 2014 4:47 pm

Thanks, this looks like a great idea. I presume you must have added some extra code to the setPaint() method in SVGGraphics2D to register the pattern paint instance, and some code in getSVGElement() to write the pattern definitions to SVG.

I'm thinking the paintPattern(Graphics2D) method in the PatternPainter interface could also take width and height arguments so that it knows the bounds that it should be working with. And also, I guess this implementation won't show any pattern when rendering to the screen, only for SVG...I will take a look at the Paint interface to see if there is some way to make it work on screen. Or did I miss something maybe?
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

remiohead
Posts: 201
Joined: Fri Oct 02, 2009 3:53 pm
antibot: No, of course not.

Re: SVG Pattern Paint

Post by remiohead » Fri Feb 07, 2014 3:27 pm

Extending from TexturePaint addresses the screen issue somewhat. This is the class I'm using in my app.

Code: Select all

public interface SVGPaint extends Paint {
	
	public void writeSvg(
			final String id,
			final SVGGraphics2D g2,
			final StringBuilder sb);
}

Code: Select all

public class SVGTexturePaint 
	extends		TexturePaint
	implements 	SVGPaint {
	
	private final int width;
	private final int height;
	private final TexturePainter painter;
	
	public SVGTexturePaint(
			final BufferedImage txtr, 
			final Rectangle2D anchor,
			final TexturePainter painter) {
		super(txtr, anchor);
		this.width = txtr.getWidth();
		this.height = txtr.getHeight();
		this.painter = painter;
	}
	
	@Override
	public void writeSvg(
			final String id,
			final SVGGraphics2D g2,
			final StringBuilder sb) {
		sb.append("<pattern ")
			.append("id=\""+id+"\" ")
			.append("width=\""+this.width+"\" ")
			.append("height=\""+this.height+"\" ")
			.append("patternUnits=\"userSpaceOnUse\" ")
			.append(">");
		this.painter.paintTexture(g2, 
				this.width, 
				this.height);
		sb.append("</pattern>");
	}
	
	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}


	public TexturePainter getPainter() {
		return painter;
	}

	public static interface TexturePainter {
		void paintTexture(
				final Graphics2D g2, 
				final int width, 
				final int height);
	}
}
In set paint:

Code: Select all

 else if(paint instanceof SVGPaint) {
        	SVGPaint tp = (SVGPaint)paint;
       		int count = this.patternPaints.keySet().size();
    		String id = "tp"+count;
    		this.elementIDs.add(id);
    		this.patternPaints.put(id, tp);
    		this.texturePaintRef = id;
        }
And finally in getSVGElement:

Code: Select all

        for(String key : this.patternPaints.keySet()) {
        	final StringBuilder saved = this.sb;
        	try {
	        	this.sb = defs;
	        	this.patternPaints.get(key).writeSvg(
	        			key, this, defs);
        	} finally {
        		this.sb = saved;
        	}
        }

david.gilbert
JFreeChart Project Leader
Posts: 11734
Joined: Fri Mar 14, 2003 10:29 am
antibot: No, of course not.
Contact:

Re: SVG Pattern Paint

Post by david.gilbert » Tue Feb 25, 2014 5:49 pm

I need to spend a bit more time on this to make sure the reuse of the same SVGGraphics2D instance to generate the pattern is going to be safe. I will leave it out for the 1.7 release and come back to it later.
David Gilbert
JFreeChart Project Leader

:idea: Read my blog
:idea: Support JFree via the Github sponsorship program

Locked