Is it possible to change PDF file in Java?

297 Views Asked by At

I need to send to frontend large PDF file (20+ pages). Almost all pages are static, but some text on 2 pages in PDF file has to be changed depending on today's date and several parameters (like name and number). That's why I think it's good not to generate full PDF file from scratch, but to have template inside my project and then open it, modify it and save it as a new file. What is the best solution to make changes in template file in Java to send it to frontend? I considered 2 approaches: 1) to have template as PDF file, edit it and send to frontend and 2) to have template as DOCX file, edit it, convert to PDF and send it to frontend side. Probably the first way is not perfect, because as I understood we can't change text in PDF, only add white rectangle and then add text on it, and this solution will be explicit when user highlights text and also text width will be not expanded (all alignments will be the same not depending of inserted word lenght). Am I right or not? The second way looks better, I can change text in DOCX file via poi, below I'm leaving my method code and libraries dependencies, but I faced with issue linked to convertion from DOCX to PDF in Java - when I use library fr.opensagres.xdocreport:fr.opensagres.poi.xwpf.converter.pdf:2.0.4 I get PDF with content, which has some differences compared to content in DOCX file - watermarks in the background dissapear, sometimes sudden characters appear in list numbers and sometimes text overlaps each other. Are there some better libraries to convert DOCX to PDF with sufficient accuracy in Java? Or may be it is a bad approach and are there better solution, for example to use hybrid approach of several ways? I shall appreciate all your ideas. Share please your experience with PDF files edting. Thanks

My current service method to edit template and return changed one:

@Override
public byte[] getContract() {
    byte[] pdfContent;
    String docxPath = "doc/contract.docx";
    InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(docxPath);

    try (XWPFDocument doc = new XWPFDocument(Objects.requireNonNull(in))) {
        for (XWPFParagraph par : doc.getParagraphs()) {
            List<XWPFRun> runs = par.getRuns();
            if (!CollectionUtils.isEmpty(runs)) {
                for (XWPFRun run : runs) {
                    String text = run.getText(0);
                    if (!StringUtils.isEmpty(text)) {
                        if (text.contains(PH_DAY)) {
                            text = text.replace(PH_DAY, "23");
                        }
                        if (text.contains(PH_MONTH)) {
                            text = text.replace(PH_MONTH, "Fevral");
                        }
                        if (text.contains(PH_YEAR)) {
                            text = text.replace(PH_YEAR, "2023");
                        }
                        if (text.contains(PH_ORDINAL_SUFFIX)) {
                            text = text.replace(PH_ORDINAL_SUFFIX, "cü");
                        }
                        if (text.contains(PH_PIN)) {
                            text = text.replace(PH_PIN, "№ AF233031");
                        }
                        if (text.contains(PH_NAME)) {
                            text = text.replace(PH_NAME, "Surname Name");
                        }
                        run.setText(text, 0);
                    }
                }
            }
        }

        try (ByteArrayOutputStream docxOut = new ByteArrayOutputStream()) {
            doc.write(docxOut);
            try (ByteArrayOutputStream pdfOut = new ByteArrayOutputStream()) {
                PdfOptions pdfOptions = PdfOptions.create();
                PdfConverter.getInstance().convert(doc, pdfOut, pdfOptions);
                pdfContent = pdfOut.toByteArray();
            }
        }
    } catch (Exception e) {
        String message = e.getMessage();
        log.error(message);
        throw new GeneralTechnicalException(GeneralTechErrorEnum.SERVER_ERROR, message, e);
    }

    return pdfContent;
}

My build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
}

plugins {
    id 'org.springframework.boot' version "$springBootVersion"
    id 'io.spring.dependency-management' version "$springDependencyVersion"
    id 'java'
    id 'org.sonarqube' version "$sonarqubeVersion"
    id 'jacoco'
    id 'checkstyle'
    id 'pmd'
}

group = 'my.project'
version = '$projectVersion'
sourceCompatibility = '$sourceCompatibility'

repositories {
    mavenCentral()
    maven {
        url "${nexusUrl}/repository/maven-public/"
        allowInsecureProtocol = true
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.boot:spring-boot-starter-cache'
    implementation "org.springframework.cloud:spring-cloud-starter-openfeign:$openFeignVersion"
    implementation "com.oracle.ojdbc:ojdbc8:$oracleVersion"
    implementation "junit:junit:$junitVersion"
    implementation "org.redisson:redisson:$redissonVersion"
    implementation 'org.apache.commons:commons-lang3'
    implementation "org.springdoc:springdoc-openapi-ui:$springDocVersion"
    implementation "net.logstash.logback:logstash-logback-encoder:$logbackEncoderVersion"
    implementation 'ch.qos.logback:logback-classic'
    implementation "org.springframework.cloud:spring-cloud-dependencies:$releaseTrainVersion"
    implementation "com.ibam:ibam-error-handling:$ibamErrorHandlerVersion"
    implementation group: 'org.codehaus.jettison', name: 'jettison', version: "$jettisonVersion"
    implementation group: 'redis.clients', name: 'jedis', version: "${jedis}"
    implementation group: 'com.esotericsoftware', name: 'kryo', version: "${kryo}"
    implementation 'org.liquibase:liquibase-core'
//    implementation "com.github.librepdf:openpdf:$openpdfVersion"
    implementation "org.apache.poi:poi-ooxml:5.2.3"
    implementation "org.apache.logging.log4j:log4j-to-slf4j:2.20.0"
    implementation "org.apache.logging.log4j:log4j-api:2.20.0"
    implementation "fr.opensagres.xdocreport:fr.opensagres.poi.xwpf.converter.pdf:2.0.4"

    //  developmentOnly 'org.springframework.boot:spring-boot-devtools'

    compileOnly "org.projectlombok:lombok:$lombokVersion"

    annotationProcessor "org.projectlombok:lombok:$lombokVersion"
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

    implementation "com.auth0:java-jwt:$jwtAuthVersion"

    testImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.4'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

tasks.named('test') {
    useJUnitPlatform()
}

pmd {
    toolVersion = '6.10.0'
    ruleSets = []
    ignoreFailures = false
    ruleSetFiles = files("${rootProject.projectDir}/pmd/rules.xml")
}

checkstyle {
    toolVersion = "$checkstyleToolVersion"
    configFile = file("${rootProject.projectDir}/checkstyle/checkstyle.xml")
    ignoreFailures = false
}

tasks.withType(Checkstyle) {
    reports {
        xml.enabled true
        html.enabled true
    }
}

jacoco {
    toolVersion = "0.8.8"
    reportsDir = file("build/reports/jacoco")
}

jacocoTestReport {
    reports {
        xml.enabled true
        csv.enabled false
    }
}

sonarqube {
    properties {
        property "sonar.java.coveragePlugin", "jacoco"
        property 'sonar.coverage.exclusions', sonarExclude
        property "sonar.jacoco.reportPath", "build/jacoco/test.exec"
        property "sonar.junit.reportsPath", "build/test-results/test"
        property "sonar.scm.forceReloadAll", "true"
        property "sonar.java.checkstyle.reportPaths", "build/reports/checkstyle/main.xml"
    }
}

bootJar {
    archiveName 'app.jar'
}

0

There are 0 best solutions below