/*******************************************************************************
* Copyright 2010 Simon Mieth
*
* 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 org.kabeja.batik.tools;
import java.awt.Color;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import org.apache.batik.transcoder.Transcoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.TranscodingHints.Key;
import org.apache.batik.transcoder.image.ImageTranscoder;
import org.kabeja.xml.AbstractSAXFilter;
import org.kabeja.xml.SAXSerializer;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public abstract class AbstractSAXSerializer extends AbstractSAXFilter
implements SAXSerializer {
public static final String TRANSCODER_HINT_TYPE_COLOR = "color";
public static final String TRANSCODER_HINT_TYPE_INTEGER = "integer";
public static final String TRANSCODER_HINT_TYPE_FLOAT = "float";
public static final String SUFFIX_JPEG = "jpg";
public static final String SUFFIX_PNG = "png";
public static final String SUFFIX_TIFF = "tif";
public static final String SUFFIX_PDF = "pdf";
public static final String MIME_TYPE_JPEG = "image/jepg";
public static final String MIME_TYPE_PNG = "image/png";
public static final String MIME_TYPE_TIFF = "image/tiff";
public static final String MIME_TYPE_PDF = "application/pdf";
public static final String TRANSCODER_HINT_TYPE_SUFFIX = "_type";
public static final String TRANSCODER_HINT_PREFIX = "KEY";
/**
* Allows you to setup a width in px,inch,mm,cm,pt. This property overrides the PAPER_PROPERTY.
*/
public static final String PROPERTY_WIDTH = "width";
/**
* Allows you to setup a height in px,inch,mm,cm,pt. This property overrides the PAPER_PROPERTY.
*/
public static final String PROPERTY_HEIGHT = "height";
/**
* Allows you to setup the dpi
*/
public static final String PROPERTY_DPI = "dpi";
public static final String PROPERTY_QUALITY = "quality";
/**
* You can choose A0-A6 papers and Letter.
*/
public static final String PROPERTY_PAPER = "paper";
/**
* Lets you choose the orientation of a paper (landscape).
*/
public static final String PROPERTY_ORIENTATION = "orientation";
public static final float INCH_TO_MM = 25.4f;
public static final float PT_TO_MM = 0.3527777777777f;
public int DPI = 96;
public float PIXEL_UNIT_TO_MM = INCH_TO_MM / DPI;
protected OutputStream out;
protected float width;
protected float height;
protected double quality = 0.9;
protected Transcoder transcoder;
protected boolean scaleToFit = true;
protected Document document;
protected abstract Transcoder createTranscoder();
/*
* (non-Javadoc)
*
* @see org.kabeja.xml.SAXSerializer#setProperties(java.util.Map)
*/
public void setProperties(Map properties) {
if (properties.containsKey(PROPERTY_DPI)) {
this.DPI = Integer.parseInt((String) properties.get(PROPERTY_DPI));
this.PIXEL_UNIT_TO_MM = INCH_TO_MM / this.DPI;
}
if (properties.containsKey(PROPERTY_PAPER)) {
this.parsePaper(((String) properties.get(PROPERTY_PAPER)).toLowerCase());
}
if (properties.containsKey(PROPERTY_QUALITY)) {
this.quality = Double.parseDouble((String) properties.get(
PROPERTY_QUALITY));
}
if (properties.containsKey(PROPERTY_WIDTH)) {
this.width = unitsToPixel(((String) properties.get(PROPERTY_WIDTH)).trim());
}
if (properties.containsKey(PROPERTY_HEIGHT)) {
this.height = unitsToPixel(((String) properties.get(PROPERTY_HEIGHT)).trim());
}
if (properties.containsKey(PROPERTY_ORIENTATION)) {
String orientation = ((String) properties.get(PROPERTY_ORIENTATION)).toLowerCase();
if (orientation.equals("landscape")) {
float w = this.width;
this.width = this.height;
this.height = w;
}
}
this.properties = properties;
}
/*
* (non-Javadoc)
*
* @see org.kabeja.xml.SAXSerializer#setOutput(java.io.OutputStream)
*/
public void setOutput(OutputStream out) {
this.out = out;
}
/*
* (non-Javadoc)
*
* @see org.xml.sax.ContentHandler#endDocument()
*/
public void endDocument() throws SAXException {
super.endDocument();
try {
transcoder = createTranscoder();
setupTranscoder(transcoder);
TranscoderInput transInput = new TranscoderInput(this.document);
// Buffering is done by the pipeline (See shouldSetContentLength)
TranscoderOutput transOutput = new TranscoderOutput(this.out);
setupTranscoder(transcoder);
transcode(transInput, transOutput);
} catch (TranscoderException e) {
throw new SAXException(e);
}
}
/**
* Override this if your Transcoder support more
* options.
* @param t
*/
protected void setupTranscoder(Transcoder t) {
//setup the transcoder hints
Iterator i = this.properties.keySet().iterator();
while(i.hasNext()){
String key = (String)i.next();
if(key.startsWith(TRANSCODER_HINT_PREFIX)){
Field[] fields = transcoder.getClass().getFields();
for(int x=0;x<fields.length;x++){
if(fields[x].getName().equals(key)){
try {
Key k = (Key)fields[x].get(null);
String type = (String)this.properties.get((key+TRANSCODER_HINT_TYPE_SUFFIX));
Object value=null;
if(TRANSCODER_HINT_TYPE_FLOAT.equals(type)){
value = new Float(Float.parseFloat((String)this.properties.get(key)));
}else if(TRANSCODER_HINT_TYPE_INTEGER.equals(type)){
value = new Integer(Integer.parseInt((String)this.properties.get(key)));
}else if(TRANSCODER_HINT_TYPE_COLOR.equals(type)){
value = Color.decode((String)this.properties.get(key));
}else{
value = (String)this.properties.get(key);
}
transcoder.addTranscodingHint(k,value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
transcoder.addTranscodingHint(ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER,
new Float(this.PIXEL_UNIT_TO_MM));
if (this.width > 0.0) {
transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH,
new Float(this.width));
}
if (this.height > 0.0) {
transcoder.addTranscodingHint(ImageTranscoder.KEY_HEIGHT,
new Float(this.height));
}
}
/*
* (non-Javadoc)
*
* @see org.xml.sax.ContentHandler#startDocument()
*/
public void startDocument() throws SAXException {
try {
SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
TransformerHandler f = factory.newTransformerHandler();
this.document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.newDocument();
// put the the transformer in the chain
f.setResult(new DOMResult(document));
super.setContentHandler(f);
} catch (TransformerConfigurationException e) {
throw new SAXException(e);
} catch (IllegalArgumentException e) {
throw new SAXException(e);
} catch (TransformerFactoryConfigurationError e) {
throw new SAXException(e.getException());
} catch (ParserConfigurationException e) {
throw new SAXException(e);
}
super.startDocument();
}
protected void transcode(TranscoderInput input, TranscoderOutput output)
throws TranscoderException {
transcoder.transcode(input, output);
}
protected float unitsToPixel(String size) {
if (size.endsWith("px")) {
return Float.parseFloat(size.substring(0, size.length() - 2));
} else if (size.endsWith("in")) {
return (Float.parseFloat(size.substring(0, size.length() - 2)) * INCH_TO_MM) / PIXEL_UNIT_TO_MM;
} else if (size.endsWith("pt")) {
return (Float.parseFloat(size.substring(0, size.length() - 2)) * PT_TO_MM) / PIXEL_UNIT_TO_MM;
} else if (size.endsWith("cm")) {
float units = Float.parseFloat(size.substring(0, size.length() - 2));
float pixel = (float) ((units * 100) / PIXEL_UNIT_TO_MM);
return pixel;
} else if (size.endsWith("mm")) {
float units = Float.parseFloat(size.substring(0, size.length() - 2));
float pixel = (float) (units / PIXEL_UNIT_TO_MM);
return pixel;
} else if (size.endsWith("m")) {
float units = Float.parseFloat(size.substring(0, size.length() - 1));
float pixel = (float) ((units * 1000) / PIXEL_UNIT_TO_MM);
return pixel;
} else {
return Float.parseFloat(size);
}
}
protected void parsePaper(String paper) {
if (paper.equals("a0")) {
this.width = 841 / PIXEL_UNIT_TO_MM;
this.height = 1189 / PIXEL_UNIT_TO_MM;
} else if (paper.equals("a1")) {
this.width = 594 / PIXEL_UNIT_TO_MM;
this.height = 841 / PIXEL_UNIT_TO_MM;
} else if (paper.equals("a2")) {
this.width = 420 / PIXEL_UNIT_TO_MM;
this.height = 594 / PIXEL_UNIT_TO_MM;
} else if (paper.equals("a3")) {
this.width = 297 / PIXEL_UNIT_TO_MM;
this.height = 420 / PIXEL_UNIT_TO_MM;
} else if (paper.equals("a4")) {
this.width = 210 / PIXEL_UNIT_TO_MM;
this.height = 297 / PIXEL_UNIT_TO_MM;
} else if (paper.equals("a5")) {
this.width = 148 / PIXEL_UNIT_TO_MM;
this.height = 210 / PIXEL_UNIT_TO_MM;
} else if (paper.equals("a6")) {
this.width = 105 / PIXEL_UNIT_TO_MM;
this.height = 148 / PIXEL_UNIT_TO_MM;
} else if (paper.equals("letter")) {
this.width = 216 / PIXEL_UNIT_TO_MM;
this.height = 279 / PIXEL_UNIT_TO_MM;
}
//add more papers here
}
public Map getProperties() {
return this.properties;
}
}