package com.itextpdf.samples.htmlsamples.chapter05; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; import com.itextpdf.barcodes.BarcodeQRCode; import com.itextpdf.barcodes.qrcode.EncodeHintType; import com.itextpdf.barcodes.qrcode.ErrorCorrectionLevel; import com.itextpdf.html2pdf.ConverterProperties; import com.itextpdf.html2pdf.HtmlConverter; import com.itextpdf.html2pdf.attach.ITagWorker; import com.itextpdf.html2pdf.attach.ProcessorContext; import com.itextpdf.html2pdf.attach.impl.DefaultTagWorkerFactory; import com.itextpdf.html2pdf.css.apply.ICssApplier; import com.itextpdf.html2pdf.css.apply.impl.BlockCssApplier; import com.itextpdf.html2pdf.css.apply.impl.DefaultCssApplierFactory; import com.itextpdf.layout.IPropertyContainer; import com.itextpdf.layout.element.Image; import com.itextpdf.licensing.base.LicenseKey; import com.itextpdf.styledxmlparser.node.IElementNode; /** * Converts an HTML file to a PDF document, introducing a custom tag to create * a QR Code involving a custom TagWorker and a custom CssApplier. */ public class C05E04_QRCode { /** * The path to the resulting PDF file. */ public static final String DEST = "./target/htmlsamples/ch05/qrcode.pdf"; /** * The path to the source HTML file. */ public static final String SRC = "./src/main/resources/htmlsamples/html/qrcode.html"; /** * The main method of this example. * * @param args no arguments are needed to run this example. * @throws IOException signals that an I/O exception has occurred. */ public static void main(String[] args) throws IOException { try (FileInputStream license = new FileInputStream(System.getenv("ITEXT7_LICENSEKEY") + "/itextkey-html2pdf_typography.json")) { LicenseKey.loadLicenseFile(license); } File file = new File(DEST); file.getParentFile().mkdirs(); C05E04_QRCode app = new C05E04_QRCode(); app.createPdf(SRC, DEST); } /** * Creates the PDF file. * * @param src the path to the source HTML file * @param dest the path to the resulting PDF * @throws IOException signals that an I/O exception has occurred. */ public void createPdf(String src, String dest) throws IOException { ConverterProperties properties = new ConverterProperties(); properties .setCssApplierFactory(new QRCodeTagCssApplierFactory()) .setTagWorkerFactory(new QRCodeTagWorkerFactory()); HtmlConverter.convertToPdf(new File(src), new File(dest), properties); } /** * A factory for creating QRCodeTagCssApplier objects. */ class QRCodeTagCssApplierFactory extends DefaultCssApplierFactory { /* (non-Javadoc) * @see com.itextpdf.html2pdf.css.apply.impl.DefaultCssApplierFactory#getCustomCssApplier(com.itextpdf.html2pdf.html.node.IElementNode) */ @Override public ICssApplier getCustomCssApplier(IElementNode tag) { if (tag.name().equals("qr")) { return new BlockCssApplier(); } return null; } } /** * A factory for creating QRCodeTagWorker objects. */ class QRCodeTagWorkerFactory extends DefaultTagWorkerFactory { /* (non-Javadoc) * @see com.itextpdf.html2pdf.attach.impl.DefaultTagWorkerFactory#getCustomTagWorker(com.itextpdf.html2pdf.html.node.IElementNode, com.itextpdf.html2pdf.attach.ProcessorContext) */ @Override public ITagWorker getCustomTagWorker(IElementNode tag, ProcessorContext context) { if (tag.name().equals("qr")) { return new QRCodeTagWorker(tag, context); } return null; } } /** * The custom ITagWorker implementation for the qr-tag. */ static class QRCodeTagWorker implements ITagWorker { /** * The different error corrections that are allowed. */ private static String[] allowedErrorCorrection = {"L", "M", "Q", "H"}; /** * The different characters sets that are allowed. */ private static String[] allowedCharset = {"Cp437", "Shift_JIS", "ISO-8859-1", "ISO-8859-16"}; /** * The QR code object. */ private BarcodeQRCode qrCode; /** * The QR code as an Image object. */ private Image qrCodeAsImage; /** * Instantiates a new QR code tag worker. * * @param element the element node * @param context the processor context */ public QRCodeTagWorker(IElementNode element, ProcessorContext context) { //Retrieve all necessary properties to create the barcode Map hints = new HashMap<>(); //Character set String charset = element.getAttribute("charset"); if (checkCharacterSet(charset)) { hints.put(EncodeHintType.CHARACTER_SET, charset); } //Error-correction level String errorCorrection = element.getAttribute("errorcorrection"); if (checkErrorCorrectionAllowed(errorCorrection)) { ErrorCorrectionLevel errorCorrectionLevel = getErrorCorrectionLevel(errorCorrection); hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel); } //Create the QR-code qrCode = new BarcodeQRCode("placeholder", hints); } /* (non-Javadoc) * @see com.itextpdf.html2pdf.attach.ITagWorker#processContent(java.lang.String, com.itextpdf.html2pdf.attach.ProcessorContext) */ @Override public boolean processContent(String content, ProcessorContext context) { //Add content to the barcode qrCode.setCode(content); return true; } /* (non-Javadoc) * @see com.itextpdf.html2pdf.attach.ITagWorker#processTagChild(com.itextpdf.html2pdf.attach.ITagWorker, com.itextpdf.html2pdf.attach.ProcessorContext) */ @Override public boolean processTagChild(ITagWorker childTagWorker, ProcessorContext context) { return false; } /* (non-Javadoc) * @see com.itextpdf.html2pdf.attach.ITagWorker#processEnd(com.itextpdf.html2pdf.html.node.IElementNode, com.itextpdf.html2pdf.attach.ProcessorContext) */ @Override public void processEnd(IElementNode element, ProcessorContext context) { //Transform barcode into image qrCodeAsImage = new Image(qrCode.createFormXObject(context.getPdfDocument())); } /* (non-Javadoc) * @see com.itextpdf.html2pdf.attach.ITagWorker#getElementResult() */ @Override public IPropertyContainer getElementResult() { return qrCodeAsImage; } /** * Checks if a type of error correction is allowed. * * @param toCheck the error correction type to check * @return true, if successful */ private static boolean checkErrorCorrectionAllowed(String toCheck) { for (int i = 0; i < allowedErrorCorrection.length; i++) { if (toCheck.toUpperCase().equals(allowedErrorCorrection[i])) { return true; } } return false; } /** * Check if a certain character set is allowed. * * @param toCheck the character set to check * @return true, if successful */ private static boolean checkCharacterSet(String toCheck) { for (int i = 0; i < allowedCharset.length; i++) { if (toCheck.equals(allowedCharset[i])) { return true; } } return false; } /** * Gets the error correction level. * * @param level the error correction level as a String * @return the error correction level */ private static ErrorCorrectionLevel getErrorCorrectionLevel(String level) { switch (level) { case "L": return ErrorCorrectionLevel.L; case "M": return ErrorCorrectionLevel.M; case "Q": return ErrorCorrectionLevel.Q; case "H": return ErrorCorrectionLevel.H; } return null; } } }