AsciiDocCompiler.java
package pro.verron.asciidoc.compiler;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import pro.verron.asciidoc.converters.AsciiDocToHtml;
import pro.verron.asciidoc.converters.AsciiDocToSvg;
import pro.verron.asciidoc.converters.AsciiDocToText;
import pro.verron.asciidoc.core.AsciiDocModel;
import pro.verron.asciidoc.core.AsciiDocParser;
import pro.verron.asciidoc.docx.AsciiDocToDocx;
import pro.verron.asciidoc.docx.DocxToAsciiDoc;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.nio.file.Files;
import java.nio.file.Path;
/// Facade utilities to parse AsciiDoc and compile it to different targets.
public final class AsciiDocCompiler {
private static final AsciiDocToHtml MODEL_TO_HTML = new AsciiDocToHtml();
private static final AsciiDocToSvg MODEL_TO_SVG = new AsciiDocToSvg();
private static final AsciiDocParser ASCIIDOC_TO_MODEL = new AsciiDocParser();
private static final AsciiDocToDocx MODEL_TO_DOCX = new AsciiDocToDocx();
private AsciiDocCompiler() {
throw new IllegalStateException("Utility class");
}
/// Compiles the AsciiDoc source text directly to a WordprocessingMLPackage.
///
/// @param asciidoc source text
/// @return package with rendered content
public static WordprocessingMLPackage toDocx(String asciidoc) {
return toDocx(toModel(asciidoc));
}
/// Compiles the parsed model to a WordprocessingMLPackage.
///
/// @param model parsed model
/// @return package with rendered content
public static WordprocessingMLPackage toDocx(AsciiDocModel model) {
return MODEL_TO_DOCX.apply(model);
}
/// Parses AsciiDoc source text into an [AsciiDocModel].
///
/// @param asciidoc source text
/// @return parsed model
public static AsciiDocModel toModel(String asciidoc) {
return ASCIIDOC_TO_MODEL.apply(asciidoc);
}
/// Compiles the parsed model to an SVG document.
///
/// @param model parsed model
/// @return SVG representation
public static String toSvg(AsciiDocModel model) {
return MODEL_TO_SVG.apply(model);
}
/// Compiles the AsciiDoc source text directly to HTML.
///
/// @param asciidoc source text
/// @return HTML representation
public static String toHtml(String asciidoc) {
var model = ASCIIDOC_TO_MODEL.apply(asciidoc);
return MODEL_TO_HTML.apply(model);
}
/// Compiles the parsed model to HTML.
///
/// @param model parsed model
/// @return HTML representation
public static String toHtml(AsciiDocModel model) {
return MODEL_TO_HTML.apply(model);
}
/// Compiles a WordprocessingMLPackage into the textual AsciiDoc representation used by tests. This mirrors the
/// legacy Stringifier output to preserve expectations.
///
/// @param pkg a Word document package
/// @return textual representation
public static String toAsciidoc(WordprocessingMLPackage pkg) {
return toAsciidoc(pkg, false);
}
/// Converts the given WordprocessingMLPackage into its textual AsciiDoc representation.
///
/// @param pkg a Word document package
/// @param skipComments whether to omit comments from the output
/// @return the textual AsciiDoc representation of the Word document package
public static String toAsciidoc(WordprocessingMLPackage pkg, boolean skipComments) {
var model = toModel(pkg);
return toAsciidoc(model, skipComments);
}
/// Parses a Word document into an [AsciiDocModel].
///
/// @param pkg a Word document package
/// @return parsed model
public static AsciiDocModel toModel(WordprocessingMLPackage pkg) {
var compiler = new DocxToAsciiDoc(pkg);
return compiler.apply(pkg);
}
/// Converts the given AsciiDoc model into its textual AsciiDoc representation.
///
/// @param model the parsed AsciiDoc model to be converted
/// @param skipComments whether to omit comments from the output
/// @return the textual AsciiDoc representation of the model
public static String toAsciidoc(AsciiDocModel model, boolean skipComments) {
return new AsciiDocToText(skipComments).apply(model);
}
/// Converts the given AsciiDoc model into its textual AsciiDoc representation.
///
/// @param model the parsed AsciiDoc model to be converted
/// @return the textual AsciiDoc representation of the model
public static String toAsciidoc(AsciiDocModel model) {
return new AsciiDocToText(false).apply(model);
}
/// Reads AsciiDoc source from an input stream and compiles it to SVG.
///
/// @param input source stream
/// @return SVG representation
public static String toSvg(InputStream input) {
try {
return toSvg(new String(input.readAllBytes()));
} catch (IOException e) {
throw new RuntimeException("Failed to read AsciiDoc input stream", e);
}
}
/// Compiles the AsciiDoc source text directly to an SVG document.
///
/// @param asciidoc source text
/// @return SVG representation
public static String toSvg(String asciidoc) {
var model = ASCIIDOC_TO_MODEL.apply(asciidoc);
return MODEL_TO_SVG.apply(model);
}
/// Saves the AsciiDoc source text directly to a PNG image file.
///
/// @param asciidoc source text
/// @param path path to save the image
public static void toImage(String asciidoc, Path path) {
saveSvgAsImage(toSvg(asciidoc), path);
}
/// Saves the given SVG document as a PNG image file.
///
/// @param svg SVG source
/// @param path path to save the image
public static void saveSvgAsImage(String svg, Path path) {
saveSvgAsImage(svg, path, 96, Color.WHITE);
}
/// Saves the given SVG document as a PNG image file with specific DPI and background color.
///
/// @param svg SVG source
/// @param path path to save the image
/// @param dpi dots per inch
/// @param background background color (null for transparent)
public static void saveSvgAsImage(String svg, Path path, int dpi, Color background) {
final var mmPerInch = 25.4f;
var transcoder = new PNGTranscoder();
if (background != null) transcoder.addTranscodingHint(PNGTranscoder.KEY_BACKGROUND_COLOR, background);
transcoder.addTranscodingHint(PNGTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, mmPerInch / dpi);
var input = new StringReader(svg);
var transcoderInput = new TranscoderInput(input);
try (OutputStream output = Files.newOutputStream(path)) {
var transcoderOutput = new TranscoderOutput(output);
transcoder.transcode(transcoderInput, transcoderOutput);
} catch (IOException e) {
throw new RuntimeException("IO error while writing PNG image", e);
} catch (TranscoderException e) {
throw new RuntimeException("Failed to transcode SVG image", e);
}
}
}