/*
* Copyright 2014-2015 Robin Stuart, Daniel Gredler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.org.okapibarcode.output;
import static uk.org.okapibarcode.graphics.TextAlignment.CENTER;
import static uk.org.okapibarcode.graphics.TextAlignment.JUSTIFY;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Text;
import uk.org.okapibarcode.backend.OkapiInternalException;
import uk.org.okapibarcode.backend.Symbol;
import uk.org.okapibarcode.graphics.Circle;
import uk.org.okapibarcode.graphics.Color;
import uk.org.okapibarcode.graphics.Hexagon;
import uk.org.okapibarcode.graphics.Rectangle;
import uk.org.okapibarcode.graphics.TextAlignment;
import uk.org.okapibarcode.graphics.TextBox;
/**
* Renders symbologies to SVG (Scalable Vector Graphics).
*
* @author Robin Stuart
* @author Daniel Gredler
*/
public class SvgRenderer implements SymbolRenderer {
/** The output stream to render to. */
private final OutputStream out;
/** The magnification factor to apply. */
private final double magnification;
/** The paper (background) color. */
private final Color paper;
/** The ink (foreground) color. */
private final Color ink;
/** Whether or not to include the XML prolog in the output. */
private final boolean xmlProlog;
/**
* Creates a new SVG renderer.
*
* @param out the output stream to render to
* @param magnification the magnification factor to apply
* @param paper the paper (background) color
* @param ink the ink (foreground) color
* @param xmlProlog whether or not to include the XML prolog in the output (usually {@code true} for
* standalone SVG documents, {@code false} for SVG content embedded directly in HTML documents)
*/
public SvgRenderer(OutputStream out, double magnification, Color paper, Color ink, boolean xmlProlog) {
this.out = out;
this.magnification = magnification;
this.paper = paper;
this.ink = ink;
this.xmlProlog = xmlProlog;
}
/** {@inheritDoc} */
@Override
public void render(Symbol symbol) throws IOException {
String content = symbol.getContent();
int width = (int) Math.ceil(symbol.getWidth() * magnification);
int height = (int) Math.ceil(symbol.getHeight() * magnification);
int marginX = (int) (symbol.getQuietZoneHorizontal() * magnification);
int marginY = (int) (symbol.getQuietZoneVertical() * magnification);
String title;
if (content.isEmpty()) {
title = "OkapiBarcode Generated Symbol";
} else {
title = content;
}
String fgColour = String.format("%02X", ink.red)
+ String.format("%02X", ink.green)
+ String.format("%02X", ink.blue);
String bgColour = String.format("%02X", paper.red)
+ String.format("%02X", paper.green)
+ String.format("%02X", paper.blue);
try (ExtendedOutputStreamWriter writer = new ExtendedOutputStreamWriter(out, "%.2f")) {
// XML Prolog
if(xmlProlog) {
writer.append("\n");
writer.append("\n");
}
// Header
writer.append("\n");
}
}
/**
* Cleans / sanitizes the specified string for inclusion in XML. A bit convoluted, but we're
* trying to do it without adding an external dependency just for this...
*
* @param s the string to be cleaned / sanitized
* @return the cleaned / sanitized string
*/
protected String clean(String s) {
// remove control characters
s = s.replaceAll("[\u0000-\u001f]", "");
// escape XML characters
try {
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Text text = document.createTextNode(s);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
DOMSource source = new DOMSource(text);
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(source, result);
return writer.toString();
} catch (ParserConfigurationException | TransformerException | TransformerFactoryConfigurationError e) {
return s;
}
}
}