Hot questions for Using PDFBox in spring boot

Top Java Programmings / PDFBox / spring boot


My Spring boot Java application is using apache pdf box library {version 2.0.6} for generating pdf. I want decimal values to be right aligned. It means all decimal dot should align in same vertical line. I also attached screenShot.

            stream.newLineAtOffset(xCordinate, yCordinate);
            List<String> resultList = processTextData(TextUtil.isEmpty(item.getDescription()) ? "-" : item.getDescription());
            int y = 0;
            int x = 50;
            int tempYcordinate = yCordinate;
            for (String string : resultList) {
                stream.newLineAtOffset(x, y);
                x = 0;
                y = -8;

            tempYcordinate = tempYcordinate - (8 * resultList.size());
            stream.newLineAtOffset(285, yCordinate);
            stream.showText("$" + NumberFormat.getInstance(Locale.US).format(Util.round(item.getUnitPrice())));
            stream.newLineAtOffset(65, 0);
            stream.showText("$" + NumberFormat.getInstance(Locale.US).format(Util.round(item.getExtPrice())));
            yCordinate = tempYcordinate;


To right align the text you need to compute the width of the text to show and align the output position to

(right alignment position) - (text width)

Find below a small snippet which shows the principle. You need to amend the snippet for your needs.

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class RightAlignDemo {

    public static void main(String[] args) throws IOException {
        File file = new File("out.pdf");
        PDDocument doc = new PDDocument();
        PDPage page = new PDPage();
        PDPageContentStream stream = new PDPageContentStream(doc, page);

        PDType1Font font = PDType1Font.TIMES_ROMAN;
        int fontSize = 12;

        stream.setFont(font, fontSize);

        double[] values = {0, 0.1, 0.01, 12.12, 123.12, 1234.12, 123456.12};

        int columnOneLeftX = 50;
        int columnTwoRightX = 170;
        int columnThreeOffsetX = 10;

        for (int i = 0; i < values.length; i++) {
            stream.newLineAtOffset(columnOneLeftX, 700 - (i*10));
            // show some left aligned non fixed width text
            stream.showText("value " + values[i]);

            // format the double value with thousands separator and 
            // two decimals
            String text = String.format("%,.2f", values[i]);
            // get the width of the formated value
            float textWidth = getTextWidth(font, fontSize, text);
            // align the position to (right alignment minus text width)
            stream.newLineAtOffset(columnTwoRightX - textWidth, 0);

            // align the positon back to columnTwoRightX plus offset for
            // column three
            stream.newLineAtOffset(textWidth + columnThreeOffsetX, 0);
            stream.showText("description " + i);


    private static float getTextWidth(PDType1Font font, int fontSize, 
            String text) throws IOException {
        return (font.getStringWidth(text) / 1000.0f) * fontSize;

PDF output


I'm trying to create a PDF and then download it automatically. I'm using PDFBox to create the PDF and it saves locally just fine but as soon as I return it via ResponseEntity or byte[] it becomes blank. I want to use a post because I want to send a body of parameters that I need for the PDF.

Here's my controller

    ResponseEntity<?> generateSampleTag(@RequestBody SampleTag sampleTag) {"inside generatePdfFromHtml method in DocumentController");
        try(ByteArrayOutputStream byteArrayOutputStream = freePdfService.generatePdf(sampleTag)) {
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_PDF_VALUE);
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=sampleTag.pdf");
            headers.add("Expires", "0");
            headers.add("Pragma", "public");
            ByteArrayResource resource = new ByteArrayResource(byteArrayOutputStream.toByteArray());
            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);


I've been trying a variety of input/output streams and header values and I'm just guessing at this point. Thanks for the help!

I answered below but my issue was Swagger couldn't download it correctly. Postman worked.


I have not used PDFBox but it has worked for me before to send an inputStream as a response with a PDF mime type header.

Something like...

ByteArrayOutputStream byteArrayOutputStream = freePdfService.generatePdf(sampleTag)
return new ResponseEntity<>(new InputStreamResource(byteArrayOutputStream), headers, HttpStatus.OK);


I have a spring boot application which renders a XML document into PDF. The document contains French characters likeé à. While running the application through STS I have no issues the PDF is generated as expected. But while running the application through command line using java -jar target\application.jar the generated PDF has French characters as é Ã. I am converting the XML into byte[] and creating the PDF. I couldn't figure out a way out. Any help is much appreciated.


Two options:

  1. Force the encoding with the file.encoding argument, such as -Dfile.encoding=utf-8.

    java -Dfile.encoding=utf-8 -jar target\application.jar
  2. (better) When you convert the xml file into a byte array, specify the encoding:

    Reader reader = new InputStreamReader(new FileInputStream("/path/to/xml/file"), StandardCharsets.UTF_8);
    // do your file reading ...


I can't find a way to stop warnings from PDFBox I am using in a psring boot application. For example:

2019-10-01 16:53:51.021  WARN 24564 --- [nio-8443-exec-2] o.a.pdfbox.pdmodel.font.PDType0Font      : No Unicode mapping for CID+4 (4) in font Calibri-Bold

2019-10-01 16:53:51.022  WARN 24564 --- [nio-8443-exec-2] o.a.pdfbox.pdmodel.font.PDCIDFontType2   : Failed to find a character mapping for 4 in Calibri-Bold

2019-10-01 16:53:51.022  WARN 24564 --- [nio-8443-exec-2] o.a.pdfbox.pdmodel.font.PDCIDFontType2   : Failed to find a character mapping for 4 in Calibri-Bold

I have tried: In Application file:

static {
  System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog");

  String[] loggers = {
  for (String logger: loggers) {
    org.apache.log4j.Logger logpdfengine = org.apache.log4j.Logger


As parameter when running jar:


Within the PDFBox code, the log is set up using:

(import org.apache.commons.logging.LogFactory;)

private static final Log LOG = LogFactory.getLog(PDCIDFontType0.class);

LOG.warn("Found PFB but expected embedded CFF font " + fd.getFontName());

I've spent a long time trying a lot of things and trolled through the answers for similar questions in SO but not got anywhere.


This is the configuration file I ended up using. I didn't include any logging releated dependencies or add any exclusions to pdfbox dependency, just added this file to the folder containing the file.

Filename is logback-spring.xml

The flooding logger was copied from how to change log levels of 3rd party library in java

<property name="LOGS" value="./logs" />

<appender name="Console"
    <layout class="ch.qos.logback.classic.PatternLayout">
            %black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable

<appender name="RollingFile"
        <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>

        <!-- rollover daily and when the file reaches 10 MegaBytes -->

<!-- LOG everything at INFO level -->
<root level="info">
    <appender-ref ref="RollingFile" />
    <appender-ref ref="Console" />

<!-- LOG "com.baeldung*" at TRACE level -->
<logger name="org.apache" level="ERROR" additivity="false">
    <appender-ref ref="RollingFile" />
    <appender-ref ref="Console" />

<logger name="flooding logger" level="ERROR" additivity="false">
  <appender-ref ref="Console"/>