package gutenberg.itext;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfPTableEvent;
import gutenberg.itext.model.SourceCode;
import gutenberg.pygments.Pygments;
import gutenberg.pygments.StyleSheet;
import gutenberg.pygments.TokenWithValue;
import gutenberg.pygments.Tokens;
import gutenberg.util.RGB;
import gutenberg.util.Style;
import java.util.Arrays;
import java.util.List;
import static gutenberg.itext.ITextUtils.toColor;
/**
* @author <a href="http://twitter.com/aloyer">@aloyer</a>
*/
public class PygmentsAdapter {
private final Pygments pygments;
private final StyleSheet styleSheet;
private final Styles styles;
public PygmentsAdapter(Pygments pygments, StyleSheet styleSheet, Styles styles) {
argNotNull("pygments cannot be null", pygments);
argNotNull("styleSheet cannot be null", styleSheet);
argNotNull("styles cannot be null", styles);
this.pygments = pygments;
this.styleSheet = styleSheet;
this.styles = styles;
}
private void argNotNull(String msg, Object o) {
if (o == null)
throw new IllegalArgumentException(msg);
}
public List<Element> process(SourceCode sourceCode) {
String lang = sourceCode.lang();
String content = sourceCode.content();
boolean linenos = sourceCode.showLineNumbers();
Tokens tokens = pygments.tokenize(lang, content);
Paragraph p = new Paragraph();
for (TokenWithValue token : tokens) {
Style style = styleSheet.styleOf(token.token);
BaseColor color = toColor(style.fg());
int s = calculateStyle(style);
Font font = styles.getFont(Styles.CODE_FONT, s, color).get();
Chunk o = new Chunk(token.value, font);
RGB bg = style.bg();
if (bg != null)
o.setBackground(toColor(bg));
p.add(o);
}
PdfPCell cell = new PdfPCell(p);
cell.setPaddingBottom(5.0f);
cell.setBorder(Rectangle.NO_BORDER);
PdfPTable table = new PdfPTable(1);
table.addCell(cell);
table.setSpacingBefore(5.0f);
table.setSpacingAfter(5.0f);
table.setTableEvent(new TableBackground(toColor(styleSheet.backgroundColor())));
return Arrays.<Element>asList(table);
}
public static class TableBackground implements PdfPTableEvent {
private final BaseColor backgroundColor;
public TableBackground(BaseColor backgroundColor) {
this.backgroundColor = backgroundColor;
}
public void tableLayout(PdfPTable table, float[][] width, float[] height,
int headerRows, int rowStart, PdfContentByte[] canvas) {
// because table is only one cell length, one can focus on using the first width
float xmin = width[0][0];
float xmax = width[0][1];
float ymin = height[height.length - 1];
float ymax = height[0];
float d = 3;
PdfContentByte background = canvas[PdfPTable.BASECANVAS];
background.saveState();
background.setColorFill(backgroundColor);
background.roundRectangle(
xmin - d,
ymin - d,
(xmax + d) - (xmin - d),
(ymax + d) - (ymin - d),
d + d);
background.fill();
background.restoreState();
}
}
private int calculateStyle(Style style) {
int s = Font.NORMAL;
if (style.isBold()) {
s |= Font.BOLD;
}
if (style.isItalic()) {
s |= Font.ITALIC;
}
if (style.isStrikethrough()) {
s |= Font.STRIKETHRU;
}
if (style.isUnderline()) {
s |= Font.UNDERLINE;
}
return s;
}
}