PdfUtils.java

package com.tdmconsult.ete.utils;

import com.tdmconsult.ete.configuration.MyConfigurationProperties;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import lombok.experimental.UtilityClass;
import org.openpdf.text.Element;
import org.openpdf.text.Image;
import org.openpdf.text.pdf.BaseFont;
import org.openpdf.text.pdf.PdfReader;
import org.openpdf.text.pdf.PdfStamper;
import org.springframework.core.io.ClassPathResource;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.pdf.ITextRenderer;


@UtilityClass
public class PdfUtils {

    public static final String STATIC_PDF_FONTS_RESOURCE_DIR = "book/fonts/";
    public static final String STATIC_IMG_RESOURCE_DIR = "book/img/";

    public static final String FONT_NORMAL = "LiberationSans-Regular.ttf";
    public static final String FONT_BOLD = "LiberationSans-Bold.ttf";
    public static final String FONT_ITALIC = "LiberationSans-Italic.ttf";
    public static final String FONT_BOLDITALIC = "LiberationSans-BoldItalic.ttf";

    private String getFontPath(final String fontFileName) throws IOException {
        final var fontResource = new ClassPathResource(
                STATIC_PDF_FONTS_RESOURCE_DIR + fontFileName,
                Thread.currentThread().getContextClassLoader());
        return fontResource.getURL().toString();
    }

    private String getImagePath() throws IOException {
        final var imgResource = new ClassPathResource(
                STATIC_IMG_RESOURCE_DIR,
                Thread.currentThread().getContextClassLoader());
        return imgResource.getURL().toString();
    }

    public void renderToOutputStream(
            final String xhtml,
            final MyConfigurationProperties.Pdf properties,
            final OutputStream os) throws IOException {

        final ITextRenderer renderer = new ITextRenderer();
        final SharedContext sharedContext = renderer.getSharedContext();
        sharedContext.setPrint(true);
        sharedContext.setInteractive(false);

        renderer.getFontResolver().addFont(getFontPath(FONT_NORMAL), BaseFont.IDENTITY_H, true);
        renderer.getFontResolver().addFont(getFontPath(FONT_BOLD), BaseFont.IDENTITY_H, true);
        renderer.getFontResolver().addFont(getFontPath(FONT_ITALIC), BaseFont.IDENTITY_H, true);
        renderer.getFontResolver().addFont(getFontPath(FONT_BOLDITALIC), BaseFont.IDENTITY_H, true);

        renderer.setDocumentFromString(xhtml);

        renderer.layout();
        renderer.createPDF(os);
    }

    public void renderWatermarkOnEachPage(
            final InputStream is,
            final MyConfigurationProperties.Pdf properties,
            final OutputStream os) throws IOException {

        final var baseFont = BaseFont.createFont(getFontPath(FONT_BOLD), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        try (
                final var reader = new PdfReader(is);
                final var stamper = new PdfStamper(reader, os)) {

            for (var pageIndex = 1; pageIndex <= reader.getNumberOfPages(); pageIndex++) {

                final var content = stamper.getOverContent(pageIndex);
                final var pageSize = reader.getPageSize(pageIndex);

                content.beginText();
                content.setFontAndSize(baseFont, properties.getFontSize());
                content.setRGBColorFill(255, 128, 128, 128);

                final var xCenter = BigDecimal.valueOf(pageSize.getLeft())
                        .add(BigDecimal.valueOf(pageSize.getRight()))
                        .divide(BigDecimal.valueOf(2));
                final var yCenter = BigDecimal.valueOf(pageSize.getTop())
                        .add(BigDecimal.valueOf(pageSize.getBottom()))
                        .divide(BigDecimal.valueOf(2));

                content.showTextAligned(
                        Element.ALIGN_CENTER,
                        properties.getWatermark(),
                        xCenter.floatValue(),
                        yCenter.add(BigDecimal.valueOf(100)).floatValue(), 25);
                content.endText();
            }
        }
    }

    public void renderLogoOnEachPage(
            final InputStream is,
            final MyConfigurationProperties.Pdf properties,
            final OutputStream os) throws IOException {

        final var logo = Image.getInstance(getImagePath() + properties.getLogoImageFileName());
        final var scalingFactor = new BigDecimal(properties.getLogoImageScale());
        logo.scaleToFit(
                BigDecimal.valueOf(logo.getPlainWidth()).divide(scalingFactor, RoundingMode.CEILING).floatValue(),
                BigDecimal.valueOf(logo.getPlainHeight()).divide(scalingFactor, RoundingMode.CEILING).floatValue());

        try (
                final var reader = new PdfReader(is);
                final var stamper = new PdfStamper(reader, os)) {

            for (var pageIndex = 1; pageIndex <= reader.getNumberOfPages(); pageIndex++) {

                final var content = stamper.getOverContent(pageIndex);
                final var pageSize = reader.getPageSize(pageIndex);

                logo.setAbsolutePosition(
                        pageSize.getWidth() - logo.getScaledWidth() - properties.getLogoImageWidthOffset(),
                        pageSize.getHeight() - logo.getScaledHeight() - properties.getLogoImageHeightOffset());

                content.addImage(logo);
            }
        }
    }

}