package boxrenderer.xhtml;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import javax.imageio.ImageIO;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.IOUtils;
import boxrenderer.Box;
import boxrenderer.ImageRenderer;
import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGUniverse;
public class BackgroundImageCssStyle extends AbstractCssStyle implements CssStyle {
private static class BufferedImageImageRenderer implements ImageRenderer {
private BufferedImage img;
public BufferedImageImageRenderer(BufferedImage img) {
if(img == null) {
throw new RuntimeException("image is null");
}
this.img = img;
}
@Override
public Dimension getDimension(Graphics2D g2) throws Exception {
return new Dimension(img.getWidth(), img.getHeight());
}
@Override
public void render(Graphics2D g2) throws Exception {
g2.drawImage(img, null, 0, 0);
}
}
@Override
public void style(Box box) throws Exception {
String value = getProperty().getValue();
if(StringUtils.startsWith(value, "inline")) {
String imgData = StringUtils.substringBetween(value, "('", "')");
byte[] buf = hexStringToByteArray(imgData);
final BufferedImage img = ImageIO.read(new ByteArrayInputStream(buf));
box.setBackgroundImage(new BufferedImageImageRenderer(img));
} else if(StringUtils.startsWith(value, "url")) {
String source = StringUtils.substringBetween(value, "('", "')");
if(StringUtils.endsWithIgnoreCase(source, ".svg")) {
box.setBackgroundImage(makeSvgImageRenderer(source));
} else {
box.setBackgroundImage(makeImageImageRenderer(source));
}
} else if(StringUtils.startsWith(value, "-moz-linear-gradient")) {
// XXX does linear gradient from left to right only
Color from = Colors.getPaint(StringUtils.split(
StringUtils.substringBetween(value, "(", ")"), ',')[1]);
Color to = Colors.getPaint(StringUtils.split(
StringUtils.substringBetween(value, "(", ")"), ',')[2]);
box.setLinearGradient(from, to);
}
}
//http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
private byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
private ImageRenderer makeSvgImageRenderer(String source) {
InputStream stream = null;
try {
stream = getResolver().resolve(source);
SVGUniverse svg = new SVGUniverse();
URI uri = svg.loadSVG(stream, source);
final SVGDiagram diagram = svg.getDiagram(uri, false);
return new ImageRenderer() {
@Override
public Dimension getDimension(Graphics2D g2) throws Exception {
return new Dimension((int)diagram.getWidth(), (int)diagram.getHeight());
}
@Override
public void render(Graphics2D g2) throws Exception {
Graphics2D g0 = (Graphics2D)g2.create();
try {
// center the svg shape in the diagram
// final Shape shape = diagram.getRoot().getShape();
// final double w = diagram.getWidth();
// final double h = diagram.getHeight();
// AffineTransform t = g0.getTransform();
// t.concatenate(AffineTransform.getTranslateInstance(
// -shape.getBounds2D().getX(), -shape.getBounds2D().getY()));
// t.concatenate(AffineTransform.getTranslateInstance(
// ((w-shape.getBounds2D().getWidth())/2.0),
// ((h-shape.getBounds2D().getHeight())/2.0)));
// g0.setTransform(t);
diagram.render(g0);
} finally {
g0.dispose();
}
}};
} catch(Exception e) {
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(stream);
}
}
private ImageRenderer makeImageImageRenderer(String source) {
InputStream stream = null;
try {
stream = getResolver().resolve(source);
return new BufferedImageImageRenderer(ImageIO.read(stream));
} catch(Exception e) {
throw new RuntimeException(e);
} finally {
IOUtils.closeQuietly(stream);
}
}
}